Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
authorJakub Kicinski <kuba@kernel.org>
Thu, 7 Jul 2022 19:07:37 +0000 (12:07 -0700)
committerJakub Kicinski <kuba@kernel.org>
Thu, 7 Jul 2022 19:07:37 +0000 (12:07 -0700)
No conflicts.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
795 files changed:
Documentation/bpf/btf.rst
Documentation/bpf/instruction-set.rst
Documentation/devicetree/bindings/net/can/microchip,mpfs-can.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/dsa/mt7530.txt [deleted file]
Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/ethernet-controller.yaml
Documentation/devicetree/bindings/net/mediatek,star-emac.yaml
Documentation/devicetree/bindings/net/micrel.txt
Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/net/snps,dwmac.yaml
Documentation/devicetree/bindings/net/ti,dp83867.yaml
Documentation/devicetree/bindings/net/xlnx,emaclite.yaml [new file with mode: 0644]
Documentation/networking/bonding.rst
Documentation/networking/can.rst
Documentation/networking/device_drivers/can/can327.rst [new file with mode: 0644]
Documentation/networking/device_drivers/can/index.rst
Documentation/networking/device_drivers/ethernet/index.rst
Documentation/networking/device_drivers/ethernet/neterion/vxge.rst [deleted file]
Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst [new file with mode: 0644]
Documentation/networking/ip-sysctl.rst
Documentation/networking/tls.rst
MAINTAINERS
arch/arm/net/bpf_jit_32.c
arch/arm64/boot/dts/rockchip/rk3568-bpi-r2-pro.dts
arch/riscv/boot/dts/microchip/mpfs.dtsi
arch/riscv/net/bpf_jit.h
arch/riscv/net/bpf_jit_core.c
drivers/atm/iphase.c
drivers/infiniband/hw/mlx5/dm.c
drivers/infiniband/hw/mlx5/mr.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/isdn/hardware/mISDN/hfcsusb.c
drivers/net/Kconfig
drivers/net/amt.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/can327.c [new file with mode: 0644]
drivers/net/can/ctucanfd/ctucanfd_base.c
drivers/net/can/dev/Makefile
drivers/net/can/dev/bittiming.c
drivers/net/can/dev/calc_bittiming.c [new file with mode: 0644]
drivers/net/can/dev/dev.c
drivers/net/can/dev/netlink.c
drivers/net/can/dev/skb.c
drivers/net/can/m_can/Kconfig
drivers/net/can/m_can/m_can.c
drivers/net/can/slcan/Makefile [new file with mode: 0644]
drivers/net/can/slcan/slcan-core.c [moved from drivers/net/can/slcan.c with 65% similarity]
drivers/net/can/slcan/slcan-ethtool.c [new file with mode: 0644]
drivers/net/can/slcan/slcan.h [new file with mode: 0644]
drivers/net/can/spi/mcp251xfd/Kconfig
drivers/net/can/usb/Kconfig
drivers/net/can/usb/Makefile
drivers/net/can/usb/esd_usb.c [moved from drivers/net/can/usb/esd_usb2.c with 81% similarity]
drivers/net/can/usb/etas_es58x/es58x_core.c
drivers/net/can/usb/etas_es58x/es58x_core.h
drivers/net/can/xilinx_can.c
drivers/net/dsa/Kconfig
drivers/net/dsa/Makefile
drivers/net/dsa/b53/b53_spi.c
drivers/net/dsa/microchip/Kconfig
drivers/net/dsa/microchip/Makefile
drivers/net/dsa/microchip/ksz8.h
drivers/net/dsa/microchip/ksz8795.c
drivers/net/dsa/microchip/ksz8795_reg.h
drivers/net/dsa/microchip/ksz8863_smi.c
drivers/net/dsa/microchip/ksz9477.c
drivers/net/dsa/microchip/ksz9477.h [new file with mode: 0644]
drivers/net/dsa/microchip/ksz9477_i2c.c
drivers/net/dsa/microchip/ksz9477_reg.h
drivers/net/dsa/microchip/ksz9477_spi.c [deleted file]
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/microchip/ksz_common.h
drivers/net/dsa/microchip/ksz_spi.c [moved from drivers/net/dsa/microchip/ksz8795_spi.c with 52% similarity]
drivers/net/dsa/microchip/lan937x.h [new file with mode: 0644]
drivers/net/dsa/microchip/lan937x_main.c [new file with mode: 0644]
drivers/net/dsa/microchip/lan937x_reg.h [new file with mode: 0644]
drivers/net/dsa/mt7530.c
drivers/net/dsa/mt7530.h
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/chip.h
drivers/net/dsa/mv88e6xxx/port.c
drivers/net/dsa/mv88e6xxx/port.h
drivers/net/dsa/ocelot/Kconfig
drivers/net/dsa/ocelot/felix.c
drivers/net/dsa/ocelot/felix.h
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/qca/ar9331.c
drivers/net/dsa/realtek/rtl8365mb.c
drivers/net/dsa/rzn1_a5psw.c [new file with mode: 0644]
drivers/net/dsa/rzn1_a5psw.h [new file with mode: 0644]
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/eql.c
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/agere/et131x.c
drivers/net/ethernet/altera/altera_utils.h
drivers/net/ethernet/amd/xgbe/xgbe-drv.c
drivers/net/ethernet/amd/xgbe/xgbe.h
drivers/net/ethernet/aquantia/atlantic/macsec/macsec_struct.h
drivers/net/ethernet/atheros/ag71xx.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/atheros/atlx/atl1.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/cadence/macb_ptp.c
drivers/net/ethernet/cavium/thunder/nicvf_queues.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/chelsio/inline_crypto/ch_ktls/chcr_ktls.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fs_enet/fs_enet.h
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/fungible/funcore/fun_hci.h
drivers/net/ethernet/fungible/funeth/funeth_ethtool.c
drivers/net/ethernet/fungible/funeth/funeth_main.c
drivers/net/ethernet/fungible/funeth/funeth_tx.c
drivers/net/ethernet/fungible/funeth/funeth_txrx.h
drivers/net/ethernet/google/gve/gve_tx_dqo.c
drivers/net/ethernet/hisilicon/hns/hns_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_trace.h
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/hisilicon/hns_mdio.c
drivers/net/ethernet/huawei/hinic/hinic_dev.h
drivers/net/ethernet/huawei/hinic/hinic_main.c
drivers/net/ethernet/huawei/hinic/hinic_rx.c
drivers/net/ethernet/huawei/hinic/hinic_sriov.c
drivers/net/ethernet/huawei/hinic/hinic_tx.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/e1000/e1000_hw.c
drivers/net/ethernet/intel/e1000/e1000_main.c
drivers/net/ethernet/intel/e1000/e1000_param.c
drivers/net/ethernet/intel/e1000e/mac.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/e1000e/param.c
drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
drivers/net/ethernet/intel/fm10k/fm10k_tlv.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_ptp.c
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_xsk.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
drivers/net/ethernet/intel/ice/ice_flex_pipe.c
drivers/net/ethernet/intel/ice/ice_gnss.c
drivers/net/ethernet/intel/ice/ice_lag.c
drivers/net/ethernet/intel/ice/ice_lib.c
drivers/net/ethernet/intel/ice/ice_protocol_type.h
drivers/net/ethernet/intel/ice/ice_sriov.c
drivers/net/ethernet/intel/ice/ice_switch.c
drivers/net/ethernet/intel/ice/ice_switch.h
drivers/net/ethernet/intel/ice/ice_tc_lib.c
drivers/net/ethernet/intel/ice/ice_tc_lib.h
drivers/net/ethernet/intel/ice/ice_virtchnl.c
drivers/net/ethernet/intel/ice/ice_vlan_mode.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_defines.h
drivers/net/ethernet/intel/igb/e1000_mac.c
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/igbvf.h
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/igc/igc_mac.c
drivers/net/ethernet/intel/igc/igc_ptp.c
drivers/net/ethernet/intel/ixgb/ixgb_hw.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgb/ixgb_param.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
drivers/net/ethernet/intel/ixgbevf/ethtool.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/intel/ixgbevf/vf.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_cpt.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
drivers/net/ethernet/marvell/prestera/prestera.h
drivers/net/ethernet/marvell/prestera/prestera_acl.c
drivers/net/ethernet/marvell/prestera/prestera_acl.h
drivers/net/ethernet/marvell/prestera/prestera_flow.c
drivers/net/ethernet/marvell/prestera/prestera_flow.h
drivers/net/ethernet/marvell/prestera/prestera_flower.c
drivers/net/ethernet/marvell/prestera/prestera_hw.h
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mediatek/mtk_eth_soc.c
drivers/net/ethernet/mediatek/mtk_star_emac.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/trap.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.h [deleted file]
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c
drivers/net/ethernet/mellanox/mlx5/core/sriov.c
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
drivers/net/ethernet/mellanox/mlxsw/Makefile
drivers/net/ethernet/mellanox/mlxsw/cmd.h
drivers/net/ethernet/mellanox/mlxsw/core.c
drivers/net/ethernet/mellanox/mlxsw/core.h
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
drivers/net/ethernet/mellanox/mlxsw/core_env.c
drivers/net/ethernet/mellanox/mlxsw/minimal.c
drivers/net/ethernet/mellanox/mlxsw/pci.c
drivers/net/ethernet/mellanox/mlxsw/port.h
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/resources.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum2_kvdl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_router_xm.c [deleted file]
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c
drivers/net/ethernet/mellanox/mlxsw/trap.h
drivers/net/ethernet/microchip/lan743x_ethtool.c
drivers/net/ethernet/microchip/lan743x_ethtool.h
drivers/net/ethernet/microchip/lan743x_main.c
drivers/net/ethernet/microchip/lan743x_main.h
drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
drivers/net/ethernet/microsoft/mana/gdma.h
drivers/net/ethernet/microsoft/mana/gdma_main.c
drivers/net/ethernet/microsoft/mana/hw_channel.c
drivers/net/ethernet/microsoft/mana/hw_channel.h
drivers/net/ethernet/microsoft/mana/mana.h
drivers/net/ethernet/microsoft/mana/mana_bpf.c
drivers/net/ethernet/microsoft/mana/mana_en.c
drivers/net/ethernet/microsoft/mana/mana_ethtool.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/mscc/ocelot_ptp.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/natsemi/natsemi.c
drivers/net/ethernet/neterion/Kconfig
drivers/net/ethernet/neterion/Makefile
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/neterion/vxge/Makefile [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-config.c [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-config.h [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-ethtool.c [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-ethtool.h [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-main.c [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-main.h [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-reg.h [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-traffic.c [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-traffic.h [deleted file]
drivers/net/ethernet/neterion/vxge/vxge-version.h [deleted file]
drivers/net/ethernet/netronome/nfp/flower/action.c
drivers/net/ethernet/netronome/nfp/flower/cmsg.h
drivers/net/ethernet/netronome/nfp/flower/conntrack.c
drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
drivers/net/ethernet/netronome/nfp/flower/metadata.c
drivers/net/ethernet/netronome/nfp/flower/offload.c
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfd3/dp.c
drivers/net/ethernet/netronome/nfp/nfd3/rings.c
drivers/net/ethernet/netronome/nfp/nfd3/xsk.c
drivers/net/ethernet/netronome/nfp/nfdk/dp.c
drivers/net/ethernet/netronome/nfp/nfdk/rings.c
drivers/net/ethernet/netronome/nfp/nfp_main.c
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
drivers/net/ethernet/netronome/nfp/nfp_net_dp.c
drivers/net/ethernet/netronome/nfp/nfp_net_dp.h
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
drivers/net/ethernet/netronome/nfp/nfp_net_repr.c
drivers/net/ethernet/netronome/nfp/nfp_net_xsk.c
drivers/net/ethernet/netronome/nfp/nfpcore/crc32.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpp.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_dev.c
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
drivers/net/ethernet/pensando/ionic/ionic_txrx.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qed/qed_int.c
drivers/net/ethernet/qlogic/qed/qed_rdma.c
drivers/net/ethernet/qlogic/qede/qede_fp.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qualcomm/emac/emac-mac.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef100.c
drivers/net/ethernet/sfc/ef100_ethtool.c
drivers/net/ethernet/sfc/ef100_netdev.c
drivers/net/ethernet/sfc/ef100_netdev.h
drivers/net/ethernet/sfc/ef100_nic.c
drivers/net/ethernet/sfc/ef100_nic.h
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx_common.c
drivers/net/ethernet/sfc/efx_common.h
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/ethtool_common.c
drivers/net/ethernet/sfc/falcon/bitfield.h
drivers/net/ethernet/sfc/falcon/farch.c
drivers/net/ethernet/sfc/mcdi.c
drivers/net/ethernet/sfc/mcdi_pcol.h
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/rx_common.c
drivers/net/ethernet/sfc/siena/farch.c
drivers/net/ethernet/sfc/siena/mcdi.c
drivers/net/ethernet/sfc/siena/mcdi_pcol.h
drivers/net/ethernet/sfc/sriov.c
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/mmc_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
drivers/net/ethernet/sun/cassini.c
drivers/net/ethernet/sun/cassini.h
drivers/net/ethernet/sun/ldmvsw.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/synopsys/dwc-xlgmac-net.c
drivers/net/ethernet/wangxun/Kconfig [new file with mode: 0644]
drivers/net/ethernet/wangxun/Makefile [new file with mode: 0644]
drivers/net/ethernet/wangxun/txgbe/Makefile [new file with mode: 0644]
drivers/net/ethernet/wangxun/txgbe/txgbe.h [new file with mode: 0644]
drivers/net/ethernet/wangxun/txgbe/txgbe_main.c [new file with mode: 0644]
drivers/net/ethernet/wangxun/txgbe/txgbe_type.h [new file with mode: 0644]
drivers/net/ethernet/xilinx/xilinx_axienet_mdio.c
drivers/net/ipa/gsi.c
drivers/net/ipa/gsi.h
drivers/net/ipa/gsi_private.h
drivers/net/ipa/gsi_trans.c
drivers/net/ipa/gsi_trans.h
drivers/net/ipa/ipa_cmd.c
drivers/net/ipa/ipa_endpoint.c
drivers/net/ipa/ipa_endpoint.h
drivers/net/ipvlan/ipvlan.h
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/macsec.c
drivers/net/macvlan.c
drivers/net/netconsole.c
drivers/net/pcs/Kconfig
drivers/net/pcs/Makefile
drivers/net/pcs/pcs-lynx.c
drivers/net/pcs/pcs-rzn1-miic.c [new file with mode: 0644]
drivers/net/pcs/pcs-xpcs.c
drivers/net/pcs/pcs-xpcs.h
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/aquantia_main.c
drivers/net/phy/bcm-phy-lib.h
drivers/net/phy/bcm-phy-ptp.c [new file with mode: 0644]
drivers/net/phy/broadcom.c
drivers/net/phy/dp83867.c
drivers/net/phy/dp83td510.c
drivers/net/phy/fixed_phy.c
drivers/net/phy/marvell-88x2222.c
drivers/net/phy/marvell.c
drivers/net/phy/micrel.c
drivers/net/phy/mxl-gpy.c
drivers/net/phy/nxp-tja11xx.c
drivers/net/phy/phy_device.c
drivers/net/phy/phylink.c
drivers/net/phy/sfp.c
drivers/net/phy/smsc.c
drivers/net/ppp/ppp_generic.c
drivers/net/team/team.c
drivers/net/usb/asix.h
drivers/net/usb/asix_common.c
drivers/net/usb/catc.c
drivers/net/usb/cdc_eem.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c
drivers/net/vmxnet3/Makefile
drivers/net/vmxnet3/upt1_defs.h
drivers/net/vmxnet3/vmxnet3_defs.h
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vrf.c
drivers/net/vxlan/vxlan_core.c
drivers/net/wan/farsync.h
drivers/net/wireguard/receive.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/microchip/wilc1000/cfg80211.c
drivers/net/wireless/microchip/wilc1000/fw.h
drivers/net/wireless/microchip/wilc1000/hif.c
drivers/net/wireless/microchip/wilc1000/hif.h
drivers/net/wireless/microchip/wilc1000/netdev.c
drivers/net/wireless/microchip/wilc1000/netdev.h
drivers/net/wireless/microchip/wilc1000/spi.c
drivers/net/wireless/microchip/wilc1000/wlan.c
drivers/net/wireless/microchip/wilc1000/wlan.h
drivers/net/wireless/microchip/wilc1000/wlan_if.h
drivers/net/wireless/ray_cs.c
drivers/net/wireless/realtek/rtlwifi/debug.c
drivers/net/wireless/realtek/rtw88/debug.c
drivers/net/wireless/realtek/rtw88/main.c
drivers/net/wireless/realtek/rtw88/rtw8723d.c
drivers/net/wireless/realtek/rtw88/rtw8723d.h
drivers/net/wireless/realtek/rtw88/rtw8723de.c
drivers/net/wireless/realtek/rtw88/rtw8723de.h [deleted file]
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/wireless/realtek/rtw88/rtw8821c.h
drivers/net/wireless/realtek/rtw88/rtw8821ce.c
drivers/net/wireless/realtek/rtw88/rtw8821ce.h [deleted file]
drivers/net/wireless/realtek/rtw88/rtw8822b.c
drivers/net/wireless/realtek/rtw88/rtw8822b.h
drivers/net/wireless/realtek/rtw88/rtw8822be.c
drivers/net/wireless/realtek/rtw88/rtw8822be.h [deleted file]
drivers/net/wireless/realtek/rtw88/rtw8822c.c
drivers/net/wireless/realtek/rtw88/rtw8822c.h
drivers/net/wireless/realtek/rtw88/rtw8822ce.c
drivers/net/wireless/realtek/rtw88/rtw8822ce.h [deleted file]
drivers/net/wireless/realtek/rtw89/cam.c
drivers/net/wireless/realtek/rtw89/cam.h
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/core.h
drivers/net/wireless/realtek/rtw89/debug.c
drivers/net/wireless/realtek/rtw89/debug.h
drivers/net/wireless/realtek/rtw89/fw.c
drivers/net/wireless/realtek/rtw89/fw.h
drivers/net/wireless/realtek/rtw89/mac.c
drivers/net/wireless/realtek/rtw89/mac.h
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/pci.c
drivers/net/wireless/realtek/rtw89/pci.h
drivers/net/wireless/realtek/rtw89/phy.c
drivers/net/wireless/realtek/rtw89/phy.h
drivers/net/wireless/realtek/rtw89/rtw8852c.c
drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.c
drivers/net/wireless/realtek/rtw89/rtw8852c_rfk.h
drivers/net/wireless/realtek/rtw89/sar.c
drivers/net/wireless/silabs/wfx/fwio.c
drivers/net/wireless/st/cw1200/bh.c
drivers/net/wireless/virt_wifi.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netback/rx.c
drivers/ptp/ptp_ocp.c
drivers/staging/qlge/qlge_main.c
include/dt-bindings/net/pcs-rzn1-miic.h [new file with mode: 0644]
include/linux/bpf.h
include/linux/bpf_verifier.h
include/linux/brcmphy.h
include/linux/btf.h
include/linux/can/bittiming.h
include/linux/can/skb.h
include/linux/filter.h
include/linux/ieee80211.h
include/linux/if_macvlan.h
include/linux/if_team.h
include/linux/if_vlan.h
include/linux/mii.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/mlx5/eswitch.h
include/linux/mlx5/fs.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mroute_base.h
include/linux/netdevice.h
include/linux/pcs-rzn1-miic.h [new file with mode: 0644]
include/linux/pcs/pcs-xpcs.h
include/linux/phy.h
include/linux/skbuff.h
include/linux/skmsg.h
include/linux/socket.h
include/linux/sockptr.h
include/linux/sysctl.h
include/linux/tcp.h
include/linux/time64.h
include/net/af_unix.h
include/net/bond_options.h
include/net/bonding.h
include/net/dropreason.h [new file with mode: 0644]
include/net/dsa.h
include/net/ip_tunnels.h
include/net/mac80211.h
include/net/neighbour.h
include/net/net_namespace.h
include/net/netns/unix.h
include/net/pkt_sched.h
include/net/raw.h
include/net/rawv6.h
include/net/sock.h
include/net/switchdev.h
include/net/tcp.h
include/net/tls.h
include/net/udp.h
include/net/xfrm.h
include/soc/mscc/ocelot.h
include/trace/events/net.h
include/trace/events/qdisc.h
include/trace/events/skb.h
include/uapi/linux/bpf.h
include/uapi/linux/btf.h
include/uapi/linux/if_ether.h
include/uapi/linux/if_link.h
include/uapi/linux/neighbour.h
include/uapi/linux/nl80211.h
include/uapi/linux/snmp.h
include/uapi/linux/sysctl.h
include/uapi/linux/tls.h
include/uapi/linux/tty.h
include/uapi/rdma/mlx5_user_ioctl_verbs.h
kernel/bpf/btf.c
kernel/bpf/cgroup.c
kernel/bpf/core.c
kernel/bpf/helpers.c
kernel/bpf/percpu_freelist.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/events/core.c
kernel/sysctl.c
kernel/trace/bpf_trace.c
kernel/trace/trace_uprobe.c
net/6lowpan/nhc.c
net/6lowpan/nhc.h
net/6lowpan/nhc_dest.c
net/6lowpan/nhc_fragment.c
net/6lowpan/nhc_ghc_ext_dest.c
net/6lowpan/nhc_ghc_ext_frag.c
net/6lowpan/nhc_ghc_ext_hop.c
net/6lowpan/nhc_ghc_ext_route.c
net/6lowpan/nhc_ghc_icmpv6.c
net/6lowpan/nhc_ghc_udp.c
net/6lowpan/nhc_hop.c
net/6lowpan/nhc_ipv6.c
net/6lowpan/nhc_mobility.c
net/6lowpan/nhc_routing.c
net/6lowpan/nhc_udp.c
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/ax25/af_ax25.c
net/ax25/ax25_dev.c
net/bpf/test_run.c
net/bridge/br_if.c
net/bridge/br_mdb.c
net/bridge/br_netlink.c
net/bridge/br_vlan.c
net/can/Kconfig
net/core/.gitignore [new file with mode: 0644]
net/core/Makefile
net/core/datagram.c
net/core/dev.c
net/core/dev_ioctl.c
net/core/devlink.c
net/core/drop_monitor.c
net/core/dst.c
net/core/failover.c
net/core/filter.c
net/core/link_watch.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/pktgen.c
net/core/skbuff.c
net/core/skmsg.c
net/core/sock.c
net/core/sock_map.c
net/core/stream.c
net/decnet/af_decnet.c
net/decnet/dn_neigh.c
net/dsa/Kconfig
net/dsa/Makefile
net/dsa/slave.c
net/dsa/tag_ksz.c
net/dsa/tag_rzn1_a5psw.c [new file with mode: 0644]
net/ethtool/ioctl.c
net/ethtool/netlink.c
net/ethtool/netlink.h
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_semantics.c
net/ipv4/ip_output.c
net/ipv4/ipconfig.c
net/ipv4/ipmr.c
net/ipv4/ipmr_base.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/raw_diag.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_bpf.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/udplite.c
net/ipv4/xfrm4_policy.c
net/ipv6/addrconf.c
net/ipv6/addrconf_core.c
net/ipv6/af_inet6.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ip6mr.c
net/ipv6/ndisc.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/udplite.c
net/ipv6/xfrm6_policy.c
net/iucv/af_iucv.c
net/llc/af_llc.c
net/mac80211/cfg.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh_hwmp.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wpa.c
net/mac80211/wpa.h
net/mptcp/pm_netlink.c
net/mptcp/protocol.c
net/mptcp/subflow.c
net/openvswitch/vport-netdev.c
net/packet/af_packet.c
net/sched/act_mirred.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/sched/sch_taprio.c
net/sctp/protocol.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/sctp/stream_interleave.c
net/sctp/ulpqueue.c
net/smc/smc_pnet.c
net/socket.c
net/switchdev/switchdev.c
net/tipc/bearer.c
net/tipc/name_table.c
net/tipc/name_table.h
net/tls/tls_device_fallback.c
net/tls/tls_main.c
net/tls/tls_proc.c
net/tls/tls_sw.c
net/unix/af_unix.c
net/unix/diag.c
net/unix/sysctl_net_unix.c
net/xdp/xdp_umem.c
net/xfrm/xfrm_device.c
samples/bpf/xdp_fwd_user.c
samples/bpf/xdp_router_ipv4.bpf.c
scripts/bpf_doc.py
tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
tools/bpf/bpftool/Documentation/bpftool-prog.rst
tools/bpf/bpftool/Makefile
tools/bpf/bpftool/bash-completion/bpftool
tools/bpf/bpftool/btf.c
tools/bpf/bpftool/btf_dumper.c
tools/bpf/bpftool/cgroup.c
tools/bpf/bpftool/common.c
tools/bpf/bpftool/feature.c
tools/bpf/bpftool/gen.c
tools/bpf/bpftool/link.c
tools/bpf/bpftool/main.c
tools/bpf/bpftool/main.h
tools/bpf/bpftool/map.c
tools/bpf/bpftool/pids.c
tools/bpf/bpftool/prog.c
tools/bpf/bpftool/struct_ops.c
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/btf.h
tools/include/uapi/linux/if_link.h
tools/lib/bpf/btf.c
tools/lib/bpf/btf.h
tools/lib/bpf/btf_dump.c
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf.h
tools/lib/bpf/libbpf.map
tools/lib/bpf/libbpf_internal.h
tools/lib/bpf/linker.c
tools/lib/bpf/relo_core.c
tools/lib/bpf/relo_core.h
tools/lib/bpf/usdt.c
tools/testing/selftests/bpf/.gitignore
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/bench.c
tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c [new file with mode: 0644]
tools/testing/selftests/bpf/benchs/run_bench_bpf_hashmap_full_update.sh [new file with mode: 0755]
tools/testing/selftests/bpf/btf_helpers.c
tools/testing/selftests/bpf/prog_tests/attach_probe.c
tools/testing/selftests/bpf/prog_tests/btf.c
tools/testing/selftests/bpf/prog_tests/btf_write.c
tools/testing/selftests/bpf/prog_tests/core_reloc.c
tools/testing/selftests/bpf/prog_tests/fexit_stress.c
tools/testing/selftests/bpf/prog_tests/libbpf_str.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/tc_redirect.c
tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/bpf_hashmap_full_update_bench.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___diff.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___err_missing.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___val3_missing.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/core_reloc_types.h
tools/testing/selftests/bpf/progs/test_attach_probe.c
tools/testing/selftests/bpf/progs/test_core_reloc_enum64val.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/test_tc_dtime.c
tools/testing/selftests/bpf/progs/test_varlen.c
tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c [new file with mode: 0644]
tools/testing/selftests/bpf/test_bpftool_synctypes.py
tools/testing/selftests/bpf/test_btf.h
tools/testing/selftests/bpf/test_xdping.sh
tools/testing/selftests/bpf/xdp_synproxy.c [new file with mode: 0644]
tools/testing/selftests/drivers/net/mlxsw/rif_counter_scale.sh [new file with mode: 0644]
tools/testing/selftests/drivers/net/mlxsw/spectrum-2/resource_scale.sh
tools/testing/selftests/drivers/net/mlxsw/spectrum-2/rif_counter_scale.sh [new symlink]
tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower_scale.sh
tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh
tools/testing/selftests/drivers/net/mlxsw/spectrum/rif_counter_scale.sh [new file with mode: 0644]
tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/af_unix/Makefile
tools/testing/selftests/net/af_unix/unix_connect.c [new file with mode: 0644]
tools/testing/selftests/net/cmsg_sender.c
tools/testing/selftests/net/fib_rule_tests.sh
tools/testing/selftests/net/forwarding/Makefile
tools/testing/selftests/net/forwarding/bridge_mdb_port_down.sh [new file with mode: 0755]
tools/testing/selftests/net/forwarding/ethtool_extended_state.sh
tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
tools/testing/selftests/net/tls.c
tools/testing/selftests/tc-testing/.gitignore

index 7940da9..f49aeef 100644 (file)
@@ -74,7 +74,7 @@ sequentially and type id is assigned to each recognized type starting from id
     #define BTF_KIND_ARRAY          3       /* Array        */
     #define BTF_KIND_STRUCT         4       /* Struct       */
     #define BTF_KIND_UNION          5       /* Union        */
-    #define BTF_KIND_ENUM           6       /* Enumeration  */
+    #define BTF_KIND_ENUM           6       /* Enumeration up to 32-bit values */
     #define BTF_KIND_FWD            7       /* Forward      */
     #define BTF_KIND_TYPEDEF        8       /* Typedef      */
     #define BTF_KIND_VOLATILE       9       /* Volatile     */
@@ -87,6 +87,7 @@ sequentially and type id is assigned to each recognized type starting from id
     #define BTF_KIND_FLOAT          16      /* Floating point       */
     #define BTF_KIND_DECL_TAG       17      /* Decl Tag     */
     #define BTF_KIND_TYPE_TAG       18      /* Type Tag     */
+    #define BTF_KIND_ENUM64         19      /* Enumeration up to 64-bit values */
 
 Note that the type section encodes debug info, not just pure types.
 ``BTF_KIND_FUNC`` is not a type, and it represents a defined subprogram.
@@ -101,10 +102,10 @@ Each type contains the following common data::
          * bits 24-28: kind (e.g. int, ptr, array...etc)
          * bits 29-30: unused
          * bit     31: kind_flag, currently used by
-         *             struct, union and fwd
+         *             struct, union, fwd, enum and enum64.
          */
         __u32 info;
-        /* "size" is used by INT, ENUM, STRUCT and UNION.
+        /* "size" is used by INT, ENUM, STRUCT, UNION and ENUM64.
          * "size" tells the size of the type it is describing.
          *
          * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
@@ -281,10 +282,10 @@ modes exist:
 
 ``struct btf_type`` encoding requirement:
   * ``name_off``: 0 or offset to a valid C identifier
-  * ``info.kind_flag``: 0
+  * ``info.kind_flag``: 0 for unsigned, 1 for signed
   * ``info.kind``: BTF_KIND_ENUM
   * ``info.vlen``: number of enum values
-  * ``size``: 4
+  * ``size``: 1/2/4/8
 
 ``btf_type`` is followed by ``info.vlen`` number of ``struct btf_enum``.::
 
@@ -297,6 +298,10 @@ The ``btf_enum`` encoding:
   * ``name_off``: offset to a valid C identifier
   * ``val``: any value
 
+If the original enum value is signed and the size is less than 4,
+that value will be sign extended into 4 bytes. If the size is 8,
+the value will be truncated into 4 bytes.
+
 2.2.7 BTF_KIND_FWD
 ~~~~~~~~~~~~~~~~~~
 
@@ -493,7 +498,7 @@ the attribute is applied to a ``struct``/``union`` member or
 a ``func`` argument, and ``btf_decl_tag.component_idx`` should be a
 valid index (starting from 0) pointing to a member or an argument.
 
-2.2.17 BTF_KIND_TYPE_TAG
+2.2.18 BTF_KIND_TYPE_TAG
 ~~~~~~~~~~~~~~~~~~~~~~~~
 
 ``struct btf_type`` encoding requirement:
@@ -516,6 +521,32 @@ type_tag, then zero or more const/volatile/restrict/typedef
 and finally the base type. The base type is one of
 int, ptr, array, struct, union, enum, func_proto and float types.
 
+2.2.19 BTF_KIND_ENUM64
+~~~~~~~~~~~~~~~~~~~~~~
+
+``struct btf_type`` encoding requirement:
+  * ``name_off``: 0 or offset to a valid C identifier
+  * ``info.kind_flag``: 0 for unsigned, 1 for signed
+  * ``info.kind``: BTF_KIND_ENUM64
+  * ``info.vlen``: number of enum values
+  * ``size``: 1/2/4/8
+
+``btf_type`` is followed by ``info.vlen`` number of ``struct btf_enum64``.::
+
+    struct btf_enum64 {
+        __u32   name_off;
+        __u32   val_lo32;
+        __u32   val_hi32;
+    };
+
+The ``btf_enum64`` encoding:
+  * ``name_off``: offset to a valid C identifier
+  * ``val_lo32``: lower 32-bit value for a 64-bit value
+  * ``val_hi32``: high 32-bit value for a 64-bit value
+
+If the original enum value is signed and the size is less than 8,
+that value will be sign extended into 8 bytes.
+
 3. BTF Kernel API
 =================
 
index 1de6a57..9e27fbd 100644 (file)
@@ -127,7 +127,7 @@ BPF_XOR | BPF_K | BPF_ALU64 means::
 Byte swap instructions
 ----------------------
 
-The byte swap instructions use an instruction class of ``BFP_ALU`` and a 4-bit
+The byte swap instructions use an instruction class of ``BPF_ALU`` and a 4-bit
 code field of ``BPF_END``.
 
 The byte swap instructions operate on the destination register
diff --git a/Documentation/devicetree/bindings/net/can/microchip,mpfs-can.yaml b/Documentation/devicetree/bindings/net/can/microchip,mpfs-can.yaml
new file mode 100644 (file)
index 0000000..45aa3de
--- /dev/null
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/can/microchip,mpfs-can.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title:
+  Microchip PolarFire SoC (MPFS) can controller
+
+maintainers:
+  - Conor Dooley <conor.dooley@microchip.com>
+
+allOf:
+  - $ref: can-controller.yaml#
+
+properties:
+  compatible:
+    const: microchip,mpfs-can
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    can@2010c000 {
+        compatible = "microchip,mpfs-can";
+        reg = <0x2010c000 0x1000>;
+        clocks = <&clkcfg 17>;
+        interrupt-parent = <&plic>;
+        interrupts = <56>;
+    };
diff --git a/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml b/Documentation/devicetree/bindings/net/dsa/mediatek,mt7530.yaml
new file mode 100644 (file)
index 0000000..17ab6c6
--- /dev/null
@@ -0,0 +1,407 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/mediatek,mt7530.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek MT7530 Ethernet switch
+
+maintainers:
+  - Sean Wang <sean.wang@mediatek.com>
+  - Landen Chao <Landen.Chao@mediatek.com>
+  - DENG Qingfang <dqfext@gmail.com>
+
+description: |
+  Port 5 of mt7530 and mt7621 switch is muxed between:
+  1. GMAC5: GMAC5 can interface with another external MAC or PHY.
+  2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC
+     of the SOC. Used in many setups where port 0/4 becomes the WAN port.
+     Note: On a MT7621 SOC with integrated switch: 2nd GMAC can only connected to
+       GMAC5 when the gpios for RGMII2 (GPIO 22-33) are not used and not
+       connected to external component!
+
+  Port 5 modes/configurations:
+  1. Port 5 is disabled and isolated: An external phy can interface to the 2nd
+     GMAC of the SOC.
+     In the case of a build-in MT7530 switch, port 5 shares the RGMII bus with 2nd
+     GMAC and an optional external phy. Mind the GPIO/pinctl settings of the SOC!
+  2. Port 5 is muxed to PHY of port 0/4: Port 0/4 interfaces with 2nd GMAC.
+     It is a simple MAC to PHY interface, port 5 needs to be setup for xMII mode
+     and RGMII delay.
+  3. Port 5 is muxed to GMAC5 and can interface to an external phy.
+     Port 5 becomes an extra switch port.
+     Only works on platform where external phy TX<->RX lines are swapped.
+     Like in the Ubiquiti ER-X-SFP.
+  4. Port 5 is muxed to GMAC5 and interfaces with the 2nd GAMC as 2nd CPU port.
+     Currently a 2nd CPU port is not supported by DSA code.
+
+  Depending on how the external PHY is wired:
+  1. normal: The PHY can only connect to 2nd GMAC but not to the switch
+  2. swapped: RGMII TX, RX are swapped; external phy interface with the switch as
+     a ethernet port. But can't interface to the 2nd GMAC.
+
+    Based on the DT the port 5 mode is configured.
+
+  Driver tries to lookup the phy-handle of the 2nd GMAC of the master device.
+  When phy-handle matches PHY of port 0 or 4 then port 5 set-up as mode 2.
+  phy-mode must be set, see also example 2 below!
+  * mt7621: phy-mode = "rgmii-txid";
+  * mt7623: phy-mode = "rgmii";
+
+  CPU-Ports need a phy-mode property:
+    Allowed values on mt7530 and mt7621:
+      - "rgmii"
+      - "trgmii"
+    On mt7531:
+      - "1000base-x"
+      - "2500base-x"
+      - "rgmii"
+      - "sgmii"
+
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt7530
+      - mediatek,mt7531
+      - mediatek,mt7621
+
+  reg:
+    maxItems: 1
+
+  core-supply:
+    description:
+      Phandle to the regulator node necessary for the core power.
+
+  "#gpio-cells":
+    const: 2
+
+  gpio-controller:
+    type: boolean
+    description:
+      if defined, MT7530's LED controller will run on GPIO mode.
+
+  "#interrupt-cells":
+    const: 1
+
+  interrupt-controller: true
+
+  interrupts:
+    maxItems: 1
+
+  io-supply:
+    description:
+      Phandle to the regulator node necessary for the I/O power.
+      See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
+      for details for the regulator setup on these boards.
+
+  mediatek,mcm:
+    type: boolean
+    description:
+      if defined, indicates that either MT7530 is the part on multi-chip
+      module belong to MT7623A has or the remotely standalone chip as the
+      function MT7623N reference board provided for.
+
+  reset-gpios:
+    maxItems: 1
+
+  reset-names:
+    const: mcm
+
+  resets:
+    description:
+      Phandle pointing to the system reset controller with line index for
+      the ethsys.
+    maxItems: 1
+
+patternProperties:
+  "^(ethernet-)?ports$":
+    type: object
+
+    patternProperties:
+      "^(ethernet-)?port@[0-9]+$":
+        type: object
+        description: Ethernet switch ports
+
+        unevaluatedProperties: false
+
+        properties:
+          reg:
+            description:
+              Port address described must be 5 or 6 for CPU port and from 0
+              to 5 for user ports.
+
+        allOf:
+          - $ref: dsa-port.yaml#
+          - if:
+              properties:
+                label:
+                  items:
+                    - const: cpu
+            then:
+              required:
+                - reg
+                - phy-mode
+
+required:
+  - compatible
+  - reg
+
+allOf:
+  - $ref: "dsa.yaml#"
+  - if:
+      required:
+        - mediatek,mcm
+    then:
+      required:
+        - resets
+        - reset-names
+
+  - dependencies:
+      interrupt-controller: [ interrupts ]
+
+  - if:
+      properties:
+        compatible:
+          items:
+            - const: mediatek,mt7530
+    then:
+      required:
+        - core-supply
+        - io-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    mdio {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        switch@0 {
+            compatible = "mediatek,mt7530";
+            reg = <0>;
+
+            core-supply = <&mt6323_vpa_reg>;
+            io-supply = <&mt6323_vemc3v3_reg>;
+            reset-gpios = <&pio 33 GPIO_ACTIVE_HIGH>;
+
+            ethernet-ports {
+                #address-cells = <1>;
+                #size-cells = <0>;
+                port@0 {
+                    reg = <0>;
+                    label = "lan0";
+                };
+
+                port@1 {
+                    reg = <1>;
+                    label = "lan1";
+                };
+
+                port@2 {
+                    reg = <2>;
+                    label = "lan2";
+                };
+
+                port@3 {
+                    reg = <3>;
+                    label = "lan3";
+                };
+
+                port@4 {
+                    reg = <4>;
+                    label = "wan";
+                };
+
+                port@6 {
+                    reg = <6>;
+                    label = "cpu";
+                    ethernet = <&gmac0>;
+                    phy-mode = "trgmii";
+                    fixed-link {
+                        speed = <1000>;
+                        full-duplex;
+                    };
+                };
+            };
+        };
+    };
+
+  - |
+    //Example 2: MT7621: Port 4 is WAN port: 2nd GMAC -> Port 5 -> PHY port 4.
+
+    ethernet {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        gmac0: mac@0 {
+            compatible = "mediatek,eth-mac";
+            reg = <0>;
+            phy-mode = "rgmii";
+
+            fixed-link {
+                speed = <1000>;
+                full-duplex;
+                pause;
+            };
+        };
+
+        gmac1: mac@1 {
+            compatible = "mediatek,eth-mac";
+            reg = <1>;
+            phy-mode = "rgmii-txid";
+            phy-handle = <&phy4>;
+        };
+
+        mdio: mdio-bus {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            /* Internal phy */
+            phy4: ethernet-phy@4 {
+                reg = <4>;
+            };
+
+            mt7530: switch@1f {
+                compatible = "mediatek,mt7621";
+                reg = <0x1f>;
+                mediatek,mcm;
+
+                resets = <&rstctrl 2>;
+                reset-names = "mcm";
+
+                ethernet-ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+
+                    port@0 {
+                        reg = <0>;
+                        label = "lan0";
+                    };
+
+                    port@1 {
+                        reg = <1>;
+                        label = "lan1";
+                    };
+
+                    port@2 {
+                        reg = <2>;
+                        label = "lan2";
+                    };
+
+                    port@3 {
+                        reg = <3>;
+                        label = "lan3";
+                    };
+
+                    /* Commented out. Port 4 is handled by 2nd GMAC.
+                    port@4 {
+                        reg = <4>;
+                        label = "lan4";
+                    };
+                    */
+
+                    port@6 {
+                        reg = <6>;
+                        label = "cpu";
+                        ethernet = <&gmac0>;
+                        phy-mode = "rgmii";
+
+                        fixed-link {
+                            speed = <1000>;
+                            full-duplex;
+                            pause;
+                        };
+                    };
+                };
+            };
+        };
+    };
+
+  - |
+    //Example 3: MT7621: Port 5 is connected to external PHY: Port 5 -> external PHY.
+
+    ethernet {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        gmac_0: mac@0 {
+            compatible = "mediatek,eth-mac";
+            reg = <0>;
+            phy-mode = "rgmii";
+
+            fixed-link {
+                speed = <1000>;
+                full-duplex;
+                pause;
+            };
+        };
+
+        mdio0: mdio-bus {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            /* External phy */
+            ephy5: ethernet-phy@7 {
+                reg = <7>;
+            };
+
+            switch@1f {
+                compatible = "mediatek,mt7621";
+                reg = <0x1f>;
+                mediatek,mcm;
+
+                resets = <&rstctrl 2>;
+                reset-names = "mcm";
+
+                ethernet-ports {
+                    #address-cells = <1>;
+                    #size-cells = <0>;
+
+                    port@0 {
+                        reg = <0>;
+                        label = "lan0";
+                    };
+
+                    port@1 {
+                        reg = <1>;
+                        label = "lan1";
+                    };
+
+                    port@2 {
+                        reg = <2>;
+                        label = "lan2";
+                    };
+
+                    port@3 {
+                        reg = <3>;
+                        label = "lan3";
+                    };
+
+                    port@4 {
+                        reg = <4>;
+                        label = "lan4";
+                    };
+
+                    port@5 {
+                        reg = <5>;
+                        label = "lan5";
+                        phy-mode = "rgmii";
+                        phy-handle = <&ephy5>;
+                    };
+
+                    cpu_port0: port@6 {
+                        reg = <6>;
+                        label = "cpu";
+                        ethernet = <&gmac_0>;
+                        phy-mode = "rgmii";
+
+                        fixed-link {
+                            speed = <1000>;
+                            full-duplex;
+                            pause;
+                        };
+                    };
+                };
+            };
+        };
+    };
diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml
new file mode 100644 (file)
index 0000000..630bf0f
--- /dev/null
@@ -0,0 +1,192 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/microchip,lan937x.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LAN937x Ethernet Switch Series Tree Bindings
+
+maintainers:
+  - UNGLinuxDriver@microchip.com
+
+allOf:
+  - $ref: dsa.yaml#
+
+properties:
+  compatible:
+    enum:
+      - microchip,lan9370
+      - microchip,lan9371
+      - microchip,lan9372
+      - microchip,lan9373
+      - microchip,lan9374
+
+  reg:
+    maxItems: 1
+
+  spi-max-frequency:
+    maximum: 50000000
+
+  reset-gpios:
+    description: Optional gpio specifier for a reset line
+    maxItems: 1
+
+  mdio:
+    $ref: /schemas/net/mdio.yaml#
+    unevaluatedProperties: false
+
+patternProperties:
+  "^(ethernet-)?ports$":
+    patternProperties:
+      "^(ethernet-)?port@[0-9]+$":
+        allOf:
+          - if:
+              properties:
+                phy-mode:
+                  contains:
+                    enum:
+                      - rgmii
+                      - rgmii-id
+                      - rgmii-txid
+                      - rgmii-rxid
+            then:
+              properties:
+                rx-internal-delay-ps:
+                  enum: [0, 2000]
+                  default: 0
+                tx-internal-delay-ps:
+                  enum: [0, 2000]
+                  default: 0
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    macb0 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            fixed-link {
+                    speed = <1000>;
+                    full-duplex;
+            };
+    };
+
+    spi {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            lan9374: switch@0 {
+                    compatible = "microchip,lan9374";
+                    reg = <0>;
+                    spi-max-frequency = <44000000>;
+
+                    ethernet-ports {
+                            #address-cells = <1>;
+                            #size-cells = <0>;
+
+                            port@0 {
+                                    reg = <0>;
+                                    label = "lan1";
+                                    phy-mode = "internal";
+                                    phy-handle = <&t1phy0>;
+                            };
+
+                            port@1 {
+                                    reg = <1>;
+                                    label = "lan2";
+                                    phy-mode = "internal";
+                                    phy-handle = <&t1phy1>;
+                            };
+
+                            port@2 {
+                                    reg = <2>;
+                                    label = "lan4";
+                                    phy-mode = "internal";
+                                    phy-handle = <&t1phy2>;
+                            };
+
+                            port@3 {
+                                    reg = <3>;
+                                    label = "lan6";
+                                    phy-mode = "internal";
+                                    phy-handle = <&t1phy3>;
+                            };
+
+                            port@4 {
+                                    reg = <4>;
+                                    phy-mode = "rgmii";
+                                    tx-internal-delay-ps = <2000>;
+                                    rx-internal-delay-ps = <2000>;
+                                    ethernet = <&macb0>;
+
+                                    fixed-link {
+                                            speed = <1000>;
+                                            full-duplex;
+                                    };
+                            };
+
+                            port@5 {
+                                    reg = <5>;
+                                    label = "lan7";
+                                    phy-mode = "rgmii";
+                                    tx-internal-delay-ps = <2000>;
+                                    rx-internal-delay-ps = <2000>;
+
+                                    fixed-link {
+                                            speed = <1000>;
+                                            full-duplex;
+                                    };
+                            };
+
+                            port@6 {
+                                    reg = <6>;
+                                    label = "lan5";
+                                    phy-mode = "internal";
+                                    phy-handle = <&t1phy6>;
+                            };
+
+                            port@7 {
+                                    reg = <7>;
+                                    label = "lan3";
+                                    phy-mode = "internal";
+                                    phy-handle = <&t1phy7>;
+                            };
+                    };
+
+                    mdio {
+                            #address-cells = <1>;
+                            #size-cells = <0>;
+
+                            t1phy0: ethernet-phy@0{
+                                    reg = <0x0>;
+                            };
+
+                            t1phy1: ethernet-phy@1{
+                                    reg = <0x1>;
+                            };
+
+                            t1phy2: ethernet-phy@2{
+                                    reg = <0x2>;
+                            };
+
+                            t1phy3: ethernet-phy@3{
+                                    reg = <0x3>;
+                            };
+
+                            t1phy6: ethernet-phy@6{
+                                    reg = <0x6>;
+                            };
+
+                            t1phy7: ethernet-phy@7{
+                                    reg = <0x7>;
+                            };
+                    };
+            };
+    };
diff --git a/Documentation/devicetree/bindings/net/dsa/mt7530.txt b/Documentation/devicetree/bindings/net/dsa/mt7530.txt
deleted file mode 100644 (file)
index 18247eb..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-Mediatek MT7530 Ethernet switch
-================================
-
-Required properties:
-
-- compatible: may be compatible = "mediatek,mt7530"
-       or compatible = "mediatek,mt7621"
-       or compatible = "mediatek,mt7531"
-- #address-cells: Must be 1.
-- #size-cells: Must be 0.
-- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
-       on multi-chip module belong to MT7623A has or the remotely standalone
-       chip as the function MT7623N reference board provided for.
-
-If compatible mediatek,mt7530 is set then the following properties are required
-
-- core-supply: Phandle to the regulator node necessary for the core power.
-- io-supply: Phandle to the regulator node necessary for the I/O power.
-       See Documentation/devicetree/bindings/regulator/mt6323-regulator.txt
-       for details for the regulator setup on these boards.
-
-If the property mediatek,mcm isn't defined, following property is required
-
-- reset-gpios: Should be a gpio specifier for a reset line.
-
-Else, following properties are required
-
-- resets : Phandle pointing to the system reset controller with
-       line index for the ethsys.
-- reset-names : Should be set to "mcm".
-
-Required properties for the child nodes within ports container:
-
-- reg: Port address described must be 6 for CPU port and from 0 to 5 for
-       user ports.
-- phy-mode: String, the following values are acceptable for port labeled
-       "cpu":
-       If compatible mediatek,mt7530 or mediatek,mt7621 is set,
-       must be either "trgmii" or "rgmii"
-       If compatible mediatek,mt7531 is set,
-       must be either "sgmii", "1000base-x" or "2500base-x"
-
-Port 5 of mt7530 and mt7621 switch is muxed between:
-1. GMAC5: GMAC5 can interface with another external MAC or PHY.
-2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC
-   of the SOC. Used in many setups where port 0/4 becomes the WAN port.
-   Note: On a MT7621 SOC with integrated switch: 2nd GMAC can only connected to
-        GMAC5 when the gpios for RGMII2 (GPIO 22-33) are not used and not
-        connected to external component!
-
-Port 5 modes/configurations:
-1. Port 5 is disabled and isolated: An external phy can interface to the 2nd
-   GMAC of the SOC.
-   In the case of a build-in MT7530 switch, port 5 shares the RGMII bus with 2nd
-   GMAC and an optional external phy. Mind the GPIO/pinctl settings of the SOC!
-2. Port 5 is muxed to PHY of port 0/4: Port 0/4 interfaces with 2nd GMAC.
-   It is a simple MAC to PHY interface, port 5 needs to be setup for xMII mode
-   and RGMII delay.
-3. Port 5 is muxed to GMAC5 and can interface to an external phy.
-   Port 5 becomes an extra switch port.
-   Only works on platform where external phy TX<->RX lines are swapped.
-   Like in the Ubiquiti ER-X-SFP.
-4. Port 5 is muxed to GMAC5 and interfaces with the 2nd GAMC as 2nd CPU port.
-   Currently a 2nd CPU port is not supported by DSA code.
-
-Depending on how the external PHY is wired:
-1. normal: The PHY can only connect to 2nd GMAC but not to the switch
-2. swapped: RGMII TX, RX are swapped; external phy interface with the switch as
-   a ethernet port. But can't interface to the 2nd GMAC.
-
-Based on the DT the port 5 mode is configured.
-
-Driver tries to lookup the phy-handle of the 2nd GMAC of the master device.
-When phy-handle matches PHY of port 0 or 4 then port 5 set-up as mode 2.
-phy-mode must be set, see also example 2 below!
- * mt7621: phy-mode = "rgmii-txid";
- * mt7623: phy-mode = "rgmii";
-
-Optional properties:
-
-- gpio-controller: Boolean; if defined, MT7530's LED controller will run on
-       GPIO mode.
-- #gpio-cells: Must be 2 if gpio-controller is defined.
-- interrupt-controller: Boolean; Enables the internal interrupt controller.
-
-If interrupt-controller is defined, the following properties are required.
-
-- #interrupt-cells: Must be 1.
-- interrupts: Parent interrupt for the interrupt controller.
-
-See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional
-required, optional properties and how the integrated switch subnodes must
-be specified.
-
-Example:
-
-       &mdio0 {
-               switch@0 {
-                       compatible = "mediatek,mt7530";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <0>;
-
-                       core-supply = <&mt6323_vpa_reg>;
-                       io-supply = <&mt6323_vemc3v3_reg>;
-                       reset-gpios = <&pio 33 0>;
-
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-                               reg = <0>;
-                               port@0 {
-                                       reg = <0>;
-                                       label = "lan0";
-                               };
-
-                               port@1 {
-                                       reg = <1>;
-                                       label = "lan1";
-                               };
-
-                               port@2 {
-                                       reg = <2>;
-                                       label = "lan2";
-                               };
-
-                               port@3 {
-                                       reg = <3>;
-                                       label = "lan3";
-                               };
-
-                               port@4 {
-                                       reg = <4>;
-                                       label = "wan";
-                               };
-
-                               port@6 {
-                                       reg = <6>;
-                                       label = "cpu";
-                                       ethernet = <&gmac0>;
-                                       phy-mode = "trgmii";
-                                       fixed-link {
-                                               speed = <1000>;
-                                               full-duplex;
-                                       };
-                               };
-                       };
-               };
-       };
-
-Example 2: MT7621: Port 4 is WAN port: 2nd GMAC -> Port 5 -> PHY port 4.
-
-&eth {
-       gmac0: mac@0 {
-               compatible = "mediatek,eth-mac";
-               reg = <0>;
-               phy-mode = "rgmii";
-
-               fixed-link {
-                       speed = <1000>;
-                       full-duplex;
-                       pause;
-               };
-       };
-
-       gmac1: mac@1 {
-               compatible = "mediatek,eth-mac";
-               reg = <1>;
-               phy-mode = "rgmii-txid";
-               phy-handle = <&phy4>;
-       };
-
-       mdio: mdio-bus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               /* Internal phy */
-               phy4: ethernet-phy@4 {
-                       reg = <4>;
-               };
-
-               mt7530: switch@1f {
-                       compatible = "mediatek,mt7621";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <0x1f>;
-                       pinctrl-names = "default";
-                       mediatek,mcm;
-
-                       resets = <&rstctrl 2>;
-                       reset-names = "mcm";
-
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
-                               port@0 {
-                                       reg = <0>;
-                                       label = "lan0";
-                               };
-
-                               port@1 {
-                                       reg = <1>;
-                                       label = "lan1";
-                               };
-
-                               port@2 {
-                                       reg = <2>;
-                                       label = "lan2";
-                               };
-
-                               port@3 {
-                                       reg = <3>;
-                                       label = "lan3";
-                               };
-
-/* Commented out. Port 4 is handled by 2nd GMAC.
-                               port@4 {
-                                       reg = <4>;
-                                       label = "lan4";
-                               };
-*/
-
-                               cpu_port0: port@6 {
-                                       reg = <6>;
-                                       label = "cpu";
-                                       ethernet = <&gmac0>;
-                                       phy-mode = "rgmii";
-
-                                       fixed-link {
-                                               speed = <1000>;
-                                               full-duplex;
-                                               pause;
-                                       };
-                               };
-                       };
-               };
-       };
-};
-
-Example 3: MT7621: Port 5 is connected to external PHY: Port 5 -> external PHY.
-
-&eth {
-       gmac0: mac@0 {
-               compatible = "mediatek,eth-mac";
-               reg = <0>;
-               phy-mode = "rgmii";
-
-               fixed-link {
-                       speed = <1000>;
-                       full-duplex;
-                       pause;
-               };
-       };
-
-       mdio: mdio-bus {
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               /* External phy */
-               ephy5: ethernet-phy@7 {
-                       reg = <7>;
-               };
-
-               mt7530: switch@1f {
-                       compatible = "mediatek,mt7621";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       reg = <0x1f>;
-                       pinctrl-names = "default";
-                       mediatek,mcm;
-
-                       resets = <&rstctrl 2>;
-                       reset-names = "mcm";
-
-                       ports {
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
-                               port@0 {
-                                       reg = <0>;
-                                       label = "lan0";
-                               };
-
-                               port@1 {
-                                       reg = <1>;
-                                       label = "lan1";
-                               };
-
-                               port@2 {
-                                       reg = <2>;
-                                       label = "lan2";
-                               };
-
-                               port@3 {
-                                       reg = <3>;
-                                       label = "lan3";
-                               };
-
-                               port@4 {
-                                       reg = <4>;
-                                       label = "lan4";
-                               };
-
-                               port@5 {
-                                       reg = <5>;
-                                       label = "lan5";
-                                       phy-mode = "rgmii";
-                                       phy-handle = <&ephy5>;
-                               };
-
-                               cpu_port0: port@6 {
-                                       reg = <6>;
-                                       label = "cpu";
-                                       ethernet = <&gmac0>;
-                                       phy-mode = "rgmii";
-
-                                       fixed-link {
-                                               speed = <1000>;
-                                               full-duplex;
-                                               pause;
-                                       };
-                               };
-                       };
-               };
-       };
-};
diff --git a/Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml b/Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml
new file mode 100644 (file)
index 0000000..4d428f5
--- /dev/null
@@ -0,0 +1,157 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/renesas,rzn1-a5psw.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/N1 Advanced 5 ports ethernet switch
+
+maintainers:
+  - Clément Léger <clement.leger@bootlin.com>
+
+description: |
+  The advanced 5 ports switch is present on the Renesas RZ/N1 SoC family and
+  handles 4 ports + 1 CPU management port.
+
+allOf:
+  - $ref: dsa.yaml#
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - renesas,r9a06g032-a5psw
+      - const: renesas,rzn1-a5psw
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: Device Level Ring (DLR) interrupt
+      - description: Switch interrupt
+      - description: Parallel Redundancy Protocol (PRP) interrupt
+      - description: Integrated HUB module interrupt
+      - description: Receive Pattern Match interrupt
+
+  interrupt-names:
+    items:
+      - const: dlr
+      - const: switch
+      - const: prp
+      - const: hub
+      - const: ptrn
+
+  power-domains:
+    maxItems: 1
+
+  mdio:
+    $ref: /schemas/net/mdio.yaml#
+    unevaluatedProperties: false
+
+  clocks:
+    items:
+      - description: AHB clock used for the switch register interface
+      - description: Switch system clock
+
+  clock-names:
+    items:
+      - const: hclk
+      - const: clk
+
+  ethernet-ports:
+    type: object
+    properties:
+      '#address-cells':
+        const: 1
+      '#size-cells':
+        const: 0
+
+    patternProperties:
+      "^(ethernet-)?port@[0-4]$":
+        type: object
+        description: Ethernet switch ports
+
+        properties:
+          pcs-handle:
+            description:
+              phandle pointing to a PCS sub-node compatible with
+              renesas,rzn1-miic.yaml#
+            $ref: /schemas/types.yaml#/definitions/phandle
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/clock/r9a06g032-sysctrl.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    switch@44050000 {
+        compatible = "renesas,r9a06g032-a5psw", "renesas,rzn1-a5psw";
+        reg = <0x44050000 0x10000>;
+        clocks = <&sysctrl R9A06G032_HCLK_SWITCH>, <&sysctrl R9A06G032_CLK_SWITCH>;
+        clock-names = "hclk", "clk";
+        power-domains = <&sysctrl>;
+        interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-names = "dlr", "switch", "prp", "hub", "ptrn";
+
+        dsa,member = <0 0>;
+
+        ethernet-ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0>;
+                label = "lan0";
+                phy-handle = <&switch0phy3>;
+                pcs-handle = <&mii_conv4>;
+            };
+
+            port@1 {
+                reg = <1>;
+                label = "lan1";
+                phy-handle = <&switch0phy1>;
+                pcs-handle = <&mii_conv3>;
+            };
+
+            port@4 {
+                reg = <4>;
+                ethernet = <&gmac2>;
+                label = "cpu";
+                fixed-link {
+                  speed = <1000>;
+                  full-duplex;
+                };
+            };
+        };
+
+        mdio {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            reset-gpios = <&gpio0a 2 GPIO_ACTIVE_HIGH>;
+            reset-delay-us = <15>;
+            clock-frequency = <2500000>;
+
+            switch0phy1: ethernet-phy@1{
+                reg = <1>;
+            };
+
+            switch0phy3: ethernet-phy@3{
+                reg = <3>;
+            };
+        };
+    };
index 4f15463..56d9aca 100644 (file)
@@ -133,12 +133,6 @@ properties:
       and is useful for determining certain configuration settings
       such as flow control thresholds.
 
-  rx-internal-delay-ps:
-    description: |
-      RGMII Receive Clock Delay defined in pico seconds.
-      This is used for controllers that have configurable RX internal delays.
-      If this property is present then the MAC applies the RX delay.
-
   sfp:
     $ref: /schemas/types.yaml#/definitions/phandle
     description:
@@ -150,12 +144,6 @@ properties:
       The size of the controller\'s transmit fifo in bytes. This
       is used for components that can have configurable fifo sizes.
 
-  tx-internal-delay-ps:
-    description: |
-      RGMII Transmit Clock Delay defined in pico seconds.
-      This is used for controllers that have configurable TX internal delays.
-      If this property is present then the MAC applies the TX delay.
-
   managed:
     description:
       Specifies the PHY management type. If auto is set and fixed-link
@@ -232,6 +220,29 @@ properties:
           required:
             - speed
 
+allOf:
+  - if:
+      properties:
+        phy-mode:
+          contains:
+            enum:
+              - rgmii
+              - rgmii-rxid
+              - rgmii-txid
+              - rgmii-id
+    then:
+      properties:
+        rx-internal-delay-ps:
+          description:
+            RGMII Receive Clock Delay defined in pico seconds.This is used for
+            controllers that have configurable RX internal delays. If this
+            property is present then the MAC applies the RX delay.
+        tx-internal-delay-ps:
+          description:
+            RGMII Transmit Clock Delay defined in pico seconds.This is used for
+            controllers that have configurable TX internal delays. If this
+            property is present then the MAC applies the TX delay.
+
 additionalProperties: true
 
 ...
index def994c..64c893c 100644 (file)
@@ -23,6 +23,7 @@ properties:
       - mediatek,mt8516-eth
       - mediatek,mt8518-eth
       - mediatek,mt8175-eth
+      - mediatek,mt8365-eth
 
   reg:
     maxItems: 1
@@ -47,6 +48,22 @@ properties:
       Phandle to the device containing the PERICFG register range. This is used
       to control the MII mode.
 
+  mediatek,rmii-rxc:
+    type: boolean
+    description:
+      If present, indicates that the RMII reference clock, which is from external
+      PHYs, is connected to RXC pin. Otherwise, is connected to TXC pin.
+
+  mediatek,rxc-inverse:
+    type: boolean
+    description:
+      If present, indicates that clock on RXC pad will be inversed.
+
+  mediatek,txc-inverse:
+    type: boolean
+    description:
+      If present, indicates that clock on TXC pad will be inversed.
+
   mdio:
     $ref: mdio.yaml#
     unevaluatedProperties: false
index a9ed691..a407dd1 100644 (file)
@@ -16,6 +16,7 @@ Optional properties:
        KSZ8051: register 0x1f, bits 5..4
        KSZ8081: register 0x1f, bits 5..4
        KSZ8091: register 0x1f, bits 5..4
+       LAN8814: register EP5.0, bit 6
 
        See the respective PHY datasheet for the mode values.
 
diff --git a/Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml b/Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml
new file mode 100644 (file)
index 0000000..2d33bba
--- /dev/null
@@ -0,0 +1,171 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/pcs/renesas,rzn1-miic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/N1 MII converter
+
+maintainers:
+  - Clément Léger <clement.leger@bootlin.com>
+
+description: |
+  This MII converter is present on the Renesas RZ/N1 SoC family. It is
+  responsible to do MII passthrough or convert it to RMII/RGMII.
+
+properties:
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  compatible:
+    items:
+      - enum:
+          - renesas,r9a06g032-miic
+      - const: renesas,rzn1-miic
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: MII reference clock
+      - description: RGMII reference clock
+      - description: RMII reference clock
+      - description: AHB clock used for the MII converter register interface
+
+  clock-names:
+    items:
+      - const: mii_ref
+      - const: rgmii_ref
+      - const: rmii_ref
+      - const: hclk
+
+  renesas,miic-switch-portin:
+    description: MII Switch PORTIN configuration. This value should use one of
+      the values defined in dt-bindings/net/pcs-rzn1-miic.h.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2]
+
+  power-domains:
+    maxItems: 1
+
+patternProperties:
+  "^mii-conv@[0-5]$":
+    type: object
+    description: MII converter port
+
+    properties:
+      reg:
+        description: MII Converter port number.
+        enum: [1, 2, 3, 4, 5]
+
+      renesas,miic-input:
+        description: Converter input port configuration. This value should use
+          one of the values defined in dt-bindings/net/pcs-rzn1-miic.h.
+        $ref: /schemas/types.yaml#/definitions/uint32
+
+    required:
+      - reg
+      - renesas,miic-input
+
+    additionalProperties: false
+
+    allOf:
+      - if:
+          properties:
+            reg:
+              const: 1
+        then:
+          properties:
+            renesas,miic-input:
+              const: 0
+      - if:
+          properties:
+            reg:
+              const: 2
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [1, 11]
+      - if:
+          properties:
+            reg:
+              const: 3
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [7, 10]
+      - if:
+          properties:
+            reg:
+              const: 4
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [4, 6, 9, 13]
+      - if:
+          properties:
+            reg:
+              const: 5
+        then:
+          properties:
+            renesas,miic-input:
+              enum: [3, 5, 8, 12]
+
+required:
+  - '#address-cells'
+  - '#size-cells'
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/net/pcs-rzn1-miic.h>
+    #include <dt-bindings/clock/r9a06g032-sysctrl.h>
+
+    eth-miic@44030000 {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      compatible = "renesas,r9a06g032-miic", "renesas,rzn1-miic";
+      reg = <0x44030000 0x10000>;
+      clocks = <&sysctrl R9A06G032_CLK_MII_REF>,
+              <&sysctrl R9A06G032_CLK_RGMII_REF>,
+              <&sysctrl R9A06G032_CLK_RMII_REF>,
+              <&sysctrl R9A06G032_HCLK_SWITCH_RG>;
+      clock-names = "mii_ref", "rgmii_ref", "rmii_ref", "hclk";
+      renesas,miic-switch-portin = <MIIC_GMAC2_PORT>;
+      power-domains = <&sysctrl>;
+
+      mii_conv1: mii-conv@1 {
+        renesas,miic-input = <MIIC_GMAC1_PORT>;
+        reg = <1>;
+      };
+
+      mii_conv2: mii-conv@2 {
+        renesas,miic-input = <MIIC_SWITCH_PORTD>;
+        reg = <2>;
+      };
+
+      mii_conv3: mii-conv@3 {
+        renesas,miic-input = <MIIC_SWITCH_PORTC>;
+        reg = <3>;
+      };
+
+      mii_conv4: mii-conv@4 {
+        renesas,miic-input = <MIIC_SWITCH_PORTB>;
+        reg = <4>;
+      };
+
+      mii_conv5: mii-conv@5 {
+        renesas,miic-input = <MIIC_SWITCH_PORTA>;
+        reg = <5>;
+      };
+    };
index 36c85eb..491597c 100644 (file)
@@ -65,6 +65,8 @@ properties:
         - ingenic,x2000-mac
         - loongson,ls2k-dwmac
         - loongson,ls7a-dwmac
+        - renesas,r9a06g032-gmac
+        - renesas,rzn1-gmac
         - rockchip,px30-gmac
         - rockchip,rk3128-gmac
         - rockchip,rk3228-gmac
@@ -135,6 +137,9 @@ properties:
   reset-names:
     const: stmmaceth
 
+  power-domains:
+    maxItems: 1
+
   mac-mode:
     $ref: ethernet-controller.yaml#/properties/phy-connection-type
     description:
index 047d757..76ff08a 100644 (file)
@@ -31,6 +31,16 @@ properties:
   reg:
     maxItems: 1
 
+  nvmem-cells:
+    maxItems: 1
+    description:
+      Nvmem data cell containing the value to write to the
+      IO_IMPEDANCE_CTRL field of the IO_MUX_CFG register.
+
+  nvmem-cell-names:
+    items:
+      - const: io_impedance_ctrl
+
   ti,min-output-impedance:
     type: boolean
     description: |
@@ -42,9 +52,11 @@ properties:
     description: |
       MAC Interface Impedance control to set the programmable output impedance
       to a maximum value (70 ohms).
-      Note: ti,min-output-impedance and ti,max-output-impedance are mutually
-        exclusive. When both properties are present ti,max-output-impedance
-        takes precedence.
+      Note: Specifying an io_impedance_ctrl nvmem cell or one of the
+        ti,min-output-impedance, ti,max-output-impedance properties
+        are mutually exclusive. If more than one is present, an nvmem
+        cell takes precedence over ti,max-output-impedance, which in
+        turn takes precedence over ti,min-output-impedance.
 
   tx-fifo-depth:
     $ref: /schemas/types.yaml#/definitions/uint32
diff --git a/Documentation/devicetree/bindings/net/xlnx,emaclite.yaml b/Documentation/devicetree/bindings/net/xlnx,emaclite.yaml
new file mode 100644 (file)
index 0000000..92d8ade
--- /dev/null
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/xlnx,emaclite.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx Emaclite Ethernet controller
+
+maintainers:
+  - Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
+  - Harini Katakam <harini.katakam@amd.com>
+
+allOf:
+  - $ref: ethernet-controller.yaml#
+
+properties:
+  compatible:
+    enum:
+      - xlnx,opb-ethernetlite-1.01.a
+      - xlnx,opb-ethernetlite-1.01.b
+      - xlnx,xps-ethernetlite-1.00.a
+      - xlnx,xps-ethernetlite-2.00.a
+      - xlnx,xps-ethernetlite-2.01.a
+      - xlnx,xps-ethernetlite-3.00.a
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  phy-handle: true
+
+  local-mac-address: true
+
+  xlnx,tx-ping-pong:
+    type: boolean
+    description: hardware supports tx ping pong buffer.
+
+  xlnx,rx-ping-pong:
+    type: boolean
+    description: hardware supports rx ping pong buffer.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - phy-handle
+
+additionalProperties: false
+
+examples:
+  - |
+    axi_ethernetlite_1: ethernet@40e00000 {
+        compatible = "xlnx,xps-ethernetlite-3.00.a";
+        reg = <0x40e00000 0x10000>;
+        interrupt-parent = <&axi_intc_1>;
+        interrupts = <1>;
+        local-mac-address = [00 00 00 00 00 00];
+        phy-handle = <&phy0>;
+        xlnx,rx-ping-pong;
+        xlnx,tx-ping-pong;
+    };
index 43be378..53a18ff 100644 (file)
@@ -780,6 +780,17 @@ peer_notif_delay
        value is 0 which means to match the value of the link monitor
        interval.
 
+prio
+       Slave priority. A higher number means higher priority.
+       The primary slave has the highest priority. This option also
+       follows the primary_reselect rules.
+
+       This option could only be configured via netlink, and is only valid
+       for active-backup(1), balance-tlb (5) and balance-alb (6) mode.
+       The valid value range is a signed 32 bit integer.
+
+       The default value is 0.
+
 primary
 
        A string (eth0, eth2, etc) specifying which slave is the
index f34cb0e..ebc822e 100644 (file)
@@ -168,7 +168,7 @@ reflect the correct [#f1]_ traffic on the node the loopback of the sent
 data has to be performed right after a successful transmission. If
 the CAN network interface is not capable of performing the loopback for
 some reason the SocketCAN core can do this task as a fallback solution.
-See :ref:`socketcan-local-loopback1` for details (recommended).
+See :ref:`socketcan-local-loopback2` for details (recommended).
 
 The loopback functionality is enabled by default to reflect standard
 networking behaviour for CAN applications. Due to some requests from
diff --git a/Documentation/networking/device_drivers/can/can327.rst b/Documentation/networking/device_drivers/can/can327.rst
new file mode 100644 (file)
index 0000000..b87bfbe
--- /dev/null
@@ -0,0 +1,331 @@
+.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+
+can327: ELM327 driver for Linux SocketCAN
+==========================================
+
+Authors
+--------
+
+Max Staudt <max@enpas.org>
+
+
+
+Motivation
+-----------
+
+This driver aims to lower the initial cost for hackers interested in
+working with CAN buses.
+
+CAN adapters are expensive, few, and far between.
+ELM327 interfaces are cheap and plentiful.
+Let's use ELM327s as CAN adapters.
+
+
+
+Introduction
+-------------
+
+This driver is an effort to turn abundant ELM327 based OBD interfaces
+into full fledged (as far as possible) CAN interfaces.
+
+Since the ELM327 was never meant to be a stand alone CAN controller,
+the driver has to switch between its modes as quickly as possible in
+order to fake full-duplex operation.
+
+As such, can327 is a best effort driver. However, this is more than
+enough to implement simple request-response protocols (such as OBD II),
+and to monitor broadcast messages on a bus (such as in a vehicle).
+
+Most ELM327s come as nondescript serial devices, attached via USB or
+Bluetooth. The driver cannot recognize them by itself, and as such it
+is up to the user to attach it in form of a TTY line discipline
+(similar to PPP, SLIP, slcan, ...).
+
+This driver is meant for ELM327 versions 1.4b and up, see below for
+known limitations in older controllers and clones.
+
+
+
+Data sheet
+-----------
+
+The official data sheets can be found at ELM electronics' home page:
+
+  https://www.elmelectronics.com/
+
+
+
+How to attach the line discipline
+----------------------------------
+
+Every ELM327 chip is factory programmed to operate at a serial setting
+of 38400 baud/s, 8 data bits, no parity, 1 stopbit.
+
+If you have kept this default configuration, the line discipline can
+be attached on a command prompt as follows::
+
+    sudo ldattach \
+           --debug \
+           --speed 38400 \
+           --eightbits \
+           --noparity \
+           --onestopbit \
+           --iflag -ICRNL,INLCR,-IXOFF \
+           30 \
+           /dev/ttyUSB0
+
+To change the ELM327's serial settings, please refer to its data
+sheet. This needs to be done before attaching the line discipline.
+
+Once the ldisc is attached, the CAN interface starts out unconfigured.
+Set the speed before starting it::
+
+    # The interface needs to be down to change parameters
+    sudo ip link set can0 down
+    sudo ip link set can0 type can bitrate 500000
+    sudo ip link set can0 up
+
+500000 bit/s is a common rate for OBD-II diagnostics.
+If you're connecting straight to a car's OBD port, this is the speed
+that most cars (but not all!) expect.
+
+After this, you can set out as usual with candump, cansniffer, etc.
+
+
+
+How to check the controller version
+------------------------------------
+
+Use a terminal program to attach to the controller.
+
+After issuing the "``AT WS``" command, the controller will respond with
+its version::
+
+    >AT WS
+
+
+    ELM327 v1.4b
+
+    >
+
+Note that clones may claim to be any version they like.
+It is not indicative of their actual feature set.
+
+
+
+
+Communication example
+----------------------
+
+This is a short and incomplete introduction on how to talk to an ELM327.
+It is here to guide understanding of the controller's and the driver's
+limitation (listed below) as well as manual testing.
+
+
+The ELM327 has two modes:
+
+- Command mode
+- Reception mode
+
+In command mode, it expects one command per line, terminated by CR.
+By default, the prompt is a "``>``", after which a command can be
+entered::
+
+    >ATE1
+    OK
+    >
+
+The init script in the driver switches off several configuration options
+that are only meaningful in the original OBD scenario the chip is meant
+for, and are actually a hindrance for can327.
+
+
+When a command is not recognized, such as by an older version of the
+ELM327, a question mark is printed as a response instead of OK::
+
+    >ATUNKNOWN
+    ?
+    >
+
+At present, can327 does not evaluate this response. See the section
+below on known limitations for details.
+
+
+When a CAN frame is to be sent, the target address is configured, after
+which the frame is sent as a command that consists of the data's hex
+dump::
+
+    >ATSH123
+    OK
+    >DEADBEEF12345678
+    OK
+    >
+
+The above interaction sends the SFF frame "``DE AD BE EF 12 34 56 78``"
+with (11 bit) CAN ID ``0x123``.
+For this to function, the controller must be configured for SFF sending
+mode (using "``AT PB``", see code or datasheet).
+
+
+Once a frame has been sent and wait-for-reply mode is on (``ATR1``,
+configured on ``listen-only=off``), or when the reply timeout expires
+and the driver sets the controller into monitoring mode (``ATMA``),
+the ELM327 will send one line for each received CAN frame, consisting
+of CAN ID, DLC, and data::
+
+    123 8 DEADBEEF12345678
+
+For EFF (29 bit) CAN frames, the address format is slightly different,
+which can327 uses to tell the two apart::
+
+    12 34 56 78 8 DEADBEEF12345678
+
+The ELM327 will receive both SFF and EFF frames - the current CAN
+config (``ATPB``) does not matter.
+
+
+If the ELM327's internal UART sending buffer runs full, it will abort
+the monitoring mode, print "BUFFER FULL" and drop back into command
+mode. Note that in this case, unlike with other error messages, the
+error message may appear on the same line as the last (usually
+incomplete) data frame::
+
+    12 34 56 78 8 DEADBEEF123 BUFFER FULL
+
+
+
+Known limitations of the controller
+------------------------------------
+
+- Clone devices ("v1.5" and others)
+
+  Sending RTR frames is not supported and will be dropped silently.
+
+  Receiving RTR with DLC 8 will appear to be a regular frame with
+  the last received frame's DLC and payload.
+
+  "``AT CSM``" (CAN Silent Monitoring, i.e. don't send CAN ACKs) is
+  not supported, and is hard coded to ON. Thus, frames are not ACKed
+  while listening: "``AT MA``" (Monitor All) will always be "silent".
+  However, immediately after sending a frame, the ELM327 will be in
+  "receive reply" mode, in which it *does* ACK any received frames.
+  Once the bus goes silent, or an error occurs (such as BUFFER FULL),
+  or the receive reply timeout runs out, the ELM327 will end reply
+  reception mode on its own and can327 will fall back to "``AT MA``"
+  in order to keep monitoring the bus.
+
+  Other limitations may apply, depending on the clone and the quality
+  of its firmware.
+
+
+- All versions
+
+  No full duplex operation is supported. The driver will switch
+  between input/output mode as quickly as possible.
+
+  The length of outgoing RTR frames cannot be set. In fact, some
+  clones (tested with one identifying as "``v1.5``") are unable to
+  send RTR frames at all.
+
+  We don't have a way to get real-time notifications on CAN errors.
+  While there is a command (``AT CS``) to retrieve some basic stats,
+  we don't poll it as it would force us to interrupt reception mode.
+
+
+- Versions prior to 1.4b
+
+  These versions do not send CAN ACKs when in monitoring mode (AT MA).
+  However, they do send ACKs while waiting for a reply immediately
+  after sending a frame. The driver maximizes this time to make the
+  controller as useful as possible.
+
+  Starting with version 1.4b, the ELM327 supports the "``AT CSM``"
+  command, and the "listen-only" CAN option will take effect.
+
+
+- Versions prior to 1.4
+
+  These chips do not support the "``AT PB``" command, and thus cannot
+  change bitrate or SFF/EFF mode on-the-fly. This will have to be
+  programmed by the user before attaching the line discipline. See the
+  data sheet for details.
+
+
+- Versions prior to 1.3
+
+  These chips cannot be used at all with can327. They do not support
+  the "``AT D1``" command, which is necessary to avoid parsing conflicts
+  on incoming data, as well as distinction of RTR frame lengths.
+
+  Specifically, this allows for easy distinction of SFF and EFF
+  frames, and to check whether frames are complete. While it is possible
+  to deduce the type and length from the length of the line the ELM327
+  sends us, this method fails when the ELM327's UART output buffer
+  overruns. It may abort sending in the middle of the line, which will
+  then be mistaken for something else.
+
+
+
+Known limitations of the driver
+--------------------------------
+
+- No 8/7 timing.
+
+  ELM327 can only set CAN bitrates that are of the form 500000/n, where
+  n is an integer divisor.
+  However there is an exception: With a separate flag, it may set the
+  speed to be 8/7 of the speed indicated by the divisor.
+  This mode is not currently implemented.
+
+- No evaluation of command responses.
+
+  The ELM327 will reply with OK when a command is understood, and with ?
+  when it is not. The driver does not currently check this, and simply
+  assumes that the chip understands every command.
+  The driver is built such that functionality degrades gracefully
+  nevertheless. See the section on known limitations of the controller.
+
+- No use of hardware CAN ID filtering
+
+  An ELM327's UART sending buffer will easily overflow on heavy CAN bus
+  load, resulting in the "``BUFFER FULL``" message. Using the hardware
+  filters available through "``AT CF xxx``" and "``AT CM xxx``" would be
+  helpful here, however SocketCAN does not currently provide a facility
+  to make use of such hardware features.
+
+
+
+Rationale behind the chosen configuration
+------------------------------------------
+
+``AT E1``
+  Echo on
+
+  We need this to be able to get a prompt reliably.
+
+``AT S1``
+  Spaces on
+
+  We need this to distinguish 11/29 bit CAN addresses received.
+
+  Note:
+  We can usually do this using the line length (odd/even),
+  but this fails if the line is not transmitted fully to
+  the host (BUFFER FULL).
+
+``AT D1``
+  DLC on
+
+  We need this to tell the "length" of RTR frames.
+
+
+
+A note on CAN bus termination
+------------------------------
+
+Your adapter may have resistors soldered in which are meant to terminate
+the bus. This is correct when it is plugged into a OBD-II socket, but
+not helpful when trying to tap into the middle of an existing CAN bus.
+
+If communications don't work with the adapter connected, check for the
+termination resistors on its PCB and try removing them.
index 0c3cc66..6a8a4f7 100644 (file)
@@ -10,6 +10,7 @@ Contents:
 .. toctree::
    :maxdepth: 2
 
+   can327
    ctu/ctucanfd-driver
    freescale/flexcan
 
index 4e06684..7f17771 100644 (file)
@@ -42,7 +42,6 @@ Contents:
    mellanox/mlx5
    microsoft/netvsc
    neterion/s2io
-   neterion/vxge
    netronome/nfp
    pensando/ionic
    smsc/smc9
@@ -52,6 +51,7 @@ Contents:
    ti/am65_nuss_cpsw_switchdev
    ti/tlan
    toshiba/spider_net
+   wangxun/txgbe
 
 .. only::  subproject and html
 
diff --git a/Documentation/networking/device_drivers/ethernet/neterion/vxge.rst b/Documentation/networking/device_drivers/ethernet/neterion/vxge.rst
deleted file mode 100644 (file)
index 589c6b1..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-==============================================================================
-Neterion's (Formerly S2io) X3100 Series 10GbE PCIe Server Adapter Linux driver
-==============================================================================
-
-.. Contents
-
-  1) Introduction
-  2) Features supported
-  3) Configurable driver parameters
-  4) Troubleshooting
-
-1. Introduction
-===============
-
-This Linux driver supports all Neterion's X3100 series 10 GbE PCIe I/O
-Virtualized Server adapters.
-
-The X3100 series supports four modes of operation, configurable via
-firmware:
-
-       - Single function mode
-       - Multi function mode
-       - SRIOV mode
-       - MRIOV mode
-
-The functions share a 10GbE link and the pci-e bus, but hardly anything else
-inside the ASIC. Features like independent hw reset, statistics, bandwidth/
-priority allocation and guarantees, GRO, TSO, interrupt moderation etc are
-supported independently on each function.
-
-(See below for a complete list of features supported for both IPv4 and IPv6)
-
-2. Features supported
-=====================
-
-i)   Single function mode (up to 17 queues)
-
-ii)  Multi function mode (up to 17 functions)
-
-iii) PCI-SIG's I/O Virtualization
-
-       - Single Root mode: v1.0 (up to 17 functions)
-       - Multi-Root mode: v1.0 (up to 17 functions)
-
-iv)  Jumbo frames
-
-       X3100 Series supports MTU up to 9600 bytes, modifiable using
-       ip command.
-
-v)   Offloads supported: (Enabled by default)
-
-       - Checksum offload (TCP/UDP/IP) on transmit and receive paths
-       - TCP Segmentation Offload (TSO) on transmit path
-       - Generic Receive Offload (GRO) on receive path
-
-vi)  MSI-X: (Enabled by default)
-
-       Resulting in noticeable performance improvement (up to 7% on certain
-       platforms).
-
-vii) NAPI: (Enabled by default)
-
-       For better Rx interrupt moderation.
-
-viii)RTH (Receive Traffic Hash): (Enabled by default)
-
-       Receive side steering for better scaling.
-
-ix)  Statistics
-
-       Comprehensive MAC-level and software statistics displayed using
-       "ethtool -S" option.
-
-x)   Multiple hardware queues: (Enabled by default)
-
-       Up to 17 hardware based transmit and receive data channels, with
-       multiple steering options (transmit multiqueue enabled by default).
-
-3) Configurable driver parameters:
-----------------------------------
-
-i)  max_config_dev
-       Specifies maximum device functions to be enabled.
-
-       Valid range: 1-8
-
-ii) max_config_port
-       Specifies number of ports to be enabled.
-
-       Valid range: 1,2
-
-       Default: 1
-
-iii) max_config_vpath
-       Specifies maximum VPATH(s) configured for each device function.
-
-       Valid range: 1-17
-
-iv) vlan_tag_strip
-       Enables/disables vlan tag stripping from all received tagged frames that
-       are not replicated at the internal L2 switch.
-
-       Valid range: 0,1 (disabled, enabled respectively)
-
-       Default: 1
-
-v)  addr_learn_en
-       Enable learning the mac address of the guest OS interface in
-       virtualization environment.
-
-       Valid range: 0,1 (disabled, enabled respectively)
-
-       Default: 0
diff --git a/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst b/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
new file mode 100644 (file)
index 0000000..eaa87db
--- /dev/null
@@ -0,0 +1,20 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================================================
+Linux Base Driver for WangXun(R) 10 Gigabit PCI Express Adapters
+================================================================
+
+WangXun 10 Gigabit Linux driver.
+Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd.
+
+
+Contents
+========
+
+- Support
+
+
+Support
+=======
+If you got any problem, contact Wangxun support team via support@trustnetic.com
+and Cc: netdev.
index 9f41961..4c8bbf5 100644 (file)
@@ -202,6 +202,12 @@ neigh/default/unres_qlen - INTEGER
 
        Default: 101
 
+neigh/default/interval_probe_time_ms - INTEGER
+       The probe interval for neighbor entries with NTF_MANAGED flag,
+       the min value is 1.
+
+       Default: 5000
+
 mtu_expires - INTEGER
        Time, in seconds, that cached PMTU information is kept.
 
index 8cb2cd4..7a66438 100644 (file)
@@ -214,6 +214,44 @@ of calling send directly after a handshake using gnutls.
 Since it doesn't implement a full record layer, control
 messages are not supported.
 
+Optional optimizations
+----------------------
+
+There are certain condition-specific optimizations the TLS ULP can make,
+if requested. Those optimizations are either not universally beneficial
+or may impact correctness, hence they require an opt-in.
+All options are set per-socket using setsockopt(), and their
+state can be checked using getsockopt() and via socket diag (``ss``).
+
+TLS_TX_ZEROCOPY_RO
+~~~~~~~~~~~~~~~~~~
+
+For device offload only. Allow sendfile() data to be transmitted directly
+to the NIC without making an in-kernel copy. This allows true zero-copy
+behavior when device offload is enabled.
+
+The application must make sure that the data is not modified between being
+submitted and transmission completing. In other words this is mostly
+applicable if the data sent on a socket via sendfile() is read-only.
+
+Modifying the data may result in different versions of the data being used
+for the original TCP transmission and TCP retransmissions. To the receiver
+this will look like TLS records had been tampered with and will result
+in record authentication failures.
+
+TLS_RX_EXPECT_NO_PAD
+~~~~~~~~~~~~~~~~~~~~
+
+TLS 1.3 only. Expect the sender to not pad records. This allows the data
+to be decrypted directly into user space buffers with TLS 1.3.
+
+This optimization is safe to enable only if the remote end is trusted,
+otherwise it is an attack vector to doubling the TLS processing cost.
+
+If the record decrypted turns out to had been padded or is not a data
+record it will be decrypted again into a kernel buffer without zero copy.
+Such events are counted in the ``TlsDecryptRetry`` statistic.
+
 Statistics
 ==========
 
@@ -239,3 +277,8 @@ TLS implementation exposes the following per-namespace statistics
 
 - ``TlsDeviceRxResync`` -
   number of RX resyncs sent to NICs handling cryptography
+
+- ``TlsDecryptRetry`` -
+  number of RX records which had to be re-decrypted due to
+  ``TLS_RX_EXPECT_NO_PAD`` mis-prediction. Note that this counter will
+  also increment for non-data records.
index 926bdf8..c4b709e 100644 (file)
@@ -171,7 +171,6 @@ F:  drivers/scsi/53c700*
 
 6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
 M:     Alexander Aring <alex.aring@gmail.com>
-M:     Jukka Rissanen <jukka.rissanen@linux.intel.com>
 L:     linux-bluetooth@vger.kernel.org
 L:     linux-wpan@vger.kernel.org
 S:     Maintained
@@ -7398,6 +7397,13 @@ L:       netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/ibm/ehea/
 
+ELM327 CAN NETWORK DRIVER
+M:     Max Staudt <max@enpas.org>
+L:     linux-can@vger.kernel.org
+S:     Maintained
+F:     Documentation/networking/device_drivers/can/can327.rst
+F:     drivers/net/can/can327.c
+
 EM28XX VIDEO4LINUX DRIVER
 M:     Mauro Carvalho Chehab <mchehab@kernel.org>
 L:     linux-media@vger.kernel.org
@@ -7503,6 +7509,13 @@ S:       Maintained
 F:     include/linux/errseq.h
 F:     lib/errseq.c
 
+ESD CAN/USB DRIVERS
+M:     Frank Jungclaus <frank.jungclaus@esd.eu>
+R:     socketcan@esd.eu
+L:     linux-can@vger.kernel.org
+S:     Maintained
+F:     drivers/net/can/usb/esd_usb.c
+
 ET131X NETWORK DRIVER
 M:     Mark Einon <mark.einon@gmail.com>
 S:     Odd Fixes
@@ -13178,6 +13191,7 @@ M:      UNGLinuxDriver@microchip.com
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
+F:     Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml
 F:     drivers/net/dsa/microchip/*
 F:     include/linux/platform_data/microchip-ksz.h
 F:     net/dsa/tag_ksz.c
@@ -13841,12 +13855,11 @@ L:    netdev@vger.kernel.org
 S:     Maintained
 F:     net/sched/sch_netem.c
 
-NETERION 10GbE DRIVERS (s2io/vxge)
+NETERION 10GbE DRIVERS (s2io)
 M:     Jon Mason <jdmason@kudzu.us>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     Documentation/networking/device_drivers/ethernet/neterion/s2io.rst
-F:     Documentation/networking/device_drivers/ethernet/neterion/vxge.rst
 F:     drivers/net/ethernet/neterion/
 
 NETFILTER
@@ -17184,6 +17197,19 @@ S:     Supported
 F:     Documentation/devicetree/bindings/iio/adc/renesas,rzg2l-adc.yaml
 F:     drivers/iio/adc/rzg2l_adc.c
 
+RENESAS RZ/N1 A5PSW SWITCH DRIVER
+M:     Clément Léger <clement.leger@bootlin.com>
+L:     linux-renesas-soc@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/net/dsa/renesas,rzn1-a5psw.yaml
+F:     Documentation/devicetree/bindings/net/pcs/renesas,rzn1-miic.yaml
+F:     drivers/net/dsa/rzn1_a5psw*
+F:     drivers/net/pcs/pcs-rzn1-miic.c
+F:     include/dt-bindings/net/pcs-rzn1-miic.h
+F:     include/linux/pcs-rzn1-miic.h
+F:     net/dsa/tag_rzn1_a5psw.c
+
 RENESAS RZ/N1 RTC CONTROLLER DRIVER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 L:     linux-rtc@vger.kernel.org
@@ -21568,6 +21594,13 @@ L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/input/tablet/wacom_serial4.c
 
+WANGXUN ETHERNET DRIVER
+M:     Jiawen Wu <jiawenwu@trustnetic.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst
+F:     drivers/net/ethernet/wangxun/
+
 WATCHDOG DEVICE DRIVERS
 M:     Wim Van Sebroeck <wim@linux-watchdog.org>
 M:     Guenter Roeck <linux@roeck-us.net>
index 9e45715..6a1c9fc 100644 (file)
@@ -712,22 +712,6 @@ static inline void emit_alu_r(const u8 dst, const u8 src, const bool is64,
        }
 }
 
-/* ALU operation (32 bit)
- * dst = dst (op) src
- */
-static inline void emit_a32_alu_r(const s8 dst, const s8 src,
-                                 struct jit_ctx *ctx, const bool is64,
-                                 const bool hi, const u8 op) {
-       const s8 *tmp = bpf2a32[TMP_REG_1];
-       s8 rn, rd;
-
-       rn = arm_bpf_get_reg32(src, tmp[1], ctx);
-       rd = arm_bpf_get_reg32(dst, tmp[0], ctx);
-       /* ALU operation */
-       emit_alu_r(rd, rn, is64, hi, op, ctx);
-       arm_bpf_put_reg32(dst, rd, ctx);
-}
-
 /* ALU operation (64 bit) */
 static inline void emit_a32_alu_r64(const bool is64, const s8 dst[],
                                  const s8 src[], struct jit_ctx *ctx,
index 40cf223..7df8cfb 100644 (file)
        status = "disabled";
 };
 
+&mdio0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       switch@0 {
+               compatible = "mediatek,mt7531";
+               reg = <0>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               reg = <1>;
+                               label = "lan0";
+                       };
+
+                       port@2 {
+                               reg = <2>;
+                               label = "lan1";
+                       };
+
+                       port@3 {
+                               reg = <3>;
+                               label = "lan2";
+                       };
+
+                       port@4 {
+                               reg = <4>;
+                               label = "lan3";
+                       };
+
+                       port@5 {
+                               reg = <5>;
+                               label = "cpu";
+                               ethernet = <&gmac0>;
+                               phy-mode = "rgmii";
+
+                               fixed-link {
+                                       speed = <1000>;
+                                       full-duplex;
+                                       pause;
+                               };
+                       };
+               };
+       };
+};
+
 &mdio1 {
        rgmii_phy1: ethernet-phy@0 {
                compatible = "ethernet-phy-ieee802.3-c22";
index 3095d08..0ec9a14 100644 (file)
                        status = "disabled";
                };
 
+               can0: can@2010c000 {
+                       compatible = "microchip,mpfs-can";
+                       reg = <0x0 0x2010c000 0x0 0x1000>;
+                       clocks = <&clkcfg CLK_CAN0>;
+                       interrupt-parent = <&plic>;
+                       interrupts = <56>;
+                       status = "disabled";
+               };
+
+               can1: can@2010d000 {
+                       compatible = "microchip,mpfs-can";
+                       reg = <0x0 0x2010d000 0x0 0x1000>;
+                       clocks = <&clkcfg CLK_CAN1>;
+                       interrupt-parent = <&plic>;
+                       interrupts = <57>;
+                       status = "disabled";
+               };
+
                mac0: ethernet@20110000 {
                        compatible = "cdns,macb";
                        reg = <0x0 0x20110000 0x0 0x2000>;
index 2a3715b..d926e0f 100644 (file)
@@ -69,6 +69,7 @@ struct rv_jit_context {
        struct bpf_prog *prog;
        u16 *insns;             /* RV insns */
        int ninsns;
+       int body_len;
        int epilogue_offset;
        int *offset;            /* BPF to RV */
        int nexentries;
index be743d7..737baf8 100644 (file)
@@ -44,7 +44,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
        unsigned int prog_size = 0, extable_size = 0;
        bool tmp_blinded = false, extra_pass = false;
        struct bpf_prog *tmp, *orig_prog = prog;
-       int pass = 0, prev_ninsns = 0, i;
+       int pass = 0, prev_ninsns = 0, prologue_len, i;
        struct rv_jit_data *jit_data;
        struct rv_jit_context *ctx;
 
@@ -95,6 +95,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
                        prog = orig_prog;
                        goto out_offset;
                }
+               ctx->body_len = ctx->ninsns;
                bpf_jit_build_prologue(ctx);
                ctx->epilogue_offset = ctx->ninsns;
                bpf_jit_build_epilogue(ctx);
@@ -161,6 +162,11 @@ skip_init_ctx:
 
        if (!prog->is_func || extra_pass) {
                bpf_jit_binary_lock_ro(jit_data->header);
+               prologue_len = ctx->epilogue_offset - ctx->body_len;
+               for (i = 0; i < prog->len; i++)
+                       ctx->offset[i] = ninsns_rvoff(prologue_len +
+                                                     ctx->offset[i]);
+               bpf_prog_fill_jited_linfo(prog, ctx->offset);
 out_offset:
                kfree(ctx->offset);
                kfree(jit_data);
index 3e726ee..3241486 100644 (file)
@@ -739,7 +739,7 @@ static u16 ia_eeprom_get (IADEV *iadev, u32 addr)
         u32    t;
        int     i;
        /*
-        * Read the first bit that was clocked with the falling edge of the
+        * Read the first bit that was clocked with the falling edge of
         * the last command data clock
         */
        NVRAM_CMD(IAREAD + addr);
index 001d766..3669c90 100644 (file)
@@ -336,9 +336,15 @@ err_copy:
 
 static enum mlx5_sw_icm_type get_icm_type(int uapi_type)
 {
-       return uapi_type == MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM ?
-                      MLX5_SW_ICM_TYPE_STEERING :
-                      MLX5_SW_ICM_TYPE_HEADER_MODIFY;
+       switch (uapi_type) {
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
+               return MLX5_SW_ICM_TYPE_HEADER_MODIFY;
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
+               return MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN;
+       case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
+       default:
+               return MLX5_SW_ICM_TYPE_STEERING;
+       }
 }
 
 static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
@@ -347,11 +353,32 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
                                            int type)
 {
        struct mlx5_core_dev *dev = to_mdev(ctx->device)->mdev;
-       enum mlx5_sw_icm_type icm_type = get_icm_type(type);
+       enum mlx5_sw_icm_type icm_type;
        struct mlx5_ib_dm_icm *dm;
        u64 act_size;
        int err;
 
+       if (!capable(CAP_SYS_RAWIO) || !capable(CAP_NET_RAW))
+               return ERR_PTR(-EPERM);
+
+       switch (type) {
+       case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
+               if (!(MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner) ||
+                     MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner) ||
+                     MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) ||
+                     MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2)))
+                       return ERR_PTR(-EOPNOTSUPP);
+               break;
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
+               if (!MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) ||
+                   !MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2))
+                       return ERR_PTR(-EOPNOTSUPP);
+               break;
+       default:
+               return ERR_PTR(-EOPNOTSUPP);
+       }
+
        dm = kzalloc(sizeof(*dm), GFP_KERNEL);
        if (!dm)
                return ERR_PTR(-ENOMEM);
@@ -359,19 +386,6 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
        dm->base.type = type;
        dm->base.ibdm.device = ctx->device;
 
-       if (!capable(CAP_SYS_RAWIO) || !capable(CAP_NET_RAW)) {
-               err = -EPERM;
-               goto free;
-       }
-
-       if (!(MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner) ||
-             MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner) ||
-             MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) ||
-             MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2))) {
-               err = -EOPNOTSUPP;
-               goto free;
-       }
-
        /* Allocation size must a multiple of the basic block size
         * and a power of 2.
         */
@@ -379,6 +393,8 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
        act_size = roundup_pow_of_two(act_size);
 
        dm->base.size = act_size;
+       icm_type = get_icm_type(type);
+
        err = mlx5_dm_sw_icm_alloc(dev, icm_type, act_size, attr->alignment,
                                   to_mucontext(ctx)->devx_uid,
                                   &dm->base.dev_addr, &dm->obj_id);
@@ -420,8 +436,8 @@ struct ib_dm *mlx5_ib_alloc_dm(struct ib_device *ibdev,
        case MLX5_IB_UAPI_DM_TYPE_MEMIC:
                return handle_alloc_dm_memic(context, attr, attrs);
        case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
-               return handle_alloc_dm_sw_icm(context, attr, attrs, type);
        case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
                return handle_alloc_dm_sw_icm(context, attr, attrs, type);
        default:
                return ERR_PTR(-EOPNOTSUPP);
@@ -474,6 +490,7 @@ static int mlx5_ib_dealloc_dm(struct ib_dm *ibdm,
                return 0;
        case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
        case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
                return mlx5_dm_icm_dealloc(ctx, to_icm(ibdm));
        default:
                return -EOPNOTSUPP;
index 1e7653c..aedfd7f 100644 (file)
@@ -1083,6 +1083,7 @@ struct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm,
                break;
        case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
        case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
+       case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
                if (attr->access_flags & ~MLX5_IB_DM_SW_ICM_ALLOWED_ACCESS)
                        return ERR_PTR(-EINVAL);
 
index 2c3dca4..f799551 100644 (file)
@@ -573,7 +573,7 @@ int ipoib_send(struct net_device *dev, struct sk_buff *skb,
        unsigned int usable_sge = priv->max_send_sge - !!skb_headlen(skb);
 
        if (skb_is_gso(skb)) {
-               hlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hlen = skb_tcp_all_headers(skb);
                phead = skb->data;
                if (unlikely(!skb_pull(skb, hlen))) {
                        ipoib_warn(priv, "linear data too small\n");
index cd5642c..651f2f8 100644 (file)
@@ -1557,7 +1557,7 @@ reset_hfcsusb(struct hfcsusb *hw)
        write_reg(hw, HFCUSB_USB_SIZE, (hw->packet_size / 8) |
                  ((hw->packet_size / 8) << 4));
 
-       /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+       /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
        write_reg(hw, HFCUSB_USB_SIZE_I, hw->iso_packet_size);
 
        /* enable PCM/GCI master mode */
index 8c1eeb5..94c8898 100644 (file)
@@ -500,6 +500,8 @@ config NET_SB1000
 
 source "drivers/net/phy/Kconfig"
 
+source "drivers/net/can/Kconfig"
+
 source "drivers/net/mctp/Kconfig"
 
 source "drivers/net/mdio/Kconfig"
index be2719a..732f4c0 100644 (file)
@@ -1373,11 +1373,11 @@ static void amt_add_srcs(struct amt_dev *amt, struct amt_tunnel_list *tunnel,
        int i;
 
        if (!v6) {
-               igmp_grec = (struct igmpv3_grec *)grec;
+               igmp_grec = grec;
                nsrcs = ntohs(igmp_grec->grec_nsrcs);
        } else {
 #if IS_ENABLED(CONFIG_IPV6)
-               mld_grec = (struct mld2_grec *)grec;
+               mld_grec = grec;
                nsrcs = ntohs(mld_grec->grec_nsrcs);
 #else
        return;
@@ -1458,11 +1458,11 @@ static void amt_lookup_act_srcs(struct amt_tunnel_list *tunnel,
        int i, j;
 
        if (!v6) {
-               igmp_grec = (struct igmpv3_grec *)grec;
+               igmp_grec = grec;
                nsrcs = ntohs(igmp_grec->grec_nsrcs);
        } else {
 #if IS_ENABLED(CONFIG_IPV6)
-               mld_grec = (struct mld2_grec *)grec;
+               mld_grec = grec;
                nsrcs = ntohs(mld_grec->grec_nsrcs);
 #else
        return;
index 6ba4c83..e75acb1 100644 (file)
@@ -1026,12 +1026,38 @@ out:
 
 }
 
+/**
+ * bond_choose_primary_or_current - select the primary or high priority slave
+ * @bond: our bonding struct
+ *
+ * - Check if there is a primary link. If the primary link was set and is up,
+ *   go on and do link reselection.
+ *
+ * - If primary link is not set or down, find the highest priority link.
+ *   If the highest priority link is not current slave, set it as primary
+ *   link and do link reselection.
+ */
 static struct slave *bond_choose_primary_or_current(struct bonding *bond)
 {
        struct slave *prim = rtnl_dereference(bond->primary_slave);
        struct slave *curr = rtnl_dereference(bond->curr_active_slave);
+       struct slave *slave, *hprio = NULL;
+       struct list_head *iter;
 
        if (!prim || prim->link != BOND_LINK_UP) {
+               bond_for_each_slave(bond, slave, iter) {
+                       if (slave->link == BOND_LINK_UP) {
+                               hprio = hprio ?: slave;
+                               if (slave->prio > hprio->prio)
+                                       hprio = slave;
+                       }
+               }
+
+               if (hprio && hprio != curr) {
+                       prim = hprio;
+                       goto link_reselect;
+               }
+
                if (!curr || curr->link != BOND_LINK_UP)
                        return NULL;
                return curr;
@@ -1042,6 +1068,7 @@ static struct slave *bond_choose_primary_or_current(struct bonding *bond)
                return prim;
        }
 
+link_reselect:
        if (!curr || curr->link != BOND_LINK_UP)
                return prim;
 
@@ -6220,45 +6247,33 @@ int bond_create(struct net *net, const char *name)
 {
        struct net_device *bond_dev;
        struct bonding *bond;
-       struct alb_bond_info *bond_info;
-       int res;
+       int res = -ENOMEM;
 
        rtnl_lock();
 
        bond_dev = alloc_netdev_mq(sizeof(struct bonding),
                                   name ? name : "bond%d", NET_NAME_UNKNOWN,
                                   bond_setup, tx_queues);
-       if (!bond_dev) {
-               pr_err("%s: eek! can't alloc netdev!\n", name);
-               rtnl_unlock();
-               return -ENOMEM;
-       }
+       if (!bond_dev)
+               goto out;
 
-       /*
-        * Initialize rx_hashtbl_used_head to RLB_NULL_INDEX.
-        * It is set to 0 by default which is wrong.
-        */
        bond = netdev_priv(bond_dev);
-       bond_info = &(BOND_ALB_INFO(bond));
-       bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
-
        dev_net_set(bond_dev, net);
        bond_dev->rtnl_link_ops = &bond_link_ops;
 
        res = register_netdevice(bond_dev);
        if (res < 0) {
                free_netdev(bond_dev);
-               rtnl_unlock();
-
-               return res;
+               goto out;
        }
 
        netif_carrier_off(bond_dev);
 
        bond_work_init_all(bond);
 
+out:
        rtnl_unlock();
-       return 0;
+       return res;
 }
 
 static int __net_init bond_net_init(struct net *net)
index 6f404f9..c2d080f 100644 (file)
@@ -27,6 +27,7 @@ static size_t bond_get_slave_size(const struct net_device *bond_dev,
                nla_total_size(sizeof(u16)) +   /* IFLA_BOND_SLAVE_AD_AGGREGATOR_ID */
                nla_total_size(sizeof(u8)) +    /* IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE */
                nla_total_size(sizeof(u16)) +   /* IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE */
+               nla_total_size(sizeof(s32)) +   /* IFLA_BOND_SLAVE_PRIO */
                0;
 }
 
@@ -53,6 +54,9 @@ static int bond_fill_slave_info(struct sk_buff *skb,
        if (nla_put_u16(skb, IFLA_BOND_SLAVE_QUEUE_ID, slave->queue_id))
                goto nla_put_failure;
 
+       if (nla_put_s32(skb, IFLA_BOND_SLAVE_PRIO, slave->prio))
+               goto nla_put_failure;
+
        if (BOND_MODE(slave->bond) == BOND_MODE_8023AD) {
                const struct aggregator *agg;
                const struct port *ad_port;
@@ -117,6 +121,7 @@ static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
 
 static const struct nla_policy bond_slave_policy[IFLA_BOND_SLAVE_MAX + 1] = {
        [IFLA_BOND_SLAVE_QUEUE_ID]      = { .type = NLA_U16 },
+       [IFLA_BOND_SLAVE_PRIO]          = { .type = NLA_S32 },
 };
 
 static int bond_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -151,7 +156,18 @@ static int bond_slave_changelink(struct net_device *bond_dev,
                snprintf(queue_id_str, sizeof(queue_id_str), "%s:%u\n",
                         slave_dev->name, queue_id);
                bond_opt_initstr(&newval, queue_id_str);
-               err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_QUEUE_ID, &newval,
+                                    data[IFLA_BOND_SLAVE_QUEUE_ID], extack);
+               if (err)
+                       return err;
+       }
+
+       if (data[IFLA_BOND_SLAVE_PRIO]) {
+               int prio = nla_get_s32(data[IFLA_BOND_SLAVE_PRIO]);
+
+               bond_opt_slave_initval(&newval, &slave_dev, prio);
+               err = __bond_opt_set(bond, BOND_OPT_PRIO, &newval,
+                                    data[IFLA_BOND_SLAVE_PRIO], extack);
                if (err)
                        return err;
        }
@@ -175,7 +191,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int mode = nla_get_u8(data[IFLA_BOND_MODE]);
 
                bond_opt_initval(&newval, mode);
-               err = __bond_opt_set(bond, BOND_OPT_MODE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_MODE, &newval,
+                                    data[IFLA_BOND_MODE], extack);
                if (err)
                        return err;
        }
@@ -192,7 +209,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        active_slave = slave_dev->name;
                }
                bond_opt_initstr(&newval, active_slave);
-               err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_ACTIVE_SLAVE, &newval,
+                                    data[IFLA_BOND_ACTIVE_SLAVE], extack);
                if (err)
                        return err;
        }
@@ -200,7 +218,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                miimon = nla_get_u32(data[IFLA_BOND_MIIMON]);
 
                bond_opt_initval(&newval, miimon);
-               err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_MIIMON, &newval,
+                                    data[IFLA_BOND_MIIMON], extack);
                if (err)
                        return err;
        }
@@ -208,7 +227,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]);
 
                bond_opt_initval(&newval, updelay);
-               err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_UPDELAY, &newval,
+                                    data[IFLA_BOND_UPDELAY], extack);
                if (err)
                        return err;
        }
@@ -216,7 +236,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]);
 
                bond_opt_initval(&newval, downdelay);
-               err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_DOWNDELAY, &newval,
+                                    data[IFLA_BOND_DOWNDELAY], extack);
                if (err)
                        return err;
        }
@@ -224,7 +245,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int delay = nla_get_u32(data[IFLA_BOND_PEER_NOTIF_DELAY]);
 
                bond_opt_initval(&newval, delay);
-               err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_PEER_NOTIF_DELAY, &newval,
+                                    data[IFLA_BOND_PEER_NOTIF_DELAY], extack);
                if (err)
                        return err;
        }
@@ -232,7 +254,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]);
 
                bond_opt_initval(&newval, use_carrier);
-               err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_USE_CARRIER, &newval,
+                                    data[IFLA_BOND_USE_CARRIER], extack);
                if (err)
                        return err;
        }
@@ -240,12 +263,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]);
 
                if (arp_interval && miimon) {
-                       netdev_err(bond->dev, "ARP monitoring cannot be used with MII monitoring\n");
+                       NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL],
+                                           "ARP monitoring cannot be used with MII monitoring");
                        return -EINVAL;
                }
 
                bond_opt_initval(&newval, arp_interval);
-               err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_ARP_INTERVAL, &newval,
+                                    data[IFLA_BOND_ARP_INTERVAL], extack);
                if (err)
                        return err;
        }
@@ -264,7 +289,9 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
 
                        bond_opt_initval(&newval, (__force u64)target);
                        err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
-                                            &newval);
+                                            &newval,
+                                            data[IFLA_BOND_ARP_IP_TARGET],
+                                            extack);
                        if (err)
                                break;
                        i++;
@@ -292,7 +319,9 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
 
                        bond_opt_initextra(&newval, &addr6, sizeof(addr6));
                        err = __bond_opt_set(bond, BOND_OPT_NS_TARGETS,
-                                            &newval);
+                                            &newval,
+                                            data[IFLA_BOND_NS_IP6_TARGET],
+                                            extack);
                        if (err)
                                break;
                        i++;
@@ -307,12 +336,14 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]);
 
                if (arp_validate && miimon) {
-                       netdev_err(bond->dev, "ARP validating cannot be used with MII monitoring\n");
+                       NL_SET_ERR_MSG_ATTR(extack, data[IFLA_BOND_ARP_INTERVAL],
+                                           "ARP validating cannot be used with MII monitoring");
                        return -EINVAL;
                }
 
                bond_opt_initval(&newval, arp_validate);
-               err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_ARP_VALIDATE, &newval,
+                                    data[IFLA_BOND_ARP_VALIDATE], extack);
                if (err)
                        return err;
        }
@@ -321,7 +352,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]);
 
                bond_opt_initval(&newval, arp_all_targets);
-               err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_ARP_ALL_TARGETS, &newval,
+                                    data[IFLA_BOND_ARP_ALL_TARGETS], extack);
                if (err)
                        return err;
        }
@@ -335,7 +367,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        primary = dev->name;
 
                bond_opt_initstr(&newval, primary);
-               err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_PRIMARY, &newval,
+                                    data[IFLA_BOND_PRIMARY], extack);
                if (err)
                        return err;
        }
@@ -344,7 +377,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]);
 
                bond_opt_initval(&newval, primary_reselect);
-               err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_PRIMARY_RESELECT, &newval,
+                                    data[IFLA_BOND_PRIMARY_RESELECT], extack);
                if (err)
                        return err;
        }
@@ -353,7 +387,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_FAIL_OVER_MAC]);
 
                bond_opt_initval(&newval, fail_over_mac);
-               err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_FAIL_OVER_MAC, &newval,
+                                    data[IFLA_BOND_FAIL_OVER_MAC], extack);
                if (err)
                        return err;
        }
@@ -362,7 +397,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_XMIT_HASH_POLICY]);
 
                bond_opt_initval(&newval, xmit_hash_policy);
-               err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_XMIT_HASH, &newval,
+                                    data[IFLA_BOND_XMIT_HASH_POLICY], extack);
                if (err)
                        return err;
        }
@@ -371,7 +407,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u32(data[IFLA_BOND_RESEND_IGMP]);
 
                bond_opt_initval(&newval, resend_igmp);
-               err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_RESEND_IGMP, &newval,
+                                    data[IFLA_BOND_RESEND_IGMP], extack);
                if (err)
                        return err;
        }
@@ -380,7 +417,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_NUM_PEER_NOTIF]);
 
                bond_opt_initval(&newval, num_peer_notif);
-               err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_NUM_PEER_NOTIF, &newval,
+                                    data[IFLA_BOND_NUM_PEER_NOTIF], extack);
                if (err)
                        return err;
        }
@@ -389,7 +427,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_ALL_SLAVES_ACTIVE]);
 
                bond_opt_initval(&newval, all_slaves_active);
-               err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_ALL_SLAVES_ACTIVE, &newval,
+                                    data[IFLA_BOND_ALL_SLAVES_ACTIVE], extack);
                if (err)
                        return err;
        }
@@ -398,7 +437,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u32(data[IFLA_BOND_MIN_LINKS]);
 
                bond_opt_initval(&newval, min_links);
-               err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_MINLINKS, &newval,
+                                    data[IFLA_BOND_MIN_LINKS], extack);
                if (err)
                        return err;
        }
@@ -407,7 +447,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u32(data[IFLA_BOND_LP_INTERVAL]);
 
                bond_opt_initval(&newval, lp_interval);
-               err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_LP_INTERVAL, &newval,
+                                    data[IFLA_BOND_LP_INTERVAL], extack);
                if (err)
                        return err;
        }
@@ -416,7 +457,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u32(data[IFLA_BOND_PACKETS_PER_SLAVE]);
 
                bond_opt_initval(&newval, packets_per_slave);
-               err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_PACKETS_PER_SLAVE, &newval,
+                                    data[IFLA_BOND_PACKETS_PER_SLAVE], extack);
                if (err)
                        return err;
        }
@@ -425,7 +467,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int lacp_active = nla_get_u8(data[IFLA_BOND_AD_LACP_ACTIVE]);
 
                bond_opt_initval(&newval, lacp_active);
-               err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_LACP_ACTIVE, &newval,
+                                    data[IFLA_BOND_AD_LACP_ACTIVE], extack);
                if (err)
                        return err;
        }
@@ -435,7 +478,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_AD_LACP_RATE]);
 
                bond_opt_initval(&newval, lacp_rate);
-               err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_LACP_RATE, &newval,
+                                    data[IFLA_BOND_AD_LACP_RATE], extack);
                if (err)
                        return err;
        }
@@ -444,7 +488,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u8(data[IFLA_BOND_AD_SELECT]);
 
                bond_opt_initval(&newval, ad_select);
-               err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_AD_SELECT, &newval,
+                                    data[IFLA_BOND_AD_SELECT], extack);
                if (err)
                        return err;
        }
@@ -453,7 +498,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u16(data[IFLA_BOND_AD_ACTOR_SYS_PRIO]);
 
                bond_opt_initval(&newval, actor_sys_prio);
-               err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYS_PRIO, &newval,
+                                    data[IFLA_BOND_AD_ACTOR_SYS_PRIO], extack);
                if (err)
                        return err;
        }
@@ -462,7 +508,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                        nla_get_u16(data[IFLA_BOND_AD_USER_PORT_KEY]);
 
                bond_opt_initval(&newval, port_key);
-               err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_AD_USER_PORT_KEY, &newval,
+                                    data[IFLA_BOND_AD_USER_PORT_KEY], extack);
                if (err)
                        return err;
        }
@@ -472,7 +519,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
 
                bond_opt_initval(&newval,
                                 nla_get_u64(data[IFLA_BOND_AD_ACTOR_SYSTEM]));
-               err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_AD_ACTOR_SYSTEM, &newval,
+                                    data[IFLA_BOND_AD_ACTOR_SYSTEM], extack);
                if (err)
                        return err;
        }
@@ -480,7 +528,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int dynamic_lb = nla_get_u8(data[IFLA_BOND_TLB_DYNAMIC_LB]);
 
                bond_opt_initval(&newval, dynamic_lb);
-               err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_TLB_DYNAMIC_LB, &newval,
+                                    data[IFLA_BOND_TLB_DYNAMIC_LB], extack);
                if (err)
                        return err;
        }
@@ -489,7 +538,8 @@ static int bond_changelink(struct net_device *bond_dev, struct nlattr *tb[],
                int missed_max = nla_get_u8(data[IFLA_BOND_MISSED_MAX]);
 
                bond_opt_initval(&newval, missed_max);
-               err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval);
+               err = __bond_opt_set(bond, BOND_OPT_MISSED_MAX, &newval,
+                                    data[IFLA_BOND_MISSED_MAX], extack);
                if (err)
                        return err;
        }
index 1f8323a..3498db1 100644 (file)
@@ -40,6 +40,8 @@ static int bond_option_arp_validate_set(struct bonding *bond,
                                        const struct bond_opt_value *newval);
 static int bond_option_arp_all_targets_set(struct bonding *bond,
                                           const struct bond_opt_value *newval);
+static int bond_option_prio_set(struct bonding *bond,
+                               const struct bond_opt_value *newval);
 static int bond_option_primary_set(struct bonding *bond,
                                   const struct bond_opt_value *newval);
 static int bond_option_primary_reselect_set(struct bonding *bond,
@@ -365,6 +367,16 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = {
                .values = bond_intmax_tbl,
                .set = bond_option_miimon_set
        },
+       [BOND_OPT_PRIO] = {
+               .id = BOND_OPT_PRIO,
+               .name = "prio",
+               .desc = "Link priority for failover re-selection",
+               .flags = BOND_OPTFLAG_RAWVAL,
+               .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
+                                               BIT(BOND_MODE_TLB) |
+                                               BIT(BOND_MODE_ALB)),
+               .set = bond_option_prio_set
+       },
        [BOND_OPT_PRIMARY] = {
                .id = BOND_OPT_PRIMARY,
                .name = "primary",
@@ -632,27 +644,35 @@ static int bond_opt_check_deps(struct bonding *bond,
 }
 
 static void bond_opt_dep_print(struct bonding *bond,
-                              const struct bond_option *opt)
+                              const struct bond_option *opt,
+                              struct nlattr *bad_attr,
+                              struct netlink_ext_ack *extack)
 {
        const struct bond_opt_value *modeval;
        struct bond_params *params;
 
        params = &bond->params;
        modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode);
-       if (test_bit(params->mode, &opt->unsuppmodes))
+       if (test_bit(params->mode, &opt->unsuppmodes)) {
                netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n",
                           opt->name, modeval->string, modeval->value);
+               NL_SET_ERR_MSG_ATTR(extack, bad_attr,
+                                   "option not supported in mode");
+       }
 }
 
 static void bond_opt_error_interpret(struct bonding *bond,
                                     const struct bond_option *opt,
-                                    int error, const struct bond_opt_value *val)
+                                    int error, const struct bond_opt_value *val,
+                                    struct nlattr *bad_attr,
+                                    struct netlink_ext_ack *extack)
 {
        const struct bond_opt_value *minval, *maxval;
        char *p;
 
        switch (error) {
        case -EINVAL:
+               NL_SET_ERR_MSG_ATTR(extack, bad_attr, "invalid option value");
                if (val) {
                        if (val->string) {
                                /* sometimes RAWVAL opts may have new lines */
@@ -674,13 +694,17 @@ static void bond_opt_error_interpret(struct bonding *bond,
                           opt->name, minval ? minval->value : 0, maxval->value);
                break;
        case -EACCES:
-               bond_opt_dep_print(bond, opt);
+               bond_opt_dep_print(bond, opt, bad_attr, extack);
                break;
        case -ENOTEMPTY:
+               NL_SET_ERR_MSG_ATTR(extack, bad_attr,
+                                   "unable to set option because the bond device has slaves");
                netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n",
                           opt->name);
                break;
        case -EBUSY:
+               NL_SET_ERR_MSG_ATTR(extack, bad_attr,
+                                   "unable to set option because the bond is up");
                netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n",
                           opt->name);
                break;
@@ -691,6 +715,8 @@ static void bond_opt_error_interpret(struct bonding *bond,
                                *p = '\0';
                        netdev_err(bond->dev, "option %s: interface %s does not exist!\n",
                                   opt->name, val->string);
+                       NL_SET_ERR_MSG_ATTR(extack, bad_attr,
+                                           "interface does not exist");
                }
                break;
        default:
@@ -703,13 +729,17 @@ static void bond_opt_error_interpret(struct bonding *bond,
  * @bond: target bond device
  * @option: option to set
  * @val: value to set it to
+ * @bad_attr: netlink attribue that caused the error
+ * @extack: extended netlink error structure, used when an error message
+ *          needs to be returned to the caller via netlink
  *
  * This function is used to change the bond's option value, it can be
  * used for both enabling/changing an option and for disabling it. RTNL lock
  * must be obtained before calling this function.
  */
 int __bond_opt_set(struct bonding *bond,
-                  unsigned int option, struct bond_opt_value *val)
+                  unsigned int option, struct bond_opt_value *val,
+                  struct nlattr *bad_attr, struct netlink_ext_ack *extack)
 {
        const struct bond_opt_value *retval = NULL;
        const struct bond_option *opt;
@@ -731,7 +761,7 @@ int __bond_opt_set(struct bonding *bond,
        ret = opt->set(bond, retval);
 out:
        if (ret)
-               bond_opt_error_interpret(bond, opt, ret, val);
+               bond_opt_error_interpret(bond, opt, ret, val, bad_attr, extack);
 
        return ret;
 }
@@ -753,7 +783,7 @@ int __bond_opt_set_notify(struct bonding *bond,
 
        ASSERT_RTNL();
 
-       ret = __bond_opt_set(bond, option, val);
+       ret = __bond_opt_set(bond, option, val, NULL, NULL);
 
        if (!ret && (bond->dev->reg_state == NETREG_REGISTERED))
                call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
@@ -1288,6 +1318,27 @@ static int bond_option_missed_max_set(struct bonding *bond,
        return 0;
 }
 
+static int bond_option_prio_set(struct bonding *bond,
+                               const struct bond_opt_value *newval)
+{
+       struct slave *slave;
+
+       slave = bond_slave_get_rtnl(newval->slave_dev);
+       if (!slave) {
+               netdev_dbg(newval->slave_dev, "%s called on NULL slave\n", __func__);
+               return -ENODEV;
+       }
+       slave->prio = newval->value;
+
+       if (rtnl_dereference(bond->primary_slave))
+               slave_warn(bond->dev, slave->dev,
+                          "prio updated, but will not affect failover re-selection as primary slave have been set\n");
+       else
+               bond_select_active_slave(bond);
+
+       return 0;
+}
+
 static int bond_option_primary_set(struct bonding *bond,
                                   const struct bond_opt_value *newval)
 {
index b2dcc1e..3048ad7 100644 (file)
@@ -1,5 +1,26 @@
 # SPDX-License-Identifier: GPL-2.0-only
-menu "CAN Device Drivers"
+
+menuconfig CAN_DEV
+       tristate "CAN Device Drivers"
+       default y
+       depends on CAN
+       help
+         Controller Area Network (CAN) is serial communications protocol up to
+         1Mbit/s for its original release (now known as Classical CAN) and up
+         to 8Mbit/s for the more recent CAN with Flexible Data-Rate
+         (CAN-FD). The CAN bus was originally mainly for automotive, but is now
+         widely used in marine (NMEA2000), industrial, and medical
+         applications. More information on the CAN network protocol family
+         PF_CAN is contained in <Documentation/networking/can.rst>.
+
+         This section contains all the CAN(-FD) device drivers including the
+         virtual ones. If you own such devices or plan to use the virtual CAN
+         interfaces to develop applications, say Y here.
+
+         To compile as a module, choose M here: the module will be called
+         can-dev.
+
+if CAN_DEV
 
 config CAN_VCAN
        tristate "Virtual Local CAN Interface (vcan)"
@@ -28,35 +49,22 @@ config CAN_VXCAN
          This driver can also be built as a module.  If so, the module
          will be called vxcan.
 
-config CAN_SLCAN
-       tristate "Serial / USB serial CAN Adaptors (slcan)"
-       depends on TTY
+config CAN_NETLINK
+       bool "CAN device drivers with Netlink support"
+       default y
        help
-         CAN driver for several 'low cost' CAN interfaces that are attached
-         via serial lines or via USB-to-serial adapters using the LAWICEL
-         ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
+         Enables the common framework for CAN device drivers. This is the
+         standard library and provides features for the Netlink interface such
+         as bittiming validation, support of CAN error states, device restart
+         and others.
 
-         As only the sending and receiving of CAN frames is implemented, this
-         driver should work with the (serial/USB) CAN hardware from:
-         www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
-
-         Userspace tools to attach the SLCAN line discipline (slcan_attach,
-         slcand) can be found in the can-utils at the linux-can project, see
-         https://github.com/linux-can/can-utils for details.
-
-         The slcan driver supports up to 10 CAN netdevices by default which
-         can be changed by the 'maxdev=xx' module option. This driver can
-         also be built as a module. If so, the module will be called slcan.
+         The additional features selected by this option will be added to the
+         can-dev module.
 
-config CAN_DEV
-       tristate "Platform CAN drivers with Netlink support"
-       default y
-       help
-         Enables the common framework for platform CAN drivers with Netlink
-         support. This is the standard library for CAN drivers.
-         If unsure, say Y.
+         This is required by all platform and hardware CAN drivers. If you
+         plan to use such devices or if unsure, say Y.
 
-if CAN_DEV
+if CAN_NETLINK
 
 config CAN_CALC_BITTIMING
        bool "CAN bit-timing calculation"
@@ -69,8 +77,15 @@ config CAN_CALC_BITTIMING
          source clock frequencies. Disabling saves some space, but then the
          bit-timing parameters must be specified directly using the Netlink
          arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
+
+         The additional features selected by this option will be added to the
+         can-dev module.
+
          If unsure, say Y.
 
+config CAN_RX_OFFLOAD
+       bool
+
 config CAN_AT91
        tristate "Atmel AT91 onchip CAN controller"
        depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM
@@ -78,10 +93,29 @@ config CAN_AT91
          This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
          and AT91SAM9X5 processors.
 
+config CAN_CAN327
+       tristate "Serial / USB serial ELM327 based OBD-II Interfaces (can327)"
+       depends on TTY
+       select CAN_RX_OFFLOAD
+       help
+         CAN driver for several 'low cost' OBD-II interfaces based on the
+         ELM327 OBD-II interpreter chip.
+
+         This is a best effort driver - the ELM327 interface was never
+         designed to be used as a standalone CAN interface. However, it can
+         still be used for simple request-response protocols (such as OBD II),
+         and to monitor broadcast messages on a bus (such as in a vehicle).
+
+         Please refer to the documentation for information on how to use it:
+         Documentation/networking/device_drivers/can/can327.rst
+
+         If this driver is built as a module, it will be called can327.
+
 config CAN_FLEXCAN
        tristate "Support for Freescale FLEXCAN based chips"
        depends on OF || COLDFIRE || COMPILE_TEST
        depends on HAS_IOMEM
+       select CAN_RX_OFFLOAD
        help
          Say Y here if you want to support for Freescale FlexCAN.
 
@@ -118,6 +152,26 @@ config CAN_KVASER_PCIEFD
            Kvaser Mini PCI Express HS v2
            Kvaser Mini PCI Express 2xHS v2
 
+config CAN_SLCAN
+       tristate "Serial / USB serial CAN Adaptors (slcan)"
+       depends on TTY
+       help
+         CAN driver for several 'low cost' CAN interfaces that are attached
+         via serial lines or via USB-to-serial adapters using the LAWICEL
+         ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
+
+         As only the sending and receiving of CAN frames is implemented, this
+         driver should work with the (serial/USB) CAN hardware from:
+         www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de
+
+         Userspace tools to attach the SLCAN line discipline (slcan_attach,
+         slcand) can be found in the can-utils at the linux-can project, see
+         https://github.com/linux-can/can-utils for details.
+
+         The slcan driver supports up to 10 CAN netdevices by default which
+         can be changed by the 'maxdev=xx' module option. This driver can
+         also be built as a module. If so, the module will be called slcan.
+
 config CAN_SUN4I
        tristate "Allwinner A10 CAN controller"
        depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
@@ -131,6 +185,7 @@ config CAN_SUN4I
 config CAN_TI_HECC
        depends on ARM
        tristate "TI High End CAN Controller"
+       select CAN_RX_OFFLOAD
        help
          Driver for TI HECC (High End CAN Controller) module found on many
          TI devices. The device specifications are available from www.ti.com
@@ -164,7 +219,7 @@ source "drivers/net/can/softing/Kconfig"
 source "drivers/net/can/spi/Kconfig"
 source "drivers/net/can/usb/Kconfig"
 
-endif
+endif #CAN_NETLINK
 
 config CAN_DEBUG_DEVICES
        bool "CAN devices debugging messages"
@@ -174,4 +229,4 @@ config CAN_DEBUG_DEVICES
          a problem with CAN support and want to see more of what is going
          on.
 
-endmenu
+endif #CAN_DEV
index 0af8598..61c75ce 100644 (file)
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_CAN_VCAN)         += vcan.o
 obj-$(CONFIG_CAN_VXCAN)                += vxcan.o
-obj-$(CONFIG_CAN_SLCAN)                += slcan.o
+obj-$(CONFIG_CAN_SLCAN)                += slcan/
 
 obj-y                          += dev/
 obj-y                          += rcar/
@@ -14,6 +14,7 @@ obj-y                         += usb/
 obj-y                          += softing/
 
 obj-$(CONFIG_CAN_AT91)         += at91_can.o
+obj-$(CONFIG_CAN_CAN327)       += can327.o
 obj-$(CONFIG_CAN_CC770)                += cc770/
 obj-$(CONFIG_CAN_C_CAN)                += c_can/
 obj-$(CONFIG_CAN_CTUCANFD)     += ctucanfd/
diff --git a/drivers/net/can/can327.c b/drivers/net/can/can327.c
new file mode 100644 (file)
index 0000000..5da7778
--- /dev/null
@@ -0,0 +1,1137 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ELM327 based CAN interface driver (tty line discipline)
+ *
+ * This driver started as a derivative of linux/drivers/net/can/slcan.c
+ * and my thanks go to the original authors for their inspiration.
+ *
+ * can327.c Author : Max Staudt <max-linux@enpas.org>
+ * slcan.c Author  : Oliver Hartkopp <socketcan@hartkopp.net>
+ * slip.c Authors  : Laurence Culhane <loz@holmes.demon.co.uk>
+ *                   Fred N. van Kempen <waltje@uwalt.nl.mugnet.org>
+ */
+
+#define pr_fmt(fmt) "can327: " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/bitops.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/lockdep.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/tty_ldisc.h>
+#include <linux/workqueue.h>
+
+#include <uapi/linux/tty.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/can/rx-offload.h>
+
+#define CAN327_NAPI_WEIGHT 4
+
+#define CAN327_SIZE_TXBUF 32
+#define CAN327_SIZE_RXBUF 1024
+
+#define CAN327_CAN_CONFIG_SEND_SFF 0x8000
+#define CAN327_CAN_CONFIG_VARIABLE_DLC 0x4000
+#define CAN327_CAN_CONFIG_RECV_BOTH_SFF_EFF 0x2000
+#define CAN327_CAN_CONFIG_BAUDRATE_MULT_8_7 0x1000
+
+#define CAN327_DUMMY_CHAR 'y'
+#define CAN327_DUMMY_STRING "y"
+#define CAN327_READY_CHAR '>'
+
+/* Bits in elm->cmds_todo */
+enum can327_tx_do {
+       CAN327_TX_DO_CAN_DATA = 0,
+       CAN327_TX_DO_CANID_11BIT,
+       CAN327_TX_DO_CANID_29BIT_LOW,
+       CAN327_TX_DO_CANID_29BIT_HIGH,
+       CAN327_TX_DO_CAN_CONFIG_PART2,
+       CAN327_TX_DO_CAN_CONFIG,
+       CAN327_TX_DO_RESPONSES,
+       CAN327_TX_DO_SILENT_MONITOR,
+       CAN327_TX_DO_INIT,
+};
+
+struct can327 {
+       /* This must be the first member when using alloc_candev() */
+       struct can_priv can;
+
+       struct can_rx_offload offload;
+
+       /* TTY buffers */
+       u8 txbuf[CAN327_SIZE_TXBUF];
+       u8 rxbuf[CAN327_SIZE_RXBUF];
+
+       /* Per-channel lock */
+       spinlock_t lock;
+
+       /* TTY and netdev devices that we're bridging */
+       struct tty_struct *tty;
+       struct net_device *dev;
+
+       /* TTY buffer accounting */
+       struct work_struct tx_work;     /* Flushes TTY TX buffer */
+       u8 *txhead;                     /* Next TX byte */
+       size_t txleft;                  /* Bytes left to TX */
+       int rxfill;                     /* Bytes already RX'd in buffer */
+
+       /* State machine */
+       enum {
+               CAN327_STATE_NOTINIT = 0,
+               CAN327_STATE_GETDUMMYCHAR,
+               CAN327_STATE_GETPROMPT,
+               CAN327_STATE_RECEIVING,
+       } state;
+
+       /* Things we have yet to send */
+       char **next_init_cmd;
+       unsigned long cmds_todo;
+
+       /* The CAN frame and config the ELM327 is sending/using,
+        * or will send/use after finishing all cmds_todo
+        */
+       struct can_frame can_frame_to_send;
+       u16 can_config;
+       u8 can_bitrate_divisor;
+
+       /* Parser state */
+       bool drop_next_line;
+
+       /* Stop the channel on UART side hardware failure, e.g. stray
+        * characters or neverending lines. This may be caused by bad
+        * UART wiring, a bad ELM327, a bad UART bridge...
+        * Once this is true, nothing will be sent to the TTY.
+        */
+       bool uart_side_failure;
+};
+
+static inline void can327_uart_side_failure(struct can327 *elm);
+
+static void can327_send(struct can327 *elm, const void *buf, size_t len)
+{
+       int written;
+
+       lockdep_assert_held(&elm->lock);
+
+       if (elm->uart_side_failure)
+               return;
+
+       memcpy(elm->txbuf, buf, len);
+
+       /* Order of next two lines is *very* important.
+        * When we are sending a little amount of data,
+        * the transfer may be completed inside the ops->write()
+        * routine, because it's running with interrupts enabled.
+        * In this case we *never* got WRITE_WAKEUP event,
+        * if we did not request it before write operation.
+        *       14 Oct 1994  Dmitry Gorodchanin.
+        */
+       set_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
+       written = elm->tty->ops->write(elm->tty, elm->txbuf, len);
+       if (written < 0) {
+               netdev_err(elm->dev, "Failed to write to tty %s.\n",
+                          elm->tty->name);
+               can327_uart_side_failure(elm);
+               return;
+       }
+
+       elm->txleft = len - written;
+       elm->txhead = elm->txbuf + written;
+}
+
+/* Take the ELM327 out of almost any state and back into command mode.
+ * We send CAN327_DUMMY_CHAR which will either abort any running
+ * operation, or be echoed back to us in case we're already in command
+ * mode.
+ */
+static void can327_kick_into_cmd_mode(struct can327 *elm)
+{
+       lockdep_assert_held(&elm->lock);
+
+       if (elm->state != CAN327_STATE_GETDUMMYCHAR &&
+           elm->state != CAN327_STATE_GETPROMPT) {
+               can327_send(elm, CAN327_DUMMY_STRING, 1);
+
+               elm->state = CAN327_STATE_GETDUMMYCHAR;
+       }
+}
+
+/* Schedule a CAN frame and necessary config changes to be sent to the TTY. */
+static void can327_send_frame(struct can327 *elm, struct can_frame *frame)
+{
+       lockdep_assert_held(&elm->lock);
+
+       /* Schedule any necessary changes in ELM327's CAN configuration */
+       if (elm->can_frame_to_send.can_id != frame->can_id) {
+               /* Set the new CAN ID for transmission. */
+               if ((frame->can_id ^ elm->can_frame_to_send.can_id)
+                   & CAN_EFF_FLAG) {
+                       elm->can_config =
+                               (frame->can_id & CAN_EFF_FLAG ? 0 : CAN327_CAN_CONFIG_SEND_SFF) |
+                               CAN327_CAN_CONFIG_VARIABLE_DLC |
+                               CAN327_CAN_CONFIG_RECV_BOTH_SFF_EFF |
+                               elm->can_bitrate_divisor;
+
+                       set_bit(CAN327_TX_DO_CAN_CONFIG, &elm->cmds_todo);
+               }
+
+               if (frame->can_id & CAN_EFF_FLAG) {
+                       clear_bit(CAN327_TX_DO_CANID_11BIT, &elm->cmds_todo);
+                       set_bit(CAN327_TX_DO_CANID_29BIT_LOW, &elm->cmds_todo);
+                       set_bit(CAN327_TX_DO_CANID_29BIT_HIGH, &elm->cmds_todo);
+               } else {
+                       set_bit(CAN327_TX_DO_CANID_11BIT, &elm->cmds_todo);
+                       clear_bit(CAN327_TX_DO_CANID_29BIT_LOW,
+                                 &elm->cmds_todo);
+                       clear_bit(CAN327_TX_DO_CANID_29BIT_HIGH,
+                                 &elm->cmds_todo);
+               }
+       }
+
+       /* Schedule the CAN frame itself. */
+       elm->can_frame_to_send = *frame;
+       set_bit(CAN327_TX_DO_CAN_DATA, &elm->cmds_todo);
+
+       can327_kick_into_cmd_mode(elm);
+}
+
+/* ELM327 initialisation sequence.
+ * The line length is limited by the buffer in can327_handle_prompt().
+ */
+static char *can327_init_script[] = {
+       "AT WS\r",        /* v1.0: Warm Start */
+       "AT PP FF OFF\r", /* v1.0: All Programmable Parameters Off */
+       "AT M0\r",        /* v1.0: Memory Off */
+       "AT AL\r",        /* v1.0: Allow Long messages */
+       "AT BI\r",        /* v1.0: Bypass Initialisation */
+       "AT CAF0\r",      /* v1.0: CAN Auto Formatting Off */
+       "AT CFC0\r",      /* v1.0: CAN Flow Control Off */
+       "AT CF 000\r",    /* v1.0: Reset CAN ID Filter */
+       "AT CM 000\r",    /* v1.0: Reset CAN ID Mask */
+       "AT E1\r",        /* v1.0: Echo On */
+       "AT H1\r",        /* v1.0: Headers On */
+       "AT L0\r",        /* v1.0: Linefeeds Off */
+       "AT SH 7DF\r",    /* v1.0: Set CAN sending ID to 0x7df */
+       "AT ST FF\r",     /* v1.0: Set maximum Timeout for response after TX */
+       "AT AT0\r",       /* v1.2: Adaptive Timing Off */
+       "AT D1\r",        /* v1.3: Print DLC On */
+       "AT S1\r",        /* v1.3: Spaces On */
+       "AT TP B\r",      /* v1.0: Try Protocol B */
+       NULL
+};
+
+static void can327_init_device(struct can327 *elm)
+{
+       lockdep_assert_held(&elm->lock);
+
+       elm->state = CAN327_STATE_NOTINIT;
+       elm->can_frame_to_send.can_id = 0x7df; /* ELM327 HW default */
+       elm->rxfill = 0;
+       elm->drop_next_line = 0;
+
+       /* We can only set the bitrate as a fraction of 500000.
+        * The bitrates listed in can327_bitrate_const will
+        * limit the user to the right values.
+        */
+       elm->can_bitrate_divisor = 500000 / elm->can.bittiming.bitrate;
+       elm->can_config =
+               CAN327_CAN_CONFIG_SEND_SFF | CAN327_CAN_CONFIG_VARIABLE_DLC |
+               CAN327_CAN_CONFIG_RECV_BOTH_SFF_EFF | elm->can_bitrate_divisor;
+
+       /* Configure ELM327 and then start monitoring */
+       elm->next_init_cmd = &can327_init_script[0];
+       set_bit(CAN327_TX_DO_INIT, &elm->cmds_todo);
+       set_bit(CAN327_TX_DO_SILENT_MONITOR, &elm->cmds_todo);
+       set_bit(CAN327_TX_DO_RESPONSES, &elm->cmds_todo);
+       set_bit(CAN327_TX_DO_CAN_CONFIG, &elm->cmds_todo);
+
+       can327_kick_into_cmd_mode(elm);
+}
+
+static void can327_feed_frame_to_netdev(struct can327 *elm, struct sk_buff *skb)
+{
+       lockdep_assert_held(&elm->lock);
+
+       if (!netif_running(elm->dev))
+               return;
+
+       /* Queue for NAPI pickup.
+        * rx-offload will update stats and LEDs for us.
+        */
+       if (can_rx_offload_queue_tail(&elm->offload, skb))
+               elm->dev->stats.rx_fifo_errors++;
+
+       /* Wake NAPI */
+       can_rx_offload_irq_finish(&elm->offload);
+}
+
+/* Called when we're out of ideas and just want it all to end. */
+static inline void can327_uart_side_failure(struct can327 *elm)
+{
+       struct can_frame *frame;
+       struct sk_buff *skb;
+
+       lockdep_assert_held(&elm->lock);
+
+       elm->uart_side_failure = true;
+
+       clear_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
+
+       elm->can.can_stats.bus_off++;
+       netif_stop_queue(elm->dev);
+       elm->can.state = CAN_STATE_BUS_OFF;
+       can_bus_off(elm->dev);
+
+       netdev_err(elm->dev,
+                  "ELM327 misbehaved. Blocking further communication.\n");
+
+       skb = alloc_can_err_skb(elm->dev, &frame);
+       if (!skb)
+               return;
+
+       frame->can_id |= CAN_ERR_BUSOFF;
+       can327_feed_frame_to_netdev(elm, skb);
+}
+
+/* Compares a byte buffer (non-NUL terminated) to the payload part of
+ * a string, and returns true iff the buffer (content *and* length) is
+ * exactly that string, without the terminating NUL byte.
+ *
+ * Example: If reference is "BUS ERROR", then this returns true iff nbytes == 9
+ *          and !memcmp(buf, "BUS ERROR", 9).
+ *
+ * The reason to use strings is so we can easily include them in the C
+ * code, and to avoid hardcoding lengths.
+ */
+static inline bool can327_rxbuf_cmp(const u8 *buf, size_t nbytes,
+                                   const char *reference)
+{
+       size_t ref_len = strlen(reference);
+
+       return (nbytes == ref_len) && !memcmp(buf, reference, ref_len);
+}
+
+static void can327_parse_error(struct can327 *elm, size_t len)
+{
+       struct can_frame *frame;
+       struct sk_buff *skb;
+
+       lockdep_assert_held(&elm->lock);
+
+       skb = alloc_can_err_skb(elm->dev, &frame);
+       if (!skb)
+               /* It's okay to return here:
+                * The outer parsing loop will drop this UART buffer.
+                */
+               return;
+
+       /* Filter possible error messages based on length of RX'd line */
+       if (can327_rxbuf_cmp(elm->rxbuf, len, "UNABLE TO CONNECT")) {
+               netdev_err(elm->dev,
+                          "ELM327 reported UNABLE TO CONNECT. Please check your setup.\n");
+       } else if (can327_rxbuf_cmp(elm->rxbuf, len, "BUFFER FULL")) {
+               /* This will only happen if the last data line was complete.
+                * Otherwise, can327_parse_frame() will heuristically
+                * emit this kind of error frame instead.
+                */
+               frame->can_id |= CAN_ERR_CRTL;
+               frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+       } else if (can327_rxbuf_cmp(elm->rxbuf, len, "BUS ERROR")) {
+               frame->can_id |= CAN_ERR_BUSERROR;
+       } else if (can327_rxbuf_cmp(elm->rxbuf, len, "CAN ERROR")) {
+               frame->can_id |= CAN_ERR_PROT;
+       } else if (can327_rxbuf_cmp(elm->rxbuf, len, "<RX ERROR")) {
+               frame->can_id |= CAN_ERR_PROT;
+       } else if (can327_rxbuf_cmp(elm->rxbuf, len, "BUS BUSY")) {
+               frame->can_id |= CAN_ERR_PROT;
+               frame->data[2] = CAN_ERR_PROT_OVERLOAD;
+       } else if (can327_rxbuf_cmp(elm->rxbuf, len, "FB ERROR")) {
+               frame->can_id |= CAN_ERR_PROT;
+               frame->data[2] = CAN_ERR_PROT_TX;
+       } else if (len == 5 && !memcmp(elm->rxbuf, "ERR", 3)) {
+               /* ERR is followed by two digits, hence line length 5 */
+               netdev_err(elm->dev, "ELM327 reported an ERR%c%c. Please power it off and on again.\n",
+                          elm->rxbuf[3], elm->rxbuf[4]);
+               frame->can_id |= CAN_ERR_CRTL;
+       } else {
+               /* Something else has happened.
+                * Maybe garbage on the UART line.
+                * Emit a generic error frame.
+                */
+       }
+
+       can327_feed_frame_to_netdev(elm, skb);
+}
+
+/* Parse CAN frames coming as ASCII from ELM327.
+ * They can be of various formats:
+ *
+ * 29-bit ID (EFF):  12 34 56 78 D PL PL PL PL PL PL PL PL
+ * 11-bit ID (!EFF): 123 D PL PL PL PL PL PL PL PL
+ *
+ * where D = DLC, PL = payload byte
+ *
+ * Instead of a payload, RTR indicates a remote request.
+ *
+ * We will use the spaces and line length to guess the format.
+ */
+static int can327_parse_frame(struct can327 *elm, size_t len)
+{
+       struct can_frame *frame;
+       struct sk_buff *skb;
+       int hexlen;
+       int datastart;
+       int i;
+
+       lockdep_assert_held(&elm->lock);
+
+       skb = alloc_can_skb(elm->dev, &frame);
+       if (!skb)
+               return -ENOMEM;
+
+       /* Find first non-hex and non-space character:
+        *  - In the simplest case, there is none.
+        *  - For RTR frames, 'R' is the first non-hex character.
+        *  - An error message may replace the end of the data line.
+        */
+       for (hexlen = 0; hexlen <= len; hexlen++) {
+               if (hex_to_bin(elm->rxbuf[hexlen]) < 0 &&
+                   elm->rxbuf[hexlen] != ' ') {
+                       break;
+               }
+       }
+
+       /* Sanity check whether the line is really a clean hexdump,
+        * or terminated by an error message, or contains garbage.
+        */
+       if (hexlen < len && !isdigit(elm->rxbuf[hexlen]) &&
+           !isupper(elm->rxbuf[hexlen]) && '<' != elm->rxbuf[hexlen] &&
+           ' ' != elm->rxbuf[hexlen]) {
+               /* The line is likely garbled anyway, so bail.
+                * The main code will restart listening.
+                */
+               kfree_skb(skb);
+               return -ENODATA;
+       }
+
+       /* Use spaces in CAN ID to distinguish 29 or 11 bit address length.
+        * No out-of-bounds access:
+        * We use the fact that we can always read from elm->rxbuf.
+        */
+       if (elm->rxbuf[2] == ' ' && elm->rxbuf[5] == ' ' &&
+           elm->rxbuf[8] == ' ' && elm->rxbuf[11] == ' ' &&
+           elm->rxbuf[13] == ' ') {
+               frame->can_id = CAN_EFF_FLAG;
+               datastart = 14;
+       } else if (elm->rxbuf[3] == ' ' && elm->rxbuf[5] == ' ') {
+               datastart = 6;
+       } else {
+               /* This is not a well-formatted data line.
+                * Assume it's an error message.
+                */
+               kfree_skb(skb);
+               return -ENODATA;
+       }
+
+       if (hexlen < datastart) {
+               /* The line is too short to be a valid frame hex dump.
+                * Something interrupted the hex dump or it is invalid.
+                */
+               kfree_skb(skb);
+               return -ENODATA;
+       }
+
+       /* From here on all chars up to buf[hexlen] are hex or spaces,
+        * at well-defined offsets.
+        */
+
+       /* Read CAN data length */
+       frame->len = (hex_to_bin(elm->rxbuf[datastart - 2]) << 0);
+
+       /* Read CAN ID */
+       if (frame->can_id & CAN_EFF_FLAG) {
+               frame->can_id |= (hex_to_bin(elm->rxbuf[0]) << 28) |
+                                (hex_to_bin(elm->rxbuf[1]) << 24) |
+                                (hex_to_bin(elm->rxbuf[3]) << 20) |
+                                (hex_to_bin(elm->rxbuf[4]) << 16) |
+                                (hex_to_bin(elm->rxbuf[6]) << 12) |
+                                (hex_to_bin(elm->rxbuf[7]) << 8) |
+                                (hex_to_bin(elm->rxbuf[9]) << 4) |
+                                (hex_to_bin(elm->rxbuf[10]) << 0);
+       } else {
+               frame->can_id |= (hex_to_bin(elm->rxbuf[0]) << 8) |
+                                (hex_to_bin(elm->rxbuf[1]) << 4) |
+                                (hex_to_bin(elm->rxbuf[2]) << 0);
+       }
+
+       /* Check for RTR frame */
+       if (elm->rxfill >= hexlen + 3 &&
+           !memcmp(&elm->rxbuf[hexlen], "RTR", 3)) {
+               frame->can_id |= CAN_RTR_FLAG;
+       }
+
+       /* Is the line long enough to hold the advertised payload?
+        * Note: RTR frames have a DLC, but no actual payload.
+        */
+       if (!(frame->can_id & CAN_RTR_FLAG) &&
+           (hexlen < frame->len * 3 + datastart)) {
+               /* Incomplete frame.
+                * Probably the ELM327's RS232 TX buffer was full.
+                * Emit an error frame and exit.
+                */
+               frame->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
+               frame->len = CAN_ERR_DLC;
+               frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+               can327_feed_frame_to_netdev(elm, skb);
+
+               /* Signal failure to parse.
+                * The line will be re-parsed as an error line, which will fail.
+                * However, this will correctly drop the state machine back into
+                * command mode.
+                */
+               return -ENODATA;
+       }
+
+       /* Parse the data nibbles. */
+       for (i = 0; i < frame->len; i++) {
+               frame->data[i] =
+                       (hex_to_bin(elm->rxbuf[datastart + 3 * i]) << 4) |
+                       (hex_to_bin(elm->rxbuf[datastart + 3 * i + 1]));
+       }
+
+       /* Feed the frame to the network layer. */
+       can327_feed_frame_to_netdev(elm, skb);
+
+       return 0;
+}
+
+static void can327_parse_line(struct can327 *elm, size_t len)
+{
+       lockdep_assert_held(&elm->lock);
+
+       /* Skip empty lines */
+       if (!len)
+               return;
+
+       /* Skip echo lines */
+       if (elm->drop_next_line) {
+               elm->drop_next_line = 0;
+               return;
+       } else if (!memcmp(elm->rxbuf, "AT", 2)) {
+               return;
+       }
+
+       /* Regular parsing */
+       if (elm->state == CAN327_STATE_RECEIVING &&
+           can327_parse_frame(elm, len)) {
+               /* Parse an error line. */
+               can327_parse_error(elm, len);
+
+               /* Start afresh. */
+               can327_kick_into_cmd_mode(elm);
+       }
+}
+
+static void can327_handle_prompt(struct can327 *elm)
+{
+       struct can_frame *frame = &elm->can_frame_to_send;
+       /* Size this buffer for the largest ELM327 line we may generate,
+        * which is currently an 8 byte CAN frame's payload hexdump.
+        * Items in can327_init_script must fit here, too!
+        */
+       char local_txbuf[sizeof("0102030405060708\r")];
+
+       lockdep_assert_held(&elm->lock);
+
+       if (!elm->cmds_todo) {
+               /* Enter CAN monitor mode */
+               can327_send(elm, "ATMA\r", 5);
+               elm->state = CAN327_STATE_RECEIVING;
+
+               /* We will be in the default state once this command is
+                * sent, so enable the TX packet queue.
+                */
+               netif_wake_queue(elm->dev);
+
+               return;
+       }
+
+       /* Reconfigure ELM327 step by step as indicated by elm->cmds_todo */
+       if (test_bit(CAN327_TX_DO_INIT, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf), "%s",
+                        *elm->next_init_cmd);
+
+               elm->next_init_cmd++;
+               if (!(*elm->next_init_cmd)) {
+                       clear_bit(CAN327_TX_DO_INIT, &elm->cmds_todo);
+                       /* Init finished. */
+               }
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_SILENT_MONITOR, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATCSM%i\r",
+                        !!(elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_RESPONSES, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATR%i\r",
+                        !(elm->can.ctrlmode & CAN_CTRLMODE_LISTENONLY));
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_CAN_CONFIG, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATPC\r");
+               set_bit(CAN327_TX_DO_CAN_CONFIG_PART2, &elm->cmds_todo);
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_CAN_CONFIG_PART2, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATPB%04X\r",
+                        elm->can_config);
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_CANID_29BIT_HIGH, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATCP%02X\r",
+                        (frame->can_id & CAN_EFF_MASK) >> 24);
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_CANID_29BIT_LOW, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATSH%06X\r",
+                        frame->can_id & CAN_EFF_MASK & ((1 << 24) - 1));
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_CANID_11BIT, &elm->cmds_todo)) {
+               snprintf(local_txbuf, sizeof(local_txbuf),
+                        "ATSH%03X\r",
+                        frame->can_id & CAN_SFF_MASK);
+
+       } else if (test_and_clear_bit(CAN327_TX_DO_CAN_DATA, &elm->cmds_todo)) {
+               if (frame->can_id & CAN_RTR_FLAG) {
+                       /* Send an RTR frame. Their DLC is fixed.
+                        * Some chips don't send them at all.
+                        */
+                       snprintf(local_txbuf, sizeof(local_txbuf), "ATRTR\r");
+               } else {
+                       /* Send a regular CAN data frame */
+                       int i;
+
+                       for (i = 0; i < frame->len; i++) {
+                               snprintf(&local_txbuf[2 * i],
+                                        sizeof(local_txbuf), "%02X",
+                                        frame->data[i]);
+                       }
+
+                       snprintf(&local_txbuf[2 * i], sizeof(local_txbuf),
+                                "\r");
+               }
+
+               elm->drop_next_line = 1;
+               elm->state = CAN327_STATE_RECEIVING;
+
+               /* We will be in the default state once this command is
+                * sent, so enable the TX packet queue.
+                */
+               netif_wake_queue(elm->dev);
+       }
+
+       can327_send(elm, local_txbuf, strlen(local_txbuf));
+}
+
+static bool can327_is_ready_char(char c)
+{
+       /* Bits 0xc0 are sometimes set (randomly), hence the mask.
+        * Probably bad hardware.
+        */
+       return (c & 0x3f) == CAN327_READY_CHAR;
+}
+
+static void can327_drop_bytes(struct can327 *elm, size_t i)
+{
+       lockdep_assert_held(&elm->lock);
+
+       memmove(&elm->rxbuf[0], &elm->rxbuf[i], CAN327_SIZE_RXBUF - i);
+       elm->rxfill -= i;
+}
+
+static void can327_parse_rxbuf(struct can327 *elm, size_t first_new_char_idx)
+{
+       size_t len, pos;
+
+       lockdep_assert_held(&elm->lock);
+
+       switch (elm->state) {
+       case CAN327_STATE_NOTINIT:
+               elm->rxfill = 0;
+               break;
+
+       case CAN327_STATE_GETDUMMYCHAR:
+               /* Wait for 'y' or '>' */
+               for (pos = 0; pos < elm->rxfill; pos++) {
+                       if (elm->rxbuf[pos] == CAN327_DUMMY_CHAR) {
+                               can327_send(elm, "\r", 1);
+                               elm->state = CAN327_STATE_GETPROMPT;
+                               pos++;
+                               break;
+                       } else if (can327_is_ready_char(elm->rxbuf[pos])) {
+                               can327_send(elm, CAN327_DUMMY_STRING, 1);
+                               pos++;
+                               break;
+                       }
+               }
+
+               can327_drop_bytes(elm, pos);
+               break;
+
+       case CAN327_STATE_GETPROMPT:
+               /* Wait for '>' */
+               if (can327_is_ready_char(elm->rxbuf[elm->rxfill - 1]))
+                       can327_handle_prompt(elm);
+
+               elm->rxfill = 0;
+               break;
+
+       case CAN327_STATE_RECEIVING:
+               /* Find <CR> delimiting feedback lines. */
+               len = first_new_char_idx;
+               while (len < elm->rxfill && elm->rxbuf[len] != '\r')
+                       len++;
+
+               if (len == CAN327_SIZE_RXBUF) {
+                       /* Assume the buffer ran full with garbage.
+                        * Did we even connect at the right baud rate?
+                        */
+                       netdev_err(elm->dev,
+                                  "RX buffer overflow. Faulty ELM327 or UART?\n");
+                       can327_uart_side_failure(elm);
+               } else if (len == elm->rxfill) {
+                       if (can327_is_ready_char(elm->rxbuf[elm->rxfill - 1])) {
+                               /* The ELM327's AT ST response timeout ran out,
+                                * so we got a prompt.
+                                * Clear RX buffer and restart listening.
+                                */
+                               elm->rxfill = 0;
+
+                               can327_handle_prompt(elm);
+                       }
+
+                       /* No <CR> found - we haven't received a full line yet.
+                        * Wait for more data.
+                        */
+               } else {
+                       /* We have a full line to parse. */
+                       can327_parse_line(elm, len);
+
+                       /* Remove parsed data from RX buffer. */
+                       can327_drop_bytes(elm, len + 1);
+
+                       /* More data to parse? */
+                       if (elm->rxfill)
+                               can327_parse_rxbuf(elm, 0);
+               }
+       }
+}
+
+static int can327_netdev_open(struct net_device *dev)
+{
+       struct can327 *elm = netdev_priv(dev);
+       int err;
+
+       spin_lock_bh(&elm->lock);
+
+       if (!elm->tty) {
+               spin_unlock_bh(&elm->lock);
+               return -ENODEV;
+       }
+
+       if (elm->uart_side_failure)
+               netdev_warn(elm->dev,
+                           "Reopening netdev after a UART side fault has been detected.\n");
+
+       /* Clear TTY buffers */
+       elm->rxfill = 0;
+       elm->txleft = 0;
+
+       /* open_candev() checks for elm->can.bittiming.bitrate != 0 */
+       err = open_candev(dev);
+       if (err) {
+               spin_unlock_bh(&elm->lock);
+               return err;
+       }
+
+       can327_init_device(elm);
+       spin_unlock_bh(&elm->lock);
+
+       err = can_rx_offload_add_manual(dev, &elm->offload, CAN327_NAPI_WEIGHT);
+       if (err) {
+               close_candev(dev);
+               return err;
+       }
+
+       can_rx_offload_enable(&elm->offload);
+
+       elm->can.state = CAN_STATE_ERROR_ACTIVE;
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static int can327_netdev_close(struct net_device *dev)
+{
+       struct can327 *elm = netdev_priv(dev);
+
+       /* Interrupt whatever the ELM327 is doing right now */
+       spin_lock_bh(&elm->lock);
+       can327_send(elm, CAN327_DUMMY_STRING, 1);
+       spin_unlock_bh(&elm->lock);
+
+       netif_stop_queue(dev);
+
+       /* Give UART one final chance to flush. */
+       clear_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
+       flush_work(&elm->tx_work);
+
+       can_rx_offload_disable(&elm->offload);
+       elm->can.state = CAN_STATE_STOPPED;
+       can_rx_offload_del(&elm->offload);
+       close_candev(dev);
+
+       return 0;
+}
+
+/* Send a can_frame to a TTY. */
+static netdev_tx_t can327_netdev_start_xmit(struct sk_buff *skb,
+                                           struct net_device *dev)
+{
+       struct can327 *elm = netdev_priv(dev);
+       struct can_frame *frame = (struct can_frame *)skb->data;
+
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
+
+       /* We shouldn't get here after a hardware fault:
+        * can_bus_off() calls netif_carrier_off()
+        */
+       if (elm->uart_side_failure) {
+               WARN_ON_ONCE(elm->uart_side_failure);
+               goto out;
+       }
+
+       netif_stop_queue(dev);
+
+       /* BHs are already disabled, so no spin_lock_bh().
+        * See Documentation/networking/netdevices.txt
+        */
+       spin_lock(&elm->lock);
+       can327_send_frame(elm, frame);
+       spin_unlock(&elm->lock);
+
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += frame->can_id & CAN_RTR_FLAG ? 0 : frame->len;
+
+out:
+       kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static const struct net_device_ops can327_netdev_ops = {
+       .ndo_open = can327_netdev_open,
+       .ndo_stop = can327_netdev_close,
+       .ndo_start_xmit = can327_netdev_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
+};
+
+static bool can327_is_valid_rx_char(u8 c)
+{
+       static const bool lut_char_is_valid['z'] = {
+               ['\r'] = true,
+               [' '] = true,
+               ['.'] = true,
+               ['0'] = true, true, true, true, true,
+               ['5'] = true, true, true, true, true,
+               ['<'] = true,
+               [CAN327_READY_CHAR] = true,
+               ['?'] = true,
+               ['A'] = true, true, true, true, true, true, true,
+               ['H'] = true, true, true, true, true, true, true,
+               ['O'] = true, true, true, true, true, true, true,
+               ['V'] = true, true, true, true, true,
+               ['a'] = true,
+               ['b'] = true,
+               ['v'] = true,
+               [CAN327_DUMMY_CHAR] = true,
+       };
+       BUILD_BUG_ON(CAN327_DUMMY_CHAR >= 'z');
+
+       return (c < ARRAY_SIZE(lut_char_is_valid) && lut_char_is_valid[c]);
+}
+
+/* Handle incoming ELM327 ASCII data.
+ * This will not be re-entered while running, but other ldisc
+ * functions may be called in parallel.
+ */
+static void can327_ldisc_rx(struct tty_struct *tty, const unsigned char *cp,
+                           const char *fp, int count)
+{
+       struct can327 *elm = (struct can327 *)tty->disc_data;
+       size_t first_new_char_idx;
+
+       if (elm->uart_side_failure)
+               return;
+
+       spin_lock_bh(&elm->lock);
+
+       /* Store old rxfill, so can327_parse_rxbuf() will have
+        * the option of skipping already checked characters.
+        */
+       first_new_char_idx = elm->rxfill;
+
+       while (count-- && elm->rxfill < CAN327_SIZE_RXBUF) {
+               if (fp && *fp++) {
+                       netdev_err(elm->dev,
+                                  "Error in received character stream. Check your wiring.");
+
+                       can327_uart_side_failure(elm);
+
+                       spin_unlock_bh(&elm->lock);
+                       return;
+               }
+
+               /* Ignore NUL characters, which the PIC microcontroller may
+                * inadvertently insert due to a known hardware bug.
+                * See ELM327 documentation, which refers to a Microchip PIC
+                * bug description.
+                */
+               if (*cp) {
+                       /* Check for stray characters on the UART line.
+                        * Likely caused by bad hardware.
+                        */
+                       if (!can327_is_valid_rx_char(*cp)) {
+                               netdev_err(elm->dev,
+                                          "Received illegal character %02x.\n",
+                                          *cp);
+                               can327_uart_side_failure(elm);
+
+                               spin_unlock_bh(&elm->lock);
+                               return;
+                       }
+
+                       elm->rxbuf[elm->rxfill++] = *cp;
+               }
+
+               cp++;
+       }
+
+       if (count >= 0) {
+               netdev_err(elm->dev,
+                          "Receive buffer overflowed. Bad chip or wiring? count = %i",
+                          count);
+
+               can327_uart_side_failure(elm);
+
+               spin_unlock_bh(&elm->lock);
+               return;
+       }
+
+       can327_parse_rxbuf(elm, first_new_char_idx);
+       spin_unlock_bh(&elm->lock);
+}
+
+/* Write out remaining transmit buffer.
+ * Scheduled when TTY is writable.
+ */
+static void can327_ldisc_tx_worker(struct work_struct *work)
+{
+       struct can327 *elm = container_of(work, struct can327, tx_work);
+       ssize_t written;
+
+       if (elm->uart_side_failure)
+               return;
+
+       spin_lock_bh(&elm->lock);
+
+       if (elm->txleft) {
+               written = elm->tty->ops->write(elm->tty, elm->txhead,
+                                              elm->txleft);
+               if (written < 0) {
+                       netdev_err(elm->dev, "Failed to write to tty %s.\n",
+                                  elm->tty->name);
+                       can327_uart_side_failure(elm);
+
+                       spin_unlock_bh(&elm->lock);
+                       return;
+               }
+
+               elm->txleft -= written;
+               elm->txhead += written;
+       }
+
+       if (!elm->txleft)
+               clear_bit(TTY_DO_WRITE_WAKEUP, &elm->tty->flags);
+
+       spin_unlock_bh(&elm->lock);
+}
+
+/* Called by the driver when there's room for more data. */
+static void can327_ldisc_tx_wakeup(struct tty_struct *tty)
+{
+       struct can327 *elm = (struct can327 *)tty->disc_data;
+
+       schedule_work(&elm->tx_work);
+}
+
+/* ELM327 can only handle bitrates that are integer divisors of 500 kHz,
+ * or 7/8 of that. Divisors are 1 to 64.
+ * Currently we don't implement support for 7/8 rates.
+ */
+static const u32 can327_bitrate_const[] = {
+       7812,  7936,  8064,  8196,   8333,   8474,   8620,   8771,
+       8928,  9090,  9259,  9433,   9615,   9803,   10000,  10204,
+       10416, 10638, 10869, 11111,  11363,  11627,  11904,  12195,
+       12500, 12820, 13157, 13513,  13888,  14285,  14705,  15151,
+       15625, 16129, 16666, 17241,  17857,  18518,  19230,  20000,
+       20833, 21739, 22727, 23809,  25000,  26315,  27777,  29411,
+       31250, 33333, 35714, 38461,  41666,  45454,  50000,  55555,
+       62500, 71428, 83333, 100000, 125000, 166666, 250000, 500000
+};
+
+static int can327_ldisc_open(struct tty_struct *tty)
+{
+       struct net_device *dev;
+       struct can327 *elm;
+       int err;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (!tty->ops->write)
+               return -EOPNOTSUPP;
+
+       dev = alloc_candev(sizeof(struct can327), 0);
+       if (!dev)
+               return -ENFILE;
+       elm = netdev_priv(dev);
+
+       /* Configure TTY interface */
+       tty->receive_room = 65536; /* We don't flow control */
+       spin_lock_init(&elm->lock);
+       INIT_WORK(&elm->tx_work, can327_ldisc_tx_worker);
+
+       /* Configure CAN metadata */
+       elm->can.bitrate_const = can327_bitrate_const;
+       elm->can.bitrate_const_cnt = ARRAY_SIZE(can327_bitrate_const);
+       elm->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY;
+
+       /* Configure netdev interface */
+       elm->dev = dev;
+       dev->netdev_ops = &can327_netdev_ops;
+
+       /* Mark ldisc channel as alive */
+       elm->tty = tty;
+       tty->disc_data = elm;
+
+       /* Let 'er rip */
+       err = register_candev(elm->dev);
+       if (err) {
+               free_candev(elm->dev);
+               return err;
+       }
+
+       netdev_info(elm->dev, "can327 on %s.\n", tty->name);
+
+       return 0;
+}
+
+/* Close down a can327 channel.
+ * This means flushing out any pending queues, and then returning.
+ * This call is serialized against other ldisc functions:
+ * Once this is called, no other ldisc function of ours is entered.
+ *
+ * We also use this function for a hangup event.
+ */
+static void can327_ldisc_close(struct tty_struct *tty)
+{
+       struct can327 *elm = (struct can327 *)tty->disc_data;
+
+       /* unregister_netdev() calls .ndo_stop() so we don't have to.
+        * Our .ndo_stop() also flushes the TTY write wakeup handler,
+        * so we can safely set elm->tty = NULL after this.
+        */
+       unregister_candev(elm->dev);
+
+       /* Mark channel as dead */
+       spin_lock_bh(&elm->lock);
+       tty->disc_data = NULL;
+       elm->tty = NULL;
+       spin_unlock_bh(&elm->lock);
+
+       netdev_info(elm->dev, "can327 off %s.\n", tty->name);
+
+       free_candev(elm->dev);
+}
+
+static int can327_ldisc_ioctl(struct tty_struct *tty, unsigned int cmd,
+                             unsigned long arg)
+{
+       struct can327 *elm = (struct can327 *)tty->disc_data;
+       unsigned int tmp;
+
+       switch (cmd) {
+       case SIOCGIFNAME:
+               tmp = strnlen(elm->dev->name, IFNAMSIZ - 1) + 1;
+               if (copy_to_user((void __user *)arg, elm->dev->name, tmp))
+                       return -EFAULT;
+               return 0;
+
+       case SIOCSIFHWADDR:
+               return -EINVAL;
+
+       default:
+               return tty_mode_ioctl(tty, cmd, arg);
+       }
+}
+
+static struct tty_ldisc_ops can327_ldisc = {
+       .owner = THIS_MODULE,
+       .name = "can327",
+       .num = N_CAN327,
+       .receive_buf = can327_ldisc_rx,
+       .write_wakeup = can327_ldisc_tx_wakeup,
+       .open = can327_ldisc_open,
+       .close = can327_ldisc_close,
+       .ioctl = can327_ldisc_ioctl,
+};
+
+static int __init can327_init(void)
+{
+       int status;
+
+       status = tty_register_ldisc(&can327_ldisc);
+       if (status)
+               pr_err("Can't register line discipline\n");
+
+       return status;
+}
+
+static void __exit can327_exit(void)
+{
+       /* This will only be called when all channels have been closed by
+        * userspace - tty_ldisc.c takes care of the module's refcount.
+        */
+       tty_unregister_ldisc(&can327_ldisc);
+}
+
+module_init(can327_init);
+module_exit(can327_exit);
+
+MODULE_ALIAS_LDISC(N_CAN327);
+MODULE_DESCRIPTION("ELM327 based CAN interface");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Max Staudt <max@enpas.org>");
index 64990bf..14ac7c0 100644 (file)
@@ -1087,7 +1087,7 @@ clear:
 /**
  * ctucan_interrupt() - CAN Isr
  * @irq:       irq number
- * @dev_id:    device id poniter
+ * @dev_id:    device id pointer
  *
  * This is the CTU CAN FD ISR. It checks for the type of interrupt
  * and invokes the corresponding ISR.
index af2901d..633687d 100644 (file)
@@ -1,9 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_CAN_DEV)          += can-dev.o
-can-dev-y                      += bittiming.o
-can-dev-y                      += dev.o
-can-dev-y                      += length.o
-can-dev-y                      += netlink.o
-can-dev-y                      += rx-offload.o
-can-dev-y                       += skb.o
+obj-$(CONFIG_CAN_DEV) += can-dev.o
+
+can-dev-y += skb.o
+
+can-dev-$(CONFIG_CAN_CALC_BITTIMING) += calc_bittiming.o
+can-dev-$(CONFIG_CAN_NETLINK) += bittiming.o
+can-dev-$(CONFIG_CAN_NETLINK) += dev.o
+can-dev-$(CONFIG_CAN_NETLINK) += length.o
+can-dev-$(CONFIG_CAN_NETLINK) += netlink.o
+can-dev-$(CONFIG_CAN_RX_OFFLOAD) += rx-offload.o
index c1e76f0..7ae8076 100644 (file)
@@ -4,205 +4,8 @@
  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
  */
 
-#include <linux/units.h>
 #include <linux/can/dev.h>
 
-#ifdef CONFIG_CAN_CALC_BITTIMING
-#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
-
-/* Bit-timing calculation derived from:
- *
- * Code based on LinCAN sources and H8S2638 project
- * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
- * Copyright 2005      Stanislav Marek
- * email: pisa@cmp.felk.cvut.cz
- *
- * Calculates proper bit-timing parameters for a specified bit-rate
- * and sample-point, which can then be used to set the bit-timing
- * registers of the CAN controller. You can find more information
- * in the header file linux/can/netlink.h.
- */
-static int
-can_update_sample_point(const struct can_bittiming_const *btc,
-                       const unsigned int sample_point_nominal, const unsigned int tseg,
-                       unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
-                       unsigned int *sample_point_error_ptr)
-{
-       unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
-       unsigned int sample_point, best_sample_point = 0;
-       unsigned int tseg1, tseg2;
-       int i;
-
-       for (i = 0; i <= 1; i++) {
-               tseg2 = tseg + CAN_SYNC_SEG -
-                       (sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
-                       1000 - i;
-               tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
-               tseg1 = tseg - tseg2;
-               if (tseg1 > btc->tseg1_max) {
-                       tseg1 = btc->tseg1_max;
-                       tseg2 = tseg - tseg1;
-               }
-
-               sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
-                       (tseg + CAN_SYNC_SEG);
-               sample_point_error = abs(sample_point_nominal - sample_point);
-
-               if (sample_point <= sample_point_nominal &&
-                   sample_point_error < best_sample_point_error) {
-                       best_sample_point = sample_point;
-                       best_sample_point_error = sample_point_error;
-                       *tseg1_ptr = tseg1;
-                       *tseg2_ptr = tseg2;
-               }
-       }
-
-       if (sample_point_error_ptr)
-               *sample_point_error_ptr = best_sample_point_error;
-
-       return best_sample_point;
-}
-
-int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
-                      const struct can_bittiming_const *btc)
-{
-       struct can_priv *priv = netdev_priv(dev);
-       unsigned int bitrate;                   /* current bitrate */
-       unsigned int bitrate_error;             /* difference between current and nominal value */
-       unsigned int best_bitrate_error = UINT_MAX;
-       unsigned int sample_point_error;        /* difference between current and nominal value */
-       unsigned int best_sample_point_error = UINT_MAX;
-       unsigned int sample_point_nominal;      /* nominal sample point */
-       unsigned int best_tseg = 0;             /* current best value for tseg */
-       unsigned int best_brp = 0;              /* current best value for brp */
-       unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
-       u64 v64;
-
-       /* Use CiA recommended sample points */
-       if (bt->sample_point) {
-               sample_point_nominal = bt->sample_point;
-       } else {
-               if (bt->bitrate > 800 * KILO /* BPS */)
-                       sample_point_nominal = 750;
-               else if (bt->bitrate > 500 * KILO /* BPS */)
-                       sample_point_nominal = 800;
-               else
-                       sample_point_nominal = 875;
-       }
-
-       /* tseg even = round down, odd = round up */
-       for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
-            tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
-               tsegall = CAN_SYNC_SEG + tseg / 2;
-
-               /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
-               brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
-
-               /* choose brp step which is possible in system */
-               brp = (brp / btc->brp_inc) * btc->brp_inc;
-               if (brp < btc->brp_min || brp > btc->brp_max)
-                       continue;
-
-               bitrate = priv->clock.freq / (brp * tsegall);
-               bitrate_error = abs(bt->bitrate - bitrate);
-
-               /* tseg brp biterror */
-               if (bitrate_error > best_bitrate_error)
-                       continue;
-
-               /* reset sample point error if we have a better bitrate */
-               if (bitrate_error < best_bitrate_error)
-                       best_sample_point_error = UINT_MAX;
-
-               can_update_sample_point(btc, sample_point_nominal, tseg / 2,
-                                       &tseg1, &tseg2, &sample_point_error);
-               if (sample_point_error >= best_sample_point_error)
-                       continue;
-
-               best_sample_point_error = sample_point_error;
-               best_bitrate_error = bitrate_error;
-               best_tseg = tseg / 2;
-               best_brp = brp;
-
-               if (bitrate_error == 0 && sample_point_error == 0)
-                       break;
-       }
-
-       if (best_bitrate_error) {
-               /* Error in one-tenth of a percent */
-               v64 = (u64)best_bitrate_error * 1000;
-               do_div(v64, bt->bitrate);
-               bitrate_error = (u32)v64;
-               if (bitrate_error > CAN_CALC_MAX_ERROR) {
-                       netdev_err(dev,
-                                  "bitrate error %d.%d%% too high\n",
-                                  bitrate_error / 10, bitrate_error % 10);
-                       return -EDOM;
-               }
-               netdev_warn(dev, "bitrate error %d.%d%%\n",
-                           bitrate_error / 10, bitrate_error % 10);
-       }
-
-       /* real sample point */
-       bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
-                                                  best_tseg, &tseg1, &tseg2,
-                                                  NULL);
-
-       v64 = (u64)best_brp * 1000 * 1000 * 1000;
-       do_div(v64, priv->clock.freq);
-       bt->tq = (u32)v64;
-       bt->prop_seg = tseg1 / 2;
-       bt->phase_seg1 = tseg1 - bt->prop_seg;
-       bt->phase_seg2 = tseg2;
-
-       /* check for sjw user settings */
-       if (!bt->sjw || !btc->sjw_max) {
-               bt->sjw = 1;
-       } else {
-               /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
-               if (bt->sjw > btc->sjw_max)
-                       bt->sjw = btc->sjw_max;
-               /* bt->sjw must not be higher than tseg2 */
-               if (tseg2 < bt->sjw)
-                       bt->sjw = tseg2;
-       }
-
-       bt->brp = best_brp;
-
-       /* real bitrate */
-       bt->bitrate = priv->clock.freq /
-               (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
-
-       return 0;
-}
-
-void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
-                  const struct can_bittiming *dbt,
-                  u32 *ctrlmode, u32 ctrlmode_supported)
-
-{
-       if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
-               return;
-
-       *ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
-
-       /* As specified in ISO 11898-1 section 11.3.3 "Transmitter
-        * delay compensation" (TDC) is only applicable if data BRP is
-        * one or two.
-        */
-       if (dbt->brp == 1 || dbt->brp == 2) {
-               /* Sample point in clock periods */
-               u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
-                                         dbt->phase_seg1) * dbt->brp;
-
-               if (sample_point_in_tc < tdc_const->tdco_min)
-                       return;
-               tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
-               *ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
-       }
-}
-#endif /* CONFIG_CAN_CALC_BITTIMING */
-
 /* Checks the validity of the specified bit-timing parameters prop_seg,
  * phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
  * prescaler value brp. You can find more information in the header
diff --git a/drivers/net/can/dev/calc_bittiming.c b/drivers/net/can/dev/calc_bittiming.c
new file mode 100644 (file)
index 0000000..d3caa04
--- /dev/null
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
+ * Copyright (C) 2006 Andrey Volkov, Varma Electronics
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
+ */
+
+#include <linux/units.h>
+#include <linux/can/dev.h>
+
+#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
+
+/* Bit-timing calculation derived from:
+ *
+ * Code based on LinCAN sources and H8S2638 project
+ * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
+ * Copyright 2005      Stanislav Marek
+ * email: pisa@cmp.felk.cvut.cz
+ *
+ * Calculates proper bit-timing parameters for a specified bit-rate
+ * and sample-point, which can then be used to set the bit-timing
+ * registers of the CAN controller. You can find more information
+ * in the header file linux/can/netlink.h.
+ */
+static int
+can_update_sample_point(const struct can_bittiming_const *btc,
+                       const unsigned int sample_point_nominal, const unsigned int tseg,
+                       unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
+                       unsigned int *sample_point_error_ptr)
+{
+       unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
+       unsigned int sample_point, best_sample_point = 0;
+       unsigned int tseg1, tseg2;
+       int i;
+
+       for (i = 0; i <= 1; i++) {
+               tseg2 = tseg + CAN_SYNC_SEG -
+                       (sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
+                       1000 - i;
+               tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
+               tseg1 = tseg - tseg2;
+               if (tseg1 > btc->tseg1_max) {
+                       tseg1 = btc->tseg1_max;
+                       tseg2 = tseg - tseg1;
+               }
+
+               sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
+                       (tseg + CAN_SYNC_SEG);
+               sample_point_error = abs(sample_point_nominal - sample_point);
+
+               if (sample_point <= sample_point_nominal &&
+                   sample_point_error < best_sample_point_error) {
+                       best_sample_point = sample_point;
+                       best_sample_point_error = sample_point_error;
+                       *tseg1_ptr = tseg1;
+                       *tseg2_ptr = tseg2;
+               }
+       }
+
+       if (sample_point_error_ptr)
+               *sample_point_error_ptr = best_sample_point_error;
+
+       return best_sample_point;
+}
+
+int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
+                      const struct can_bittiming_const *btc)
+{
+       struct can_priv *priv = netdev_priv(dev);
+       unsigned int bitrate;                   /* current bitrate */
+       unsigned int bitrate_error;             /* difference between current and nominal value */
+       unsigned int best_bitrate_error = UINT_MAX;
+       unsigned int sample_point_error;        /* difference between current and nominal value */
+       unsigned int best_sample_point_error = UINT_MAX;
+       unsigned int sample_point_nominal;      /* nominal sample point */
+       unsigned int best_tseg = 0;             /* current best value for tseg */
+       unsigned int best_brp = 0;              /* current best value for brp */
+       unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
+       u64 v64;
+
+       /* Use CiA recommended sample points */
+       if (bt->sample_point) {
+               sample_point_nominal = bt->sample_point;
+       } else {
+               if (bt->bitrate > 800 * KILO /* BPS */)
+                       sample_point_nominal = 750;
+               else if (bt->bitrate > 500 * KILO /* BPS */)
+                       sample_point_nominal = 800;
+               else
+                       sample_point_nominal = 875;
+       }
+
+       /* tseg even = round down, odd = round up */
+       for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
+            tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
+               tsegall = CAN_SYNC_SEG + tseg / 2;
+
+               /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
+               brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
+
+               /* choose brp step which is possible in system */
+               brp = (brp / btc->brp_inc) * btc->brp_inc;
+               if (brp < btc->brp_min || brp > btc->brp_max)
+                       continue;
+
+               bitrate = priv->clock.freq / (brp * tsegall);
+               bitrate_error = abs(bt->bitrate - bitrate);
+
+               /* tseg brp biterror */
+               if (bitrate_error > best_bitrate_error)
+                       continue;
+
+               /* reset sample point error if we have a better bitrate */
+               if (bitrate_error < best_bitrate_error)
+                       best_sample_point_error = UINT_MAX;
+
+               can_update_sample_point(btc, sample_point_nominal, tseg / 2,
+                                       &tseg1, &tseg2, &sample_point_error);
+               if (sample_point_error >= best_sample_point_error)
+                       continue;
+
+               best_sample_point_error = sample_point_error;
+               best_bitrate_error = bitrate_error;
+               best_tseg = tseg / 2;
+               best_brp = brp;
+
+               if (bitrate_error == 0 && sample_point_error == 0)
+                       break;
+       }
+
+       if (best_bitrate_error) {
+               /* Error in one-tenth of a percent */
+               v64 = (u64)best_bitrate_error * 1000;
+               do_div(v64, bt->bitrate);
+               bitrate_error = (u32)v64;
+               if (bitrate_error > CAN_CALC_MAX_ERROR) {
+                       netdev_err(dev,
+                                  "bitrate error %d.%d%% too high\n",
+                                  bitrate_error / 10, bitrate_error % 10);
+                       return -EDOM;
+               }
+               netdev_warn(dev, "bitrate error %d.%d%%\n",
+                           bitrate_error / 10, bitrate_error % 10);
+       }
+
+       /* real sample point */
+       bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
+                                                  best_tseg, &tseg1, &tseg2,
+                                                  NULL);
+
+       v64 = (u64)best_brp * 1000 * 1000 * 1000;
+       do_div(v64, priv->clock.freq);
+       bt->tq = (u32)v64;
+       bt->prop_seg = tseg1 / 2;
+       bt->phase_seg1 = tseg1 - bt->prop_seg;
+       bt->phase_seg2 = tseg2;
+
+       /* check for sjw user settings */
+       if (!bt->sjw || !btc->sjw_max) {
+               bt->sjw = 1;
+       } else {
+               /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
+               if (bt->sjw > btc->sjw_max)
+                       bt->sjw = btc->sjw_max;
+               /* bt->sjw must not be higher than tseg2 */
+               if (tseg2 < bt->sjw)
+                       bt->sjw = tseg2;
+       }
+
+       bt->brp = best_brp;
+
+       /* real bitrate */
+       bt->bitrate = priv->clock.freq /
+               (bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
+
+       return 0;
+}
+
+void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
+                  const struct can_bittiming *dbt,
+                  u32 *ctrlmode, u32 ctrlmode_supported)
+
+{
+       if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
+               return;
+
+       *ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
+
+       /* As specified in ISO 11898-1 section 11.3.3 "Transmitter
+        * delay compensation" (TDC) is only applicable if data BRP is
+        * one or two.
+        */
+       if (dbt->brp == 1 || dbt->brp == 2) {
+               /* Sample point in clock periods */
+               u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
+                                         dbt->phase_seg1) * dbt->brp;
+
+               if (sample_point_in_tc < tdc_const->tdco_min)
+                       return;
+               tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
+               *ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
+       }
+}
index 96c9d9d..523eaac 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/gpio/consumer.h>
 #include <linux/of.h>
 
-#define MOD_DESC "CAN device driver interface"
-
-MODULE_DESCRIPTION(MOD_DESC);
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-
 static void can_update_state_error_stats(struct net_device *dev,
                                         enum can_state new_state)
 {
@@ -513,7 +506,7 @@ static __init int can_dev_init(void)
 
        err = can_netlink_register();
        if (!err)
-               pr_info(MOD_DESC "\n");
+               pr_info("CAN device driver interface\n");
 
        return err;
 }
index 7633d98..8efa22d 100644 (file)
@@ -176,7 +176,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
                 * directly via do_set_bitrate(). Bail out if neither
                 * is given.
                 */
-               if (!priv->bittiming_const && !priv->do_set_bittiming)
+               if (!priv->bittiming_const && !priv->do_set_bittiming &&
+                   !priv->bitrate_const)
                        return -EOPNOTSUPP;
 
                memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
@@ -278,7 +279,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
                 * directly via do_set_bitrate(). Bail out if neither
                 * is given.
                 */
-               if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
+               if (!priv->data_bittiming_const && !priv->do_set_data_bittiming &&
+                   !priv->data_bitrate_const)
                        return -EOPNOTSUPP;
 
                memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
@@ -509,7 +511,8 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
        if (priv->do_get_state)
                priv->do_get_state(dev, &state);
 
-       if ((priv->bittiming.bitrate &&
+       if ((priv->bittiming.bitrate != CAN_BITRATE_UNSET &&
+            priv->bittiming.bitrate != CAN_BITRATE_UNKNOWN &&
             nla_put(skb, IFLA_CAN_BITTIMING,
                     sizeof(priv->bittiming), &priv->bittiming)) ||
 
index 6166024..8bb62dd 100644 (file)
@@ -5,6 +5,14 @@
  */
 
 #include <linux/can/dev.h>
+#include <linux/can/netlink.h>
+#include <linux/module.h>
+
+#define MOD_DESC "CAN device driver interface"
+
+MODULE_DESCRIPTION(MOD_DESC);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 
 /* Local echo of CAN messages
  *
@@ -252,3 +260,67 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
        return skb;
 }
 EXPORT_SYMBOL_GPL(alloc_can_err_skb);
+
+/* Check for outgoing skbs that have not been created by the CAN subsystem */
+static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
+{
+       /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
+       if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
+               return false;
+
+       /* af_packet does not apply CAN skb specific settings */
+       if (skb->ip_summed == CHECKSUM_NONE) {
+               /* init headroom */
+               can_skb_prv(skb)->ifindex = dev->ifindex;
+               can_skb_prv(skb)->skbcnt = 0;
+
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+               /* perform proper loopback on capable devices */
+               if (dev->flags & IFF_ECHO)
+                       skb->pkt_type = PACKET_LOOPBACK;
+               else
+                       skb->pkt_type = PACKET_HOST;
+
+               skb_reset_mac_header(skb);
+               skb_reset_network_header(skb);
+               skb_reset_transport_header(skb);
+       }
+
+       return true;
+}
+
+/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
+bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
+{
+       const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+       struct can_priv *priv = netdev_priv(dev);
+
+       if (skb->protocol == htons(ETH_P_CAN)) {
+               if (unlikely(skb->len != CAN_MTU ||
+                            cfd->len > CAN_MAX_DLEN))
+                       goto inval_skb;
+       } else if (skb->protocol == htons(ETH_P_CANFD)) {
+               if (unlikely(skb->len != CANFD_MTU ||
+                            cfd->len > CANFD_MAX_DLEN))
+                       goto inval_skb;
+       } else {
+               goto inval_skb;
+       }
+
+       if (!can_skb_headroom_valid(dev, skb)) {
+               goto inval_skb;
+       } else if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) {
+               netdev_info_once(dev,
+                                "interface in listen only mode, dropping skb\n");
+               goto inval_skb;
+       }
+
+       return false;
+
+inval_skb:
+       kfree_skb(skb);
+       dev->stats.tx_dropped++;
+       return true;
+}
+EXPORT_SYMBOL_GPL(can_dropped_invalid_skb);
index 45ad1b3..fc2afab 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 menuconfig CAN_M_CAN
        tristate "Bosch M_CAN support"
+       select CAN_RX_OFFLOAD
        help
          Say Y here if you want support for Bosch M_CAN controller framework.
          This is common support for devices that embed the Bosch M_CAN IP.
index 7931f9c..afaaeb6 100644 (file)
@@ -1348,8 +1348,8 @@ static void m_can_chip_config(struct net_device *dev)
        /* set bittiming params */
        m_can_set_bittiming(dev);
 
-       /* enable internal timestamp generation, with a prescalar of 16. The
-        * prescalar is applied to the nominal bit timing
+       /* enable internal timestamp generation, with a prescaler of 16. The
+        * prescaler is applied to the nominal bit timing
         */
        m_can_write(cdev, M_CAN_TSCC,
                    FIELD_PREP(TSCC_TCP_MASK, 0xf) |
diff --git a/drivers/net/can/slcan/Makefile b/drivers/net/can/slcan/Makefile
new file mode 100644 (file)
index 0000000..8a88e48
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_CAN_SLCAN) += slcan.o
+
+slcan-objs :=
+slcan-objs += slcan-core.o
+slcan-objs += slcan-ethtool.o
similarity index 65%
rename from drivers/net/can/slcan.c
rename to drivers/net/can/slcan/slcan-core.c
index 64a3aee..54d29a4 100644 (file)
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
 #include <linux/can.h>
+#include <linux/can/dev.h>
 #include <linux/can/skb.h>
-#include <linux/can/can-ml.h>
+
+#include "slcan.h"
 
 MODULE_ALIAS_LDISC(N_SLCAN);
 MODULE_DESCRIPTION("serial line CAN interface");
@@ -76,8 +78,13 @@ MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
 #define SLC_CMD_LEN 1
 #define SLC_SFF_ID_LEN 3
 #define SLC_EFF_ID_LEN 8
-
+#define SLC_STATE_LEN 1
+#define SLC_STATE_BE_RXCNT_LEN 3
+#define SLC_STATE_BE_TXCNT_LEN 3
+#define SLC_STATE_FRAME_LEN       (1 + SLC_CMD_LEN + SLC_STATE_BE_RXCNT_LEN + \
+                                  SLC_STATE_BE_TXCNT_LEN)
 struct slcan {
+       struct can_priv         can;
        int                     magic;
 
        /* Various fields. */
@@ -96,10 +103,42 @@ struct slcan {
        unsigned long           flags;          /* Flag values/ mode etc     */
 #define SLF_INUSE              0               /* Channel in use            */
 #define SLF_ERROR              1               /* Parity, etc. error        */
+#define SLF_XCMD               2               /* Command transmission      */
+       unsigned long           cmd_flags;      /* Command flags             */
+#define CF_ERR_RST             0               /* Reset errors on open      */
+       wait_queue_head_t       xcmd_wait;      /* Wait queue for commands   */
+                                               /* transmission              */
 };
 
 static struct net_device **slcan_devs;
 
+static const u32 slcan_bitrate_const[] = {
+       10000, 20000, 50000, 100000, 125000,
+       250000, 500000, 800000, 1000000
+};
+
+bool slcan_err_rst_on_open(struct net_device *ndev)
+{
+       struct slcan *sl = netdev_priv(ndev);
+
+       return !!test_bit(CF_ERR_RST, &sl->cmd_flags);
+}
+
+int slcan_enable_err_rst_on_open(struct net_device *ndev, bool on)
+{
+       struct slcan *sl = netdev_priv(ndev);
+
+       if (netif_running(ndev))
+               return -EBUSY;
+
+       if (on)
+               set_bit(CF_ERR_RST, &sl->cmd_flags);
+       else
+               clear_bit(CF_ERR_RST, &sl->cmd_flags);
+
+       return 0;
+}
+
  /************************************************************************
   *                    SLCAN ENCAPSULATION FORMAT                       *
   ************************************************************************/
@@ -140,88 +179,289 @@ static struct net_device **slcan_devs;
   ************************************************************************/
 
 /* Send one completely decapsulated can_frame to the network layer */
-static void slc_bump(struct slcan *sl)
+static void slc_bump_frame(struct slcan *sl)
 {
        struct sk_buff *skb;
-       struct can_frame cf;
+       struct can_frame *cf;
        int i, tmp;
        u32 tmpid;
        char *cmd = sl->rbuff;
 
-       memset(&cf, 0, sizeof(cf));
+       skb = alloc_can_skb(sl->dev, &cf);
+       if (unlikely(!skb)) {
+               sl->dev->stats.rx_dropped++;
+               return;
+       }
 
        switch (*cmd) {
        case 'r':
-               cf.can_id = CAN_RTR_FLAG;
+               cf->can_id = CAN_RTR_FLAG;
                fallthrough;
        case 't':
                /* store dlc ASCII value and terminate SFF CAN ID string */
-               cf.len = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
+               cf->len = sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN];
                sl->rbuff[SLC_CMD_LEN + SLC_SFF_ID_LEN] = 0;
                /* point to payload data behind the dlc */
                cmd += SLC_CMD_LEN + SLC_SFF_ID_LEN + 1;
                break;
        case 'R':
-               cf.can_id = CAN_RTR_FLAG;
+               cf->can_id = CAN_RTR_FLAG;
                fallthrough;
        case 'T':
-               cf.can_id |= CAN_EFF_FLAG;
+               cf->can_id |= CAN_EFF_FLAG;
                /* store dlc ASCII value and terminate EFF CAN ID string */
-               cf.len = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
+               cf->len = sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN];
                sl->rbuff[SLC_CMD_LEN + SLC_EFF_ID_LEN] = 0;
                /* point to payload data behind the dlc */
                cmd += SLC_CMD_LEN + SLC_EFF_ID_LEN + 1;
                break;
        default:
-               return;
+               goto decode_failed;
        }
 
        if (kstrtou32(sl->rbuff + SLC_CMD_LEN, 16, &tmpid))
-               return;
+               goto decode_failed;
 
-       cf.can_id |= tmpid;
+       cf->can_id |= tmpid;
 
        /* get len from sanitized ASCII value */
-       if (cf.len >= '0' && cf.len < '9')
-               cf.len -= '0';
+       if (cf->len >= '0' && cf->len < '9')
+               cf->len -= '0';
        else
-               return;
+               goto decode_failed;
 
        /* RTR frames may have a dlc > 0 but they never have any data bytes */
-       if (!(cf.can_id & CAN_RTR_FLAG)) {
-               for (i = 0; i < cf.len; i++) {
+       if (!(cf->can_id & CAN_RTR_FLAG)) {
+               for (i = 0; i < cf->len; i++) {
                        tmp = hex_to_bin(*cmd++);
                        if (tmp < 0)
-                               return;
-                       cf.data[i] = (tmp << 4);
+                               goto decode_failed;
+
+                       cf->data[i] = (tmp << 4);
                        tmp = hex_to_bin(*cmd++);
                        if (tmp < 0)
-                               return;
-                       cf.data[i] |= tmp;
+                               goto decode_failed;
+
+                       cf->data[i] |= tmp;
                }
        }
 
-       skb = dev_alloc_skb(sizeof(struct can_frame) +
-                           sizeof(struct can_skb_priv));
-       if (!skb)
+       sl->dev->stats.rx_packets++;
+       if (!(cf->can_id & CAN_RTR_FLAG))
+               sl->dev->stats.rx_bytes += cf->len;
+
+       netif_rx(skb);
+       return;
+
+decode_failed:
+       sl->dev->stats.rx_errors++;
+       dev_kfree_skb(skb);
+}
+
+/* A change state frame must contain state info and receive and transmit
+ * error counters.
+ *
+ * Examples:
+ *
+ * sb256256 : state bus-off: rx counter 256, tx counter 256
+ * sa057033 : state active, rx counter 57, tx counter 33
+ */
+static void slc_bump_state(struct slcan *sl)
+{
+       struct net_device *dev = sl->dev;
+       struct sk_buff *skb;
+       struct can_frame *cf;
+       char *cmd = sl->rbuff;
+       u32 rxerr, txerr;
+       enum can_state state, rx_state, tx_state;
+
+       switch (cmd[1]) {
+       case 'a':
+               state = CAN_STATE_ERROR_ACTIVE;
+               break;
+       case 'w':
+               state = CAN_STATE_ERROR_WARNING;
+               break;
+       case 'p':
+               state = CAN_STATE_ERROR_PASSIVE;
+               break;
+       case 'b':
+               state = CAN_STATE_BUS_OFF;
+               break;
+       default:
+               return;
+       }
+
+       if (state == sl->can.state || sl->rcount < SLC_STATE_FRAME_LEN)
                return;
 
-       skb->dev = sl->dev;
-       skb->protocol = htons(ETH_P_CAN);
-       skb->pkt_type = PACKET_BROADCAST;
-       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       cmd += SLC_STATE_BE_RXCNT_LEN + SLC_CMD_LEN + 1;
+       cmd[SLC_STATE_BE_TXCNT_LEN] = 0;
+       if (kstrtou32(cmd, 10, &txerr))
+               return;
 
-       can_skb_reserve(skb);
-       can_skb_prv(skb)->ifindex = sl->dev->ifindex;
-       can_skb_prv(skb)->skbcnt = 0;
+       *cmd = 0;
+       cmd -= SLC_STATE_BE_RXCNT_LEN;
+       if (kstrtou32(cmd, 10, &rxerr))
+               return;
 
-       skb_put_data(skb, &cf, sizeof(struct can_frame));
+       skb = alloc_can_err_skb(dev, &cf);
+       if (skb) {
+               cf->data[6] = txerr;
+               cf->data[7] = rxerr;
+       } else {
+               cf = NULL;
+       }
 
-       sl->dev->stats.rx_packets++;
-       if (!(cf.can_id & CAN_RTR_FLAG))
-               sl->dev->stats.rx_bytes += cf.len;
+       tx_state = txerr >= rxerr ? state : 0;
+       rx_state = txerr <= rxerr ? state : 0;
+       can_change_state(dev, cf, tx_state, rx_state);
 
-       netif_rx(skb);
+       if (state == CAN_STATE_BUS_OFF)
+               can_bus_off(dev);
+
+       if (skb)
+               netif_rx(skb);
+}
+
+/* An error frame can contain more than one type of error.
+ *
+ * Examples:
+ *
+ * e1a : len 1, errors: ACK error
+ * e3bcO: len 3, errors: Bit0 error, CRC error, Tx overrun error
+ */
+static void slc_bump_err(struct slcan *sl)
+{
+       struct net_device *dev = sl->dev;
+       struct sk_buff *skb;
+       struct can_frame *cf;
+       char *cmd = sl->rbuff;
+       bool rx_errors = false, tx_errors = false, rx_over_errors = false;
+       int i, len;
+
+       /* get len from sanitized ASCII value */
+       len = cmd[1];
+       if (len >= '0' && len < '9')
+               len -= '0';
+       else
+               return;
+
+       if ((len + SLC_CMD_LEN + 1) > sl->rcount)
+               return;
+
+       skb = alloc_can_err_skb(dev, &cf);
+
+       if (skb)
+               cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+
+       cmd += SLC_CMD_LEN + 1;
+       for (i = 0; i < len; i++, cmd++) {
+               switch (*cmd) {
+               case 'a':
+                       netdev_dbg(dev, "ACK error\n");
+                       tx_errors = true;
+                       if (skb) {
+                               cf->can_id |= CAN_ERR_ACK;
+                               cf->data[3] = CAN_ERR_PROT_LOC_ACK;
+                       }
+
+                       break;
+               case 'b':
+                       netdev_dbg(dev, "Bit0 error\n");
+                       tx_errors = true;
+                       if (skb)
+                               cf->data[2] |= CAN_ERR_PROT_BIT0;
+
+                       break;
+               case 'B':
+                       netdev_dbg(dev, "Bit1 error\n");
+                       tx_errors = true;
+                       if (skb)
+                               cf->data[2] |= CAN_ERR_PROT_BIT1;
+
+                       break;
+               case 'c':
+                       netdev_dbg(dev, "CRC error\n");
+                       rx_errors = true;
+                       if (skb) {
+                               cf->data[2] |= CAN_ERR_PROT_BIT;
+                               cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
+                       }
+
+                       break;
+               case 'f':
+                       netdev_dbg(dev, "Form Error\n");
+                       rx_errors = true;
+                       if (skb)
+                               cf->data[2] |= CAN_ERR_PROT_FORM;
+
+                       break;
+               case 'o':
+                       netdev_dbg(dev, "Rx overrun error\n");
+                       rx_over_errors = true;
+                       rx_errors = true;
+                       if (skb) {
+                               cf->can_id |= CAN_ERR_CRTL;
+                               cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+                       }
+
+                       break;
+               case 'O':
+                       netdev_dbg(dev, "Tx overrun error\n");
+                       tx_errors = true;
+                       if (skb) {
+                               cf->can_id |= CAN_ERR_CRTL;
+                               cf->data[1] = CAN_ERR_CRTL_TX_OVERFLOW;
+                       }
+
+                       break;
+               case 's':
+                       netdev_dbg(dev, "Stuff error\n");
+                       rx_errors = true;
+                       if (skb)
+                               cf->data[2] |= CAN_ERR_PROT_STUFF;
+
+                       break;
+               default:
+                       if (skb)
+                               dev_kfree_skb(skb);
+
+                       return;
+               }
+       }
+
+       if (rx_errors)
+               dev->stats.rx_errors++;
+
+       if (rx_over_errors)
+               dev->stats.rx_over_errors++;
+
+       if (tx_errors)
+               dev->stats.tx_errors++;
+
+       if (skb)
+               netif_rx(skb);
+}
+
+static void slc_bump(struct slcan *sl)
+{
+       switch (sl->rbuff[0]) {
+       case 'r':
+               fallthrough;
+       case 't':
+               fallthrough;
+       case 'R':
+               fallthrough;
+       case 'T':
+               return slc_bump_frame(sl);
+       case 'e':
+               return slc_bump_err(sl);
+       case 's':
+               return slc_bump_state(sl);
+       default:
+               return;
+       }
 }
 
 /* parse tty input stream */
@@ -318,12 +558,22 @@ static void slcan_transmit(struct work_struct *work)
 
        spin_lock_bh(&sl->lock);
        /* First make sure we're connected. */
-       if (!sl->tty || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) {
+       if (!sl->tty || sl->magic != SLCAN_MAGIC ||
+           (unlikely(!netif_running(sl->dev)) &&
+            likely(!test_bit(SLF_XCMD, &sl->flags)))) {
                spin_unlock_bh(&sl->lock);
                return;
        }
 
        if (sl->xleft <= 0)  {
+               if (unlikely(test_bit(SLF_XCMD, &sl->flags))) {
+                       clear_bit(SLF_XCMD, &sl->flags);
+                       clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+                       spin_unlock_bh(&sl->lock);
+                       wake_up(&sl->xcmd_wait);
+                       return;
+               }
+
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
                sl->dev->stats.tx_packets++;
@@ -365,7 +615,7 @@ static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_lock(&sl->lock);
        if (!netif_running(dev))  {
                spin_unlock(&sl->lock);
-               printk(KERN_WARNING "%s: xmit: iface is down\n", dev->name);
+               netdev_warn(dev, "xmit: iface is down\n");
                goto out;
        }
        if (sl->tty == NULL) {
@@ -387,17 +637,63 @@ out:
  *   Routines looking at netdevice side.
  ******************************************/
 
+static int slcan_transmit_cmd(struct slcan *sl, const unsigned char *cmd)
+{
+       int ret, actual, n;
+
+       spin_lock(&sl->lock);
+       if (!sl->tty) {
+               spin_unlock(&sl->lock);
+               return -ENODEV;
+       }
+
+       n = snprintf(sl->xbuff, sizeof(sl->xbuff), "%s", cmd);
+       set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+       actual = sl->tty->ops->write(sl->tty, sl->xbuff, n);
+       sl->xleft = n - actual;
+       sl->xhead = sl->xbuff + actual;
+       set_bit(SLF_XCMD, &sl->flags);
+       spin_unlock(&sl->lock);
+       ret = wait_event_interruptible_timeout(sl->xcmd_wait,
+                                              !test_bit(SLF_XCMD, &sl->flags),
+                                              HZ);
+       clear_bit(SLF_XCMD, &sl->flags);
+       if (ret == -ERESTARTSYS)
+               return ret;
+
+       if (ret == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 /* Netdevice UP -> DOWN routine */
 static int slc_close(struct net_device *dev)
 {
        struct slcan *sl = netdev_priv(dev);
+       int err;
 
        spin_lock_bh(&sl->lock);
        if (sl->tty) {
+               if (sl->can.bittiming.bitrate &&
+                   sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) {
+                       spin_unlock_bh(&sl->lock);
+                       err = slcan_transmit_cmd(sl, "C\r");
+                       spin_lock_bh(&sl->lock);
+                       if (err)
+                               netdev_warn(dev,
+                                           "failed to send close command 'C\\r'\n");
+               }
+
                /* TTY discipline is running. */
                clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
        }
        netif_stop_queue(dev);
+       close_candev(dev);
+       sl->can.state = CAN_STATE_STOPPED;
+       if (sl->can.bittiming.bitrate == CAN_BITRATE_UNKNOWN)
+               sl->can.bittiming.bitrate = CAN_BITRATE_UNSET;
+
        sl->rcount   = 0;
        sl->xleft    = 0;
        spin_unlock_bh(&sl->lock);
@@ -409,20 +705,77 @@ static int slc_close(struct net_device *dev)
 static int slc_open(struct net_device *dev)
 {
        struct slcan *sl = netdev_priv(dev);
+       unsigned char cmd[SLC_MTU];
+       int err, s;
 
        if (sl->tty == NULL)
                return -ENODEV;
 
-       sl->flags &= (1 << SLF_INUSE);
+       /* The baud rate is not set with the command
+        * `ip link set <iface> type can bitrate <baud>' and therefore
+        * can.bittiming.bitrate is CAN_BITRATE_UNSET (0), causing
+        * open_candev() to fail. So let's set to a fake value.
+        */
+       if (sl->can.bittiming.bitrate == CAN_BITRATE_UNSET)
+               sl->can.bittiming.bitrate = CAN_BITRATE_UNKNOWN;
+
+       err = open_candev(dev);
+       if (err) {
+               netdev_err(dev, "failed to open can device\n");
+               return err;
+       }
+
+       sl->flags &= BIT(SLF_INUSE);
+
+       if (sl->can.bittiming.bitrate != CAN_BITRATE_UNKNOWN) {
+               for (s = 0; s < ARRAY_SIZE(slcan_bitrate_const); s++) {
+                       if (sl->can.bittiming.bitrate == slcan_bitrate_const[s])
+                               break;
+               }
+
+               /* The CAN framework has already validate the bitrate value,
+                * so we can avoid to check if `s' has been properly set.
+                */
+
+               snprintf(cmd, sizeof(cmd), "C\rS%d\r", s);
+               err = slcan_transmit_cmd(sl, cmd);
+               if (err) {
+                       netdev_err(dev,
+                                  "failed to send bitrate command 'C\\rS%d\\r'\n",
+                                  s);
+                       goto cmd_transmit_failed;
+               }
+
+               if (test_bit(CF_ERR_RST, &sl->cmd_flags)) {
+                       err = slcan_transmit_cmd(sl, "F\r");
+                       if (err) {
+                               netdev_err(dev,
+                                          "failed to send error command 'F\\r'\n");
+                               goto cmd_transmit_failed;
+                       }
+               }
+
+               err = slcan_transmit_cmd(sl, "O\r");
+               if (err) {
+                       netdev_err(dev, "failed to send open command 'O\\r'\n");
+                       goto cmd_transmit_failed;
+               }
+       }
+
+       sl->can.state = CAN_STATE_ERROR_ACTIVE;
        netif_start_queue(dev);
        return 0;
+
+cmd_transmit_failed:
+       close_candev(dev);
+       return err;
 }
 
-/* Hook the destructor so we can free slcan devs at the right point in time */
-static void slc_free_netdev(struct net_device *dev)
+static void slc_dealloc(struct slcan *sl)
 {
-       int i = dev->base_addr;
+       int i = sl->dev->base_addr;
 
+       free_candev(sl->dev);
        slcan_devs[i] = NULL;
 }
 
@@ -438,24 +791,6 @@ static const struct net_device_ops slc_netdev_ops = {
        .ndo_change_mtu         = slcan_change_mtu,
 };
 
-static void slc_setup(struct net_device *dev)
-{
-       dev->netdev_ops         = &slc_netdev_ops;
-       dev->needs_free_netdev  = true;
-       dev->priv_destructor    = slc_free_netdev;
-
-       dev->hard_header_len    = 0;
-       dev->addr_len           = 0;
-       dev->tx_queue_len       = 10;
-
-       dev->mtu                = CAN_MTU;
-       dev->type               = ARPHRD_CAN;
-
-       /* New-style flags. */
-       dev->flags              = IFF_NOARP;
-       dev->features           = NETIF_F_HW_CSUM;
-}
-
 /******************************************
   Routines looking at TTY side.
  ******************************************/
@@ -518,11 +853,8 @@ static void slc_sync(void)
 static struct slcan *slc_alloc(void)
 {
        int i;
-       char name[IFNAMSIZ];
        struct net_device *dev = NULL;
-       struct can_ml_priv *can_ml;
        struct slcan       *sl;
-       int size;
 
        for (i = 0; i < maxdev; i++) {
                dev = slcan_devs[i];
@@ -535,22 +867,24 @@ static struct slcan *slc_alloc(void)
        if (i >= maxdev)
                return NULL;
 
-       sprintf(name, "slcan%d", i);
-       size = ALIGN(sizeof(*sl), NETDEV_ALIGN) + sizeof(struct can_ml_priv);
-       dev = alloc_netdev(size, name, NET_NAME_UNKNOWN, slc_setup);
+       dev = alloc_candev(sizeof(*sl), 1);
        if (!dev)
                return NULL;
 
+       snprintf(dev->name, sizeof(dev->name), "slcan%d", i);
+       dev->netdev_ops = &slc_netdev_ops;
        dev->base_addr  = i;
+       slcan_set_ethtool_ops(dev);
        sl = netdev_priv(dev);
-       can_ml = (void *)sl + ALIGN(sizeof(*sl), NETDEV_ALIGN);
-       can_set_ml_priv(dev, can_ml);
 
        /* Initialize channel control data */
        sl->magic = SLCAN_MAGIC;
        sl->dev = dev;
+       sl->can.bitrate_const = slcan_bitrate_const;
+       sl->can.bitrate_const_cnt = ARRAY_SIZE(slcan_bitrate_const);
        spin_lock_init(&sl->lock);
        INIT_WORK(&sl->tx_work, slcan_transmit);
+       init_waitqueue_head(&sl->xcmd_wait);
        slcan_devs[i] = dev;
 
        return sl;
@@ -609,26 +943,28 @@ static int slcan_open(struct tty_struct *tty)
 
                set_bit(SLF_INUSE, &sl->flags);
 
-               err = register_netdevice(sl->dev);
-               if (err)
+               rtnl_unlock();
+               err = register_candev(sl->dev);
+               if (err) {
+                       pr_err("slcan: can't register candev\n");
                        goto err_free_chan;
+               }
+       } else {
+               rtnl_unlock();
        }
 
-       /* Done.  We have linked the TTY line to a channel. */
-       rtnl_unlock();
        tty->receive_room = 65536;      /* We don't flow control */
 
        /* TTY layer expects 0 on success */
        return 0;
 
 err_free_chan:
+       rtnl_lock();
        sl->tty = NULL;
        tty->disc_data = NULL;
        clear_bit(SLF_INUSE, &sl->flags);
-       slc_free_netdev(sl->dev);
-       /* do not call free_netdev before rtnl_unlock */
+       slc_dealloc(sl);
        rtnl_unlock();
-       free_netdev(sl->dev);
        return err;
 
 err_exit:
@@ -662,9 +998,11 @@ static void slcan_close(struct tty_struct *tty)
        synchronize_rcu();
        flush_work(&sl->tx_work);
 
-       /* Flush network side */
-       unregister_netdev(sl->dev);
-       /* This will complete via sl_free_netdev */
+       slc_close(sl->dev);
+       unregister_candev(sl->dev);
+       rtnl_lock();
+       slc_dealloc(sl);
+       rtnl_unlock();
 }
 
 static void slcan_hangup(struct tty_struct *tty)
@@ -772,15 +1110,15 @@ static void __exit slcan_exit(void)
                dev = slcan_devs[i];
                if (!dev)
                        continue;
-               slcan_devs[i] = NULL;
 
                sl = netdev_priv(dev);
                if (sl->tty) {
-                       printk(KERN_ERR "%s: tty discipline still running\n",
-                              dev->name);
+                       netdev_err(dev, "tty discipline still running\n");
                }
 
-               unregister_netdev(dev);
+               slc_close(dev);
+               unregister_candev(dev);
+               slc_dealloc(sl);
        }
 
        kfree(slcan_devs);
diff --git a/drivers/net/can/slcan/slcan-ethtool.c b/drivers/net/can/slcan/slcan-ethtool.c
new file mode 100644 (file)
index 0000000..bf0afdc
--- /dev/null
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2022 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ *
+ */
+
+#include <linux/can/dev.h>
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+
+#include "slcan.h"
+
+static const char slcan_priv_flags_strings[][ETH_GSTRING_LEN] = {
+#define SLCAN_PRIV_FLAGS_ERR_RST_ON_OPEN BIT(0)
+       "err-rst-on-open",
+};
+
+static void slcan_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
+{
+       switch (stringset) {
+       case ETH_SS_PRIV_FLAGS:
+               memcpy(data, slcan_priv_flags_strings,
+                      sizeof(slcan_priv_flags_strings));
+       }
+}
+
+static u32 slcan_get_priv_flags(struct net_device *ndev)
+{
+       u32 flags = 0;
+
+       if (slcan_err_rst_on_open(ndev))
+               flags |= SLCAN_PRIV_FLAGS_ERR_RST_ON_OPEN;
+
+       return flags;
+}
+
+static int slcan_set_priv_flags(struct net_device *ndev, u32 flags)
+{
+       bool err_rst_op_open = !!(flags & SLCAN_PRIV_FLAGS_ERR_RST_ON_OPEN);
+
+       return slcan_enable_err_rst_on_open(ndev, err_rst_op_open);
+}
+
+static int slcan_get_sset_count(struct net_device *netdev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_PRIV_FLAGS:
+               return ARRAY_SIZE(slcan_priv_flags_strings);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static const struct ethtool_ops slcan_ethtool_ops = {
+       .get_strings = slcan_get_strings,
+       .get_priv_flags = slcan_get_priv_flags,
+       .set_priv_flags = slcan_set_priv_flags,
+       .get_sset_count = slcan_get_sset_count,
+};
+
+void slcan_set_ethtool_ops(struct net_device *netdev)
+{
+       netdev->ethtool_ops = &slcan_ethtool_ops;
+}
diff --git a/drivers/net/can/slcan/slcan.h b/drivers/net/can/slcan/slcan.h
new file mode 100644 (file)
index 0000000..d463c8d
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * slcan.h - serial line CAN interface driver
+ *
+ * Copyright (C) Laurence Culhane <loz@holmes.demon.co.uk>
+ * Copyright (C) Fred N. van Kempen <waltje@uwalt.nl.mugnet.org>
+ * Copyright (C) Oliver Hartkopp <socketcan@hartkopp.net>
+ * Copyright (C) 2022 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com>
+ *
+ */
+
+#ifndef _SLCAN_H
+#define _SLCAN_H
+
+bool slcan_err_rst_on_open(struct net_device *ndev);
+int slcan_enable_err_rst_on_open(struct net_device *ndev, bool on);
+void slcan_set_ethtool_ops(struct net_device *ndev);
+
+#endif /* _SLCAN_H */
index dd0fc0a..877e435 100644 (file)
@@ -2,6 +2,7 @@
 
 config CAN_MCP251XFD
        tristate "Microchip MCP251xFD SPI CAN controllers"
+       select CAN_RX_OFFLOAD
        select REGMAP
        select WANT_DEV_COREDUMP
        help
index f959215..1218f96 100644 (file)
@@ -14,11 +14,18 @@ config CAN_EMS_USB
          This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
          from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
 
-config CAN_ESD_USB2
-       tristate "ESD USB/2 CAN/USB interface"
+config CAN_ESD_USB
+       tristate "esd electronics gmbh CAN/USB interfaces"
        help
-         This driver supports the CAN-USB/2 interface
-         from esd electronic system design gmbh (http://www.esd.eu).
+         This driver adds supports for several CAN/USB interfaces
+         from esd electronics gmbh (https://www.esd.eu).
+
+         The drivers supports the following devices:
+           - esd CAN-USB/2
+           - esd CAN-USB/Micro
+
+         To compile this driver as a module, choose M here: the module
+         will be called esd_usb.
 
 config CAN_ETAS_ES58X
        tristate "ETAS ES58X CAN/USB interfaces"
index 748cf31..1ea16be 100644 (file)
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
 obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
-obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
+obj-$(CONFIG_CAN_ESD_USB) += esd_usb.o
 obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x/
 obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
 obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/
similarity index 81%
rename from drivers/net/can/usb/esd_usb2.c
rename to drivers/net/can/usb/esd_usb.c
index 286daaa..8a4bf29 100644 (file)
@@ -1,8 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * CAN driver for esd CAN-USB/2 and CAN-USB/Micro
+ * CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro
  *
- * Copyright (C) 2010-2012 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
+ * Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu>
+ * Copyright (C) 2022 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu>
  */
 #include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
-MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>");
-MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 and CAN-USB/Micro interfaces");
+MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>");
+MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>");
+MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces");
 MODULE_LICENSE("GPL v2");
 
-/* Define these values to match your devices */
+/* USB vendor and product ID */
 #define USB_ESDGMBH_VENDOR_ID  0x0ab4
 #define USB_CANUSB2_PRODUCT_ID 0x0010
 #define USB_CANUSBM_PRODUCT_ID 0x0011
 
+/* CAN controller clock frequencies */
 #define ESD_USB2_CAN_CLOCK     60000000
 #define ESD_USBM_CAN_CLOCK     36000000
-#define ESD_USB2_MAX_NETS      2
 
-/* USB2 commands */
+/* Maximum number of CAN nets */
+#define ESD_USB_MAX_NETS       2
+
+/* USB commands */
 #define CMD_VERSION            1 /* also used for VERSION_REPLY */
 #define CMD_CAN_RX             2 /* device to host only */
 #define CMD_CAN_TX             3 /* also used for TX_DONE */
@@ -43,13 +48,15 @@ MODULE_LICENSE("GPL v2");
 #define ESD_EVENT              0x40000000
 #define ESD_IDMASK             0x1fffffff
 
-/* esd CAN event ids used by this driver */
-#define ESD_EV_CAN_ERROR_EXT   2
+/* esd CAN event ids */
+#define ESD_EV_CAN_ERROR_EXT   2 /* CAN controller specific diagnostic data */
 
 /* baudrate message flags */
-#define ESD_USB2_UBR           0x80000000
-#define ESD_USB2_LOM           0x40000000
-#define ESD_USB2_NO_BAUDRATE   0x7fffffff
+#define ESD_USB_UBR            0x80000000
+#define ESD_USB_LOM            0x40000000
+#define ESD_USB_NO_BAUDRATE    0x7fffffff
+
+/* bit timing CAN-USB/2 */
 #define ESD_USB2_TSEG1_MIN     1
 #define ESD_USB2_TSEG1_MAX     16
 #define ESD_USB2_TSEG1_SHIFT   16
@@ -68,7 +75,7 @@ MODULE_LICENSE("GPL v2");
 #define ESD_ID_ENABLE          0x80
 #define ESD_MAX_ID_SEGMENT     64
 
-/* SJA1000 ECC register (emulated by usb2 firmware) */
+/* SJA1000 ECC register (emulated by usb firmware) */
 #define SJA1000_ECC_SEG                0x1F
 #define SJA1000_ECC_DIR                0x20
 #define SJA1000_ECC_ERR                0x06
@@ -158,7 +165,7 @@ struct set_baudrate_msg {
 };
 
 /* Main message type used between library and application */
-struct __attribute__ ((packed)) esd_usb2_msg {
+struct __packed esd_usb_msg {
        union {
                struct header_msg hdr;
                struct version_msg version;
@@ -171,23 +178,23 @@ struct __attribute__ ((packed)) esd_usb2_msg {
        } msg;
 };
 
-static struct usb_device_id esd_usb2_table[] = {
+static struct usb_device_id esd_usb_table[] = {
        {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
        {USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)},
        {}
 };
-MODULE_DEVICE_TABLE(usb, esd_usb2_table);
+MODULE_DEVICE_TABLE(usb, esd_usb_table);
 
-struct esd_usb2_net_priv;
+struct esd_usb_net_priv;
 
 struct esd_tx_urb_context {
-       struct esd_usb2_net_priv *priv;
+       struct esd_usb_net_priv *priv;
        u32 echo_index;
 };
 
-struct esd_usb2 {
+struct esd_usb {
        struct usb_device *udev;
-       struct esd_usb2_net_priv *nets[ESD_USB2_MAX_NETS];
+       struct esd_usb_net_priv *nets[ESD_USB_MAX_NETS];
 
        struct usb_anchor rx_submitted;
 
@@ -198,22 +205,22 @@ struct esd_usb2 {
        dma_addr_t rxbuf_dma[MAX_RX_URBS];
 };
 
-struct esd_usb2_net_priv {
+struct esd_usb_net_priv {
        struct can_priv can; /* must be the first member */
 
        atomic_t active_tx_jobs;
        struct usb_anchor tx_submitted;
        struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
 
-       struct esd_usb2 *usb2;
+       struct esd_usb *usb;
        struct net_device *netdev;
        int index;
        u8 old_state;
        struct can_berr_counter bec;
 };
 
-static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
-                             struct esd_usb2_msg *msg)
+static void esd_usb_rx_event(struct esd_usb_net_priv *priv,
+                            struct esd_usb_msg *msg)
 {
        struct net_device_stats *stats = &priv->netdev->stats;
        struct can_frame *cf;
@@ -296,8 +303,8 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
        }
 }
 
-static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
-                               struct esd_usb2_msg *msg)
+static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv,
+                              struct esd_usb_msg *msg)
 {
        struct net_device_stats *stats = &priv->netdev->stats;
        struct can_frame *cf;
@@ -311,7 +318,7 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
        id = le32_to_cpu(msg->msg.rx.id);
 
        if (id & ESD_EVENT) {
-               esd_usb2_rx_event(priv, msg);
+               esd_usb_rx_event(priv, msg);
        } else {
                skb = alloc_can_skb(priv->netdev, &cf);
                if (skb == NULL) {
@@ -338,12 +345,10 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
 
                netif_rx(skb);
        }
-
-       return;
 }
 
-static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
-                                struct esd_usb2_msg *msg)
+static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv,
+                               struct esd_usb_msg *msg)
 {
        struct net_device_stats *stats = &priv->netdev->stats;
        struct net_device *netdev = priv->netdev;
@@ -370,9 +375,9 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
        netif_wake_queue(netdev);
 }
 
-static void esd_usb2_read_bulk_callback(struct urb *urb)
+static void esd_usb_read_bulk_callback(struct urb *urb)
 {
-       struct esd_usb2 *dev = urb->context;
+       struct esd_usb *dev = urb->context;
        int retval;
        int pos = 0;
        int i;
@@ -394,9 +399,9 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
        }
 
        while (pos < urb->actual_length) {
-               struct esd_usb2_msg *msg;
+               struct esd_usb_msg *msg;
 
-               msg = (struct esd_usb2_msg *)(urb->transfer_buffer + pos);
+               msg = (struct esd_usb_msg *)(urb->transfer_buffer + pos);
 
                switch (msg->msg.hdr.cmd) {
                case CMD_CAN_RX:
@@ -405,7 +410,7 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
                                break;
                        }
 
-                       esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
+                       esd_usb_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
                        break;
 
                case CMD_CAN_TX:
@@ -414,8 +419,8 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
                                break;
                        }
 
-                       esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
-                                            msg);
+                       esd_usb_tx_done_msg(dev->nets[msg->msg.txdone.net],
+                                           msg);
                        break;
                }
 
@@ -430,7 +435,7 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 resubmit_urb:
        usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
                          urb->transfer_buffer, RX_BUFFER_SIZE,
-                         esd_usb2_read_bulk_callback, dev);
+                         esd_usb_read_bulk_callback, dev);
 
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval == -ENODEV) {
@@ -442,19 +447,15 @@ resubmit_urb:
                dev_err(dev->udev->dev.parent,
                        "failed resubmitting read bulk urb: %d\n", retval);
        }
-
-       return;
 }
 
-/*
- * callback for bulk IN urb
- */
-static void esd_usb2_write_bulk_callback(struct urb *urb)
+/* callback for bulk IN urb */
+static void esd_usb_write_bulk_callback(struct urb *urb)
 {
        struct esd_tx_urb_context *context = urb->context;
-       struct esd_usb2_net_priv *priv;
+       struct esd_usb_net_priv *priv;
        struct net_device *netdev;
-       size_t size = sizeof(struct esd_usb2_msg);
+       size_t size = sizeof(struct esd_usb_msg);
 
        WARN_ON(!context);
 
@@ -478,7 +479,7 @@ static ssize_t firmware_show(struct device *d,
                             struct device_attribute *attr, char *buf)
 {
        struct usb_interface *intf = to_usb_interface(d);
-       struct esd_usb2 *dev = usb_get_intfdata(intf);
+       struct esd_usb *dev = usb_get_intfdata(intf);
 
        return sprintf(buf, "%d.%d.%d\n",
                       (dev->version >> 12) & 0xf,
@@ -491,7 +492,7 @@ static ssize_t hardware_show(struct device *d,
                             struct device_attribute *attr, char *buf)
 {
        struct usb_interface *intf = to_usb_interface(d);
-       struct esd_usb2 *dev = usb_get_intfdata(intf);
+       struct esd_usb *dev = usb_get_intfdata(intf);
 
        return sprintf(buf, "%d.%d.%d\n",
                       (dev->version >> 28) & 0xf,
@@ -504,13 +505,13 @@ static ssize_t nets_show(struct device *d,
                         struct device_attribute *attr, char *buf)
 {
        struct usb_interface *intf = to_usb_interface(d);
-       struct esd_usb2 *dev = usb_get_intfdata(intf);
+       struct esd_usb *dev = usb_get_intfdata(intf);
 
        return sprintf(buf, "%d", dev->net_count);
 }
 static DEVICE_ATTR_RO(nets);
 
-static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
+static int esd_usb_send_msg(struct esd_usb *dev, struct esd_usb_msg *msg)
 {
        int actual_length;
 
@@ -522,8 +523,8 @@ static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
                            1000);
 }
 
-static int esd_usb2_wait_msg(struct esd_usb2 *dev,
-                            struct esd_usb2_msg *msg)
+static int esd_usb_wait_msg(struct esd_usb *dev,
+                           struct esd_usb_msg *msg)
 {
        int actual_length;
 
@@ -535,7 +536,7 @@ static int esd_usb2_wait_msg(struct esd_usb2 *dev,
                            1000);
 }
 
-static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
+static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
 {
        int i, err = 0;
 
@@ -568,7 +569,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
                usb_fill_bulk_urb(urb, dev->udev,
                                  usb_rcvbulkpipe(dev->udev, 1),
                                  buf, RX_BUFFER_SIZE,
-                                 esd_usb2_read_bulk_callback, dev);
+                                 esd_usb_read_bulk_callback, dev);
                urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                usb_anchor_urb(urb, &dev->rx_submitted);
 
@@ -606,14 +607,12 @@ freeurb:
        return 0;
 }
 
-/*
- * Start interface
- */
-static int esd_usb2_start(struct esd_usb2_net_priv *priv)
+/* Start interface */
+static int esd_usb_start(struct esd_usb_net_priv *priv)
 {
-       struct esd_usb2 *dev = priv->usb2;
+       struct esd_usb *dev = priv->usb;
        struct net_device *netdev = priv->netdev;
-       struct esd_usb2_msg *msg;
+       struct esd_usb_msg *msg;
        int err, i;
 
        msg = kmalloc(sizeof(*msg), GFP_KERNEL);
@@ -622,8 +621,7 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
                goto out;
        }
 
-       /*
-        * Enable all IDs
+       /* Enable all IDs
         * The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
         * Each bit represents one 11 bit CAN identifier. A set bit
         * enables reception of the corresponding CAN identifier. A cleared
@@ -644,11 +642,11 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
        /* enable 29bit extended IDs */
        msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
 
-       err = esd_usb2_send_msg(dev, msg);
+       err = esd_usb_send_msg(dev, msg);
        if (err)
                goto out;
 
-       err = esd_usb2_setup_rx_urbs(dev);
+       err = esd_usb_setup_rx_urbs(dev);
        if (err)
                goto out;
 
@@ -664,9 +662,9 @@ out:
        return err;
 }
 
-static void unlink_all_urbs(struct esd_usb2 *dev)
+static void unlink_all_urbs(struct esd_usb *dev)
 {
-       struct esd_usb2_net_priv *priv;
+       struct esd_usb_net_priv *priv;
        int i, j;
 
        usb_kill_anchored_urbs(&dev->rx_submitted);
@@ -687,9 +685,9 @@ static void unlink_all_urbs(struct esd_usb2 *dev)
        }
 }
 
-static int esd_usb2_open(struct net_device *netdev)
+static int esd_usb_open(struct net_device *netdev)
 {
-       struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+       struct esd_usb_net_priv *priv = netdev_priv(netdev);
        int err;
 
        /* common open */
@@ -698,7 +696,7 @@ static int esd_usb2_open(struct net_device *netdev)
                return err;
 
        /* finally start device */
-       err = esd_usb2_start(priv);
+       err = esd_usb_start(priv);
        if (err) {
                netdev_warn(netdev, "couldn't start device: %d\n", err);
                close_candev(netdev);
@@ -710,20 +708,20 @@ static int esd_usb2_open(struct net_device *netdev)
        return 0;
 }
 
-static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
+static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
                                      struct net_device *netdev)
 {
-       struct esd_usb2_net_priv *priv = netdev_priv(netdev);
-       struct esd_usb2 *dev = priv->usb2;
+       struct esd_usb_net_priv *priv = netdev_priv(netdev);
+       struct esd_usb *dev = priv->usb;
        struct esd_tx_urb_context *context = NULL;
        struct net_device_stats *stats = &netdev->stats;
        struct can_frame *cf = (struct can_frame *)skb->data;
-       struct esd_usb2_msg *msg;
+       struct esd_usb_msg *msg;
        struct urb *urb;
        u8 *buf;
        int i, err;
        int ret = NETDEV_TX_OK;
-       size_t size = sizeof(struct esd_usb2_msg);
+       size_t size = sizeof(struct esd_usb_msg);
 
        if (can_dropped_invalid_skb(netdev, skb))
                return NETDEV_TX_OK;
@@ -745,7 +743,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
                goto nobufmem;
        }
 
-       msg = (struct esd_usb2_msg *)buf;
+       msg = (struct esd_usb_msg *)buf;
 
        msg->msg.hdr.len = 3; /* minimal length */
        msg->msg.hdr.cmd = CMD_CAN_TX;
@@ -771,9 +769,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
                }
        }
 
-       /*
-        * This may never happen.
-        */
+       /* This may never happen */
        if (!context) {
                netdev_warn(netdev, "couldn't find free context\n");
                ret = NETDEV_TX_BUSY;
@@ -788,7 +784,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
 
        usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
                          msg->msg.hdr.len << 2,
-                         esd_usb2_write_bulk_callback, context);
+                         esd_usb_write_bulk_callback, context);
 
        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -821,8 +817,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
 
        netif_trans_update(netdev);
 
-       /*
-        * Release our reference to this URB, the USB core will eventually free
+       /* Release our reference to this URB, the USB core will eventually free
         * it entirely.
         */
        usb_free_urb(urb);
@@ -839,24 +834,24 @@ nourbmem:
        return ret;
 }
 
-static int esd_usb2_close(struct net_device *netdev)
+static int esd_usb_close(struct net_device *netdev)
 {
-       struct esd_usb2_net_priv *priv = netdev_priv(netdev);
-       struct esd_usb2_msg *msg;
+       struct esd_usb_net_priv *priv = netdev_priv(netdev);
+       struct esd_usb_msg *msg;
        int i;
 
        msg = kmalloc(sizeof(*msg), GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
 
-       /* Disable all IDs (see esd_usb2_start()) */
+       /* Disable all IDs (see esd_usb_start()) */
        msg->msg.hdr.cmd = CMD_IDADD;
        msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
        msg->msg.filter.net = priv->index;
        msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
        for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
                msg->msg.filter.mask[i] = 0;
-       if (esd_usb2_send_msg(priv->usb2, msg) < 0)
+       if (esd_usb_send_msg(priv->usb, msg) < 0)
                netdev_err(netdev, "sending idadd message failed\n");
 
        /* set CAN controller to reset mode */
@@ -864,8 +859,8 @@ static int esd_usb2_close(struct net_device *netdev)
        msg->msg.hdr.cmd = CMD_SETBAUD;
        msg->msg.setbaud.net = priv->index;
        msg->msg.setbaud.rsvd = 0;
-       msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
-       if (esd_usb2_send_msg(priv->usb2, msg) < 0)
+       msg->msg.setbaud.baud = cpu_to_le32(ESD_USB_NO_BAUDRATE);
+       if (esd_usb_send_msg(priv->usb, msg) < 0)
                netdev_err(netdev, "sending setbaud message failed\n");
 
        priv->can.state = CAN_STATE_STOPPED;
@@ -879,10 +874,10 @@ static int esd_usb2_close(struct net_device *netdev)
        return 0;
 }
 
-static const struct net_device_ops esd_usb2_netdev_ops = {
-       .ndo_open = esd_usb2_open,
-       .ndo_stop = esd_usb2_close,
-       .ndo_start_xmit = esd_usb2_start_xmit,
+static const struct net_device_ops esd_usb_netdev_ops = {
+       .ndo_open = esd_usb_open,
+       .ndo_stop = esd_usb_close,
+       .ndo_start_xmit = esd_usb_start_xmit,
        .ndo_change_mtu = can_change_mtu,
 };
 
@@ -900,20 +895,20 @@ static const struct can_bittiming_const esd_usb2_bittiming_const = {
 
 static int esd_usb2_set_bittiming(struct net_device *netdev)
 {
-       struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+       struct esd_usb_net_priv *priv = netdev_priv(netdev);
        struct can_bittiming *bt = &priv->can.bittiming;
-       struct esd_usb2_msg *msg;
+       struct esd_usb_msg *msg;
        int err;
        u32 canbtr;
        int sjw_shift;
 
-       canbtr = ESD_USB2_UBR;
+       canbtr = ESD_USB_UBR;
        if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
-               canbtr |= ESD_USB2_LOM;
+               canbtr |= ESD_USB_LOM;
 
        canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
 
-       if (le16_to_cpu(priv->usb2->udev->descriptor.idProduct) ==
+       if (le16_to_cpu(priv->usb->udev->descriptor.idProduct) ==
            USB_CANUSBM_PRODUCT_ID)
                sjw_shift = ESD_USBM_SJW_SHIFT;
        else
@@ -941,16 +936,16 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
 
        netdev_info(netdev, "setting BTR=%#x\n", canbtr);
 
-       err = esd_usb2_send_msg(priv->usb2, msg);
+       err = esd_usb_send_msg(priv->usb, msg);
 
        kfree(msg);
        return err;
 }
 
-static int esd_usb2_get_berr_counter(const struct net_device *netdev,
-                                    struct can_berr_counter *bec)
+static int esd_usb_get_berr_counter(const struct net_device *netdev,
+                                   struct can_berr_counter *bec)
 {
-       struct esd_usb2_net_priv *priv = netdev_priv(netdev);
+       struct esd_usb_net_priv *priv = netdev_priv(netdev);
 
        bec->txerr = priv->bec.txerr;
        bec->rxerr = priv->bec.rxerr;
@@ -958,7 +953,7 @@ static int esd_usb2_get_berr_counter(const struct net_device *netdev,
        return 0;
 }
 
-static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
+static int esd_usb_set_mode(struct net_device *netdev, enum can_mode mode)
 {
        switch (mode) {
        case CAN_MODE_START:
@@ -972,11 +967,11 @@ static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
        return 0;
 }
 
-static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
+static int esd_usb_probe_one_net(struct usb_interface *intf, int index)
 {
-       struct esd_usb2 *dev = usb_get_intfdata(intf);
+       struct esd_usb *dev = usb_get_intfdata(intf);
        struct net_device *netdev;
-       struct esd_usb2_net_priv *priv;
+       struct esd_usb_net_priv *priv;
        int err = 0;
        int i;
 
@@ -995,7 +990,7 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
        for (i = 0; i < MAX_TX_URBS; i++)
                priv->tx_contexts[i].echo_index = MAX_TX_URBS;
 
-       priv->usb2 = dev;
+       priv->usb = dev;
        priv->netdev = netdev;
        priv->index = index;
 
@@ -1013,12 +1008,12 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
 
        priv->can.bittiming_const = &esd_usb2_bittiming_const;
        priv->can.do_set_bittiming = esd_usb2_set_bittiming;
-       priv->can.do_set_mode = esd_usb2_set_mode;
-       priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
+       priv->can.do_set_mode = esd_usb_set_mode;
+       priv->can.do_get_berr_counter = esd_usb_get_berr_counter;
 
        netdev->flags |= IFF_ECHO; /* we support local echo */
 
-       netdev->netdev_ops = &esd_usb2_netdev_ops;
+       netdev->netdev_ops = &esd_usb_netdev_ops;
 
        SET_NETDEV_DEV(netdev, &intf->dev);
        netdev->dev_id = index;
@@ -1038,17 +1033,16 @@ done:
        return err;
 }
 
-/*
- * probe function for new USB2 devices
+/* probe function for new USB devices
  *
  * check version information and number of available
  * CAN interfaces
  */
-static int esd_usb2_probe(struct usb_interface *intf,
+static int esd_usb_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
-       struct esd_usb2 *dev;
-       struct esd_usb2_msg *msg;
+       struct esd_usb *dev;
+       struct esd_usb_msg *msg;
        int i, err;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1076,13 +1070,13 @@ static int esd_usb2_probe(struct usb_interface *intf,
        msg->msg.version.flags = 0;
        msg->msg.version.drv_version = 0;
 
-       err = esd_usb2_send_msg(dev, msg);
+       err = esd_usb_send_msg(dev, msg);
        if (err < 0) {
                dev_err(&intf->dev, "sending version message failed\n");
                goto free_msg;
        }
 
-       err = esd_usb2_wait_msg(dev, msg);
+       err = esd_usb_wait_msg(dev, msg);
        if (err < 0) {
                dev_err(&intf->dev, "no version message answer\n");
                goto free_msg;
@@ -1105,7 +1099,7 @@ static int esd_usb2_probe(struct usb_interface *intf,
 
        /* do per device probing */
        for (i = 0; i < dev->net_count; i++)
-               esd_usb2_probe_one_net(intf, i);
+               esd_usb_probe_one_net(intf, i);
 
 free_msg:
        kfree(msg);
@@ -1115,12 +1109,10 @@ done:
        return err;
 }
 
-/*
- * called by the usb core when the device is removed from the system
- */
-static void esd_usb2_disconnect(struct usb_interface *intf)
+/* called by the usb core when the device is removed from the system */
+static void esd_usb_disconnect(struct usb_interface *intf)
 {
-       struct esd_usb2 *dev = usb_get_intfdata(intf);
+       struct esd_usb *dev = usb_get_intfdata(intf);
        struct net_device *netdev;
        int i;
 
@@ -1144,11 +1136,11 @@ static void esd_usb2_disconnect(struct usb_interface *intf)
 }
 
 /* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver esd_usb2_driver = {
-       .name = "esd_usb2",
-       .probe = esd_usb2_probe,
-       .disconnect = esd_usb2_disconnect,
-       .id_table = esd_usb2_table,
+static struct usb_driver esd_usb_driver = {
+       .name = "esd_usb",
+       .probe = esd_usb_probe,
+       .disconnect = esd_usb_disconnect,
+       .id_table = esd_usb_table,
 };
 
-module_usb_driver(esd_usb2_driver);
+module_usb_driver(esd_usb_driver);
index 2d73ebb..7353745 100644 (file)
@@ -1707,7 +1707,7 @@ static int es58x_alloc_rx_urbs(struct es58x_device *es58x_dev)
 {
        const struct device *dev = es58x_dev->dev;
        const struct es58x_parameters *param = es58x_dev->param;
-       size_t rx_buf_len = es58x_dev->rx_max_packet_size;
+       u16 rx_buf_len = usb_maxpacket(es58x_dev->udev, es58x_dev->rx_pipe);
        struct urb *urb;
        u8 *buf;
        int i;
@@ -1739,7 +1739,7 @@ static int es58x_alloc_rx_urbs(struct es58x_device *es58x_dev)
                dev_err(dev, "%s: Could not setup any rx URBs\n", __func__);
                return ret;
        }
-       dev_dbg(dev, "%s: Allocated %d rx URBs each of size %zu\n",
+       dev_dbg(dev, "%s: Allocated %d rx URBs each of size %u\n",
                __func__, i, rx_buf_len);
 
        return ret;
@@ -2223,7 +2223,6 @@ static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf,
                                             ep_in->bEndpointAddress);
        es58x_dev->tx_pipe = usb_sndbulkpipe(es58x_dev->udev,
                                             ep_out->bEndpointAddress);
-       es58x_dev->rx_max_packet_size = le16_to_cpu(ep_in->wMaxPacketSize);
 
        return es58x_dev;
 }
index e5033cb..d769bdf 100644 (file)
@@ -380,7 +380,6 @@ struct es58x_operators {
  * @timestamps: a temporary buffer to store the time stamps before
  *     feeding them to es58x_can_get_echo_skb(). Can only be used
  *     in RX branches.
- * @rx_max_packet_size: Maximum length of bulk-in URB.
  * @num_can_ch: Number of CAN channel (i.e. number of elements of @netdev).
  * @opened_channel_cnt: number of channels opened. Free of race
  *     conditions because its two users (net_device_ops:ndo_open()
@@ -401,8 +400,8 @@ struct es58x_device {
        const struct es58x_parameters *param;
        const struct es58x_operators *ops;
 
-       int rx_pipe;
-       int tx_pipe;
+       unsigned int rx_pipe;
+       unsigned int tx_pipe;
 
        struct usb_anchor rx_urbs;
        struct usb_anchor tx_urbs_busy;
@@ -414,7 +413,6 @@ struct es58x_device {
 
        u64 timestamps[ES58X_ECHO_BULK_MAX];
 
-       u16 rx_max_packet_size;
        u8 num_can_ch;
        u8 opened_channel_cnt;
 
index e179d31..0de2f97 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /* Xilinx CAN device driver
  *
- * Copyright (C) 2012 - 2014 Xilinx, Inc.
+ * Copyright (C) 2012 - 2022 Xilinx, Inc.
  * Copyright (C) 2009 PetaLogix. All rights reserved.
  * Copyright (C) 2017 - 2018 Sandvik Mining and Construction Oy
  *
@@ -9,6 +9,7 @@
  * This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
  */
 
+#include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/errno.h>
 #include <linux/init.h>
@@ -50,7 +51,7 @@ enum xcan_reg {
 
        /* only on CAN FD cores */
        XCAN_F_BRPR_OFFSET      = 0x088, /* Data Phase Baud Rate
-                                         * Prescalar
+                                         * Prescaler
                                          */
        XCAN_F_BTR_OFFSET       = 0x08C, /* Data Phase Bit Timing */
        XCAN_TRR_OFFSET         = 0x0090, /* TX Buffer Ready Request */
@@ -86,6 +87,8 @@ enum xcan_reg {
 #define XCAN_MSR_LBACK_MASK            0x00000002 /* Loop back mode select */
 #define XCAN_MSR_SLEEP_MASK            0x00000001 /* Sleep mode select */
 #define XCAN_BRPR_BRP_MASK             0x000000FF /* Baud rate prescaler */
+#define XCAN_BRPR_TDCO_MASK            GENMASK(12, 8)  /* TDCO */
+#define XCAN_2_BRPR_TDCO_MASK          GENMASK(13, 8)  /* TDCO for CANFD 2.0 */
 #define XCAN_BTR_SJW_MASK              0x00000180 /* Synchronous jump width */
 #define XCAN_BTR_TS2_MASK              0x00000070 /* Time segment 2 */
 #define XCAN_BTR_TS1_MASK              0x0000000F /* Time segment 1 */
@@ -99,6 +102,7 @@ enum xcan_reg {
 #define XCAN_ESR_STER_MASK             0x00000004 /* Stuff error */
 #define XCAN_ESR_FMER_MASK             0x00000002 /* Form error */
 #define XCAN_ESR_CRCER_MASK            0x00000001 /* CRC error */
+#define XCAN_SR_TDCV_MASK              GENMASK(22, 16) /* TDCV Value */
 #define XCAN_SR_TXFLL_MASK             0x00000400 /* TX FIFO is full */
 #define XCAN_SR_ESTAT_MASK             0x00000180 /* Error status */
 #define XCAN_SR_ERRWRN_MASK            0x00000040 /* Error warning */
@@ -132,6 +136,7 @@ enum xcan_reg {
 #define XCAN_DLCR_BRS_MASK             0x04000000 /* BRS Mask in DLC */
 
 /* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
+#define XCAN_BRPR_TDC_ENABLE           BIT(16) /* Transmitter Delay Compensation (TDC) Enable */
 #define XCAN_BTR_SJW_SHIFT             7  /* Synchronous jump width */
 #define XCAN_BTR_TS2_SHIFT             4  /* Time segment 2 */
 #define XCAN_BTR_SJW_SHIFT_CANFD       16 /* Synchronous jump width */
@@ -276,6 +281,26 @@ static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
        .brp_inc = 1,
 };
 
+/* Transmission Delay Compensation constants for CANFD 1.0 */
+static const struct can_tdc_const xcan_tdc_const_canfd = {
+       .tdcv_min = 0,
+       .tdcv_max = 0, /* Manual mode not supported. */
+       .tdco_min = 0,
+       .tdco_max = 32,
+       .tdcf_min = 0, /* Filter window not supported */
+       .tdcf_max = 0,
+};
+
+/* Transmission Delay Compensation constants for CANFD 2.0 */
+static const struct can_tdc_const xcan_tdc_const_canfd2 = {
+       .tdcv_min = 0,
+       .tdcv_max = 0, /* Manual mode not supported. */
+       .tdco_min = 0,
+       .tdco_max = 64,
+       .tdcf_min = 0, /* Filter window not supported */
+       .tdcf_max = 0,
+};
+
 /**
  * xcan_write_reg_le - Write a value to the device register little endian
  * @priv:      Driver private data structure
@@ -405,7 +430,7 @@ static int xcan_set_bittiming(struct net_device *ndev)
                return -EPERM;
        }
 
-       /* Setting Baud Rate prescalar value in BRPR Register */
+       /* Setting Baud Rate prescaler value in BRPR Register */
        btr0 = (bt->brp - 1);
 
        /* Setting Time Segment 1 in BTR Register */
@@ -422,8 +447,16 @@ static int xcan_set_bittiming(struct net_device *ndev)
 
        if (priv->devtype.cantype == XAXI_CANFD ||
            priv->devtype.cantype == XAXI_CANFD_2_0) {
-               /* Setting Baud Rate prescalar value in F_BRPR Register */
+               /* Setting Baud Rate prescaler value in F_BRPR Register */
                btr0 = dbt->brp - 1;
+               if (can_tdc_is_enabled(&priv->can)) {
+                       if (priv->devtype.cantype == XAXI_CANFD)
+                               btr0 |= FIELD_PREP(XCAN_BRPR_TDCO_MASK, priv->can.tdc.tdco) |
+                                       XCAN_BRPR_TDC_ENABLE;
+                       else
+                               btr0 |= FIELD_PREP(XCAN_2_BRPR_TDCO_MASK, priv->can.tdc.tdco) |
+                                       XCAN_BRPR_TDC_ENABLE;
+               }
 
                /* Setting Time Segment 1 in BTR Register */
                btr1 = dbt->prop_seg + dbt->phase_seg1 - 1;
@@ -1483,6 +1516,22 @@ static int xcan_get_berr_counter(const struct net_device *ndev,
        return 0;
 }
 
+/**
+ * xcan_get_auto_tdcv - Get Transmitter Delay Compensation Value
+ * @ndev:      Pointer to net_device structure
+ * @tdcv:      Pointer to TDCV value
+ *
+ * Return: 0 on success
+ */
+static int xcan_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv)
+{
+       struct xcan_priv *priv = netdev_priv(ndev);
+
+       *tdcv = FIELD_GET(XCAN_SR_TDCV_MASK, priv->read_reg(priv, XCAN_SR_OFFSET));
+
+       return 0;
+}
+
 static const struct net_device_ops xcan_netdev_ops = {
        .ndo_open       = xcan_open,
        .ndo_stop       = xcan_close,
@@ -1735,17 +1784,24 @@ static int xcan_probe(struct platform_device *pdev)
        priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
                                        CAN_CTRLMODE_BERR_REPORTING;
 
-       if (devtype->cantype == XAXI_CANFD)
+       if (devtype->cantype == XAXI_CANFD) {
                priv->can.data_bittiming_const =
                        &xcan_data_bittiming_const_canfd;
+               priv->can.tdc_const = &xcan_tdc_const_canfd;
+       }
 
-       if (devtype->cantype == XAXI_CANFD_2_0)
+       if (devtype->cantype == XAXI_CANFD_2_0) {
                priv->can.data_bittiming_const =
                        &xcan_data_bittiming_const_canfd2;
+               priv->can.tdc_const = &xcan_tdc_const_canfd2;
+       }
 
        if (devtype->cantype == XAXI_CANFD ||
-           devtype->cantype == XAXI_CANFD_2_0)
-               priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
+           devtype->cantype == XAXI_CANFD_2_0) {
+               priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD |
+                                               CAN_CTRLMODE_TDC_AUTO;
+               priv->can.do_get_auto_tdcv = xcan_get_auto_tdcv;
+       }
 
        priv->reg_base = addr;
        priv->tx_max = tx_max;
index 6d1fcb0..702d68a 100644 (file)
@@ -70,6 +70,15 @@ config NET_DSA_QCA8K
 
 source "drivers/net/dsa/realtek/Kconfig"
 
+config NET_DSA_RZN1_A5PSW
+       tristate "Renesas RZ/N1 A5PSW Ethernet switch support"
+       depends on OF && ARCH_RZN1
+       select NET_DSA_TAG_RZN1_A5PSW
+       select PCS_RZN1_MIIC
+       help
+         This driver supports the A5PSW switch, which is embedded in Renesas
+         RZ/N1 SoC.
+
 config NET_DSA_SMSC_LAN9303
        tristate
        select NET_DSA_TAG_LAN9303
index e73838c..b32907a 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
 obj-$(CONFIG_NET_DSA_MT7530)   += mt7530.o
 obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
 obj-$(CONFIG_NET_DSA_QCA8K)    += qca8k.o
+obj-$(CONFIG_NET_DSA_RZN1_A5PSW) += rzn1_a5psw.o
 obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
 obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
 obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
index 0e54b2a..308f15d 100644 (file)
@@ -320,8 +320,6 @@ static void b53_spi_remove(struct spi_device *spi)
 
        if (dev)
                b53_switch_remove(dev);
-
-       spi_set_drvdata(spi, NULL);
 }
 
 static void b53_spi_shutdown(struct spi_device *spi)
index c9e2a89..06b1efd 100644 (file)
@@ -1,49 +1,29 @@
 # SPDX-License-Identifier: GPL-2.0-only
-config NET_DSA_MICROCHIP_KSZ_COMMON
-       select NET_DSA_TAG_KSZ
-       tristate
-
-menuconfig NET_DSA_MICROCHIP_KSZ9477
-       tristate "Microchip KSZ9477 series switch support"
+menuconfig NET_DSA_MICROCHIP_KSZ_COMMON
+       tristate "Microchip KSZ8795/KSZ9477/LAN937x series switch support"
        depends on NET_DSA
-       select NET_DSA_MICROCHIP_KSZ_COMMON
+       select NET_DSA_TAG_KSZ
        help
-         This driver adds support for Microchip KSZ9477 switch chips.
+         This driver adds support for Microchip KSZ9477 series switch and
+         KSZ8795/KSZ88x3 switch chips.
 
 config NET_DSA_MICROCHIP_KSZ9477_I2C
-       tristate "KSZ9477 series I2C connected switch driver"
-       depends on NET_DSA_MICROCHIP_KSZ9477 && I2C
+       tristate "KSZ series I2C connected switch driver"
+       depends on NET_DSA_MICROCHIP_KSZ_COMMON && I2C
        select REGMAP_I2C
        help
          Select to enable support for registering switches configured through I2C.
 
-config NET_DSA_MICROCHIP_KSZ9477_SPI
-       tristate "KSZ9477 series SPI connected switch driver"
-       depends on NET_DSA_MICROCHIP_KSZ9477 && SPI
+config NET_DSA_MICROCHIP_KSZ_SPI
+       tristate "KSZ series SPI connected switch driver"
+       depends on NET_DSA_MICROCHIP_KSZ_COMMON && SPI
        select REGMAP_SPI
        help
          Select to enable support for registering switches configured through SPI.
 
-menuconfig NET_DSA_MICROCHIP_KSZ8795
-       tristate "Microchip KSZ8795 series switch support"
-       depends on NET_DSA
-       select NET_DSA_MICROCHIP_KSZ_COMMON
-       help
-         This driver adds support for Microchip KSZ8795/KSZ88X3 switch chips.
-
-config NET_DSA_MICROCHIP_KSZ8795_SPI
-       tristate "KSZ8795 series SPI connected switch driver"
-       depends on NET_DSA_MICROCHIP_KSZ8795 && SPI
-       select REGMAP_SPI
-       help
-         This driver accesses KSZ8795 chip through SPI.
-
-         It is required to use the KSZ8795 switch driver as the only access
-         is through SPI.
-
 config NET_DSA_MICROCHIP_KSZ8863_SMI
        tristate "KSZ series SMI connected switch driver"
-       depends on NET_DSA_MICROCHIP_KSZ8795
+       depends on NET_DSA_MICROCHIP_KSZ_COMMON
        select MDIO_BITBANG
        help
          Select to enable support for registering switches configured through
index 2a03b21..2887355 100644 (file)
@@ -1,8 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)     += ksz_common.o
-obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477)                += ksz9477.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON)     += ksz_switch.o
+ksz_switch-objs := ksz_common.o
+ksz_switch-objs += ksz9477.o
+ksz_switch-objs += ksz8795.o
+ksz_switch-objs += lan937x_main.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)    += ksz9477_i2c.o
-obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_SPI)    += ksz9477_spi.o
-obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795)                += ksz8795.o
-obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8795_SPI)    += ksz8795_spi.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI)                += ksz_spi.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)    += ksz8863_smi.o
index 03da369..42c50cc 100644 (file)
@@ -7,64 +7,55 @@
 
 #ifndef __KSZ8XXX_H
 #define __KSZ8XXX_H
-#include <linux/kernel.h>
 
-enum ksz_regs {
-       REG_IND_CTRL_0,
-       REG_IND_DATA_8,
-       REG_IND_DATA_CHECK,
-       REG_IND_DATA_HI,
-       REG_IND_DATA_LO,
-       REG_IND_MIB_CHECK,
-       REG_IND_BYTE,
-       P_FORCE_CTRL,
-       P_LINK_STATUS,
-       P_LOCAL_CTRL,
-       P_NEG_RESTART_CTRL,
-       P_REMOTE_STATUS,
-       P_SPEED_STATUS,
-       S_TAIL_TAG_CTRL,
-};
+#include <linux/types.h>
+#include <net/dsa.h>
+#include "ksz_common.h"
 
-enum ksz_masks {
-       PORT_802_1P_REMAPPING,
-       SW_TAIL_TAG_ENABLE,
-       MIB_COUNTER_OVERFLOW,
-       MIB_COUNTER_VALID,
-       VLAN_TABLE_FID,
-       VLAN_TABLE_MEMBERSHIP,
-       VLAN_TABLE_VALID,
-       STATIC_MAC_TABLE_VALID,
-       STATIC_MAC_TABLE_USE_FID,
-       STATIC_MAC_TABLE_FID,
-       STATIC_MAC_TABLE_OVERRIDE,
-       STATIC_MAC_TABLE_FWD_PORTS,
-       DYNAMIC_MAC_TABLE_ENTRIES_H,
-       DYNAMIC_MAC_TABLE_MAC_EMPTY,
-       DYNAMIC_MAC_TABLE_NOT_READY,
-       DYNAMIC_MAC_TABLE_ENTRIES,
-       DYNAMIC_MAC_TABLE_FID,
-       DYNAMIC_MAC_TABLE_SRC_PORT,
-       DYNAMIC_MAC_TABLE_TIMESTAMP,
-};
-
-enum ksz_shifts {
-       VLAN_TABLE_MEMBERSHIP_S,
-       VLAN_TABLE,
-       STATIC_MAC_FWD_PORTS,
-       STATIC_MAC_FID,
-       DYNAMIC_MAC_ENTRIES_H,
-       DYNAMIC_MAC_ENTRIES,
-       DYNAMIC_MAC_FID,
-       DYNAMIC_MAC_TIMESTAMP,
-       DYNAMIC_MAC_SRC_PORT,
-};
-
-struct ksz8 {
-       const u8 *regs;
-       const u32 *masks;
-       const u8 *shifts;
-       void *priv;
-};
+int ksz8_setup(struct dsa_switch *ds);
+u32 ksz8_get_port_addr(int port, int offset);
+void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member);
+void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port);
+void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port);
+void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
+void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val);
+int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
+                        u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries);
+int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
+                        struct alu_struct *alu);
+void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
+                         struct alu_struct *alu);
+void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt);
+void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                   u64 *dropped, u64 *cnt);
+void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze);
+void ksz8_port_init_cnt(struct ksz_device *dev, int port);
+int ksz8_fdb_dump(struct ksz_device *dev, int port,
+                 dsa_fdb_dump_cb_t *cb, void *data);
+int ksz8_mdb_add(struct ksz_device *dev, int port,
+                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
+int ksz8_mdb_del(struct ksz_device *dev, int port,
+                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
+int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag,
+                            struct netlink_ext_ack *extack);
+int ksz8_port_vlan_add(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_vlan *vlan,
+                      struct netlink_ext_ack *extack);
+int ksz8_port_vlan_del(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_vlan *vlan);
+int ksz8_port_mirror_add(struct ksz_device *dev, int port,
+                        struct dsa_mall_mirror_tc_entry *mirror,
+                        bool ingress, struct netlink_ext_ack *extack);
+void ksz8_port_mirror_del(struct ksz_device *dev, int port,
+                         struct dsa_mall_mirror_tc_entry *mirror);
+int ksz8_get_stp_reg(void);
+void ksz8_get_caps(struct ksz_device *dev, int port,
+                  struct phylink_config *config);
+void ksz8_config_cpu_port(struct dsa_switch *ds);
+int ksz8_enable_stp_addr(struct ksz_device *dev);
+int ksz8_reset_switch(struct ksz_device *dev);
+int ksz8_switch_detect(struct ksz_device *dev);
+int ksz8_switch_init(struct ksz_device *dev);
+void ksz8_switch_exit(struct ksz_device *dev);
 
 #endif
index 12a599d..911aace 100644 (file)
 #include "ksz8795_reg.h"
 #include "ksz8.h"
 
-static const u8 ksz8795_regs[] = {
-       [REG_IND_CTRL_0]                = 0x6E,
-       [REG_IND_DATA_8]                = 0x70,
-       [REG_IND_DATA_CHECK]            = 0x72,
-       [REG_IND_DATA_HI]               = 0x71,
-       [REG_IND_DATA_LO]               = 0x75,
-       [REG_IND_MIB_CHECK]             = 0x74,
-       [REG_IND_BYTE]                  = 0xA0,
-       [P_FORCE_CTRL]                  = 0x0C,
-       [P_LINK_STATUS]                 = 0x0E,
-       [P_LOCAL_CTRL]                  = 0x07,
-       [P_NEG_RESTART_CTRL]            = 0x0D,
-       [P_REMOTE_STATUS]               = 0x08,
-       [P_SPEED_STATUS]                = 0x09,
-       [S_TAIL_TAG_CTRL]               = 0x0C,
-};
-
-static const u32 ksz8795_masks[] = {
-       [PORT_802_1P_REMAPPING]         = BIT(7),
-       [SW_TAIL_TAG_ENABLE]            = BIT(1),
-       [MIB_COUNTER_OVERFLOW]          = BIT(6),
-       [MIB_COUNTER_VALID]             = BIT(5),
-       [VLAN_TABLE_FID]                = GENMASK(6, 0),
-       [VLAN_TABLE_MEMBERSHIP]         = GENMASK(11, 7),
-       [VLAN_TABLE_VALID]              = BIT(12),
-       [STATIC_MAC_TABLE_VALID]        = BIT(21),
-       [STATIC_MAC_TABLE_USE_FID]      = BIT(23),
-       [STATIC_MAC_TABLE_FID]          = GENMASK(30, 24),
-       [STATIC_MAC_TABLE_OVERRIDE]     = BIT(26),
-       [STATIC_MAC_TABLE_FWD_PORTS]    = GENMASK(24, 20),
-       [DYNAMIC_MAC_TABLE_ENTRIES_H]   = GENMASK(6, 0),
-       [DYNAMIC_MAC_TABLE_MAC_EMPTY]   = BIT(8),
-       [DYNAMIC_MAC_TABLE_NOT_READY]   = BIT(7),
-       [DYNAMIC_MAC_TABLE_ENTRIES]     = GENMASK(31, 29),
-       [DYNAMIC_MAC_TABLE_FID]         = GENMASK(26, 20),
-       [DYNAMIC_MAC_TABLE_SRC_PORT]    = GENMASK(26, 24),
-       [DYNAMIC_MAC_TABLE_TIMESTAMP]   = GENMASK(28, 27),
-};
-
-static const u8 ksz8795_shifts[] = {
-       [VLAN_TABLE_MEMBERSHIP_S]       = 7,
-       [VLAN_TABLE]                    = 16,
-       [STATIC_MAC_FWD_PORTS]          = 16,
-       [STATIC_MAC_FID]                = 24,
-       [DYNAMIC_MAC_ENTRIES_H]         = 3,
-       [DYNAMIC_MAC_ENTRIES]           = 29,
-       [DYNAMIC_MAC_FID]               = 16,
-       [DYNAMIC_MAC_TIMESTAMP]         = 27,
-       [DYNAMIC_MAC_SRC_PORT]          = 24,
-};
-
-static const u8 ksz8863_regs[] = {
-       [REG_IND_CTRL_0]                = 0x79,
-       [REG_IND_DATA_8]                = 0x7B,
-       [REG_IND_DATA_CHECK]            = 0x7B,
-       [REG_IND_DATA_HI]               = 0x7C,
-       [REG_IND_DATA_LO]               = 0x80,
-       [REG_IND_MIB_CHECK]             = 0x80,
-       [P_FORCE_CTRL]                  = 0x0C,
-       [P_LINK_STATUS]                 = 0x0E,
-       [P_LOCAL_CTRL]                  = 0x0C,
-       [P_NEG_RESTART_CTRL]            = 0x0D,
-       [P_REMOTE_STATUS]               = 0x0E,
-       [P_SPEED_STATUS]                = 0x0F,
-       [S_TAIL_TAG_CTRL]               = 0x03,
-};
-
-static const u32 ksz8863_masks[] = {
-       [PORT_802_1P_REMAPPING]         = BIT(3),
-       [SW_TAIL_TAG_ENABLE]            = BIT(6),
-       [MIB_COUNTER_OVERFLOW]          = BIT(7),
-       [MIB_COUNTER_VALID]             = BIT(6),
-       [VLAN_TABLE_FID]                = GENMASK(15, 12),
-       [VLAN_TABLE_MEMBERSHIP]         = GENMASK(18, 16),
-       [VLAN_TABLE_VALID]              = BIT(19),
-       [STATIC_MAC_TABLE_VALID]        = BIT(19),
-       [STATIC_MAC_TABLE_USE_FID]      = BIT(21),
-       [STATIC_MAC_TABLE_FID]          = GENMASK(29, 26),
-       [STATIC_MAC_TABLE_OVERRIDE]     = BIT(20),
-       [STATIC_MAC_TABLE_FWD_PORTS]    = GENMASK(18, 16),
-       [DYNAMIC_MAC_TABLE_ENTRIES_H]   = GENMASK(5, 0),
-       [DYNAMIC_MAC_TABLE_MAC_EMPTY]   = BIT(7),
-       [DYNAMIC_MAC_TABLE_NOT_READY]   = BIT(7),
-       [DYNAMIC_MAC_TABLE_ENTRIES]     = GENMASK(31, 28),
-       [DYNAMIC_MAC_TABLE_FID]         = GENMASK(19, 16),
-       [DYNAMIC_MAC_TABLE_SRC_PORT]    = GENMASK(21, 20),
-       [DYNAMIC_MAC_TABLE_TIMESTAMP]   = GENMASK(23, 22),
-};
-
-static u8 ksz8863_shifts[] = {
-       [VLAN_TABLE_MEMBERSHIP_S]       = 16,
-       [STATIC_MAC_FWD_PORTS]          = 16,
-       [STATIC_MAC_FID]                = 22,
-       [DYNAMIC_MAC_ENTRIES_H]         = 3,
-       [DYNAMIC_MAC_ENTRIES]           = 24,
-       [DYNAMIC_MAC_FID]               = 16,
-       [DYNAMIC_MAC_TIMESTAMP]         = 24,
-       [DYNAMIC_MAC_SRC_PORT]          = 20,
-};
-
 static bool ksz_is_ksz88x3(struct ksz_device *dev)
 {
        return dev->chip_id == 0x8830;
@@ -145,11 +45,12 @@ static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
 
 static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
 {
-       struct ksz8 *ksz8 = dev->priv;
-       const u8 *regs = ksz8->regs;
+       const u16 *regs;
        u16 ctrl_addr;
        int ret = 0;
 
+       regs = dev->info->regs;
+
        mutex_lock(&dev->alu_mutex);
 
        ctrl_addr = IND_ACC_TABLE(table) | addr;
@@ -162,7 +63,7 @@ static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
        return ret;
 }
 
-static int ksz8_reset_switch(struct ksz_device *dev)
+int ksz8_reset_switch(struct ksz_device *dev)
 {
        if (ksz_is_ksz88x3(dev)) {
                /* reset switch */
@@ -213,18 +114,17 @@ static void ksz8795_set_prio_queue(struct ksz_device *dev, int port, int queue)
                        true);
 }
 
-static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
+void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
 {
-       struct ksz8 *ksz8 = dev->priv;
        const u32 *masks;
-       const u8 *regs;
+       const u16 *regs;
        u16 ctrl_addr;
        u32 data;
        u8 check;
        int loop;
 
-       masks = ksz8->masks;
-       regs = ksz8->regs;
+       masks = dev->info->masks;
+       regs = dev->info->regs;
 
        ctrl_addr = addr + dev->info->reg_mib_cnt * port;
        ctrl_addr |= IND_ACC_TABLE(TABLE_MIB | TABLE_READ);
@@ -252,16 +152,15 @@ static void ksz8_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
 static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
                              u64 *dropped, u64 *cnt)
 {
-       struct ksz8 *ksz8 = dev->priv;
        const u32 *masks;
-       const u8 *regs;
+       const u16 *regs;
        u16 ctrl_addr;
        u32 data;
        u8 check;
        int loop;
 
-       masks = ksz8->masks;
-       regs = ksz8->regs;
+       masks = dev->info->masks;
+       regs = dev->info->regs;
 
        addr -= dev->info->reg_mib_cnt;
        ctrl_addr = (KSZ8795_MIB_TOTAL_RX_1 - KSZ8795_MIB_TOTAL_RX_0) * port;
@@ -305,13 +204,14 @@ static void ksz8795_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
 static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
                              u64 *dropped, u64 *cnt)
 {
-       struct ksz8 *ksz8 = dev->priv;
-       const u8 *regs = ksz8->regs;
        u32 *last = (u32 *)dropped;
+       const u16 *regs;
        u16 ctrl_addr;
        u32 data;
        u32 cur;
 
+       regs = dev->info->regs;
+
        addr -= dev->info->reg_mib_cnt;
        ctrl_addr = addr ? KSZ8863_MIB_PACKET_DROPPED_TX_0 :
                           KSZ8863_MIB_PACKET_DROPPED_RX_0;
@@ -334,8 +234,8 @@ static void ksz8863_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
        }
 }
 
-static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
-                          u64 *dropped, u64 *cnt)
+void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                   u64 *dropped, u64 *cnt)
 {
        if (ksz_is_ksz88x3(dev))
                ksz8863_r_mib_pkt(dev, port, addr, dropped, cnt);
@@ -343,7 +243,7 @@ static void ksz8_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
                ksz8795_r_mib_pkt(dev, port, addr, dropped, cnt);
 }
 
-static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
+void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
 {
        if (ksz_is_ksz88x3(dev))
                return;
@@ -358,7 +258,7 @@ static void ksz8_freeze_mib(struct ksz_device *dev, int port, bool freeze)
                ksz_cfg(dev, REG_SW_CTRL_6, BIT(port), false);
 }
 
-static void ksz8_port_init_cnt(struct ksz_device *dev, int port)
+void ksz8_port_init_cnt(struct ksz_device *dev, int port)
 {
        struct ksz_port_mib *mib = &dev->ports[port].mib;
        u64 *dropped;
@@ -392,10 +292,11 @@ static void ksz8_port_init_cnt(struct ksz_device *dev, int port)
 
 static void ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
 {
-       struct ksz8 *ksz8 = dev->priv;
-       const u8 *regs = ksz8->regs;
+       const u16 *regs;
        u16 ctrl_addr;
 
+       regs = dev->info->regs;
+
        ctrl_addr = IND_ACC_TABLE(table | TABLE_READ) | addr;
 
        mutex_lock(&dev->alu_mutex);
@@ -406,10 +307,11 @@ static void ksz8_r_table(struct ksz_device *dev, int table, u16 addr, u64 *data)
 
 static void ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data)
 {
-       struct ksz8 *ksz8 = dev->priv;
-       const u8 *regs = ksz8->regs;
+       const u16 *regs;
        u16 ctrl_addr;
 
+       regs = dev->info->regs;
+
        ctrl_addr = IND_ACC_TABLE(table) | addr;
 
        mutex_lock(&dev->alu_mutex);
@@ -420,13 +322,12 @@ static void ksz8_w_table(struct ksz_device *dev, int table, u16 addr, u64 data)
 
 static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data)
 {
-       struct ksz8 *ksz8 = dev->priv;
        int timeout = 100;
        const u32 *masks;
-       const u8 *regs;
+       const u16 *regs;
 
-       masks = ksz8->masks;
-       regs = ksz8->regs;
+       masks = dev->info->masks;
+       regs = dev->info->regs;
 
        do {
                ksz_read8(dev, regs[REG_IND_DATA_CHECK], data);
@@ -447,22 +348,20 @@ static int ksz8_valid_dyn_entry(struct ksz_device *dev, u8 *data)
        return 0;
 }
 
-static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
-                               u8 *mac_addr, u8 *fid, u8 *src_port,
-                               u8 *timestamp, u16 *entries)
+int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr, u8 *mac_addr,
+                        u8 *fid, u8 *src_port, u8 *timestamp, u16 *entries)
 {
-       struct ksz8 *ksz8 = dev->priv;
        u32 data_hi, data_lo;
        const u8 *shifts;
        const u32 *masks;
-       const u8 *regs;
+       const u16 *regs;
        u16 ctrl_addr;
        u8 data;
        int rc;
 
-       shifts = ksz8->shifts;
-       masks = ksz8->masks;
-       regs = ksz8->regs;
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+       regs = dev->info->regs;
 
        ctrl_addr = IND_ACC_TABLE(TABLE_DYNAMIC_MAC | TABLE_READ) | addr;
 
@@ -512,17 +411,16 @@ static int ksz8_r_dyn_mac_table(struct ksz_device *dev, u16 addr,
        return rc;
 }
 
-static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
-                               struct alu_struct *alu)
+int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
+                        struct alu_struct *alu)
 {
-       struct ksz8 *ksz8 = dev->priv;
        u32 data_hi, data_lo;
        const u8 *shifts;
        const u32 *masks;
        u64 data;
 
-       shifts = ksz8->shifts;
-       masks = ksz8->masks;
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
 
        ksz8_r_table(dev, TABLE_STATIC_MAC, addr, &data);
        data_hi = data >> 32;
@@ -551,17 +449,16 @@ static int ksz8_r_sta_mac_table(struct ksz_device *dev, u16 addr,
        return -ENXIO;
 }
 
-static void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
-                                struct alu_struct *alu)
+void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
+                         struct alu_struct *alu)
 {
-       struct ksz8 *ksz8 = dev->priv;
        u32 data_hi, data_lo;
        const u8 *shifts;
        const u32 *masks;
        u64 data;
 
-       shifts = ksz8->shifts;
-       masks = ksz8->masks;
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
 
        data_lo = ((u32)alu->mac[2] << 24) |
                ((u32)alu->mac[3] << 16) |
@@ -587,12 +484,11 @@ static void ksz8_w_sta_mac_table(struct ksz_device *dev, u16 addr,
 static void ksz8_from_vlan(struct ksz_device *dev, u32 vlan, u8 *fid,
                           u8 *member, u8 *valid)
 {
-       struct ksz8 *ksz8 = dev->priv;
        const u8 *shifts;
        const u32 *masks;
 
-       shifts = ksz8->shifts;
-       masks = ksz8->masks;
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
 
        *fid = vlan & masks[VLAN_TABLE_FID];
        *member = (vlan & masks[VLAN_TABLE_MEMBERSHIP]) >>
@@ -603,12 +499,11 @@ static void ksz8_from_vlan(struct ksz_device *dev, u32 vlan, u8 *fid,
 static void ksz8_to_vlan(struct ksz_device *dev, u8 fid, u8 member, u8 valid,
                         u16 *vlan)
 {
-       struct ksz8 *ksz8 = dev->priv;
        const u8 *shifts;
        const u32 *masks;
 
-       shifts = ksz8->shifts;
-       masks = ksz8->masks;
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
 
        *vlan = fid;
        *vlan |= (u16)member << shifts[VLAN_TABLE_MEMBERSHIP_S];
@@ -618,12 +513,11 @@ static void ksz8_to_vlan(struct ksz_device *dev, u8 fid, u8 member, u8 valid,
 
 static void ksz8_r_vlan_entries(struct ksz_device *dev, u16 addr)
 {
-       struct ksz8 *ksz8 = dev->priv;
        const u8 *shifts;
        u64 data;
        int i;
 
-       shifts = ksz8->shifts;
+       shifts = dev->info->shifts;
 
        ksz8_r_table(dev, TABLE_VLAN, addr, &data);
        addr *= 4;
@@ -663,16 +557,17 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
        ksz8_w_table(dev, TABLE_VLAN, addr, buf);
 }
 
-static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
+void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
 {
-       struct ksz8 *ksz8 = dev->priv;
        u8 restart, speed, ctrl, link;
-       const u8 *regs = ksz8->regs;
        int processed = true;
+       const u16 *regs;
        u8 val1, val2;
        u16 data = 0;
        u8 p = phy;
 
+       regs = dev->info->regs;
+
        switch (reg) {
        case MII_BMCR:
                ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart);
@@ -786,13 +681,14 @@ static void ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
                *val = data;
 }
 
-static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
+void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
 {
-       struct ksz8 *ksz8 = dev->priv;
        u8 restart, speed, ctrl, data;
-       const u8 *regs = ksz8->regs;
+       const u16 *regs;
        u8 p = phy;
 
+       regs = dev->info->regs;
+
        switch (reg) {
        case MII_BMCR:
 
@@ -898,30 +794,7 @@ static void ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
        }
 }
 
-static enum dsa_tag_protocol ksz8_get_tag_protocol(struct dsa_switch *ds,
-                                                  int port,
-                                                  enum dsa_tag_protocol mp)
-{
-       struct ksz_device *dev = ds->priv;
-
-       /* ksz88x3 uses the same tag schema as KSZ9893 */
-       return ksz_is_ksz88x3(dev) ?
-               DSA_TAG_PROTO_KSZ9893 : DSA_TAG_PROTO_KSZ8795;
-}
-
-static u32 ksz8_sw_get_phy_flags(struct dsa_switch *ds, int port)
-{
-       /* Silicon Errata Sheet (DS80000830A):
-        * Port 1 does not work with LinkMD Cable-Testing.
-        * Port 1 does not respond to received PAUSE control frames.
-        */
-       if (!port)
-               return MICREL_KSZ8_P1_ERRATA;
-
-       return 0;
-}
-
-static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
+void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
 {
        u8 data;
 
@@ -931,16 +804,14 @@ static void ksz8_cfg_port_member(struct ksz_device *dev, int port, u8 member)
        ksz_pwrite8(dev, port, P_MIRROR_CTRL, data);
 }
 
-static void ksz8_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
-{
-       ksz_port_stp_state_set(ds, port, state, P_STP_CTRL);
-}
-
-static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
+void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
 {
        u8 learn[DSA_MAX_PORTS];
        int first, index, cnt;
        struct ksz_port *p;
+       const u16 *regs;
+
+       regs = dev->info->regs;
 
        if ((uint)port < dev->info->port_cnt) {
                first = port;
@@ -954,9 +825,9 @@ static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
                p = &dev->ports[index];
                if (!p->on)
                        continue;
-               ksz_pread8(dev, index, P_STP_CTRL, &learn[index]);
+               ksz_pread8(dev, index, regs[P_STP_CTRL], &learn[index]);
                if (!(learn[index] & PORT_LEARN_DISABLE))
-                       ksz_pwrite8(dev, index, P_STP_CTRL,
+                       ksz_pwrite8(dev, index, regs[P_STP_CTRL],
                                    learn[index] | PORT_LEARN_DISABLE);
        }
        ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true);
@@ -965,15 +836,113 @@ static void ksz8_flush_dyn_mac_table(struct ksz_device *dev, int port)
                if (!p->on)
                        continue;
                if (!(learn[index] & PORT_LEARN_DISABLE))
-                       ksz_pwrite8(dev, index, P_STP_CTRL, learn[index]);
+                       ksz_pwrite8(dev, index, regs[P_STP_CTRL], learn[index]);
        }
 }
 
-static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag,
-                                   struct netlink_ext_ack *extack)
+int ksz8_fdb_dump(struct ksz_device *dev, int port,
+                 dsa_fdb_dump_cb_t *cb, void *data)
 {
-       struct ksz_device *dev = ds->priv;
+       int ret = 0;
+       u16 i = 0;
+       u16 entries = 0;
+       u8 timestamp = 0;
+       u8 fid;
+       u8 member;
+       struct alu_struct alu;
+
+       do {
+               alu.is_static = false;
+               ret = ksz8_r_dyn_mac_table(dev, i, alu.mac, &fid, &member,
+                                          &timestamp, &entries);
+               if (!ret && (member & BIT(port))) {
+                       ret = cb(alu.mac, alu.fid, alu.is_static, data);
+                       if (ret)
+                               break;
+               }
+               i++;
+       } while (i < entries);
+       if (i >= entries)
+               ret = 0;
+
+       return ret;
+}
+
+int ksz8_mdb_add(struct ksz_device *dev, int port,
+                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
+{
+       struct alu_struct alu;
+       int index;
+       int empty = 0;
+
+       alu.port_forward = 0;
+       for (index = 0; index < dev->info->num_statics; index++) {
+               if (!ksz8_r_sta_mac_table(dev, index, &alu)) {
+                       /* Found one already in static MAC table. */
+                       if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
+                           alu.fid == mdb->vid)
+                               break;
+               /* Remember the first empty entry. */
+               } else if (!empty) {
+                       empty = index + 1;
+               }
+       }
+
+       /* no available entry */
+       if (index == dev->info->num_statics && !empty)
+               return -ENOSPC;
+
+       /* add entry */
+       if (index == dev->info->num_statics) {
+               index = empty - 1;
+               memset(&alu, 0, sizeof(alu));
+               memcpy(alu.mac, mdb->addr, ETH_ALEN);
+               alu.is_static = true;
+       }
+       alu.port_forward |= BIT(port);
+       if (mdb->vid) {
+               alu.is_use_fid = true;
+
+               /* Need a way to map VID to FID. */
+               alu.fid = mdb->vid;
+       }
+       ksz8_w_sta_mac_table(dev, index, &alu);
+
+       return 0;
+}
+
+int ksz8_mdb_del(struct ksz_device *dev, int port,
+                const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
+{
+       struct alu_struct alu;
+       int index;
+
+       for (index = 0; index < dev->info->num_statics; index++) {
+               if (!ksz8_r_sta_mac_table(dev, index, &alu)) {
+                       /* Found one already in static MAC table. */
+                       if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
+                           alu.fid == mdb->vid)
+                               break;
+               }
+       }
+
+       /* no available entry */
+       if (index == dev->info->num_statics)
+               goto exit;
+
+       /* clear port */
+       alu.port_forward &= ~BIT(port);
+       if (!alu.port_forward)
+               alu.is_static = false;
+       ksz8_w_sta_mac_table(dev, index, &alu);
+
+exit:
+       return 0;
+}
 
+int ksz8_port_vlan_filtering(struct ksz_device *dev, int port, bool flag,
+                            struct netlink_ext_ack *extack)
+{
        if (ksz_is_ksz88x3(dev))
                return -ENOTSUPP;
 
@@ -998,12 +967,11 @@ static void ksz8_port_enable_pvid(struct ksz_device *dev, int port, bool state)
        }
 }
 
-static int ksz8_port_vlan_add(struct dsa_switch *ds, int port,
-                             const struct switchdev_obj_port_vlan *vlan,
-                             struct netlink_ext_ack *extack)
+int ksz8_port_vlan_add(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_vlan *vlan,
+                      struct netlink_ext_ack *extack)
 {
        bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
-       struct ksz_device *dev = ds->priv;
        struct ksz_port *p = &dev->ports[port];
        u16 data, new_pvid = 0;
        u8 fid, member, valid;
@@ -1071,10 +1039,9 @@ static int ksz8_port_vlan_add(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int ksz8_port_vlan_del(struct dsa_switch *ds, int port,
-                             const struct switchdev_obj_port_vlan *vlan)
+int ksz8_port_vlan_del(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_vlan *vlan)
 {
-       struct ksz_device *dev = ds->priv;
        u16 data, pvid;
        u8 fid, member, valid;
 
@@ -1104,12 +1071,10 @@ static int ksz8_port_vlan_del(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int ksz8_port_mirror_add(struct dsa_switch *ds, int port,
-                               struct dsa_mall_mirror_tc_entry *mirror,
-                               bool ingress, struct netlink_ext_ack *extack)
+int ksz8_port_mirror_add(struct ksz_device *dev, int port,
+                        struct dsa_mall_mirror_tc_entry *mirror,
+                        bool ingress, struct netlink_ext_ack *extack)
 {
-       struct ksz_device *dev = ds->priv;
-
        if (ingress) {
                ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
                dev->mirror_rx |= BIT(port);
@@ -1128,10 +1093,9 @@ static int ksz8_port_mirror_add(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static void ksz8_port_mirror_del(struct dsa_switch *ds, int port,
-                                struct dsa_mall_mirror_tc_entry *mirror)
+void ksz8_port_mirror_del(struct ksz_device *dev, int port,
+                         struct dsa_mall_mirror_tc_entry *mirror)
 {
-       struct ksz_device *dev = ds->priv;
        u8 data;
 
        if (mirror->ingress) {
@@ -1197,14 +1161,13 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
        p->phydev.duplex = 1;
 }
 
-static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 {
        struct dsa_switch *ds = dev->ds;
-       struct ksz8 *ksz8 = dev->priv;
        const u32 *masks;
        u8 member;
 
-       masks = ksz8->masks;
+       masks = dev->info->masks;
 
        /* enable broadcast storm limit */
        ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
@@ -1234,17 +1197,17 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
        ksz8_cfg_port_member(dev, port, member);
 }
 
-static void ksz8_config_cpu_port(struct dsa_switch *ds)
+void ksz8_config_cpu_port(struct dsa_switch *ds)
 {
        struct ksz_device *dev = ds->priv;
-       struct ksz8 *ksz8 = dev->priv;
-       const u8 *regs = ksz8->regs;
        struct ksz_port *p;
        const u32 *masks;
+       const u16 *regs;
        u8 remote;
        int i;
 
-       masks = ksz8->masks;
+       masks = dev->info->masks;
+       regs = dev->info->regs;
 
        /* Switch marks the maximum frame with extra byte as oversize. */
        ksz_cfg(dev, REG_SW_CTRL_2, SW_LEGAL_PACKET_DISABLE, true);
@@ -1258,7 +1221,7 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)
        for (i = 0; i < dev->phy_port_cnt; i++) {
                p = &dev->ports[i];
 
-               ksz8_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+               ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
 
                /* Last port may be disabled. */
                if (i == dev->phy_port_cnt)
@@ -1272,15 +1235,15 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)
                        continue;
                if (!ksz_is_ksz88x3(dev)) {
                        ksz_pread8(dev, i, regs[P_REMOTE_STATUS], &remote);
-                       if (remote & PORT_FIBER_MODE)
+                       if (remote & KSZ8_PORT_FIBER_MODE)
                                p->fiber = 1;
                }
                if (p->fiber)
-                       ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL,
-                                    true);
+                       ksz_port_cfg(dev, i, regs[P_STP_CTRL],
+                                    PORT_FORCE_FLOW_CTRL, true);
                else
-                       ksz_port_cfg(dev, i, P_STP_CTRL, PORT_FORCE_FLOW_CTRL,
-                                    false);
+                       ksz_port_cfg(dev, i, regs[P_STP_CTRL],
+                                    PORT_FORCE_FLOW_CTRL, false);
        }
 }
 
@@ -1301,22 +1264,26 @@ static int ksz8_handle_global_errata(struct dsa_switch *ds)
        return ret;
 }
 
-static int ksz8_setup(struct dsa_switch *ds)
+int ksz8_enable_stp_addr(struct ksz_device *dev)
 {
-       struct ksz_device *dev = ds->priv;
        struct alu_struct alu;
-       int i, ret = 0;
 
-       dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
-                                      dev->info->num_vlans, GFP_KERNEL);
-       if (!dev->vlan_cache)
-               return -ENOMEM;
+       /* Setup STP address for STP operation. */
+       memset(&alu, 0, sizeof(alu));
+       ether_addr_copy(alu.mac, eth_stp_addr);
+       alu.is_static = true;
+       alu.is_override = true;
+       alu.port_forward = dev->info->cpu_ports;
 
-       ret = ksz8_reset_switch(dev);
-       if (ret) {
-               dev_err(ds->dev, "failed to reset switch\n");
-               return ret;
-       }
+       ksz8_w_sta_mac_table(dev, 0, &alu);
+
+       return 0;
+}
+
+int ksz8_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       int i;
 
        ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true);
 
@@ -1335,10 +1302,6 @@ static int ksz8_setup(struct dsa_switch *ds)
                           UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
                           UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);
 
-       ksz8_config_cpu_port(ds);
-
-       ksz_cfg(dev, REG_SW_CTRL_2, MULTICAST_STORM_DISABLE, true);
-
        ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_REPLACE_VID, false);
 
        ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
@@ -1346,38 +1309,15 @@ static int ksz8_setup(struct dsa_switch *ds)
        if (!ksz_is_ksz88x3(dev))
                ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);
 
-       /* set broadcast storm protection 10% rate */
-       regmap_update_bits(dev->regmap[1], S_REPLACE_VID_CTRL,
-                          BROADCAST_STORM_RATE,
-                          (BROADCAST_STORM_VALUE *
-                          BROADCAST_STORM_PROT_RATE) / 100);
-
        for (i = 0; i < (dev->info->num_vlans / 4); i++)
                ksz8_r_vlan_entries(dev, i);
 
-       /* Setup STP address for STP operation. */
-       memset(&alu, 0, sizeof(alu));
-       ether_addr_copy(alu.mac, eth_stp_addr);
-       alu.is_static = true;
-       alu.is_override = true;
-       alu.port_forward = dev->info->cpu_ports;
-
-       ksz8_w_sta_mac_table(dev, 0, &alu);
-
-       ksz_init_mib_timer(dev);
-
-       ds->configure_vlan_while_not_filtering = false;
-
        return ksz8_handle_global_errata(ds);
 }
 
-static void ksz8_get_caps(struct dsa_switch *ds, int port,
-                         struct phylink_config *config)
+void ksz8_get_caps(struct ksz_device *dev, int port,
+                  struct phylink_config *config)
 {
-       struct ksz_device *dev = ds->priv;
-
-       ksz_phylink_get_caps(ds, port, config);
-
        config->mac_capabilities = MAC_10 | MAC_100;
 
        /* Silicon Errata Sheet (DS80000830A):
@@ -1393,102 +1333,17 @@ static void ksz8_get_caps(struct dsa_switch *ds, int port,
                config->mac_capabilities |= MAC_ASYM_PAUSE;
 }
 
-static const struct dsa_switch_ops ksz8_switch_ops = {
-       .get_tag_protocol       = ksz8_get_tag_protocol,
-       .get_phy_flags          = ksz8_sw_get_phy_flags,
-       .setup                  = ksz8_setup,
-       .phy_read               = ksz_phy_read16,
-       .phy_write              = ksz_phy_write16,
-       .phylink_get_caps       = ksz8_get_caps,
-       .phylink_mac_link_down  = ksz_mac_link_down,
-       .port_enable            = ksz_enable_port,
-       .get_strings            = ksz_get_strings,
-       .get_ethtool_stats      = ksz_get_ethtool_stats,
-       .get_sset_count         = ksz_sset_count,
-       .port_bridge_join       = ksz_port_bridge_join,
-       .port_bridge_leave      = ksz_port_bridge_leave,
-       .port_stp_state_set     = ksz8_port_stp_state_set,
-       .port_fast_age          = ksz_port_fast_age,
-       .port_vlan_filtering    = ksz8_port_vlan_filtering,
-       .port_vlan_add          = ksz8_port_vlan_add,
-       .port_vlan_del          = ksz8_port_vlan_del,
-       .port_fdb_dump          = ksz_port_fdb_dump,
-       .port_mdb_add           = ksz_port_mdb_add,
-       .port_mdb_del           = ksz_port_mdb_del,
-       .port_mirror_add        = ksz8_port_mirror_add,
-       .port_mirror_del        = ksz8_port_mirror_del,
-};
-
-static u32 ksz8_get_port_addr(int port, int offset)
+u32 ksz8_get_port_addr(int port, int offset)
 {
        return PORT_CTRL_ADDR(port, offset);
 }
 
-static int ksz8_switch_detect(struct ksz_device *dev)
+int ksz8_switch_init(struct ksz_device *dev)
 {
-       u8 id1, id2;
-       u16 id16;
-       int ret;
-
-       /* read chip id */
-       ret = ksz_read16(dev, REG_CHIP_ID0, &id16);
-       if (ret)
-               return ret;
-
-       id1 = id16 >> 8;
-       id2 = id16 & SW_CHIP_ID_M;
-
-       switch (id1) {
-       case KSZ87_FAMILY_ID:
-               if ((id2 != CHIP_ID_94 && id2 != CHIP_ID_95))
-                       return -ENODEV;
-
-               if (id2 == CHIP_ID_95) {
-                       u8 val;
-
-                       id2 = 0x95;
-                       ksz_read8(dev, REG_PORT_STATUS_0, &val);
-                       if (val & PORT_FIBER_MODE)
-                               id2 = 0x65;
-               } else if (id2 == CHIP_ID_94) {
-                       id2 = 0x94;
-               }
-               break;
-       case KSZ88_FAMILY_ID:
-               if (id2 != CHIP_ID_63)
-                       return -ENODEV;
-               break;
-       default:
-               dev_err(dev->dev, "invalid family id: %d\n", id1);
-               return -ENODEV;
-       }
-       id16 &= ~0xff;
-       id16 |= id2;
-       dev->chip_id = id16;
-
-       return 0;
-}
-
-static int ksz8_switch_init(struct ksz_device *dev)
-{
-       struct ksz8 *ksz8 = dev->priv;
-
-       dev->ds->ops = &ksz8_switch_ops;
-
        dev->cpu_port = fls(dev->info->cpu_ports) - 1;
        dev->phy_port_cnt = dev->info->port_cnt - 1;
        dev->port_mask = (BIT(dev->phy_port_cnt) - 1) | dev->info->cpu_ports;
 
-       if (ksz_is_ksz88x3(dev)) {
-               ksz8->regs = ksz8863_regs;
-               ksz8->masks = ksz8863_masks;
-               ksz8->shifts = ksz8863_shifts;
-       } else {
-               ksz8->regs = ksz8795_regs;
-               ksz8->masks = ksz8795_masks;
-               ksz8->shifts = ksz8795_shifts;
-       }
-
        /* We rely on software untagging on the CPU port, so that we
         * can support both tagged and untagged VLANs
         */
@@ -1502,37 +1357,11 @@ static int ksz8_switch_init(struct ksz_device *dev)
        return 0;
 }
 
-static void ksz8_switch_exit(struct ksz_device *dev)
+void ksz8_switch_exit(struct ksz_device *dev)
 {
        ksz8_reset_switch(dev);
 }
 
-static const struct ksz_dev_ops ksz8_dev_ops = {
-       .get_port_addr = ksz8_get_port_addr,
-       .cfg_port_member = ksz8_cfg_port_member,
-       .flush_dyn_mac_table = ksz8_flush_dyn_mac_table,
-       .port_setup = ksz8_port_setup,
-       .r_phy = ksz8_r_phy,
-       .w_phy = ksz8_w_phy,
-       .r_dyn_mac_table = ksz8_r_dyn_mac_table,
-       .r_sta_mac_table = ksz8_r_sta_mac_table,
-       .w_sta_mac_table = ksz8_w_sta_mac_table,
-       .r_mib_cnt = ksz8_r_mib_cnt,
-       .r_mib_pkt = ksz8_r_mib_pkt,
-       .freeze_mib = ksz8_freeze_mib,
-       .port_init_cnt = ksz8_port_init_cnt,
-       .shutdown = ksz8_reset_switch,
-       .detect = ksz8_switch_detect,
-       .init = ksz8_switch_init,
-       .exit = ksz8_switch_exit,
-};
-
-int ksz8_switch_register(struct ksz_device *dev)
-{
-       return ksz_switch_register(dev, &ksz8_dev_ops);
-}
-EXPORT_SYMBOL(ksz8_switch_register);
-
 MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
 MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch DSA Driver");
 MODULE_LICENSE("GPL");
index 4109433..a848eb4 100644 (file)
 #define KS_PRIO_M                      0x3
 #define KS_PRIO_S                      2
 
-#define REG_CHIP_ID0                   0x00
-
-#define KSZ87_FAMILY_ID                        0x87
-#define KSZ88_FAMILY_ID                        0x88
-
-#define REG_CHIP_ID1                   0x01
-
-#define SW_CHIP_ID_M                   0xF0
-#define SW_CHIP_ID_S                   4
 #define SW_REVISION_M                  0x0E
 #define SW_REVISION_S                  1
-#define SW_START                       0x01
-
-#define CHIP_ID_94                     0x60
-#define CHIP_ID_95                     0x90
-#define CHIP_ID_63                     0x30
 
 #define KSZ8863_REG_SW_RESET           0x43
 
@@ -57,7 +43,6 @@
 #define REG_SW_CTRL_2                  0x04
 
 #define UNICAST_VLAN_BOUNDARY          BIT(7)
-#define MULTICAST_STORM_DISABLE                BIT(6)
 #define SW_BACK_PRESSURE               BIT(5)
 #define FAIR_FLOW_CTRL                 BIT(4)
 #define NO_EXC_COLLISION_DROP          BIT(3)
 #define SW_FLOW_CTRL                   BIT(5)
 #define SW_10_MBIT                     BIT(4)
 #define SW_REPLACE_VID                 BIT(3)
-#define BROADCAST_STORM_RATE_HI                0x07
 
 #define REG_SW_CTRL_5                  0x07
 
-#define BROADCAST_STORM_RATE_LO                0xFF
-#define BROADCAST_STORM_RATE           0x07FF
-
 #define REG_SW_CTRL_6                  0x08
 
 #define SW_MIB_COUNTER_FLUSH           BIT(7)
 #define REG_PORT_4_STATUS_0            0x48
 
 /* For KSZ8765. */
-#define PORT_FIBER_MODE                        BIT(7)
-
 #define PORT_REMOTE_ASYM_PAUSE         BIT(5)
 #define PORT_REMOTE_SYM_PAUSE          BIT(4)
 #define PORT_REMOTE_100BTX_FD          BIT(3)
 
 #define REG_PORT_CTRL_5                        0x05
 
-#define REG_PORT_STATUS_0              0x08
 #define REG_PORT_STATUS_1              0x09
 #define REG_PORT_LINK_MD_CTRL          0x0A
 #define REG_PORT_LINK_MD_RESULT                0x0B
 #define P_TAG_CTRL                     REG_PORT_CTRL_0
 #define P_MIRROR_CTRL                  REG_PORT_CTRL_1
 #define P_802_1P_CTRL                  REG_PORT_CTRL_2
-#define P_STP_CTRL                     REG_PORT_CTRL_2
 #define P_PASS_ALL_CTRL                        REG_PORT_CTRL_12
 #define P_INS_SRC_PVID_CTRL            REG_PORT_CTRL_12
 #define P_DROP_TAG_CTRL                        REG_PORT_CTRL_13
 #define REG_IND_EEE_GLOB2_LO           0x34
 #define REG_IND_EEE_GLOB2_HI           0x35
 
-/* Driver set switch broadcast storm protection at 10% rate. */
-#define BROADCAST_STORM_PROT_RATE      10
-
-/* 148,800 frames * 67 ms / 100 */
-#define BROADCAST_STORM_VALUE          9969
-
 /**
  * MIB_COUNTER_VALUE                   00-00000000-3FFFFFFF
  * MIB_TOTAL_BYTES                     00-0000000F-FFFFFFFF
index b6f99e6..5247fdf 100644 (file)
@@ -26,11 +26,9 @@ static int ksz8863_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
        struct mdio_device *mdev;
        u8 reg = *(u8 *)reg_buf;
        u8 *val = val_buf;
-       struct ksz8 *ksz8;
        int i, ret = 0;
 
-       ksz8 = dev->priv;
-       mdev = ksz8->priv;
+       mdev = dev->priv;
 
        mutex_lock_nested(&mdev->bus->mdio_lock, MDIO_MUTEX_NESTED);
        for (i = 0; i < val_len; i++) {
@@ -55,13 +53,11 @@ static int ksz8863_mdio_write(void *ctx, const void *data, size_t count)
 {
        struct ksz_device *dev = ctx;
        struct mdio_device *mdev;
-       struct ksz8 *ksz8;
        int i, ret = 0;
        u32 reg;
        u8 *val;
 
-       ksz8 = dev->priv;
-       mdev = ksz8->priv;
+       mdev = dev->priv;
 
        val = (u8 *)(data + 4);
        reg = *(u32 *)data;
@@ -142,17 +138,10 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev)
 {
        struct regmap_config rc;
        struct ksz_device *dev;
-       struct ksz8 *ksz8;
        int ret;
        int i;
 
-       ksz8 = devm_kzalloc(&mdiodev->dev, sizeof(struct ksz8), GFP_KERNEL);
-       if (!ksz8)
-               return -ENOMEM;
-
-       ksz8->priv = mdiodev;
-
-       dev = ksz_switch_alloc(&mdiodev->dev, ksz8);
+       dev = ksz_switch_alloc(&mdiodev->dev, mdiodev);
        if (!dev)
                return -ENOMEM;
 
@@ -174,7 +163,7 @@ static int ksz8863_smi_probe(struct mdio_device *mdiodev)
        if (mdiodev->dev.platform_data)
                dev->pdata = mdiodev->dev.platform_data;
 
-       ret = ksz8_switch_register(dev);
+       ret = ksz_switch_register(dev);
 
        /* Main DSA driver may not be started yet. */
        if (ret)
index ab40b70..6453642 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "ksz9477_reg.h"
 #include "ksz_common.h"
+#include "ksz9477.h"
 
 /* Used with variable features to indicate capabilities. */
 #define GBIT_SUPPORT                   BIT(0)
@@ -47,9 +48,8 @@ static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset,
                           bits, set ? bits : 0);
 }
 
-static int ksz9477_change_mtu(struct dsa_switch *ds, int port, int mtu)
+int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu)
 {
-       struct ksz_device *dev = ds->priv;
        u16 frame_size, max_frame = 0;
        int i;
 
@@ -65,7 +65,7 @@ static int ksz9477_change_mtu(struct dsa_switch *ds, int port, int mtu)
                                  REG_SW_MTU_MASK, max_frame);
 }
 
-static int ksz9477_max_mtu(struct dsa_switch *ds, int port)
+int ksz9477_max_mtu(struct ksz_device *dev, int port)
 {
        return KSZ9477_MAX_FRAME_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN;
 }
@@ -175,7 +175,7 @@ static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev)
                                        10, 1000);
 }
 
-static int ksz9477_reset_switch(struct ksz_device *dev)
+int ksz9477_reset_switch(struct ksz_device *dev)
 {
        u8 data8;
        u32 data32;
@@ -198,12 +198,6 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
        ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F);
        ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
 
-       /* set broadcast storm protection 10% rate */
-       regmap_update_bits(dev->regmap[1], REG_SW_MAC_CTRL_2,
-                          BROADCAST_STORM_RATE,
-                          (BROADCAST_STORM_VALUE *
-                          BROADCAST_STORM_PROT_RATE) / 100);
-
        data8 = SW_ENABLE_REFCLKO;
        if (dev->synclko_disable)
                data8 = 0;
@@ -214,8 +208,7 @@ static int ksz9477_reset_switch(struct ksz_device *dev)
        return 0;
 }
 
-static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
-                             u64 *cnt)
+void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
 {
        struct ksz_port *p = &dev->ports[port];
        unsigned int val;
@@ -242,14 +235,14 @@ static void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr,
        *cnt += data;
 }
 
-static void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
-                             u64 *dropped, u64 *cnt)
+void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                      u64 *dropped, u64 *cnt)
 {
        addr = dev->info->mib_names[addr].index;
        ksz9477_r_mib_cnt(dev, port, addr, cnt);
 }
 
-static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
+void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
 {
        u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
        struct ksz_port *p = &dev->ports[port];
@@ -263,7 +256,7 @@ static void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
        mutex_unlock(&p->mib.cnt_mutex);
 }
 
-static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
+void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
 {
        struct ksz_port_mib *mib = &dev->ports[port].mib;
 
@@ -276,21 +269,8 @@ static void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
        mutex_unlock(&mib->cnt_mutex);
 }
 
-static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds,
-                                                     int port,
-                                                     enum dsa_tag_protocol mp)
+void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
 {
-       enum dsa_tag_protocol proto = DSA_TAG_PROTO_KSZ9477;
-       struct ksz_device *dev = ds->priv;
-
-       if (dev->features & IS_9893)
-               proto = DSA_TAG_PROTO_KSZ9893;
-       return proto;
-}
-
-static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg)
-{
-       struct ksz_device *dev = ds->priv;
        u16 val = 0xffff;
 
        /* No real PHY after this. Simulate the PHY.
@@ -335,40 +315,30 @@ static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg)
                ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
        }
 
-       return val;
+       *data = val;
 }
 
-static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg,
-                              u16 val)
+void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
 {
-       struct ksz_device *dev = ds->priv;
-
        /* No real PHY after this. */
        if (addr >= dev->phy_port_cnt)
-               return 0;
+               return;
 
        /* No gigabit support.  Do not write to this register. */
        if (!(dev->features & GBIT_SUPPORT) && reg == MII_CTRL1000)
-               return 0;
-       ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
+               return;
 
-       return 0;
+       ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
 }
 
-static void ksz9477_cfg_port_member(struct ksz_device *dev, int port,
-                                   u8 member)
+void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member)
 {
        ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member);
 }
 
-static void ksz9477_port_stp_state_set(struct dsa_switch *ds, int port,
-                                      u8 state)
-{
-       ksz_port_stp_state_set(ds, port, state, P_STP_CTRL);
-}
-
-static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
+void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
 {
+       const u16 *regs = dev->info->regs;
        u8 data;
 
        regmap_update_bits(dev->regmap[0], REG_SW_LUE_CTRL_2,
@@ -377,24 +347,21 @@ static void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
 
        if (port < dev->info->port_cnt) {
                /* flush individual port */
-               ksz_pread8(dev, port, P_STP_CTRL, &data);
+               ksz_pread8(dev, port, regs[P_STP_CTRL], &data);
                if (!(data & PORT_LEARN_DISABLE))
-                       ksz_pwrite8(dev, port, P_STP_CTRL,
+                       ksz_pwrite8(dev, port, regs[P_STP_CTRL],
                                    data | PORT_LEARN_DISABLE);
                ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true);
-               ksz_pwrite8(dev, port, P_STP_CTRL, data);
+               ksz_pwrite8(dev, port, regs[P_STP_CTRL], data);
        } else {
                /* flush all */
                ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_STP_TABLE, true);
        }
 }
 
-static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port,
-                                      bool flag,
-                                      struct netlink_ext_ack *extack)
+int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
+                               bool flag, struct netlink_ext_ack *extack)
 {
-       struct ksz_device *dev = ds->priv;
-
        if (flag) {
                ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
                             PORT_VLAN_LOOKUP_VID_0, true);
@@ -408,11 +375,10 @@ static int ksz9477_port_vlan_filtering(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int ksz9477_port_vlan_add(struct dsa_switch *ds, int port,
-                                const struct switchdev_obj_port_vlan *vlan,
-                                struct netlink_ext_ack *extack)
+int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
+                         const struct switchdev_obj_port_vlan *vlan,
+                         struct netlink_ext_ack *extack)
 {
-       struct ksz_device *dev = ds->priv;
        u32 vlan_table[3];
        bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
        int err;
@@ -445,10 +411,9 @@ static int ksz9477_port_vlan_add(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port,
-                                const struct switchdev_obj_port_vlan *vlan)
+int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
+                         const struct switchdev_obj_port_vlan *vlan)
 {
-       struct ksz_device *dev = ds->priv;
        bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
        u32 vlan_table[3];
        u16 pvid;
@@ -479,11 +444,9 @@ static int ksz9477_port_vlan_del(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static int ksz9477_port_fdb_add(struct dsa_switch *ds, int port,
-                               const unsigned char *addr, u16 vid,
-                               struct dsa_db db)
+int ksz9477_fdb_add(struct ksz_device *dev, int port,
+                   const unsigned char *addr, u16 vid, struct dsa_db db)
 {
-       struct ksz_device *dev = ds->priv;
        u32 alu_table[4];
        u32 data;
        int ret = 0;
@@ -537,11 +500,9 @@ exit:
        return ret;
 }
 
-static int ksz9477_port_fdb_del(struct dsa_switch *ds, int port,
-                               const unsigned char *addr, u16 vid,
-                               struct dsa_db db)
+int ksz9477_fdb_del(struct ksz_device *dev, int port,
+                   const unsigned char *addr, u16 vid, struct dsa_db db)
 {
-       struct ksz_device *dev = ds->priv;
        u32 alu_table[4];
        u32 data;
        int ret = 0;
@@ -628,10 +589,9 @@ static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table)
        alu->mac[5] = alu_table[3] & 0xFF;
 }
 
-static int ksz9477_port_fdb_dump(struct dsa_switch *ds, int port,
-                                dsa_fdb_dump_cb_t *cb, void *data)
+int ksz9477_fdb_dump(struct ksz_device *dev, int port,
+                    dsa_fdb_dump_cb_t *cb, void *data)
 {
-       struct ksz_device *dev = ds->priv;
        int ret = 0;
        u32 ksz_data;
        u32 alu_table[4];
@@ -680,17 +640,20 @@ exit:
        return ret;
 }
 
-static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
-                               const struct switchdev_obj_port_mdb *mdb,
-                               struct dsa_db db)
+int ksz9477_mdb_add(struct ksz_device *dev, int port,
+                   const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
 {
-       struct ksz_device *dev = ds->priv;
        u32 static_table[4];
+       const u8 *shifts;
+       const u32 *masks;
        u32 data;
        int index;
        u32 mac_hi, mac_lo;
        int err = 0;
 
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+
        mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]);
        mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16));
        mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]);
@@ -699,8 +662,8 @@ static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
 
        for (index = 0; index < dev->info->num_statics; index++) {
                /* find empty slot first */
-               data = (index << ALU_STAT_INDEX_S) |
-                       ALU_STAT_READ | ALU_STAT_START;
+               data = (index << shifts[ALU_STAT_INDEX]) |
+                       masks[ALU_STAT_READ] | ALU_STAT_START;
                ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
 
                /* wait to be finished */
@@ -744,7 +707,7 @@ static int ksz9477_port_mdb_add(struct dsa_switch *ds, int port,
 
        ksz9477_write_table(dev, static_table);
 
-       data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START;
+       data = (index << shifts[ALU_STAT_INDEX]) | ALU_STAT_START;
        ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
 
        /* wait to be finished */
@@ -756,17 +719,20 @@ exit:
        return err;
 }
 
-static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
-                               const struct switchdev_obj_port_mdb *mdb,
-                               struct dsa_db db)
+int ksz9477_mdb_del(struct ksz_device *dev, int port,
+                   const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
 {
-       struct ksz_device *dev = ds->priv;
        u32 static_table[4];
+       const u8 *shifts;
+       const u32 *masks;
        u32 data;
        int index;
        int ret = 0;
        u32 mac_hi, mac_lo;
 
+       shifts = dev->info->shifts;
+       masks = dev->info->masks;
+
        mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]);
        mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16));
        mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]);
@@ -775,8 +741,8 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
 
        for (index = 0; index < dev->info->num_statics; index++) {
                /* find empty slot first */
-               data = (index << ALU_STAT_INDEX_S) |
-                       ALU_STAT_READ | ALU_STAT_START;
+               data = (index << shifts[ALU_STAT_INDEX]) |
+                       masks[ALU_STAT_READ] | ALU_STAT_START;
                ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
 
                /* wait to be finished */
@@ -818,7 +784,7 @@ static int ksz9477_port_mdb_del(struct dsa_switch *ds, int port,
 
        ksz9477_write_table(dev, static_table);
 
-       data = (index << ALU_STAT_INDEX_S) | ALU_STAT_START;
+       data = (index << shifts[ALU_STAT_INDEX]) | ALU_STAT_START;
        ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
 
        /* wait to be finished */
@@ -832,11 +798,10 @@ exit:
        return ret;
 }
 
-static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port,
-                                  struct dsa_mall_mirror_tc_entry *mirror,
-                                  bool ingress, struct netlink_ext_ack *extack)
+int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
+                           struct dsa_mall_mirror_tc_entry *mirror,
+                           bool ingress, struct netlink_ext_ack *extack)
 {
-       struct ksz_device *dev = ds->priv;
        u8 data;
        int p;
 
@@ -872,10 +837,9 @@ static int ksz9477_port_mirror_add(struct dsa_switch *ds, int port,
        return 0;
 }
 
-static void ksz9477_port_mirror_del(struct dsa_switch *ds, int port,
-                                   struct dsa_mall_mirror_tc_entry *mirror)
+void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
+                            struct dsa_mall_mirror_tc_entry *mirror)
 {
-       struct ksz_device *dev = ds->priv;
        bool in_use = false;
        u8 data;
        int p;
@@ -1097,16 +1061,17 @@ static void ksz9477_phy_errata_setup(struct ksz_device *dev, int port)
        ksz9477_port_mmd_write(dev, port, 0x1c, 0x20, 0xeeee);
 }
 
-static void ksz9477_get_caps(struct dsa_switch *ds, int port,
-                            struct phylink_config *config)
+void ksz9477_get_caps(struct ksz_device *dev, int port,
+                     struct phylink_config *config)
 {
-       ksz_phylink_get_caps(ds, port, config);
+       config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE |
+                                  MAC_SYM_PAUSE;
 
-       config->mac_capabilities = MAC_10 | MAC_100 | MAC_1000FD |
-                                  MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
+       if (dev->features & GBIT_SUPPORT)
+               config->mac_capabilities |= MAC_1000FD;
 }
 
-static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 {
        struct ksz_port *p = &dev->ports[port];
        struct dsa_switch *ds = dev->ds;
@@ -1203,7 +1168,7 @@ static void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
                ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
 }
 
-static void ksz9477_config_cpu_port(struct dsa_switch *ds)
+void ksz9477_config_cpu_port(struct dsa_switch *ds)
 {
        struct ksz_device *dev = ds->priv;
        struct ksz_port *p;
@@ -1260,7 +1225,7 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
                        continue;
                p = &dev->ports[i];
 
-               ksz9477_port_stp_state_set(ds, i, BR_STATE_DISABLED);
+               ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
                p->on = 1;
                if (i < dev->phy_port_cnt)
                        p->phy = 1;
@@ -1273,22 +1238,44 @@ static void ksz9477_config_cpu_port(struct dsa_switch *ds)
        }
 }
 
-static int ksz9477_setup(struct dsa_switch *ds)
+int ksz9477_enable_stp_addr(struct ksz_device *dev)
 {
-       struct ksz_device *dev = ds->priv;
-       int ret = 0;
+       const u32 *masks;
+       u32 data;
+       int ret;
 
-       dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
-                                      dev->info->num_vlans, GFP_KERNEL);
-       if (!dev->vlan_cache)
-               return -ENOMEM;
+       masks = dev->info->masks;
 
-       ret = ksz9477_reset_switch(dev);
-       if (ret) {
-               dev_err(ds->dev, "failed to reset switch\n");
+       /* Enable Reserved multicast table */
+       ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
+
+       /* Set the Override bit for forwarding BPDU packet to CPU */
+       ret = ksz_write32(dev, REG_SW_ALU_VAL_B,
+                         ALU_V_OVERRIDE | BIT(dev->cpu_port));
+       if (ret < 0)
+               return ret;
+
+       data = ALU_STAT_START | ALU_RESV_MCAST_ADDR | masks[ALU_STAT_WRITE];
+
+       ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
+       if (ret < 0)
+               return ret;
+
+       /* wait to be finished */
+       ret = ksz9477_wait_alu_sta_ready(dev);
+       if (ret < 0) {
+               dev_err(dev->dev, "Failed to update Reserved Multicast table\n");
                return ret;
        }
 
+       return 0;
+}
+
+int ksz9477_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       int ret = 0;
+
        /* Required for port partitioning. */
        ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY,
                      true);
@@ -1305,69 +1292,27 @@ static int ksz9477_setup(struct dsa_switch *ds)
        if (ret)
                return ret;
 
-       ksz9477_config_cpu_port(ds);
-
-       ksz_cfg(dev, REG_SW_MAC_CTRL_1, MULTICAST_STORM_DISABLE, true);
-
        /* queue based egress rate limit */
        ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
 
        /* enable global MIB counter freeze function */
        ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
 
-       /* start switch */
-       ksz_cfg(dev, REG_SW_OPERATION, SW_START, true);
-
-       ksz_init_mib_timer(dev);
-
-       ds->configure_vlan_while_not_filtering = false;
-
        return 0;
 }
 
-static const struct dsa_switch_ops ksz9477_switch_ops = {
-       .get_tag_protocol       = ksz9477_get_tag_protocol,
-       .setup                  = ksz9477_setup,
-       .phy_read               = ksz9477_phy_read16,
-       .phy_write              = ksz9477_phy_write16,
-       .phylink_mac_link_down  = ksz_mac_link_down,
-       .phylink_get_caps       = ksz9477_get_caps,
-       .port_enable            = ksz_enable_port,
-       .get_strings            = ksz_get_strings,
-       .get_ethtool_stats      = ksz_get_ethtool_stats,
-       .get_sset_count         = ksz_sset_count,
-       .port_bridge_join       = ksz_port_bridge_join,
-       .port_bridge_leave      = ksz_port_bridge_leave,
-       .port_stp_state_set     = ksz9477_port_stp_state_set,
-       .port_fast_age          = ksz_port_fast_age,
-       .port_vlan_filtering    = ksz9477_port_vlan_filtering,
-       .port_vlan_add          = ksz9477_port_vlan_add,
-       .port_vlan_del          = ksz9477_port_vlan_del,
-       .port_fdb_dump          = ksz9477_port_fdb_dump,
-       .port_fdb_add           = ksz9477_port_fdb_add,
-       .port_fdb_del           = ksz9477_port_fdb_del,
-       .port_mdb_add           = ksz9477_port_mdb_add,
-       .port_mdb_del           = ksz9477_port_mdb_del,
-       .port_mirror_add        = ksz9477_port_mirror_add,
-       .port_mirror_del        = ksz9477_port_mirror_del,
-       .get_stats64            = ksz_get_stats64,
-       .port_change_mtu        = ksz9477_change_mtu,
-       .port_max_mtu           = ksz9477_max_mtu,
-};
-
-static u32 ksz9477_get_port_addr(int port, int offset)
+u32 ksz9477_get_port_addr(int port, int offset)
 {
        return PORT_CTRL_ADDR(port, offset);
 }
 
-static int ksz9477_switch_detect(struct ksz_device *dev)
+int ksz9477_switch_init(struct ksz_device *dev)
 {
        u8 data8;
-       u8 id_hi;
-       u8 id_lo;
-       u32 id32;
        int ret;
 
+       dev->port_mask = (1 << dev->info->port_cnt) - 1;
+
        /* turn off SPI DO Edge select */
        ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
        if (ret)
@@ -1378,10 +1323,6 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
        if (ret)
                return ret;
 
-       /* read chip id */
-       ret = ksz_read32(dev, REG_CHIP_ID0__1, &id32);
-       if (ret)
-               return ret;
        ret = ksz_read8(dev, REG_GLOBAL_OPTIONS, &data8);
        if (ret)
                return ret;
@@ -1392,12 +1333,7 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
        /* Default capability is gigabit capable. */
        dev->features = GBIT_SUPPORT;
 
-       dev_dbg(dev->dev, "Switch detect: ID=%08x%02x\n", id32, data8);
-       id_hi = (u8)(id32 >> 16);
-       id_lo = (u8)(id32 >> 8);
-       if ((id_lo & 0xf) == 3) {
-               /* Chip is from KSZ9893 design. */
-               dev_info(dev->dev, "Found KSZ9893\n");
+       if (dev->chip_id == KSZ9893_CHIP_ID) {
                dev->features |= IS_9893;
 
                /* Chip does not support gigabit. */
@@ -1405,7 +1341,6 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
                        dev->features &= ~GBIT_SUPPORT;
                dev->phy_port_cnt = 2;
        } else {
-               dev_info(dev->dev, "Found KSZ9477 or compatible\n");
                /* Chip uses new XMII register definitions. */
                dev->features |= NEW_XMII;
 
@@ -1414,72 +1349,14 @@ static int ksz9477_switch_detect(struct ksz_device *dev)
                        dev->features &= ~GBIT_SUPPORT;
        }
 
-       /* Change chip id to known ones so it can be matched against them. */
-       id32 = (id_hi << 16) | (id_lo << 8);
-
-       dev->chip_id = id32;
-
        return 0;
 }
 
-static int ksz9477_switch_init(struct ksz_device *dev)
-{
-       dev->ds->ops = &ksz9477_switch_ops;
-
-       dev->port_mask = (1 << dev->info->port_cnt) - 1;
-
-       return 0;
-}
-
-static void ksz9477_switch_exit(struct ksz_device *dev)
+void ksz9477_switch_exit(struct ksz_device *dev)
 {
        ksz9477_reset_switch(dev);
 }
 
-static const struct ksz_dev_ops ksz9477_dev_ops = {
-       .get_port_addr = ksz9477_get_port_addr,
-       .cfg_port_member = ksz9477_cfg_port_member,
-       .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
-       .port_setup = ksz9477_port_setup,
-       .r_mib_cnt = ksz9477_r_mib_cnt,
-       .r_mib_pkt = ksz9477_r_mib_pkt,
-       .r_mib_stat64 = ksz_r_mib_stats64,
-       .freeze_mib = ksz9477_freeze_mib,
-       .port_init_cnt = ksz9477_port_init_cnt,
-       .shutdown = ksz9477_reset_switch,
-       .detect = ksz9477_switch_detect,
-       .init = ksz9477_switch_init,
-       .exit = ksz9477_switch_exit,
-};
-
-int ksz9477_switch_register(struct ksz_device *dev)
-{
-       int ret, i;
-       struct phy_device *phydev;
-
-       ret = ksz_switch_register(dev, &ksz9477_dev_ops);
-       if (ret)
-               return ret;
-
-       for (i = 0; i < dev->phy_port_cnt; ++i) {
-               if (!dsa_is_user_port(dev->ds, i))
-                       continue;
-
-               phydev = dsa_to_port(dev->ds, i)->slave->phydev;
-
-               /* The MAC actually cannot run in 1000 half-duplex mode. */
-               phy_remove_link_mode(phydev,
-                                    ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
-
-               /* PHY does not support gigabit. */
-               if (!(dev->features & GBIT_SUPPORT))
-                       phy_remove_link_mode(phydev,
-                                            ETHTOOL_LINK_MODE_1000baseT_Full_BIT);
-       }
-       return ret;
-}
-EXPORT_SYMBOL(ksz9477_switch_register);
-
 MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
 MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch DSA Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/ksz9477.h b/drivers/net/dsa/microchip/ksz9477.h
new file mode 100644 (file)
index 0000000..cd278b3
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Microchip KSZ9477 series Header file
+ *
+ * Copyright (C) 2017-2022 Microchip Technology Inc.
+ */
+
+#ifndef __KSZ9477_H
+#define __KSZ9477_H
+
+#include <net/dsa.h>
+#include "ksz_common.h"
+
+int ksz9477_setup(struct dsa_switch *ds);
+u32 ksz9477_get_port_addr(int port, int offset);
+void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member);
+void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port);
+void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port);
+void ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data);
+void ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val);
+void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt);
+void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
+                      u64 *dropped, u64 *cnt);
+void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze);
+void ksz9477_port_init_cnt(struct ksz_device *dev, int port);
+int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
+                               bool flag, struct netlink_ext_ack *extack);
+int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
+                         const struct switchdev_obj_port_vlan *vlan,
+                         struct netlink_ext_ack *extack);
+int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
+                         const struct switchdev_obj_port_vlan *vlan);
+int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
+                           struct dsa_mall_mirror_tc_entry *mirror,
+                           bool ingress, struct netlink_ext_ack *extack);
+void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
+                            struct dsa_mall_mirror_tc_entry *mirror);
+int ksz9477_get_stp_reg(void);
+void ksz9477_get_caps(struct ksz_device *dev, int port,
+                     struct phylink_config *config);
+int ksz9477_fdb_dump(struct ksz_device *dev, int port,
+                    dsa_fdb_dump_cb_t *cb, void *data);
+int ksz9477_fdb_add(struct ksz_device *dev, int port,
+                   const unsigned char *addr, u16 vid, struct dsa_db db);
+int ksz9477_fdb_del(struct ksz_device *dev, int port,
+                   const unsigned char *addr, u16 vid, struct dsa_db db);
+int ksz9477_mdb_add(struct ksz_device *dev, int port,
+                   const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
+int ksz9477_mdb_del(struct ksz_device *dev, int port,
+                   const struct switchdev_obj_port_mdb *mdb, struct dsa_db db);
+int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu);
+int ksz9477_max_mtu(struct ksz_device *dev, int port);
+void ksz9477_config_cpu_port(struct dsa_switch *ds);
+int ksz9477_enable_stp_addr(struct ksz_device *dev);
+int ksz9477_reset_switch(struct ksz_device *dev);
+int ksz9477_dsa_init(struct ksz_device *dev);
+int ksz9477_switch_init(struct ksz_device *dev);
+void ksz9477_switch_exit(struct ksz_device *dev);
+
+#endif
index faa3163..9996651 100644 (file)
@@ -41,7 +41,7 @@ static int ksz9477_i2c_probe(struct i2c_client *i2c,
        if (i2c->dev.platform_data)
                dev->pdata = i2c->dev.platform_data;
 
-       ret = ksz9477_switch_register(dev);
+       ret = ksz_switch_register(dev);
 
        /* Main DSA driver may not be started yet. */
        if (ret)
@@ -71,8 +71,8 @@ static void ksz9477_i2c_shutdown(struct i2c_client *i2c)
        if (!dev)
                return;
 
-       if (dev->dev_ops->shutdown)
-               dev->dev_ops->shutdown(dev);
+       if (dev->dev_ops->reset)
+               dev->dev_ops->reset(dev);
 
        dsa_switch_shutdown(dev->ds);
 
index 7a2c8d4..d0cce4c 100644 (file)
@@ -25,7 +25,6 @@
 
 #define REG_CHIP_ID2__1                        0x0002
 
-#define CHIP_ID_63                     0x63
 #define CHIP_ID_66                     0x66
 #define CHIP_ID_67                     0x67
 #define CHIP_ID_77                     0x77
 
 #define SW_DOUBLE_TAG                  BIT(7)
 #define SW_RESET                       BIT(1)
-#define SW_START                       BIT(0)
 
 #define REG_SW_MAC_ADDR_0              0x0302
 #define REG_SW_MAC_ADDR_1              0x0303
 
 #define REG_SW_MAC_CTRL_1              0x0331
 
-#define MULTICAST_STORM_DISABLE                BIT(6)
 #define SW_BACK_PRESSURE               BIT(5)
 #define FAIR_FLOW_CTRL                 BIT(4)
 #define NO_EXC_COLLISION_DROP          BIT(3)
 #define REG_SW_MAC_CTRL_2              0x0332
 
 #define SW_REPLACE_VID                 BIT(3)
-#define BROADCAST_STORM_RATE_HI                0x07
 
 #define REG_SW_MAC_CTRL_3              0x0333
 
-#define BROADCAST_STORM_RATE_LO                0xFF
-#define BROADCAST_STORM_RATE           0x07FF
-
 #define REG_SW_MAC_CTRL_4              0x0334
 
 #define SW_PASS_PAUSE                  BIT(3)
 
 #define REG_SW_ALU_STAT_CTRL__4                0x041C
 
-#define ALU_STAT_INDEX_M               (BIT(4) - 1)
-#define ALU_STAT_INDEX_S               16
 #define ALU_RESV_MCAST_INDEX_M         (BIT(6) - 1)
 #define ALU_STAT_START                 BIT(7)
 #define ALU_RESV_MCAST_ADDR            BIT(1)
-#define ALU_STAT_READ                  BIT(0)
 
 #define REG_SW_ALU_VAL_A               0x0420
 
 /* 5 - MIB Counters */
 #define REG_PORT_MIB_CTRL_STAT__4      0x0500
 
-#define MIB_COUNTER_OVERFLOW           BIT(31)
-#define MIB_COUNTER_VALID              BIT(30)
 #define MIB_COUNTER_READ               BIT(25)
 #define MIB_COUNTER_FLUSH_FREEZE       BIT(24)
 #define MIB_COUNTER_INDEX_M            (BIT(8) - 1)
 #define P_BCAST_STORM_CTRL             REG_PORT_MAC_CTRL_0
 #define P_PRIO_CTRL                    REG_PORT_MRI_PRIO_CTRL
 #define P_MIRROR_CTRL                  REG_PORT_MRI_MIRROR_CTRL
-#define P_STP_CTRL                     REG_PORT_LUE_MSTP_STATE
 #define P_PHY_CTRL                     REG_PORT_PHY_CTRL
-#define P_NEG_RESTART_CTRL             REG_PORT_PHY_CTRL
-#define P_LINK_STATUS                  REG_PORT_PHY_STATUS
-#define P_SPEED_STATUS                 REG_PORT_PHY_PHY_CTRL
 #define P_RATE_LIMIT_CTRL              REG_PORT_MAC_IN_RATE_LIMIT
 
 #define S_LINK_AGING_CTRL              REG_SW_LUE_CTRL_1
 #define PTP_TRIG_UNIT_M                        (BIT(MAX_TRIG_UNIT) - 1)
 #define PTP_TS_UNIT_M                  (BIT(MAX_TIMESTAMP_UNIT) - 1)
 
-/* Driver set switch broadcast storm protection at 10% rate. */
-#define BROADCAST_STORM_PROT_RATE      10
-
-/* 148,800 frames * 67 ms / 100 */
-#define BROADCAST_STORM_VALUE          9969
-
 #define KSZ9477_MAX_FRAME_SIZE         9000
 
 #endif /* KSZ9477_REGS_H */
diff --git a/drivers/net/dsa/microchip/ksz9477_spi.c b/drivers/net/dsa/microchip/ksz9477_spi.c
deleted file mode 100644 (file)
index 1bc8b0c..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Microchip KSZ9477 series register access through SPI
- *
- * Copyright (C) 2017-2019 Microchip Technology Inc.
- */
-
-#include <asm/unaligned.h>
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/regmap.h>
-#include <linux/spi/spi.h>
-
-#include "ksz_common.h"
-
-#define SPI_ADDR_SHIFT                 24
-#define SPI_ADDR_ALIGN                 3
-#define SPI_TURNAROUND_SHIFT           5
-
-KSZ_REGMAP_TABLE(ksz9477, 32, SPI_ADDR_SHIFT,
-                SPI_TURNAROUND_SHIFT, SPI_ADDR_ALIGN);
-
-static int ksz9477_spi_probe(struct spi_device *spi)
-{
-       struct regmap_config rc;
-       struct ksz_device *dev;
-       int i, ret;
-
-       dev = ksz_switch_alloc(&spi->dev, spi);
-       if (!dev)
-               return -ENOMEM;
-
-       for (i = 0; i < ARRAY_SIZE(ksz9477_regmap_config); i++) {
-               rc = ksz9477_regmap_config[i];
-               rc.lock_arg = &dev->regmap_mutex;
-               dev->regmap[i] = devm_regmap_init_spi(spi, &rc);
-               if (IS_ERR(dev->regmap[i])) {
-                       ret = PTR_ERR(dev->regmap[i]);
-                       dev_err(&spi->dev,
-                               "Failed to initialize regmap%i: %d\n",
-                               ksz9477_regmap_config[i].val_bits, ret);
-                       return ret;
-               }
-       }
-
-       if (spi->dev.platform_data)
-               dev->pdata = spi->dev.platform_data;
-
-       /* setup spi */
-       spi->mode = SPI_MODE_3;
-       ret = spi_setup(spi);
-       if (ret)
-               return ret;
-
-       ret = ksz9477_switch_register(dev);
-
-       /* Main DSA driver may not be started yet. */
-       if (ret)
-               return ret;
-
-       spi_set_drvdata(spi, dev);
-
-       return 0;
-}
-
-static void ksz9477_spi_remove(struct spi_device *spi)
-{
-       struct ksz_device *dev = spi_get_drvdata(spi);
-
-       if (dev)
-               ksz_switch_remove(dev);
-
-       spi_set_drvdata(spi, NULL);
-}
-
-static void ksz9477_spi_shutdown(struct spi_device *spi)
-{
-       struct ksz_device *dev = spi_get_drvdata(spi);
-
-       if (dev)
-               dsa_switch_shutdown(dev->ds);
-
-       spi_set_drvdata(spi, NULL);
-}
-
-static const struct of_device_id ksz9477_dt_ids[] = {
-       {
-               .compatible = "microchip,ksz9477",
-               .data = &ksz_switch_chips[KSZ9477]
-       },
-       {
-               .compatible = "microchip,ksz9897",
-               .data = &ksz_switch_chips[KSZ9897]
-       },
-       {
-               .compatible = "microchip,ksz9893",
-               .data = &ksz_switch_chips[KSZ9893]
-       },
-       {
-               .compatible = "microchip,ksz9563",
-               .data = &ksz_switch_chips[KSZ9893]
-       },
-       {
-               .compatible = "microchip,ksz8563",
-               .data = &ksz_switch_chips[KSZ9893]
-       },
-       {
-               .compatible = "microchip,ksz9567",
-               .data = &ksz_switch_chips[KSZ9567]
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, ksz9477_dt_ids);
-
-static const struct spi_device_id ksz9477_spi_ids[] = {
-       { "ksz9477" },
-       { "ksz9897" },
-       { "ksz9893" },
-       { "ksz9563" },
-       { "ksz8563" },
-       { "ksz9567" },
-       { },
-};
-MODULE_DEVICE_TABLE(spi, ksz9477_spi_ids);
-
-static struct spi_driver ksz9477_spi_driver = {
-       .driver = {
-               .name   = "ksz9477-switch",
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(ksz9477_dt_ids),
-       },
-       .id_table = ksz9477_spi_ids,
-       .probe  = ksz9477_spi_probe,
-       .remove = ksz9477_spi_remove,
-       .shutdown = ksz9477_spi_shutdown,
-};
-
-module_spi_driver(ksz9477_spi_driver);
-
-MODULE_ALIAS("spi:ksz9477");
-MODULE_ALIAS("spi:ksz9897");
-MODULE_ALIAS("spi:ksz9893");
-MODULE_ALIAS("spi:ksz9563");
-MODULE_ALIAS("spi:ksz8563");
-MODULE_ALIAS("spi:ksz9567");
-MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
-MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch SPI access Driver");
-MODULE_LICENSE("GPL");
index 9ca8c8d..28d7cb2 100644 (file)
 #include <linux/if_bridge.h>
 #include <linux/of_device.h>
 #include <linux/of_net.h>
+#include <linux/micrel_phy.h>
 #include <net/dsa.h>
 #include <net/switchdev.h>
 
 #include "ksz_common.h"
+#include "ksz8.h"
+#include "ksz9477.h"
+#include "lan937x.h"
 
 #define MIB_COUNTER_NUM 0x20
 
@@ -138,6 +142,234 @@ static const struct ksz_mib_names ksz9477_mib_names[] = {
        { 0x83, "tx_discards" },
 };
 
+static const struct ksz_dev_ops ksz8_dev_ops = {
+       .setup = ksz8_setup,
+       .get_port_addr = ksz8_get_port_addr,
+       .cfg_port_member = ksz8_cfg_port_member,
+       .flush_dyn_mac_table = ksz8_flush_dyn_mac_table,
+       .port_setup = ksz8_port_setup,
+       .r_phy = ksz8_r_phy,
+       .w_phy = ksz8_w_phy,
+       .r_mib_pkt = ksz8_r_mib_pkt,
+       .freeze_mib = ksz8_freeze_mib,
+       .port_init_cnt = ksz8_port_init_cnt,
+       .fdb_dump = ksz8_fdb_dump,
+       .mdb_add = ksz8_mdb_add,
+       .mdb_del = ksz8_mdb_del,
+       .vlan_filtering = ksz8_port_vlan_filtering,
+       .vlan_add = ksz8_port_vlan_add,
+       .vlan_del = ksz8_port_vlan_del,
+       .mirror_add = ksz8_port_mirror_add,
+       .mirror_del = ksz8_port_mirror_del,
+       .get_caps = ksz8_get_caps,
+       .config_cpu_port = ksz8_config_cpu_port,
+       .enable_stp_addr = ksz8_enable_stp_addr,
+       .reset = ksz8_reset_switch,
+       .init = ksz8_switch_init,
+       .exit = ksz8_switch_exit,
+};
+
+static const struct ksz_dev_ops ksz9477_dev_ops = {
+       .setup = ksz9477_setup,
+       .get_port_addr = ksz9477_get_port_addr,
+       .cfg_port_member = ksz9477_cfg_port_member,
+       .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
+       .port_setup = ksz9477_port_setup,
+       .r_phy = ksz9477_r_phy,
+       .w_phy = ksz9477_w_phy,
+       .r_mib_cnt = ksz9477_r_mib_cnt,
+       .r_mib_pkt = ksz9477_r_mib_pkt,
+       .r_mib_stat64 = ksz_r_mib_stats64,
+       .freeze_mib = ksz9477_freeze_mib,
+       .port_init_cnt = ksz9477_port_init_cnt,
+       .vlan_filtering = ksz9477_port_vlan_filtering,
+       .vlan_add = ksz9477_port_vlan_add,
+       .vlan_del = ksz9477_port_vlan_del,
+       .mirror_add = ksz9477_port_mirror_add,
+       .mirror_del = ksz9477_port_mirror_del,
+       .get_caps = ksz9477_get_caps,
+       .fdb_dump = ksz9477_fdb_dump,
+       .fdb_add = ksz9477_fdb_add,
+       .fdb_del = ksz9477_fdb_del,
+       .mdb_add = ksz9477_mdb_add,
+       .mdb_del = ksz9477_mdb_del,
+       .change_mtu = ksz9477_change_mtu,
+       .max_mtu = ksz9477_max_mtu,
+       .config_cpu_port = ksz9477_config_cpu_port,
+       .enable_stp_addr = ksz9477_enable_stp_addr,
+       .reset = ksz9477_reset_switch,
+       .init = ksz9477_switch_init,
+       .exit = ksz9477_switch_exit,
+};
+
+static const struct ksz_dev_ops lan937x_dev_ops = {
+       .setup = lan937x_setup,
+       .get_port_addr = ksz9477_get_port_addr,
+       .cfg_port_member = ksz9477_cfg_port_member,
+       .flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
+       .port_setup = lan937x_port_setup,
+       .r_phy = lan937x_r_phy,
+       .w_phy = lan937x_w_phy,
+       .r_mib_cnt = ksz9477_r_mib_cnt,
+       .r_mib_pkt = ksz9477_r_mib_pkt,
+       .r_mib_stat64 = ksz_r_mib_stats64,
+       .freeze_mib = ksz9477_freeze_mib,
+       .port_init_cnt = ksz9477_port_init_cnt,
+       .vlan_filtering = ksz9477_port_vlan_filtering,
+       .vlan_add = ksz9477_port_vlan_add,
+       .vlan_del = ksz9477_port_vlan_del,
+       .mirror_add = ksz9477_port_mirror_add,
+       .mirror_del = ksz9477_port_mirror_del,
+       .get_caps = lan937x_phylink_get_caps,
+       .phylink_mac_config = lan937x_phylink_mac_config,
+       .phylink_mac_link_up = lan937x_phylink_mac_link_up,
+       .fdb_dump = ksz9477_fdb_dump,
+       .fdb_add = ksz9477_fdb_add,
+       .fdb_del = ksz9477_fdb_del,
+       .mdb_add = ksz9477_mdb_add,
+       .mdb_del = ksz9477_mdb_del,
+       .change_mtu = lan937x_change_mtu,
+       .max_mtu = ksz9477_max_mtu,
+       .config_cpu_port = lan937x_config_cpu_port,
+       .enable_stp_addr = ksz9477_enable_stp_addr,
+       .reset = lan937x_reset_switch,
+       .init = lan937x_switch_init,
+       .exit = lan937x_switch_exit,
+};
+
+static const u16 ksz8795_regs[] = {
+       [REG_IND_CTRL_0]                = 0x6E,
+       [REG_IND_DATA_8]                = 0x70,
+       [REG_IND_DATA_CHECK]            = 0x72,
+       [REG_IND_DATA_HI]               = 0x71,
+       [REG_IND_DATA_LO]               = 0x75,
+       [REG_IND_MIB_CHECK]             = 0x74,
+       [REG_IND_BYTE]                  = 0xA0,
+       [P_FORCE_CTRL]                  = 0x0C,
+       [P_LINK_STATUS]                 = 0x0E,
+       [P_LOCAL_CTRL]                  = 0x07,
+       [P_NEG_RESTART_CTRL]            = 0x0D,
+       [P_REMOTE_STATUS]               = 0x08,
+       [P_SPEED_STATUS]                = 0x09,
+       [S_TAIL_TAG_CTRL]               = 0x0C,
+       [P_STP_CTRL]                    = 0x02,
+       [S_START_CTRL]                  = 0x01,
+       [S_BROADCAST_CTRL]              = 0x06,
+       [S_MULTICAST_CTRL]              = 0x04,
+};
+
+static const u32 ksz8795_masks[] = {
+       [PORT_802_1P_REMAPPING]         = BIT(7),
+       [SW_TAIL_TAG_ENABLE]            = BIT(1),
+       [MIB_COUNTER_OVERFLOW]          = BIT(6),
+       [MIB_COUNTER_VALID]             = BIT(5),
+       [VLAN_TABLE_FID]                = GENMASK(6, 0),
+       [VLAN_TABLE_MEMBERSHIP]         = GENMASK(11, 7),
+       [VLAN_TABLE_VALID]              = BIT(12),
+       [STATIC_MAC_TABLE_VALID]        = BIT(21),
+       [STATIC_MAC_TABLE_USE_FID]      = BIT(23),
+       [STATIC_MAC_TABLE_FID]          = GENMASK(30, 24),
+       [STATIC_MAC_TABLE_OVERRIDE]     = BIT(26),
+       [STATIC_MAC_TABLE_FWD_PORTS]    = GENMASK(24, 20),
+       [DYNAMIC_MAC_TABLE_ENTRIES_H]   = GENMASK(6, 0),
+       [DYNAMIC_MAC_TABLE_MAC_EMPTY]   = BIT(8),
+       [DYNAMIC_MAC_TABLE_NOT_READY]   = BIT(7),
+       [DYNAMIC_MAC_TABLE_ENTRIES]     = GENMASK(31, 29),
+       [DYNAMIC_MAC_TABLE_FID]         = GENMASK(26, 20),
+       [DYNAMIC_MAC_TABLE_SRC_PORT]    = GENMASK(26, 24),
+       [DYNAMIC_MAC_TABLE_TIMESTAMP]   = GENMASK(28, 27),
+};
+
+static const u8 ksz8795_shifts[] = {
+       [VLAN_TABLE_MEMBERSHIP_S]       = 7,
+       [VLAN_TABLE]                    = 16,
+       [STATIC_MAC_FWD_PORTS]          = 16,
+       [STATIC_MAC_FID]                = 24,
+       [DYNAMIC_MAC_ENTRIES_H]         = 3,
+       [DYNAMIC_MAC_ENTRIES]           = 29,
+       [DYNAMIC_MAC_FID]               = 16,
+       [DYNAMIC_MAC_TIMESTAMP]         = 27,
+       [DYNAMIC_MAC_SRC_PORT]          = 24,
+};
+
+static const u16 ksz8863_regs[] = {
+       [REG_IND_CTRL_0]                = 0x79,
+       [REG_IND_DATA_8]                = 0x7B,
+       [REG_IND_DATA_CHECK]            = 0x7B,
+       [REG_IND_DATA_HI]               = 0x7C,
+       [REG_IND_DATA_LO]               = 0x80,
+       [REG_IND_MIB_CHECK]             = 0x80,
+       [P_FORCE_CTRL]                  = 0x0C,
+       [P_LINK_STATUS]                 = 0x0E,
+       [P_LOCAL_CTRL]                  = 0x0C,
+       [P_NEG_RESTART_CTRL]            = 0x0D,
+       [P_REMOTE_STATUS]               = 0x0E,
+       [P_SPEED_STATUS]                = 0x0F,
+       [S_TAIL_TAG_CTRL]               = 0x03,
+       [P_STP_CTRL]                    = 0x02,
+       [S_START_CTRL]                  = 0x01,
+       [S_BROADCAST_CTRL]              = 0x06,
+       [S_MULTICAST_CTRL]              = 0x04,
+};
+
+static const u32 ksz8863_masks[] = {
+       [PORT_802_1P_REMAPPING]         = BIT(3),
+       [SW_TAIL_TAG_ENABLE]            = BIT(6),
+       [MIB_COUNTER_OVERFLOW]          = BIT(7),
+       [MIB_COUNTER_VALID]             = BIT(6),
+       [VLAN_TABLE_FID]                = GENMASK(15, 12),
+       [VLAN_TABLE_MEMBERSHIP]         = GENMASK(18, 16),
+       [VLAN_TABLE_VALID]              = BIT(19),
+       [STATIC_MAC_TABLE_VALID]        = BIT(19),
+       [STATIC_MAC_TABLE_USE_FID]      = BIT(21),
+       [STATIC_MAC_TABLE_FID]          = GENMASK(29, 26),
+       [STATIC_MAC_TABLE_OVERRIDE]     = BIT(20),
+       [STATIC_MAC_TABLE_FWD_PORTS]    = GENMASK(18, 16),
+       [DYNAMIC_MAC_TABLE_ENTRIES_H]   = GENMASK(5, 0),
+       [DYNAMIC_MAC_TABLE_MAC_EMPTY]   = BIT(7),
+       [DYNAMIC_MAC_TABLE_NOT_READY]   = BIT(7),
+       [DYNAMIC_MAC_TABLE_ENTRIES]     = GENMASK(31, 28),
+       [DYNAMIC_MAC_TABLE_FID]         = GENMASK(19, 16),
+       [DYNAMIC_MAC_TABLE_SRC_PORT]    = GENMASK(21, 20),
+       [DYNAMIC_MAC_TABLE_TIMESTAMP]   = GENMASK(23, 22),
+};
+
+static u8 ksz8863_shifts[] = {
+       [VLAN_TABLE_MEMBERSHIP_S]       = 16,
+       [STATIC_MAC_FWD_PORTS]          = 16,
+       [STATIC_MAC_FID]                = 22,
+       [DYNAMIC_MAC_ENTRIES_H]         = 3,
+       [DYNAMIC_MAC_ENTRIES]           = 24,
+       [DYNAMIC_MAC_FID]               = 16,
+       [DYNAMIC_MAC_TIMESTAMP]         = 24,
+       [DYNAMIC_MAC_SRC_PORT]          = 20,
+};
+
+static const u16 ksz9477_regs[] = {
+       [P_STP_CTRL]                    = 0x0B04,
+       [S_START_CTRL]                  = 0x0300,
+       [S_BROADCAST_CTRL]              = 0x0332,
+       [S_MULTICAST_CTRL]              = 0x0331,
+};
+
+static const u32 ksz9477_masks[] = {
+       [ALU_STAT_WRITE]                = 0,
+       [ALU_STAT_READ]                 = 1,
+};
+
+static const u8 ksz9477_shifts[] = {
+       [ALU_STAT_INDEX]                = 16,
+};
+
+static const u32 lan937x_masks[] = {
+       [ALU_STAT_WRITE]                = 1,
+       [ALU_STAT_READ]                 = 2,
+};
+
+static const u8 lan937x_shifts[] = {
+       [ALU_STAT_INDEX]                = 8,
+};
+
 const struct ksz_chip_data ksz_switch_chips[] = {
        [KSZ8795] = {
                .chip_id = KSZ8795_CHIP_ID,
@@ -147,10 +379,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total cpu and user ports */
+               .ops = &ksz8_dev_ops,
                .ksz87xx_eee_link_erratum = true,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz8795_regs,
+               .masks = ksz8795_masks,
+               .shifts = ksz8795_shifts,
                .supports_mii = {false, false, false, false, true},
                .supports_rmii = {false, false, false, false, true},
                .supports_rgmii = {false, false, false, false, true},
@@ -179,10 +415,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total cpu and user ports */
+               .ops = &ksz8_dev_ops,
                .ksz87xx_eee_link_erratum = true,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz8795_regs,
+               .masks = ksz8795_masks,
+               .shifts = ksz8795_shifts,
                .supports_mii = {false, false, false, false, true},
                .supports_rmii = {false, false, false, false, true},
                .supports_rgmii = {false, false, false, false, true},
@@ -197,10 +437,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total cpu and user ports */
+               .ops = &ksz8_dev_ops,
                .ksz87xx_eee_link_erratum = true,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz8795_regs,
+               .masks = ksz8795_masks,
+               .shifts = ksz8795_shifts,
                .supports_mii = {false, false, false, false, true},
                .supports_rmii = {false, false, false, false, true},
                .supports_rgmii = {false, false, false, false, true},
@@ -215,9 +459,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 8,
                .cpu_ports = 0x4,       /* can be configured as cpu port */
                .port_cnt = 3,
+               .ops = &ksz8_dev_ops,
                .mib_names = ksz88xx_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz8863_regs,
+               .masks = ksz8863_masks,
+               .shifts = ksz8863_shifts,
                .supports_mii = {false, false, true},
                .supports_rmii = {false, false, true},
                .internal_phy = {true, true, false},
@@ -231,10 +479,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 16,
                .cpu_ports = 0x7F,      /* can be configured as cpu port */
                .port_cnt = 7,          /* total physical port count */
+               .ops = &ksz9477_dev_ops,
                .phy_errata_9477 = true,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = ksz9477_masks,
+               .shifts = ksz9477_shifts,
                .supports_mii   = {false, false, false, false,
                                   false, true, false},
                .supports_rmii  = {false, false, false, false,
@@ -253,10 +505,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 16,
                .cpu_ports = 0x7F,      /* can be configured as cpu port */
                .port_cnt = 7,          /* total physical port count */
+               .ops = &ksz9477_dev_ops,
                .phy_errata_9477 = true,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = ksz9477_masks,
+               .shifts = ksz9477_shifts,
                .supports_mii   = {false, false, false, false,
                                   false, true, true},
                .supports_rmii  = {false, false, false, false,
@@ -275,9 +531,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 16,
                .cpu_ports = 0x07,      /* can be configured as cpu port */
                .port_cnt = 3,          /* total port count */
+               .ops = &ksz9477_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = ksz9477_masks,
+               .shifts = ksz9477_shifts,
                .supports_mii = {false, false, true},
                .supports_rmii = {false, false, true},
                .supports_rgmii = {false, false, true},
@@ -292,10 +552,14 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 16,
                .cpu_ports = 0x7F,      /* can be configured as cpu port */
                .port_cnt = 7,          /* total physical port count */
+               .ops = &ksz9477_dev_ops,
                .phy_errata_9477 = true,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = ksz9477_masks,
+               .shifts = ksz9477_shifts,
                .supports_mii   = {false, false, false, false,
                                   false, true, true},
                .supports_rmii  = {false, false, false, false,
@@ -314,9 +578,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x10,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = lan937x_masks,
+               .shifts = lan937x_shifts,
                .supports_mii = {false, false, false, false, true},
                .supports_rmii = {false, false, false, false, true},
                .supports_rgmii = {false, false, false, false, true},
@@ -331,9 +599,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x30,      /* can be configured as cpu port */
                .port_cnt = 6,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = lan937x_masks,
+               .shifts = lan937x_shifts,
                .supports_mii = {false, false, false, false, true, true},
                .supports_rmii = {false, false, false, false, true, true},
                .supports_rgmii = {false, false, false, false, true, true},
@@ -348,9 +620,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x30,      /* can be configured as cpu port */
                .port_cnt = 8,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = lan937x_masks,
+               .shifts = lan937x_shifts,
                .supports_mii   = {false, false, false, false,
                                   true, true, false, false},
                .supports_rmii  = {false, false, false, false,
@@ -369,9 +645,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x38,      /* can be configured as cpu port */
                .port_cnt = 5,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = lan937x_masks,
+               .shifts = lan937x_shifts,
                .supports_mii   = {false, false, false, false,
                                   true, true, false, false},
                .supports_rmii  = {false, false, false, false,
@@ -390,9 +670,13 @@ const struct ksz_chip_data ksz_switch_chips[] = {
                .num_statics = 256,
                .cpu_ports = 0x30,      /* can be configured as cpu port */
                .port_cnt = 8,          /* total physical port count */
+               .ops = &lan937x_dev_ops,
                .mib_names = ksz9477_mib_names,
                .mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
                .reg_mib_cnt = MIB_COUNTER_NUM,
+               .regs = ksz9477_regs,
+               .masks = lan937x_masks,
+               .shifts = lan937x_shifts,
                .supports_mii   = {false, false, false, false,
                                   true, true, false, false},
                .supports_rmii  = {false, false, false, false,
@@ -436,8 +720,8 @@ static int ksz_check_device_id(struct ksz_device *dev)
        return 0;
 }
 
-void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
-                         struct phylink_config *config)
+static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
+                                struct phylink_config *config)
 {
        struct ksz_device *dev = ds->priv;
 
@@ -456,23 +740,29 @@ void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
        if (dev->info->internal_phy[port])
                __set_bit(PHY_INTERFACE_MODE_INTERNAL,
                          config->supported_interfaces);
+
+       if (dev->dev_ops->get_caps)
+               dev->dev_ops->get_caps(dev, port, config);
 }
-EXPORT_SYMBOL_GPL(ksz_phylink_get_caps);
 
 void ksz_r_mib_stats64(struct ksz_device *dev, int port)
 {
+       struct ethtool_pause_stats *pstats;
        struct rtnl_link_stats64 *stats;
        struct ksz_stats_raw *raw;
        struct ksz_port_mib *mib;
 
        mib = &dev->ports[port].mib;
        stats = &mib->stats64;
+       pstats = &mib->pause_stats;
        raw = (struct ksz_stats_raw *)mib->counters;
 
        spin_lock(&mib->stats64_lock);
 
-       stats->rx_packets = raw->rx_bcast + raw->rx_mcast + raw->rx_ucast;
-       stats->tx_packets = raw->tx_bcast + raw->tx_mcast + raw->tx_ucast;
+       stats->rx_packets = raw->rx_bcast + raw->rx_mcast + raw->rx_ucast +
+               raw->rx_pause;
+       stats->tx_packets = raw->tx_bcast + raw->tx_mcast + raw->tx_ucast +
+               raw->tx_pause;
 
        /* HW counters are counting bytes + FCS which is not acceptable
         * for rtnl_link_stats64 interface
@@ -498,12 +788,14 @@ void ksz_r_mib_stats64(struct ksz_device *dev, int port)
        stats->multicast = raw->rx_mcast;
        stats->collisions = raw->tx_total_col;
 
+       pstats->tx_pause_frames = raw->tx_pause;
+       pstats->rx_pause_frames = raw->rx_pause;
+
        spin_unlock(&mib->stats64_lock);
 }
-EXPORT_SYMBOL_GPL(ksz_r_mib_stats64);
 
-void ksz_get_stats64(struct dsa_switch *ds, int port,
-                    struct rtnl_link_stats64 *s)
+static void ksz_get_stats64(struct dsa_switch *ds, int port,
+                           struct rtnl_link_stats64 *s)
 {
        struct ksz_device *dev = ds->priv;
        struct ksz_port_mib *mib;
@@ -514,10 +806,22 @@ void ksz_get_stats64(struct dsa_switch *ds, int port,
        memcpy(s, &mib->stats64, sizeof(*s));
        spin_unlock(&mib->stats64_lock);
 }
-EXPORT_SYMBOL_GPL(ksz_get_stats64);
 
-void ksz_get_strings(struct dsa_switch *ds, int port,
-                    u32 stringset, uint8_t *buf)
+static void ksz_get_pause_stats(struct dsa_switch *ds, int port,
+                               struct ethtool_pause_stats *pause_stats)
+{
+       struct ksz_device *dev = ds->priv;
+       struct ksz_port_mib *mib;
+
+       mib = &dev->ports[port].mib;
+
+       spin_lock(&mib->stats64_lock);
+       memcpy(pause_stats, &mib->pause_stats, sizeof(*pause_stats));
+       spin_unlock(&mib->stats64_lock);
+}
+
+static void ksz_get_strings(struct dsa_switch *ds, int port,
+                           u32 stringset, uint8_t *buf)
 {
        struct ksz_device *dev = ds->priv;
        int i;
@@ -530,9 +834,8 @@ void ksz_get_strings(struct dsa_switch *ds, int port,
                       dev->info->mib_names[i].string, ETH_GSTRING_LEN);
        }
 }
-EXPORT_SYMBOL_GPL(ksz_get_strings);
 
-void ksz_update_port_member(struct ksz_device *dev, int port)
+static void ksz_update_port_member(struct ksz_device *dev, int port)
 {
        struct ksz_port *p = &dev->ports[port];
        struct dsa_switch *ds = dev->ds;
@@ -589,7 +892,55 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
 
        dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
 }
-EXPORT_SYMBOL_GPL(ksz_update_port_member);
+
+static int ksz_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       const u16 *regs;
+       int ret;
+
+       regs = dev->info->regs;
+
+       dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
+                                      dev->info->num_vlans, GFP_KERNEL);
+       if (!dev->vlan_cache)
+               return -ENOMEM;
+
+       ret = dev->dev_ops->reset(dev);
+       if (ret) {
+               dev_err(ds->dev, "failed to reset switch\n");
+               return ret;
+       }
+
+       /* set broadcast storm protection 10% rate */
+       regmap_update_bits(dev->regmap[1], regs[S_BROADCAST_CTRL],
+                          BROADCAST_STORM_RATE,
+                          (BROADCAST_STORM_VALUE *
+                          BROADCAST_STORM_PROT_RATE) / 100);
+
+       dev->dev_ops->config_cpu_port(ds);
+
+       dev->dev_ops->enable_stp_addr(dev);
+
+       regmap_update_bits(dev->regmap[0], regs[S_MULTICAST_CTRL],
+                          MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE);
+
+       ksz_init_mib_timer(dev);
+
+       ds->configure_vlan_while_not_filtering = false;
+
+       if (dev->dev_ops->setup) {
+               ret = dev->dev_ops->setup(ds);
+               if (ret)
+                       return ret;
+       }
+
+       /* start switch */
+       regmap_update_bits(dev->regmap[0], regs[S_START_CTRL],
+                          SW_START, SW_START);
+
+       return 0;
+}
 
 static void port_r_cnt(struct ksz_device *dev, int port)
 {
@@ -667,9 +1018,8 @@ void ksz_init_mib_timer(struct ksz_device *dev)
                memset(mib->counters, 0, dev->info->mib_cnt * sizeof(u64));
        }
 }
-EXPORT_SYMBOL_GPL(ksz_init_mib_timer);
 
-int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
+static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
 {
        struct ksz_device *dev = ds->priv;
        u16 val = 0xffff;
@@ -678,9 +1028,8 @@ int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
 
        return val;
 }
-EXPORT_SYMBOL_GPL(ksz_phy_read16);
 
-int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
+static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
 {
        struct ksz_device *dev = ds->priv;
 
@@ -688,10 +1037,25 @@ int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ksz_phy_write16);
 
-void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
-                      phy_interface_t interface)
+static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (dev->chip_id == KSZ8830_CHIP_ID) {
+               /* Silicon Errata Sheet (DS80000830A):
+                * Port 1 does not work with LinkMD Cable-Testing.
+                * Port 1 does not respond to received PAUSE control frames.
+                */
+               if (!port)
+                       return MICREL_KSZ8_P1_ERRATA;
+       }
+
+       return 0;
+}
+
+static void ksz_mac_link_down(struct dsa_switch *ds, int port,
+                             unsigned int mode, phy_interface_t interface)
 {
        struct ksz_device *dev = ds->priv;
        struct ksz_port *p = &dev->ports[port];
@@ -702,9 +1066,8 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
        if (dev->mib_read_interval)
                schedule_delayed_work(&dev->mib_read, 0);
 }
-EXPORT_SYMBOL_GPL(ksz_mac_link_down);
 
-int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
+static int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
 {
        struct ksz_device *dev = ds->priv;
 
@@ -713,9 +1076,9 @@ int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
 
        return dev->info->mib_cnt;
 }
-EXPORT_SYMBOL_GPL(ksz_sset_count);
 
-void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
+static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
+                                 uint64_t *buf)
 {
        const struct dsa_port *dp = dsa_to_port(ds, port);
        struct ksz_device *dev = ds->priv;
@@ -731,12 +1094,11 @@ void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
        memcpy(buf, mib->counters, dev->info->mib_cnt * sizeof(u64));
        mutex_unlock(&mib->cnt_mutex);
 }
-EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);
 
-int ksz_port_bridge_join(struct dsa_switch *ds, int port,
-                        struct dsa_bridge bridge,
-                        bool *tx_fwd_offload,
-                        struct netlink_ext_ack *extack)
+static int ksz_port_bridge_join(struct dsa_switch *ds, int port,
+                               struct dsa_bridge bridge,
+                               bool *tx_fwd_offload,
+                               struct netlink_ext_ack *extack)
 {
        /* port_stp_state_set() will be called after to put the port in
         * appropriate state so there is no need to do anything.
@@ -744,135 +1106,83 @@ int ksz_port_bridge_join(struct dsa_switch *ds, int port,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ksz_port_bridge_join);
 
-void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
-                          struct dsa_bridge bridge)
+static void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
+                                 struct dsa_bridge bridge)
 {
        /* port_stp_state_set() will be called after to put the port in
         * forwarding state so there is no need to do anything.
         */
 }
-EXPORT_SYMBOL_GPL(ksz_port_bridge_leave);
 
-void ksz_port_fast_age(struct dsa_switch *ds, int port)
+static void ksz_port_fast_age(struct dsa_switch *ds, int port)
 {
        struct ksz_device *dev = ds->priv;
 
        dev->dev_ops->flush_dyn_mac_table(dev, port);
 }
-EXPORT_SYMBOL_GPL(ksz_port_fast_age);
 
-int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
-                     void *data)
+static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
+                           const unsigned char *addr, u16 vid,
+                           struct dsa_db db)
 {
        struct ksz_device *dev = ds->priv;
-       int ret = 0;
-       u16 i = 0;
-       u16 entries = 0;
-       u8 timestamp = 0;
-       u8 fid;
-       u8 member;
-       struct alu_struct alu;
-
-       do {
-               alu.is_static = false;
-               ret = dev->dev_ops->r_dyn_mac_table(dev, i, alu.mac, &fid,
-                                                   &member, &timestamp,
-                                                   &entries);
-               if (!ret && (member & BIT(port))) {
-                       ret = cb(alu.mac, alu.fid, alu.is_static, data);
-                       if (ret)
-                               break;
-               }
-               i++;
-       } while (i < entries);
-       if (i >= entries)
-               ret = 0;
 
-       return ret;
+       if (!dev->dev_ops->fdb_add)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->fdb_add(dev, port, addr, vid, db);
 }
-EXPORT_SYMBOL_GPL(ksz_port_fdb_dump);
 
-int ksz_port_mdb_add(struct dsa_switch *ds, int port,
-                    const struct switchdev_obj_port_mdb *mdb,
-                    struct dsa_db db)
+static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
+                           const unsigned char *addr,
+                           u16 vid, struct dsa_db db)
 {
        struct ksz_device *dev = ds->priv;
-       struct alu_struct alu;
-       int index;
-       int empty = 0;
-
-       alu.port_forward = 0;
-       for (index = 0; index < dev->info->num_statics; index++) {
-               if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
-                       /* Found one already in static MAC table. */
-                       if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
-                           alu.fid == mdb->vid)
-                               break;
-               /* Remember the first empty entry. */
-               } else if (!empty) {
-                       empty = index + 1;
-               }
-       }
 
-       /* no available entry */
-       if (index == dev->info->num_statics && !empty)
-               return -ENOSPC;
+       if (!dev->dev_ops->fdb_del)
+               return -EOPNOTSUPP;
 
-       /* add entry */
-       if (index == dev->info->num_statics) {
-               index = empty - 1;
-               memset(&alu, 0, sizeof(alu));
-               memcpy(alu.mac, mdb->addr, ETH_ALEN);
-               alu.is_static = true;
-       }
-       alu.port_forward |= BIT(port);
-       if (mdb->vid) {
-               alu.is_use_fid = true;
+       return dev->dev_ops->fdb_del(dev, port, addr, vid, db);
+}
 
-               /* Need a way to map VID to FID. */
-               alu.fid = mdb->vid;
-       }
-       dev->dev_ops->w_sta_mac_table(dev, index, &alu);
+static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
+                            dsa_fdb_dump_cb_t *cb, void *data)
+{
+       struct ksz_device *dev = ds->priv;
 
-       return 0;
+       if (!dev->dev_ops->fdb_dump)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->fdb_dump(dev, port, cb, data);
 }
-EXPORT_SYMBOL_GPL(ksz_port_mdb_add);
 
-int ksz_port_mdb_del(struct dsa_switch *ds, int port,
-                    const struct switchdev_obj_port_mdb *mdb,
-                    struct dsa_db db)
+static int ksz_port_mdb_add(struct dsa_switch *ds, int port,
+                           const struct switchdev_obj_port_mdb *mdb,
+                           struct dsa_db db)
 {
        struct ksz_device *dev = ds->priv;
-       struct alu_struct alu;
-       int index;
-
-       for (index = 0; index < dev->info->num_statics; index++) {
-               if (!dev->dev_ops->r_sta_mac_table(dev, index, &alu)) {
-                       /* Found one already in static MAC table. */
-                       if (!memcmp(alu.mac, mdb->addr, ETH_ALEN) &&
-                           alu.fid == mdb->vid)
-                               break;
-               }
-       }
 
-       /* no available entry */
-       if (index == dev->info->num_statics)
-               goto exit;
+       if (!dev->dev_ops->mdb_add)
+               return -EOPNOTSUPP;
 
-       /* clear port */
-       alu.port_forward &= ~BIT(port);
-       if (!alu.port_forward)
-               alu.is_static = false;
-       dev->dev_ops->w_sta_mac_table(dev, index, &alu);
+       return dev->dev_ops->mdb_add(dev, port, mdb, db);
+}
 
-exit:
-       return 0;
+static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
+                           const struct switchdev_obj_port_mdb *mdb,
+                           struct dsa_db db)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->mdb_del)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->mdb_del(dev, port, mdb, db);
 }
-EXPORT_SYMBOL_GPL(ksz_port_mdb_del);
 
-int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
+static int ksz_enable_port(struct dsa_switch *ds, int port,
+                          struct phy_device *phy)
 {
        struct ksz_device *dev = ds->priv;
 
@@ -888,16 +1198,17 @@ int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(ksz_enable_port);
 
-void ksz_port_stp_state_set(struct dsa_switch *ds, int port,
-                           u8 state, int reg)
+void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
 {
        struct ksz_device *dev = ds->priv;
        struct ksz_port *p;
+       const u16 *regs;
        u8 data;
 
-       ksz_pread8(dev, port, reg, &data);
+       regs = dev->info->regs;
+
+       ksz_pread8(dev, port, regs[P_STP_CTRL], &data);
        data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
 
        switch (state) {
@@ -921,14 +1232,239 @@ void ksz_port_stp_state_set(struct dsa_switch *ds, int port,
                return;
        }
 
-       ksz_pwrite8(dev, port, reg, data);
+       ksz_pwrite8(dev, port, regs[P_STP_CTRL], data);
 
        p = &dev->ports[port];
        p->stp_state = state;
 
        ksz_update_port_member(dev, port);
 }
-EXPORT_SYMBOL_GPL(ksz_port_stp_state_set);
+
+static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
+                                                 int port,
+                                                 enum dsa_tag_protocol mp)
+{
+       struct ksz_device *dev = ds->priv;
+       enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE;
+
+       if (dev->chip_id == KSZ8795_CHIP_ID ||
+           dev->chip_id == KSZ8794_CHIP_ID ||
+           dev->chip_id == KSZ8765_CHIP_ID)
+               proto = DSA_TAG_PROTO_KSZ8795;
+
+       if (dev->chip_id == KSZ8830_CHIP_ID ||
+           dev->chip_id == KSZ9893_CHIP_ID)
+               proto = DSA_TAG_PROTO_KSZ9893;
+
+       if (dev->chip_id == KSZ9477_CHIP_ID ||
+           dev->chip_id == KSZ9897_CHIP_ID ||
+           dev->chip_id == KSZ9567_CHIP_ID)
+               proto = DSA_TAG_PROTO_KSZ9477;
+
+       if (is_lan937x(dev))
+               proto = DSA_TAG_PROTO_LAN937X_VALUE;
+
+       return proto;
+}
+
+static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
+                                  bool flag, struct netlink_ext_ack *extack)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->vlan_filtering)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->vlan_filtering(dev, port, flag, extack);
+}
+
+static int ksz_port_vlan_add(struct dsa_switch *ds, int port,
+                            const struct switchdev_obj_port_vlan *vlan,
+                            struct netlink_ext_ack *extack)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->vlan_add)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->vlan_add(dev, port, vlan, extack);
+}
+
+static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
+                            const struct switchdev_obj_port_vlan *vlan)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->vlan_del)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->vlan_del(dev, port, vlan);
+}
+
+static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
+                              struct dsa_mall_mirror_tc_entry *mirror,
+                              bool ingress, struct netlink_ext_ack *extack)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->mirror_add)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->mirror_add(dev, port, mirror, ingress, extack);
+}
+
+static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
+                               struct dsa_mall_mirror_tc_entry *mirror)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (dev->dev_ops->mirror_del)
+               dev->dev_ops->mirror_del(dev, port, mirror);
+}
+
+static int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->change_mtu)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->change_mtu(dev, port, mtu);
+}
+
+static int ksz_max_mtu(struct dsa_switch *ds, int port)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (!dev->dev_ops->max_mtu)
+               return -EOPNOTSUPP;
+
+       return dev->dev_ops->max_mtu(dev, port);
+}
+
+static void ksz_phylink_mac_config(struct dsa_switch *ds, int port,
+                                  unsigned int mode,
+                                  const struct phylink_link_state *state)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (dev->dev_ops->phylink_mac_config)
+               dev->dev_ops->phylink_mac_config(dev, port, mode, state);
+}
+
+static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
+                                   unsigned int mode,
+                                   phy_interface_t interface,
+                                   struct phy_device *phydev, int speed,
+                                   int duplex, bool tx_pause, bool rx_pause)
+{
+       struct ksz_device *dev = ds->priv;
+
+       if (dev->dev_ops->phylink_mac_link_up)
+               dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface,
+                                                 phydev, speed, duplex,
+                                                 tx_pause, rx_pause);
+}
+
+static int ksz_switch_detect(struct ksz_device *dev)
+{
+       u8 id1, id2;
+       u16 id16;
+       u32 id32;
+       int ret;
+
+       /* read chip id */
+       ret = ksz_read16(dev, REG_CHIP_ID0, &id16);
+       if (ret)
+               return ret;
+
+       id1 = FIELD_GET(SW_FAMILY_ID_M, id16);
+       id2 = FIELD_GET(SW_CHIP_ID_M, id16);
+
+       switch (id1) {
+       case KSZ87_FAMILY_ID:
+               if (id2 == KSZ87_CHIP_ID_95) {
+                       u8 val;
+
+                       dev->chip_id = KSZ8795_CHIP_ID;
+
+                       ksz_read8(dev, KSZ8_PORT_STATUS_0, &val);
+                       if (val & KSZ8_PORT_FIBER_MODE)
+                               dev->chip_id = KSZ8765_CHIP_ID;
+               } else if (id2 == KSZ87_CHIP_ID_94) {
+                       dev->chip_id = KSZ8794_CHIP_ID;
+               } else {
+                       return -ENODEV;
+               }
+               break;
+       case KSZ88_FAMILY_ID:
+               if (id2 == KSZ88_CHIP_ID_63)
+                       dev->chip_id = KSZ8830_CHIP_ID;
+               else
+                       return -ENODEV;
+               break;
+       default:
+               ret = ksz_read32(dev, REG_CHIP_ID0, &id32);
+               if (ret)
+                       return ret;
+
+               dev->chip_rev = FIELD_GET(SW_REV_ID_M, id32);
+               id32 &= ~0xFF;
+
+               switch (id32) {
+               case KSZ9477_CHIP_ID:
+               case KSZ9897_CHIP_ID:
+               case KSZ9893_CHIP_ID:
+               case KSZ9567_CHIP_ID:
+               case LAN9370_CHIP_ID:
+               case LAN9371_CHIP_ID:
+               case LAN9372_CHIP_ID:
+               case LAN9373_CHIP_ID:
+               case LAN9374_CHIP_ID:
+                       dev->chip_id = id32;
+                       break;
+               default:
+                       dev_err(dev->dev,
+                               "unsupported switch detected %x)\n", id32);
+                       return -ENODEV;
+               }
+       }
+       return 0;
+}
+
+static const struct dsa_switch_ops ksz_switch_ops = {
+       .get_tag_protocol       = ksz_get_tag_protocol,
+       .get_phy_flags          = ksz_get_phy_flags,
+       .setup                  = ksz_setup,
+       .phy_read               = ksz_phy_read16,
+       .phy_write              = ksz_phy_write16,
+       .phylink_get_caps       = ksz_phylink_get_caps,
+       .phylink_mac_config     = ksz_phylink_mac_config,
+       .phylink_mac_link_up    = ksz_phylink_mac_link_up,
+       .phylink_mac_link_down  = ksz_mac_link_down,
+       .port_enable            = ksz_enable_port,
+       .get_strings            = ksz_get_strings,
+       .get_ethtool_stats      = ksz_get_ethtool_stats,
+       .get_sset_count         = ksz_sset_count,
+       .port_bridge_join       = ksz_port_bridge_join,
+       .port_bridge_leave      = ksz_port_bridge_leave,
+       .port_stp_state_set     = ksz_port_stp_state_set,
+       .port_fast_age          = ksz_port_fast_age,
+       .port_vlan_filtering    = ksz_port_vlan_filtering,
+       .port_vlan_add          = ksz_port_vlan_add,
+       .port_vlan_del          = ksz_port_vlan_del,
+       .port_fdb_dump          = ksz_port_fdb_dump,
+       .port_fdb_add           = ksz_port_fdb_add,
+       .port_fdb_del           = ksz_port_fdb_del,
+       .port_mdb_add           = ksz_port_mdb_add,
+       .port_mdb_del           = ksz_port_mdb_del,
+       .port_mirror_add        = ksz_port_mirror_add,
+       .port_mirror_del        = ksz_port_mirror_del,
+       .get_stats64            = ksz_get_stats64,
+       .get_pause_stats        = ksz_get_pause_stats,
+       .port_change_mtu        = ksz_change_mtu,
+       .port_max_mtu           = ksz_max_mtu,
+};
 
 struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
 {
@@ -941,6 +1477,7 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
 
        ds->dev = base;
        ds->num_ports = DSA_MAX_PORTS;
+       ds->ops = &ksz_switch_ops;
 
        swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
        if (!swdev)
@@ -956,8 +1493,7 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
 }
 EXPORT_SYMBOL(ksz_switch_alloc);
 
-int ksz_switch_register(struct ksz_device *dev,
-                       const struct ksz_dev_ops *ops)
+int ksz_switch_register(struct ksz_device *dev)
 {
        const struct ksz_chip_data *info;
        struct device_node *port, *ports;
@@ -986,10 +1522,9 @@ int ksz_switch_register(struct ksz_device *dev,
        mutex_init(&dev->alu_mutex);
        mutex_init(&dev->vlan_mutex);
 
-       dev->dev_ops = ops;
-
-       if (dev->dev_ops->detect(dev))
-               return -EINVAL;
+       ret = ksz_switch_detect(dev);
+       if (ret)
+               return ret;
 
        info = ksz_lookup_info(dev->chip_id);
        if (!info)
@@ -998,10 +1533,15 @@ int ksz_switch_register(struct ksz_device *dev,
        /* Update the compatible info with the probed one */
        dev->info = info;
 
+       dev_info(dev->dev, "found switch: %s, rev %i\n",
+                dev->info->dev_name, dev->chip_rev);
+
        ret = ksz_check_device_id(dev);
        if (ret)
                return ret;
 
+       dev->dev_ops = dev->info->ops;
+
        ret = dev->dev_ops->init(dev);
        if (ret)
                return ret;
@@ -1072,7 +1612,7 @@ int ksz_switch_register(struct ksz_device *dev,
        /* Start the MIB timer. */
        schedule_delayed_work(&dev->mib_read, 0);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(ksz_switch_register);
 
index 8500eae..d5dddb7 100644 (file)
@@ -25,6 +25,7 @@ struct ksz_port_mib {
        u8 cnt_ptr;
        u64 *counters;
        struct rtnl_link_stats64 stats64;
+       struct ethtool_pause_stats pause_stats;
        struct spinlock stats64_lock;
 };
 
@@ -41,11 +42,19 @@ struct ksz_chip_data {
        int num_statics;
        int cpu_ports;
        int port_cnt;
+       const struct ksz_dev_ops *ops;
        bool phy_errata_9477;
        bool ksz87xx_eee_link_erratum;
        const struct ksz_mib_names *mib_names;
        int mib_cnt;
        u8 reg_mib_cnt;
+       const u16 *regs;
+       const u32 *masks;
+       const u8 *shifts;
+       int stp_ctrl_reg;
+       int broadcast_ctrl_reg;
+       int multicast_ctrl_reg;
+       int start_ctrl_reg;
        bool supports_mii[KSZ_MAX_NUM_PORTS];
        bool supports_rmii[KSZ_MAX_NUM_PORTS];
        bool supports_rgmii[KSZ_MAX_NUM_PORTS];
@@ -90,6 +99,7 @@ struct ksz_device {
 
        /* chip specific data */
        u32 chip_id;
+       u8 chip_rev;
        int cpu_port;                   /* port connected to CPU */
        int phy_port_cnt;
        phy_interface_t compat_interface;
@@ -140,6 +150,64 @@ enum ksz_chip_id {
        LAN9374_CHIP_ID = 0x00937400,
 };
 
+enum ksz_regs {
+       REG_IND_CTRL_0,
+       REG_IND_DATA_8,
+       REG_IND_DATA_CHECK,
+       REG_IND_DATA_HI,
+       REG_IND_DATA_LO,
+       REG_IND_MIB_CHECK,
+       REG_IND_BYTE,
+       P_FORCE_CTRL,
+       P_LINK_STATUS,
+       P_LOCAL_CTRL,
+       P_NEG_RESTART_CTRL,
+       P_REMOTE_STATUS,
+       P_SPEED_STATUS,
+       S_TAIL_TAG_CTRL,
+       P_STP_CTRL,
+       S_START_CTRL,
+       S_BROADCAST_CTRL,
+       S_MULTICAST_CTRL,
+};
+
+enum ksz_masks {
+       PORT_802_1P_REMAPPING,
+       SW_TAIL_TAG_ENABLE,
+       MIB_COUNTER_OVERFLOW,
+       MIB_COUNTER_VALID,
+       VLAN_TABLE_FID,
+       VLAN_TABLE_MEMBERSHIP,
+       VLAN_TABLE_VALID,
+       STATIC_MAC_TABLE_VALID,
+       STATIC_MAC_TABLE_USE_FID,
+       STATIC_MAC_TABLE_FID,
+       STATIC_MAC_TABLE_OVERRIDE,
+       STATIC_MAC_TABLE_FWD_PORTS,
+       DYNAMIC_MAC_TABLE_ENTRIES_H,
+       DYNAMIC_MAC_TABLE_MAC_EMPTY,
+       DYNAMIC_MAC_TABLE_NOT_READY,
+       DYNAMIC_MAC_TABLE_ENTRIES,
+       DYNAMIC_MAC_TABLE_FID,
+       DYNAMIC_MAC_TABLE_SRC_PORT,
+       DYNAMIC_MAC_TABLE_TIMESTAMP,
+       ALU_STAT_WRITE,
+       ALU_STAT_READ,
+};
+
+enum ksz_shifts {
+       VLAN_TABLE_MEMBERSHIP_S,
+       VLAN_TABLE,
+       STATIC_MAC_FWD_PORTS,
+       STATIC_MAC_FID,
+       DYNAMIC_MAC_ENTRIES_H,
+       DYNAMIC_MAC_ENTRIES,
+       DYNAMIC_MAC_FID,
+       DYNAMIC_MAC_TIMESTAMP,
+       DYNAMIC_MAC_SRC_PORT,
+       ALU_STAT_INDEX,
+};
+
 struct alu_struct {
        /* entry 1 */
        u8      is_static:1;
@@ -160,6 +228,7 @@ struct alu_struct {
 };
 
 struct ksz_dev_ops {
+       int (*setup)(struct dsa_switch *ds);
        u32 (*get_port_addr)(int port, int offset);
        void (*cfg_port_member)(struct ksz_device *dev, int port, u8 member);
        void (*flush_dyn_mac_table)(struct ksz_device *dev, int port);
@@ -167,71 +236,65 @@ struct ksz_dev_ops {
        void (*port_setup)(struct ksz_device *dev, int port, bool cpu_port);
        void (*r_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 *val);
        void (*w_phy)(struct ksz_device *dev, u16 phy, u16 reg, u16 val);
-       int (*r_dyn_mac_table)(struct ksz_device *dev, u16 addr, u8 *mac_addr,
-                              u8 *fid, u8 *src_port, u8 *timestamp,
-                              u16 *entries);
-       int (*r_sta_mac_table)(struct ksz_device *dev, u16 addr,
-                              struct alu_struct *alu);
-       void (*w_sta_mac_table)(struct ksz_device *dev, u16 addr,
-                               struct alu_struct *alu);
        void (*r_mib_cnt)(struct ksz_device *dev, int port, u16 addr,
                          u64 *cnt);
        void (*r_mib_pkt)(struct ksz_device *dev, int port, u16 addr,
                          u64 *dropped, u64 *cnt);
        void (*r_mib_stat64)(struct ksz_device *dev, int port);
+       int  (*vlan_filtering)(struct ksz_device *dev, int port,
+                              bool flag, struct netlink_ext_ack *extack);
+       int  (*vlan_add)(struct ksz_device *dev, int port,
+                        const struct switchdev_obj_port_vlan *vlan,
+                        struct netlink_ext_ack *extack);
+       int  (*vlan_del)(struct ksz_device *dev, int port,
+                        const struct switchdev_obj_port_vlan *vlan);
+       int (*mirror_add)(struct ksz_device *dev, int port,
+                         struct dsa_mall_mirror_tc_entry *mirror,
+                         bool ingress, struct netlink_ext_ack *extack);
+       void (*mirror_del)(struct ksz_device *dev, int port,
+                          struct dsa_mall_mirror_tc_entry *mirror);
+       int (*fdb_add)(struct ksz_device *dev, int port,
+                      const unsigned char *addr, u16 vid, struct dsa_db db);
+       int (*fdb_del)(struct ksz_device *dev, int port,
+                      const unsigned char *addr, u16 vid, struct dsa_db db);
+       int (*fdb_dump)(struct ksz_device *dev, int port,
+                       dsa_fdb_dump_cb_t *cb, void *data);
+       int (*mdb_add)(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_mdb *mdb,
+                      struct dsa_db db);
+       int (*mdb_del)(struct ksz_device *dev, int port,
+                      const struct switchdev_obj_port_mdb *mdb,
+                      struct dsa_db db);
+       void (*get_caps)(struct ksz_device *dev, int port,
+                        struct phylink_config *config);
+       int (*change_mtu)(struct ksz_device *dev, int port, int mtu);
+       int (*max_mtu)(struct ksz_device *dev, int port);
        void (*freeze_mib)(struct ksz_device *dev, int port, bool freeze);
        void (*port_init_cnt)(struct ksz_device *dev, int port);
-       int (*shutdown)(struct ksz_device *dev);
-       int (*detect)(struct ksz_device *dev);
+       void (*phylink_mac_config)(struct ksz_device *dev, int port,
+                                  unsigned int mode,
+                                  const struct phylink_link_state *state);
+       void (*phylink_mac_link_up)(struct ksz_device *dev, int port,
+                                   unsigned int mode,
+                                   phy_interface_t interface,
+                                   struct phy_device *phydev, int speed,
+                                   int duplex, bool tx_pause, bool rx_pause);
+       void (*config_cpu_port)(struct dsa_switch *ds);
+       int (*enable_stp_addr)(struct ksz_device *dev);
+       int (*reset)(struct ksz_device *dev);
        int (*init)(struct ksz_device *dev);
        void (*exit)(struct ksz_device *dev);
 };
 
 struct ksz_device *ksz_switch_alloc(struct device *base, void *priv);
-int ksz_switch_register(struct ksz_device *dev,
-                       const struct ksz_dev_ops *ops);
+int ksz_switch_register(struct ksz_device *dev);
 void ksz_switch_remove(struct ksz_device *dev);
 
-int ksz8_switch_register(struct ksz_device *dev);
-int ksz9477_switch_register(struct ksz_device *dev);
-
-void ksz_update_port_member(struct ksz_device *dev, int port);
 void ksz_init_mib_timer(struct ksz_device *dev);
 void ksz_r_mib_stats64(struct ksz_device *dev, int port);
-void ksz_get_stats64(struct dsa_switch *ds, int port,
-                    struct rtnl_link_stats64 *s);
-void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
-                         struct phylink_config *config);
+void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
 extern const struct ksz_chip_data ksz_switch_chips[];
 
-/* Common DSA access functions */
-
-int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg);
-int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val);
-void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
-                      phy_interface_t interface);
-int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
-void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf);
-int ksz_port_bridge_join(struct dsa_switch *ds, int port,
-                        struct dsa_bridge bridge, bool *tx_fwd_offload,
-                        struct netlink_ext_ack *extack);
-void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
-                          struct dsa_bridge bridge);
-void ksz_port_stp_state_set(struct dsa_switch *ds, int port,
-                           u8 state, int reg);
-void ksz_port_fast_age(struct dsa_switch *ds, int port);
-int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
-                     void *data);
-int ksz_port_mdb_add(struct dsa_switch *ds, int port,
-                    const struct switchdev_obj_port_mdb *mdb,
-                    struct dsa_db db);
-int ksz_port_mdb_del(struct dsa_switch *ds, int port,
-                    const struct switchdev_obj_port_mdb *mdb,
-                    struct dsa_db db);
-int ksz_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy);
-void ksz_get_strings(struct dsa_switch *ds, int port,
-                    u32 stringset, uint8_t *buf);
-
 /* Common register access functions */
 
 static inline int ksz_read8(struct ksz_device *dev, u32 reg, u8 *val)
@@ -348,11 +411,51 @@ static inline void ksz_regmap_unlock(void *__mtx)
        mutex_unlock(mtx);
 }
 
+static inline int is_lan937x(struct ksz_device *dev)
+{
+       return dev->chip_id == LAN9370_CHIP_ID ||
+               dev->chip_id == LAN9371_CHIP_ID ||
+               dev->chip_id == LAN9372_CHIP_ID ||
+               dev->chip_id == LAN9373_CHIP_ID ||
+               dev->chip_id == LAN9374_CHIP_ID;
+}
+
 /* STP State Defines */
 #define PORT_TX_ENABLE                 BIT(2)
 #define PORT_RX_ENABLE                 BIT(1)
 #define PORT_LEARN_DISABLE             BIT(0)
 
+/* Switch ID Defines */
+#define REG_CHIP_ID0                   0x00
+
+#define SW_FAMILY_ID_M                 GENMASK(15, 8)
+#define KSZ87_FAMILY_ID                        0x87
+#define KSZ88_FAMILY_ID                        0x88
+
+#define KSZ8_PORT_STATUS_0             0x08
+#define KSZ8_PORT_FIBER_MODE           BIT(7)
+
+#define SW_CHIP_ID_M                   GENMASK(7, 4)
+#define KSZ87_CHIP_ID_94               0x6
+#define KSZ87_CHIP_ID_95               0x9
+#define KSZ88_CHIP_ID_63               0x3
+
+#define SW_REV_ID_M                    GENMASK(7, 4)
+
+/* Driver set switch broadcast storm protection at 10% rate. */
+#define BROADCAST_STORM_PROT_RATE      10
+
+/* 148,800 frames * 67 ms / 100 */
+#define BROADCAST_STORM_VALUE          9969
+
+#define BROADCAST_STORM_RATE_HI                0x07
+#define BROADCAST_STORM_RATE_LO                0xFF
+#define BROADCAST_STORM_RATE           0x07FF
+
+#define MULTICAST_STORM_DISABLE                BIT(6)
+
+#define SW_START                       0x01
+
 /* Regmap tables generation */
 #define KSZ_SPI_OP_RD          3
 #define KSZ_SPI_OP_WR          2
similarity index 52%
rename from drivers/net/dsa/microchip/ksz8795_spi.c
rename to drivers/net/dsa/microchip/ksz_spi.c
index 961a74c..4844830 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Microchip KSZ8795 series register access through SPI
+ * Microchip ksz series register access through SPI
  *
  * Copyright (C) 2017 Microchip Technology Inc.
  *     Tristram Ha <Tristram.Ha@microchip.com>
@@ -14,7 +14,6 @@
 #include <linux/regmap.h>
 #include <linux/spi/spi.h>
 
-#include "ksz8.h"
 #include "ksz_common.h"
 
 #define KSZ8795_SPI_ADDR_SHIFT                 12
 #define KSZ8863_SPI_ADDR_ALIGN                 8
 #define KSZ8863_SPI_TURNAROUND_SHIFT           0
 
+#define KSZ9477_SPI_ADDR_SHIFT                 24
+#define KSZ9477_SPI_ADDR_ALIGN                 3
+#define KSZ9477_SPI_TURNAROUND_SHIFT           5
+
 KSZ_REGMAP_TABLE(ksz8795, 16, KSZ8795_SPI_ADDR_SHIFT,
                 KSZ8795_SPI_TURNAROUND_SHIFT, KSZ8795_SPI_ADDR_ALIGN);
 
 KSZ_REGMAP_TABLE(ksz8863, 16, KSZ8863_SPI_ADDR_SHIFT,
                 KSZ8863_SPI_TURNAROUND_SHIFT, KSZ8863_SPI_ADDR_ALIGN);
 
-static int ksz8795_spi_probe(struct spi_device *spi)
+KSZ_REGMAP_TABLE(ksz9477, 32, KSZ9477_SPI_ADDR_SHIFT,
+                KSZ9477_SPI_TURNAROUND_SHIFT, KSZ9477_SPI_ADDR_ALIGN);
+
+static int ksz_spi_probe(struct spi_device *spi)
 {
        const struct regmap_config *regmap_config;
        const struct ksz_chip_data *chip;
        struct device *ddev = &spi->dev;
        struct regmap_config rc;
        struct ksz_device *dev;
-       struct ksz8 *ksz8;
        int i, ret = 0;
 
-       ksz8 = devm_kzalloc(&spi->dev, sizeof(struct ksz8), GFP_KERNEL);
-       if (!ksz8)
-               return -ENOMEM;
-
-       ksz8->priv = spi;
-
-       dev = ksz_switch_alloc(&spi->dev, ksz8);
+       dev = ksz_switch_alloc(&spi->dev, spi);
        if (!dev)
                return -ENOMEM;
 
@@ -57,8 +56,12 @@ static int ksz8795_spi_probe(struct spi_device *spi)
 
        if (chip->chip_id == KSZ8830_CHIP_ID)
                regmap_config = ksz8863_regmap_config;
-       else
+       else if (chip->chip_id == KSZ8795_CHIP_ID ||
+                chip->chip_id == KSZ8794_CHIP_ID ||
+                chip->chip_id == KSZ8765_CHIP_ID)
                regmap_config = ksz8795_regmap_config;
+       else
+               regmap_config = ksz9477_regmap_config;
 
        for (i = 0; i < ARRAY_SIZE(ksz8795_regmap_config); i++) {
                rc = regmap_config[i];
@@ -82,7 +85,7 @@ static int ksz8795_spi_probe(struct spi_device *spi)
        if (ret)
                return ret;
 
-       ret = ksz8_switch_register(dev);
+       ret = ksz_switch_register(dev);
 
        /* Main DSA driver may not be started yet. */
        if (ret)
@@ -93,7 +96,7 @@ static int ksz8795_spi_probe(struct spi_device *spi)
        return 0;
 }
 
-static void ksz8795_spi_remove(struct spi_device *spi)
+static void ksz_spi_remove(struct spi_device *spi)
 {
        struct ksz_device *dev = spi_get_drvdata(spi);
 
@@ -103,22 +106,22 @@ static void ksz8795_spi_remove(struct spi_device *spi)
        spi_set_drvdata(spi, NULL);
 }
 
-static void ksz8795_spi_shutdown(struct spi_device *spi)
+static void ksz_spi_shutdown(struct spi_device *spi)
 {
        struct ksz_device *dev = spi_get_drvdata(spi);
 
        if (!dev)
                return;
 
-       if (dev->dev_ops->shutdown)
-               dev->dev_ops->shutdown(dev);
+       if (dev->dev_ops->reset)
+               dev->dev_ops->reset(dev);
 
        dsa_switch_shutdown(dev->ds);
 
        spi_set_drvdata(spi, NULL);
 }
 
-static const struct of_device_id ksz8795_dt_ids[] = {
+static const struct of_device_id ksz_dt_ids[] = {
        {
                .compatible = "microchip,ksz8765",
                .data = &ksz_switch_chips[KSZ8765]
@@ -139,34 +142,96 @@ static const struct of_device_id ksz8795_dt_ids[] = {
                .compatible = "microchip,ksz8873",
                .data = &ksz_switch_chips[KSZ8830]
        },
+       {
+               .compatible = "microchip,ksz9477",
+               .data = &ksz_switch_chips[KSZ9477]
+       },
+       {
+               .compatible = "microchip,ksz9897",
+               .data = &ksz_switch_chips[KSZ9897]
+       },
+       {
+               .compatible = "microchip,ksz9893",
+               .data = &ksz_switch_chips[KSZ9893]
+       },
+       {
+               .compatible = "microchip,ksz9563",
+               .data = &ksz_switch_chips[KSZ9893]
+       },
+       {
+               .compatible = "microchip,ksz8563",
+               .data = &ksz_switch_chips[KSZ9893]
+       },
+       {
+               .compatible = "microchip,ksz9567",
+               .data = &ksz_switch_chips[KSZ9567]
+       },
+       {
+               .compatible = "microchip,lan9370",
+               .data = &ksz_switch_chips[LAN9370]
+       },
+       {
+               .compatible = "microchip,lan9371",
+               .data = &ksz_switch_chips[LAN9371]
+       },
+       {
+               .compatible = "microchip,lan9372",
+               .data = &ksz_switch_chips[LAN9372]
+       },
+       {
+               .compatible = "microchip,lan9373",
+               .data = &ksz_switch_chips[LAN9373]
+       },
+       {
+               .compatible = "microchip,lan9374",
+               .data = &ksz_switch_chips[LAN9374]
+       },
        {},
 };
-MODULE_DEVICE_TABLE(of, ksz8795_dt_ids);
+MODULE_DEVICE_TABLE(of, ksz_dt_ids);
 
-static const struct spi_device_id ksz8795_spi_ids[] = {
+static const struct spi_device_id ksz_spi_ids[] = {
        { "ksz8765" },
        { "ksz8794" },
        { "ksz8795" },
        { "ksz8863" },
        { "ksz8873" },
+       { "ksz9477" },
+       { "ksz9897" },
+       { "ksz9893" },
+       { "ksz9563" },
+       { "ksz8563" },
+       { "ksz9567" },
+       { "lan9370" },
+       { "lan9371" },
+       { "lan9372" },
+       { "lan9373" },
+       { "lan9374" },
        { },
 };
-MODULE_DEVICE_TABLE(spi, ksz8795_spi_ids);
+MODULE_DEVICE_TABLE(spi, ksz_spi_ids);
 
-static struct spi_driver ksz8795_spi_driver = {
+static struct spi_driver ksz_spi_driver = {
        .driver = {
-               .name   = "ksz8795-switch",
+               .name   = "ksz-switch",
                .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(ksz8795_dt_ids),
+               .of_match_table = of_match_ptr(ksz_dt_ids),
        },
-       .id_table = ksz8795_spi_ids,
-       .probe  = ksz8795_spi_probe,
-       .remove = ksz8795_spi_remove,
-       .shutdown = ksz8795_spi_shutdown,
+       .id_table = ksz_spi_ids,
+       .probe  = ksz_spi_probe,
+       .remove = ksz_spi_remove,
+       .shutdown = ksz_spi_shutdown,
 };
 
-module_spi_driver(ksz8795_spi_driver);
+module_spi_driver(ksz_spi_driver);
 
+MODULE_ALIAS("spi:ksz9477");
+MODULE_ALIAS("spi:ksz9897");
+MODULE_ALIAS("spi:ksz9893");
+MODULE_ALIAS("spi:ksz9563");
+MODULE_ALIAS("spi:ksz8563");
+MODULE_ALIAS("spi:ksz9567");
+MODULE_ALIAS("spi:lan937x");
 MODULE_AUTHOR("Tristram Ha <Tristram.Ha@microchip.com>");
-MODULE_DESCRIPTION("Microchip KSZ8795 Series Switch SPI Driver");
+MODULE_DESCRIPTION("Microchip ksz Series Switch SPI Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/lan937x.h b/drivers/net/dsa/microchip/lan937x.h
new file mode 100644 (file)
index 0000000..72ba9cb
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Microchip lan937x dev ops headers
+ * Copyright (C) 2019-2022 Microchip Technology Inc.
+ */
+
+#ifndef __LAN937X_CFG_H
+#define __LAN937X_CFG_H
+
+int lan937x_reset_switch(struct ksz_device *dev);
+int lan937x_setup(struct dsa_switch *ds);
+void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port);
+void lan937x_config_cpu_port(struct dsa_switch *ds);
+int lan937x_switch_init(struct ksz_device *dev);
+void lan937x_switch_exit(struct ksz_device *dev);
+void lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data);
+void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val);
+int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu);
+void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
+                             struct phylink_config *config);
+void lan937x_phylink_mac_link_up(struct ksz_device *dev, int port,
+                                unsigned int mode, phy_interface_t interface,
+                                struct phy_device *phydev, int speed,
+                                int duplex, bool tx_pause, bool rx_pause);
+void lan937x_phylink_mac_config(struct ksz_device *dev, int port,
+                               unsigned int mode,
+                               const struct phylink_link_state *state);
+#endif
diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c
new file mode 100644 (file)
index 0000000..c29d175
--- /dev/null
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Microchip LAN937X switch driver main logic
+ * Copyright (C) 2019-2022 Microchip Technology Inc.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iopoll.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
+#include <linux/math.h>
+#include <net/dsa.h>
+#include <net/switchdev.h>
+
+#include "lan937x_reg.h"
+#include "ksz_common.h"
+#include "lan937x.h"
+
+static int lan937x_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
+{
+       return regmap_update_bits(dev->regmap[0], addr, bits, set ? bits : 0);
+}
+
+static int lan937x_port_cfg(struct ksz_device *dev, int port, int offset,
+                           u8 bits, bool set)
+{
+       return regmap_update_bits(dev->regmap[0], PORT_CTRL_ADDR(port, offset),
+                                 bits, set ? bits : 0);
+}
+
+static int lan937x_enable_spi_indirect_access(struct ksz_device *dev)
+{
+       u16 data16;
+       int ret;
+
+       /* Enable Phy access through SPI */
+       ret = lan937x_cfg(dev, REG_GLOBAL_CTRL_0, SW_PHY_REG_BLOCK, false);
+       if (ret < 0)
+               return ret;
+
+       ret = ksz_read16(dev, REG_VPHY_SPECIAL_CTRL__2, &data16);
+       if (ret < 0)
+               return ret;
+
+       /* Allow SPI access */
+       data16 |= VPHY_SPI_INDIRECT_ENABLE;
+
+       return ksz_write16(dev, REG_VPHY_SPECIAL_CTRL__2, data16);
+}
+
+static int lan937x_vphy_ind_addr_wr(struct ksz_device *dev, int addr, int reg)
+{
+       u16 addr_base = REG_PORT_T1_PHY_CTRL_BASE;
+       u16 temp;
+
+       /* get register address based on the logical port */
+       temp = PORT_CTRL_ADDR(addr, (addr_base + (reg << 2)));
+
+       return ksz_write16(dev, REG_VPHY_IND_ADDR__2, temp);
+}
+
+static int lan937x_internal_phy_write(struct ksz_device *dev, int addr, int reg,
+                                     u16 val)
+{
+       unsigned int value;
+       int ret;
+
+       /* Check for internal phy port */
+       if (!dev->info->internal_phy[addr])
+               return -EOPNOTSUPP;
+
+       ret = lan937x_vphy_ind_addr_wr(dev, addr, reg);
+       if (ret < 0)
+               return ret;
+
+       /* Write the data to be written to the VPHY reg */
+       ret = ksz_write16(dev, REG_VPHY_IND_DATA__2, val);
+       if (ret < 0)
+               return ret;
+
+       /* Write the Write En and Busy bit */
+       ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2,
+                         (VPHY_IND_WRITE | VPHY_IND_BUSY));
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read_poll_timeout(dev->regmap[1], REG_VPHY_IND_CTRL__2,
+                                      value, !(value & VPHY_IND_BUSY), 10,
+                                      1000);
+       if (ret < 0) {
+               dev_err(dev->dev, "Failed to write phy register\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg,
+                                    u16 *val)
+{
+       unsigned int value;
+       int ret;
+
+       /* Check for internal phy port, return 0xffff for non-existent phy */
+       if (!dev->info->internal_phy[addr])
+               return 0xffff;
+
+       ret = lan937x_vphy_ind_addr_wr(dev, addr, reg);
+       if (ret < 0)
+               return ret;
+
+       /* Write Read and Busy bit to start the transaction */
+       ret = ksz_write16(dev, REG_VPHY_IND_CTRL__2, VPHY_IND_BUSY);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read_poll_timeout(dev->regmap[1], REG_VPHY_IND_CTRL__2,
+                                      value, !(value & VPHY_IND_BUSY), 10,
+                                      1000);
+       if (ret < 0) {
+               dev_err(dev->dev, "Failed to read phy register\n");
+               return ret;
+       }
+
+       /* Read the VPHY register which has the PHY data */
+       return ksz_read16(dev, REG_VPHY_IND_DATA__2, val);
+}
+
+void lan937x_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
+{
+       lan937x_internal_phy_read(dev, addr, reg, data);
+}
+
+void lan937x_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
+{
+       lan937x_internal_phy_write(dev, addr, reg, val);
+}
+
+static int lan937x_sw_mdio_read(struct mii_bus *bus, int addr, int regnum)
+{
+       struct ksz_device *dev = bus->priv;
+       u16 val;
+       int ret;
+
+       if (regnum & MII_ADDR_C45)
+               return -EOPNOTSUPP;
+
+       ret = lan937x_internal_phy_read(dev, addr, regnum, &val);
+       if (ret < 0)
+               return ret;
+
+       return val;
+}
+
+static int lan937x_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
+                                u16 val)
+{
+       struct ksz_device *dev = bus->priv;
+
+       if (regnum & MII_ADDR_C45)
+               return -EOPNOTSUPP;
+
+       return lan937x_internal_phy_write(dev, addr, regnum, val);
+}
+
+static int lan937x_mdio_register(struct ksz_device *dev)
+{
+       struct dsa_switch *ds = dev->ds;
+       struct device_node *mdio_np;
+       struct mii_bus *bus;
+       int ret;
+
+       mdio_np = of_get_child_by_name(dev->dev->of_node, "mdio");
+       if (!mdio_np) {
+               dev_err(ds->dev, "no MDIO bus node\n");
+               return -ENODEV;
+       }
+
+       bus = devm_mdiobus_alloc(ds->dev);
+       if (!bus) {
+               of_node_put(mdio_np);
+               return -ENOMEM;
+       }
+
+       bus->priv = dev;
+       bus->read = lan937x_sw_mdio_read;
+       bus->write = lan937x_sw_mdio_write;
+       bus->name = "lan937x slave smi";
+       snprintf(bus->id, MII_BUS_ID_SIZE, "SMI-%d", ds->index);
+       bus->parent = ds->dev;
+       bus->phy_mask = ~ds->phys_mii_mask;
+
+       ds->slave_mii_bus = bus;
+
+       ret = devm_of_mdiobus_register(ds->dev, bus, mdio_np);
+       if (ret) {
+               dev_err(ds->dev, "unable to register MDIO bus %s\n",
+                       bus->id);
+       }
+
+       of_node_put(mdio_np);
+
+       return ret;
+}
+
+int lan937x_reset_switch(struct ksz_device *dev)
+{
+       u32 data32;
+       int ret;
+
+       /* reset switch */
+       ret = lan937x_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
+       if (ret < 0)
+               return ret;
+
+       /* Enable Auto Aging */
+       ret = lan937x_cfg(dev, REG_SW_LUE_CTRL_1, SW_LINK_AUTO_AGING, true);
+       if (ret < 0)
+               return ret;
+
+       /* disable interrupts */
+       ret = ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);
+       if (ret < 0)
+               return ret;
+
+       ret = ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0xFF);
+       if (ret < 0)
+               return ret;
+
+       return ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
+}
+
+void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port)
+{
+       struct dsa_switch *ds = dev->ds;
+       u8 member;
+
+       /* enable tag tail for host port */
+       if (cpu_port)
+               lan937x_port_cfg(dev, port, REG_PORT_CTRL_0,
+                                PORT_TAIL_TAG_ENABLE, true);
+
+       /* disable frame check length field */
+       lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0, PORT_CHECK_LENGTH,
+                        false);
+
+       /* set back pressure for half duplex */
+       lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE,
+                        true);
+
+       /* enable 802.1p priority */
+       lan937x_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true);
+
+       if (!dev->info->internal_phy[port])
+               lan937x_port_cfg(dev, port, REG_PORT_XMII_CTRL_0,
+                                PORT_MII_TX_FLOW_CTRL | PORT_MII_RX_FLOW_CTRL,
+                                true);
+
+       if (cpu_port)
+               member = dsa_user_ports(ds);
+       else
+               member = BIT(dsa_upstream_port(ds, port));
+
+       dev->dev_ops->cfg_port_member(dev, port, member);
+}
+
+void lan937x_config_cpu_port(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       struct dsa_port *dp;
+
+       dsa_switch_for_each_cpu_port(dp, ds) {
+               if (dev->info->cpu_ports & (1 << dp->index)) {
+                       dev->cpu_port = dp->index;
+
+                       /* enable cpu port */
+                       lan937x_port_setup(dev, dp->index, true);
+               }
+       }
+
+       dsa_switch_for_each_user_port(dp, ds) {
+               ksz_port_stp_state_set(ds, dp->index, BR_STATE_DISABLED);
+       }
+}
+
+int lan937x_change_mtu(struct ksz_device *dev, int port, int new_mtu)
+{
+       struct dsa_switch *ds = dev->ds;
+       int ret;
+
+       new_mtu += VLAN_ETH_HLEN + ETH_FCS_LEN;
+
+       if (dsa_is_cpu_port(ds, port))
+               new_mtu += LAN937X_TAG_LEN;
+
+       if (new_mtu >= FR_MIN_SIZE)
+               ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0,
+                                      PORT_JUMBO_PACKET, true);
+       else
+               ret = lan937x_port_cfg(dev, port, REG_PORT_MAC_CTRL_0,
+                                      PORT_JUMBO_PACKET, false);
+       if (ret < 0) {
+               dev_err(ds->dev, "failed to enable jumbo\n");
+               return ret;
+       }
+
+       /* Write the frame size in PORT_MAX_FR_SIZE register */
+       ksz_pwrite16(dev, port, PORT_MAX_FR_SIZE, new_mtu);
+
+       return 0;
+}
+
+static void lan937x_config_gbit(struct ksz_device *dev, bool gbit, u8 *data)
+{
+       if (gbit)
+               *data &= ~PORT_MII_NOT_1GBIT;
+       else
+               *data |= PORT_MII_NOT_1GBIT;
+}
+
+static void lan937x_mac_config(struct ksz_device *dev, int port,
+                              phy_interface_t interface)
+{
+       u8 data8;
+
+       ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8);
+
+       /* clear MII selection & set it based on interface later */
+       data8 &= ~PORT_MII_SEL_M;
+
+       /* configure MAC based on interface */
+       switch (interface) {
+       case PHY_INTERFACE_MODE_MII:
+               lan937x_config_gbit(dev, false, &data8);
+               data8 |= PORT_MII_SEL;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               lan937x_config_gbit(dev, false, &data8);
+               data8 |= PORT_RMII_SEL;
+               break;
+       default:
+               dev_err(dev->dev, "Unsupported interface '%s' for port %d\n",
+                       phy_modes(interface), port);
+               return;
+       }
+
+       /* Write the updated value */
+       ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8);
+}
+
+static void lan937x_config_interface(struct ksz_device *dev, int port,
+                                    int speed, int duplex,
+                                    bool tx_pause, bool rx_pause)
+{
+       u8 xmii_ctrl0, xmii_ctrl1;
+
+       ksz_pread8(dev, port, REG_PORT_XMII_CTRL_0, &xmii_ctrl0);
+       ksz_pread8(dev, port, REG_PORT_XMII_CTRL_1, &xmii_ctrl1);
+
+       xmii_ctrl0 &= ~(PORT_MII_100MBIT | PORT_MII_FULL_DUPLEX |
+                       PORT_MII_TX_FLOW_CTRL | PORT_MII_RX_FLOW_CTRL);
+
+       if (speed == SPEED_1000)
+               lan937x_config_gbit(dev, true, &xmii_ctrl1);
+       else
+               lan937x_config_gbit(dev, false, &xmii_ctrl1);
+
+       if (speed == SPEED_100)
+               xmii_ctrl0 |= PORT_MII_100MBIT;
+
+       if (duplex)
+               xmii_ctrl0 |= PORT_MII_FULL_DUPLEX;
+
+       if (tx_pause)
+               xmii_ctrl0 |= PORT_MII_TX_FLOW_CTRL;
+
+       if (rx_pause)
+               xmii_ctrl0 |= PORT_MII_RX_FLOW_CTRL;
+
+       ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_0, xmii_ctrl0);
+       ksz_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, xmii_ctrl1);
+}
+
+void lan937x_phylink_get_caps(struct ksz_device *dev, int port,
+                             struct phylink_config *config)
+{
+       config->mac_capabilities = MAC_100FD;
+
+       if (dev->info->supports_rgmii[port]) {
+               /* MII/RMII/RGMII ports */
+               config->mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+                                           MAC_100HD | MAC_10 | MAC_1000FD;
+       }
+}
+
+void lan937x_phylink_mac_link_up(struct ksz_device *dev, int port,
+                                unsigned int mode, phy_interface_t interface,
+                                struct phy_device *phydev, int speed,
+                                int duplex, bool tx_pause, bool rx_pause)
+{
+       /* Internal PHYs */
+       if (dev->info->internal_phy[port])
+               return;
+
+       lan937x_config_interface(dev, port, speed, duplex,
+                                tx_pause, rx_pause);
+}
+
+void lan937x_phylink_mac_config(struct ksz_device *dev, int port,
+                               unsigned int mode,
+                               const struct phylink_link_state *state)
+{
+       /* Internal PHYs */
+       if (dev->info->internal_phy[port])
+               return;
+
+       if (phylink_autoneg_inband(mode)) {
+               dev_err(dev->dev, "In-band AN not supported!\n");
+               return;
+       }
+
+       lan937x_mac_config(dev, port, state->interface);
+}
+
+int lan937x_setup(struct dsa_switch *ds)
+{
+       struct ksz_device *dev = ds->priv;
+       int ret;
+
+       /* enable Indirect Access from SPI to the VPHY registers */
+       ret = lan937x_enable_spi_indirect_access(dev);
+       if (ret < 0) {
+               dev_err(dev->dev, "failed to enable spi indirect access");
+               return ret;
+       }
+
+       ret = lan937x_mdio_register(dev);
+       if (ret < 0) {
+               dev_err(dev->dev, "failed to register the mdio");
+               return ret;
+       }
+
+       /* The VLAN aware is a global setting. Mixed vlan
+        * filterings are not supported.
+        */
+       ds->vlan_filtering_is_global = true;
+
+       /* Enable aggressive back off for half duplex & UNH mode */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_0,
+                   (SW_PAUSE_UNH_MODE | SW_NEW_BACKOFF | SW_AGGR_BACKOFF),
+                   true);
+
+       /* If NO_EXC_COLLISION_DROP bit is set, the switch will not drop
+        * packets when 16 or more collisions occur
+        */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_1, NO_EXC_COLLISION_DROP, true);
+
+       /* enable global MIB counter freeze function */
+       lan937x_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
+
+       /* disable CLK125 & CLK25, 1: disable, 0: enable */
+       lan937x_cfg(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1,
+                   (SW_CLK125_ENB | SW_CLK25_ENB), true);
+
+       return 0;
+}
+
+int lan937x_switch_init(struct ksz_device *dev)
+{
+       dev->port_mask = (1 << dev->info->port_cnt) - 1;
+
+       return 0;
+}
+
+void lan937x_switch_exit(struct ksz_device *dev)
+{
+       lan937x_reset_switch(dev);
+}
+
+MODULE_AUTHOR("Arun Ramadoss <arun.ramadoss@microchip.com>");
+MODULE_DESCRIPTION("Microchip LAN937x Series Switch DSA Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/lan937x_reg.h b/drivers/net/dsa/microchip/lan937x_reg.h
new file mode 100644 (file)
index 0000000..c187d0a
--- /dev/null
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Microchip LAN937X switch register definitions
+ * Copyright (C) 2019-2021 Microchip Technology Inc.
+ */
+#ifndef __LAN937X_REG_H
+#define __LAN937X_REG_H
+
+#define PORT_CTRL_ADDR(port, addr)     ((addr) | (((port) + 1)  << 12))
+
+/* 0 - Operation */
+#define REG_GLOBAL_CTRL_0              0x0007
+
+#define SW_PHY_REG_BLOCK               BIT(7)
+#define SW_FAST_MODE                   BIT(3)
+#define SW_FAST_MODE_OVERRIDE          BIT(2)
+
+#define REG_SW_INT_STATUS__4           0x0010
+#define REG_SW_INT_MASK__4             0x0014
+
+#define LUE_INT                                BIT(31)
+#define TRIG_TS_INT                    BIT(30)
+#define APB_TIMEOUT_INT                        BIT(29)
+#define OVER_TEMP_INT                  BIT(28)
+#define HSR_INT                                BIT(27)
+#define PIO_INT                                BIT(26)
+#define POR_READY_INT                  BIT(25)
+
+#define SWITCH_INT_MASK                        \
+       (LUE_INT | TRIG_TS_INT | APB_TIMEOUT_INT | OVER_TEMP_INT | HSR_INT | \
+        PIO_INT | POR_READY_INT)
+
+#define REG_SW_PORT_INT_STATUS__4      0x0018
+#define REG_SW_PORT_INT_MASK__4                0x001C
+
+/* 1 - Global */
+#define REG_SW_GLOBAL_OUTPUT_CTRL__1   0x0103
+#define SW_CLK125_ENB                  BIT(1)
+#define SW_CLK25_ENB                   BIT(0)
+
+/* 3 - Operation Control */
+#define REG_SW_OPERATION               0x0300
+
+#define SW_DOUBLE_TAG                  BIT(7)
+#define SW_OVER_TEMP_ENABLE            BIT(2)
+#define SW_RESET                       BIT(1)
+
+#define REG_SW_LUE_CTRL_0              0x0310
+
+#define SW_VLAN_ENABLE                 BIT(7)
+#define SW_DROP_INVALID_VID            BIT(6)
+#define SW_AGE_CNT_M                   0x7
+#define SW_AGE_CNT_S                   3
+#define SW_RESV_MCAST_ENABLE           BIT(2)
+
+#define REG_SW_LUE_CTRL_1              0x0311
+
+#define UNICAST_LEARN_DISABLE          BIT(7)
+#define SW_FLUSH_STP_TABLE             BIT(5)
+#define SW_FLUSH_MSTP_TABLE            BIT(4)
+#define SW_SRC_ADDR_FILTER             BIT(3)
+#define SW_AGING_ENABLE                        BIT(2)
+#define SW_FAST_AGING                  BIT(1)
+#define SW_LINK_AUTO_AGING             BIT(0)
+
+#define REG_SW_MAC_CTRL_0              0x0330
+#define SW_NEW_BACKOFF                 BIT(7)
+#define SW_PAUSE_UNH_MODE              BIT(1)
+#define SW_AGGR_BACKOFF                        BIT(0)
+
+#define REG_SW_MAC_CTRL_1              0x0331
+#define SW_SHORT_IFG                   BIT(7)
+#define MULTICAST_STORM_DISABLE                BIT(6)
+#define SW_BACK_PRESSURE               BIT(5)
+#define FAIR_FLOW_CTRL                 BIT(4)
+#define NO_EXC_COLLISION_DROP          BIT(3)
+#define SW_LEGAL_PACKET_DISABLE                BIT(1)
+#define SW_PASS_SHORT_FRAME            BIT(0)
+
+#define REG_SW_MAC_CTRL_6              0x0336
+#define SW_MIB_COUNTER_FLUSH           BIT(7)
+#define SW_MIB_COUNTER_FREEZE          BIT(6)
+
+/* 4 - LUE */
+#define REG_SW_ALU_STAT_CTRL__4                0x041C
+
+#define REG_SW_ALU_VAL_B               0x0424
+#define ALU_V_OVERRIDE                 BIT(31)
+#define ALU_V_USE_FID                  BIT(30)
+#define ALU_V_PORT_MAP                 0xFF
+
+/* 7 - VPhy */
+#define REG_VPHY_IND_ADDR__2           0x075C
+#define REG_VPHY_IND_DATA__2           0x0760
+
+#define REG_VPHY_IND_CTRL__2           0x0768
+
+#define VPHY_IND_WRITE                 BIT(1)
+#define VPHY_IND_BUSY                  BIT(0)
+
+#define REG_VPHY_SPECIAL_CTRL__2       0x077C
+#define VPHY_SMI_INDIRECT_ENABLE       BIT(15)
+#define VPHY_SW_LOOPBACK               BIT(14)
+#define VPHY_MDIO_INTERNAL_ENABLE      BIT(13)
+#define VPHY_SPI_INDIRECT_ENABLE       BIT(12)
+#define VPHY_PORT_MODE_M               0x3
+#define VPHY_PORT_MODE_S               8
+#define VPHY_MODE_RGMII                        0
+#define VPHY_MODE_MII_PHY              1
+#define VPHY_MODE_SGMII                        2
+#define VPHY_MODE_RMII_PHY             3
+#define VPHY_SW_COLLISION_TEST         BIT(7)
+#define VPHY_SPEED_DUPLEX_STAT_M       0x7
+#define VPHY_SPEED_DUPLEX_STAT_S       2
+#define VPHY_SPEED_1000                        BIT(4)
+#define VPHY_SPEED_100                 BIT(3)
+#define VPHY_FULL_DUPLEX               BIT(2)
+
+/* Port Registers */
+
+/* 0 - Operation */
+#define REG_PORT_CTRL_0                        0x0020
+
+#define PORT_MAC_LOOPBACK              BIT(7)
+#define PORT_MAC_REMOTE_LOOPBACK       BIT(6)
+#define PORT_K2L_INSERT_ENABLE         BIT(5)
+#define PORT_K2L_DEBUG_ENABLE          BIT(4)
+#define PORT_TAIL_TAG_ENABLE           BIT(2)
+#define PORT_QUEUE_SPLIT_ENABLE                0x3
+
+/* 1 - Phy */
+#define REG_PORT_T1_PHY_CTRL_BASE      0x0100
+
+/* 3 - xMII */
+#define REG_PORT_XMII_CTRL_0           0x0300
+#define PORT_SGMII_SEL                 BIT(7)
+#define PORT_MII_FULL_DUPLEX           BIT(6)
+#define PORT_MII_TX_FLOW_CTRL          BIT(5)
+#define PORT_MII_100MBIT               BIT(4)
+#define PORT_MII_RX_FLOW_CTRL          BIT(3)
+#define PORT_GRXC_ENABLE               BIT(0)
+
+#define REG_PORT_XMII_CTRL_1           0x0301
+#define PORT_MII_NOT_1GBIT             BIT(6)
+#define PORT_MII_SEL_EDGE              BIT(5)
+#define PORT_RGMII_ID_IG_ENABLE                BIT(4)
+#define PORT_RGMII_ID_EG_ENABLE                BIT(3)
+#define PORT_MII_MAC_MODE              BIT(2)
+#define PORT_MII_SEL_M                 0x3
+#define PORT_RGMII_SEL                 0x0
+#define PORT_RMII_SEL                  0x1
+#define PORT_MII_SEL                   0x2
+
+/* 4 - MAC */
+#define REG_PORT_MAC_CTRL_0            0x0400
+#define PORT_CHECK_LENGTH              BIT(2)
+#define PORT_BROADCAST_STORM           BIT(1)
+#define PORT_JUMBO_PACKET              BIT(0)
+
+#define REG_PORT_MAC_CTRL_1            0x0401
+#define PORT_BACK_PRESSURE             BIT(3)
+#define PORT_PASS_ALL                  BIT(0)
+
+#define PORT_MAX_FR_SIZE               0x404
+#define FR_MIN_SIZE            1522
+
+/* 8 - Classification and Policing */
+#define REG_PORT_MRI_PRIO_CTRL         0x0801
+#define PORT_HIGHEST_PRIO              BIT(7)
+#define PORT_OR_PRIO                   BIT(6)
+#define PORT_MAC_PRIO_ENABLE           BIT(4)
+#define PORT_VLAN_PRIO_ENABLE          BIT(3)
+#define PORT_802_1P_PRIO_ENABLE                BIT(2)
+#define PORT_DIFFSERV_PRIO_ENABLE      BIT(1)
+#define PORT_ACL_PRIO_ENABLE           BIT(0)
+
+#define P_PRIO_CTRL                    REG_PORT_MRI_PRIO_CTRL
+
+#define LAN937X_TAG_LEN                        2
+
+#endif
index 2b02d82..8358079 100644 (file)
@@ -1038,6 +1038,7 @@ static int
 mt7530_port_enable(struct dsa_switch *ds, int port,
                   struct phy_device *phy)
 {
+       struct dsa_port *dp = dsa_to_port(ds, port);
        struct mt7530_priv *priv = ds->priv;
 
        mutex_lock(&priv->reg_mutex);
@@ -1046,7 +1047,11 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
         * restore the port matrix if the port is the member of a certain
         * bridge.
         */
-       priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT));
+       if (dsa_port_is_user(dp)) {
+               struct dsa_port *cpu_dp = dp->cpu_dp;
+
+               priv->ports[port].pm |= PCR_MATRIX(BIT(cpu_dp->index));
+       }
        priv->ports[port].enable = true;
        mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
                   priv->ports[port].pm);
@@ -1195,7 +1200,8 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
                        struct netlink_ext_ack *extack)
 {
        struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
-       u32 port_bitmap = BIT(MT7530_CPU_PORT);
+       struct dsa_port *cpu_dp = dp->cpu_dp;
+       u32 port_bitmap = BIT(cpu_dp->index);
        struct mt7530_priv *priv = ds->priv;
 
        mutex_lock(&priv->reg_mutex);
@@ -1272,9 +1278,12 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
         * the CPU port get out of VLAN filtering mode.
         */
        if (all_user_ports_removed) {
-               mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT),
+               struct dsa_port *dp = dsa_to_port(ds, port);
+               struct dsa_port *cpu_dp = dp->cpu_dp;
+
+               mt7530_write(priv, MT7530_PCR_P(cpu_dp->index),
                             PCR_MATRIX(dsa_user_ports(priv->ds)));
-               mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), PORT_SPEC_TAG
+               mt7530_write(priv, MT7530_PVC_P(cpu_dp->index), PORT_SPEC_TAG
                             | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
        }
 }
@@ -1312,6 +1321,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
                         struct dsa_bridge bridge)
 {
        struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
+       struct dsa_port *cpu_dp = dp->cpu_dp;
        struct mt7530_priv *priv = ds->priv;
 
        mutex_lock(&priv->reg_mutex);
@@ -1340,8 +1350,8 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
         */
        if (priv->ports[port].enable)
                mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
-                          PCR_MATRIX(BIT(MT7530_CPU_PORT)));
-       priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT));
+                          PCR_MATRIX(BIT(cpu_dp->index)));
+       priv->ports[port].pm = PCR_MATRIX(BIT(cpu_dp->index));
 
        /* When a port is removed from the bridge, the port would be set up
         * back to the default as is at initial boot which is a VLAN-unaware
@@ -1508,6 +1518,9 @@ static int
 mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
                           struct netlink_ext_ack *extack)
 {
+       struct dsa_port *dp = dsa_to_port(ds, port);
+       struct dsa_port *cpu_dp = dp->cpu_dp;
+
        if (vlan_filtering) {
                /* The port is being kept as VLAN-unaware port when bridge is
                 * set up with vlan_filtering not being set, Otherwise, the
@@ -1515,7 +1528,7 @@ mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering,
                 * for becoming a VLAN-aware port.
                 */
                mt7530_port_set_vlan_aware(ds, port);
-               mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT);
+               mt7530_port_set_vlan_aware(ds, cpu_dp->index);
        } else {
                mt7530_port_set_vlan_unaware(ds, port);
        }
@@ -1527,11 +1540,11 @@ static void
 mt7530_hw_vlan_add(struct mt7530_priv *priv,
                   struct mt7530_hw_vlan_entry *entry)
 {
+       struct dsa_port *dp = dsa_to_port(priv->ds, entry->port);
        u8 new_members;
        u32 val;
 
-       new_members = entry->old_members | BIT(entry->port) |
-                     BIT(MT7530_CPU_PORT);
+       new_members = entry->old_members | BIT(entry->port);
 
        /* Validate the entry with independent learning, create egress tag per
         * VLAN and joining the port as one of the port members.
@@ -1542,22 +1555,20 @@ mt7530_hw_vlan_add(struct mt7530_priv *priv,
 
        /* Decide whether adding tag or not for those outgoing packets from the
         * port inside the VLAN.
-        */
-       val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG :
-                               MT7530_VLAN_EGRESS_TAG;
-       mt7530_rmw(priv, MT7530_VAWD2,
-                  ETAG_CTRL_P_MASK(entry->port),
-                  ETAG_CTRL_P(entry->port, val));
-
-       /* CPU port is always taken as a tagged port for serving more than one
+        * CPU port is always taken as a tagged port for serving more than one
         * VLANs across and also being applied with egress type stack mode for
         * that VLAN tags would be appended after hardware special tag used as
         * DSA tag.
         */
+       if (dsa_port_is_cpu(dp))
+               val = MT7530_VLAN_EGRESS_STACK;
+       else if (entry->untagged)
+               val = MT7530_VLAN_EGRESS_UNTAG;
+       else
+               val = MT7530_VLAN_EGRESS_TAG;
        mt7530_rmw(priv, MT7530_VAWD2,
-                  ETAG_CTRL_P_MASK(MT7530_CPU_PORT),
-                  ETAG_CTRL_P(MT7530_CPU_PORT,
-                              MT7530_VLAN_EGRESS_STACK));
+                  ETAG_CTRL_P_MASK(entry->port),
+                  ETAG_CTRL_P(entry->port, val));
 }
 
 static void
@@ -1576,11 +1587,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *priv,
                return;
        }
 
-       /* If certain member apart from CPU port is still alive in the VLAN,
-        * the entry would be kept valid. Otherwise, the entry is got to be
-        * disabled.
-        */
-       if (new_members && new_members != BIT(MT7530_CPU_PORT)) {
+       if (new_members) {
                val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) |
                      VLAN_VALID;
                mt7530_write(priv, MT7530_VAWD1, val);
@@ -2098,11 +2105,12 @@ static int
 mt7530_setup(struct dsa_switch *ds)
 {
        struct mt7530_priv *priv = ds->priv;
+       struct device_node *dn = NULL;
        struct device_node *phy_node;
        struct device_node *mac_np;
        struct mt7530_dummy_poll p;
        phy_interface_t interface;
-       struct device_node *dn;
+       struct dsa_port *cpu_dp;
        u32 id, val;
        int ret, i;
 
@@ -2110,7 +2118,19 @@ mt7530_setup(struct dsa_switch *ds)
         * controller also is the container for two GMACs nodes representing
         * as two netdev instances.
         */
-       dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent;
+       dsa_switch_for_each_cpu_port(cpu_dp, ds) {
+               dn = cpu_dp->master->dev.of_node->parent;
+               /* It doesn't matter which CPU port is found first,
+                * their masters should share the same parent OF node
+                */
+               break;
+       }
+
+       if (!dn) {
+               dev_err(ds->dev, "parent OF node of DSA master not found");
+               return -EINVAL;
+       }
+
        ds->assisted_learning_on_cpu_port = true;
        ds->mtu_enforcement_ingress = true;
 
@@ -2272,6 +2292,7 @@ mt7531_setup(struct dsa_switch *ds)
 {
        struct mt7530_priv *priv = ds->priv;
        struct mt7530_dummy_poll p;
+       struct dsa_port *cpu_dp;
        u32 val, id;
        int ret, i;
 
@@ -2344,8 +2365,11 @@ mt7531_setup(struct dsa_switch *ds)
                                 CORE_PLL_GROUP4, val);
 
        /* BPDU to CPU port */
-       mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
-                  BIT(MT7530_CPU_PORT));
+       dsa_switch_for_each_cpu_port(cpu_dp, ds) {
+               mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
+                          BIT(cpu_dp->index));
+               break;
+       }
        mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
                   MT753X_BPDU_CPU_ONLY);
 
index 71e36b6..e509af9 100644 (file)
@@ -8,7 +8,6 @@
 
 #define MT7530_NUM_PORTS               7
 #define MT7530_NUM_PHYS                        5
-#define MT7530_CPU_PORT                        6
 #define MT7530_NUM_FDB_RECORDS         2048
 #define MT7530_ALL_MEMBERS             0xff
 
index 0b49d24..37b6495 100644 (file)
@@ -449,9 +449,6 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
                        goto restore_link;
        }
 
-       if (speed == SPEED_MAX && chip->info->ops->port_max_speed_mode)
-               mode = chip->info->ops->port_max_speed_mode(port);
-
        if (chip->info->ops->port_set_pause) {
                err = chip->info->ops->port_set_pause(chip, port, pause);
                if (err)
@@ -3280,28 +3277,51 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
 {
        struct device_node *phy_handle = NULL;
        struct dsa_switch *ds = chip->ds;
+       phy_interface_t mode;
        struct dsa_port *dp;
-       int tx_amp;
+       int tx_amp, speed;
        int err;
        u16 reg;
 
        chip->ports[port].chip = chip;
        chip->ports[port].port = port;
 
+       dp = dsa_to_port(ds, port);
+
        /* MAC Forcing register: don't force link, speed, duplex or flow control
         * state to any particular values on physical ports, but force the CPU
         * port and all DSA ports to their maximum bandwidth and full duplex.
         */
-       if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
+       if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
+               unsigned long caps = dp->pl_config.mac_capabilities;
+
+               if (chip->info->ops->port_max_speed_mode)
+                       mode = chip->info->ops->port_max_speed_mode(port);
+               else
+                       mode = PHY_INTERFACE_MODE_NA;
+
+               if (caps & MAC_10000FD)
+                       speed = SPEED_10000;
+               else if (caps & MAC_5000FD)
+                       speed = SPEED_5000;
+               else if (caps & MAC_2500FD)
+                       speed = SPEED_2500;
+               else if (caps & MAC_1000)
+                       speed = SPEED_1000;
+               else if (caps & MAC_100)
+                       speed = SPEED_100;
+               else
+                       speed = SPEED_10;
+
                err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
-                                              SPEED_MAX, DUPLEX_FULL,
-                                              PAUSE_OFF,
-                                              PHY_INTERFACE_MODE_NA);
-       else
+                                              speed, DUPLEX_FULL,
+                                              PAUSE_OFF, mode);
+       } else {
                err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
                                               SPEED_UNFORCED, DUPLEX_UNFORCED,
                                               PAUSE_ON,
                                               PHY_INTERFACE_MODE_NA);
+       }
        if (err)
                return err;
 
@@ -3473,7 +3493,6 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
        }
 
        if (chip->info->ops->serdes_set_tx_amplitude) {
-               dp = dsa_to_port(ds, port);
                if (dp)
                        phy_handle = of_parse_phandle(dp->dn, "phy-handle", 0);
 
index 5e03cfe..e693154 100644 (file)
@@ -488,14 +488,13 @@ struct mv88e6xxx_ops {
        int (*port_set_pause)(struct mv88e6xxx_chip *chip, int port,
                              int pause);
 
-#define SPEED_MAX              INT_MAX
 #define SPEED_UNFORCED         -2
 #define DUPLEX_UNFORCED                -2
 
        /* Port's MAC speed (in Mbps) and MAC duplex mode
         *
         * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid.
-        * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value.
+        * Use SPEED_UNFORCED for normal detection.
         *
         * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex,
         * or DUPLEX_UNFORCED for normal duplex detection.
index 795b312..90c55f2 100644 (file)
@@ -294,28 +294,10 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip,
        return 0;
 }
 
-/* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */
-int mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
-                                   int speed, int duplex)
-{
-       if (speed == SPEED_MAX)
-               speed = 200;
-
-       if (speed > 200)
-               return -EOPNOTSUPP;
-
-       /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */
-       return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false,
-                                              duplex);
-}
-
 /* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */
 int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                    int speed, int duplex)
 {
-       if (speed == SPEED_MAX)
-               speed = 1000;
-
        if (speed == 200 || speed > 1000)
                return -EOPNOTSUPP;
 
@@ -327,9 +309,6 @@ int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                    int speed, int duplex)
 {
-       if (speed == SPEED_MAX)
-               speed = 100;
-
        if (speed > 100)
                return -EOPNOTSUPP;
 
@@ -341,9 +320,6 @@ int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                    int speed, int duplex)
 {
-       if (speed == SPEED_MAX)
-               speed = port < 5 ? 1000 : 2500;
-
        if (speed > 2500)
                return -EOPNOTSUPP;
 
@@ -369,9 +345,6 @@ phy_interface_t mv88e6341_port_max_speed_mode(int port)
 int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                    int speed, int duplex)
 {
-       if (speed == SPEED_MAX)
-               speed = 1000;
-
        if (speed > 1000)
                return -EOPNOTSUPP;
 
@@ -386,9 +359,6 @@ int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                    int speed, int duplex)
 {
-       if (speed == SPEED_MAX)
-               speed = port < 9 ? 1000 : 2500;
-
        if (speed > 2500)
                return -EOPNOTSUPP;
 
@@ -414,9 +384,6 @@ phy_interface_t mv88e6390_port_max_speed_mode(int port)
 int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                     int speed, int duplex)
 {
-       if (speed == SPEED_MAX)
-               speed = port < 9 ? 1000 : 10000;
-
        if (speed == 200 && port != 0)
                return -EOPNOTSUPP;
 
@@ -445,9 +412,6 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
        u16 reg, ctrl;
        int err;
 
-       if (speed == SPEED_MAX)
-               speed = (port > 0 && port < 9) ? 1000 : 10000;
-
        if (speed == 200 && port != 0)
                return -EOPNOTSUPP;
 
index e0a705d..cb04243 100644 (file)
@@ -342,8 +342,6 @@ int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link);
 int mv88e6xxx_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup);
 int mv88e6185_port_sync_link(struct mv88e6xxx_chip *chip, int port, unsigned int mode, bool isup);
 
-int mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
-                                   int speed, int duplex);
 int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
                                    int speed, int duplex);
 int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
index 220b0b0..08db9cf 100644 (file)
@@ -6,6 +6,7 @@ config NET_DSA_MSCC_FELIX
        depends on NET_VENDOR_FREESCALE
        depends on HAS_IOMEM
        depends on PTP_1588_CLOCK_OPTIONAL
+       depends on NET_SCH_TAPRIO || NET_SCH_TAPRIO=n
        select MSCC_OCELOT_SWITCH_LIB
        select NET_DSA_TAG_OCELOT_8021Q
        select NET_DSA_TAG_OCELOT
index 3e07dc3..8591968 100644 (file)
@@ -1553,9 +1553,18 @@ static void felix_txtstamp(struct dsa_switch *ds, int port,
 static int felix_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
 {
        struct ocelot *ocelot = ds->priv;
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       struct felix *felix = ocelot_to_felix(ocelot);
 
        ocelot_port_set_maxlen(ocelot, port, new_mtu);
 
+       mutex_lock(&ocelot->tas_lock);
+
+       if (ocelot_port->taprio && felix->info->tas_guard_bands_update)
+               felix->info->tas_guard_bands_update(ocelot, port);
+
+       mutex_unlock(&ocelot->tas_lock);
+
        return 0;
 }
 
index 9e07eb7..deb8dde 100644 (file)
@@ -53,6 +53,7 @@ struct felix_info {
                                    struct phylink_link_state *state);
        int     (*port_setup_tc)(struct dsa_switch *ds, int port,
                                 enum tc_setup_type type, void *type_data);
+       void    (*tas_guard_bands_update)(struct ocelot *ocelot, int port);
        void    (*port_sched_speed_set)(struct ocelot *ocelot, int port,
                                        u32 speed);
        struct regmap *(*init_regmap)(struct ocelot *ocelot,
index 9c27b9b..61ed317 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/iopoll.h>
 #include <linux/mdio.h>
 #include <linux/pci.h>
+#include <linux/time.h>
 #include "felix.h"
 
 #define VSC9959_NUM_PORTS              6
@@ -1127,9 +1128,199 @@ static void vsc9959_mdio_bus_free(struct ocelot *ocelot)
        mdiobus_free(felix->imdio);
 }
 
+/* Extract shortest continuous gate open intervals in ns for each traffic class
+ * of a cyclic tc-taprio schedule. If a gate is always open, the duration is
+ * considered U64_MAX. If the gate is always closed, it is considered 0.
+ */
+static void vsc9959_tas_min_gate_lengths(struct tc_taprio_qopt_offload *taprio,
+                                        u64 min_gate_len[OCELOT_NUM_TC])
+{
+       struct tc_taprio_sched_entry *entry;
+       u64 gate_len[OCELOT_NUM_TC];
+       int tc, i, n;
+
+       /* Initialize arrays */
+       for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
+               min_gate_len[tc] = U64_MAX;
+               gate_len[tc] = 0;
+       }
+
+       /* If we don't have taprio, consider all gates as permanently open */
+       if (!taprio)
+               return;
+
+       n = taprio->num_entries;
+
+       /* Walk through the gate list twice to determine the length
+        * of consecutively open gates for a traffic class, including
+        * open gates that wrap around. We are just interested in the
+        * minimum window size, and this doesn't change what the
+        * minimum is (if the gate never closes, min_gate_len will
+        * remain U64_MAX).
+        */
+       for (i = 0; i < 2 * n; i++) {
+               entry = &taprio->entries[i % n];
+
+               for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
+                       if (entry->gate_mask & BIT(tc)) {
+                               gate_len[tc] += entry->interval;
+                       } else {
+                               /* Gate closes now, record a potential new
+                                * minimum and reinitialize length
+                                */
+                               if (min_gate_len[tc] > gate_len[tc])
+                                       min_gate_len[tc] = gate_len[tc];
+                               gate_len[tc] = 0;
+                       }
+               }
+       }
+}
+
+/* Update QSYS_PORT_MAX_SDU to make sure the static guard bands added by the
+ * switch (see the ALWAYS_GUARD_BAND_SCH_Q comment) are correct at all MTU
+ * values (the default value is 1518). Also, for traffic class windows smaller
+ * than one MTU sized frame, update QSYS_QMAXSDU_CFG to enable oversized frame
+ * dropping, such that these won't hang the port, as they will never be sent.
+ */
+static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
+{
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
+       u64 min_gate_len[OCELOT_NUM_TC];
+       int speed, picos_per_byte;
+       u64 needed_bit_time_ps;
+       u32 val, maxlen;
+       u8 tas_speed;
+       int tc;
+
+       lockdep_assert_held(&ocelot->tas_lock);
+
+       val = ocelot_read_rix(ocelot, QSYS_TAG_CONFIG, port);
+       tas_speed = QSYS_TAG_CONFIG_LINK_SPEED_X(val);
+
+       switch (tas_speed) {
+       case OCELOT_SPEED_10:
+               speed = SPEED_10;
+               break;
+       case OCELOT_SPEED_100:
+               speed = SPEED_100;
+               break;
+       case OCELOT_SPEED_1000:
+               speed = SPEED_1000;
+               break;
+       case OCELOT_SPEED_2500:
+               speed = SPEED_2500;
+               break;
+       default:
+               return;
+       }
+
+       picos_per_byte = (USEC_PER_SEC * 8) / speed;
+
+       val = ocelot_port_readl(ocelot_port, DEV_MAC_MAXLEN_CFG);
+       /* MAXLEN_CFG accounts automatically for VLAN. We need to include it
+        * manually in the bit time calculation, plus the preamble and SFD.
+        */
+       maxlen = val + 2 * VLAN_HLEN;
+       /* Consider the standard Ethernet overhead of 8 octets preamble+SFD,
+        * 4 octets FCS, 12 octets IFG.
+        */
+       needed_bit_time_ps = (maxlen + 24) * picos_per_byte;
+
+       dev_dbg(ocelot->dev,
+               "port %d: max frame size %d needs %llu ps at speed %d\n",
+               port, maxlen, needed_bit_time_ps, speed);
+
+       vsc9959_tas_min_gate_lengths(ocelot_port->taprio, min_gate_len);
+
+       for (tc = 0; tc < OCELOT_NUM_TC; tc++) {
+               u32 max_sdu;
+
+               if (min_gate_len[tc] == U64_MAX /* Gate always open */ ||
+                   min_gate_len[tc] * PSEC_PER_NSEC > needed_bit_time_ps) {
+                       /* Setting QMAXSDU_CFG to 0 disables oversized frame
+                        * dropping.
+                        */
+                       max_sdu = 0;
+                       dev_dbg(ocelot->dev,
+                               "port %d tc %d min gate len %llu"
+                               ", sending all frames\n",
+                               port, tc, min_gate_len[tc]);
+               } else {
+                       /* If traffic class doesn't support a full MTU sized
+                        * frame, make sure to enable oversize frame dropping
+                        * for frames larger than the smallest that would fit.
+                        */
+                       max_sdu = div_u64(min_gate_len[tc] * PSEC_PER_NSEC,
+                                         picos_per_byte);
+                       /* A TC gate may be completely closed, which is a
+                        * special case where all packets are oversized.
+                        * Any limit smaller than 64 octets accomplishes this
+                        */
+                       if (!max_sdu)
+                               max_sdu = 1;
+                       /* Take L1 overhead into account, but just don't allow
+                        * max_sdu to go negative or to 0. Here we use 20
+                        * because QSYS_MAXSDU_CFG_* already counts the 4 FCS
+                        * octets as part of packet size.
+                        */
+                       if (max_sdu > 20)
+                               max_sdu -= 20;
+                       dev_info(ocelot->dev,
+                                "port %d tc %d min gate length %llu"
+                                " ns not enough for max frame size %d at %d"
+                                " Mbps, dropping frames over %d"
+                                " octets including FCS\n",
+                                port, tc, min_gate_len[tc], maxlen, speed,
+                                max_sdu);
+               }
+
+               /* ocelot_write_rix is a macro that concatenates
+                * QSYS_MAXSDU_CFG_* with _RSZ, so we need to spell out
+                * the writes to each traffic class
+                */
+               switch (tc) {
+               case 0:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_0,
+                                        port);
+                       break;
+               case 1:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_1,
+                                        port);
+                       break;
+               case 2:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_2,
+                                        port);
+                       break;
+               case 3:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_3,
+                                        port);
+                       break;
+               case 4:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_4,
+                                        port);
+                       break;
+               case 5:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_5,
+                                        port);
+                       break;
+               case 6:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_6,
+                                        port);
+                       break;
+               case 7:
+                       ocelot_write_rix(ocelot, max_sdu, QSYS_QMAXSDU_CFG_7,
+                                        port);
+                       break;
+               }
+       }
+
+       ocelot_write_rix(ocelot, maxlen, QSYS_PORT_MAX_SDU, port);
+}
+
 static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
                                    u32 speed)
 {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
        u8 tas_speed;
 
        switch (speed) {
@@ -1154,6 +1345,13 @@ static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
                       QSYS_TAG_CONFIG_LINK_SPEED(tas_speed),
                       QSYS_TAG_CONFIG_LINK_SPEED_M,
                       QSYS_TAG_CONFIG, port);
+
+       mutex_lock(&ocelot->tas_lock);
+
+       if (ocelot_port->taprio)
+               vsc9959_tas_guard_bands_update(ocelot, port);
+
+       mutex_unlock(&ocelot->tas_lock);
 }
 
 static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
@@ -1196,26 +1394,36 @@ static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix,
 static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port,
                                    struct tc_taprio_qopt_offload *taprio)
 {
+       struct ocelot_port *ocelot_port = ocelot->ports[port];
        struct timespec64 base_ts;
        int ret, i;
        u32 val;
 
+       mutex_lock(&ocelot->tas_lock);
+
        if (!taprio->enable) {
-               ocelot_rmw_rix(ocelot,
-                              QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF),
-                              QSYS_TAG_CONFIG_ENABLE |
-                              QSYS_TAG_CONFIG_INIT_GATE_STATE_M,
+               ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
                               QSYS_TAG_CONFIG, port);
 
+               taprio_offload_free(ocelot_port->taprio);
+               ocelot_port->taprio = NULL;
+
+               vsc9959_tas_guard_bands_update(ocelot, port);
+
+               mutex_unlock(&ocelot->tas_lock);
                return 0;
        }
 
        if (taprio->cycle_time > NSEC_PER_SEC ||
-           taprio->cycle_time_extension >= NSEC_PER_SEC)
-               return -EINVAL;
+           taprio->cycle_time_extension >= NSEC_PER_SEC) {
+               ret = -EINVAL;
+               goto err;
+       }
 
-       if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX)
-               return -ERANGE;
+       if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX) {
+               ret = -ERANGE;
+               goto err;
+       }
 
        /* Enable guard band. The switch will schedule frames without taking
         * their length into account. Thus we'll always need to enable the
@@ -1236,8 +1444,10 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port,
         * config is pending, need reset the TAS module
         */
        val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
-       if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING)
-               return  -EBUSY;
+       if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING) {
+               ret = -EBUSY;
+               goto err;
+       }
 
        ocelot_rmw_rix(ocelot,
                       QSYS_TAG_CONFIG_ENABLE |
@@ -1270,10 +1480,67 @@ static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port,
        ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val,
                                 !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE),
                                 10, 100000);
+       if (ret)
+               goto err;
+
+       ocelot_port->taprio = taprio_offload_get(taprio);
+       vsc9959_tas_guard_bands_update(ocelot, port);
+
+err:
+       mutex_unlock(&ocelot->tas_lock);
 
        return ret;
 }
 
+static void vsc9959_tas_clock_adjust(struct ocelot *ocelot)
+{
+       struct tc_taprio_qopt_offload *taprio;
+       struct ocelot_port *ocelot_port;
+       struct timespec64 base_ts;
+       int port;
+       u32 val;
+
+       mutex_lock(&ocelot->tas_lock);
+
+       for (port = 0; port < ocelot->num_phys_ports; port++) {
+               ocelot_port = ocelot->ports[port];
+               taprio = ocelot_port->taprio;
+               if (!taprio)
+                       continue;
+
+               ocelot_rmw(ocelot,
+                          QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port),
+                          QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
+                          QSYS_TAS_PARAM_CFG_CTRL);
+
+               /* Disable time-aware shaper */
+               ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
+                              QSYS_TAG_CONFIG, port);
+
+               vsc9959_new_base_time(ocelot, taprio->base_time,
+                                     taprio->cycle_time, &base_ts);
+
+               ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1);
+               ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec),
+                            QSYS_PARAM_CFG_REG_2);
+               val = upper_32_bits(base_ts.tv_sec);
+               ocelot_rmw(ocelot,
+                          QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val),
+                          QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M,
+                          QSYS_PARAM_CFG_REG_3);
+
+               ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
+                          QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
+                          QSYS_TAS_PARAM_CFG_CTRL);
+
+               /* Re-enable time-aware shaper */
+               ocelot_rmw_rix(ocelot, QSYS_TAG_CONFIG_ENABLE,
+                              QSYS_TAG_CONFIG_ENABLE,
+                              QSYS_TAG_CONFIG, port);
+       }
+       mutex_unlock(&ocelot->tas_lock);
+}
+
 static int vsc9959_qos_port_cbs_set(struct dsa_switch *ds, int port,
                                    struct tc_cbs_qopt_offload *cbs_qopt)
 {
@@ -2214,6 +2481,7 @@ static const struct ocelot_ops vsc9959_ops = {
        .psfp_filter_del        = vsc9959_psfp_filter_del,
        .psfp_stats_get         = vsc9959_psfp_stats_get,
        .cut_through_fwd        = vsc9959_cut_through_fwd,
+       .tas_clock_adjust       = vsc9959_tas_clock_adjust,
 };
 
 static const struct felix_info felix_info_vsc9959 = {
@@ -2240,6 +2508,7 @@ static const struct felix_info felix_info_vsc9959 = {
        .port_modes             = vsc9959_port_modes,
        .port_setup_tc          = vsc9959_port_setup_tc,
        .port_sched_speed_set   = vsc9959_sched_speed_set,
+       .tas_guard_bands_update = vsc9959_tas_guard_bands_update,
        .init_regmap            = ocelot_regmap_init,
 };
 
index e5098cf..0796b7c 100644 (file)
@@ -231,6 +231,7 @@ struct ar9331_sw_port {
        int idx;
        struct delayed_work mib_read;
        struct rtnl_link_stats64 stats;
+       struct ethtool_pause_stats pause_stats;
        struct spinlock stats_lock;
 };
 
@@ -604,6 +605,7 @@ static void ar9331_sw_phylink_mac_link_up(struct dsa_switch *ds, int port,
 static void ar9331_read_stats(struct ar9331_sw_port *port)
 {
        struct ar9331_sw_priv *priv = ar9331_sw_port_to_priv(port);
+       struct ethtool_pause_stats *pstats = &port->pause_stats;
        struct rtnl_link_stats64 *stats = &port->stats;
        struct ar9331_sw_stats_raw raw;
        int ret;
@@ -644,6 +646,9 @@ static void ar9331_read_stats(struct ar9331_sw_port *port)
        stats->multicast += raw.rxmulti;
        stats->collisions += raw.txcollision;
 
+       pstats->tx_pause_frames += raw.txpause;
+       pstats->rx_pause_frames += raw.rxpause;
+
        spin_unlock(&port->stats_lock);
 }
 
@@ -668,6 +673,17 @@ static void ar9331_get_stats64(struct dsa_switch *ds, int port,
        spin_unlock(&p->stats_lock);
 }
 
+static void ar9331_get_pause_stats(struct dsa_switch *ds, int port,
+                                  struct ethtool_pause_stats *pause_stats)
+{
+       struct ar9331_sw_priv *priv = (struct ar9331_sw_priv *)ds->priv;
+       struct ar9331_sw_port *p = &priv->port[port];
+
+       spin_lock(&p->stats_lock);
+       memcpy(pause_stats, &p->pause_stats, sizeof(*pause_stats));
+       spin_unlock(&p->stats_lock);
+}
+
 static const struct dsa_switch_ops ar9331_sw_ops = {
        .get_tag_protocol       = ar9331_sw_get_tag_protocol,
        .setup                  = ar9331_sw_setup,
@@ -677,6 +693,7 @@ static const struct dsa_switch_ops ar9331_sw_ops = {
        .phylink_mac_link_down  = ar9331_sw_phylink_mac_link_down,
        .phylink_mac_link_up    = ar9331_sw_phylink_mac_link_up,
        .get_stats64            = ar9331_get_stats64,
+       .get_pause_stats        = ar9331_get_pause_stats,
 };
 
 static irqreturn_t ar9331_sw_irq(int irq, void *data)
@@ -818,7 +835,7 @@ static int __ar9331_mdio_write(struct mii_bus *sbus, u8 mode, u16 reg, u16 val)
                FIELD_GET(AR9331_SW_LOW_ADDR_PHY, reg);
        r = FIELD_GET(AR9331_SW_LOW_ADDR_REG, reg);
 
-       return mdiobus_write(sbus, p, r, val);
+       return __mdiobus_write(sbus, p, r, val);
 }
 
 static int __ar9331_mdio_read(struct mii_bus *sbus, u16 reg)
@@ -829,7 +846,7 @@ static int __ar9331_mdio_read(struct mii_bus *sbus, u16 reg)
                FIELD_GET(AR9331_SW_LOW_ADDR_PHY, reg);
        r = FIELD_GET(AR9331_SW_LOW_ADDR_REG, reg);
 
-       return mdiobus_read(sbus, p, r);
+       return __mdiobus_read(sbus, p, r);
 }
 
 static int ar9331_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
@@ -849,6 +866,8 @@ static int ar9331_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
                return 0;
        }
 
+       mutex_lock_nested(&sbus->mdio_lock, MDIO_MUTEX_NESTED);
+
        ret = __ar9331_mdio_read(sbus, reg);
        if (ret < 0)
                goto error;
@@ -860,9 +879,13 @@ static int ar9331_mdio_read(void *ctx, const void *reg_buf, size_t reg_len,
 
        *(u32 *)val_buf |= ret << 16;
 
+       mutex_unlock(&sbus->mdio_lock);
+
        return 0;
 error:
+       mutex_unlock(&sbus->mdio_lock);
        dev_err_ratelimited(&sbus->dev, "Bus error. Failed to read register.\n");
+
        return ret;
 }
 
@@ -872,12 +895,15 @@ static int ar9331_mdio_write(void *ctx, u32 reg, u32 val)
        struct mii_bus *sbus = priv->sbus;
        int ret;
 
+       mutex_lock_nested(&sbus->mdio_lock, MDIO_MUTEX_NESTED);
        if (reg == AR9331_SW_REG_PAGE) {
                ret = __ar9331_mdio_write(sbus, AR9331_SW_MDIO_PHY_MODE_PAGE,
                                          0, val);
                if (ret < 0)
                        goto error;
 
+               mutex_unlock(&sbus->mdio_lock);
+
                return 0;
        }
 
@@ -897,10 +923,14 @@ static int ar9331_mdio_write(void *ctx, u32 reg, u32 val)
        if (ret < 0)
                goto error;
 
+       mutex_unlock(&sbus->mdio_lock);
+
        return 0;
 
 error:
+       mutex_unlock(&sbus->mdio_lock);
        dev_err_ratelimited(&sbus->dev, "Bus error. Failed to write register.\n");
+
        return ret;
 }
 
index 769f672..da31d8b 100644 (file)
 
 #include "realtek.h"
 
-/* Chip-specific data and limits */
-#define RTL8365MB_CHIP_ID_8365MB_VC    0x6367
-#define RTL8365MB_CHIP_VER_8365MB_VC   0x0040
-
-#define RTL8365MB_CHIP_ID_8367S                0x6367
-#define RTL8365MB_CHIP_VER_8367S       0x00A0
-
-#define RTL8365MB_CHIP_ID_8367RB       0x6367
-#define RTL8365MB_CHIP_VER_8367RB      0x0020
-
 /* Family-specific data and limits */
 #define RTL8365MB_PHYADDRMAX           7
 #define RTL8365MB_NUM_PHYREGS          32
 #define RTL8365MB_PHYREGMAX            (RTL8365MB_NUM_PHYREGS - 1)
-/* RTL8370MB and RTL8310SR, possibly suportable by this driver, have 10 ports */
-#define RTL8365MB_MAX_NUM_PORTS                10
+#define RTL8365MB_MAX_NUM_PORTS                11
+#define RTL8365MB_MAX_NUM_EXTINTS      3
 #define RTL8365MB_LEARN_LIMIT_MAX      2112
 
-/* valid for all 6-port or less variants */
-static const int rtl8365mb_extint_port_map[]  = { -1, -1, -1, -1, -1, -1, 1, 2, -1, -1};
-
 /* Chip identification registers */
 #define RTL8365MB_CHIP_ID_REG          0x1300
 
@@ -201,7 +188,7 @@ static const int rtl8365mb_extint_port_map[]  = { -1, -1, -1, -1, -1, -1, 1, 2,
 /* The PHY OCP addresses of PHY registers 0~31 start here */
 #define RTL8365MB_PHY_OCP_ADDR_PHYREG_BASE             0xA400
 
-/* EXT interface port mode values - used in DIGITAL_INTERFACE_SELECT */
+/* External interface port mode values - used in DIGITAL_INTERFACE_SELECT */
 #define RTL8365MB_EXT_PORT_MODE_DISABLE                0
 #define RTL8365MB_EXT_PORT_MODE_RGMII          1
 #define RTL8365MB_EXT_PORT_MODE_MII_MAC                2
@@ -217,19 +204,7 @@ static const int rtl8365mb_extint_port_map[]  = { -1, -1, -1, -1, -1, -1, 1, 2,
 #define RTL8365MB_EXT_PORT_MODE_1000X          12
 #define RTL8365MB_EXT_PORT_MODE_100FX          13
 
-/* Realtek docs and driver uses logic number as EXT_PORT0=16, EXT_PORT1=17,
- * EXT_PORT2=18, to interact with switch ports. That logic number is internally
- * converted to either a physical port number (0..9) or an external interface id (0..2),
- * depending on which function was called. The external interface id is calculated as
- * (ext_id=logic_port-15), while the logical to physical map depends on the chip id/version.
- *
- * EXT_PORT0 mentioned in datasheets and rtl8367c driver is used in this driver
- * as extid==1, EXT_PORT2, mentioned in Realtek rtl8367c driver for 10-port switches,
- * would have an ext_id of 3 (out of range for most extint macros) and ext_id 0 does
- * not seem to be used as well for this family.
- */
-
-/* EXT interface mode configuration registers 0~1 */
+/* External interface mode configuration registers 0~1 */
 #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG0                0x1305 /* EXT1 */
 #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1                0x13C3 /* EXT2 */
 #define RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(_extint) \
@@ -241,7 +216,7 @@ static const int rtl8365mb_extint_port_map[]  = { -1, -1, -1, -1, -1, -1, 1, 2,
 #define   RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(_extint) \
                (((_extint) % 2) * 4)
 
-/* EXT interface RGMII TX/RX delay configuration registers 0~2 */
+/* External interface RGMII TX/RX delay configuration registers 0~2 */
 #define RTL8365MB_EXT_RGMXF_REG0               0x1306 /* EXT0 */
 #define RTL8365MB_EXT_RGMXF_REG1               0x1307 /* EXT1 */
 #define RTL8365MB_EXT_RGMXF_REG2               0x13C5 /* EXT2 */
@@ -258,7 +233,7 @@ static const int rtl8365mb_extint_port_map[]  = { -1, -1, -1, -1, -1, -1, 1, 2,
 #define RTL8365MB_PORT_SPEED_100M      1
 #define RTL8365MB_PORT_SPEED_1000M     2
 
-/* EXT interface force configuration registers 0~2 */
+/* External interface force configuration registers 0~2 */
 #define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG0         0x1310 /* EXT0 */
 #define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG1         0x1311 /* EXT1 */
 #define RTL8365MB_DIGITAL_INTERFACE_FORCE_REG2         0x13C4 /* EXT2 */
@@ -490,6 +465,95 @@ static const struct rtl8365mb_jam_tbl_entry rtl8365mb_init_jam_common[] = {
        { 0x1D32, 0x0002 },
 };
 
+enum rtl8365mb_phy_interface_mode {
+       RTL8365MB_PHY_INTERFACE_MODE_INVAL = 0,
+       RTL8365MB_PHY_INTERFACE_MODE_INTERNAL = BIT(0),
+       RTL8365MB_PHY_INTERFACE_MODE_MII = BIT(1),
+       RTL8365MB_PHY_INTERFACE_MODE_TMII = BIT(2),
+       RTL8365MB_PHY_INTERFACE_MODE_RMII = BIT(3),
+       RTL8365MB_PHY_INTERFACE_MODE_RGMII = BIT(4),
+       RTL8365MB_PHY_INTERFACE_MODE_SGMII = BIT(5),
+       RTL8365MB_PHY_INTERFACE_MODE_HSGMII = BIT(6),
+};
+
+/**
+ * struct rtl8365mb_extint - external interface info
+ * @port: the port with an external interface
+ * @id: the external interface ID, which is either 0, 1, or 2
+ * @supported_interfaces: a bitmask of supported PHY interface modes
+ *
+ * Represents a mapping: port -> { id, supported_interfaces }. To be embedded
+ * in &struct rtl8365mb_chip_info for every port with an external interface.
+ */
+struct rtl8365mb_extint {
+       int port;
+       int id;
+       unsigned int supported_interfaces;
+};
+
+/**
+ * struct rtl8365mb_chip_info - static chip-specific info
+ * @name: human-readable chip name
+ * @chip_id: chip identifier
+ * @chip_ver: chip silicon revision
+ * @extints: available external interfaces
+ * @jam_table: chip-specific initialization jam table
+ * @jam_size: size of the chip's jam table
+ *
+ * These data are specific to a given chip in the family of switches supported
+ * by this driver. When adding support for another chip in the family, a new
+ * chip info should be added to the rtl8365mb_chip_infos array.
+ */
+struct rtl8365mb_chip_info {
+       const char *name;
+       u32 chip_id;
+       u32 chip_ver;
+       const struct rtl8365mb_extint extints[RTL8365MB_MAX_NUM_EXTINTS];
+       const struct rtl8365mb_jam_tbl_entry *jam_table;
+       size_t jam_size;
+};
+
+/* Chip info for each supported switch in the family */
+#define PHY_INTF(_mode) (RTL8365MB_PHY_INTERFACE_MODE_ ## _mode)
+static const struct rtl8365mb_chip_info rtl8365mb_chip_infos[] = {
+       {
+               .name = "RTL8365MB-VC",
+               .chip_id = 0x6367,
+               .chip_ver = 0x0040,
+               .extints = {
+                       { 6, 1, PHY_INTF(MII) | PHY_INTF(TMII) |
+                               PHY_INTF(RMII) | PHY_INTF(RGMII) },
+               },
+               .jam_table = rtl8365mb_init_jam_8365mb_vc,
+               .jam_size = ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc),
+       },
+       {
+               .name = "RTL8367S",
+               .chip_id = 0x6367,
+               .chip_ver = 0x00A0,
+               .extints = {
+                       { 6, 1, PHY_INTF(SGMII) | PHY_INTF(HSGMII) },
+                       { 7, 2, PHY_INTF(MII) | PHY_INTF(TMII) |
+                               PHY_INTF(RMII) | PHY_INTF(RGMII) },
+               },
+               .jam_table = rtl8365mb_init_jam_8365mb_vc,
+               .jam_size = ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc),
+       },
+       {
+               .name = "RTL8367RB-VB",
+               .chip_id = 0x6367,
+               .chip_ver = 0x0020,
+               .extints = {
+                       { 6, 1, PHY_INTF(MII) | PHY_INTF(TMII) |
+                               PHY_INTF(RMII) | PHY_INTF(RGMII) },
+                       { 7, 2, PHY_INTF(MII) | PHY_INTF(TMII) |
+                               PHY_INTF(RMII) | PHY_INTF(RGMII) },
+               },
+               .jam_table = rtl8365mb_init_jam_8365mb_vc,
+               .jam_size = ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc),
+       },
+};
+
 enum rtl8365mb_stp_state {
        RTL8365MB_STP_STATE_DISABLED = 0,
        RTL8365MB_STP_STATE_BLOCKING = 1,
@@ -559,33 +623,23 @@ struct rtl8365mb_port {
 };
 
 /**
- * struct rtl8365mb - private chip-specific driver data
+ * struct rtl8365mb - driver private data
  * @priv: pointer to parent realtek_priv data
  * @irq: registered IRQ or zero
- * @chip_id: chip identifier
- * @chip_ver: chip silicon revision
- * @port_mask: mask of all ports
- * @learn_limit_max: maximum number of L2 addresses the chip can learn
+ * @chip_info: chip-specific info about the attached switch
  * @cpu: CPU tagging and CPU port configuration for this chip
  * @mib_lock: prevent concurrent reads of MIB counters
  * @ports: per-port data
- * @jam_table: chip-specific initialization jam table
- * @jam_size: size of the chip's jam table
  *
  * Private data for this driver.
  */
 struct rtl8365mb {
        struct realtek_priv *priv;
        int irq;
-       u32 chip_id;
-       u32 chip_ver;
-       u32 port_mask;
-       u32 learn_limit_max;
+       const struct rtl8365mb_chip_info *chip_info;
        struct rtl8365mb_cpu cpu;
        struct mutex mib_lock;
        struct rtl8365mb_port ports[RTL8365MB_MAX_NUM_PORTS];
-       const struct rtl8365mb_jam_tbl_entry *jam_table;
-       size_t jam_size;
 };
 
 static int rtl8365mb_phy_poll_busy(struct realtek_priv *priv)
@@ -780,6 +834,26 @@ static int rtl8365mb_dsa_phy_write(struct dsa_switch *ds, int phy, int regnum,
        return rtl8365mb_phy_write(ds->priv, phy, regnum, val);
 }
 
+static const struct rtl8365mb_extint *
+rtl8365mb_get_port_extint(struct realtek_priv *priv, int port)
+{
+       struct rtl8365mb *mb = priv->chip_data;
+       int i;
+
+       for (i = 0; i < RTL8365MB_MAX_NUM_EXTINTS; i++) {
+               const struct rtl8365mb_extint *extint =
+                       &mb->chip_info->extints[i];
+
+               if (!extint->supported_interfaces)
+                       continue;
+
+               if (extint->port == port)
+                       return extint;
+       }
+
+       return NULL;
+}
+
 static enum dsa_tag_protocol
 rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port,
                           enum dsa_tag_protocol mp)
@@ -800,20 +874,17 @@ rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port,
 static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
                                      phy_interface_t interface)
 {
+       const struct rtl8365mb_extint *extint =
+               rtl8365mb_get_port_extint(priv, port);
        struct device_node *dn;
        struct dsa_port *dp;
        int tx_delay = 0;
        int rx_delay = 0;
-       int ext_int;
        u32 val;
        int ret;
 
-       ext_int = rtl8365mb_extint_port_map[port];
-
-       if (ext_int <= 0) {
-               dev_err(priv->dev, "Port %d is not an external interface port\n", port);
-               return -EINVAL;
-       }
+       if (!extint)
+               return -ENODEV;
 
        dp = dsa_to_port(priv->ds, port);
        dn = dp->dn;
@@ -847,7 +918,7 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
                        tx_delay = val / 2;
                else
                        dev_warn(priv->dev,
-                                "EXT interface TX delay must be 0 or 2 ns\n");
+                                "RGMII TX delay must be 0 or 2 ns\n");
        }
 
        if (!of_property_read_u32(dn, "rx-internal-delay-ps", &val)) {
@@ -857,11 +928,11 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
                        rx_delay = val;
                else
                        dev_warn(priv->dev,
-                                "EXT interface RX delay must be 0 to 2.1 ns\n");
+                                "RGMII RX delay must be 0 to 2.1 ns\n");
        }
 
        ret = regmap_update_bits(
-               priv->map, RTL8365MB_EXT_RGMXF_REG(ext_int),
+               priv->map, RTL8365MB_EXT_RGMXF_REG(extint->id),
                RTL8365MB_EXT_RGMXF_TXDELAY_MASK |
                        RTL8365MB_EXT_RGMXF_RXDELAY_MASK,
                FIELD_PREP(RTL8365MB_EXT_RGMXF_TXDELAY_MASK, tx_delay) |
@@ -870,11 +941,11 @@ static int rtl8365mb_ext_config_rgmii(struct realtek_priv *priv, int port,
                return ret;
 
        ret = regmap_update_bits(
-               priv->map, RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(ext_int),
-               RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(ext_int),
+               priv->map, RTL8365MB_DIGITAL_INTERFACE_SELECT_REG(extint->id),
+               RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK(extint->id),
                RTL8365MB_EXT_PORT_MODE_RGMII
                        << RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET(
-                                  ext_int));
+                                  extint->id));
        if (ret)
                return ret;
 
@@ -885,21 +956,18 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
                                          bool link, int speed, int duplex,
                                          bool tx_pause, bool rx_pause)
 {
+       const struct rtl8365mb_extint *extint =
+               rtl8365mb_get_port_extint(priv, port);
        u32 r_tx_pause;
        u32 r_rx_pause;
        u32 r_duplex;
        u32 r_speed;
        u32 r_link;
-       int ext_int;
        int val;
        int ret;
 
-       ext_int = rtl8365mb_extint_port_map[port];
-
-       if (ext_int <= 0) {
-               dev_err(priv->dev, "Port %d is not an external interface port\n", port);
-               return -EINVAL;
-       }
+       if (!extint)
+               return -ENODEV;
 
        if (link) {
                /* Force the link up with the desired configuration */
@@ -947,7 +1015,7 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
                         r_duplex) |
              FIELD_PREP(RTL8365MB_DIGITAL_INTERFACE_FORCE_SPEED_MASK, r_speed);
        ret = regmap_write(priv->map,
-                          RTL8365MB_DIGITAL_INTERFACE_FORCE_REG(ext_int),
+                          RTL8365MB_DIGITAL_INTERFACE_FORCE_REG(extint->id),
                           val);
        if (ret)
                return ret;
@@ -958,7 +1026,13 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
 static void rtl8365mb_phylink_get_caps(struct dsa_switch *ds, int port,
                                       struct phylink_config *config)
 {
-       if (dsa_is_user_port(ds, port)) {
+       const struct rtl8365mb_extint *extint =
+               rtl8365mb_get_port_extint(ds->priv, port);
+
+       config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
+                                  MAC_10 | MAC_100 | MAC_1000FD;
+
+       if (!extint) {
                __set_bit(PHY_INTERFACE_MODE_INTERNAL,
                          config->supported_interfaces);
 
@@ -967,12 +1041,16 @@ static void rtl8365mb_phylink_get_caps(struct dsa_switch *ds, int port,
                 */
                __set_bit(PHY_INTERFACE_MODE_GMII,
                          config->supported_interfaces);
-       } else if (dsa_is_cpu_port(ds, port)) {
-               phy_interface_set_rgmii(config->supported_interfaces);
+               return;
        }
 
-       config->mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
-                                  MAC_10 | MAC_100 | MAC_1000FD;
+       /* Populate according to the modes supported by _this driver_,
+        * not necessarily the modes supported by the hardware, some of
+        * which remain unimplemented.
+        */
+
+       if (extint->supported_interfaces & RTL8365MB_PHY_INTERFACE_MODE_RGMII)
+               phy_interface_set_rgmii(config->supported_interfaces);
 }
 
 static void rtl8365mb_phylink_mac_config(struct dsa_switch *ds, int port,
@@ -1091,15 +1169,13 @@ static void rtl8365mb_port_stp_state_set(struct dsa_switch *ds, int port,
 static int rtl8365mb_port_set_learning(struct realtek_priv *priv, int port,
                                       bool enable)
 {
-       struct rtl8365mb *mb = priv->chip_data;
-
        /* Enable/disable learning by limiting the number of L2 addresses the
         * port can learn. Realtek documentation states that a limit of zero
         * disables learning. When enabling learning, set it to the chip's
         * maximum.
         */
        return regmap_write(priv->map, RTL8365MB_LUT_PORT_LEARN_LIMIT_REG(port),
-                           enable ? mb->learn_limit_max : 0);
+                           enable ? RTL8365MB_LEARN_LIMIT_MAX : 0);
 }
 
 static int rtl8365mb_port_set_isolation(struct realtek_priv *priv, int port,
@@ -1489,13 +1565,10 @@ static irqreturn_t rtl8365mb_irq(int irq, void *data)
 {
        struct realtek_priv *priv = data;
        unsigned long line_changes = 0;
-       struct rtl8365mb *mb;
        u32 stat;
        int line;
        int ret;
 
-       mb = priv->chip_data;
-
        ret = rtl8365mb_get_and_clear_status_reg(priv, RTL8365MB_INTR_STATUS_REG,
                                                 &stat);
        if (ret)
@@ -1520,7 +1593,7 @@ static irqreturn_t rtl8365mb_irq(int irq, void *data)
 
                linkdown_ind = FIELD_GET(RTL8365MB_PORT_LINKDOWN_IND_MASK, val);
 
-               line_changes = (linkup_ind | linkdown_ind) & mb->port_mask;
+               line_changes = linkup_ind | linkdown_ind;
        }
 
        if (!line_changes)
@@ -1792,14 +1865,17 @@ static int rtl8365mb_change_tag_protocol(struct dsa_switch *ds,
 static int rtl8365mb_switch_init(struct realtek_priv *priv)
 {
        struct rtl8365mb *mb = priv->chip_data;
+       const struct rtl8365mb_chip_info *ci;
        int ret;
        int i;
 
+       ci = mb->chip_info;
+
        /* Do any chip-specific init jam before getting to the common stuff */
-       if (mb->jam_table) {
-               for (i = 0; i < mb->jam_size; i++) {
-                       ret = regmap_write(priv->map, mb->jam_table[i].reg,
-                                          mb->jam_table[i].val);
+       if (ci->jam_table) {
+               for (i = 0; i < ci->jam_size; i++) {
+                       ret = regmap_write(priv->map, ci->jam_table[i].reg,
+                                          ci->jam_table[i].val);
                        if (ret)
                                return ret;
                }
@@ -1972,6 +2048,7 @@ static int rtl8365mb_detect(struct realtek_priv *priv)
        u32 chip_id;
        u32 chip_ver;
        int ret;
+       int i;
 
        ret = rtl8365mb_get_chip_id_and_ver(priv->map, &chip_id, &chip_ver);
        if (ret) {
@@ -1980,54 +2057,32 @@ static int rtl8365mb_detect(struct realtek_priv *priv)
                return ret;
        }
 
-       switch (chip_id) {
-       case RTL8365MB_CHIP_ID_8365MB_VC:
-               switch (chip_ver) {
-               case RTL8365MB_CHIP_VER_8365MB_VC:
-                       dev_info(priv->dev,
-                                "found an RTL8365MB-VC switch (ver=0x%04x)\n",
-                                chip_ver);
-                       break;
-               case RTL8365MB_CHIP_VER_8367RB:
-                       dev_info(priv->dev,
-                                "found an RTL8367RB-VB switch (ver=0x%04x)\n",
-                                chip_ver);
-                       break;
-               case RTL8365MB_CHIP_VER_8367S:
-                       dev_info(priv->dev,
-                                "found an RTL8367S switch (ver=0x%04x)\n",
-                                chip_ver);
+       for (i = 0; i < ARRAY_SIZE(rtl8365mb_chip_infos); i++) {
+               const struct rtl8365mb_chip_info *ci = &rtl8365mb_chip_infos[i];
+
+               if (ci->chip_id == chip_id && ci->chip_ver == chip_ver) {
+                       mb->chip_info = ci;
                        break;
-               default:
-                       dev_err(priv->dev, "unrecognized switch version (ver=0x%04x)",
-                               chip_ver);
-                       return -ENODEV;
                }
+       }
 
-               priv->num_ports = RTL8365MB_MAX_NUM_PORTS;
-
-               mb->priv = priv;
-               mb->chip_id = chip_id;
-               mb->chip_ver = chip_ver;
-               mb->port_mask = GENMASK(priv->num_ports - 1, 0);
-               mb->learn_limit_max = RTL8365MB_LEARN_LIMIT_MAX;
-               mb->jam_table = rtl8365mb_init_jam_8365mb_vc;
-               mb->jam_size = ARRAY_SIZE(rtl8365mb_init_jam_8365mb_vc);
-
-               mb->cpu.trap_port = RTL8365MB_MAX_NUM_PORTS;
-               mb->cpu.insert = RTL8365MB_CPU_INSERT_TO_ALL;
-               mb->cpu.position = RTL8365MB_CPU_POS_AFTER_SA;
-               mb->cpu.rx_length = RTL8365MB_CPU_RXLEN_64BYTES;
-               mb->cpu.format = RTL8365MB_CPU_FORMAT_8BYTES;
-
-               break;
-       default:
+       if (!mb->chip_info) {
                dev_err(priv->dev,
-                       "found an unknown Realtek switch (id=0x%04x, ver=0x%04x)\n",
-                       chip_id, chip_ver);
+                       "unrecognized switch (id=0x%04x, ver=0x%04x)", chip_id,
+                       chip_ver);
                return -ENODEV;
        }
 
+       dev_info(priv->dev, "found an %s switch\n", mb->chip_info->name);
+
+       priv->num_ports = RTL8365MB_MAX_NUM_PORTS;
+       mb->priv = priv;
+       mb->cpu.trap_port = RTL8365MB_MAX_NUM_PORTS;
+       mb->cpu.insert = RTL8365MB_CPU_INSERT_TO_ALL;
+       mb->cpu.position = RTL8365MB_CPU_POS_AFTER_SA;
+       mb->cpu.rx_length = RTL8365MB_CPU_RXLEN_64BYTES;
+       mb->cpu.format = RTL8365MB_CPU_FORMAT_8BYTES;
+
        return 0;
 }
 
diff --git a/drivers/net/dsa/rzn1_a5psw.c b/drivers/net/dsa/rzn1_a5psw.c
new file mode 100644 (file)
index 0000000..0744e81
--- /dev/null
@@ -0,0 +1,1064 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Schneider-Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
+#include <linux/if_bridge.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <net/dsa.h>
+
+#include "rzn1_a5psw.h"
+
+struct a5psw_stats {
+       u16 offset;
+       const char name[ETH_GSTRING_LEN];
+};
+
+#define STAT_DESC(_offset) {   \
+       .offset = A5PSW_##_offset,      \
+       .name = __stringify(_offset),   \
+}
+
+static const struct a5psw_stats a5psw_stats[] = {
+       STAT_DESC(aFramesTransmittedOK),
+       STAT_DESC(aFramesReceivedOK),
+       STAT_DESC(aFrameCheckSequenceErrors),
+       STAT_DESC(aAlignmentErrors),
+       STAT_DESC(aOctetsTransmittedOK),
+       STAT_DESC(aOctetsReceivedOK),
+       STAT_DESC(aTxPAUSEMACCtrlFrames),
+       STAT_DESC(aRxPAUSEMACCtrlFrames),
+       STAT_DESC(ifInErrors),
+       STAT_DESC(ifOutErrors),
+       STAT_DESC(ifInUcastPkts),
+       STAT_DESC(ifInMulticastPkts),
+       STAT_DESC(ifInBroadcastPkts),
+       STAT_DESC(ifOutDiscards),
+       STAT_DESC(ifOutUcastPkts),
+       STAT_DESC(ifOutMulticastPkts),
+       STAT_DESC(ifOutBroadcastPkts),
+       STAT_DESC(etherStatsDropEvents),
+       STAT_DESC(etherStatsOctets),
+       STAT_DESC(etherStatsPkts),
+       STAT_DESC(etherStatsUndersizePkts),
+       STAT_DESC(etherStatsOversizePkts),
+       STAT_DESC(etherStatsPkts64Octets),
+       STAT_DESC(etherStatsPkts65to127Octets),
+       STAT_DESC(etherStatsPkts128to255Octets),
+       STAT_DESC(etherStatsPkts256to511Octets),
+       STAT_DESC(etherStatsPkts1024to1518Octets),
+       STAT_DESC(etherStatsPkts1519toXOctets),
+       STAT_DESC(etherStatsJabbers),
+       STAT_DESC(etherStatsFragments),
+       STAT_DESC(VLANReceived),
+       STAT_DESC(VLANTransmitted),
+       STAT_DESC(aDeferred),
+       STAT_DESC(aMultipleCollisions),
+       STAT_DESC(aSingleCollisions),
+       STAT_DESC(aLateCollisions),
+       STAT_DESC(aExcessiveCollisions),
+       STAT_DESC(aCarrierSenseErrors),
+};
+
+static void a5psw_reg_writel(struct a5psw *a5psw, int offset, u32 value)
+{
+       writel(value, a5psw->base + offset);
+}
+
+static u32 a5psw_reg_readl(struct a5psw *a5psw, int offset)
+{
+       return readl(a5psw->base + offset);
+}
+
+static void a5psw_reg_rmw(struct a5psw *a5psw, int offset, u32 mask, u32 val)
+{
+       u32 reg;
+
+       spin_lock(&a5psw->reg_lock);
+
+       reg = a5psw_reg_readl(a5psw, offset);
+       reg &= ~mask;
+       reg |= val;
+       a5psw_reg_writel(a5psw, offset, reg);
+
+       spin_unlock(&a5psw->reg_lock);
+}
+
+static enum dsa_tag_protocol a5psw_get_tag_protocol(struct dsa_switch *ds,
+                                                   int port,
+                                                   enum dsa_tag_protocol mp)
+{
+       return DSA_TAG_PROTO_RZN1_A5PSW;
+}
+
+static void a5psw_port_pattern_set(struct a5psw *a5psw, int port, int pattern,
+                                  bool enable)
+{
+       u32 rx_match = 0;
+
+       if (enable)
+               rx_match |= A5PSW_RXMATCH_CONFIG_PATTERN(pattern);
+
+       a5psw_reg_rmw(a5psw, A5PSW_RXMATCH_CONFIG(port),
+                     A5PSW_RXMATCH_CONFIG_PATTERN(pattern), rx_match);
+}
+
+static void a5psw_port_mgmtfwd_set(struct a5psw *a5psw, int port, bool enable)
+{
+       /* Enable "management forward" pattern matching, this will forward
+        * packets from this port only towards the management port and thus
+        * isolate the port.
+        */
+       a5psw_port_pattern_set(a5psw, port, A5PSW_PATTERN_MGMTFWD, enable);
+}
+
+static void a5psw_port_enable_set(struct a5psw *a5psw, int port, bool enable)
+{
+       u32 port_ena = 0;
+
+       if (enable)
+               port_ena |= A5PSW_PORT_ENA_TX_RX(port);
+
+       a5psw_reg_rmw(a5psw, A5PSW_PORT_ENA, A5PSW_PORT_ENA_TX_RX(port),
+                     port_ena);
+}
+
+static int a5psw_lk_execute_ctrl(struct a5psw *a5psw, u32 *ctrl)
+{
+       int ret;
+
+       a5psw_reg_writel(a5psw, A5PSW_LK_ADDR_CTRL, *ctrl);
+
+       ret = readl_poll_timeout(a5psw->base + A5PSW_LK_ADDR_CTRL, *ctrl,
+                                !(*ctrl & A5PSW_LK_ADDR_CTRL_BUSY),
+                                A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
+       if (ret)
+               dev_err(a5psw->dev, "LK_CTRL timeout waiting for BUSY bit\n");
+
+       return ret;
+}
+
+static void a5psw_port_fdb_flush(struct a5psw *a5psw, int port)
+{
+       u32 ctrl = A5PSW_LK_ADDR_CTRL_DELETE_PORT | BIT(port);
+
+       mutex_lock(&a5psw->lk_lock);
+       a5psw_lk_execute_ctrl(a5psw, &ctrl);
+       mutex_unlock(&a5psw->lk_lock);
+}
+
+static void a5psw_port_authorize_set(struct a5psw *a5psw, int port,
+                                    bool authorize)
+{
+       u32 reg = a5psw_reg_readl(a5psw, A5PSW_AUTH_PORT(port));
+
+       if (authorize)
+               reg |= A5PSW_AUTH_PORT_AUTHORIZED;
+       else
+               reg &= ~A5PSW_AUTH_PORT_AUTHORIZED;
+
+       a5psw_reg_writel(a5psw, A5PSW_AUTH_PORT(port), reg);
+}
+
+static void a5psw_port_disable(struct dsa_switch *ds, int port)
+{
+       struct a5psw *a5psw = ds->priv;
+
+       a5psw_port_authorize_set(a5psw, port, false);
+       a5psw_port_enable_set(a5psw, port, false);
+}
+
+static int a5psw_port_enable(struct dsa_switch *ds, int port,
+                            struct phy_device *phy)
+{
+       struct a5psw *a5psw = ds->priv;
+
+       a5psw_port_authorize_set(a5psw, port, true);
+       a5psw_port_enable_set(a5psw, port, true);
+
+       return 0;
+}
+
+static int a5psw_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+{
+       struct a5psw *a5psw = ds->priv;
+
+       new_mtu += ETH_HLEN + A5PSW_EXTRA_MTU_LEN + ETH_FCS_LEN;
+       a5psw_reg_writel(a5psw, A5PSW_FRM_LENGTH(port), new_mtu);
+
+       return 0;
+}
+
+static int a5psw_port_max_mtu(struct dsa_switch *ds, int port)
+{
+       return A5PSW_MAX_MTU;
+}
+
+static void a5psw_phylink_get_caps(struct dsa_switch *ds, int port,
+                                  struct phylink_config *config)
+{
+       unsigned long *intf = config->supported_interfaces;
+
+       config->mac_capabilities = MAC_1000FD;
+
+       if (dsa_is_cpu_port(ds, port)) {
+               /* GMII is used internally and GMAC2 is connected to the switch
+                * using 1000Mbps Full-Duplex mode only (cf ethernet manual)
+                */
+               __set_bit(PHY_INTERFACE_MODE_GMII, intf);
+       } else {
+               config->mac_capabilities |= MAC_100 | MAC_10;
+               phy_interface_set_rgmii(intf);
+               __set_bit(PHY_INTERFACE_MODE_RMII, intf);
+               __set_bit(PHY_INTERFACE_MODE_MII, intf);
+       }
+}
+
+static struct phylink_pcs *
+a5psw_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
+                            phy_interface_t interface)
+{
+       struct dsa_port *dp = dsa_to_port(ds, port);
+       struct a5psw *a5psw = ds->priv;
+
+       if (!dsa_port_is_cpu(dp) && a5psw->pcs[port])
+               return a5psw->pcs[port];
+
+       return NULL;
+}
+
+static void a5psw_phylink_mac_link_down(struct dsa_switch *ds, int port,
+                                       unsigned int mode,
+                                       phy_interface_t interface)
+{
+       struct a5psw *a5psw = ds->priv;
+       u32 cmd_cfg;
+
+       cmd_cfg = a5psw_reg_readl(a5psw, A5PSW_CMD_CFG(port));
+       cmd_cfg &= ~(A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA);
+       a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
+}
+
+static void a5psw_phylink_mac_link_up(struct dsa_switch *ds, int port,
+                                     unsigned int mode,
+                                     phy_interface_t interface,
+                                     struct phy_device *phydev, int speed,
+                                     int duplex, bool tx_pause, bool rx_pause)
+{
+       u32 cmd_cfg = A5PSW_CMD_CFG_RX_ENA | A5PSW_CMD_CFG_TX_ENA |
+                     A5PSW_CMD_CFG_TX_CRC_APPEND;
+       struct a5psw *a5psw = ds->priv;
+
+       if (speed == SPEED_1000)
+               cmd_cfg |= A5PSW_CMD_CFG_ETH_SPEED;
+
+       if (duplex == DUPLEX_HALF)
+               cmd_cfg |= A5PSW_CMD_CFG_HD_ENA;
+
+       cmd_cfg |= A5PSW_CMD_CFG_CNTL_FRM_ENA;
+
+       if (!rx_pause)
+               cmd_cfg &= ~A5PSW_CMD_CFG_PAUSE_IGNORE;
+
+       a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port), cmd_cfg);
+}
+
+static int a5psw_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
+{
+       struct a5psw *a5psw = ds->priv;
+       unsigned long rate;
+       u64 max, tmp;
+       u32 agetime;
+
+       rate = clk_get_rate(a5psw->clk);
+       max = div64_ul(((u64)A5PSW_LK_AGETIME_MASK * A5PSW_TABLE_ENTRIES * 1024),
+                      rate) * 1000;
+       if (msecs > max)
+               return -EINVAL;
+
+       tmp = div_u64(rate, MSEC_PER_SEC);
+       agetime = div_u64(msecs * tmp, 1024 * A5PSW_TABLE_ENTRIES);
+
+       a5psw_reg_writel(a5psw, A5PSW_LK_AGETIME, agetime);
+
+       return 0;
+}
+
+static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
+                                         bool set)
+{
+       u8 offsets[] = {A5PSW_UCAST_DEF_MASK, A5PSW_BCAST_DEF_MASK,
+                       A5PSW_MCAST_DEF_MASK};
+       int i;
+
+       if (set)
+               a5psw->bridged_ports |= BIT(port);
+       else
+               a5psw->bridged_ports &= ~BIT(port);
+
+       for (i = 0; i < ARRAY_SIZE(offsets); i++)
+               a5psw_reg_writel(a5psw, offsets[i], a5psw->bridged_ports);
+}
+
+static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
+                                 struct dsa_bridge bridge,
+                                 bool *tx_fwd_offload,
+                                 struct netlink_ext_ack *extack)
+{
+       struct a5psw *a5psw = ds->priv;
+
+       /* We only support 1 bridge device */
+       if (a5psw->br_dev && bridge.dev != a5psw->br_dev) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Forwarding offload supported for a single bridge");
+               return -EOPNOTSUPP;
+       }
+
+       a5psw->br_dev = bridge.dev;
+       a5psw_flooding_set_resolution(a5psw, port, true);
+       a5psw_port_mgmtfwd_set(a5psw, port, false);
+
+       return 0;
+}
+
+static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
+                                   struct dsa_bridge bridge)
+{
+       struct a5psw *a5psw = ds->priv;
+
+       a5psw_flooding_set_resolution(a5psw, port, false);
+       a5psw_port_mgmtfwd_set(a5psw, port, true);
+
+       /* No more ports bridged */
+       if (a5psw->bridged_ports == BIT(A5PSW_CPU_PORT))
+               a5psw->br_dev = NULL;
+}
+
+static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
+{
+       u32 mask = A5PSW_INPUT_LEARN_DIS(port) | A5PSW_INPUT_LEARN_BLOCK(port);
+       struct a5psw *a5psw = ds->priv;
+       u32 reg = 0;
+
+       switch (state) {
+       case BR_STATE_DISABLED:
+       case BR_STATE_BLOCKING:
+               reg |= A5PSW_INPUT_LEARN_DIS(port);
+               reg |= A5PSW_INPUT_LEARN_BLOCK(port);
+               break;
+       case BR_STATE_LISTENING:
+               reg |= A5PSW_INPUT_LEARN_DIS(port);
+               break;
+       case BR_STATE_LEARNING:
+               reg |= A5PSW_INPUT_LEARN_BLOCK(port);
+               break;
+       case BR_STATE_FORWARDING:
+       default:
+               break;
+       }
+
+       a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, mask, reg);
+}
+
+static void a5psw_port_fast_age(struct dsa_switch *ds, int port)
+{
+       struct a5psw *a5psw = ds->priv;
+
+       a5psw_port_fdb_flush(a5psw, port);
+}
+
+static int a5psw_lk_execute_lookup(struct a5psw *a5psw, union lk_data *lk_data,
+                                  u16 *entry)
+{
+       u32 ctrl;
+       int ret;
+
+       a5psw_reg_writel(a5psw, A5PSW_LK_DATA_LO, lk_data->lo);
+       a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data->hi);
+
+       ctrl = A5PSW_LK_ADDR_CTRL_LOOKUP;
+       ret = a5psw_lk_execute_ctrl(a5psw, &ctrl);
+       if (ret)
+               return ret;
+
+       *entry = ctrl & A5PSW_LK_ADDR_CTRL_ADDRESS;
+
+       return 0;
+}
+
+static int a5psw_port_fdb_add(struct dsa_switch *ds, int port,
+                             const unsigned char *addr, u16 vid,
+                             struct dsa_db db)
+{
+       struct a5psw *a5psw = ds->priv;
+       union lk_data lk_data = {0};
+       bool inc_learncount = false;
+       int ret = 0;
+       u16 entry;
+       u32 reg;
+
+       ether_addr_copy(lk_data.entry.mac, addr);
+       lk_data.entry.port_mask = BIT(port);
+
+       mutex_lock(&a5psw->lk_lock);
+
+       /* Set the value to be written in the lookup table */
+       ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
+       if (ret)
+               goto lk_unlock;
+
+       lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
+       if (!lk_data.entry.valid) {
+               inc_learncount = true;
+               /* port_mask set to 0x1f when entry is not valid, clear it */
+               lk_data.entry.port_mask = 0;
+               lk_data.entry.prio = 0;
+       }
+
+       lk_data.entry.port_mask |= BIT(port);
+       lk_data.entry.is_static = 1;
+       lk_data.entry.valid = 1;
+
+       a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
+
+       reg = A5PSW_LK_ADDR_CTRL_WRITE | entry;
+       ret = a5psw_lk_execute_ctrl(a5psw, &reg);
+       if (ret)
+               goto lk_unlock;
+
+       if (inc_learncount) {
+               reg = A5PSW_LK_LEARNCOUNT_MODE_INC;
+               a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
+       }
+
+lk_unlock:
+       mutex_unlock(&a5psw->lk_lock);
+
+       return ret;
+}
+
+static int a5psw_port_fdb_del(struct dsa_switch *ds, int port,
+                             const unsigned char *addr, u16 vid,
+                             struct dsa_db db)
+{
+       struct a5psw *a5psw = ds->priv;
+       union lk_data lk_data = {0};
+       bool clear = false;
+       u16 entry;
+       u32 reg;
+       int ret;
+
+       ether_addr_copy(lk_data.entry.mac, addr);
+
+       mutex_lock(&a5psw->lk_lock);
+
+       ret = a5psw_lk_execute_lookup(a5psw, &lk_data, &entry);
+       if (ret)
+               goto lk_unlock;
+
+       lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
+
+       /* Our hardware does not associate any VID to the FDB entries so this
+        * means that if two entries were added for the same mac but for
+        * different VID, then, on the deletion of the first one, we would also
+        * delete the second one. Since there is unfortunately nothing we can do
+        * about that, do not return an error...
+        */
+       if (!lk_data.entry.valid)
+               goto lk_unlock;
+
+       lk_data.entry.port_mask &= ~BIT(port);
+       /* If there is no more port in the mask, clear the entry */
+       if (lk_data.entry.port_mask == 0)
+               clear = true;
+
+       a5psw_reg_writel(a5psw, A5PSW_LK_DATA_HI, lk_data.hi);
+
+       reg = entry;
+       if (clear)
+               reg |= A5PSW_LK_ADDR_CTRL_CLEAR;
+       else
+               reg |= A5PSW_LK_ADDR_CTRL_WRITE;
+
+       ret = a5psw_lk_execute_ctrl(a5psw, &reg);
+       if (ret)
+               goto lk_unlock;
+
+       /* Decrement LEARNCOUNT */
+       if (clear) {
+               reg = A5PSW_LK_LEARNCOUNT_MODE_DEC;
+               a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
+       }
+
+lk_unlock:
+       mutex_unlock(&a5psw->lk_lock);
+
+       return ret;
+}
+
+static int a5psw_port_fdb_dump(struct dsa_switch *ds, int port,
+                              dsa_fdb_dump_cb_t *cb, void *data)
+{
+       struct a5psw *a5psw = ds->priv;
+       union lk_data lk_data;
+       int i = 0, ret = 0;
+       u32 reg;
+
+       mutex_lock(&a5psw->lk_lock);
+
+       for (i = 0; i < A5PSW_TABLE_ENTRIES; i++) {
+               reg = A5PSW_LK_ADDR_CTRL_READ | A5PSW_LK_ADDR_CTRL_WAIT | i;
+
+               ret = a5psw_lk_execute_ctrl(a5psw, &reg);
+               if (ret)
+                       goto out_unlock;
+
+               lk_data.hi = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_HI);
+               /* If entry is not valid or does not contain the port, skip */
+               if (!lk_data.entry.valid ||
+                   !(lk_data.entry.port_mask & BIT(port)))
+                       continue;
+
+               lk_data.lo = a5psw_reg_readl(a5psw, A5PSW_LK_DATA_LO);
+
+               ret = cb(lk_data.entry.mac, 0, lk_data.entry.is_static, data);
+               if (ret)
+                       goto out_unlock;
+       }
+
+out_unlock:
+       mutex_unlock(&a5psw->lk_lock);
+
+       return ret;
+}
+
+static u64 a5psw_read_stat(struct a5psw *a5psw, u32 offset, int port)
+{
+       u32 reg_lo, reg_hi;
+
+       reg_lo = a5psw_reg_readl(a5psw, offset + A5PSW_PORT_OFFSET(port));
+       /* A5PSW_STATS_HIWORD is latched on stat read */
+       reg_hi = a5psw_reg_readl(a5psw, A5PSW_STATS_HIWORD);
+
+       return ((u64)reg_hi << 32) | reg_lo;
+}
+
+static void a5psw_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+                             uint8_t *data)
+{
+       unsigned int u;
+
+       if (stringset != ETH_SS_STATS)
+               return;
+
+       for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++) {
+               memcpy(data + u * ETH_GSTRING_LEN, a5psw_stats[u].name,
+                      ETH_GSTRING_LEN);
+       }
+}
+
+static void a5psw_get_ethtool_stats(struct dsa_switch *ds, int port,
+                                   uint64_t *data)
+{
+       struct a5psw *a5psw = ds->priv;
+       unsigned int u;
+
+       for (u = 0; u < ARRAY_SIZE(a5psw_stats); u++)
+               data[u] = a5psw_read_stat(a5psw, a5psw_stats[u].offset, port);
+}
+
+static int a5psw_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+       if (sset != ETH_SS_STATS)
+               return 0;
+
+       return ARRAY_SIZE(a5psw_stats);
+}
+
+static void a5psw_get_eth_mac_stats(struct dsa_switch *ds, int port,
+                                   struct ethtool_eth_mac_stats *mac_stats)
+{
+       struct a5psw *a5psw = ds->priv;
+
+#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
+       mac_stats->FramesTransmittedOK = RD(aFramesTransmittedOK);
+       mac_stats->SingleCollisionFrames = RD(aSingleCollisions);
+       mac_stats->MultipleCollisionFrames = RD(aMultipleCollisions);
+       mac_stats->FramesReceivedOK = RD(aFramesReceivedOK);
+       mac_stats->FrameCheckSequenceErrors = RD(aFrameCheckSequenceErrors);
+       mac_stats->AlignmentErrors = RD(aAlignmentErrors);
+       mac_stats->OctetsTransmittedOK = RD(aOctetsTransmittedOK);
+       mac_stats->FramesWithDeferredXmissions = RD(aDeferred);
+       mac_stats->LateCollisions = RD(aLateCollisions);
+       mac_stats->FramesAbortedDueToXSColls = RD(aExcessiveCollisions);
+       mac_stats->FramesLostDueToIntMACXmitError = RD(ifOutErrors);
+       mac_stats->CarrierSenseErrors = RD(aCarrierSenseErrors);
+       mac_stats->OctetsReceivedOK = RD(aOctetsReceivedOK);
+       mac_stats->FramesLostDueToIntMACRcvError = RD(ifInErrors);
+       mac_stats->MulticastFramesXmittedOK = RD(ifOutMulticastPkts);
+       mac_stats->BroadcastFramesXmittedOK = RD(ifOutBroadcastPkts);
+       mac_stats->FramesWithExcessiveDeferral = RD(aDeferred);
+       mac_stats->MulticastFramesReceivedOK = RD(ifInMulticastPkts);
+       mac_stats->BroadcastFramesReceivedOK = RD(ifInBroadcastPkts);
+#undef RD
+}
+
+static const struct ethtool_rmon_hist_range a5psw_rmon_ranges[] = {
+       { 0, 64 },
+       { 65, 127 },
+       { 128, 255 },
+       { 256, 511 },
+       { 512, 1023 },
+       { 1024, 1518 },
+       { 1519, A5PSW_MAX_MTU },
+       {}
+};
+
+static void a5psw_get_rmon_stats(struct dsa_switch *ds, int port,
+                                struct ethtool_rmon_stats *rmon_stats,
+                                const struct ethtool_rmon_hist_range **ranges)
+{
+       struct a5psw *a5psw = ds->priv;
+
+#define RD(name) a5psw_read_stat(a5psw, A5PSW_##name, port)
+       rmon_stats->undersize_pkts = RD(etherStatsUndersizePkts);
+       rmon_stats->oversize_pkts = RD(etherStatsOversizePkts);
+       rmon_stats->fragments = RD(etherStatsFragments);
+       rmon_stats->jabbers = RD(etherStatsJabbers);
+       rmon_stats->hist[0] = RD(etherStatsPkts64Octets);
+       rmon_stats->hist[1] = RD(etherStatsPkts65to127Octets);
+       rmon_stats->hist[2] = RD(etherStatsPkts128to255Octets);
+       rmon_stats->hist[3] = RD(etherStatsPkts256to511Octets);
+       rmon_stats->hist[4] = RD(etherStatsPkts512to1023Octets);
+       rmon_stats->hist[5] = RD(etherStatsPkts1024to1518Octets);
+       rmon_stats->hist[6] = RD(etherStatsPkts1519toXOctets);
+#undef RD
+
+       *ranges = a5psw_rmon_ranges;
+}
+
+static void a5psw_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
+                                    struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+       struct a5psw *a5psw = ds->priv;
+       u64 stat;
+
+       stat = a5psw_read_stat(a5psw, A5PSW_aTxPAUSEMACCtrlFrames, port);
+       ctrl_stats->MACControlFramesTransmitted = stat;
+       stat = a5psw_read_stat(a5psw, A5PSW_aRxPAUSEMACCtrlFrames, port);
+       ctrl_stats->MACControlFramesReceived = stat;
+}
+
+static int a5psw_setup(struct dsa_switch *ds)
+{
+       struct a5psw *a5psw = ds->priv;
+       int port, vlan, ret;
+       struct dsa_port *dp;
+       u32 reg;
+
+       /* Validate that there is only 1 CPU port with index A5PSW_CPU_PORT */
+       dsa_switch_for_each_cpu_port(dp, ds) {
+               if (dp->index != A5PSW_CPU_PORT) {
+                       dev_err(a5psw->dev, "Invalid CPU port\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* Configure management port */
+       reg = A5PSW_CPU_PORT | A5PSW_MGMT_CFG_DISCARD;
+       a5psw_reg_writel(a5psw, A5PSW_MGMT_CFG, reg);
+
+       /* Set pattern 0 to forward all frame to mgmt port */
+       a5psw_reg_writel(a5psw, A5PSW_PATTERN_CTRL(A5PSW_PATTERN_MGMTFWD),
+                        A5PSW_PATTERN_CTRL_MGMTFWD);
+
+       /* Enable port tagging */
+       reg = FIELD_PREP(A5PSW_MGMT_TAG_CFG_TAGFIELD, ETH_P_DSA_A5PSW);
+       reg |= A5PSW_MGMT_TAG_CFG_ENABLE | A5PSW_MGMT_TAG_CFG_ALL_FRAMES;
+       a5psw_reg_writel(a5psw, A5PSW_MGMT_TAG_CFG, reg);
+
+       /* Enable normal switch operation */
+       reg = A5PSW_LK_ADDR_CTRL_BLOCKING | A5PSW_LK_ADDR_CTRL_LEARNING |
+             A5PSW_LK_ADDR_CTRL_AGEING | A5PSW_LK_ADDR_CTRL_ALLOW_MIGR |
+             A5PSW_LK_ADDR_CTRL_CLEAR_TABLE;
+       a5psw_reg_writel(a5psw, A5PSW_LK_CTRL, reg);
+
+       ret = readl_poll_timeout(a5psw->base + A5PSW_LK_CTRL, reg,
+                                !(reg & A5PSW_LK_ADDR_CTRL_CLEAR_TABLE),
+                                A5PSW_LK_BUSY_USEC_POLL, A5PSW_CTRL_TIMEOUT);
+       if (ret) {
+               dev_err(a5psw->dev, "Failed to clear lookup table\n");
+               return ret;
+       }
+
+       /* Reset learn count to 0 */
+       reg = A5PSW_LK_LEARNCOUNT_MODE_SET;
+       a5psw_reg_writel(a5psw, A5PSW_LK_LEARNCOUNT, reg);
+
+       /* Clear VLAN resource table */
+       reg = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_WR_TAGMASK;
+       for (vlan = 0; vlan < A5PSW_VLAN_COUNT; vlan++)
+               a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(vlan), reg);
+
+       /* Reset all ports */
+       dsa_switch_for_each_port(dp, ds) {
+               port = dp->index;
+
+               /* Reset the port */
+               a5psw_reg_writel(a5psw, A5PSW_CMD_CFG(port),
+                                A5PSW_CMD_CFG_SW_RESET);
+
+               /* Enable only CPU port */
+               a5psw_port_enable_set(a5psw, port, dsa_port_is_cpu(dp));
+
+               if (dsa_port_is_unused(dp))
+                       continue;
+
+               /* Enable egress flooding for CPU port */
+               if (dsa_port_is_cpu(dp))
+                       a5psw_flooding_set_resolution(a5psw, port, true);
+
+               /* Enable management forward only for user ports */
+               if (dsa_port_is_user(dp))
+                       a5psw_port_mgmtfwd_set(a5psw, port, true);
+       }
+
+       return 0;
+}
+
+static const struct dsa_switch_ops a5psw_switch_ops = {
+       .get_tag_protocol = a5psw_get_tag_protocol,
+       .setup = a5psw_setup,
+       .port_disable = a5psw_port_disable,
+       .port_enable = a5psw_port_enable,
+       .phylink_get_caps = a5psw_phylink_get_caps,
+       .phylink_mac_select_pcs = a5psw_phylink_mac_select_pcs,
+       .phylink_mac_link_down = a5psw_phylink_mac_link_down,
+       .phylink_mac_link_up = a5psw_phylink_mac_link_up,
+       .port_change_mtu = a5psw_port_change_mtu,
+       .port_max_mtu = a5psw_port_max_mtu,
+       .get_sset_count = a5psw_get_sset_count,
+       .get_strings = a5psw_get_strings,
+       .get_ethtool_stats = a5psw_get_ethtool_stats,
+       .get_eth_mac_stats = a5psw_get_eth_mac_stats,
+       .get_eth_ctrl_stats = a5psw_get_eth_ctrl_stats,
+       .get_rmon_stats = a5psw_get_rmon_stats,
+       .set_ageing_time = a5psw_set_ageing_time,
+       .port_bridge_join = a5psw_port_bridge_join,
+       .port_bridge_leave = a5psw_port_bridge_leave,
+       .port_stp_state_set = a5psw_port_stp_state_set,
+       .port_fast_age = a5psw_port_fast_age,
+       .port_fdb_add = a5psw_port_fdb_add,
+       .port_fdb_del = a5psw_port_fdb_del,
+       .port_fdb_dump = a5psw_port_fdb_dump,
+};
+
+static int a5psw_mdio_wait_busy(struct a5psw *a5psw)
+{
+       u32 status;
+       int err;
+
+       err = readl_poll_timeout(a5psw->base + A5PSW_MDIO_CFG_STATUS, status,
+                                !(status & A5PSW_MDIO_CFG_STATUS_BUSY), 10,
+                                1000 * USEC_PER_MSEC);
+       if (err)
+               dev_err(a5psw->dev, "MDIO command timeout\n");
+
+       return err;
+}
+
+static int a5psw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
+{
+       struct a5psw *a5psw = bus->priv;
+       u32 cmd, status;
+       int ret;
+
+       if (phy_reg & MII_ADDR_C45)
+               return -EOPNOTSUPP;
+
+       cmd = A5PSW_MDIO_COMMAND_READ;
+       cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
+       cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
+
+       a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
+
+       ret = a5psw_mdio_wait_busy(a5psw);
+       if (ret)
+               return ret;
+
+       ret = a5psw_reg_readl(a5psw, A5PSW_MDIO_DATA) & A5PSW_MDIO_DATA_MASK;
+
+       status = a5psw_reg_readl(a5psw, A5PSW_MDIO_CFG_STATUS);
+       if (status & A5PSW_MDIO_CFG_STATUS_READERR)
+               return -EIO;
+
+       return ret;
+}
+
+static int a5psw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg,
+                           u16 phy_data)
+{
+       struct a5psw *a5psw = bus->priv;
+       u32 cmd;
+
+       if (phy_reg & MII_ADDR_C45)
+               return -EOPNOTSUPP;
+
+       cmd = FIELD_PREP(A5PSW_MDIO_COMMAND_REG_ADDR, phy_reg);
+       cmd |= FIELD_PREP(A5PSW_MDIO_COMMAND_PHY_ADDR, phy_id);
+
+       a5psw_reg_writel(a5psw, A5PSW_MDIO_COMMAND, cmd);
+       a5psw_reg_writel(a5psw, A5PSW_MDIO_DATA, phy_data);
+
+       return a5psw_mdio_wait_busy(a5psw);
+}
+
+static int a5psw_mdio_config(struct a5psw *a5psw, u32 mdio_freq)
+{
+       unsigned long rate;
+       unsigned long div;
+       u32 cfgstatus;
+
+       rate = clk_get_rate(a5psw->hclk);
+       div = ((rate / mdio_freq) / 2);
+       if (div > FIELD_MAX(A5PSW_MDIO_CFG_STATUS_CLKDIV) ||
+           div < A5PSW_MDIO_CLK_DIV_MIN) {
+               dev_err(a5psw->dev, "MDIO clock div %ld out of range\n", div);
+               return -ERANGE;
+       }
+
+       cfgstatus = FIELD_PREP(A5PSW_MDIO_CFG_STATUS_CLKDIV, div);
+
+       a5psw_reg_writel(a5psw, A5PSW_MDIO_CFG_STATUS, cfgstatus);
+
+       return 0;
+}
+
+static int a5psw_probe_mdio(struct a5psw *a5psw, struct device_node *node)
+{
+       struct device *dev = a5psw->dev;
+       struct mii_bus *bus;
+       u32 mdio_freq;
+       int ret;
+
+       if (of_property_read_u32(node, "clock-frequency", &mdio_freq))
+               mdio_freq = A5PSW_MDIO_DEF_FREQ;
+
+       ret = a5psw_mdio_config(a5psw, mdio_freq);
+       if (ret)
+               return ret;
+
+       bus = devm_mdiobus_alloc(dev);
+       if (!bus)
+               return -ENOMEM;
+
+       bus->name = "a5psw_mdio";
+       bus->read = a5psw_mdio_read;
+       bus->write = a5psw_mdio_write;
+       bus->priv = a5psw;
+       bus->parent = dev;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+
+       a5psw->mii_bus = bus;
+
+       return devm_of_mdiobus_register(dev, bus, node);
+}
+
+static void a5psw_pcs_free(struct a5psw *a5psw)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(a5psw->pcs); i++) {
+               if (a5psw->pcs[i])
+                       miic_destroy(a5psw->pcs[i]);
+       }
+}
+
+static int a5psw_pcs_get(struct a5psw *a5psw)
+{
+       struct device_node *ports, *port, *pcs_node;
+       struct phylink_pcs *pcs;
+       int ret;
+       u32 reg;
+
+       ports = of_get_child_by_name(a5psw->dev->of_node, "ethernet-ports");
+       if (!ports)
+               return -EINVAL;
+
+       for_each_available_child_of_node(ports, port) {
+               pcs_node = of_parse_phandle(port, "pcs-handle", 0);
+               if (!pcs_node)
+                       continue;
+
+               if (of_property_read_u32(port, "reg", &reg)) {
+                       ret = -EINVAL;
+                       goto free_pcs;
+               }
+
+               if (reg >= ARRAY_SIZE(a5psw->pcs)) {
+                       ret = -ENODEV;
+                       goto free_pcs;
+               }
+
+               pcs = miic_create(a5psw->dev, pcs_node);
+               if (IS_ERR(pcs)) {
+                       dev_err(a5psw->dev, "Failed to create PCS for port %d\n",
+                               reg);
+                       ret = PTR_ERR(pcs);
+                       goto free_pcs;
+               }
+
+               a5psw->pcs[reg] = pcs;
+               of_node_put(pcs_node);
+       }
+       of_node_put(ports);
+
+       return 0;
+
+free_pcs:
+       of_node_put(pcs_node);
+       of_node_put(port);
+       of_node_put(ports);
+       a5psw_pcs_free(a5psw);
+
+       return ret;
+}
+
+static int a5psw_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *mdio;
+       struct dsa_switch *ds;
+       struct a5psw *a5psw;
+       int ret;
+
+       a5psw = devm_kzalloc(dev, sizeof(*a5psw), GFP_KERNEL);
+       if (!a5psw)
+               return -ENOMEM;
+
+       a5psw->dev = dev;
+       mutex_init(&a5psw->lk_lock);
+       spin_lock_init(&a5psw->reg_lock);
+       a5psw->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(a5psw->base))
+               return PTR_ERR(a5psw->base);
+
+       ret = a5psw_pcs_get(a5psw);
+       if (ret)
+               return ret;
+
+       a5psw->hclk = devm_clk_get(dev, "hclk");
+       if (IS_ERR(a5psw->hclk)) {
+               dev_err(dev, "failed get hclk clock\n");
+               ret = PTR_ERR(a5psw->hclk);
+               goto free_pcs;
+       }
+
+       a5psw->clk = devm_clk_get(dev, "clk");
+       if (IS_ERR(a5psw->clk)) {
+               dev_err(dev, "failed get clk_switch clock\n");
+               ret = PTR_ERR(a5psw->clk);
+               goto free_pcs;
+       }
+
+       ret = clk_prepare_enable(a5psw->clk);
+       if (ret)
+               goto free_pcs;
+
+       ret = clk_prepare_enable(a5psw->hclk);
+       if (ret)
+               goto clk_disable;
+
+       mdio = of_get_child_by_name(dev->of_node, "mdio");
+       if (of_device_is_available(mdio)) {
+               ret = a5psw_probe_mdio(a5psw, mdio);
+               if (ret) {
+                       of_node_put(mdio);
+                       dev_err(dev, "Failed to register MDIO: %d\n", ret);
+                       goto hclk_disable;
+               }
+       }
+
+       of_node_put(mdio);
+
+       ds = &a5psw->ds;
+       ds->dev = dev;
+       ds->num_ports = A5PSW_PORTS_NUM;
+       ds->ops = &a5psw_switch_ops;
+       ds->priv = a5psw;
+
+       ret = dsa_register_switch(ds);
+       if (ret) {
+               dev_err(dev, "Failed to register DSA switch: %d\n", ret);
+               goto hclk_disable;
+       }
+
+       return 0;
+
+hclk_disable:
+       clk_disable_unprepare(a5psw->hclk);
+clk_disable:
+       clk_disable_unprepare(a5psw->clk);
+free_pcs:
+       a5psw_pcs_free(a5psw);
+
+       return ret;
+}
+
+static int a5psw_remove(struct platform_device *pdev)
+{
+       struct a5psw *a5psw = platform_get_drvdata(pdev);
+
+       if (!a5psw)
+               return 0;
+
+       dsa_unregister_switch(&a5psw->ds);
+       a5psw_pcs_free(a5psw);
+       clk_disable_unprepare(a5psw->hclk);
+       clk_disable_unprepare(a5psw->clk);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static void a5psw_shutdown(struct platform_device *pdev)
+{
+       struct a5psw *a5psw = platform_get_drvdata(pdev);
+
+       if (!a5psw)
+               return;
+
+       dsa_switch_shutdown(&a5psw->ds);
+
+       platform_set_drvdata(pdev, NULL);
+}
+
+static const struct of_device_id a5psw_of_mtable[] = {
+       { .compatible = "renesas,rzn1-a5psw", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, a5psw_of_mtable);
+
+static struct platform_driver a5psw_driver = {
+       .driver = {
+               .name    = "rzn1_a5psw",
+               .of_match_table = of_match_ptr(a5psw_of_mtable),
+       },
+       .probe = a5psw_probe,
+       .remove = a5psw_remove,
+       .shutdown = a5psw_shutdown,
+};
+module_platform_driver(a5psw_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas RZ/N1 Advanced 5-port Switch driver");
+MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>");
diff --git a/drivers/net/dsa/rzn1_a5psw.h b/drivers/net/dsa/rzn1_a5psw.h
new file mode 100644 (file)
index 0000000..c67abd4
--- /dev/null
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 Schneider Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_mdio.h>
+#include <linux/platform_device.h>
+#include <linux/pcs-rzn1-miic.h>
+#include <net/dsa.h>
+
+#define A5PSW_REVISION                 0x0
+#define A5PSW_PORT_OFFSET(port)                (0x400 * (port))
+
+#define A5PSW_PORT_ENA                 0x8
+#define A5PSW_PORT_ENA_RX_SHIFT                16
+#define A5PSW_PORT_ENA_TX_RX(port)     (BIT((port) + A5PSW_PORT_ENA_RX_SHIFT) | \
+                                        BIT(port))
+#define A5PSW_UCAST_DEF_MASK           0xC
+
+#define A5PSW_VLAN_VERIFY              0x10
+#define A5PSW_VLAN_VERI_SHIFT          0
+#define A5PSW_VLAN_DISC_SHIFT          16
+
+#define A5PSW_BCAST_DEF_MASK           0x14
+#define A5PSW_MCAST_DEF_MASK           0x18
+
+#define A5PSW_INPUT_LEARN              0x1C
+#define A5PSW_INPUT_LEARN_DIS(p)       BIT((p) + 16)
+#define A5PSW_INPUT_LEARN_BLOCK(p)     BIT(p)
+
+#define A5PSW_MGMT_CFG                 0x20
+#define A5PSW_MGMT_CFG_DISCARD         BIT(7)
+
+#define A5PSW_MODE_CFG                 0x24
+#define A5PSW_MODE_STATS_RESET         BIT(31)
+
+#define A5PSW_VLAN_IN_MODE             0x28
+#define A5PSW_VLAN_IN_MODE_PORT_SHIFT(port)    ((port) * 2)
+#define A5PSW_VLAN_IN_MODE_PORT(port)          (GENMASK(1, 0) << \
+                                       A5PSW_VLAN_IN_MODE_PORT_SHIFT(port))
+#define A5PSW_VLAN_IN_MODE_SINGLE_PASSTHROUGH  0x0
+#define A5PSW_VLAN_IN_MODE_SINGLE_REPLACE      0x1
+#define A5PSW_VLAN_IN_MODE_TAG_ALWAYS          0x2
+
+#define A5PSW_VLAN_OUT_MODE            0x2C
+#define A5PSW_VLAN_OUT_MODE_PORT(port) (GENMASK(1, 0) << ((port) * 2))
+#define A5PSW_VLAN_OUT_MODE_DIS                0x0
+#define A5PSW_VLAN_OUT_MODE_STRIP      0x1
+#define A5PSW_VLAN_OUT_MODE_TAG_THROUGH        0x2
+#define A5PSW_VLAN_OUT_MODE_TRANSPARENT        0x3
+
+#define A5PSW_VLAN_IN_MODE_ENA         0x30
+#define A5PSW_VLAN_TAG_ID              0x34
+
+#define A5PSW_SYSTEM_TAGINFO(port)     (0x200 + A5PSW_PORT_OFFSET(port))
+
+#define A5PSW_AUTH_PORT(port)          (0x240 + 4 * (port))
+#define A5PSW_AUTH_PORT_AUTHORIZED     BIT(0)
+
+#define A5PSW_VLAN_RES(entry)          (0x280 + 4 * (entry))
+#define A5PSW_VLAN_RES_WR_PORTMASK     BIT(30)
+#define A5PSW_VLAN_RES_WR_TAGMASK      BIT(29)
+#define A5PSW_VLAN_RES_RD_TAGMASK      BIT(28)
+#define A5PSW_VLAN_RES_ID              GENMASK(16, 5)
+#define A5PSW_VLAN_RES_PORTMASK                GENMASK(4, 0)
+
+#define A5PSW_RXMATCH_CONFIG(port)     (0x3e80 + 4 * (port))
+#define A5PSW_RXMATCH_CONFIG_PATTERN(p)        BIT(p)
+
+#define A5PSW_PATTERN_CTRL(p)          (0x3eb0 + 4  * (p))
+#define A5PSW_PATTERN_CTRL_MGMTFWD     BIT(1)
+
+#define A5PSW_LK_CTRL          0x400
+#define A5PSW_LK_ADDR_CTRL_BLOCKING    BIT(0)
+#define A5PSW_LK_ADDR_CTRL_LEARNING    BIT(1)
+#define A5PSW_LK_ADDR_CTRL_AGEING      BIT(2)
+#define A5PSW_LK_ADDR_CTRL_ALLOW_MIGR  BIT(3)
+#define A5PSW_LK_ADDR_CTRL_CLEAR_TABLE BIT(6)
+
+#define A5PSW_LK_ADDR_CTRL             0x408
+#define A5PSW_LK_ADDR_CTRL_BUSY                BIT(31)
+#define A5PSW_LK_ADDR_CTRL_DELETE_PORT BIT(30)
+#define A5PSW_LK_ADDR_CTRL_CLEAR       BIT(29)
+#define A5PSW_LK_ADDR_CTRL_LOOKUP      BIT(28)
+#define A5PSW_LK_ADDR_CTRL_WAIT                BIT(27)
+#define A5PSW_LK_ADDR_CTRL_READ                BIT(26)
+#define A5PSW_LK_ADDR_CTRL_WRITE       BIT(25)
+#define A5PSW_LK_ADDR_CTRL_ADDRESS     GENMASK(12, 0)
+
+#define A5PSW_LK_DATA_LO               0x40C
+#define A5PSW_LK_DATA_HI               0x410
+#define A5PSW_LK_DATA_HI_VALID         BIT(16)
+#define A5PSW_LK_DATA_HI_PORT          BIT(16)
+
+#define A5PSW_LK_LEARNCOUNT            0x418
+#define A5PSW_LK_LEARNCOUNT_COUNT      GENMASK(13, 0)
+#define A5PSW_LK_LEARNCOUNT_MODE       GENMASK(31, 30)
+#define A5PSW_LK_LEARNCOUNT_MODE_SET   0x0
+#define A5PSW_LK_LEARNCOUNT_MODE_INC   0x1
+#define A5PSW_LK_LEARNCOUNT_MODE_DEC   0x2
+
+#define A5PSW_MGMT_TAG_CFG             0x480
+#define A5PSW_MGMT_TAG_CFG_TAGFIELD    GENMASK(31, 16)
+#define A5PSW_MGMT_TAG_CFG_ALL_FRAMES  BIT(1)
+#define A5PSW_MGMT_TAG_CFG_ENABLE      BIT(0)
+
+#define A5PSW_LK_AGETIME               0x41C
+#define A5PSW_LK_AGETIME_MASK          GENMASK(23, 0)
+
+#define A5PSW_MDIO_CFG_STATUS          0x700
+#define A5PSW_MDIO_CFG_STATUS_CLKDIV   GENMASK(15, 7)
+#define A5PSW_MDIO_CFG_STATUS_READERR  BIT(1)
+#define A5PSW_MDIO_CFG_STATUS_BUSY     BIT(0)
+
+#define A5PSW_MDIO_COMMAND             0x704
+/* Register is named TRAININIT in datasheet and should be set when reading */
+#define A5PSW_MDIO_COMMAND_READ                BIT(15)
+#define A5PSW_MDIO_COMMAND_PHY_ADDR    GENMASK(9, 5)
+#define A5PSW_MDIO_COMMAND_REG_ADDR    GENMASK(4, 0)
+
+#define A5PSW_MDIO_DATA                        0x708
+#define A5PSW_MDIO_DATA_MASK           GENMASK(15, 0)
+
+#define A5PSW_CMD_CFG(port)            (0x808 + A5PSW_PORT_OFFSET(port))
+#define A5PSW_CMD_CFG_CNTL_FRM_ENA     BIT(23)
+#define A5PSW_CMD_CFG_SW_RESET         BIT(13)
+#define A5PSW_CMD_CFG_TX_CRC_APPEND    BIT(11)
+#define A5PSW_CMD_CFG_HD_ENA           BIT(10)
+#define A5PSW_CMD_CFG_PAUSE_IGNORE     BIT(8)
+#define A5PSW_CMD_CFG_CRC_FWD          BIT(6)
+#define A5PSW_CMD_CFG_ETH_SPEED                BIT(3)
+#define A5PSW_CMD_CFG_RX_ENA           BIT(1)
+#define A5PSW_CMD_CFG_TX_ENA           BIT(0)
+
+#define A5PSW_FRM_LENGTH(port)         (0x814 + A5PSW_PORT_OFFSET(port))
+#define A5PSW_FRM_LENGTH_MASK          GENMASK(13, 0)
+
+#define A5PSW_STATUS(port)             (0x840 + A5PSW_PORT_OFFSET(port))
+
+#define A5PSW_STATS_HIWORD             0x900
+
+/* Stats */
+#define A5PSW_aFramesTransmittedOK             0x868
+#define A5PSW_aFramesReceivedOK                        0x86C
+#define A5PSW_aFrameCheckSequenceErrors                0x870
+#define A5PSW_aAlignmentErrors                 0x874
+#define A5PSW_aOctetsTransmittedOK             0x878
+#define A5PSW_aOctetsReceivedOK                        0x87C
+#define A5PSW_aTxPAUSEMACCtrlFrames            0x880
+#define A5PSW_aRxPAUSEMACCtrlFrames            0x884
+/* If */
+#define A5PSW_ifInErrors                       0x888
+#define A5PSW_ifOutErrors                      0x88C
+#define A5PSW_ifInUcastPkts                    0x890
+#define A5PSW_ifInMulticastPkts                        0x894
+#define A5PSW_ifInBroadcastPkts                        0x898
+#define A5PSW_ifOutDiscards                    0x89C
+#define A5PSW_ifOutUcastPkts                   0x8A0
+#define A5PSW_ifOutMulticastPkts               0x8A4
+#define A5PSW_ifOutBroadcastPkts               0x8A8
+/* Ether */
+#define A5PSW_etherStatsDropEvents             0x8AC
+#define A5PSW_etherStatsOctets                 0x8B0
+#define A5PSW_etherStatsPkts                   0x8B4
+#define A5PSW_etherStatsUndersizePkts          0x8B8
+#define A5PSW_etherStatsOversizePkts           0x8BC
+#define A5PSW_etherStatsPkts64Octets           0x8C0
+#define A5PSW_etherStatsPkts65to127Octets      0x8C4
+#define A5PSW_etherStatsPkts128to255Octets     0x8C8
+#define A5PSW_etherStatsPkts256to511Octets     0x8CC
+#define A5PSW_etherStatsPkts512to1023Octets    0x8D0
+#define A5PSW_etherStatsPkts1024to1518Octets   0x8D4
+#define A5PSW_etherStatsPkts1519toXOctets      0x8D8
+#define A5PSW_etherStatsJabbers                        0x8DC
+#define A5PSW_etherStatsFragments              0x8E0
+
+#define A5PSW_VLANReceived                     0x8E8
+#define A5PSW_VLANTransmitted                  0x8EC
+
+#define A5PSW_aDeferred                                0x910
+#define A5PSW_aMultipleCollisions              0x914
+#define A5PSW_aSingleCollisions                        0x918
+#define A5PSW_aLateCollisions                  0x91C
+#define A5PSW_aExcessiveCollisions             0x920
+#define A5PSW_aCarrierSenseErrors              0x924
+
+#define A5PSW_VLAN_TAG(prio, id)       (((prio) << 12) | (id))
+#define A5PSW_PORTS_NUM                        5
+#define A5PSW_CPU_PORT                 (A5PSW_PORTS_NUM - 1)
+#define A5PSW_MDIO_DEF_FREQ            2500000
+#define A5PSW_MDIO_TIMEOUT             100
+#define A5PSW_JUMBO_LEN                        (10 * SZ_1K)
+#define A5PSW_MDIO_CLK_DIV_MIN         5
+#define A5PSW_TAG_LEN                  8
+#define A5PSW_VLAN_COUNT               32
+
+/* Ensure enough space for 2 VLAN tags */
+#define A5PSW_EXTRA_MTU_LEN            (A5PSW_TAG_LEN + 8)
+#define A5PSW_MAX_MTU                  (A5PSW_JUMBO_LEN - A5PSW_EXTRA_MTU_LEN)
+
+#define A5PSW_PATTERN_MGMTFWD          0
+
+#define A5PSW_LK_BUSY_USEC_POLL                10
+#define A5PSW_CTRL_TIMEOUT             1000
+#define A5PSW_TABLE_ENTRIES            8192
+
+struct fdb_entry {
+       u8 mac[ETH_ALEN];
+       u16 valid:1;
+       u16 is_static:1;
+       u16 prio:3;
+       u16 port_mask:5;
+       u16 reserved:6;
+} __packed;
+
+union lk_data {
+       struct {
+               u32 lo;
+               u32 hi;
+       };
+       struct fdb_entry entry;
+};
+
+/**
+ * struct a5psw - switch struct
+ * @base: Base address of the switch
+ * @hclk: hclk_switch clock
+ * @clk: clk_switch clock
+ * @dev: Device associated to the switch
+ * @mii_bus: MDIO bus struct
+ * @mdio_freq: MDIO bus frequency requested
+ * @pcs: Array of PCS connected to the switch ports (not for the CPU)
+ * @ds: DSA switch struct
+ * @stats_lock: lock to access statistics (shared HI counter)
+ * @lk_lock: Lock for the lookup table
+ * @reg_lock: Lock for register read-modify-write operation
+ * @bridged_ports: Mask of ports that are bridged and should be flooded
+ * @br_dev: Bridge net device
+ */
+struct a5psw {
+       void __iomem *base;
+       struct clk *hclk;
+       struct clk *clk;
+       struct device *dev;
+       struct mii_bus  *mii_bus;
+       struct phylink_pcs *pcs[A5PSW_PORTS_NUM - 1];
+       struct dsa_switch ds;
+       struct mutex lk_lock;
+       spinlock_t reg_lock;
+       u32 bridged_ports;
+       struct net_device *br_dev;
+};
index 72b6fc1..b253e27 100644 (file)
@@ -2330,7 +2330,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
                else
                        mode = MLO_AN_PHY;
 
-               rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode);
+               rc = xpcs_do_config(xpcs, priv->phy_mode[i], mode, NULL);
                if (rc < 0)
                        goto out;
 
index 557ca8f..ca3e470 100644 (file)
@@ -225,7 +225,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave)
        list_del(&slave->list);
        queue->num_slaves--;
        slave->dev->flags &= ~IFF_SLAVE;
-       dev_put_track(slave->dev, &slave->dev_tracker);
+       netdev_put(slave->dev, &slave->dev_tracker);
        kfree(slave);
 }
 
@@ -399,7 +399,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave)
                if (duplicate_slave)
                        eql_kill_one_slave(queue, duplicate_slave);
 
-               dev_hold_track(slave->dev, &slave->dev_tracker, GFP_ATOMIC);
+               netdev_hold(slave->dev, &slave->dev_tracker, GFP_ATOMIC);
                list_add(&slave->list, &queue->all_slaves);
                queue->num_slaves++;
                slave->dev->flags |= IFF_SLAVE;
index 955abbc..9a55c1d 100644 (file)
@@ -84,6 +84,7 @@ source "drivers/net/ethernet/huawei/Kconfig"
 source "drivers/net/ethernet/i825xx/Kconfig"
 source "drivers/net/ethernet/ibm/Kconfig"
 source "drivers/net/ethernet/intel/Kconfig"
+source "drivers/net/ethernet/wangxun/Kconfig"
 source "drivers/net/ethernet/xscale/Kconfig"
 
 config JME
index 9eb0116..c06e75e 100644 (file)
@@ -97,6 +97,7 @@ obj-$(CONFIG_NET_VENDOR_TOSHIBA) += toshiba/
 obj-$(CONFIG_NET_VENDOR_TUNDRA) += tundra/
 obj-$(CONFIG_NET_VENDOR_VERTEXCOM) += vertexcom/
 obj-$(CONFIG_NET_VENDOR_VIA) += via/
+obj-$(CONFIG_NET_VENDOR_WANGXUN) += wangxun/
 obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/
 obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
 obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
index fbf4588..d19d157 100644 (file)
@@ -1106,7 +1106,7 @@ static void et1310_config_rxmac_regs(struct et131x_adapter *adapter)
        writel(0, &rxmac->mif_ctrl);
        writel(0, &rxmac->space_avail);
 
-       /* Initialize the the mif_ctrl register
+       /* Initialize the mif_ctrl register
         * bit 3:  Receive code error. One or more nibbles were signaled as
         *         errors  during the reception of the packet.  Clear this
         *         bit in Gigabit, set it in 100Mbit.  This was derived
index b7d772f..3c2e32f 100644 (file)
@@ -3,11 +3,12 @@
  * Copyright (C) 2014 Altera Corporation. All rights reserved
  */
 
-#include <linux/kernel.h>
-
 #ifndef __ALTERA_UTILS_H__
 #define __ALTERA_UTILS_H__
 
+#include <linux/compiler.h>
+#include <linux/types.h>
+
 void tse_set_bit(void __iomem *ioaddr, size_t offs, u32 bit_mask);
 void tse_clear_bit(void __iomem *ioaddr, size_t offs, u32 bit_mask);
 int tse_bit_is_set(void __iomem *ioaddr, size_t offs, u32 bit_mask);
index 4d46780..f342bb8 100644 (file)
@@ -1673,12 +1673,10 @@ static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet)
                return ret;
 
        if (XGMAC_GET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES, VXLAN)) {
-               packet->header_len = skb_inner_transport_offset(skb) +
-                                    inner_tcp_hdrlen(skb);
+               packet->header_len = skb_inner_tcp_all_headers(skb);
                packet->tcp_header_len = inner_tcp_hdrlen(skb);
        } else {
-               packet->header_len = skb_transport_offset(skb) +
-                                    tcp_hdrlen(skb);
+               packet->header_len = skb_tcp_all_headers(skb);
                packet->tcp_header_len = tcp_hdrlen(skb);
        }
        packet->tcp_payload_len = skb->len - packet->header_len;
index d954755..b875c43 100644 (file)
@@ -417,7 +417,7 @@ struct xgbe_rx_ring_data {
 
 /* Structure used to hold information related to the descriptor
  * and the packet associated with the descriptor (always use
- * use the XGBE_GET_DESC_DATA macro to access this data from the ring)
+ * the XGBE_GET_DESC_DATA macro to access this data from the ring)
  */
 struct xgbe_ring_data {
        struct xgbe_ring_desc *rdesc;   /* Virtual address of descriptor */
index b6119dc..c2fda80 100644 (file)
@@ -158,7 +158,7 @@ struct aq_mss_egress_class_record {
         *  1: compare the SNAP header.
         *  If this bit is set to 1, the extracted filed will assume the
         *  SNAP header exist as encapsulated in 802.3 (RFC 1042). I.E. the
-        *  next 5 bytes after the the LLC header is SNAP header.
+        *  next 5 bytes after the LLC header is SNAP header.
         */
        u32 snap_mask;
        /*! 0: don't care and no LLC header exist.
@@ -422,7 +422,7 @@ struct aq_mss_ingress_preclass_record {
         *  1: compare the SNAP header.
         *  If this bit is set to 1, the extracted filed will assume the
         *  SNAP header exist as encapsulated in 802.3 (RFC 1042). I.E. the
-        *  next 5 bytes after the the LLC header is SNAP header.
+        *  next 5 bytes after the LLC header is SNAP header.
         */
        u32 snap_mask;
        /*! Mask is per-byte.
index cac5097..1c6ea67 100644 (file)
@@ -946,7 +946,7 @@ static unsigned int ag71xx_max_frame_len(unsigned int mtu)
        return ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
 }
 
-static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
+static void ag71xx_hw_set_macaddr(struct ag71xx *ag, const unsigned char *mac)
 {
        u32 t;
 
index 4945939..9485847 100644 (file)
@@ -2072,7 +2072,7 @@ static u16 atl1c_cal_tpd_req(const struct sk_buff *skb)
        tpd_req = skb_shinfo(skb)->nr_frags + 1;
 
        if (skb_is_gso(skb)) {
-               proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               proto_hdr_len = skb_tcp_all_headers(skb);
                if (proto_hdr_len < skb_headlen(skb))
                        tpd_req++;
                if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
@@ -2107,7 +2107,7 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter,
                        if (real_len < skb->len)
                                pskb_trim(skb, real_len);
 
-                       hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       hdr_len = skb_tcp_all_headers(skb);
                        if (unlikely(skb->len == hdr_len)) {
                                /* only xsum need */
                                if (netif_msg_tx_queued(adapter))
@@ -2132,7 +2132,7 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter,
                        *tpd = atl1c_get_tpd(adapter, queue);
                        ipv6_hdr(skb)->payload_len = 0;
                        /* check payload == 0 byte ? */
-                       hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       hdr_len = skb_tcp_all_headers(skb);
                        if (unlikely(skb->len == hdr_len)) {
                                /* only xsum need */
                                if (netif_msg_tx_queued(adapter))
@@ -2219,7 +2219,8 @@ static int atl1c_tx_map(struct atl1c_adapter *adapter,
        tso = (tpd->word1 >> TPD_LSO_EN_SHIFT) & TPD_LSO_EN_MASK;
        if (tso) {
                /* TSO */
-               map_len = hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
+               map_len = hdr_len;
                use_tpd = tpd;
 
                buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
@@ -2849,7 +2850,7 @@ static pci_ers_result_t atl1c_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;
 }
 
index 2068186..57a51fb 100644 (file)
@@ -1609,8 +1609,7 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb)
        if (skb_is_gso(skb)) {
                if (skb->protocol == htons(ETH_P_IP) ||
                   (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6)) {
-                       proto_hdr_len = skb_transport_offset(skb) +
-                                       tcp_hdrlen(skb);
+                       proto_hdr_len = skb_tcp_all_headers(skb);
                        if (proto_hdr_len < skb_headlen(skb)) {
                                tpd_req += ((skb_headlen(skb) - proto_hdr_len +
                                           MAX_TX_BUF_LEN - 1) >>
@@ -1645,7 +1644,7 @@ static int atl1e_tso_csum(struct atl1e_adapter *adapter,
                        if (real_len < skb->len)
                                pskb_trim(skb, real_len);
 
-                       hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       hdr_len = skb_tcp_all_headers(skb);
                        if (unlikely(skb->len == hdr_len)) {
                                /* only xsum need */
                                netdev_warn(adapter->netdev,
@@ -1713,7 +1712,8 @@ static int atl1e_tx_map(struct atl1e_adapter *adapter,
        segment = (tpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK;
        if (segment) {
                /* TSO */
-               map_len = hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
+               map_len = hdr_len;
                use_tpd = tpd;
 
                tx_buffer = atl1e_get_tx_buffer(adapter, use_tpd);
@@ -2482,7 +2482,7 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 
        pci_disable_device(pdev);
 
-       /* Request a slot slot reset. */
+       /* Request a slot reset. */
        return PCI_ERS_RESULT_NEED_RESET;
 }
 
index 6a96996..ff1fe09 100644 (file)
@@ -2115,7 +2115,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
                                ntohs(iph->tot_len));
                        if (real_len < skb->len)
                                pskb_trim(skb, real_len);
-                       hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       hdr_len = skb_tcp_all_headers(skb);
                        if (skb->len == hdr_len) {
                                iph->check = 0;
                                tcp_hdr(skb)->check =
@@ -2206,7 +2206,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
        retval = (ptpd->word3 >> TPD_SEGMENT_EN_SHIFT) & TPD_SEGMENT_EN_MASK;
        if (retval) {
                /* TSO */
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                buffer_info->length = hdr_len;
                page = virt_to_page(skb->data);
                offset = offset_in_page(skb->data);
@@ -2367,8 +2367,7 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
        mss = skb_shinfo(skb)->gso_size;
        if (mss) {
                if (skb->protocol == htons(ETH_P_IP)) {
-                       proto_hdr_len = (skb_transport_offset(skb) +
-                                        tcp_hdrlen(skb));
+                       proto_hdr_len = skb_tcp_all_headers(skb);
                        if (unlikely(proto_hdr_len > len)) {
                                dev_kfree_skb_any(skb);
                                return NETDEV_TX_OK;
index 698438a..514d61d 100644 (file)
@@ -388,7 +388,7 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
                                         priv->rx_buf_size, DMA_FROM_DEVICE);
                        priv->rx_buf[desc_idx] = NULL;
 
-                       skb = build_skb(buf, priv->rx_frag_size);
+                       skb = napi_build_skb(buf, priv->rx_frag_size);
                        if (unlikely(!skb)) {
                                skb_free_frag(buf);
                                dev->stats.rx_dropped++;
@@ -468,7 +468,7 @@ static int bcm_enet_tx_reclaim(struct net_device *dev, int force)
                        dev->stats.tx_errors++;
 
                bytes += skb->len;
-               dev_kfree_skb(skb);
+               napi_consume_skb(skb, !force);
                released++;
        }
 
index 5729a5a..712b559 100644 (file)
@@ -3421,12 +3421,9 @@ static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
 
                        /* Headers length */
                        if (xmit_type & XMIT_GSO_ENC)
-                               hlen = (int)(skb_inner_transport_header(skb) -
-                                            skb->data) +
-                                            inner_tcp_hdrlen(skb);
+                               hlen = skb_inner_tcp_all_headers(skb);
                        else
-                               hlen = (int)(skb_transport_header(skb) -
-                                            skb->data) + tcp_hdrlen(skb);
+                               hlen = skb_tcp_all_headers(skb);
 
                        /* Amount of data (w/o headers) on linear part of SKB*/
                        first_bd_sz = skb_headlen(skb) - hlen;
@@ -3534,15 +3531,13 @@ static u8 bnx2x_set_pbd_csum_enc(struct bnx2x *bp, struct sk_buff *skb,
                        ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
                        ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
 
-               return skb_inner_transport_header(skb) +
-                       inner_tcp_hdrlen(skb) - skb->data;
+               return skb_inner_tcp_all_headers(skb);
        }
 
        /* We support checksum offload for TCP and UDP only.
         * No need to pass the UDP header length - it's a constant.
         */
-       return skb_inner_transport_header(skb) +
-               sizeof(struct udphdr) - skb->data;
+       return skb_inner_transport_offset(skb) + sizeof(struct udphdr);
 }
 
 /**
@@ -3568,12 +3563,12 @@ static u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
                        ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
                        ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
 
-               return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
+               return skb_tcp_all_headers(skb);
        }
        /* We support checksum offload for TCP and UDP only.
         * No need to pass the UDP header length - it's a constant.
         */
-       return skb_transport_header(skb) + sizeof(struct udphdr) - skb->data;
+       return skb_transport_offset(skb) + sizeof(struct udphdr);
 }
 
 /* set FW indication according to inner or outer protocols if tunneled */
index 56b46b8..c74b2e4 100644 (file)
@@ -535,12 +535,9 @@ normal_tx:
                u32 hdr_len;
 
                if (skb->encapsulation)
-                       hdr_len = skb_inner_network_offset(skb) +
-                               skb_inner_network_header_len(skb) +
-                               inner_tcp_hdrlen(skb);
+                       hdr_len = skb_inner_tcp_all_headers(skb);
                else
-                       hdr_len = skb_transport_offset(skb) +
-                               tcp_hdrlen(skb);
+                       hdr_len = skb_tcp_all_headers(skb);
 
                txbd1->tx_bd_hsize_lflags |= cpu_to_le32(TX_BD_FLAGS_LSO |
                                        TX_BD_FLAGS_T_IPID |
@@ -4480,7 +4477,7 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool irq_reinit)
                }
        }
        if (irq_reinit) {
-               kfree(bp->ntp_fltr_bmap);
+               bitmap_free(bp->ntp_fltr_bmap);
                bp->ntp_fltr_bmap = NULL;
        }
        bp->ntp_fltr_count = 0;
@@ -4499,9 +4496,7 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp)
                INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]);
 
        bp->ntp_fltr_count = 0;
-       bp->ntp_fltr_bmap = kcalloc(BITS_TO_LONGS(BNXT_NTP_FLTR_MAX_FLTR),
-                                   sizeof(long),
-                                   GFP_KERNEL);
+       bp->ntp_fltr_bmap = bitmap_zalloc(BNXT_NTP_FLTR_MAX_FLTR, GFP_KERNEL);
 
        if (!bp->ntp_fltr_bmap)
                rc = -ENOMEM;
@@ -10658,7 +10653,7 @@ static void __bnxt_close_nic(struct bnxt *bp, bool irq_re_init,
        while (bnxt_drv_busy(bp))
                msleep(20);
 
-       /* Flush rings and and disable interrupts */
+       /* Flush rings and disable interrupts */
        bnxt_shutdown_nic(bp, irq_re_init);
 
        /* TODO CHIMP_FW: Link/PHY related cleanup if (link_re_init) */
index ddf2f39..c4ed436 100644 (file)
@@ -307,7 +307,7 @@ int bnxt_set_vf_bw(struct net_device *dev, int vf_id, int min_tx_rate,
                return -EINVAL;
        }
 
-       if (min_tx_rate > pf_link_speed || min_tx_rate > max_tx_rate) {
+       if (min_tx_rate > pf_link_speed) {
                netdev_info(bp->dev, "min tx rate %d is invalid for VF %d\n",
                            min_tx_rate, vf_id);
                return -EINVAL;
index f7f10cf..e86503d 100644 (file)
@@ -660,7 +660,7 @@ static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id,
        id_tbl->max = size;
        id_tbl->next = next;
        spin_lock_init(&id_tbl->lock);
-       id_tbl->table = kcalloc(BITS_TO_LONGS(size), sizeof(long), GFP_KERNEL);
+       id_tbl->table = bitmap_zalloc(size, GFP_KERNEL);
        if (!id_tbl->table)
                return -ENOMEM;
 
@@ -669,7 +669,7 @@ static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id,
 
 static void cnic_free_id_tbl(struct cnic_id_tbl *id_tbl)
 {
-       kfree(id_tbl->table);
+       bitmap_free(id_tbl->table);
        id_tbl->table = NULL;
 }
 
index c28f8cc..db1e9d8 100644 (file)
@@ -7944,7 +7944,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                iph = ip_hdr(skb);
                tcp_opt_len = tcp_optlen(skb);
 
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb) - ETH_HLEN;
+               hdr_len = skb_tcp_all_headers(skb) - ETH_HLEN;
 
                /* HW/FW can not correctly segment packets that have been
                 * vlan encapsulated.
index f6fe08d..29dd0f9 100644 (file)
@@ -2823,8 +2823,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                        BNAD_UPDATE_CTR(bnad, tx_skb_mss_too_long);
                        return -EINVAL;
                }
-               if (unlikely((gso_size + skb_transport_offset(skb) +
-                             tcp_hdrlen(skb)) >= skb->len)) {
+               if (unlikely((gso_size + skb_tcp_all_headers(skb)) >= skb->len)) {
                        txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
                        txqent->hdr.wi.lso_mss = 0;
                        BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short);
@@ -2872,8 +2871,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                                BNAD_UPDATE_CTR(bnad, tcpcsum_offload);
 
                                if (unlikely(skb_headlen(skb) <
-                                           skb_transport_offset(skb) +
-                                   tcp_hdrlen(skb))) {
+                                           skb_tcp_all_headers(skb))) {
                                        BNAD_UPDATE_CTR(bnad, tx_skb_tcp_hdr);
                                        return -EINVAL;
                                }
index d89098f..90a9798 100644 (file)
@@ -2267,7 +2267,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* only queue eth + ip headers separately for UDP */
                        hdrlen = skb_transport_offset(skb);
                else
-                       hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
+                       hdrlen = skb_tcp_all_headers(skb);
                if (skb_headlen(skb) < hdrlen) {
                        netdev_err(bp->dev, "Error - LSO headers fragmented!!!\n");
                        /* if this is required, would need to copy to single buffer */
@@ -4913,8 +4913,8 @@ static int macb_probe(struct platform_device *pdev)
 
        /* MTU range: 68 - 1500 or 10240 */
        dev->min_mtu = GEM_MTU_MIN_SIZE;
-       if (bp->caps & MACB_CAPS_JUMBO)
-               dev->max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN;
+       if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len)
+               dev->max_mtu = bp->jumbo_max_len - ETH_HLEN - ETH_FCS_LEN;
        else
                dev->max_mtu = ETH_DATA_LEN;
 
index 9559c16..e6cb20a 100644 (file)
@@ -434,7 +434,7 @@ int gem_get_hwtst(struct net_device *dev, struct ifreq *rq)
                return 0;
 }
 
-static int gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
+static void gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
 {
        u32 reg_val;
 
@@ -444,8 +444,6 @@ static int gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
                macb_writel(bp, NCR, reg_val | MACB_BIT(OSSMODE));
        else
                macb_writel(bp, NCR, reg_val & ~MACB_BIT(OSSMODE));
-
-       return 0;
 }
 
 int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -468,8 +466,7 @@ int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
        case HWTSTAMP_TX_OFF:
                break;
        case HWTSTAMP_TX_ONESTEP_SYNC:
-               if (gem_ptp_set_one_step_sync(bp, 1) != 0)
-                       return -ERANGE;
+               gem_ptp_set_one_step_sync(bp, 1);
                tx_bd_control = TSTAMP_ALL_FRAMES;
                break;
        case HWTSTAMP_TX_ON:
index 4367edb..06397cc 100644 (file)
@@ -1261,7 +1261,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq,
 static int nicvf_tso_count_subdescs(struct sk_buff *skb)
 {
        struct skb_shared_info *sh = skb_shinfo(skb);
-       unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       unsigned int sh_len = skb_tcp_all_headers(skb);
        unsigned int data_len = skb->len - sh_len;
        unsigned int p_len = sh->gso_size;
        long f_id = -1;    /* id of the current fragment */
@@ -1382,7 +1382,7 @@ nicvf_sq_add_hdr_subdesc(struct nicvf *nic, struct snd_queue *sq, int qentry,
 
        if (nic->hw_tso && skb_shinfo(skb)->gso_size) {
                hdr->tso = 1;
-               hdr->tso_start = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr->tso_start = skb_tcp_all_headers(skb);
                hdr->tso_max_paysize = skb_shinfo(skb)->gso_size;
                /* For non-tunneled pkts, point this to L2 ethertype */
                hdr->inner_l3_offset = skb_network_offset(skb) - 2;
index 4a872f3..7d52048 100644 (file)
@@ -85,7 +85,7 @@ static void cxgb4_dcb_cleanup_apps(struct net_device *dev)
 
                if (err) {
                        dev_err(adap->pdev_dev,
-                               "Failed DCB Clear %s Application Priority: sel=%d, prot=%d, err=%d\n",
+                               "Failed DCB Clear %s Application Priority: sel=%d, prot=%d, err=%d\n",
                                dcb_ver_array[dcb->dcb_version], app.selector,
                                app.protocol, -err);
                        break;
index 7d49fd4..14e0d98 100644 (file)
@@ -3429,18 +3429,18 @@ static ssize_t blocked_fl_write(struct file *filp, const char __user *ubuf,
        unsigned long *t;
        struct adapter *adap = filp->private_data;
 
-       t = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz), sizeof(long), GFP_KERNEL);
+       t = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
        if (!t)
                return -ENOMEM;
 
        err = bitmap_parse_user(ubuf, count, t, adap->sge.egr_sz);
        if (err) {
-               kfree(t);
+               bitmap_free(t);
                return err;
        }
 
        bitmap_copy(adap->sge.blocked_fl, t, adap->sge.egr_sz);
-       kfree(t);
+       bitmap_free(t);
        return count;
 }
 
index 6c790af..77897ed 100644 (file)
@@ -2227,7 +2227,7 @@ void cxgb4_cleanup_ethtool_filters(struct adapter *adap)
        if (eth_filter_info) {
                for (i = 0; i < adap->params.nports; i++) {
                        kvfree(eth_filter_info[i].loc_array);
-                       kfree(eth_filter_info[i].bmap);
+                       bitmap_free(eth_filter_info[i].bmap);
                }
                kfree(eth_filter_info);
        }
@@ -2270,9 +2270,7 @@ int cxgb4_init_ethtool_filters(struct adapter *adap)
                        goto free_eth_finfo;
                }
 
-               eth_filter->port[i].bmap = kcalloc(BITS_TO_LONGS(nentries),
-                                                  sizeof(unsigned long),
-                                                  GFP_KERNEL);
+               eth_filter->port[i].bmap = bitmap_zalloc(nentries, GFP_KERNEL);
                if (!eth_filter->port[i].bmap) {
                        ret = -ENOMEM;
                        goto free_eth_finfo;
@@ -2284,7 +2282,7 @@ int cxgb4_init_ethtool_filters(struct adapter *adap)
 
 free_eth_finfo:
        while (i-- > 0) {
-               kfree(eth_filter->port[i].bmap);
+               bitmap_free(eth_filter->port[i].bmap);
                kvfree(eth_filter->port[i].loc_array);
        }
        kfree(eth_filter_info);
index 0c78c0d..d006192 100644 (file)
@@ -5047,28 +5047,24 @@ static int adap_init0(struct adapter *adap, int vpd_skip)
        /* Allocate the memory for the vaious egress queue bitmaps
         * ie starving_fl, txq_maperr and blocked_fl.
         */
-       adap->sge.starving_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
-                                       sizeof(long), GFP_KERNEL);
+       adap->sge.starving_fl = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
        if (!adap->sge.starving_fl) {
                ret = -ENOMEM;
                goto bye;
        }
 
-       adap->sge.txq_maperr = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
-                                      sizeof(long), GFP_KERNEL);
+       adap->sge.txq_maperr = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
        if (!adap->sge.txq_maperr) {
                ret = -ENOMEM;
                goto bye;
        }
 
 #ifdef CONFIG_DEBUG_FS
-       adap->sge.blocked_fl = kcalloc(BITS_TO_LONGS(adap->sge.egr_sz),
-                                      sizeof(long), GFP_KERNEL);
+       adap->sge.blocked_fl = bitmap_zalloc(adap->sge.egr_sz, GFP_KERNEL);
        if (!adap->sge.blocked_fl) {
                ret = -ENOMEM;
                goto bye;
        }
-       bitmap_zero(adap->sge.blocked_fl, adap->sge.egr_sz);
 #endif
 
        params[0] = FW_PARAM_PFVF(CLIP_START);
@@ -5417,10 +5413,10 @@ bye:
        adap_free_hma_mem(adap);
        kfree(adap->sge.egr_map);
        kfree(adap->sge.ingr_map);
-       kfree(adap->sge.starving_fl);
-       kfree(adap->sge.txq_maperr);
+       bitmap_free(adap->sge.starving_fl);
+       bitmap_free(adap->sge.txq_maperr);
 #ifdef CONFIG_DEBUG_FS
-       kfree(adap->sge.blocked_fl);
+       bitmap_free(adap->sge.blocked_fl);
 #endif
        if (ret != -ETIMEDOUT && ret != -EIO)
                t4_fw_bye(adap, adap->mbox);
@@ -5854,8 +5850,7 @@ static int alloc_msix_info(struct adapter *adap, u32 num_vec)
        if (!msix_info)
                return -ENOMEM;
 
-       adap->msix_bmap.msix_bmap = kcalloc(BITS_TO_LONGS(num_vec),
-                                           sizeof(long), GFP_KERNEL);
+       adap->msix_bmap.msix_bmap = bitmap_zalloc(num_vec, GFP_KERNEL);
        if (!adap->msix_bmap.msix_bmap) {
                kfree(msix_info);
                return -ENOMEM;
@@ -5870,7 +5865,7 @@ static int alloc_msix_info(struct adapter *adap, u32 num_vec)
 
 static void free_msix_info(struct adapter *adap)
 {
-       kfree(adap->msix_bmap.msix_bmap);
+       bitmap_free(adap->msix_bmap.msix_bmap);
        kfree(adap->msix_info);
 }
 
@@ -6189,10 +6184,10 @@ static void free_some_resources(struct adapter *adapter)
        cxgb4_cleanup_ethtool_filters(adapter);
        kfree(adapter->sge.egr_map);
        kfree(adapter->sge.ingr_map);
-       kfree(adapter->sge.starving_fl);
-       kfree(adapter->sge.txq_maperr);
+       bitmap_free(adapter->sge.starving_fl);
+       bitmap_free(adapter->sge.txq_maperr);
 #ifdef CONFIG_DEBUG_FS
-       kfree(adapter->sge.blocked_fl);
+       bitmap_free(adapter->sge.blocked_fl);
 #endif
        disable_msi(adapter);
 
index f889f40..ee52e3b 100644 (file)
@@ -1531,7 +1531,7 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 
 #if IS_ENABLED(CONFIG_CHELSIO_TLS_DEVICE)
        if (cxgb4_is_ktls_skb(skb) &&
-           (skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb))))
+           (skb->len - skb_tcp_all_headers(skb)))
                return adap->uld[CXGB4_ULD_KTLS].tx_handler(skb, dev);
 #endif /* CHELSIO_TLS_DEVICE */
 
index 7de3800..c2822e6 100644 (file)
@@ -2859,7 +2859,7 @@ static const struct net_device_ops cxgb4vf_netdev_ops     = {
  *                             address stored on the adapter
  *     @adapter: The adapter
  *
- *     Find the the port mask for the VF based on the index of mac
+ *     Find the port mask for the VF based on the index of mac
  *     address stored in the adapter. If no mac address is stored on
  *     the adapter for the VF, use the port mask received from the
  *     firmware.
index d546993..1c52592 100644 (file)
@@ -877,7 +877,7 @@ int t4vf_get_sge_params(struct adapter *adapter)
 
        /* T4 uses a single control field to specify both the PCIe Padding and
         * Packing Boundary.  T5 introduced the ability to specify these
-        * separately with the Padding Boundary in SGE_CONTROL and and Packing
+        * separately with the Padding Boundary in SGE_CONTROL and Packing
         * Boundary in SGE_CONTROL2.  So for T5 and later we need to grab
         * SGE_CONTROL in order to determine how ingress packet data will be
         * laid out in Packed Buffer Mode.  Unfortunately, older versions of
index 60b648b..bfee0e4 100644 (file)
@@ -1012,7 +1012,7 @@ chcr_ktls_write_tcp_options(struct chcr_ktls_info *tx_info, struct sk_buff *skb,
        /* packet length = eth hdr len + ip hdr len + tcp hdr len
         * (including options).
         */
-       pktlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       pktlen = skb_tcp_all_headers(skb);
 
        ctrl = sizeof(*cpl) + pktlen;
        len16 = DIV_ROUND_UP(sizeof(*wr) + ctrl, 16);
@@ -1907,7 +1907,7 @@ static int chcr_ktls_sw_fallback(struct sk_buff *skb,
                return 0;
 
        th = tcp_hdr(nskb);
-       skb_offset =  skb_transport_offset(nskb) + tcp_hdrlen(nskb);
+       skb_offset = skb_tcp_all_headers(nskb);
        data_len = nskb->len - skb_offset;
        skb_tx_timestamp(nskb);
 
@@ -1938,7 +1938,7 @@ static int chcr_ktls_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned long flags;
 
        tcp_seq = ntohl(th->seq);
-       skb_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       skb_offset = skb_tcp_all_headers(skb);
        skb_data_len = skb->len - skb_offset;
        data_len = skb_data_len;
 
index 1c81b16..372fb7b 100644 (file)
@@ -680,11 +680,10 @@ static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
        skb_frag_t *frag;
 
        if (skb->encapsulation) {
-               hdr_len = skb_inner_transport_header(skb) - skb->data;
-               hdr_len += inner_tcp_hdrlen(skb);
+               hdr_len = skb_inner_tcp_all_headers(skb);
                enic_preload_tcp_csum_encap(skb);
        } else {
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                enic_preload_tcp_csum(skb);
        }
 
index cd4e243..414362f 100644 (file)
@@ -737,9 +737,9 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status)
 static int be_gso_hdr_len(struct sk_buff *skb)
 {
        if (skb->encapsulation)
-               return skb_inner_transport_offset(skb) +
-                      inner_tcp_hdrlen(skb);
-       return skb_transport_offset(skb) + tcp_hdrlen(skb);
+               return skb_inner_tcp_all_headers(skb);
+
+       return skb_tcp_all_headers(skb);
 }
 
 static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb)
@@ -3178,7 +3178,7 @@ static irqreturn_t be_intx(int irq, void *dev)
        }
        be_eq_notify(adapter, eqo->q.id, false, true, num_evts, 0);
 
-       /* Return IRQ_HANDLED only for the the first spurious intr
+       /* Return IRQ_HANDLED only for the first spurious intr
         * after a valid intr to stop the kernel from branding
         * this irq as a bad one!
         */
index a902751..e8e2aa1 100644 (file)
@@ -691,7 +691,7 @@ fec_enet_txq_put_hdr_tso(struct fec_enet_priv_tx_q *txq,
                         struct bufdesc *bdp, int index)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       int hdr_len = skb_tcp_all_headers(skb);
        struct bufdesc_ex *ebdp = container_of(bdp, struct bufdesc_ex, desc);
        void *bufaddr;
        unsigned long dmabuf;
index 5ff2634..cb419ae 100644 (file)
@@ -201,7 +201,7 @@ void fs_enet_platform_cleanup(void);
 
 /* access macros */
 #if defined(CONFIG_CPM1)
-/* for a CPM1 __raw_xxx's are sufficient */
+/* for a CPM1 __raw_xxx's are sufficient */
 #define __cbd_out32(addr, x)   __raw_writel(x, addr)
 #define __cbd_out16(addr, x)   __raw_writew(x, addr)
 #define __cbd_in32(addr)       __raw_readl(addr)
index 3dc9369..e7bf152 100644 (file)
@@ -1944,6 +1944,7 @@ static netdev_tx_t gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
        }
 
+       skb_tx_timestamp(skb);
        netdev_tx_sent_queue(txq, bytes_sent);
 
        gfar_wmb();
index 9a2c16d..81fb687 100644 (file)
@@ -1457,6 +1457,7 @@ static int gfar_get_ts_info(struct net_device *dev,
 
        if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)) {
                info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+                                       SOF_TIMESTAMPING_TX_SOFTWARE |
                                        SOF_TIMESTAMPING_SOFTWARE;
                return 0;
        }
@@ -1474,7 +1475,10 @@ static int gfar_get_ts_info(struct net_device *dev,
 
        info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
                                SOF_TIMESTAMPING_RX_HARDWARE |
-                               SOF_TIMESTAMPING_RAW_HARDWARE;
+                               SOF_TIMESTAMPING_RAW_HARDWARE |
+                               SOF_TIMESTAMPING_RX_SOFTWARE |
+                               SOF_TIMESTAMPING_TX_SOFTWARE |
+                               SOF_TIMESTAMPING_SOFTWARE;
        info->tx_types = (1 << HWTSTAMP_TX_OFF) |
                         (1 << HWTSTAMP_TX_ON);
        info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
index 257203e..f218196 100644 (file)
@@ -442,6 +442,7 @@ enum fun_port_lane_attr {
 };
 
 enum fun_admin_port_subop {
+       FUN_ADMIN_PORT_SUBOP_XCVR_READ = 0x23,
        FUN_ADMIN_PORT_SUBOP_INETADDR_EVENT = 0x24,
 };
 
@@ -595,6 +596,19 @@ struct fun_admin_port_req {
 
                        struct fun_admin_read48_req read48[];
                } read;
+               struct fun_admin_port_xcvr_read_req {
+                       u8 subop;
+                       u8 rsvd0;
+                       __be16 flags;
+                       __be32 id;
+
+                       u8 bank;
+                       u8 page;
+                       u8 offset;
+                       u8 length;
+                       u8 dev_addr;
+                       u8 rsvd1[3];
+               } xcvr_read;
                struct fun_admin_port_inetaddr_event_req {
                        __u8 subop;
                        __u8 rsvd0;
@@ -625,6 +639,15 @@ struct fun_admin_port_req {
                .id = cpu_to_be32(_id),                          \
        }
 
+#define FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(_flags, _id, _bank, _page,   \
+                                         _offset, _length, _dev_addr) \
+       ((struct fun_admin_port_xcvr_read_req) {                       \
+               .subop = FUN_ADMIN_PORT_SUBOP_XCVR_READ,               \
+               .flags = cpu_to_be16(_flags), .id = cpu_to_be32(_id),  \
+               .bank = (_bank), .page = (_page), .offset = (_offset), \
+               .length = (_length), .dev_addr = (_dev_addr),          \
+       })
+
 struct fun_admin_port_rsp {
        struct fun_admin_rsp_common common;
 
@@ -659,6 +682,23 @@ struct fun_admin_port_rsp {
        } u;
 };
 
+struct fun_admin_port_xcvr_read_rsp {
+       struct fun_admin_rsp_common common;
+
+       u8 subop;
+       u8 rsvd0[3];
+       __be32 id;
+
+       u8 bank;
+       u8 page;
+       u8 offset;
+       u8 length;
+       u8 dev_addr;
+       u8 rsvd1[3];
+
+       u8 data[128];
+};
+
 enum fun_xcvr_type {
        FUN_XCVR_BASET = 0x0,
        FUN_XCVR_CU = 0x1,
index d081168..31aa185 100644 (file)
@@ -78,6 +78,7 @@ static const char * const txq_stat_names[] = {
        "tx_cso",
        "tx_tso",
        "tx_encapsulated_tso",
+       "tx_uso",
        "tx_more",
        "tx_queue_stops",
        "tx_queue_restarts",
@@ -778,6 +779,7 @@ static void fun_get_ethtool_stats(struct net_device *netdev,
                ADD_STAT(txs.tx_cso);
                ADD_STAT(txs.tx_tso);
                ADD_STAT(txs.tx_encap_tso);
+               ADD_STAT(txs.tx_uso);
                ADD_STAT(txs.tx_more);
                ADD_STAT(txs.tx_nstops);
                ADD_STAT(txs.tx_nrestarts);
@@ -1116,6 +1118,39 @@ static int fun_set_fecparam(struct net_device *netdev,
        return fun_port_write_cmd(fp, FUN_ADMIN_PORT_KEY_FEC, fec_mode);
 }
 
+static int fun_get_port_module_page(struct net_device *netdev,
+                                   const struct ethtool_module_eeprom *req,
+                                   struct netlink_ext_ack *extack)
+{
+       union {
+               struct fun_admin_port_req req;
+               struct fun_admin_port_xcvr_read_rsp rsp;
+       } cmd;
+       struct funeth_priv *fp = netdev_priv(netdev);
+       int rc;
+
+       if (fp->port_caps & FUN_PORT_CAP_VPORT) {
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Specified port is virtual, only physical ports have modules");
+               return -EOPNOTSUPP;
+       }
+
+       cmd.req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_PORT,
+                                                   sizeof(cmd.req));
+       cmd.req.u.xcvr_read =
+               FUN_ADMIN_PORT_XCVR_READ_REQ_INIT(0, netdev->dev_port,
+                                                 req->bank, req->page,
+                                                 req->offset, req->length,
+                                                 req->i2c_address);
+       rc = fun_submit_admin_sync_cmd(fp->fdev, &cmd.req.common, &cmd.rsp,
+                                      sizeof(cmd.rsp), 0);
+       if (rc)
+               return rc;
+
+       memcpy(req->data, cmd.rsp.data, req->length);
+       return req->length;
+}
+
 static const struct ethtool_ops fun_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES,
@@ -1154,6 +1189,7 @@ static const struct ethtool_ops fun_ethtool_ops = {
        .get_eth_mac_stats   = fun_get_802_3_stats,
        .get_eth_ctrl_stats  = fun_get_802_3_ctrl_stats,
        .get_rmon_stats      = fun_get_rmon_stats,
+       .get_module_eeprom_by_page = fun_get_port_module_page,
 };
 
 void fun_set_ethtool_ops(struct net_device *netdev)
index 9485cf6..f247b7a 100644 (file)
@@ -1357,7 +1357,8 @@ static const struct net_device_ops fun_netdev_ops = {
 #define GSO_ENCAP_FLAGS (NETIF_F_GSO_GRE | NETIF_F_GSO_IPXIP4 | \
                         NETIF_F_GSO_IPXIP6 | NETIF_F_GSO_UDP_TUNNEL | \
                         NETIF_F_GSO_UDP_TUNNEL_CSUM)
-#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | \
+                  NETIF_F_GSO_UDP_L4)
 #define VLAN_FEAT (NETIF_F_SG | NETIF_F_HW_CSUM | TSO_FLAGS | \
                   GSO_ENCAP_FLAGS | NETIF_F_HIGHDMA)
 
index ff6e292..a97e3af 100644 (file)
@@ -83,7 +83,7 @@ static struct sk_buff *fun_tls_tx(struct sk_buff *skb, struct funeth_txq *q,
        const struct fun_ktls_tx_ctx *tls_ctx;
        u32 datalen, seq;
 
-       datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+       datalen = skb->len - skb_tcp_all_headers(skb);
        if (!datalen)
                return skb;
 
@@ -130,6 +130,7 @@ static unsigned int write_pkt_desc(struct sk_buff *skb, struct funeth_txq *q,
        struct fun_dataop_gl *gle;
        const struct tcphdr *th;
        unsigned int ngle, i;
+       unsigned int l4_hlen;
        u16 flags;
 
        if (unlikely(map_skb(skb, q->dma_dev, addrs, lens))) {
@@ -178,6 +179,7 @@ static unsigned int write_pkt_desc(struct sk_buff *skb, struct funeth_txq *q,
                                                 FUN_ETH_UPDATE_INNER_L3_LEN;
                        }
                        th = inner_tcp_hdr(skb);
+                       l4_hlen = __tcp_hdrlen(th);
                        fun_eth_offload_init(&req->offload, flags,
                                             shinfo->gso_size,
                                             tcp_hdr_doff_flags(th), 0,
@@ -185,6 +187,24 @@ static unsigned int write_pkt_desc(struct sk_buff *skb, struct funeth_txq *q,
                                             skb_inner_transport_offset(skb),
                                             skb_network_offset(skb), ol4_ofst);
                        FUN_QSTAT_INC(q, tx_encap_tso);
+               } else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
+                       flags = FUN_ETH_INNER_LSO | FUN_ETH_INNER_UDP |
+                               FUN_ETH_UPDATE_INNER_L4_CKSUM |
+                               FUN_ETH_UPDATE_INNER_L4_LEN |
+                               FUN_ETH_UPDATE_INNER_L3_LEN;
+
+                       if (ip_hdr(skb)->version == 4)
+                               flags |= FUN_ETH_UPDATE_INNER_L3_CKSUM;
+                       else
+                               flags |= FUN_ETH_INNER_IPV6;
+
+                       l4_hlen = sizeof(struct udphdr);
+                       fun_eth_offload_init(&req->offload, flags,
+                                            shinfo->gso_size,
+                                            cpu_to_be16(l4_hlen << 10), 0,
+                                            skb_network_offset(skb),
+                                            skb_transport_offset(skb), 0, 0);
+                       FUN_QSTAT_INC(q, tx_uso);
                } else {
                        /* HW considers one set of headers as inner */
                        flags = FUN_ETH_INNER_LSO |
@@ -195,6 +215,7 @@ static unsigned int write_pkt_desc(struct sk_buff *skb, struct funeth_txq *q,
                        else
                                flags |= FUN_ETH_UPDATE_INNER_L3_CKSUM;
                        th = tcp_hdr(skb);
+                       l4_hlen = __tcp_hdrlen(th);
                        fun_eth_offload_init(&req->offload, flags,
                                             shinfo->gso_size,
                                             tcp_hdr_doff_flags(th), 0,
@@ -209,7 +230,7 @@ static unsigned int write_pkt_desc(struct sk_buff *skb, struct funeth_txq *q,
 
                extra_pkts = shinfo->gso_segs - 1;
                extra_bytes = (be16_to_cpu(req->offload.inner_l4_off) +
-                              __tcp_hdrlen(th)) * extra_pkts;
+                              l4_hlen) * extra_pkts;
        } else if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
                flags = FUN_ETH_UPDATE_INNER_L4_CKSUM;
                if (skb->csum_offset == offsetof(struct udphdr, check))
index 04c9f91..1711f82 100644 (file)
@@ -82,6 +82,7 @@ struct funeth_txq_stats {  /* per Tx queue SW counters */
        u64 tx_cso;        /* # of packets with checksum offload */
        u64 tx_tso;        /* # of non-encapsulated TSO super-packets */
        u64 tx_encap_tso;  /* # of encapsulated TSO super-packets */
+       u64 tx_uso;        /* # of non-encapsulated UDP LSO super-packets */
        u64 tx_more;       /* # of DBs elided due to xmit_more */
        u64 tx_nstops;     /* # of times the queue has stopped */
        u64 tx_nrestarts;  /* # of times the queue has restarted */
index ec394d9..588d648 100644 (file)
@@ -386,7 +386,7 @@ static int gve_prep_tso(struct sk_buff *skb)
                                     (__force __wsum)htonl(paylen));
 
                /* Compute length of segmentation header. */
-               header_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               header_len = skb_tcp_all_headers(skb);
                break;
        default:
                return -EINVAL;
@@ -598,9 +598,9 @@ static int gve_num_buffer_descs_needed(const struct sk_buff *skb)
  */
 static bool gve_can_send_tso(const struct sk_buff *skb)
 {
-       const int header_len = skb_checksum_start_offset(skb) + tcp_hdrlen(skb);
        const int max_bufs_per_seg = GVE_TX_MAX_DATA_DESCS - 1;
        const struct skb_shared_info *shinfo = skb_shinfo(skb);
+       const int header_len = skb_tcp_all_headers(skb);
        const int gso_size = shinfo->gso_size;
        int cur_seg_num_bufs;
        int cur_seg_size;
@@ -795,7 +795,7 @@ static void gve_handle_packet_completion(struct gve_priv *priv,
                             GVE_PACKET_STATE_PENDING_REINJECT_COMPL)) {
                        /* No outstanding miss completion but packet allocated
                         * implies packet receives a re-injection completion
-                        * without a prior miss completion. Return without
+                        * without a prior miss completion. Return without
                         * completing the packet.
                         */
                        net_err_ratelimited("%s: Re-injection completion received without corresponding miss completion: %d\n",
index 2f0bd21..d94cc8c 100644 (file)
@@ -31,8 +31,6 @@
 #define HNS_BUFFER_SIZE_2048 2048
 
 #define BD_MAX_SEND_SIZE 8191
-#define SKB_TMP_LEN(SKB) \
-       (((SKB)->transport_header - (SKB)->mac_header) + tcp_hdrlen(SKB))
 
 static void fill_v2_desc_hw(struct hnae_ring *ring, void *priv, int size,
                            int send_sz, dma_addr_t dma, int frag_end,
@@ -94,7 +92,7 @@ static void fill_v2_desc_hw(struct hnae_ring *ring, void *priv, int size,
                                                     HNSV2_TXD_TSE_B, 1);
                                        l4_len = tcp_hdrlen(skb);
                                        mss = skb_shinfo(skb)->gso_size;
-                                       paylen = skb->len - SKB_TMP_LEN(skb);
+                                       paylen = skb->len - skb_tcp_all_headers(skb);
                                }
                        } else if (skb->protocol == htons(ETH_P_IPV6)) {
                                hnae_set_bit(tvsvsn, HNSV2_TXD_IPV6_B, 1);
@@ -108,7 +106,7 @@ static void fill_v2_desc_hw(struct hnae_ring *ring, void *priv, int size,
                                                     HNSV2_TXD_TSE_B, 1);
                                        l4_len = tcp_hdrlen(skb);
                                        mss = skb_shinfo(skb)->gso_size;
-                                       paylen = skb->len - SKB_TMP_LEN(skb);
+                                       paylen = skb->len - skb_tcp_all_headers(skb);
                                }
                        }
                        desc->tx.ip_offset = ip_offset;
index ae56306..35d7004 100644 (file)
@@ -1838,9 +1838,9 @@ static unsigned int hns3_tx_bd_num(struct sk_buff *skb, unsigned int *bd_size,
 static unsigned int hns3_gso_hdr_len(struct sk_buff *skb)
 {
        if (!skb->encapsulation)
-               return skb_transport_offset(skb) + tcp_hdrlen(skb);
+               return skb_tcp_all_headers(skb);
 
-       return skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb);
+       return skb_inner_tcp_all_headers(skb);
 }
 
 /* HW need every continuous max_non_tso_bd_num buffer data to be larger
index 5153e5d..b8a1ecb 100644 (file)
@@ -37,8 +37,7 @@ DECLARE_EVENT_CLASS(hns3_skb_template,
                __entry->gso_segs = skb_shinfo(skb)->gso_segs;
                __entry->gso_type = skb_shinfo(skb)->gso_type;
                __entry->hdr_len = skb->encapsulation ?
-               skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb) :
-               skb_transport_offset(skb) + tcp_hdrlen(skb);
+               skb_inner_tcp_all_headers(skb) : skb_tcp_all_headers(skb);
                __entry->ip_summed = skb->ip_summed;
                __entry->fraglist = skb_has_frag_list(skb);
                hns3_shinfo_pack(skb_shinfo(skb), __entry->size);
index 5eaf09e..26f8733 100644 (file)
@@ -979,7 +979,7 @@ static int hclgevf_update_mac_list(struct hnae3_handle *handle,
 
        /* if the mac addr is already in the mac list, no need to add a new
         * one into it, just check the mac addr state, convert it to a new
-        * new state, or just remove it, or do nothing.
+        * state, or just remove it, or do nothing.
         */
        mac_node = hclgevf_find_mac_node(list, addr);
        if (mac_node) {
index 07fdab5..c2ae1b4 100644 (file)
@@ -174,7 +174,7 @@ static int hns_mdio_wait_ready(struct mii_bus *bus)
        u32 cmd_reg_value;
        int i;
 
-       /* waitting for MDIO_COMMAND_REG 's mdio_start==0 */
+       /* waiting for MDIO_COMMAND_REG's mdio_start==0 */
        /* after that can do read or write*/
        for (i = 0; i < MDIO_TIMEOUT; i++) {
                cmd_reg_value = MDIO_GET_REG_BIT(mdio_dev,
@@ -319,7 +319,7 @@ static int hns_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
                                   MDIO_C45_READ, phy_id, devad);
        }
 
-       /* Step 5: waitting for MDIO_COMMAND_REG 's mdio_start==0,*/
+       /* Step 5: waiting for MDIO_COMMAND_REG's mdio_start==0,*/
        /* check for read or write opt is finished */
        ret = hns_mdio_wait_ready(bus);
        if (ret) {
index fb3e891..a4fbf44 100644 (file)
@@ -95,9 +95,6 @@ struct hinic_dev {
        u16                             sq_depth;
        u16                             rq_depth;
 
-       struct hinic_txq_stats          tx_stats;
-       struct hinic_rxq_stats          rx_stats;
-
        u8                              rss_tmpl_idx;
        u8                              rss_hash_engine;
        u16                             num_rss;
index 0532929..c23ee2d 100644 (file)
@@ -62,8 +62,6 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)");
 
 #define HINIC_LRO_RX_TIMER_DEFAULT     16
 
-#define VLAN_BITMAP_SIZE(nic_dev)       (ALIGN(VLAN_N_VID, 8) / 8)
-
 #define work_to_rx_mode_work(work)      \
                container_of(work, struct hinic_rx_mode_work, work)
 
@@ -82,56 +80,44 @@ static int set_features(struct hinic_dev *nic_dev,
                        netdev_features_t pre_features,
                        netdev_features_t features, bool force_change);
 
-static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq)
+static void gather_rx_stats(struct hinic_rxq_stats *nic_rx_stats, struct hinic_rxq *rxq)
 {
-       struct hinic_rxq_stats *nic_rx_stats = &nic_dev->rx_stats;
        struct hinic_rxq_stats rx_stats;
 
-       u64_stats_init(&rx_stats.syncp);
-
        hinic_rxq_get_stats(rxq, &rx_stats);
 
-       u64_stats_update_begin(&nic_rx_stats->syncp);
        nic_rx_stats->bytes += rx_stats.bytes;
        nic_rx_stats->pkts  += rx_stats.pkts;
        nic_rx_stats->errors += rx_stats.errors;
        nic_rx_stats->csum_errors += rx_stats.csum_errors;
        nic_rx_stats->other_errors += rx_stats.other_errors;
-       u64_stats_update_end(&nic_rx_stats->syncp);
-
-       hinic_rxq_clean_stats(rxq);
 }
 
-static void update_tx_stats(struct hinic_dev *nic_dev, struct hinic_txq *txq)
+static void gather_tx_stats(struct hinic_txq_stats *nic_tx_stats, struct hinic_txq *txq)
 {
-       struct hinic_txq_stats *nic_tx_stats = &nic_dev->tx_stats;
        struct hinic_txq_stats tx_stats;
 
-       u64_stats_init(&tx_stats.syncp);
-
        hinic_txq_get_stats(txq, &tx_stats);
 
-       u64_stats_update_begin(&nic_tx_stats->syncp);
        nic_tx_stats->bytes += tx_stats.bytes;
        nic_tx_stats->pkts += tx_stats.pkts;
        nic_tx_stats->tx_busy += tx_stats.tx_busy;
        nic_tx_stats->tx_wake += tx_stats.tx_wake;
        nic_tx_stats->tx_dropped += tx_stats.tx_dropped;
        nic_tx_stats->big_frags_pkts += tx_stats.big_frags_pkts;
-       u64_stats_update_end(&nic_tx_stats->syncp);
-
-       hinic_txq_clean_stats(txq);
 }
 
-static void update_nic_stats(struct hinic_dev *nic_dev)
+static void gather_nic_stats(struct hinic_dev *nic_dev,
+                            struct hinic_rxq_stats *nic_rx_stats,
+                            struct hinic_txq_stats *nic_tx_stats)
 {
        int i, num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);
 
        for (i = 0; i < num_qps; i++)
-               update_rx_stats(nic_dev, &nic_dev->rxqs[i]);
+               gather_rx_stats(nic_rx_stats, &nic_dev->rxqs[i]);
 
        for (i = 0; i < num_qps; i++)
-               update_tx_stats(nic_dev, &nic_dev->txqs[i]);
+               gather_tx_stats(nic_tx_stats, &nic_dev->txqs[i]);
 }
 
 /**
@@ -560,8 +546,6 @@ int hinic_close(struct net_device *netdev)
        netif_carrier_off(netdev);
        netif_tx_disable(netdev);
 
-       update_nic_stats(nic_dev);
-
        up(&nic_dev->mgmt_lock);
 
        if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
@@ -855,26 +839,19 @@ static void hinic_get_stats64(struct net_device *netdev,
                              struct rtnl_link_stats64 *stats)
 {
        struct hinic_dev *nic_dev = netdev_priv(netdev);
-       struct hinic_rxq_stats *nic_rx_stats;
-       struct hinic_txq_stats *nic_tx_stats;
-
-       nic_rx_stats = &nic_dev->rx_stats;
-       nic_tx_stats = &nic_dev->tx_stats;
-
-       down(&nic_dev->mgmt_lock);
+       struct hinic_rxq_stats nic_rx_stats = {};
+       struct hinic_txq_stats nic_tx_stats = {};
 
        if (nic_dev->flags & HINIC_INTF_UP)
-               update_nic_stats(nic_dev);
-
-       up(&nic_dev->mgmt_lock);
+               gather_nic_stats(nic_dev, &nic_rx_stats, &nic_tx_stats);
 
-       stats->rx_bytes   = nic_rx_stats->bytes;
-       stats->rx_packets = nic_rx_stats->pkts;
-       stats->rx_errors  = nic_rx_stats->errors;
+       stats->rx_bytes   = nic_rx_stats.bytes;
+       stats->rx_packets = nic_rx_stats.pkts;
+       stats->rx_errors  = nic_rx_stats.errors;
 
-       stats->tx_bytes   = nic_tx_stats->bytes;
-       stats->tx_packets = nic_tx_stats->pkts;
-       stats->tx_errors  = nic_tx_stats->tx_dropped;
+       stats->tx_bytes   = nic_tx_stats.bytes;
+       stats->tx_packets = nic_tx_stats.pkts;
+       stats->tx_errors  = nic_tx_stats.tx_dropped;
 }
 
 static int hinic_set_features(struct net_device *netdev,
@@ -1173,8 +1150,6 @@ static void hinic_free_intr_coalesce(struct hinic_dev *nic_dev)
 static int nic_dev_init(struct pci_dev *pdev)
 {
        struct hinic_rx_mode_work *rx_mode_work;
-       struct hinic_txq_stats *tx_stats;
-       struct hinic_rxq_stats *rx_stats;
        struct hinic_dev *nic_dev;
        struct net_device *netdev;
        struct hinic_hwdev *hwdev;
@@ -1236,15 +1211,8 @@ static int nic_dev_init(struct pci_dev *pdev)
 
        sema_init(&nic_dev->mgmt_lock, 1);
 
-       tx_stats = &nic_dev->tx_stats;
-       rx_stats = &nic_dev->rx_stats;
-
-       u64_stats_init(&tx_stats->syncp);
-       u64_stats_init(&rx_stats->syncp);
-
-       nic_dev->vlan_bitmap = devm_kzalloc(&pdev->dev,
-                                           VLAN_BITMAP_SIZE(nic_dev),
-                                           GFP_KERNEL);
+       nic_dev->vlan_bitmap = devm_bitmap_zalloc(&pdev->dev, VLAN_N_VID,
+                                                 GFP_KERNEL);
        if (!nic_dev->vlan_bitmap) {
                err = -ENOMEM;
                goto err_vlan_bitmap;
index 24b7b81..a866bea 100644 (file)
@@ -73,7 +73,6 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
        struct hinic_rxq_stats *rxq_stats = &rxq->rxq_stats;
        unsigned int start;
 
-       u64_stats_update_begin(&stats->syncp);
        do {
                start = u64_stats_fetch_begin(&rxq_stats->syncp);
                stats->pkts = rxq_stats->pkts;
@@ -83,7 +82,6 @@ void hinic_rxq_get_stats(struct hinic_rxq *rxq, struct hinic_rxq_stats *stats)
                stats->csum_errors = rxq_stats->csum_errors;
                stats->other_errors = rxq_stats->other_errors;
        } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
-       u64_stats_update_end(&stats->syncp);
 }
 
 /**
index 01e7d3c..df55584 100644 (file)
@@ -852,12 +852,6 @@ int hinic_ndo_set_vf_bw(struct net_device *netdev,
                return -EINVAL;
        }
 
-       if (max_tx_rate < min_tx_rate) {
-               netif_err(nic_dev, drv, netdev, "Max rate %d must be greater than or equal to min rate %d\n",
-                         max_tx_rate, min_tx_rate);
-               return -EINVAL;
-       }
-
        err = hinic_port_link_state(nic_dev, &link_state);
        if (err) {
                netif_err(nic_dev, drv, netdev,
index 87408e7..5051cdf 100644 (file)
@@ -98,7 +98,6 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats)
        struct hinic_txq_stats *txq_stats = &txq->txq_stats;
        unsigned int start;
 
-       u64_stats_update_begin(&stats->syncp);
        do {
                start = u64_stats_fetch_begin(&txq_stats->syncp);
                stats->pkts    = txq_stats->pkts;
@@ -108,7 +107,6 @@ void hinic_txq_get_stats(struct hinic_txq *txq, struct hinic_txq_stats *stats)
                stats->tx_dropped = txq_stats->tx_dropped;
                stats->big_frags_pkts = txq_stats->big_frags_pkts;
        } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
-       u64_stats_update_end(&stats->syncp);
 }
 
 /**
index 8ce3348..5dc3028 100644 (file)
@@ -1617,7 +1617,7 @@ static void write_swqe2_immediate(struct sk_buff *skb, struct ehea_swqe *swqe,
                 * For TSO packets we only copy the headers into the
                 * immediate area.
                 */
-               immediate_len = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
+               immediate_len = skb_tcp_all_headers(skb);
        }
 
        if (skb_is_gso(skb) || skb_data_size >= SWQE2_MAX_IMM) {
index 36418b5..11a884a 100644 (file)
@@ -1430,7 +1430,6 @@ static int e100_phy_check_without_mii(struct nic *nic)
 #define MII_NSC_CONG           MII_RESV1
 #define NSC_CONG_ENABLE                0x0100
 #define NSC_CONG_TXREADY       0x0400
-#define ADVERTISE_FC_SUPPORTED 0x0400
 static int e100_phy_init(struct nic *nic)
 {
        struct net_device *netdev = nic->netdev;
index 1042e79..4542e2b 100644 (file)
@@ -2000,7 +2000,7 @@ s32 e1000_force_mac_fc(struct e1000_hw *hw)
         *      1:  Rx flow control is enabled (we can receive pause
         *          frames but not send pause frames).
         *      2:  Tx flow control is enabled (we can send pause frames
-        *          frames but we do not receive pause frames).
+        *          but we do not receive pause frames).
         *      3:  Both Rx and TX flow control (symmetric) is enabled.
         *  other:  No other values should be possible at this point.
         */
@@ -4376,7 +4376,7 @@ void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
 /**
  * e1000_write_vfta - Writes a value to the specified offset in the VLAN filter table.
  * @hw: Struct containing variables accessed by shared code
- * @offset: Offset in VLAN filer table to write
+ * @offset: Offset in VLAN filter table to write
  * @value: Value to write into VLAN filter table
  */
 void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
@@ -4396,7 +4396,7 @@ void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
 }
 
 /**
- * e1000_clear_vfta - Clears the VLAN filer table
+ * e1000_clear_vfta - Clears the VLAN filter table
  * @hw: Struct containing variables accessed by shared code
  */
 static void e1000_clear_vfta(struct e1000_hw *hw)
index 3f5feb5..23299fc 100644 (file)
@@ -2708,7 +2708,7 @@ static int e1000_tso(struct e1000_adapter *adapter,
                if (err < 0)
                        return err;
 
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                mss = skb_shinfo(skb)->gso_size;
                if (protocol == htons(ETH_P_IP)) {
                        struct iphdr *iph = ip_hdr(skb);
@@ -3139,7 +3139,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
                max_per_txd = min(mss << 2, max_per_txd);
                max_txd_pwr = fls(max_per_txd) - 1;
 
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                if (skb->data_len && hdr_len == len) {
                        switch (hw->mac_type) {
                        case e1000_82544: {
index 4d4f5bf..f4154ca 100644 (file)
@@ -82,7 +82,6 @@ E1000_PARAM(Duplex, "Duplex setting");
  */
 E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
 #define AUTONEG_ADV_DEFAULT  0x2F
-#define AUTONEG_ADV_MASK     0x2F
 
 /* User Specified Flow Control Override
  *
@@ -95,7 +94,6 @@ E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
  * Default Value: Read flow control settings from the EEPROM
  */
 E1000_PARAM(FlowControl, "Flow Control setting");
-#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
 
 /* XsumRX - Receive Checksum Offload Enable/Disable
  *
index 51512a7..5df7ad9 100644 (file)
@@ -957,7 +957,7 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw)
         *      1:  Rx flow control is enabled (we can receive pause
         *          frames but not send pause frames).
         *      2:  Tx flow control is enabled (we can send pause frames
-        *          frames but we do not receive pause frames).
+        *          but we do not receive pause frames).
         *      3:  Both Rx and Tx flow control (symmetric) is enabled.
         *  other:  No other values should be possible at this point.
         */
index fa06f68..38e60de 100644 (file)
@@ -5474,7 +5474,7 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       hdr_len = skb_tcp_all_headers(skb);
        mss = skb_shinfo(skb)->gso_size;
        if (protocol == htons(ETH_P_IP)) {
                struct iphdr *iph = ip_hdr(skb);
@@ -5846,7 +5846,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
                 * points to just header, pull a few bytes of payload from
                 * frags into skb->data
                 */
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                /* we do this workaround for ES2LAN, but it is un-necessary,
                 * avoiding it could save a lot of cycles
                 */
index ebe121d..3132d8f 100644 (file)
@@ -101,8 +101,6 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
  * demoted to the most advanced interrupt mode available.
  */
 E1000_PARAM(IntMode, "Interrupt Mode");
-#define MAX_INTMODE    2
-#define MIN_INTMODE    0
 
 /* Enable Smart Power Down of the PHY
  *
index 30ca9ee..87fa587 100644 (file)
@@ -809,7 +809,7 @@ static s32 fm10k_mbx_read(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
  *  @hw: pointer to hardware structure
  *  @mbx: pointer to mailbox
  *
- *  This function copies the message from the the message array to mbmem
+ *  This function copies the message from the message array to mbmem
  **/
 static void fm10k_mbx_write(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx)
 {
@@ -1825,7 +1825,7 @@ static void fm10k_sm_mbx_process_error(struct fm10k_mbx_info *mbx)
                fm10k_sm_mbx_connect_reset(mbx);
                break;
        case FM10K_STATE_CONNECT:
-               /* try connnecting at lower version */
+               /* try connecting at lower version */
                if (mbx->remote) {
                        while (mbx->local > 1)
                                mbx->local--;
index f6d5686..75cbdf2 100644 (file)
@@ -78,7 +78,7 @@ static s32 fm10k_tlv_attr_put_null_string(u32 *msg, u16 attr_id,
  *  @string: Pointer to location of destination string
  *
  *  This function pulls the string back out of the attribute and will place
- *  it in the array pointed by by string.  It will return success if provided
+ *  it in the array pointed by string.  It will return success if provided
  *  with a valid pointers.
  **/
 static s32 fm10k_tlv_attr_get_null_string(u32 *attr, unsigned char *string)
@@ -584,7 +584,7 @@ s32 fm10k_tlv_msg_parse(struct fm10k_hw *hw, u32 *msg,
  *  @mbx: Unused mailbox pointer
  *
  *  This function is a default handler for unrecognized messages.  At a
- *  minimum it just indicates that the message requested was
+ *  minimum it just indicates that the message requested was
  *  unimplemented.
  **/
 s32 fm10k_tlv_msg_error(struct fm10k_hw __always_unused *hw,
index 407fe8f..97c574a 100644 (file)
@@ -566,6 +566,7 @@ struct i40e_pf {
 #define I40E_FLAG_DISABLE_FW_LLDP              BIT(24)
 #define I40E_FLAG_RS_FEC                       BIT(25)
 #define I40E_FLAG_BASE_R_FEC                   BIT(26)
+#define I40E_FLAG_VF_VLAN_PRUNING              BIT(27)
 /* TOTAL_PORT_SHUTDOWN
  * Allows to physically disable the link on the NIC's port.
  * If enabled, (after link down request from the OS)
index 19704f5..d9a934c 100644 (file)
@@ -236,8 +236,6 @@ static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[],
        I40E_STAT(struct i40e_cp_veb_tc_stats, _name, _stat)
 #define I40E_PFC_STAT(_name, _stat) \
        I40E_STAT(struct i40e_pfc_stats, _name, _stat)
-#define I40E_QUEUE_STAT(_name, _stat) \
-       I40E_STAT(struct i40e_ring, _name, _stat)
 
 static const struct i40e_stats i40e_gstrings_net_stats[] = {
        I40E_NETDEV_STAT(rx_packets),
@@ -457,6 +455,8 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = {
        I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_DISABLE_FW_LLDP, 0),
        I40E_PRIV_FLAG("rs-fec", I40E_FLAG_RS_FEC, 0),
        I40E_PRIV_FLAG("base-r-fec", I40E_FLAG_BASE_R_FEC, 0),
+       I40E_PRIV_FLAG("vf-vlan-pruning",
+                      I40E_FLAG_VF_VLAN_PRUNING, 0),
 };
 
 #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags)
@@ -1141,6 +1141,71 @@ static int i40e_get_link_ksettings(struct net_device *netdev,
        return 0;
 }
 
+#define I40E_LBIT_SIZE 8
+/**
+ * i40e_speed_to_link_speed - Translate decimal speed to i40e_aq_link_speed
+ * @speed: speed in decimal
+ * @ks: ethtool ksettings
+ *
+ * Return i40e_aq_link_speed based on speed
+ **/
+static enum i40e_aq_link_speed
+i40e_speed_to_link_speed(__u32 speed, const struct ethtool_link_ksettings *ks)
+{
+       enum i40e_aq_link_speed link_speed = I40E_LINK_SPEED_UNKNOWN;
+       bool speed_changed = false;
+       int i, j;
+
+       static const struct {
+               __u32 speed;
+               enum i40e_aq_link_speed link_speed;
+               __u8 bit[I40E_LBIT_SIZE];
+       } i40e_speed_lut[] = {
+#define I40E_LBIT(mode) ETHTOOL_LINK_MODE_ ## mode ##_Full_BIT
+               {SPEED_100, I40E_LINK_SPEED_100MB, {I40E_LBIT(100baseT)} },
+               {SPEED_1000, I40E_LINK_SPEED_1GB,
+                {I40E_LBIT(1000baseT), I40E_LBIT(1000baseX),
+                 I40E_LBIT(1000baseKX)} },
+               {SPEED_10000, I40E_LINK_SPEED_10GB,
+                {I40E_LBIT(10000baseT), I40E_LBIT(10000baseKR),
+                 I40E_LBIT(10000baseLR), I40E_LBIT(10000baseCR),
+                 I40E_LBIT(10000baseSR), I40E_LBIT(10000baseKX4)} },
+
+               {SPEED_25000, I40E_LINK_SPEED_25GB,
+                {I40E_LBIT(25000baseCR), I40E_LBIT(25000baseKR),
+                 I40E_LBIT(25000baseSR)} },
+               {SPEED_40000, I40E_LINK_SPEED_40GB,
+                {I40E_LBIT(40000baseKR4), I40E_LBIT(40000baseCR4),
+                 I40E_LBIT(40000baseSR4), I40E_LBIT(40000baseLR4)} },
+               {SPEED_20000, I40E_LINK_SPEED_20GB,
+                {I40E_LBIT(20000baseKR2)} },
+               {SPEED_2500, I40E_LINK_SPEED_2_5GB, {I40E_LBIT(2500baseT)} },
+               {SPEED_5000, I40E_LINK_SPEED_5GB, {I40E_LBIT(2500baseT)} }
+#undef I40E_LBIT
+};
+
+       for (i = 0; i < ARRAY_SIZE(i40e_speed_lut); i++) {
+               if (i40e_speed_lut[i].speed == speed) {
+                       for (j = 0; j < I40E_LBIT_SIZE; j++) {
+                               if (test_bit(i40e_speed_lut[i].bit[j],
+                                            ks->link_modes.supported)) {
+                                       speed_changed = true;
+                                       break;
+                               }
+                               if (!i40e_speed_lut[i].bit[j])
+                                       break;
+                       }
+                       if (speed_changed) {
+                               link_speed = i40e_speed_lut[i].link_speed;
+                               break;
+                       }
+               }
+       }
+       return link_speed;
+}
+
+#undef I40E_LBIT_SIZE
+
 /**
  * i40e_set_link_ksettings - Set Speed and Duplex
  * @netdev: network interface device structure
@@ -1157,12 +1222,14 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
        struct ethtool_link_ksettings copy_ks;
        struct i40e_aq_set_phy_config config;
        struct i40e_pf *pf = np->vsi->back;
+       enum i40e_aq_link_speed link_speed;
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_hw *hw = &pf->hw;
        bool autoneg_changed = false;
        i40e_status status = 0;
        int timeout = 50;
        int err = 0;
+       __u32 speed;
        u8 autoneg;
 
        /* Changing port settings is not supported if this isn't the
@@ -1195,6 +1262,7 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
 
        /* save autoneg out of ksettings */
        autoneg = copy_ks.base.autoneg;
+       speed = copy_ks.base.speed;
 
        /* get our own copy of the bits to check against */
        memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings));
@@ -1213,6 +1281,7 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
 
        /* set autoneg back to what it currently is */
        copy_ks.base.autoneg = safe_ks.base.autoneg;
+       copy_ks.base.speed  = safe_ks.base.speed;
 
        /* If copy_ks.base and safe_ks.base are not the same now, then they are
         * trying to set something that we do not support.
@@ -1329,6 +1398,27 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
                                                  40000baseLR4_Full))
                config.link_speed |= I40E_LINK_SPEED_40GB;
 
+       /* Autonegotiation must be disabled to change speed */
+       if ((speed != SPEED_UNKNOWN && safe_ks.base.speed != speed) &&
+           (autoneg == AUTONEG_DISABLE ||
+           (safe_ks.base.autoneg == AUTONEG_DISABLE && !autoneg_changed))) {
+               link_speed = i40e_speed_to_link_speed(speed, ks);
+               if (link_speed == I40E_LINK_SPEED_UNKNOWN) {
+                       netdev_info(netdev, "Given speed is not supported\n");
+                       err = -EOPNOTSUPP;
+                       goto done;
+               } else {
+                       config.link_speed = link_speed;
+               }
+       } else {
+               if (safe_ks.base.speed != speed) {
+                       netdev_info(netdev,
+                                   "Unable to set speed, disable autoneg\n");
+                       err = -EOPNOTSUPP;
+                       goto done;
+               }
+       }
+
        /* If speed didn't get set, set it to what it currently is.
         * This is needed because if advertise is 0 (as it is when autoneg
         * is disabled) then speed won't get set.
@@ -5294,6 +5384,13 @@ flags_complete:
                return -EOPNOTSUPP;
        }
 
+       if ((changed_flags & I40E_FLAG_VF_VLAN_PRUNING) &&
+           pf->num_alloc_vfs) {
+               dev_warn(&pf->pdev->dev,
+                        "Changing vf-vlan-pruning flag while VF(s) are active is not supported\n");
+               return -EOPNOTSUPP;
+       }
+
        if ((changed_flags & new_flags &
             I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
            (new_flags & I40E_FLAG_MFP_ENABLED))
index aa786fd..151e9b6 100644 (file)
@@ -1442,6 +1442,114 @@ static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
 }
 
 /**
+ * i40e_get_vf_new_vlan - Get new vlan id on a vf
+ * @vsi: the vsi to configure
+ * @new_mac: new mac filter to be added
+ * @f: existing mac filter, replaced with new_mac->f if new_mac is not NULL
+ * @vlan_filters: the number of active VLAN filters
+ * @trusted: flag if the VF is trusted
+ *
+ * Get new VLAN id based on current VLAN filters, trust, PVID
+ * and vf-vlan-prune-disable flag.
+ *
+ * Returns the value of the new vlan filter or
+ * the old value if no new filter is needed.
+ */
+static s16 i40e_get_vf_new_vlan(struct i40e_vsi *vsi,
+                               struct i40e_new_mac_filter *new_mac,
+                               struct i40e_mac_filter *f,
+                               int vlan_filters,
+                               bool trusted)
+{
+       s16 pvid = le16_to_cpu(vsi->info.pvid);
+       struct i40e_pf *pf = vsi->back;
+       bool is_any;
+
+       if (new_mac)
+               f = new_mac->f;
+
+       if (pvid && f->vlan != pvid)
+               return pvid;
+
+       is_any = (trusted ||
+                 !(pf->flags & I40E_FLAG_VF_VLAN_PRUNING));
+
+       if ((vlan_filters && f->vlan == I40E_VLAN_ANY) ||
+           (!is_any && !vlan_filters && f->vlan == I40E_VLAN_ANY) ||
+           (is_any && !vlan_filters && f->vlan == 0)) {
+               if (is_any)
+                       return I40E_VLAN_ANY;
+               else
+                       return 0;
+       }
+
+       return f->vlan;
+}
+
+/**
+ * i40e_correct_vf_mac_vlan_filters - Correct non-VLAN VF filters if necessary
+ * @vsi: the vsi to configure
+ * @tmp_add_list: list of filters ready to be added
+ * @tmp_del_list: list of filters ready to be deleted
+ * @vlan_filters: the number of active VLAN filters
+ * @trusted: flag if the VF is trusted
+ *
+ * Correct VF VLAN filters based on current VLAN filters, trust, PVID
+ * and vf-vlan-prune-disable flag.
+ *
+ * In case of memory allocation failure return -ENOMEM. Otherwise, return 0.
+ *
+ * This function is only expected to be called from within
+ * i40e_sync_vsi_filters.
+ *
+ * NOTE: This function expects to be called while under the
+ * mac_filter_hash_lock
+ */
+static int i40e_correct_vf_mac_vlan_filters(struct i40e_vsi *vsi,
+                                           struct hlist_head *tmp_add_list,
+                                           struct hlist_head *tmp_del_list,
+                                           int vlan_filters,
+                                           bool trusted)
+{
+       struct i40e_mac_filter *f, *add_head;
+       struct i40e_new_mac_filter *new_mac;
+       struct hlist_node *h;
+       int bkt, new_vlan;
+
+       hlist_for_each_entry(new_mac, tmp_add_list, hlist) {
+               new_mac->f->vlan = i40e_get_vf_new_vlan(vsi, new_mac, NULL,
+                                                       vlan_filters, trusted);
+       }
+
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
+               new_vlan = i40e_get_vf_new_vlan(vsi, NULL, f, vlan_filters,
+                                               trusted);
+               if (new_vlan != f->vlan) {
+                       add_head = i40e_add_filter(vsi, f->macaddr, new_vlan);
+                       if (!add_head)
+                               return -ENOMEM;
+                       /* Create a temporary i40e_new_mac_filter */
+                       new_mac = kzalloc(sizeof(*new_mac), GFP_ATOMIC);
+                       if (!new_mac)
+                               return -ENOMEM;
+                       new_mac->f = add_head;
+                       new_mac->state = add_head->state;
+
+                       /* Add the new filter to the tmp list */
+                       hlist_add_head(&new_mac->hlist, tmp_add_list);
+
+                       /* Put the original filter into the delete list */
+                       f->state = I40E_FILTER_REMOVE;
+                       hash_del(&f->hlist);
+                       hlist_add_head(&f->hlist, tmp_del_list);
+               }
+       }
+
+       vsi->has_vlan_filter = !!vlan_filters;
+       return 0;
+}
+
+/**
  * i40e_rm_default_mac_filter - Remove the default MAC filter set by NVM
  * @vsi: the PF Main VSI - inappropriate for any other VSI
  * @macaddr: the MAC address
@@ -2496,10 +2604,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                                vlan_filters++;
                }
 
-               retval = i40e_correct_mac_vlan_filters(vsi,
-                                                      &tmp_add_list,
-                                                      &tmp_del_list,
-                                                      vlan_filters);
+               if (vsi->type != I40E_VSI_SRIOV)
+                       retval = i40e_correct_mac_vlan_filters
+                               (vsi, &tmp_add_list, &tmp_del_list,
+                                vlan_filters);
+               else
+                       retval = i40e_correct_vf_mac_vlan_filters
+                               (vsi, &tmp_add_list, &tmp_del_list,
+                                vlan_filters, pf->vf[vsi->vf_id].trusted);
 
                hlist_for_each_entry(new, &tmp_add_list, hlist)
                        netdev_hw_addr_refcnt(new->f, vsi->netdev, 1);
@@ -2928,8 +3040,21 @@ int i40e_add_vlan_all_mac(struct i40e_vsi *vsi, s16 vid)
        int bkt;
 
        hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
-               if (f->state == I40E_FILTER_REMOVE)
+               /* If we're asked to add a filter that has been marked for
+                * removal, it is safe to simply restore it to active state.
+                * __i40e_del_filter will have simply deleted any filters which
+                * were previously marked NEW or FAILED, so if it is currently
+                * marked REMOVE it must have previously been ACTIVE. Since we
+                * haven't yet run the sync filters task, just restore this
+                * filter to the ACTIVE state so that the sync task leaves it
+                * in place.
+                */
+               if (f->state == I40E_FILTER_REMOVE && f->vlan == vid) {
+                       f->state = I40E_FILTER_ACTIVE;
+                       continue;
+               } else if (f->state == I40E_FILTER_REMOVE) {
                        continue;
+               }
                add_f = i40e_add_filter(vsi, f->macaddr, vid);
                if (!add_f) {
                        dev_info(&vsi->back->pdev->dev,
@@ -4110,7 +4235,6 @@ static void i40e_free_misc_vector(struct i40e_pf *pf)
        i40e_flush(&pf->hw);
 
        if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
-               synchronize_irq(pf->msix_entries[0].vector);
                free_irq(pf->msix_entries[0].vector, pf);
                clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
        }
@@ -4849,7 +4973,6 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
                        irq_set_affinity_notifier(irq_num, NULL);
                        /* remove our suggested affinity mask for this IRQ */
                        irq_update_affinity_hint(irq_num, NULL);
-                       synchronize_irq(irq_num);
                        free_irq(irq_num, vsi->q_vectors[i]);
 
                        /* Tear down the interrupt queue link list
@@ -13106,7 +13229,7 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb,
        }
 
        /* No need to validate L4LEN as TCP is the only protocol with a
-        * flexible value and we support all possible values supported
+        * flexible value and we support all possible values supported
         * by TCP, which is at most 15 dwords
         */
 
index 61e5789..57a71fa 100644 (file)
@@ -27,7 +27,6 @@
 #define I40E_PRTTSYN_CTL1_TSYNTYPE_V2  (2 << \
                                        I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
 #define I40E_SUBDEV_ID_25G_PTP_PIN     0xB
-#define to_dev(obj) container_of(obj, struct device, kobj)
 
 enum i40e_ptp_pin {
        SDP3_2 = 0,
index 7bc1174..f6ba97a 100644 (file)
@@ -372,7 +372,6 @@ static void i40e_change_filter_num(bool ipv4, bool add, u16 *ipv4_filter_num,
        }
 }
 
-#define IP_HEADER_OFFSET               14
 #define I40E_UDPIP_DUMMY_PACKET_LEN    42
 #define I40E_UDPIP6_DUMMY_PACKET_LEN   62
 /**
@@ -1483,10 +1482,8 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
        if (!rx_ring->rx_bi)
                return;
 
-       if (rx_ring->skb) {
-               dev_kfree_skb(rx_ring->skb);
-               rx_ring->skb = NULL;
-       }
+       dev_kfree_skb(rx_ring->skb);
+       rx_ring->skb = NULL;
 
        if (rx_ring->xsk_pool) {
                i40e_xsk_clean_rx_ring(rx_ring);
@@ -2291,16 +2288,14 @@ int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp, struct i40e_ring *xdp_ring)
  * i40e_run_xdp - run an XDP program
  * @rx_ring: Rx ring being processed
  * @xdp: XDP buffer containing the frame
+ * @xdp_prog: XDP program to run
  **/
-static int i40e_run_xdp(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
+static int i40e_run_xdp(struct i40e_ring *rx_ring, struct xdp_buff *xdp, struct bpf_prog *xdp_prog)
 {
        int err, result = I40E_XDP_PASS;
        struct i40e_ring *xdp_ring;
-       struct bpf_prog *xdp_prog;
        u32 act;
 
-       xdp_prog = READ_ONCE(rx_ring->xdp_prog);
-
        if (!xdp_prog)
                goto xdp_out;
 
@@ -2445,6 +2440,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        unsigned int offset = rx_ring->rx_offset;
        struct sk_buff *skb = rx_ring->skb;
        unsigned int xdp_xmit = 0;
+       struct bpf_prog *xdp_prog;
        bool failure = false;
        struct xdp_buff xdp;
        int xdp_res = 0;
@@ -2454,6 +2450,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
 #endif
        xdp_init_buff(&xdp, frame_sz, &rx_ring->xdp_rxq);
 
+       xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+
        while (likely(total_rx_packets < (unsigned int)budget)) {
                struct i40e_rx_buffer *rx_buffer;
                union i40e_rx_desc *rx_desc;
@@ -2509,11 +2507,12 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                        hard_start = page_address(rx_buffer->page) +
                                     rx_buffer->page_offset - offset;
                        xdp_prepare_buff(&xdp, hard_start, offset, size, true);
+                       xdp_buff_clear_frags_flag(&xdp);
 #if (PAGE_SIZE > 4096)
                        /* At larger PAGE_SIZE, frame_sz depend on len size */
                        xdp.frame_sz = i40e_rx_frame_truesize(rx_ring, size);
 #endif
-                       xdp_res = i40e_run_xdp(rx_ring, &xdp);
+                       xdp_res = i40e_run_xdp(rx_ring, &xdp, xdp_prog);
                }
 
                if (xdp_res) {
@@ -3713,35 +3712,55 @@ u16 i40e_lan_select_queue(struct net_device *netdev,
 static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf,
                              struct i40e_ring *xdp_ring)
 {
-       u16 i = xdp_ring->next_to_use;
-       struct i40e_tx_buffer *tx_bi;
-       struct i40e_tx_desc *tx_desc;
+       struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);
+       u8 nr_frags = unlikely(xdp_frame_has_frags(xdpf)) ? sinfo->nr_frags : 0;
+       u16 i = 0, index = xdp_ring->next_to_use;
+       struct i40e_tx_buffer *tx_head = &xdp_ring->tx_bi[index];
+       struct i40e_tx_buffer *tx_bi = tx_head;
+       struct i40e_tx_desc *tx_desc = I40E_TX_DESC(xdp_ring, index);
        void *data = xdpf->data;
        u32 size = xdpf->len;
-       dma_addr_t dma;
 
-       if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) {
+       if (unlikely(I40E_DESC_UNUSED(xdp_ring) < 1 + nr_frags)) {
                xdp_ring->tx_stats.tx_busy++;
                return I40E_XDP_CONSUMED;
        }
-       dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE);
-       if (dma_mapping_error(xdp_ring->dev, dma))
-               return I40E_XDP_CONSUMED;
 
-       tx_bi = &xdp_ring->tx_bi[i];
-       tx_bi->bytecount = size;
-       tx_bi->gso_segs = 1;
-       tx_bi->xdpf = xdpf;
+       tx_head->bytecount = xdp_get_frame_len(xdpf);
+       tx_head->gso_segs = 1;
+       tx_head->xdpf = xdpf;
 
-       /* record length, and DMA address */
-       dma_unmap_len_set(tx_bi, len, size);
-       dma_unmap_addr_set(tx_bi, dma, dma);
+       for (;;) {
+               dma_addr_t dma;
 
-       tx_desc = I40E_TX_DESC(xdp_ring, i);
-       tx_desc->buffer_addr = cpu_to_le64(dma);
-       tx_desc->cmd_type_offset_bsz = build_ctob(I40E_TX_DESC_CMD_ICRC
-                                                 | I40E_TXD_CMD,
-                                                 0, size, 0);
+               dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE);
+               if (dma_mapping_error(xdp_ring->dev, dma))
+                       goto unmap;
+
+               /* record length, and DMA address */
+               dma_unmap_len_set(tx_bi, len, size);
+               dma_unmap_addr_set(tx_bi, dma, dma);
+
+               tx_desc->buffer_addr = cpu_to_le64(dma);
+               tx_desc->cmd_type_offset_bsz =
+                       build_ctob(I40E_TX_DESC_CMD_ICRC, 0, size, 0);
+
+               if (++index == xdp_ring->count)
+                       index = 0;
+
+               if (i == nr_frags)
+                       break;
+
+               tx_bi = &xdp_ring->tx_bi[index];
+               tx_desc = I40E_TX_DESC(xdp_ring, index);
+
+               data = skb_frag_address(&sinfo->frags[i]);
+               size = skb_frag_size(&sinfo->frags[i]);
+               i++;
+       }
+
+       tx_desc->cmd_type_offset_bsz |=
+               cpu_to_le64(I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
 
        /* Make certain all of the status bits have been updated
         * before next_to_watch is written.
@@ -3749,14 +3768,30 @@ static int i40e_xmit_xdp_ring(struct xdp_frame *xdpf,
        smp_wmb();
 
        xdp_ring->xdp_tx_active++;
-       i++;
-       if (i == xdp_ring->count)
-               i = 0;
 
-       tx_bi->next_to_watch = tx_desc;
-       xdp_ring->next_to_use = i;
+       tx_head->next_to_watch = tx_desc;
+       xdp_ring->next_to_use = index;
 
        return I40E_XDP_TX;
+
+unmap:
+       for (;;) {
+               tx_bi = &xdp_ring->tx_bi[index];
+               if (dma_unmap_len(tx_bi, len))
+                       dma_unmap_page(xdp_ring->dev,
+                                      dma_unmap_addr(tx_bi, dma),
+                                      dma_unmap_len(tx_bi, len),
+                                      DMA_TO_DEVICE);
+               dma_unmap_len_set(tx_bi, len, 0);
+               if (tx_bi == tx_head)
+                       break;
+
+               if (!index)
+                       index += xdp_ring->count;
+               index--;
+       }
+
+       return I40E_XDP_CONSUMED;
 }
 
 /**
index 86b0f21..4f184c5 100644 (file)
@@ -4353,6 +4353,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
                /* duplicate request, so just return success */
                goto error_pvid;
 
+       i40e_vlan_stripping_enable(vsi);
        i40e_vc_reset_vf(vf, true);
        /* During reset the VF got a new VSI, so refresh a pointer. */
        vsi = pf->vsi[vf->lan_vsi_idx];
@@ -4368,7 +4369,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
         * MAC addresses deleted.
         */
        if ((!(vlan_id || qos) ||
-           vlanprio != le16_to_cpu(vsi->info.pvid)) &&
+            vlanprio != le16_to_cpu(vsi->info.pvid)) &&
            vsi->info.pvid) {
                ret = i40e_add_vlan_all_mac(vsi, I40E_VLAN_ANY);
                if (ret) {
@@ -4731,6 +4732,11 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
                goto out;
 
        vf->trusted = setting;
+
+       /* request PF to sync mac/vlan filters for the VF */
+       set_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state);
+       pf->vsi[vf->lan_vsi_idx]->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+
        i40e_vc_reset_vf(vf, true);
        dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
                 vf_id, setting ? "" : "un");
index af3e7e6..6d4009e 100644 (file)
@@ -143,20 +143,17 @@ int i40e_xsk_pool_setup(struct i40e_vsi *vsi, struct xsk_buff_pool *pool,
  * i40e_run_xdp_zc - Executes an XDP program on an xdp_buff
  * @rx_ring: Rx ring
  * @xdp: xdp_buff used as input to the XDP program
+ * @xdp_prog: XDP program to run
  *
  * Returns any of I40E_XDP_{PASS, CONSUMED, TX, REDIR}
  **/
-static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)
+static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp,
+                          struct bpf_prog *xdp_prog)
 {
        int err, result = I40E_XDP_PASS;
        struct i40e_ring *xdp_ring;
-       struct bpf_prog *xdp_prog;
        u32 act;
 
-       /* NB! xdp_prog will always be !NULL, due to the fact that
-        * this path is enabled by setting an XDP program.
-        */
-       xdp_prog = READ_ONCE(rx_ring->xdp_prog);
        act = bpf_prog_run_xdp(xdp_prog, xdp);
 
        if (likely(act == XDP_REDIRECT)) {
@@ -339,9 +336,15 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
        u16 next_to_clean = rx_ring->next_to_clean;
        u16 count_mask = rx_ring->count - 1;
        unsigned int xdp_res, xdp_xmit = 0;
+       struct bpf_prog *xdp_prog;
        bool failure = false;
        u16 cleaned_count;
 
+       /* NB! xdp_prog will always be !NULL, due to the fact that
+        * this path is enabled by setting an XDP program.
+        */
+       xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+
        while (likely(total_rx_packets < (unsigned int)budget)) {
                union i40e_rx_desc *rx_desc;
                unsigned int rx_packets;
@@ -378,7 +381,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
                xsk_buff_set_size(bi, size);
                xsk_buff_dma_sync_for_cpu(bi, rx_ring->xsk_pool);
 
-               xdp_res = i40e_run_xdp_zc(rx_ring, bi);
+               xdp_res = i40e_run_xdp_zc(rx_ring, bi, xdp_prog);
                i40e_handle_xdp_result_zc(rx_ring, bi, rx_desc, &rx_packets,
                                          &rx_bytes, size, xdp_res, &failure);
                if (failure)
index 49aed3e..fda1198 100644 (file)
@@ -146,7 +146,8 @@ struct iavf_mac_filter {
                u8 remove:1;        /* filter needs to be removed */
                u8 add:1;           /* filter needs to be added */
                u8 is_primary:1;    /* filter is a default VF MAC */
-               u8 padding:4;
+               u8 add_handled:1;   /* received response for filter add */
+               u8 padding:3;
        };
 };
 
@@ -248,6 +249,7 @@ struct iavf_adapter {
        struct work_struct adminq_task;
        struct delayed_work client_task;
        wait_queue_head_t down_waitqueue;
+       wait_queue_head_t vc_waitqueue;
        struct iavf_q_vector *q_vectors;
        struct list_head vlan_filter_list;
        struct list_head mac_filter_list;
@@ -292,6 +294,7 @@ struct iavf_adapter {
 #define IAVF_FLAG_QUEUES_DISABLED              BIT(17)
 #define IAVF_FLAG_SETUP_NETDEV_FEATURES                BIT(18)
 #define IAVF_FLAG_REINIT_MSIX_NEEDED           BIT(20)
+#define IAVF_FLAG_INITIAL_MAC_SET              BIT(23)
 /* duplicates for common code */
 #define IAVF_FLAG_DCB_ENABLED                  0
        /* flags for admin queue service task */
@@ -559,6 +562,8 @@ void iavf_enable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
 void iavf_disable_vlan_stripping_v2(struct iavf_adapter *adapter, u16 tpid);
 void iavf_enable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
 void iavf_disable_vlan_insertion_v2(struct iavf_adapter *adapter, u16 tpid);
+int iavf_replace_primary_mac(struct iavf_adapter *adapter,
+                            const u8 *new_mac);
 void
 iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
                               netdev_features_t prev_features,
index f3ecb3b..69ade65 100644 (file)
@@ -983,6 +983,7 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
 
                list_add_tail(&f->list, &adapter->mac_filter_list);
                f->add = true;
+               f->add_handled = false;
                f->is_new_mac = true;
                f->is_primary = ether_addr_equal(macaddr, adapter->hw.mac.addr);
                adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
@@ -994,47 +995,132 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter,
 }
 
 /**
- * iavf_set_mac - NDO callback to set port mac address
- * @netdev: network interface device structure
- * @p: pointer to an address structure
+ * iavf_replace_primary_mac - Replace current primary address
+ * @adapter: board private structure
+ * @new_mac: new MAC address to be applied
  *
- * Returns 0 on success, negative on failure
+ * Replace current dev_addr and send request to PF for removal of previous
+ * primary MAC address filter and addition of new primary MAC filter.
+ * Return 0 for success, -ENOMEM for failure.
+ *
+ * Do not call this with mac_vlan_list_lock!
  **/
-static int iavf_set_mac(struct net_device *netdev, void *p)
+int iavf_replace_primary_mac(struct iavf_adapter *adapter,
+                            const u8 *new_mac)
 {
-       struct iavf_adapter *adapter = netdev_priv(netdev);
        struct iavf_hw *hw = &adapter->hw;
        struct iavf_mac_filter *f;
-       struct sockaddr *addr = p;
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EADDRNOTAVAIL;
-
-       if (ether_addr_equal(netdev->dev_addr, addr->sa_data))
-               return 0;
 
        spin_lock_bh(&adapter->mac_vlan_list_lock);
 
+       list_for_each_entry(f, &adapter->mac_filter_list, list) {
+               f->is_primary = false;
+       }
+
        f = iavf_find_filter(adapter, hw->mac.addr);
        if (f) {
                f->remove = true;
-               f->is_primary = true;
                adapter->aq_required |= IAVF_FLAG_AQ_DEL_MAC_FILTER;
        }
 
-       f = iavf_add_filter(adapter, addr->sa_data);
+       f = iavf_add_filter(adapter, new_mac);
+
        if (f) {
+               /* Always send the request to add if changing primary MAC
+                * even if filter is already present on the list
+                */
                f->is_primary = true;
-               ether_addr_copy(hw->mac.addr, addr->sa_data);
+               f->add = true;
+               adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER;
+               ether_addr_copy(hw->mac.addr, new_mac);
        }
 
        spin_unlock_bh(&adapter->mac_vlan_list_lock);
 
        /* schedule the watchdog task to immediately process the request */
-       if (f)
+       if (f) {
                queue_work(iavf_wq, &adapter->watchdog_task.work);
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/**
+ * iavf_is_mac_set_handled - wait for a response to set MAC from PF
+ * @netdev: network interface device structure
+ * @macaddr: MAC address to set
+ *
+ * Returns true on success, false on failure
+ */
+static bool iavf_is_mac_set_handled(struct net_device *netdev,
+                                   const u8 *macaddr)
+{
+       struct iavf_adapter *adapter = netdev_priv(netdev);
+       struct iavf_mac_filter *f;
+       bool ret = false;
+
+       spin_lock_bh(&adapter->mac_vlan_list_lock);
+
+       f = iavf_find_filter(adapter, macaddr);
 
-       return (f == NULL) ? -ENOMEM : 0;
+       if (!f || (!f->add && f->add_handled))
+               ret = true;
+
+       spin_unlock_bh(&adapter->mac_vlan_list_lock);
+
+       return ret;
+}
+
+/**
+ * iavf_set_mac - NDO callback to set port MAC address
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int iavf_set_mac(struct net_device *netdev, void *p)
+{
+       struct iavf_adapter *adapter = netdev_priv(netdev);
+       struct sockaddr *addr = p;
+       bool handle_mac = iavf_is_mac_set_handled(netdev, addr->sa_data);
+       int ret;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       ret = iavf_replace_primary_mac(adapter, addr->sa_data);
+
+       if (ret)
+               return ret;
+
+       /* If this is an initial set MAC during VF spawn do not wait */
+       if (adapter->flags & IAVF_FLAG_INITIAL_MAC_SET) {
+               adapter->flags &= ~IAVF_FLAG_INITIAL_MAC_SET;
+               return 0;
+       }
+
+       if (handle_mac)
+               goto done;
+
+       ret = wait_event_interruptible_timeout(adapter->vc_waitqueue, false, msecs_to_jiffies(2500));
+
+       /* If ret < 0 then it means wait was interrupted.
+        * If ret == 0 then it means we got a timeout.
+        * else it means we got response for set MAC from PF,
+        * check if netdev MAC was updated to requested MAC,
+        * if yes then set MAC succeeded otherwise it failed return -EACCES
+        */
+       if (ret < 0)
+               return ret;
+
+       if (!ret)
+               return -EAGAIN;
+
+done:
+       if (!ether_addr_equal(netdev->dev_addr, addr->sa_data))
+               return -EACCES;
+
+       return 0;
 }
 
 /**
@@ -2451,6 +2537,8 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
                ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr);
        }
 
+       adapter->flags |= IAVF_FLAG_INITIAL_MAC_SET;
+
        adapter->tx_desc_count = IAVF_DEFAULT_TXD;
        adapter->rx_desc_count = IAVF_DEFAULT_RXD;
        err = iavf_init_interrupt_scheme(adapter);
@@ -4162,7 +4250,7 @@ static netdev_features_t iavf_features_check(struct sk_buff *skb,
        }
 
        /* No need to validate L4LEN as TCP is the only protocol with a
-        * flexible value and we support all possible values supported
+        * flexible value and we support all possible values supported
         * by TCP, which is at most 15 dwords
         */
 
@@ -4681,6 +4769,9 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Setup the wait queue for indicating transition to down status */
        init_waitqueue_head(&adapter->down_waitqueue);
 
+       /* Setup the wait queue for indicating virtchannel events */
+       init_waitqueue_head(&adapter->vc_waitqueue);
+
        return 0;
 
 err_ioremap:
index 782450d..0d22bba 100644 (file)
@@ -5,10 +5,6 @@
 #include "iavf_prototype.h"
 #include "iavf_client.h"
 
-/* busy wait delay in msec */
-#define IAVF_BUSY_WAIT_DELAY 10
-#define IAVF_BUSY_WAIT_COUNT 50
-
 /**
  * iavf_send_pf_msg
  * @adapter: adapter structure
@@ -598,6 +594,8 @@ static void iavf_mac_add_ok(struct iavf_adapter *adapter)
        spin_lock_bh(&adapter->mac_vlan_list_lock);
        list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) {
                f->is_new_mac = false;
+               if (!f->add && !f->add_handled)
+                       f->add_handled = true;
        }
        spin_unlock_bh(&adapter->mac_vlan_list_lock);
 }
@@ -618,6 +616,9 @@ static void iavf_mac_add_reject(struct iavf_adapter *adapter)
                if (f->remove && ether_addr_equal(f->macaddr, netdev->dev_addr))
                        f->remove = false;
 
+               if (!f->add && !f->add_handled)
+                       f->add_handled = true;
+
                if (f->is_new_mac) {
                        list_del(&f->list);
                        kfree(f);
@@ -1932,6 +1933,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                        iavf_mac_add_reject(adapter);
                        /* restore administratively set MAC address */
                        ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
+                       wake_up(&adapter->vc_waitqueue);
                        break;
                case VIRTCHNL_OP_DEL_VLAN:
                        dev_err(&adapter->pdev->dev, "Failed to delete VLAN filter, error %s\n",
@@ -2091,7 +2093,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                if (!v_retval)
                        iavf_mac_add_ok(adapter);
                if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr))
-                       eth_hw_addr_set(netdev, adapter->hw.mac.addr);
+                       if (!ether_addr_equal(netdev->dev_addr,
+                                             adapter->hw.mac.addr)) {
+                               netif_addr_lock_bh(netdev);
+                               eth_hw_addr_set(netdev, adapter->hw.mac.addr);
+                               netif_addr_unlock_bh(netdev);
+                       }
+               wake_up(&adapter->vc_waitqueue);
                break;
        case VIRTCHNL_OP_GET_STATS: {
                struct iavf_eth_stats *stats =
@@ -2121,10 +2129,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                        /* restore current mac address */
                        ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr);
                } else {
+                       netif_addr_lock_bh(netdev);
                        /* refresh current mac address if changed */
-                       eth_hw_addr_set(netdev, adapter->hw.mac.addr);
                        ether_addr_copy(netdev->perm_addr,
                                        adapter->hw.mac.addr);
+                       netif_addr_unlock_bh(netdev);
                }
                spin_lock_bh(&adapter->mac_vlan_list_lock);
                iavf_add_filter(adapter, adapter->hw.mac.addr);
@@ -2160,6 +2169,10 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                }
                fallthrough;
        case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS: {
+               struct iavf_mac_filter *f;
+               bool was_mac_changed;
+               u64 aq_required = 0;
+
                if (v_opcode == VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS)
                        memcpy(&adapter->vlan_v2_caps, msg,
                               min_t(u16, msglen,
@@ -2167,6 +2180,46 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
 
                iavf_process_config(adapter);
                adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
+               was_mac_changed = !ether_addr_equal(netdev->dev_addr,
+                                                   adapter->hw.mac.addr);
+
+               spin_lock_bh(&adapter->mac_vlan_list_lock);
+
+               /* re-add all MAC filters */
+               list_for_each_entry(f, &adapter->mac_filter_list, list) {
+                       if (was_mac_changed &&
+                           ether_addr_equal(netdev->dev_addr, f->macaddr))
+                               ether_addr_copy(f->macaddr,
+                                               adapter->hw.mac.addr);
+
+                       f->is_new_mac = true;
+                       f->add = true;
+                       f->add_handled = false;
+                       f->remove = false;
+               }
+
+               /* re-add all VLAN filters */
+               if (VLAN_FILTERING_ALLOWED(adapter)) {
+                       struct iavf_vlan_filter *vlf;
+
+                       if (!list_empty(&adapter->vlan_filter_list)) {
+                               list_for_each_entry(vlf,
+                                                   &adapter->vlan_filter_list,
+                                                   list)
+                                       vlf->add = true;
+
+                               aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER;
+                       }
+               }
+
+               spin_unlock_bh(&adapter->mac_vlan_list_lock);
+
+               netif_addr_lock_bh(netdev);
+               eth_hw_addr_set(netdev, adapter->hw.mac.addr);
+               netif_addr_unlock_bh(netdev);
+
+               adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER |
+                       aq_required;
                }
                break;
        case VIRTCHNL_OP_ENABLE_QUEUES:
index 5d10c4f..ead6d50 100644 (file)
@@ -852,7 +852,7 @@ ice_create_init_fdir_rule(struct ice_pf *pf, enum ice_fltr_ptype flow)
        if (!seg)
                return -ENOMEM;
 
-       tun_seg = devm_kcalloc(dev, sizeof(*seg), ICE_FD_HW_SEG_MAX,
+       tun_seg = devm_kcalloc(dev, ICE_FD_HW_SEG_MAX, sizeof(*tun_seg),
                               GFP_KERNEL);
        if (!tun_seg) {
                devm_kfree(dev, seg);
@@ -1214,7 +1214,7 @@ ice_cfg_fdir_xtrct_seq(struct ice_pf *pf, struct ethtool_rx_flow_spec *fsp,
        if (!seg)
                return -ENOMEM;
 
-       tun_seg = devm_kcalloc(dev, sizeof(*seg), ICE_FD_HW_SEG_MAX,
+       tun_seg = devm_kcalloc(dev, ICE_FD_HW_SEG_MAX, sizeof(*tun_seg),
                               GFP_KERNEL);
        if (!tun_seg) {
                devm_kfree(dev, seg);
index c73cdab..ada5198 100644 (file)
@@ -2639,7 +2639,7 @@ ice_ptg_remove_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg)
  *
  * This function will either add or move a ptype to a particular PTG depending
  * on if the ptype is already part of another group. Note that using a
- * destination PTG ID of ICE_DEFAULT_PTG (0) will move the ptype to the
+ * destination PTG ID of ICE_DEFAULT_PTG (0) will move the ptype to the
  * default PTG.
  */
 static int
index 57586a2..c6d755f 100644 (file)
@@ -17,13 +17,13 @@ static void ice_gnss_read(struct kthread_work *work)
        struct gnss_serial *gnss = container_of(work, struct gnss_serial,
                                                read_work.work);
        struct ice_aqc_link_topo_addr link_topo;
-       u8 i2c_params, bytes_read;
+       unsigned int i, bytes_read, data_len;
        struct tty_port *port;
        struct ice_pf *pf;
        struct ice_hw *hw;
        __be16 data_len_b;
        char *buf = NULL;
-       u16 i, data_len;
+       u8 i2c_params;
        int err = 0;
 
        pf = gnss->back;
@@ -65,7 +65,7 @@ static void ice_gnss_read(struct kthread_work *work)
                mdelay(10);
        }
 
-       data_len = min(data_len, (u16)PAGE_SIZE);
+       data_len = min_t(typeof(data_len), data_len, PAGE_SIZE);
        data_len = tty_buffer_request_room(port, data_len);
        if (!data_len) {
                err = -ENOMEM;
@@ -74,9 +74,10 @@ static void ice_gnss_read(struct kthread_work *work)
 
        /* Read received data */
        for (i = 0; i < data_len; i += bytes_read) {
-               u16 bytes_left = data_len - i;
+               unsigned int bytes_left = data_len - i;
 
-               bytes_read = min_t(typeof(bytes_left), bytes_left, ICE_MAX_I2C_DATA_SIZE);
+               bytes_read = min_t(typeof(bytes_left), bytes_left,
+                                  ICE_MAX_I2C_DATA_SIZE);
 
                err = ice_aq_read_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR,
                                      cpu_to_le16(ICE_GNSS_UBX_EMPTY_DATA),
index 4f954db..c9f7393 100644 (file)
@@ -447,11 +447,9 @@ void ice_deinit_lag(struct ice_pf *pf)
        if (lag->pf)
                ice_unregister_lag_handler(lag);
 
-       if (lag->upper_netdev)
-               dev_put(lag->upper_netdev);
+       dev_put(lag->upper_netdev);
 
-       if (lag->peer_netdev)
-               dev_put(lag->peer_netdev);
+       dev_put(lag->peer_netdev);
 
        kfree(lag);
 
index f7f9c97..a6c4be5 100644 (file)
@@ -887,6 +887,9 @@ static void ice_set_dflt_vsi_ctx(struct ice_hw *hw, struct ice_vsi_ctx *ctxt)
                        (ICE_AQ_VSI_OUTER_TAG_VLAN_8100 <<
                         ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
                        ICE_AQ_VSI_OUTER_TAG_TYPE_M;
+               ctxt->info.outer_vlan_flags |=
+                       FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_EMODE_M,
+                                  ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING);
        }
        /* Have 1:1 UP mapping for both ingress/egress tables */
        table |= ICE_UP_TABLE_TRANSLATE(0, 0);
@@ -2419,7 +2422,7 @@ static void ice_set_agg_vsi(struct ice_vsi *vsi)
                                agg_id);
                        return;
                }
-               /* aggregator node is created, store the neeeded info */
+               /* aggregator node is created, store the needed info */
                agg_node->valid = true;
                agg_node->agg_id = agg_id;
        }
index 3f64300..d4a0d08 100644 (file)
@@ -43,6 +43,8 @@ enum ice_protocol_type {
        ICE_NVGRE,
        ICE_GTP,
        ICE_GTP_NO_PAY,
+       ICE_VLAN_EX,
+       ICE_VLAN_IN,
        ICE_VXLAN_GPE,
        ICE_SCTP_IL,
        ICE_PROTOCOL_LAST
@@ -109,13 +111,18 @@ enum ice_prot_id {
 #define ICE_GRE_OF_HW          64
 
 #define ICE_UDP_OF_HW  52 /* UDP Tunnels */
-#define ICE_META_DATA_ID_HW 255 /* this is used for tunnel type */
+#define ICE_META_DATA_ID_HW 255 /* this is used for tunnel and VLAN type */
 
 #define ICE_MDID_SIZE 2
+
 #define ICE_TUN_FLAG_MDID 21
 #define ICE_TUN_FLAG_MDID_OFF (ICE_MDID_SIZE * ICE_TUN_FLAG_MDID)
 #define ICE_TUN_FLAG_MASK 0xFF
 
+#define ICE_VLAN_FLAG_MDID 20
+#define ICE_VLAN_FLAG_MDID_OFF (ICE_MDID_SIZE * ICE_VLAN_FLAG_MDID)
+#define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK 0xD000
+
 #define ICE_TUN_FLAG_FV_IND 2
 
 /* Mapping of software defined protocol ID to hardware defined protocol ID */
index bb1721f..86093b2 100644 (file)
@@ -1593,16 +1593,6 @@ ice_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
                goto out_put_vf;
        }
 
-       /* when max_tx_rate is zero that means no max Tx rate limiting, so only
-        * check if max_tx_rate is non-zero
-        */
-       if (max_tx_rate && min_tx_rate > max_tx_rate) {
-               dev_err(dev, "Cannot set min Tx rate %d Mbps greater than max Tx rate %d Mbps\n",
-                       min_tx_rate, max_tx_rate);
-               ret = -EINVAL;
-               goto out_put_vf;
-       }
-
        if (min_tx_rate && ice_is_dcb_active(pf)) {
                dev_err(dev, "DCB on PF is currently enabled. VF min Tx rate limiting not allowed on this PF.\n");
                ret = -EOPNOTSUPP;
index 8d8f3ee..2d12747 100644 (file)
@@ -31,16 +31,16 @@ static const u8 dummy_eth_header[DUMMY_ETH_HDR_LEN] = { 0x2, 0, 0, 0, 0, 0,
                                                        0x81, 0, 0, 0};
 
 enum {
-       ICE_PKT_VLAN            = BIT(0),
-       ICE_PKT_OUTER_IPV6      = BIT(1),
-       ICE_PKT_TUN_GTPC        = BIT(2),
-       ICE_PKT_TUN_GTPU        = BIT(3),
-       ICE_PKT_TUN_NVGRE       = BIT(4),
-       ICE_PKT_TUN_UDP         = BIT(5),
-       ICE_PKT_INNER_IPV6      = BIT(6),
-       ICE_PKT_INNER_TCP       = BIT(7),
-       ICE_PKT_INNER_UDP       = BIT(8),
-       ICE_PKT_GTP_NOPAY       = BIT(9),
+       ICE_PKT_OUTER_IPV6      = BIT(0),
+       ICE_PKT_TUN_GTPC        = BIT(1),
+       ICE_PKT_TUN_GTPU        = BIT(2),
+       ICE_PKT_TUN_NVGRE       = BIT(3),
+       ICE_PKT_TUN_UDP         = BIT(4),
+       ICE_PKT_INNER_IPV6      = BIT(5),
+       ICE_PKT_INNER_TCP       = BIT(6),
+       ICE_PKT_INNER_UDP       = BIT(7),
+       ICE_PKT_GTP_NOPAY       = BIT(8),
+       ICE_PKT_KMALLOC         = BIT(9),
 };
 
 struct ice_dummy_pkt_offsets {
@@ -53,22 +53,42 @@ struct ice_dummy_pkt_profile {
        const u8 *pkt;
        u32 match;
        u16 pkt_len;
+       u16 offsets_len;
 };
 
-#define ICE_DECLARE_PKT_OFFSETS(type)                          \
-       static const struct ice_dummy_pkt_offsets               \
+#define ICE_DECLARE_PKT_OFFSETS(type)                                  \
+       static const struct ice_dummy_pkt_offsets                       \
        ice_dummy_##type##_packet_offsets[]
 
-#define ICE_DECLARE_PKT_TEMPLATE(type)                         \
+#define ICE_DECLARE_PKT_TEMPLATE(type)                                 \
        static const u8 ice_dummy_##type##_packet[]
 
-#define ICE_PKT_PROFILE(type, m) {                             \
-       .match          = (m),                                  \
-       .pkt            = ice_dummy_##type##_packet,            \
-       .pkt_len        = sizeof(ice_dummy_##type##_packet),    \
-       .offsets        = ice_dummy_##type##_packet_offsets,    \
+#define ICE_PKT_PROFILE(type, m) {                                     \
+       .match          = (m),                                          \
+       .pkt            = ice_dummy_##type##_packet,                    \
+       .pkt_len        = sizeof(ice_dummy_##type##_packet),            \
+       .offsets        = ice_dummy_##type##_packet_offsets,            \
+       .offsets_len    = sizeof(ice_dummy_##type##_packet_offsets),    \
 }
 
+ICE_DECLARE_PKT_OFFSETS(vlan) = {
+       { ICE_VLAN_OFOS,        12 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(vlan) = {
+       0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
+};
+
+ICE_DECLARE_PKT_OFFSETS(qinq) = {
+       { ICE_VLAN_EX,          12 },
+       { ICE_VLAN_IN,          16 },
+};
+
+ICE_DECLARE_PKT_TEMPLATE(qinq) = {
+       0x91, 0x00, 0x00, 0x00, /* ICE_VLAN_EX 12 */
+       0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_IN 16 */
+};
+
 ICE_DECLARE_PKT_OFFSETS(gre_tcp) = {
        { ICE_MAC_OFOS,         0 },
        { ICE_ETYPE_OL,         12 },
@@ -506,38 +526,6 @@ ICE_DECLARE_PKT_TEMPLATE(udp) = {
        0x00, 0x00,     /* 2 bytes for 4 byte alignment */
 };
 
-/* offset info for MAC + VLAN + IPv4 + UDP dummy packet */
-ICE_DECLARE_PKT_OFFSETS(vlan_udp) = {
-       { ICE_MAC_OFOS,         0 },
-       { ICE_VLAN_OFOS,        12 },
-       { ICE_ETYPE_OL,         16 },
-       { ICE_IPV4_OFOS,        18 },
-       { ICE_UDP_ILOS,         38 },
-       { ICE_PROTOCOL_LAST,    0 },
-};
-
-/* C-tag (801.1Q), IPv4:UDP dummy packet */
-ICE_DECLARE_PKT_TEMPLATE(vlan_udp) = {
-       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
-
-       0x08, 0x00,             /* ICE_ETYPE_OL 16 */
-
-       0x45, 0x00, 0x00, 0x1c, /* ICE_IPV4_OFOS 18 */
-       0x00, 0x01, 0x00, 0x00,
-       0x00, 0x11, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 38 */
-       0x00, 0x08, 0x00, 0x00,
-
-       0x00, 0x00,     /* 2 bytes for 4 byte alignment */
-};
-
 /* offset info for MAC + IPv4 + TCP dummy packet */
 ICE_DECLARE_PKT_OFFSETS(tcp) = {
        { ICE_MAC_OFOS,         0 },
@@ -570,41 +558,6 @@ ICE_DECLARE_PKT_TEMPLATE(tcp) = {
        0x00, 0x00,     /* 2 bytes for 4 byte alignment */
 };
 
-/* offset info for MAC + VLAN (C-tag, 802.1Q) + IPv4 + TCP dummy packet */
-ICE_DECLARE_PKT_OFFSETS(vlan_tcp) = {
-       { ICE_MAC_OFOS,         0 },
-       { ICE_VLAN_OFOS,        12 },
-       { ICE_ETYPE_OL,         16 },
-       { ICE_IPV4_OFOS,        18 },
-       { ICE_TCP_IL,           38 },
-       { ICE_PROTOCOL_LAST,    0 },
-};
-
-/* C-tag (801.1Q), IPv4:TCP dummy packet */
-ICE_DECLARE_PKT_TEMPLATE(vlan_tcp) = {
-       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
-
-       0x08, 0x00,             /* ICE_ETYPE_OL 16 */
-
-       0x45, 0x00, 0x00, 0x28, /* ICE_IPV4_OFOS 18 */
-       0x00, 0x01, 0x00, 0x00,
-       0x00, 0x06, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 38 */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x50, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x00, 0x00,     /* 2 bytes for 4 byte alignment */
-};
-
 ICE_DECLARE_PKT_OFFSETS(tcp_ipv6) = {
        { ICE_MAC_OFOS,         0 },
        { ICE_ETYPE_OL,         12 },
@@ -640,46 +593,6 @@ ICE_DECLARE_PKT_TEMPLATE(tcp_ipv6) = {
        0x00, 0x00, /* 2 bytes for 4 byte alignment */
 };
 
-/* C-tag (802.1Q): IPv6 + TCP */
-ICE_DECLARE_PKT_OFFSETS(vlan_tcp_ipv6) = {
-       { ICE_MAC_OFOS,         0 },
-       { ICE_VLAN_OFOS,        12 },
-       { ICE_ETYPE_OL,         16 },
-       { ICE_IPV6_OFOS,        18 },
-       { ICE_TCP_IL,           58 },
-       { ICE_PROTOCOL_LAST,    0 },
-};
-
-/* C-tag (802.1Q), IPv6 + TCP dummy packet */
-ICE_DECLARE_PKT_TEMPLATE(vlan_tcp_ipv6) = {
-       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x81, 0x00, 0x00, 0x00, /* ICE_VLAN_OFOS 12 */
-
-       0x86, 0xDD,             /* ICE_ETYPE_OL 16 */
-
-       0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */
-       0x00, 0x14, 0x06, 0x00, /* Next header is TCP */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x00, 0x00, 0x00, 0x00, /* ICE_TCP_IL 58 */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x50, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x00, 0x00, /* 2 bytes for 4 byte alignment */
-};
-
 /* IPv6 + UDP */
 ICE_DECLARE_PKT_OFFSETS(udp_ipv6) = {
        { ICE_MAC_OFOS,         0 },
@@ -717,43 +630,6 @@ ICE_DECLARE_PKT_TEMPLATE(udp_ipv6) = {
        0x00, 0x00, /* 2 bytes for 4 byte alignment */
 };
 
-/* C-tag (802.1Q): IPv6 + UDP */
-ICE_DECLARE_PKT_OFFSETS(vlan_udp_ipv6) = {
-       { ICE_MAC_OFOS,         0 },
-       { ICE_VLAN_OFOS,        12 },
-       { ICE_ETYPE_OL,         16 },
-       { ICE_IPV6_OFOS,        18 },
-       { ICE_UDP_ILOS,         58 },
-       { ICE_PROTOCOL_LAST,    0 },
-};
-
-/* C-tag (802.1Q), IPv6 + UDP dummy packet */
-ICE_DECLARE_PKT_TEMPLATE(vlan_udp_ipv6) = {
-       0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x81, 0x00, 0x00, 0x00,/* ICE_VLAN_OFOS 12 */
-
-       0x86, 0xDD,             /* ICE_ETYPE_OL 16 */
-
-       0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 18 */
-       0x00, 0x08, 0x11, 0x00, /* Next header UDP */
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00,
-
-       0x00, 0x00, 0x00, 0x00, /* ICE_UDP_ILOS 58 */
-       0x00, 0x08, 0x00, 0x00,
-
-       0x00, 0x00, /* 2 bytes for 4 byte alignment */
-};
-
 /* Outer IPv4 + Outer UDP + GTP + Inner IPv4 + Inner TCP */
 ICE_DECLARE_PKT_OFFSETS(ipv4_gtpu_ipv4_tcp) = {
        { ICE_MAC_OFOS,         0 },
@@ -1271,14 +1147,9 @@ static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {
        ICE_PKT_PROFILE(udp_tun_ipv6_udp, ICE_PKT_TUN_UDP |
                                          ICE_PKT_INNER_IPV6),
        ICE_PKT_PROFILE(udp_tun_udp, ICE_PKT_TUN_UDP),
-       ICE_PKT_PROFILE(vlan_udp_ipv6, ICE_PKT_OUTER_IPV6 | ICE_PKT_INNER_UDP |
-                                      ICE_PKT_VLAN),
        ICE_PKT_PROFILE(udp_ipv6, ICE_PKT_OUTER_IPV6 | ICE_PKT_INNER_UDP),
-       ICE_PKT_PROFILE(vlan_udp, ICE_PKT_INNER_UDP | ICE_PKT_VLAN),
        ICE_PKT_PROFILE(udp, ICE_PKT_INNER_UDP),
-       ICE_PKT_PROFILE(vlan_tcp_ipv6, ICE_PKT_OUTER_IPV6 | ICE_PKT_VLAN),
        ICE_PKT_PROFILE(tcp_ipv6, ICE_PKT_OUTER_IPV6),
-       ICE_PKT_PROFILE(vlan_tcp, ICE_PKT_VLAN),
        ICE_PKT_PROFILE(tcp, 0),
 };
 
@@ -4609,6 +4480,8 @@ static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {
        { ICE_NVGRE,            { 0, 2, 4, 6 } },
        { ICE_GTP,              { 8, 10, 12, 14, 16, 18, 20, 22 } },
        { ICE_GTP_NO_PAY,       { 8, 10, 12, 14 } },
+       { ICE_VLAN_EX,          { 2, 0 } },
+       { ICE_VLAN_IN,          { 2, 0 } },
 };
 
 static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
@@ -4629,6 +4502,8 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
        { ICE_NVGRE,            ICE_GRE_OF_HW },
        { ICE_GTP,              ICE_UDP_OF_HW },
        { ICE_GTP_NO_PAY,       ICE_UDP_ILOS_HW },
+       { ICE_VLAN_EX,          ICE_VLAN_OF_HW },
+       { ICE_VLAN_IN,          ICE_VLAN_OL_HW },
 };
 
 /**
@@ -5313,10 +5188,11 @@ static bool ice_tun_type_match_word(enum ice_sw_tunnel_type tun_type, u16 *mask)
  * ice_add_special_words - Add words that are not protocols, such as metadata
  * @rinfo: other information regarding the rule e.g. priority and action info
  * @lkup_exts: lookup word structure
+ * @dvm_ena: is double VLAN mode enabled
  */
 static int
 ice_add_special_words(struct ice_adv_rule_info *rinfo,
-                     struct ice_prot_lkup_ext *lkup_exts)
+                     struct ice_prot_lkup_ext *lkup_exts, bool dvm_ena)
 {
        u16 mask;
 
@@ -5335,6 +5211,19 @@ ice_add_special_words(struct ice_adv_rule_info *rinfo,
                }
        }
 
+       if (rinfo->vlan_type != 0 && dvm_ena) {
+               if (lkup_exts->n_val_words < ICE_MAX_CHAIN_WORDS) {
+                       u8 word = lkup_exts->n_val_words++;
+
+                       lkup_exts->fv_words[word].prot_id = ICE_META_DATA_ID_HW;
+                       lkup_exts->fv_words[word].off = ICE_VLAN_FLAG_MDID_OFF;
+                       lkup_exts->field_mask[word] =
+                                       ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK;
+               } else {
+                       return -ENOSPC;
+               }
+       }
+
        return 0;
 }
 
@@ -5454,7 +5343,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        /* Create any special protocol/offset pairs, such as looking at tunnel
         * bits by extracting metadata
         */
-       status = ice_add_special_words(rinfo, lkup_exts);
+       status = ice_add_special_words(rinfo, lkup_exts, ice_is_dvm_ena(hw));
        if (status)
                goto err_free_lkup_exts;
 
@@ -5555,6 +5444,79 @@ err_free_lkup_exts:
 }
 
 /**
+ * ice_dummy_packet_add_vlan - insert VLAN header to dummy pkt
+ *
+ * @dummy_pkt: dummy packet profile pattern to which VLAN tag(s) will be added
+ * @num_vlan: number of VLAN tags
+ */
+static struct ice_dummy_pkt_profile *
+ice_dummy_packet_add_vlan(const struct ice_dummy_pkt_profile *dummy_pkt,
+                         u32 num_vlan)
+{
+       struct ice_dummy_pkt_profile *profile;
+       struct ice_dummy_pkt_offsets *offsets;
+       u32 buf_len, off, etype_off, i;
+       u8 *pkt;
+
+       if (num_vlan < 1 || num_vlan > 2)
+               return ERR_PTR(-EINVAL);
+
+       off = num_vlan * VLAN_HLEN;
+
+       buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet_offsets)) +
+                 dummy_pkt->offsets_len;
+       offsets = kzalloc(buf_len, GFP_KERNEL);
+       if (!offsets)
+               return ERR_PTR(-ENOMEM);
+
+       offsets[0] = dummy_pkt->offsets[0];
+       if (num_vlan == 2) {
+               offsets[1] = ice_dummy_qinq_packet_offsets[0];
+               offsets[2] = ice_dummy_qinq_packet_offsets[1];
+       } else if (num_vlan == 1) {
+               offsets[1] = ice_dummy_vlan_packet_offsets[0];
+       }
+
+       for (i = 1; dummy_pkt->offsets[i].type != ICE_PROTOCOL_LAST; i++) {
+               offsets[i + num_vlan].type = dummy_pkt->offsets[i].type;
+               offsets[i + num_vlan].offset =
+                       dummy_pkt->offsets[i].offset + off;
+       }
+       offsets[i + num_vlan] = dummy_pkt->offsets[i];
+
+       etype_off = dummy_pkt->offsets[1].offset;
+
+       buf_len = array_size(num_vlan, sizeof(ice_dummy_vlan_packet)) +
+                 dummy_pkt->pkt_len;
+       pkt = kzalloc(buf_len, GFP_KERNEL);
+       if (!pkt) {
+               kfree(offsets);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       memcpy(pkt, dummy_pkt->pkt, etype_off);
+       memcpy(pkt + etype_off,
+              num_vlan == 2 ? ice_dummy_qinq_packet : ice_dummy_vlan_packet,
+              off);
+       memcpy(pkt + etype_off + off, dummy_pkt->pkt + etype_off,
+              dummy_pkt->pkt_len - etype_off);
+
+       profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+       if (!profile) {
+               kfree(offsets);
+               kfree(pkt);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       profile->offsets = offsets;
+       profile->pkt = pkt;
+       profile->pkt_len = buf_len;
+       profile->match |= ICE_PKT_KMALLOC;
+
+       return profile;
+}
+
+/**
  * ice_find_dummy_packet - find dummy packet
  *
  * @lkups: lookup elements or match criteria for the advanced recipe, one
@@ -5569,7 +5531,7 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                      enum ice_sw_tunnel_type tun_type)
 {
        const struct ice_dummy_pkt_profile *ret = ice_dummy_pkt_profiles;
-       u32 match = 0;
+       u32 match = 0, vlan_count = 0;
        u16 i;
 
        switch (tun_type) {
@@ -5597,8 +5559,11 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                        match |= ICE_PKT_INNER_TCP;
                else if (lkups[i].type == ICE_IPV6_OFOS)
                        match |= ICE_PKT_OUTER_IPV6;
-               else if (lkups[i].type == ICE_VLAN_OFOS)
-                       match |= ICE_PKT_VLAN;
+               else if (lkups[i].type == ICE_VLAN_OFOS ||
+                        lkups[i].type == ICE_VLAN_EX)
+                       vlan_count++;
+               else if (lkups[i].type == ICE_VLAN_IN)
+                       vlan_count++;
                else if (lkups[i].type == ICE_ETYPE_OL &&
                         lkups[i].h_u.ethertype.ethtype_id ==
                                cpu_to_be16(ICE_IPV6_ETHER_ID) &&
@@ -5620,6 +5585,9 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
        while (ret->match && (match & ret->match) != ret->match)
                ret++;
 
+       if (vlan_count != 0)
+               ret = ice_dummy_packet_add_vlan(ret, vlan_count);
+
        return ret;
 }
 
@@ -5678,6 +5646,8 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,
                        len = sizeof(struct ice_ethtype_hdr);
                        break;
                case ICE_VLAN_OFOS:
+               case ICE_VLAN_EX:
+               case ICE_VLAN_IN:
                        len = sizeof(struct ice_vlan_hdr);
                        break;
                case ICE_IPV4_OFOS:
@@ -5783,6 +5753,36 @@ ice_fill_adv_packet_tun(struct ice_hw *hw, enum ice_sw_tunnel_type tun_type,
 }
 
 /**
+ * ice_fill_adv_packet_vlan - fill dummy packet with VLAN tag type
+ * @vlan_type: VLAN tag type
+ * @pkt: dummy packet to fill in
+ * @offsets: offset info for the dummy packet
+ */
+static int
+ice_fill_adv_packet_vlan(u16 vlan_type, u8 *pkt,
+                        const struct ice_dummy_pkt_offsets *offsets)
+{
+       u16 i;
+
+       /* Find VLAN header and insert VLAN TPID */
+       for (i = 0; offsets[i].type != ICE_PROTOCOL_LAST; i++) {
+               if (offsets[i].type == ICE_VLAN_OFOS ||
+                   offsets[i].type == ICE_VLAN_EX) {
+                       struct ice_vlan_hdr *hdr;
+                       u16 offset;
+
+                       offset = offsets[i].offset;
+                       hdr = (struct ice_vlan_hdr *)&pkt[offset];
+                       hdr->type = cpu_to_be16(vlan_type);
+
+                       return 0;
+               }
+       }
+
+       return -EIO;
+}
+
+/**
  * ice_find_adv_rule_entry - Search a rule entry
  * @hw: pointer to the hardware structure
  * @lkups: lookup elements or match criteria for the advanced recipe, one
@@ -5817,6 +5817,7 @@ ice_find_adv_rule_entry(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                        }
                if (rinfo->sw_act.flag == list_itr->rule_info.sw_act.flag &&
                    rinfo->tun_type == list_itr->rule_info.tun_type &&
+                   rinfo->vlan_type == list_itr->rule_info.vlan_type &&
                    lkups_matched)
                        return list_itr;
        }
@@ -5993,16 +5994,22 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
 
        /* locate a dummy packet */
        profile = ice_find_dummy_packet(lkups, lkups_cnt, rinfo->tun_type);
+       if (IS_ERR(profile))
+               return PTR_ERR(profile);
 
        if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
              rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
              rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
-             rinfo->sw_act.fltr_act == ICE_DROP_PACKET))
-               return -EIO;
+             rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) {
+               status = -EIO;
+               goto free_pkt_profile;
+       }
 
        vsi_handle = rinfo->sw_act.vsi_handle;
-       if (!ice_is_vsi_valid(hw, vsi_handle))
-               return -EINVAL;
+       if (!ice_is_vsi_valid(hw, vsi_handle)) {
+               status =  -EINVAL;
+               goto free_pkt_profile;
+       }
 
        if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI)
                rinfo->sw_act.fwd_id.hw_vsi_id =
@@ -6012,7 +6019,7 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
 
        status = ice_add_adv_recipe(hw, lkups, lkups_cnt, rinfo, &rid);
        if (status)
-               return status;
+               goto free_pkt_profile;
        m_entry = ice_find_adv_rule_entry(hw, lkups, lkups_cnt, rid, rinfo);
        if (m_entry) {
                /* we have to add VSI to VSI_LIST and increment vsi_count.
@@ -6031,12 +6038,14 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                        added_entry->rule_id = m_entry->rule_info.fltr_rule_id;
                        added_entry->vsi_handle = rinfo->sw_act.vsi_handle;
                }
-               return status;
+               goto free_pkt_profile;
        }
        rule_buf_sz = ICE_SW_RULE_RX_TX_HDR_SIZE(s_rule, profile->pkt_len);
        s_rule = kzalloc(rule_buf_sz, GFP_KERNEL);
-       if (!s_rule)
-               return -ENOMEM;
+       if (!s_rule) {
+               status = -ENOMEM;
+               goto free_pkt_profile;
+       }
        if (!rinfo->flags_info.act_valid) {
                act |= ICE_SINGLE_ACT_LAN_ENABLE;
                act |= ICE_SINGLE_ACT_LB_ENABLE;
@@ -6105,6 +6114,14 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
                        goto err_ice_add_adv_rule;
        }
 
+       if (rinfo->vlan_type != 0 && ice_is_dvm_ena(hw)) {
+               status = ice_fill_adv_packet_vlan(rinfo->vlan_type,
+                                                 s_rule->hdr_data,
+                                                 profile->offsets);
+               if (status)
+                       goto err_ice_add_adv_rule;
+       }
+
        status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule,
                                 rule_buf_sz, 1, ice_aqc_opc_add_sw_rules,
                                 NULL);
@@ -6150,6 +6167,13 @@ err_ice_add_adv_rule:
 
        kfree(s_rule);
 
+free_pkt_profile:
+       if (profile->match & ICE_PKT_KMALLOC) {
+               kfree(profile->offsets);
+               kfree(profile->pkt);
+               kfree(profile);
+       }
+
        return status;
 }
 
@@ -6342,7 +6366,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
        /* Create any special protocol/offset pairs, such as looking at tunnel
         * bits by extracting metadata
         */
-       status = ice_add_special_words(rinfo, &lkup_exts);
+       status = ice_add_special_words(rinfo, &lkup_exts, ice_is_dvm_ena(hw));
        if (status)
                return status;
 
index eb641e5..59488e3 100644 (file)
@@ -192,6 +192,7 @@ struct ice_adv_rule_info {
        u32 priority;
        u8 rx; /* true means LOOKUP_RX otherwise LOOKUP_TX */
        u16 fltr_rule_id;
+       u16 vlan_type;
        struct ice_adv_rule_flags_info flags_info;
 };
 
index b803f2a..1479515 100644 (file)
@@ -50,6 +50,10 @@ ice_tc_count_lkups(u32 flags, struct ice_tc_flower_lyr_2_4_hdrs *headers,
        if (flags & ICE_TC_FLWR_FIELD_VLAN)
                lkups_cnt++;
 
+       /* is CVLAN specified? */
+       if (flags & ICE_TC_FLWR_FIELD_CVLAN)
+               lkups_cnt++;
+
        /* are IPv[4|6] fields specified? */
        if (flags & (ICE_TC_FLWR_FIELD_DEST_IPV4 | ICE_TC_FLWR_FIELD_SRC_IPV4 |
                     ICE_TC_FLWR_FIELD_DEST_IPV6 | ICE_TC_FLWR_FIELD_SRC_IPV6))
@@ -134,6 +138,18 @@ ice_sw_type_from_tunnel(enum ice_tunnel_type type)
        }
 }
 
+static u16 ice_check_supported_vlan_tpid(u16 vlan_tpid)
+{
+       switch (vlan_tpid) {
+       case ETH_P_8021Q:
+       case ETH_P_8021AD:
+       case ETH_P_QINQ1:
+               return vlan_tpid;
+       default:
+               return 0;
+       }
+}
+
 static int
 ice_tc_fill_tunnel_outer(u32 flags, struct ice_tc_flower_fltr *fltr,
                         struct ice_adv_lkup_elem *list)
@@ -269,8 +285,11 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
 {
        struct ice_tc_flower_lyr_2_4_hdrs *headers = &tc_fltr->outer_headers;
        bool inner = false;
+       u16 vlan_tpid = 0;
        int i = 0;
 
+       rule_info->vlan_type = vlan_tpid;
+
        rule_info->tun_type = ice_sw_type_from_tunnel(tc_fltr->tunnel_type);
        if (tc_fltr->tunnel_type != TNL_LAST) {
                i = ice_tc_fill_tunnel_outer(flags, tc_fltr, list);
@@ -311,12 +330,26 @@ ice_tc_fill_rules(struct ice_hw *hw, u32 flags,
 
        /* copy VLAN info */
        if (flags & ICE_TC_FLWR_FIELD_VLAN) {
-               list[i].type = ICE_VLAN_OFOS;
+               vlan_tpid = be16_to_cpu(headers->vlan_hdr.vlan_tpid);
+               rule_info->vlan_type =
+                               ice_check_supported_vlan_tpid(vlan_tpid);
+
+               if (flags & ICE_TC_FLWR_FIELD_CVLAN)
+                       list[i].type = ICE_VLAN_EX;
+               else
+                       list[i].type = ICE_VLAN_OFOS;
                list[i].h_u.vlan_hdr.vlan = headers->vlan_hdr.vlan_id;
                list[i].m_u.vlan_hdr.vlan = cpu_to_be16(0xFFFF);
                i++;
        }
 
+       if (flags & ICE_TC_FLWR_FIELD_CVLAN) {
+               list[i].type = ICE_VLAN_IN;
+               list[i].h_u.vlan_hdr.vlan = headers->cvlan_hdr.vlan_id;
+               list[i].m_u.vlan_hdr.vlan = cpu_to_be16(0xFFFF);
+               i++;
+       }
+
        /* copy L3 (IPv[4|6]: src, dest) address */
        if (flags & (ICE_TC_FLWR_FIELD_DEST_IPV4 |
                     ICE_TC_FLWR_FIELD_SRC_IPV4)) {
@@ -945,6 +978,7 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
              BIT(FLOW_DISSECTOR_KEY_BASIC) |
              BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
              BIT(FLOW_DISSECTOR_KEY_VLAN) |
+             BIT(FLOW_DISSECTOR_KEY_CVLAN) |
              BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
              BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
              BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL) |
@@ -1060,6 +1094,34 @@ ice_parse_cls_flower(struct net_device *filter_dev, struct ice_vsi *vsi,
                                cpu_to_be16(match.key->vlan_id & VLAN_VID_MASK);
                if (match.mask->vlan_priority)
                        headers->vlan_hdr.vlan_prio = match.key->vlan_priority;
+               if (match.mask->vlan_tpid)
+                       headers->vlan_hdr.vlan_tpid = match.key->vlan_tpid;
+       }
+
+       if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
+               struct flow_match_vlan match;
+
+               if (!ice_is_dvm_ena(&vsi->back->hw)) {
+                       NL_SET_ERR_MSG_MOD(fltr->extack, "Double VLAN mode is not enabled");
+                       return -EINVAL;
+               }
+
+               flow_rule_match_cvlan(rule, &match);
+
+               if (match.mask->vlan_id) {
+                       if (match.mask->vlan_id == VLAN_VID_MASK) {
+                               fltr->flags |= ICE_TC_FLWR_FIELD_CVLAN;
+                       } else {
+                               NL_SET_ERR_MSG_MOD(fltr->extack,
+                                                  "Bad CVLAN mask");
+                               return -EINVAL;
+                       }
+               }
+
+               headers->cvlan_hdr.vlan_id =
+                               cpu_to_be16(match.key->vlan_id & VLAN_VID_MASK);
+               if (match.mask->vlan_priority)
+                       headers->cvlan_hdr.vlan_prio = match.key->vlan_priority;
        }
 
        if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
@@ -1194,7 +1256,7 @@ ice_handle_tclass_action(struct ice_vsi *vsi,
                           ICE_TC_FLWR_FIELD_ENC_DST_MAC)) {
                ether_addr_copy(fltr->outer_headers.l2_key.dst_mac,
                                vsi->netdev->dev_addr);
-               memset(fltr->outer_headers.l2_mask.dst_mac, 0xff, ETH_ALEN);
+               eth_broadcast_addr(fltr->outer_headers.l2_mask.dst_mac);
        }
 
        /* validate specified dest MAC address, make sure either it belongs to
index e25e958..0193874 100644 (file)
@@ -23,6 +23,7 @@
 #define ICE_TC_FLWR_FIELD_ENC_DST_MAC          BIT(16)
 #define ICE_TC_FLWR_FIELD_ETH_TYPE_ID          BIT(17)
 #define ICE_TC_FLWR_FIELD_ENC_OPTS             BIT(18)
+#define ICE_TC_FLWR_FIELD_CVLAN                        BIT(19)
 
 #define ICE_TC_FLOWER_MASK_32   0xFFFFFFFF
 
@@ -40,6 +41,7 @@ struct ice_tc_flower_action {
 struct ice_tc_vlan_hdr {
        __be16 vlan_id; /* Only last 12 bits valid */
        u16 vlan_prio; /* Only last 3 bits valid (valid values: 0..7) */
+       __be16 vlan_tpid;
 };
 
 struct ice_tc_l2_hdr {
@@ -81,6 +83,7 @@ struct ice_tc_flower_lyr_2_4_hdrs {
        struct ice_tc_l2_hdr l2_key;
        struct ice_tc_l2_hdr l2_mask;
        struct ice_tc_vlan_hdr vlan_hdr;
+       struct ice_tc_vlan_hdr cvlan_hdr;
        /* L3 (IPv4[6]) layer fields with their mask */
        struct ice_tc_l3_hdr l3_key;
        struct ice_tc_l3_hdr l3_mask;
index 4547bc1..b2b5d2e 100644 (file)
@@ -360,6 +360,54 @@ static u16 ice_vc_get_max_frame_size(struct ice_vf *vf)
 }
 
 /**
+ * ice_vc_get_vlan_caps
+ * @hw: pointer to the hw
+ * @vf: pointer to the VF info
+ * @vsi: pointer to the VSI
+ * @driver_caps: current driver caps
+ *
+ * Return 0 if there is no VLAN caps supported, or VLAN caps value
+ */
+static u32
+ice_vc_get_vlan_caps(struct ice_hw *hw, struct ice_vf *vf, struct ice_vsi *vsi,
+                    u32 driver_caps)
+{
+       if (ice_is_eswitch_mode_switchdev(vf->pf))
+               /* In switchdev setting VLAN from VF isn't supported */
+               return 0;
+
+       if (driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
+               /* VLAN offloads based on current device configuration */
+               return VIRTCHNL_VF_OFFLOAD_VLAN_V2;
+       } else if (driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN) {
+               /* allow VF to negotiate VIRTCHNL_VF_OFFLOAD explicitly for
+                * these two conditions, which amounts to guest VLAN filtering
+                * and offloads being based on the inner VLAN or the
+                * inner/single VLAN respectively and don't allow VF to
+                * negotiate VIRTCHNL_VF_OFFLOAD in any other cases
+                */
+               if (ice_is_dvm_ena(hw) && ice_vf_is_port_vlan_ena(vf)) {
+                       return VIRTCHNL_VF_OFFLOAD_VLAN;
+               } else if (!ice_is_dvm_ena(hw) &&
+                          !ice_vf_is_port_vlan_ena(vf)) {
+                       /* configure backward compatible support for VFs that
+                        * only support VIRTCHNL_VF_OFFLOAD_VLAN, the PF is
+                        * configured in SVM, and no port VLAN is configured
+                        */
+                       ice_vf_vsi_cfg_svm_legacy_vlan_mode(vsi);
+                       return VIRTCHNL_VF_OFFLOAD_VLAN;
+               } else if (ice_is_dvm_ena(hw)) {
+                       /* configure software offloaded VLAN support when DVM
+                        * is enabled, but no port VLAN is enabled
+                        */
+                       ice_vf_vsi_cfg_dvm_legacy_vlan_mode(vsi);
+               }
+       }
+
+       return 0;
+}
+
+/**
  * ice_vc_get_vf_res_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
@@ -402,33 +450,8 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
                goto err;
        }
 
-       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
-               /* VLAN offloads based on current device configuration */
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN_V2;
-       } else if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_VLAN) {
-               /* allow VF to negotiate VIRTCHNL_VF_OFFLOAD explicitly for
-                * these two conditions, which amounts to guest VLAN filtering
-                * and offloads being based on the inner VLAN or the
-                * inner/single VLAN respectively and don't allow VF to
-                * negotiate VIRTCHNL_VF_OFFLOAD in any other cases
-                */
-               if (ice_is_dvm_ena(hw) && ice_vf_is_port_vlan_ena(vf)) {
-                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
-               } else if (!ice_is_dvm_ena(hw) &&
-                          !ice_vf_is_port_vlan_ena(vf)) {
-                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
-                       /* configure backward compatible support for VFs that
-                        * only support VIRTCHNL_VF_OFFLOAD_VLAN, the PF is
-                        * configured in SVM, and no port VLAN is configured
-                        */
-                       ice_vf_vsi_cfg_svm_legacy_vlan_mode(vsi);
-               } else if (ice_is_dvm_ena(hw)) {
-                       /* configure software offloaded VLAN support when DVM
-                        * is enabled, but no port VLAN is enabled
-                        */
-                       ice_vf_vsi_cfg_dvm_legacy_vlan_mode(vsi);
-               }
-       }
+       vfres->vf_cap_flags |= ice_vc_get_vlan_caps(hw, vf, vsi,
+                                                   vf->driver_caps);
 
        if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
                vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
@@ -3528,42 +3551,6 @@ ice_vc_repr_del_mac(struct ice_vf __always_unused *vf, u8 __always_unused *msg)
                                     VIRTCHNL_STATUS_SUCCESS, NULL, 0);
 }
 
-static int ice_vc_repr_add_vlan(struct ice_vf *vf, u8 __always_unused *msg)
-{
-       dev_dbg(ice_pf_to_dev(vf->pf),
-               "Can't add VLAN in switchdev mode for VF %d\n", vf->vf_id);
-       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_VLAN,
-                                    VIRTCHNL_STATUS_SUCCESS, NULL, 0);
-}
-
-static int ice_vc_repr_del_vlan(struct ice_vf *vf, u8 __always_unused *msg)
-{
-       dev_dbg(ice_pf_to_dev(vf->pf),
-               "Can't delete VLAN in switchdev mode for VF %d\n", vf->vf_id);
-       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_VLAN,
-                                    VIRTCHNL_STATUS_SUCCESS, NULL, 0);
-}
-
-static int ice_vc_repr_ena_vlan_stripping(struct ice_vf *vf)
-{
-       dev_dbg(ice_pf_to_dev(vf->pf),
-               "Can't enable VLAN stripping in switchdev mode for VF %d\n",
-               vf->vf_id);
-       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING,
-                                    VIRTCHNL_STATUS_ERR_NOT_SUPPORTED,
-                                    NULL, 0);
-}
-
-static int ice_vc_repr_dis_vlan_stripping(struct ice_vf *vf)
-{
-       dev_dbg(ice_pf_to_dev(vf->pf),
-               "Can't disable VLAN stripping in switchdev mode for VF %d\n",
-               vf->vf_id);
-       return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING,
-                                    VIRTCHNL_STATUS_ERR_NOT_SUPPORTED,
-                                    NULL, 0);
-}
-
 static int
 ice_vc_repr_cfg_promiscuous_mode(struct ice_vf *vf, u8 __always_unused *msg)
 {
@@ -3590,10 +3577,10 @@ static const struct ice_virtchnl_ops ice_virtchnl_repr_ops = {
        .config_rss_lut = ice_vc_config_rss_lut,
        .get_stats_msg = ice_vc_get_stats_msg,
        .cfg_promiscuous_mode_msg = ice_vc_repr_cfg_promiscuous_mode,
-       .add_vlan_msg = ice_vc_repr_add_vlan,
-       .remove_vlan_msg = ice_vc_repr_del_vlan,
-       .ena_vlan_stripping = ice_vc_repr_ena_vlan_stripping,
-       .dis_vlan_stripping = ice_vc_repr_dis_vlan_stripping,
+       .add_vlan_msg = ice_vc_add_vlan_msg,
+       .remove_vlan_msg = ice_vc_remove_vlan_msg,
+       .ena_vlan_stripping = ice_vc_ena_vlan_stripping,
+       .dis_vlan_stripping = ice_vc_dis_vlan_stripping,
        .handle_rss_cfg_msg = ice_vc_handle_rss_cfg,
        .add_fdir_fltr_msg = ice_vc_add_fdir_fltr,
        .del_fdir_fltr_msg = ice_vc_del_fdir_fltr,
index 1b618de..bcda2e0 100644 (file)
@@ -199,7 +199,6 @@ static bool ice_is_dvm_supported(struct ice_hw *hw)
 #define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX            2
 #define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX          2
 #define ICE_PKT_FLAGS_0_TO_15_FV_IDX                   1
-#define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK          0xD000
 static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = {
        {
                /* Update recipe ICE_SW_LKUP_VLAN to filter based on the
index cbe92fd..8d6e44e 100644 (file)
@@ -2207,7 +2207,7 @@ out:
  *  igb_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
  *  @hw: pointer to the HW structure
  *
- *  This resets the the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
+ *  This resets the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
  *  the values found in the EEPROM.  This addresses an issue in which these
  *  bits are not restored from EEPROM after reset.
  **/
index ca54297..fa02892 100644 (file)
 #define E1000_VFTA_ENTRY_MASK                0x7F
 #define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
 
-/* DMA Coalescing register fields */
-#define E1000_PCIEMISC_LX_DECISION      0x00000080 /* Lx power on DMA coal */
-
 /* Tx Rate-Scheduler Config fields */
 #define E1000_RTTBCNRC_RS_ENA          0x80000000
 #define E1000_RTTBCNRC_RF_DEC_MASK     0x00003FFF
index 1277c5c..205d577 100644 (file)
@@ -854,7 +854,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
         *      1:  Rx flow control is enabled (we can receive pause
         *          frames but not send pause frames).
         *      2:  Tx flow control is enabled (we can send pause frames
-        *          frames but we do not receive pause frames).
+        *          but we do not receive pause frames).
         *      3:  Both Rx and TX flow control (symmetric) is enabled.
         *  other:  No other values should be possible at this point.
         */
index 9cb4998..eb9f6da 100644 (file)
 #define E1000_DMCRTRH  0x05DD0 /* Receive Packet Rate Threshold */
 #define E1000_DMCCNT   0x05DD4 /* Current Rx Count */
 #define E1000_FCRTC    0x02170 /* Flow Control Rx high watermark */
-#define E1000_PCIEMISC 0x05BB8 /* PCIE misc config register */
 
 /* TX Rate Limit Registers */
 #define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select - WO */
index c5f04c4..4f91a85 100644 (file)
@@ -1945,7 +1945,7 @@ static void igb_setup_tx_mode(struct igb_adapter *adapter)
                 * However, when we do so, no frame from queue 2 and 3 are
                 * transmitted.  It seems the MAX_TPKT_SIZE should not be great
                 * or _equal_ to the buffer size programmed in TXPBS. For this
-                * reason, we set set MAX_ TPKT_SIZE to (4kB - 1) / 64.
+                * reason, we set MAX_ TPKT_SIZE to (4kB - 1) / 64.
                 */
                val = (4096 - 1) / 64;
                wr32(E1000_I210_DTXMXPKTSZ, val);
@@ -9522,7 +9522,7 @@ static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev,
                igb_down(adapter);
        pci_disable_device(pdev);
 
-       /* Request a slot slot reset. */
+       /* Request a slot reset. */
        return PCI_ERS_RESULT_NEED_RESET;
 }
 
index 975eb47..57d39ee 100644 (file)
@@ -227,7 +227,7 @@ struct igbvf_adapter {
 
        /* The VF counters don't clear on read so we have to get a base
         * count on driver start up and always subtract that base on
-        * on the first update, thus the flag..
+        * the first update, thus the flag..
         */
        struct e1000_vf_stats stats;
        u64 zero_base;
index 43ced78..f4e91db 100644 (file)
@@ -2537,7 +2537,7 @@ static pci_ers_result_t igbvf_io_error_detected(struct pci_dev *pdev,
                igbvf_down(adapter);
        pci_disable_device(pdev);
 
-       /* Request a slot slot reset. */
+       /* Request a slot reset. */
        return PCI_ERS_RESULT_NEED_RESET;
 }
 
index 67b8ffd..a5c4b19 100644 (file)
@@ -193,7 +193,7 @@ s32 igc_force_mac_fc(struct igc_hw *hw)
         *      1:  Rx flow control is enabled (we can receive pause
         *          frames but not send pause frames).
         *      2:  Tx flow control is enabled (we can send pause frames
-        *          frames but we do not receive pause frames).
+        *          but we do not receive pause frames).
         *      3:  Both Rx and TX flow control (symmetric) is enabled.
         *  other:  No other values should be possible at this point.
         */
index 653e9f1..8dbb9f9 100644 (file)
@@ -15,7 +15,6 @@
 #define INCVALUE_MASK          0x7fffffff
 #define ISGN                   0x80000000
 
-#define IGC_SYSTIM_OVERFLOW_PERIOD     (HZ * 60 * 9)
 #define IGC_PTP_TX_TIMEOUT             (HZ * 15)
 
 #define IGC_PTM_STAT_SLEEP             2
index c8d1e81..98bd326 100644 (file)
@@ -576,7 +576,7 @@ ixgb_rar_set(struct ixgb_hw *hw,
  * Writes a value to the specified offset in the VLAN filter table.
  *
  * hw - Struct containing variables accessed by shared code
- * offset - Offset in VLAN filer table to write
+ * offset - Offset in VLAN filter table to write
  * value - Value to write into VLAN filter table
  *****************************************************************************/
 void
@@ -588,7 +588,7 @@ ixgb_write_vfta(struct ixgb_hw *hw,
 }
 
 /******************************************************************************
- * Clears the VLAN filer table
+ * Clears the VLAN filter table
  *
  * hw - Struct containing variables accessed by shared code
  *****************************************************************************/
index affdefc..45be9a1 100644 (file)
@@ -1187,7 +1187,7 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
                if (err < 0)
                        return err;
 
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                mss = skb_shinfo(skb)->gso_size;
                iph = ip_hdr(skb);
                iph->tot_len = 0;
@@ -1704,7 +1704,6 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
        netdev->stats.tx_window_errors = 0;
 }
 
-#define IXGB_MAX_INTR 10
 /**
  * ixgb_intr - Interrupt Handler
  * @irq: interrupt number
index f0cadd5..d40f962 100644 (file)
@@ -141,8 +141,6 @@ IXGB_PARAM(IntDelayEnable, "Transmit Interrupt Delay Enable");
 #define MAX_RDTR                        0xFFFF
 #define MIN_RDTR                             0
 
-#define XSUMRX_DEFAULT          OPTION_ENABLED
-
 #define DEFAULT_FCRTL                  0x28000
 #define DEFAULT_FCRTH                  0x30000
 #define MIN_FCRTL                            0
index 921a4d9..48444ab 100644 (file)
@@ -167,12 +167,46 @@ enum ixgbe_tx_flags {
 #define IXGBE_82599_VF_DEVICE_ID        0x10ED
 #define IXGBE_X540_VF_DEVICE_ID         0x1515
 
+#define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter)    \
+       {                                                       \
+               u32 current_counter = IXGBE_READ_REG(hw, reg);  \
+               if (current_counter < last_counter)             \
+                       counter += 0x100000000LL;               \
+               last_counter = current_counter;                 \
+               counter &= 0xFFFFFFFF00000000LL;                \
+               counter |= current_counter;                     \
+       }
+
+#define UPDATE_VF_COUNTER_36bit(reg_lsb, reg_msb, last_counter, counter) \
+       {                                                                \
+               u64 current_counter_lsb = IXGBE_READ_REG(hw, reg_lsb);   \
+               u64 current_counter_msb = IXGBE_READ_REG(hw, reg_msb);   \
+               u64 current_counter = (current_counter_msb << 32) |      \
+                       current_counter_lsb;                             \
+               if (current_counter < last_counter)                      \
+                       counter += 0x1000000000LL;                       \
+               last_counter = current_counter;                          \
+               counter &= 0xFFFFFFF000000000LL;                         \
+               counter |= current_counter;                              \
+       }
+
+struct vf_stats {
+       u64 gprc;
+       u64 gorc;
+       u64 gptc;
+       u64 gotc;
+       u64 mprc;
+};
+
 struct vf_data_storage {
        struct pci_dev *vfdev;
        unsigned char vf_mac_addresses[ETH_ALEN];
        u16 vf_mc_hashes[IXGBE_MAX_VF_MC_ENTRIES];
        u16 num_vf_mc_hashes;
        bool clear_to_send;
+       struct vf_stats vfstats;
+       struct vf_stats last_vfstats;
+       struct vf_stats saved_rst_vfstats;
        bool pf_set_mac;
        u16 pf_vlan; /* When set, guest VLAN config not allowed. */
        u16 pf_qos;
index 95c92fe..1003889 100644 (file)
@@ -879,7 +879,7 @@ static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind,
  *  ixgbe_clear_vfta_82598 - Clear VLAN filter table
  *  @hw: pointer to hardware structure
  *
- *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ *  Clears the VLAN filter table, and the VMDq index associated with the filter
  **/
 static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw)
 {
index 4c26c4b..38c4609 100644 (file)
@@ -3237,7 +3237,7 @@ vfta_update:
  *  ixgbe_clear_vfta_generic - Clear VLAN filter table
  *  @hw: pointer to hardware structure
  *
- *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ *  Clears the VLAN filter table, and the VMDq index associated with the filter
  **/
 s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw)
 {
index 72e6ebf..e85f7d2 100644 (file)
@@ -8,12 +8,10 @@
 #include "ixgbe_sriov.h"
 
 /* Callbacks for DCB netlink in the kernel */
-#define BIT_DCB_MODE   0x01
 #define BIT_PFC                0x02
 #define BIT_PG_RX      0x04
 #define BIT_PG_TX      0x08
 #define BIT_APP_UPCHG  0x10
-#define BIT_LINKSPEED   0x80
 
 /* Responses for the DCB_C_SET_ALL command */
 #define DCB_HW_CHG_RST  0  /* DCB configuration changed with reset */
index 628d0eb..04f453e 100644 (file)
@@ -18,8 +18,6 @@
 #include "ixgbe_phy.h"
 
 
-#define IXGBE_ALL_RAR_ENTRIES 16
-
 enum {NETDEV_STATS, IXGBE_STATS};
 
 struct ixgbe_stats {
index 77c2e70..0493326 100644 (file)
@@ -5161,7 +5161,7 @@ static int ixgbe_hpbthresh(struct ixgbe_adapter *adapter, int pb)
 }
 
 /**
- * ixgbe_lpbthresh - calculate low water mark for for flow control
+ * ixgbe_lpbthresh - calculate low water mark for flow control
  *
  * @adapter: board private structure to calculate for
  * @pb: packet buffer to calculate
@@ -5549,6 +5549,47 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
        return ret;
 }
 
+/**
+ * ixgbe_clear_vf_stats_counters - Clear out VF stats after reset
+ * @adapter: board private structure
+ *
+ * On a reset we need to clear out the VF stats or accounting gets
+ * messed up because they're not clear on read.
+ **/
+static void ixgbe_clear_vf_stats_counters(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       int i;
+
+       for (i = 0; i < adapter->num_vfs; i++) {
+               adapter->vfinfo[i].last_vfstats.gprc =
+                       IXGBE_READ_REG(hw, IXGBE_PVFGPRC(i));
+               adapter->vfinfo[i].saved_rst_vfstats.gprc +=
+                       adapter->vfinfo[i].vfstats.gprc;
+               adapter->vfinfo[i].vfstats.gprc = 0;
+               adapter->vfinfo[i].last_vfstats.gptc =
+                       IXGBE_READ_REG(hw, IXGBE_PVFGPTC(i));
+               adapter->vfinfo[i].saved_rst_vfstats.gptc +=
+                       adapter->vfinfo[i].vfstats.gptc;
+               adapter->vfinfo[i].vfstats.gptc = 0;
+               adapter->vfinfo[i].last_vfstats.gorc =
+                       IXGBE_READ_REG(hw, IXGBE_PVFGORC_LSB(i));
+               adapter->vfinfo[i].saved_rst_vfstats.gorc +=
+                       adapter->vfinfo[i].vfstats.gorc;
+               adapter->vfinfo[i].vfstats.gorc = 0;
+               adapter->vfinfo[i].last_vfstats.gotc =
+                       IXGBE_READ_REG(hw, IXGBE_PVFGOTC_LSB(i));
+               adapter->vfinfo[i].saved_rst_vfstats.gotc +=
+                       adapter->vfinfo[i].vfstats.gotc;
+               adapter->vfinfo[i].vfstats.gotc = 0;
+               adapter->vfinfo[i].last_vfstats.mprc =
+                       IXGBE_READ_REG(hw, IXGBE_PVFMPRC(i));
+               adapter->vfinfo[i].saved_rst_vfstats.mprc +=
+                       adapter->vfinfo[i].vfstats.mprc;
+               adapter->vfinfo[i].vfstats.mprc = 0;
+       }
+}
+
 static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
@@ -5684,6 +5725,7 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
        adapter->link_check_timeout = jiffies;
        mod_timer(&adapter->service_timer, jiffies);
 
+       ixgbe_clear_vf_stats_counters(adapter);
        /* Set PF Reset Done bit so PF/VF Mail Ops can work */
        ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
        ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
@@ -7271,6 +7313,32 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        netdev->stats.rx_length_errors = hwstats->rlec;
        netdev->stats.rx_crc_errors = hwstats->crcerrs;
        netdev->stats.rx_missed_errors = total_mpc;
+
+       /* VF Stats Collection - skip while resetting because these
+        * are not clear on read and otherwise you'll sometimes get
+        * crazy values.
+        */
+       if (!test_bit(__IXGBE_RESETTING, &adapter->state)) {
+               for (i = 0; i < adapter->num_vfs; i++) {
+                       UPDATE_VF_COUNTER_32bit(IXGBE_PVFGPRC(i),
+                                               adapter->vfinfo[i].last_vfstats.gprc,
+                                               adapter->vfinfo[i].vfstats.gprc);
+                       UPDATE_VF_COUNTER_32bit(IXGBE_PVFGPTC(i),
+                                               adapter->vfinfo[i].last_vfstats.gptc,
+                                               adapter->vfinfo[i].vfstats.gptc);
+                       UPDATE_VF_COUNTER_36bit(IXGBE_PVFGORC_LSB(i),
+                                               IXGBE_PVFGORC_MSB(i),
+                                               adapter->vfinfo[i].last_vfstats.gorc,
+                                               adapter->vfinfo[i].vfstats.gorc);
+                       UPDATE_VF_COUNTER_36bit(IXGBE_PVFGOTC_LSB(i),
+                                               IXGBE_PVFGOTC_MSB(i),
+                                               adapter->vfinfo[i].last_vfstats.gotc,
+                                               adapter->vfinfo[i].vfstats.gotc);
+                       UPDATE_VF_COUNTER_32bit(IXGBE_PVFMPRC(i),
+                                               adapter->vfinfo[i].last_vfstats.mprc,
+                                               adapter->vfinfo[i].vfstats.mprc);
+               }
+       }
 }
 
 /**
@@ -9022,6 +9090,23 @@ static void ixgbe_get_stats64(struct net_device *netdev,
        stats->rx_missed_errors = netdev->stats.rx_missed_errors;
 }
 
+static int ixgbe_ndo_get_vf_stats(struct net_device *netdev, int vf,
+                                 struct ifla_vf_stats *vf_stats)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       if (vf < 0 || vf >= adapter->num_vfs)
+               return -EINVAL;
+
+       vf_stats->rx_packets = adapter->vfinfo[vf].vfstats.gprc;
+       vf_stats->rx_bytes   = adapter->vfinfo[vf].vfstats.gorc;
+       vf_stats->tx_packets = adapter->vfinfo[vf].vfstats.gptc;
+       vf_stats->tx_bytes   = adapter->vfinfo[vf].vfstats.gotc;
+       vf_stats->multicast  = adapter->vfinfo[vf].vfstats.mprc;
+
+       return 0;
+}
+
 #ifdef CONFIG_IXGBE_DCB
 /**
  * ixgbe_validate_rtr - verify 802.1Qp to Rx packet buffer mapping is valid.
@@ -10338,6 +10423,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_set_vf_rss_query_en = ixgbe_ndo_set_vf_rss_query_en,
        .ndo_set_vf_trust       = ixgbe_ndo_set_vf_trust,
        .ndo_get_vf_config      = ixgbe_ndo_get_vf_config,
+       .ndo_get_vf_stats       = ixgbe_ndo_get_vf_stats,
        .ndo_get_stats64        = ixgbe_get_stats64,
        .ndo_setup_tc           = __ixgbe_setup_tc,
 #ifdef IXGBE_FCOE
index 336426a..27a71fa 100644 (file)
 #define IXGBE_X550_BASE_PERIOD 0xC80000000ULL
 #define INCVALUE_MASK  0x7FFFFFFF
 #define ISGN           0x80000000
-#define MAX_TIMADJ     0x7FFFFFFF
 
 /**
  * ixgbe_ptp_setup_sdp_X540
index d4e63f0..67e49aa 100644 (file)
@@ -77,7 +77,7 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
        IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
        adapter->bridge_mode = BRIDGE_MODE_VEB;
 
-       /* limit trafffic classes based on VFs enabled */
+       /* limit traffic classes based on VFs enabled */
        if ((adapter->hw.mac.type == ixgbe_mac_82599EB) && (num_vfs < 16)) {
                adapter->dcb_cfg.num_tcs.pg_tcs = MAX_TRAFFIC_CLASS;
                adapter->dcb_cfg.num_tcs.pfc_tcs = MAX_TRAFFIC_CLASS;
index 6da9880..7f7ea46 100644 (file)
@@ -2533,6 +2533,13 @@ enum {
 #define IXGBE_PVFTXDCTL(P)     (0x06028 + (0x40 * (P)))
 #define IXGBE_PVFTDWBAL(P)     (0x06038 + (0x40 * (P)))
 #define IXGBE_PVFTDWBAH(P)     (0x0603C + (0x40 * (P)))
+#define IXGBE_PVFGPRC(x)       (0x0101C + (0x40 * (x)))
+#define IXGBE_PVFGPTC(x)       (0x08300 + (0x04 * (x)))
+#define IXGBE_PVFGORC_LSB(x)   (0x01020 + (0x40 * (x)))
+#define IXGBE_PVFGORC_MSB(x)   (0x0D020 + (0x40 * (x)))
+#define IXGBE_PVFGOTC_LSB(x)   (0x08400 + (0x08 * (x)))
+#define IXGBE_PVFGOTC_MSB(x)   (0x08404 + (0x08 * (x)))
+#define IXGBE_PVFMPRC(x)       (0x0D01C + (0x40 * (x)))
 
 #define IXGBE_PVFTDWBALn(q_per_pool, vf_number, vf_q_index) \
                (IXGBE_PVFTDWBAL((q_per_pool)*(vf_number) + (vf_q_index)))
index e4b50c7..35c2b9b 100644 (file)
@@ -1737,7 +1737,7 @@ static s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
  * @speed: link speed
  * @autoneg_wait_to_complete: unused
  *
- * Configure the the integrated PHY for native SFP support.
+ * Configure the integrated PHY for native SFP support.
  */
 static s32
 ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed,
@@ -1786,7 +1786,7 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed,
  * @speed: link speed
  * @autoneg_wait_to_complete: unused
  *
- * Configure the the integrated PHY for SFP support.
+ * Configure the integrated PHY for SFP support.
  */
 static s32
 ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed,
index 3b41f83..fed4687 100644 (file)
@@ -17,8 +17,6 @@
 
 #include "ixgbevf.h"
 
-#define IXGBE_ALL_RAR_ENTRIES 16
-
 enum {NETDEV_STATS, IXGBEVF_STATS};
 
 struct ixgbe_stats {
@@ -130,8 +128,6 @@ static void ixgbevf_set_msglevel(struct net_device *netdev, u32 data)
        adapter->msg_enable = data;
 }
 
-#define IXGBE_GET_STAT(_A_, _R_) (_A_->stats._R_)
-
 static int ixgbevf_get_regs_len(struct net_device *netdev)
 {
 #define IXGBE_REGS_LEN 45
index 55b87bc..2f12fbe 100644 (file)
@@ -4787,7 +4787,7 @@ static pci_ers_result_t ixgbevf_io_error_detected(struct pci_dev *pdev,
                pci_disable_device(pdev);
        rtnl_unlock();
 
-       /* Request a slot slot reset. */
+       /* Request a slot reset. */
        return PCI_ERS_RESULT_NEED_RESET;
 }
 
index 68fc32e..1641d00 100644 (file)
@@ -964,7 +964,7 @@ int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
        if (!err) {
                msg[0] &= ~IXGBE_VT_MSGTYPE_CTS;
 
-               /* if we we didn't get an ACK there must have been
+               /* if we didn't get an ACK there must have been
                 * some sort of mailbox error so we should treat it
                 * as such
                 */
index 57eff4e..b6be055 100644 (file)
@@ -775,7 +775,7 @@ txq_put_hdr_tso(struct sk_buff *skb, struct tx_queue *txq, int length,
                u32 *first_cmd_sts, bool first_desc)
 {
        struct mv643xx_eth_private *mp = txq_to_mp(txq);
-       int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       int hdr_len = skb_tcp_all_headers(skb);
        int tx_index;
        struct tx_desc *desc;
        int ret;
index 384f5a1..0caa2df 100644 (file)
@@ -2664,8 +2664,8 @@ err_drop_frame:
 static inline void
 mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_tx_queue *txq)
 {
-       int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
        struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index];
+       int hdr_len = skb_tcp_all_headers(skb);
        struct mvneta_tx_desc *tx_desc;
 
        tx_desc = mvneta_txq_next_desc_get(txq);
@@ -2727,7 +2727,7 @@ static int mvneta_tx_tso(struct sk_buff *skb, struct net_device *dev,
        if ((txq->count + tso_count_descs(skb)) >= txq->size)
                return 0;
 
-       if (skb_headlen(skb) < (skb_transport_offset(skb) + tcp_hdrlen(skb))) {
+       if (skb_headlen(skb) < skb_tcp_all_headers(skb)) {
                pr_info("*** Is this even possible?\n");
                return 0;
        }
index a9da85e..38bbae5 100644 (file)
@@ -17,7 +17,7 @@
 #define        PCI_DEVID_OTX2_CPT10K_PF 0xA0F2
 
 /* Length of initial context fetch in 128 byte words */
-#define CPT_CTX_ILEN    2
+#define CPT_CTX_ILEN    2ULL
 
 #define cpt_get_eng_sts(e_min, e_max, rsp, etype)                   \
 ({                                                                  \
@@ -480,7 +480,7 @@ static int cpt_inline_ipsec_cfg_inbound(struct rvu *rvu, int blkaddr, u8 cptlf,
         */
        if (!is_rvu_otx2(rvu)) {
                val = (ilog2(NIX_CHAN_CPT_X2P_MASK + 1) << 16);
-               val |= rvu->hw->cpt_chan_base;
+               val |= (u64)rvu->hw->cpt_chan_base;
 
                rvu_write64(rvu, blkaddr, CPT_AF_X2PX_LINK_CFG(0), val);
                rvu_write64(rvu, blkaddr, CPT_AF_X2PX_LINK_CFG(1), val);
index 3a31fb8..e05fd2b 100644 (file)
@@ -2534,7 +2534,7 @@ alloc:
 
        /* Copy MCAM entry indices into mbox response entry_list.
         * Requester always expects indices in ascending order, so
-        * so reverse the list if reverse bitmap is used for allocation.
+        * reverse the list if reverse bitmap is used for allocation.
         */
        if (!req->contig && rsp->count) {
                index = 0;
index 3baeafc..a18e8ef 100644 (file)
@@ -624,7 +624,7 @@ static void otx2_sqe_add_ext(struct otx2_nic *pfvf, struct otx2_snd_queue *sq,
        ext->subdc = NIX_SUBDC_EXT;
        if (skb_shinfo(skb)->gso_size) {
                ext->lso = 1;
-               ext->lso_sb = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               ext->lso_sb = skb_tcp_all_headers(skb);
                ext->lso_mps = skb_shinfo(skb)->gso_size;
 
                /* Only TSOv4 and TSOv6 GSO offloads are supported */
@@ -931,7 +931,7 @@ static bool is_hw_tso_supported(struct otx2_nic *pfvf,
         * be correctly modified, hence don't offload such TSO segments.
         */
 
-       payload_len = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+       payload_len = skb->len - skb_tcp_all_headers(skb);
        last_seg_size = payload_len % skb_shinfo(skb)->gso_size;
        if (last_seg_size && last_seg_size < 16)
                return false;
index 6f754ae..0bb46ee 100644 (file)
@@ -107,7 +107,8 @@ struct prestera_port_phy_config {
 struct prestera_port {
        struct net_device *dev;
        struct prestera_switch *sw;
-       struct prestera_flow_block *flow_block;
+       struct prestera_flow_block *ingress_flow_block;
+       struct prestera_flow_block *egress_flow_block;
        struct devlink_port dl_port;
        struct list_head lag_member;
        struct prestera_lag *lag;
index 3a141f2..3d4b85f 100644 (file)
@@ -61,6 +61,7 @@ struct prestera_acl_ruleset {
        u32 index;
        u16 pcl_id;
        bool offload;
+       bool ingress;
 };
 
 struct prestera_acl_vtcam {
@@ -70,6 +71,7 @@ struct prestera_acl_vtcam {
        u32 id;
        bool is_keymask_set;
        u8 lookup;
+       u8 direction;
 };
 
 static const struct rhashtable_params prestera_acl_ruleset_ht_params = {
@@ -93,23 +95,36 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = {
        .automatic_shrinking = true,
 };
 
-int prestera_acl_chain_to_client(u32 chain_index, u32 *client)
+int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client)
 {
-       static const u32 client_map[] = {
-               PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0,
-               PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1,
-               PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2
+       static const u32 ingress_client_map[] = {
+               PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0,
+               PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1,
+               PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2
        };
 
-       if (chain_index >= ARRAY_SIZE(client_map))
+       if (!ingress) {
+               /* prestera supports only one chain on egress */
+               if (chain_index > 0)
+                       return -EINVAL;
+
+               *client = PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP;
+               return 0;
+       }
+
+       if (chain_index >= ARRAY_SIZE(ingress_client_map))
                return -EINVAL;
 
-       *client = client_map[chain_index];
+       *client = ingress_client_map[chain_index];
        return 0;
 }
 
-static bool prestera_acl_chain_is_supported(u32 chain_index)
+static bool prestera_acl_chain_is_supported(u32 chain_index, bool ingress)
 {
+       if (!ingress)
+               /* prestera supports only one chain on egress */
+               return chain_index == 0;
+
        return (chain_index & ~PRESTERA_ACL_CHAIN_MASK) == 0;
 }
 
@@ -122,7 +137,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
        u32 uid = 0;
        int err;
 
-       if (!prestera_acl_chain_is_supported(chain_index))
+       if (!prestera_acl_chain_is_supported(chain_index, block->ingress))
                return ERR_PTR(-EINVAL);
 
        ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL);
@@ -130,6 +145,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
                return ERR_PTR(-ENOMEM);
 
        ruleset->acl = acl;
+       ruleset->ingress = block->ingress;
        ruleset->ht_key.block = block;
        ruleset->ht_key.chain_index = chain_index;
        refcount_set(&ruleset->refcount, 1);
@@ -172,13 +188,18 @@ int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset)
 {
        struct prestera_acl_iface iface;
        u32 vtcam_id;
+       int dir;
        int err;
 
+       dir = ruleset->ingress ?
+               PRESTERA_HW_VTCAM_DIR_INGRESS : PRESTERA_HW_VTCAM_DIR_EGRESS;
+
        if (ruleset->offload)
                return -EEXIST;
 
        err = prestera_acl_vtcam_id_get(ruleset->acl,
                                        ruleset->ht_key.chain_index,
+                                       dir,
                                        ruleset->keymask, &vtcam_id);
        if (err)
                goto err_vtcam_create;
@@ -719,7 +740,7 @@ vtcam_found:
        return 0;
 }
 
-int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
+int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir,
                              void *keymask, u32 *vtcam_id)
 {
        struct prestera_acl_vtcam *vtcam;
@@ -731,7 +752,8 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
         * fine for now
         */
        list_for_each_entry(vtcam, &acl->vtcam_list, list) {
-               if (lookup != vtcam->lookup)
+               if (lookup != vtcam->lookup ||
+                   dir != vtcam->direction)
                        continue;
 
                if (!keymask && !vtcam->is_keymask_set) {
@@ -752,7 +774,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
                return -ENOMEM;
 
        err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id,
-                                      PRESTERA_HW_VTCAM_DIR_INGRESS);
+                                      dir);
        if (err) {
                kfree(vtcam);
 
@@ -765,6 +787,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
                return 0;
        }
 
+       vtcam->direction = dir;
        vtcam->id = new_vtcam_id;
        vtcam->lookup = lookup;
        if (keymask) {
index f963e1e..03fc5b9 100644 (file)
@@ -199,9 +199,9 @@ void
 prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule,
                                     u16 pcl_id);
 
-int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
+int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir,
                              void *keymask, u32 *vtcam_id);
 int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id);
-int prestera_acl_chain_to_client(u32 chain_index, u32 *client);
+int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client);
 
 #endif /* _PRESTERA_ACL_H_ */
index 05c3ad9..2262693 100644 (file)
@@ -75,7 +75,9 @@ static void prestera_flow_block_destroy(void *cb_priv)
 }
 
 static struct prestera_flow_block *
-prestera_flow_block_create(struct prestera_switch *sw, struct net *net)
+prestera_flow_block_create(struct prestera_switch *sw,
+                          struct net *net,
+                          bool ingress)
 {
        struct prestera_flow_block *block;
 
@@ -87,6 +89,7 @@ prestera_flow_block_create(struct prestera_switch *sw, struct net *net)
        INIT_LIST_HEAD(&block->template_list);
        block->net = net;
        block->sw = sw;
+       block->ingress = ingress;
 
        return block;
 }
@@ -165,7 +168,8 @@ static int prestera_flow_block_unbind(struct prestera_flow_block *block,
 static struct prestera_flow_block *
 prestera_flow_block_get(struct prestera_switch *sw,
                        struct flow_block_offload *f,
-                       bool *register_block)
+                       bool *register_block,
+                       bool ingress)
 {
        struct prestera_flow_block *block;
        struct flow_block_cb *block_cb;
@@ -173,7 +177,7 @@ prestera_flow_block_get(struct prestera_switch *sw,
        block_cb = flow_block_cb_lookup(f->block,
                                        prestera_flow_block_cb, sw);
        if (!block_cb) {
-               block = prestera_flow_block_create(sw, f->net);
+               block = prestera_flow_block_create(sw, f->net, ingress);
                if (!block)
                        return ERR_PTR(-ENOMEM);
 
@@ -209,7 +213,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block)
 }
 
 static int prestera_setup_flow_block_bind(struct prestera_port *port,
-                                         struct flow_block_offload *f)
+                                         struct flow_block_offload *f, bool ingress)
 {
        struct prestera_switch *sw = port->sw;
        struct prestera_flow_block *block;
@@ -217,7 +221,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
        bool register_block;
        int err;
 
-       block = prestera_flow_block_get(sw, f, &register_block);
+       block = prestera_flow_block_get(sw, f, &register_block, ingress);
        if (IS_ERR(block))
                return PTR_ERR(block);
 
@@ -232,7 +236,11 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
                list_add_tail(&block_cb->driver_list, &prestera_block_cb_list);
        }
 
-       port->flow_block = block;
+       if (ingress)
+               port->ingress_flow_block = block;
+       else
+               port->egress_flow_block = block;
+
        return 0;
 
 err_block_bind:
@@ -242,7 +250,7 @@ err_block_bind:
 }
 
 static void prestera_setup_flow_block_unbind(struct prestera_port *port,
-                                            struct flow_block_offload *f)
+                                            struct flow_block_offload *f, bool ingress)
 {
        struct prestera_switch *sw = port->sw;
        struct prestera_flow_block *block;
@@ -266,24 +274,38 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port,
                list_del(&block_cb->driver_list);
        }
 error:
-       port->flow_block = NULL;
+       if (ingress)
+               port->ingress_flow_block = NULL;
+       else
+               port->egress_flow_block = NULL;
 }
 
-int prestera_flow_block_setup(struct prestera_port *port,
-                             struct flow_block_offload *f)
+static int prestera_setup_flow_block_clsact(struct prestera_port *port,
+                                           struct flow_block_offload *f,
+                                           bool ingress)
 {
-       if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
-               return -EOPNOTSUPP;
-
        f->driver_block_list = &prestera_block_cb_list;
 
        switch (f->command) {
        case FLOW_BLOCK_BIND:
-               return prestera_setup_flow_block_bind(port, f);
+               return prestera_setup_flow_block_bind(port, f, ingress);
        case FLOW_BLOCK_UNBIND:
-               prestera_setup_flow_block_unbind(port, f);
+               prestera_setup_flow_block_unbind(port, f, ingress);
                return 0;
        default:
                return -EOPNOTSUPP;
        }
 }
+
+int prestera_flow_block_setup(struct prestera_port *port,
+                             struct flow_block_offload *f)
+{
+       switch (f->binder_type) {
+       case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
+               return prestera_setup_flow_block_clsact(port, f, true);
+       case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
+               return prestera_setup_flow_block_clsact(port, f, false);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
index 6550278..0c9e132 100644 (file)
@@ -23,6 +23,7 @@ struct prestera_flow_block {
        struct flow_block_cb *block_cb;
        struct list_head template_list;
        unsigned int rule_count;
+       bool ingress;
 };
 
 int prestera_flow_block_setup(struct prestera_port *port,
index d43e503..a54748a 100644 (file)
@@ -79,7 +79,7 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block,
        } else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) {
                /* setup counter first */
                rule->re_arg.count.valid = true;
-               err = prestera_acl_chain_to_client(chain_index,
+               err = prestera_acl_chain_to_client(chain_index, block->ingress,
                                                   &rule->re_arg.count.client);
                if (err)
                        return err;
index 579d9ba..aa74f66 100644 (file)
@@ -123,9 +123,10 @@ enum prestera_hw_vtcam_direction_t {
 };
 
 enum {
-       PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0 = 0,
-       PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1 = 1,
-       PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 = 2,
+       PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0 = 0,
+       PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1 = 1,
+       PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2 = 2,
+       PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP = 3,
 };
 
 struct prestera_switch;
index a1e907c..bbea545 100644 (file)
@@ -1863,7 +1863,7 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
        if (mss != 0) {
 
                if (!(hw->flags & SKY2_HW_NEW_LE))
-                       mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
+                       mss += skb_tcp_all_headers(skb);
 
                if (mss != sky2->tx_last_mss) {
                        le = get_tx_le(sky2, &slot);
@@ -4711,7 +4711,7 @@ static irqreturn_t sky2_test_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Test interrupt path by forcing a software IRQ */
+/* Test interrupt path by forcing a software IRQ */
 static int sky2_test_msi(struct sky2_hw *hw)
 {
        struct pci_dev *pdev = hw->pdev;
index 59c9a10..6beb3d4 100644 (file)
@@ -1444,8 +1444,8 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
        int done = 0, bytes = 0;
 
        while (done < budget) {
+               unsigned int pktlen, *rxdcsum;
                struct net_device *netdev;
-               unsigned int pktlen;
                dma_addr_t dma_addr;
                u32 hash, reason;
                int mac = 0;
@@ -1512,7 +1512,13 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
                pktlen = RX_DMA_GET_PLEN0(trxd.rxd2);
                skb->dev = netdev;
                skb_put(skb, pktlen);
-               if (trxd.rxd4 & eth->soc->txrx.rx_dma_l4_valid)
+
+               if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+                       rxdcsum = &trxd.rxd3;
+               else
+                       rxdcsum = &trxd.rxd4;
+
+               if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
                        skb_checksum_none_assert(skb);
@@ -3761,6 +3767,7 @@ static const struct mtk_soc_data mt7986_data = {
                .txd_size = sizeof(struct mtk_tx_dma_v2),
                .rxd_size = sizeof(struct mtk_rx_dma_v2),
                .rx_irq_done_mask = MTK_RX_DONE_INT_V2,
+               .rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
                .dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
                .dma_len_offset = 8,
        },
index 95839fd..21c3668 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/platform_device.h>
@@ -32,6 +33,7 @@
 #define MTK_STAR_SKB_ALIGNMENT                 16
 #define MTK_STAR_HASHTABLE_MC_LIMIT            256
 #define MTK_STAR_HASHTABLE_SIZE_MAX            512
+#define MTK_STAR_DESC_NEEDED                   (MAX_SKB_FRAGS + 4)
 
 /* Normally we'd use NET_IP_ALIGN but on arm64 its value is 0 and it doesn't
  * work for this controller.
@@ -129,6 +131,11 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
 #define MTK_STAR_REG_INT_MASK                  0x0054
 #define MTK_STAR_BIT_INT_MASK_FNRC             BIT(6)
 
+/* Delay-Macro Register */
+#define MTK_STAR_REG_TEST0                     0x0058
+#define MTK_STAR_BIT_INV_RX_CLK                        BIT(30)
+#define MTK_STAR_BIT_INV_TX_CLK                        BIT(31)
+
 /* Misc. Config Register */
 #define MTK_STAR_REG_TEST1                     0x005c
 #define MTK_STAR_BIT_TEST1_RST_HASH_MBIST      BIT(31)
@@ -149,6 +156,7 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
 #define MTK_STAR_REG_MAC_CLK_CONF              0x00ac
 #define MTK_STAR_MSK_MAC_CLK_CONF              GENMASK(7, 0)
 #define MTK_STAR_BIT_CLK_DIV_10                        0x0a
+#define MTK_STAR_BIT_CLK_DIV_50                        0x32
 
 /* Counter registers. */
 #define MTK_STAR_REG_C_RXOKPKT                 0x0100
@@ -181,9 +189,14 @@ static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
 #define MTK_STAR_REG_C_RX_TWIST                        0x0218
 
 /* Ethernet CFG Control */
-#define MTK_PERICFG_REG_NIC_CFG_CON            0x03c4
-#define MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII    GENMASK(3, 0)
-#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII       BIT(0)
+#define MTK_PERICFG_REG_NIC_CFG0_CON           0x03c4
+#define MTK_PERICFG_REG_NIC_CFG1_CON           0x03c8
+#define MTK_PERICFG_REG_NIC_CFG_CON_V2         0x0c10
+#define MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF   GENMASK(3, 0)
+#define MTK_PERICFG_BIT_NIC_CFG_CON_MII                0
+#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII       1
+#define MTK_PERICFG_BIT_NIC_CFG_CON_CLK                BIT(0)
+#define MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2     BIT(8)
 
 /* Represents the actual structure of descriptors used by the MAC. We can
  * reuse the same structure for both TX and RX - the layout is the same, only
@@ -216,7 +229,8 @@ struct mtk_star_ring_desc_data {
        struct sk_buff *skb;
 };
 
-#define MTK_STAR_RING_NUM_DESCS                        128
+#define MTK_STAR_RING_NUM_DESCS                        512
+#define MTK_STAR_TX_THRESH                     (MTK_STAR_RING_NUM_DESCS / 4)
 #define MTK_STAR_NUM_TX_DESCS                  MTK_STAR_RING_NUM_DESCS
 #define MTK_STAR_NUM_RX_DESCS                  MTK_STAR_RING_NUM_DESCS
 #define MTK_STAR_NUM_DESCS_TOTAL               (MTK_STAR_RING_NUM_DESCS * 2)
@@ -231,6 +245,11 @@ struct mtk_star_ring {
        unsigned int tail;
 };
 
+struct mtk_star_compat {
+       int (*set_interface_mode)(struct net_device *ndev);
+       unsigned char bit_clk_div;
+};
+
 struct mtk_star_priv {
        struct net_device *ndev;
 
@@ -246,7 +265,8 @@ struct mtk_star_priv {
        struct mtk_star_ring rx_ring;
 
        struct mii_bus *mii;
-       struct napi_struct napi;
+       struct napi_struct tx_napi;
+       struct napi_struct rx_napi;
 
        struct device_node *phy_node;
        phy_interface_t phy_intf;
@@ -255,6 +275,11 @@ struct mtk_star_priv {
        int speed;
        int duplex;
        int pause;
+       bool rmii_rxc;
+       bool rx_inv;
+       bool tx_inv;
+
+       const struct mtk_star_compat *compat_data;
 
        /* Protects against concurrent descriptor access. */
        spinlock_t lock;
@@ -357,19 +382,16 @@ mtk_star_ring_push_head_tx(struct mtk_star_ring *ring,
        mtk_star_ring_push_head(ring, desc_data, flags);
 }
 
-static unsigned int mtk_star_ring_num_used_descs(struct mtk_star_ring *ring)
+static unsigned int mtk_star_tx_ring_avail(struct mtk_star_ring *ring)
 {
-       return abs(ring->head - ring->tail);
-}
+       u32 avail;
 
-static bool mtk_star_ring_full(struct mtk_star_ring *ring)
-{
-       return mtk_star_ring_num_used_descs(ring) == MTK_STAR_RING_NUM_DESCS;
-}
+       if (ring->tail > ring->head)
+               avail = ring->tail - ring->head - 1;
+       else
+               avail = MTK_STAR_RING_NUM_DESCS - ring->head + ring->tail - 1;
 
-static bool mtk_star_ring_descs_available(struct mtk_star_ring *ring)
-{
-       return mtk_star_ring_num_used_descs(ring) > 0;
+       return avail;
 }
 
 static dma_addr_t mtk_star_dma_map_rx(struct mtk_star_priv *priv,
@@ -414,6 +436,36 @@ static void mtk_star_nic_disable_pd(struct mtk_star_priv *priv)
                          MTK_STAR_BIT_MAC_CFG_NIC_PD);
 }
 
+static void mtk_star_enable_dma_irq(struct mtk_star_priv *priv,
+                                   bool rx, bool tx)
+{
+       u32 value;
+
+       regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
+
+       if (tx)
+               value &= ~MTK_STAR_BIT_INT_STS_TNTC;
+       if (rx)
+               value &= ~MTK_STAR_BIT_INT_STS_FNRC;
+
+       regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
+}
+
+static void mtk_star_disable_dma_irq(struct mtk_star_priv *priv,
+                                    bool rx, bool tx)
+{
+       u32 value;
+
+       regmap_read(priv->regs, MTK_STAR_REG_INT_MASK, &value);
+
+       if (tx)
+               value |= MTK_STAR_BIT_INT_STS_TNTC;
+       if (rx)
+               value |= MTK_STAR_BIT_INT_STS_FNRC;
+
+       regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, value);
+}
+
 /* Unmask the three interrupts we care about, mask all others. */
 static void mtk_star_intr_enable(struct mtk_star_priv *priv)
 {
@@ -429,20 +481,11 @@ static void mtk_star_intr_disable(struct mtk_star_priv *priv)
        regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~0);
 }
 
-static unsigned int mtk_star_intr_read(struct mtk_star_priv *priv)
-{
-       unsigned int val;
-
-       regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
-
-       return val;
-}
-
 static unsigned int mtk_star_intr_ack_all(struct mtk_star_priv *priv)
 {
        unsigned int val;
 
-       val = mtk_star_intr_read(priv);
+       regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
        regmap_write(priv->regs, MTK_STAR_REG_INT_STS, val);
 
        return val;
@@ -714,25 +757,44 @@ static void mtk_star_free_tx_skbs(struct mtk_star_priv *priv)
        mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_tx);
 }
 
-/* All processing for TX and RX happens in the napi poll callback.
- *
- * FIXME: The interrupt handling should be more fine-grained with each
- * interrupt enabled/disabled independently when needed. Unfortunatly this
- * turned out to impact the driver's stability and until we have something
- * working properly, we're disabling all interrupts during TX & RX processing
- * or when resetting the counter registers.
- */
+/**
+ * mtk_star_handle_irq - Interrupt Handler.
+ * @irq: interrupt number.
+ * @data: pointer to a network interface device structure.
+ * Description : this is the driver interrupt service routine.
+ * it mainly handles:
+ *  1. tx complete interrupt for frame transmission.
+ *  2. rx complete interrupt for frame reception.
+ *  3. MAC Management Counter interrupt to avoid counter overflow.
+ **/
 static irqreturn_t mtk_star_handle_irq(int irq, void *data)
 {
-       struct mtk_star_priv *priv;
-       struct net_device *ndev;
-
-       ndev = data;
-       priv = netdev_priv(ndev);
+       struct net_device *ndev = data;
+       struct mtk_star_priv *priv = netdev_priv(ndev);
+       unsigned int intr_status = mtk_star_intr_ack_all(priv);
+       bool rx, tx;
+
+       rx = (intr_status & MTK_STAR_BIT_INT_STS_FNRC) &&
+            napi_schedule_prep(&priv->rx_napi);
+       tx = (intr_status & MTK_STAR_BIT_INT_STS_TNTC) &&
+            napi_schedule_prep(&priv->tx_napi);
+
+       if (rx || tx) {
+               spin_lock(&priv->lock);
+               /* mask Rx and TX Complete interrupt */
+               mtk_star_disable_dma_irq(priv, rx, tx);
+               spin_unlock(&priv->lock);
+
+               if (rx)
+                       __napi_schedule(&priv->rx_napi);
+               if (tx)
+                       __napi_schedule(&priv->tx_napi);
+       }
 
-       if (netif_running(ndev)) {
-               mtk_star_intr_disable(priv);
-               napi_schedule(&priv->napi);
+       /* interrupt is triggered once any counters reach 0x8000000 */
+       if (intr_status & MTK_STAR_REG_INT_STS_MIB_CNT_TH) {
+               mtk_star_update_stats(priv);
+               mtk_star_reset_counters(priv);
        }
 
        return IRQ_HANDLED;
@@ -821,32 +883,26 @@ static void mtk_star_phy_config(struct mtk_star_priv *priv)
        val <<= MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD;
 
        val |= MTK_STAR_BIT_PHY_CTRL1_AN_EN;
-       val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
-       val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
-       /* Only full-duplex supported for now. */
-       val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
-
-       regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val);
-
        if (priv->pause) {
-               val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K;
-               val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH;
-               val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR;
+               val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
+               val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
+               val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
        } else {
-               val = 0;
+               val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
+               val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
+               val &= ~MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
        }
+       regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val);
 
+       val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K;
+       val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH;
+       val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR;
        regmap_update_bits(priv->regs, MTK_STAR_REG_FC_CFG,
                           MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH |
                           MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR, val);
 
-       if (priv->pause) {
-               val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
-               val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS;
-       } else {
-               val = 0;
-       }
-
+       val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
+       val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS;
        regmap_update_bits(priv->regs, MTK_STAR_REG_EXT_CFG,
                           MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS, val);
 }
@@ -898,14 +954,7 @@ static void mtk_star_init_config(struct mtk_star_priv *priv)
        regmap_write(priv->regs, MTK_STAR_REG_SYS_CONF, val);
        regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CLK_CONF,
                           MTK_STAR_MSK_MAC_CLK_CONF,
-                          MTK_STAR_BIT_CLK_DIV_10);
-}
-
-static void mtk_star_set_mode_rmii(struct mtk_star_priv *priv)
-{
-       regmap_update_bits(priv->pericfg, MTK_PERICFG_REG_NIC_CFG_CON,
-                          MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII,
-                          MTK_PERICFG_BIT_NIC_CFG_CON_RMII);
+                          priv->compat_data->bit_clk_div);
 }
 
 static int mtk_star_enable(struct net_device *ndev)
@@ -951,11 +1000,12 @@ static int mtk_star_enable(struct net_device *ndev)
 
        /* Request the interrupt */
        ret = request_irq(ndev->irq, mtk_star_handle_irq,
-                         IRQF_TRIGGER_FALLING, ndev->name, ndev);
+                         IRQF_TRIGGER_NONE, ndev->name, ndev);
        if (ret)
                goto err_free_skbs;
 
-       napi_enable(&priv->napi);
+       napi_enable(&priv->tx_napi);
+       napi_enable(&priv->rx_napi);
 
        mtk_star_intr_ack_all(priv);
        mtk_star_intr_enable(priv);
@@ -988,7 +1038,8 @@ static void mtk_star_disable(struct net_device *ndev)
        struct mtk_star_priv *priv = netdev_priv(ndev);
 
        netif_stop_queue(ndev);
-       napi_disable(&priv->napi);
+       napi_disable(&priv->tx_napi);
+       napi_disable(&priv->rx_napi);
        mtk_star_intr_disable(priv);
        mtk_star_dma_disable(priv);
        mtk_star_intr_ack_all(priv);
@@ -1020,13 +1071,45 @@ static int mtk_star_netdev_ioctl(struct net_device *ndev,
        return phy_mii_ioctl(ndev->phydev, req, cmd);
 }
 
-static int mtk_star_netdev_start_xmit(struct sk_buff *skb,
-                                     struct net_device *ndev)
+static int __mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
+{
+       netif_stop_queue(priv->ndev);
+
+       /* Might race with mtk_star_tx_poll, check again */
+       smp_mb();
+       if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) < size))
+               return -EBUSY;
+
+       netif_start_queue(priv->ndev);
+
+       return 0;
+}
+
+static inline int mtk_star_maybe_stop_tx(struct mtk_star_priv *priv, u16 size)
+{
+       if (likely(mtk_star_tx_ring_avail(&priv->tx_ring) >= size))
+               return 0;
+
+       return __mtk_star_maybe_stop_tx(priv, size);
+}
+
+static netdev_tx_t mtk_star_netdev_start_xmit(struct sk_buff *skb,
+                                             struct net_device *ndev)
 {
        struct mtk_star_priv *priv = netdev_priv(ndev);
        struct mtk_star_ring *ring = &priv->tx_ring;
        struct device *dev = mtk_star_get_dev(priv);
        struct mtk_star_ring_desc_data desc_data;
+       int nfrags = skb_shinfo(skb)->nr_frags;
+
+       if (unlikely(mtk_star_tx_ring_avail(ring) < nfrags + 1)) {
+               if (!netif_queue_stopped(ndev)) {
+                       netif_stop_queue(ndev);
+                       /* This is a hard error, log it. */
+                       pr_err_ratelimited("Tx ring full when queue awake\n");
+               }
+               return NETDEV_TX_BUSY;
+       }
 
        desc_data.dma_addr = mtk_star_dma_map_tx(priv, skb);
        if (dma_mapping_error(dev, desc_data.dma_addr))
@@ -1034,17 +1117,11 @@ static int mtk_star_netdev_start_xmit(struct sk_buff *skb,
 
        desc_data.skb = skb;
        desc_data.len = skb->len;
-
-       spin_lock_bh(&priv->lock);
-
        mtk_star_ring_push_head_tx(ring, &desc_data);
 
        netdev_sent_queue(ndev, skb->len);
 
-       if (mtk_star_ring_full(ring))
-               netif_stop_queue(ndev);
-
-       spin_unlock_bh(&priv->lock);
+       mtk_star_maybe_stop_tx(priv, MTK_STAR_DESC_NEEDED);
 
        mtk_star_dma_resume_tx(priv);
 
@@ -1076,31 +1153,40 @@ static int mtk_star_tx_complete_one(struct mtk_star_priv *priv)
        return ret;
 }
 
-static void mtk_star_tx_complete_all(struct mtk_star_priv *priv)
+static int mtk_star_tx_poll(struct napi_struct *napi, int budget)
 {
+       struct mtk_star_priv *priv = container_of(napi, struct mtk_star_priv,
+                                                 tx_napi);
+       int ret = 0, pkts_compl = 0, bytes_compl = 0, count = 0;
        struct mtk_star_ring *ring = &priv->tx_ring;
        struct net_device *ndev = priv->ndev;
-       int ret, pkts_compl, bytes_compl;
-       bool wake = false;
-
-       spin_lock(&priv->lock);
-
-       for (pkts_compl = 0, bytes_compl = 0;;
-            pkts_compl++, bytes_compl += ret, wake = true) {
-               if (!mtk_star_ring_descs_available(ring))
-                       break;
+       unsigned int head = ring->head;
+       unsigned int entry = ring->tail;
 
+       while (entry != head && count < (MTK_STAR_RING_NUM_DESCS - 1)) {
                ret = mtk_star_tx_complete_one(priv);
                if (ret < 0)
                        break;
+
+               count++;
+               pkts_compl++;
+               bytes_compl += ret;
+               entry = ring->tail;
        }
 
        netdev_completed_queue(ndev, pkts_compl, bytes_compl);
 
-       if (wake && netif_queue_stopped(ndev))
+       if (unlikely(netif_queue_stopped(ndev)) &&
+           (mtk_star_tx_ring_avail(ring) > MTK_STAR_TX_THRESH))
                netif_wake_queue(ndev);
 
-       spin_unlock(&priv->lock);
+       if (napi_complete(napi)) {
+               spin_lock(&priv->lock);
+               mtk_star_enable_dma_irq(priv, false, true);
+               spin_unlock(&priv->lock);
+       }
+
+       return 0;
 }
 
 static void mtk_star_netdev_get_stats64(struct net_device *ndev,
@@ -1180,7 +1266,7 @@ static const struct ethtool_ops mtk_star_ethtool_ops = {
        .set_link_ksettings     = phy_ethtool_set_link_ksettings,
 };
 
-static int mtk_star_receive_packet(struct mtk_star_priv *priv)
+static int mtk_star_rx(struct mtk_star_priv *priv, int budget)
 {
        struct mtk_star_ring *ring = &priv->rx_ring;
        struct device *dev = mtk_star_get_dev(priv);
@@ -1188,107 +1274,85 @@ static int mtk_star_receive_packet(struct mtk_star_priv *priv)
        struct net_device *ndev = priv->ndev;
        struct sk_buff *curr_skb, *new_skb;
        dma_addr_t new_dma_addr;
-       int ret;
+       int ret, count = 0;
 
-       spin_lock(&priv->lock);
-       ret = mtk_star_ring_pop_tail(ring, &desc_data);
-       spin_unlock(&priv->lock);
-       if (ret)
-               return -1;
+       while (count < budget) {
+               ret = mtk_star_ring_pop_tail(ring, &desc_data);
+               if (ret)
+                       return -1;
 
-       curr_skb = desc_data.skb;
+               curr_skb = desc_data.skb;
 
-       if ((desc_data.flags & MTK_STAR_DESC_BIT_RX_CRCE) ||
-           (desc_data.flags & MTK_STAR_DESC_BIT_RX_OSIZE)) {
-               /* Error packet -> drop and reuse skb. */
-               new_skb = curr_skb;
-               goto push_new_skb;
-       }
+               if ((desc_data.flags & MTK_STAR_DESC_BIT_RX_CRCE) ||
+                   (desc_data.flags & MTK_STAR_DESC_BIT_RX_OSIZE)) {
+                       /* Error packet -> drop and reuse skb. */
+                       new_skb = curr_skb;
+                       goto push_new_skb;
+               }
 
-       /* Prepare new skb before receiving the current one. Reuse the current
-        * skb if we fail at any point.
-        */
-       new_skb = mtk_star_alloc_skb(ndev);
-       if (!new_skb) {
-               ndev->stats.rx_dropped++;
-               new_skb = curr_skb;
-               goto push_new_skb;
-       }
+               /* Prepare new skb before receiving the current one.
+                * Reuse the current skb if we fail at any point.
+                */
+               new_skb = mtk_star_alloc_skb(ndev);
+               if (!new_skb) {
+                       ndev->stats.rx_dropped++;
+                       new_skb = curr_skb;
+                       goto push_new_skb;
+               }
 
-       new_dma_addr = mtk_star_dma_map_rx(priv, new_skb);
-       if (dma_mapping_error(dev, new_dma_addr)) {
-               ndev->stats.rx_dropped++;
-               dev_kfree_skb(new_skb);
-               new_skb = curr_skb;
-               netdev_err(ndev, "DMA mapping error of RX descriptor\n");
-               goto push_new_skb;
-       }
+               new_dma_addr = mtk_star_dma_map_rx(priv, new_skb);
+               if (dma_mapping_error(dev, new_dma_addr)) {
+                       ndev->stats.rx_dropped++;
+                       dev_kfree_skb(new_skb);
+                       new_skb = curr_skb;
+                       netdev_err(ndev, "DMA mapping error of RX descriptor\n");
+                       goto push_new_skb;
+               }
 
-       /* We can't fail anymore at this point: it's safe to unmap the skb. */
-       mtk_star_dma_unmap_rx(priv, &desc_data);
+               /* We can't fail anymore at this point:
+                * it's safe to unmap the skb.
+                */
+               mtk_star_dma_unmap_rx(priv, &desc_data);
 
-       skb_put(desc_data.skb, desc_data.len);
-       desc_data.skb->ip_summed = CHECKSUM_NONE;
-       desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
-       desc_data.skb->dev = ndev;
-       netif_receive_skb(desc_data.skb);
+               skb_put(desc_data.skb, desc_data.len);
+               desc_data.skb->ip_summed = CHECKSUM_NONE;
+               desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
+               desc_data.skb->dev = ndev;
+               netif_receive_skb(desc_data.skb);
 
-       /* update dma_addr for new skb */
-       desc_data.dma_addr = new_dma_addr;
+               /* update dma_addr for new skb */
+               desc_data.dma_addr = new_dma_addr;
 
 push_new_skb:
-       desc_data.len = skb_tailroom(new_skb);
-       desc_data.skb = new_skb;
 
-       spin_lock(&priv->lock);
-       mtk_star_ring_push_head_rx(ring, &desc_data);
-       spin_unlock(&priv->lock);
+               count++;
 
-       return 0;
-}
-
-static int mtk_star_process_rx(struct mtk_star_priv *priv, int budget)
-{
-       int received, ret;
-
-       for (received = 0, ret = 0; received < budget && ret == 0; received++)
-               ret = mtk_star_receive_packet(priv);
+               desc_data.len = skb_tailroom(new_skb);
+               desc_data.skb = new_skb;
+               mtk_star_ring_push_head_rx(ring, &desc_data);
+       }
 
        mtk_star_dma_resume_rx(priv);
 
-       return received;
+       return count;
 }
 
-static int mtk_star_poll(struct napi_struct *napi, int budget)
+static int mtk_star_rx_poll(struct napi_struct *napi, int budget)
 {
        struct mtk_star_priv *priv;
-       unsigned int status;
-       int received = 0;
-
-       priv = container_of(napi, struct mtk_star_priv, napi);
-
-       status = mtk_star_intr_read(priv);
-       mtk_star_intr_ack_all(priv);
+       int work_done = 0;
 
-       if (status & MTK_STAR_BIT_INT_STS_TNTC)
-               /* Clean-up all TX descriptors. */
-               mtk_star_tx_complete_all(priv);
+       priv = container_of(napi, struct mtk_star_priv, rx_napi);
 
-       if (status & MTK_STAR_BIT_INT_STS_FNRC)
-               /* Receive up to $budget packets. */
-               received = mtk_star_process_rx(priv, budget);
-
-       if (unlikely(status & MTK_STAR_REG_INT_STS_MIB_CNT_TH)) {
-               mtk_star_update_stats(priv);
-               mtk_star_reset_counters(priv);
+       work_done = mtk_star_rx(priv, budget);
+       if (work_done < budget) {
+               napi_complete_done(napi, work_done);
+               spin_lock(&priv->lock);
+               mtk_star_enable_dma_irq(priv, true, false);
+               spin_unlock(&priv->lock);
        }
 
-       if (received < budget)
-               napi_complete_done(napi, received);
-
-       mtk_star_intr_enable(priv);
-
-       return received;
+       return work_done;
 }
 
 static void mtk_star_mdio_rwok_clear(struct mtk_star_priv *priv)
@@ -1442,6 +1506,25 @@ static void mtk_star_clk_disable_unprepare(void *data)
        clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
 }
 
+static int mtk_star_set_timing(struct mtk_star_priv *priv)
+{
+       struct device *dev = mtk_star_get_dev(priv);
+       unsigned int delay_val = 0;
+
+       switch (priv->phy_intf) {
+       case PHY_INTERFACE_MODE_MII:
+       case PHY_INTERFACE_MODE_RMII:
+               delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_RX_CLK, priv->rx_inv);
+               delay_val |= FIELD_PREP(MTK_STAR_BIT_INV_TX_CLK, priv->tx_inv);
+               break;
+       default:
+               dev_err(dev, "This interface not supported\n");
+               return -EINVAL;
+       }
+
+       return regmap_write(priv->regs, MTK_STAR_REG_TEST0, delay_val);
+}
+
 static int mtk_star_probe(struct platform_device *pdev)
 {
        struct device_node *of_node;
@@ -1460,6 +1543,7 @@ static int mtk_star_probe(struct platform_device *pdev)
 
        priv = netdev_priv(ndev);
        priv->ndev = ndev;
+       priv->compat_data = of_device_get_match_data(&pdev->dev);
        SET_NETDEV_DEV(ndev, dev);
        platform_set_drvdata(pdev, ndev);
 
@@ -1510,7 +1594,8 @@ static int mtk_star_probe(struct platform_device *pdev)
        ret = of_get_phy_mode(of_node, &priv->phy_intf);
        if (ret) {
                return ret;
-       } else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII) {
+       } else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII &&
+                  priv->phy_intf != PHY_INTERFACE_MODE_MII) {
                dev_err(dev, "unsupported phy mode: %s\n",
                        phy_modes(priv->phy_intf));
                return -EINVAL;
@@ -1522,7 +1607,23 @@ static int mtk_star_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       mtk_star_set_mode_rmii(priv);
+       priv->rmii_rxc = of_property_read_bool(of_node, "mediatek,rmii-rxc");
+       priv->rx_inv = of_property_read_bool(of_node, "mediatek,rxc-inverse");
+       priv->tx_inv = of_property_read_bool(of_node, "mediatek,txc-inverse");
+
+       if (priv->compat_data->set_interface_mode) {
+               ret = priv->compat_data->set_interface_mode(ndev);
+               if (ret) {
+                       dev_err(dev, "Failed to set phy interface, err = %d\n", ret);
+                       return -EINVAL;
+               }
+       }
+
+       ret = mtk_star_set_timing(priv);
+       if (ret) {
+               dev_err(dev, "Failed to set timing, err = %d\n", ret);
+               return -EINVAL;
+       }
 
        ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
        if (ret) {
@@ -1550,16 +1651,93 @@ static int mtk_star_probe(struct platform_device *pdev)
        ndev->netdev_ops = &mtk_star_netdev_ops;
        ndev->ethtool_ops = &mtk_star_ethtool_ops;
 
-       netif_napi_add(ndev, &priv->napi, mtk_star_poll, NAPI_POLL_WEIGHT);
+       netif_napi_add(ndev, &priv->rx_napi, mtk_star_rx_poll,
+                      NAPI_POLL_WEIGHT);
+       netif_tx_napi_add(ndev, &priv->tx_napi, mtk_star_tx_poll,
+                         NAPI_POLL_WEIGHT);
 
        return devm_register_netdev(dev, ndev);
 }
 
 #ifdef CONFIG_OF
+static int mt8516_set_interface_mode(struct net_device *ndev)
+{
+       struct mtk_star_priv *priv = netdev_priv(ndev);
+       struct device *dev = mtk_star_get_dev(priv);
+       unsigned int intf_val, ret, rmii_rxc;
+
+       switch (priv->phy_intf) {
+       case PHY_INTERFACE_MODE_MII:
+               intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
+               rmii_rxc = 0;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
+               rmii_rxc = priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK;
+               break;
+       default:
+               dev_err(dev, "This interface not supported\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->pericfg,
+                                MTK_PERICFG_REG_NIC_CFG1_CON,
+                                MTK_PERICFG_BIT_NIC_CFG_CON_CLK,
+                                rmii_rxc);
+       if (ret)
+               return ret;
+
+       return regmap_update_bits(priv->pericfg,
+                                 MTK_PERICFG_REG_NIC_CFG0_CON,
+                                 MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF,
+                                 intf_val);
+}
+
+static int mt8365_set_interface_mode(struct net_device *ndev)
+{
+       struct mtk_star_priv *priv = netdev_priv(ndev);
+       struct device *dev = mtk_star_get_dev(priv);
+       unsigned int intf_val;
+
+       switch (priv->phy_intf) {
+       case PHY_INTERFACE_MODE_MII:
+               intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_MII;
+               break;
+       case PHY_INTERFACE_MODE_RMII:
+               intf_val = MTK_PERICFG_BIT_NIC_CFG_CON_RMII;
+               intf_val |= priv->rmii_rxc ? 0 : MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2;
+               break;
+       default:
+               dev_err(dev, "This interface not supported\n");
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(priv->pericfg,
+                                 MTK_PERICFG_REG_NIC_CFG_CON_V2,
+                                 MTK_PERICFG_REG_NIC_CFG_CON_CFG_INTF |
+                                 MTK_PERICFG_BIT_NIC_CFG_CON_CLK_V2,
+                                 intf_val);
+}
+
+static const struct mtk_star_compat mtk_star_mt8516_compat = {
+       .set_interface_mode = mt8516_set_interface_mode,
+       .bit_clk_div = MTK_STAR_BIT_CLK_DIV_10,
+};
+
+static const struct mtk_star_compat mtk_star_mt8365_compat = {
+       .set_interface_mode = mt8365_set_interface_mode,
+       .bit_clk_div = MTK_STAR_BIT_CLK_DIV_50,
+};
+
 static const struct of_device_id mtk_star_of_match[] = {
-       { .compatible = "mediatek,mt8516-eth", },
-       { .compatible = "mediatek,mt8518-eth", },
-       { .compatible = "mediatek,mt8175-eth", },
+       { .compatible = "mediatek,mt8516-eth",
+         .data = &mtk_star_mt8516_compat },
+       { .compatible = "mediatek,mt8518-eth",
+         .data = &mtk_star_mt8516_compat },
+       { .compatible = "mediatek,mt8175-eth",
+         .data = &mtk_star_mt8516_compat },
+       { .compatible = "mediatek,mt8365-eth",
+         .data = &mtk_star_mt8365_compat },
        { }
 };
 MODULE_DEVICE_TABLE(of, mtk_star_of_match);
index af3b2b5..43a4102 100644 (file)
@@ -645,7 +645,7 @@ static int get_real_size(const struct sk_buff *skb,
                *inline_ok = false;
                *hopbyhop = 0;
                if (skb->encapsulation) {
-                       *lso_header_size = (skb_inner_transport_header(skb) - skb->data) + inner_tcp_hdrlen(skb);
+                       *lso_header_size = skb_inner_tcp_all_headers(skb);
                } else {
                        /* Detects large IPV6 TCP packets and prepares for removal of
                         * HBH header that has been pushed by ip6_xmit(),
@@ -653,7 +653,7 @@ static int get_real_size(const struct sk_buff *skb,
                         */
                        if (ipv6_has_hopopt_jumbo(skb))
                                *hopbyhop = sizeof(struct hop_jumbo_hdr);
-                       *lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb);
+                       *lso_header_size = skb_tcp_all_headers(skb);
                }
                real_size = CTRL_SIZE + shinfo->nr_frags * DS_SIZE +
                        ALIGN(*lso_header_size - *hopbyhop + 4, DS_SIZE);
index 9ea867a..5dadc2f 100644 (file)
@@ -17,7 +17,7 @@ mlx5_core-y :=        main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
                fs_counters.o fs_ft_pool.o rl.o lag/debugfs.o lag/lag.o dev.o events.o wq.o lib/gid.o \
                lib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \
                diag/fw_tracer.o diag/crdump.o devlink.o diag/rsc_dump.o \
-               fw_reset.o qos.o lib/tout.o
+               fw_reset.o qos.o lib/tout.o lib/aso.o
 
 #
 # Netdev basic
@@ -45,7 +45,8 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en_tc.o en/rep/tc.o en/rep/neigh.o \
                                        esw/indir_table.o en/tc_tun_encap.o \
                                        en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
                                        en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
-                                       en/tc/post_act.o en/tc/int_port.o
+                                       en/tc/post_act.o en/tc/int_port.o en/tc/meter.o \
+                                       en/tc/post_meter.o
 
 mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/act/trap.o \
                                        en/tc/act/accept.o en/tc/act/mark.o en/tc/act/goto.o \
@@ -53,7 +54,7 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT)     += en/tc/act/act.o en/tc/act/drop.o en/tc/a
                                        en/tc/act/vlan.o en/tc/act/vlan_mangle.o en/tc/act/mpls.o \
                                        en/tc/act/mirred.o en/tc/act/mirred_nic.o \
                                        en/tc/act/ct.o en/tc/act/sample.o en/tc/act/ptype.o \
-                                       en/tc/act/redirect_ingress.o
+                                       en/tc/act/redirect_ingress.o en/tc/act/police.o
 
 ifneq ($(CONFIG_MLX5_TC_CT),)
        mlx5_core-y                          += en/tc_ct.o en/tc/ct_fs_dmfs.o
index 2755c25..305fde6 100644 (file)
@@ -30,7 +30,7 @@ static struct mlx5e_tc_act *tc_acts_fdb[NUM_FLOW_ACTIONS] = {
        NULL, /* FLOW_ACTION_WAKE, */
        NULL, /* FLOW_ACTION_QUEUE, */
        &mlx5e_tc_act_sample,
-       NULL, /* FLOW_ACTION_POLICE, */
+       &mlx5e_tc_act_police,
        &mlx5e_tc_act_ct,
        NULL, /* FLOW_ACTION_CT_METADATA, */
        &mlx5e_tc_act_mpls_push,
@@ -106,8 +106,8 @@ mlx5e_tc_act_init_parse_state(struct mlx5e_tc_act_parse_state *parse_state,
 {
        memset(parse_state, 0, sizeof(*parse_state));
        parse_state->flow = flow;
-       parse_state->num_actions = flow_action->num_entries;
        parse_state->extack = extack;
+       parse_state->flow_action = flow_action;
 }
 
 void
index f34714c..095ff8e 100644 (file)
@@ -13,7 +13,7 @@
 struct mlx5_flow_attr;
 
 struct mlx5e_tc_act_parse_state {
-       unsigned int num_actions;
+       struct flow_action *flow_action;
        struct mlx5e_tc_flow *flow;
        struct netlink_ext_ack *extack;
        u32 actions;
@@ -76,6 +76,7 @@ extern struct mlx5e_tc_act mlx5e_tc_act_ct;
 extern struct mlx5e_tc_act mlx5e_tc_act_sample;
 extern struct mlx5e_tc_act mlx5e_tc_act_ptype;
 extern struct mlx5e_tc_act mlx5e_tc_act_redirect_ingress;
+extern struct mlx5e_tc_act mlx5e_tc_act_police;
 
 struct mlx5e_tc_act *
 mlx5e_tc_act_get(enum flow_action_id act_id,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c
new file mode 100644 (file)
index 0000000..ab32fe6
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include "act.h"
+#include "en/tc_priv.h"
+
+static bool
+tc_act_can_offload_police(struct mlx5e_tc_act_parse_state *parse_state,
+                         const struct flow_action_entry *act,
+                         int act_index,
+                         struct mlx5_flow_attr *attr)
+{
+       if (mlx5e_policer_validate(parse_state->flow_action, act,
+                                  parse_state->extack))
+               return false;
+
+       return !!mlx5e_get_flow_meters(parse_state->flow->priv->mdev);
+}
+
+static int
+tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
+                   const struct flow_action_entry *act,
+                   struct mlx5e_priv *priv,
+                   struct mlx5_flow_attr *attr)
+{
+       struct mlx5e_flow_meter_params *params;
+
+       params = &attr->meter_attr.params;
+       params->index = act->hw_index;
+       if (act->police.rate_bytes_ps) {
+               params->mode = MLX5_RATE_LIMIT_BPS;
+               /* change rate to bits per second */
+               params->rate = act->police.rate_bytes_ps << 3;
+               params->burst = act->police.burst;
+       } else if (act->police.rate_pkt_ps) {
+               params->mode = MLX5_RATE_LIMIT_PPS;
+               params->rate = act->police.rate_pkt_ps;
+               params->burst = act->police.burst_pkt;
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
+       attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
+
+       return 0;
+}
+
+static bool
+tc_act_is_multi_table_act_police(struct mlx5e_priv *priv,
+                                const struct flow_action_entry *act,
+                                struct mlx5_flow_attr *attr)
+{
+       return true;
+}
+
+struct mlx5e_tc_act mlx5e_tc_act_police = {
+       .can_offload = tc_act_can_offload_police,
+       .parse_action = tc_act_parse_police,
+       .is_multi_table_act = tc_act_is_multi_table_act_police,
+};
index a7d9eab..53b270f 100644 (file)
@@ -12,7 +12,7 @@ tc_act_can_offload_trap(struct mlx5e_tc_act_parse_state *parse_state,
 {
        struct netlink_ext_ack *extack = parse_state->extack;
 
-       if (parse_state->num_actions != 1) {
+       if (parse_state->flow_action->num_entries != 1) {
                NL_SET_ERR_MSG_MOD(extack, "action trap is supported as a sole action only");
                return false;
        }
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
new file mode 100644 (file)
index 0000000..ca33f67
--- /dev/null
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include <linux/math64.h>
+#include "lib/aso.h"
+#include "en/tc/post_act.h"
+#include "meter.h"
+#include "en/tc_priv.h"
+#include "post_meter.h"
+
+#define MLX5_START_COLOR_SHIFT 28
+#define MLX5_METER_MODE_SHIFT 24
+#define MLX5_CBS_EXP_SHIFT 24
+#define MLX5_CBS_MAN_SHIFT 16
+#define MLX5_CIR_EXP_SHIFT 8
+
+/* cir = 8*(10^9)*cir_mantissa/(2^cir_exponent)) bits/s */
+#define MLX5_CONST_CIR 8000000000ULL
+#define MLX5_CALC_CIR(m, e)  ((MLX5_CONST_CIR * (m)) >> (e))
+#define MLX5_MAX_CIR ((MLX5_CONST_CIR * 0x100) - 1)
+
+/* cbs = cbs_mantissa*2^cbs_exponent */
+#define MLX5_CALC_CBS(m, e)  ((m) << (e))
+#define MLX5_MAX_CBS ((0x100ULL << 0x1F) - 1)
+#define MLX5_MAX_HW_CBS 0x7FFFFFFF
+
+struct mlx5e_flow_meter_aso_obj {
+       struct list_head entry;
+       int base_id;
+       int total_meters;
+
+       unsigned long meters_map[0]; /* must be at the end of this struct */
+};
+
+struct mlx5e_flow_meters {
+       enum mlx5_flow_namespace_type ns_type;
+       struct mlx5_aso *aso;
+       struct mutex aso_lock; /* Protects aso operations */
+       int log_granularity;
+       u32 pdn;
+
+       DECLARE_HASHTABLE(hashtbl, 8);
+
+       struct mutex sync_lock; /* protect flow meter operations */
+       struct list_head partial_list;
+       struct list_head full_list;
+
+       struct mlx5_core_dev *mdev;
+       struct mlx5e_post_act *post_act;
+
+       struct mlx5e_post_meter_priv *post_meter;
+};
+
+static void
+mlx5e_flow_meter_cir_calc(u64 cir, u8 *man, u8 *exp)
+{
+       s64 _cir, _delta, delta = S64_MAX;
+       u8 e, _man = 0, _exp = 0;
+       u64 m;
+
+       for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
+               m = cir << e;
+               if ((s64)m < 0) /* overflow */
+                       break;
+               m = div64_u64(m, MLX5_CONST_CIR);
+               if (m > 0xFF) /* man width 8 bit */
+                       continue;
+               _cir = MLX5_CALC_CIR(m, e);
+               _delta = cir - _cir;
+               if (_delta < delta) {
+                       _man = m;
+                       _exp = e;
+                       if (!_delta)
+                               goto found;
+                       delta = _delta;
+               }
+       }
+
+found:
+       *man = _man;
+       *exp = _exp;
+}
+
+static void
+mlx5e_flow_meter_cbs_calc(u64 cbs, u8 *man, u8 *exp)
+{
+       s64 _cbs, _delta, delta = S64_MAX;
+       u8 e, _man = 0, _exp = 0;
+       u64 m;
+
+       for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
+               m = cbs >> e;
+               if (m > 0xFF) /* man width 8 bit */
+                       continue;
+               _cbs = MLX5_CALC_CBS(m, e);
+               _delta = cbs - _cbs;
+               if (_delta < delta) {
+                       _man = m;
+                       _exp = e;
+                       if (!_delta)
+                               goto found;
+                       delta = _delta;
+               }
+       }
+
+found:
+       *man = _man;
+       *exp = _exp;
+}
+
+int
+mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
+                     struct mlx5e_flow_meter_handle *meter,
+                     struct mlx5e_flow_meter_params *meter_params)
+{
+       struct mlx5_wqe_aso_ctrl_seg *aso_ctrl;
+       struct mlx5_wqe_aso_data_seg *aso_data;
+       struct mlx5e_flow_meters *flow_meters;
+       u8 cir_man, cir_exp, cbs_man, cbs_exp;
+       struct mlx5_aso_wqe *aso_wqe;
+       struct mlx5_aso *aso;
+       u64 rate, burst;
+       u8 ds_cnt;
+       int err;
+
+       rate = meter_params->rate;
+       burst = meter_params->burst;
+
+       /* HW treats each packet as 128 bytes in PPS mode */
+       if (meter_params->mode == MLX5_RATE_LIMIT_PPS) {
+               rate <<= 10;
+               burst <<= 7;
+       }
+
+       if (!rate || rate > MLX5_MAX_CIR || !burst || burst > MLX5_MAX_CBS)
+               return -EINVAL;
+
+       /* HW has limitation of total 31 bits for cbs */
+       if (burst > MLX5_MAX_HW_CBS) {
+               mlx5_core_warn(mdev,
+                              "burst(%lld) is too large, use HW allowed value(%d)\n",
+                              burst, MLX5_MAX_HW_CBS);
+               burst = MLX5_MAX_HW_CBS;
+       }
+
+       mlx5_core_dbg(mdev, "meter mode=%d\n", meter_params->mode);
+       mlx5e_flow_meter_cir_calc(rate, &cir_man, &cir_exp);
+       mlx5_core_dbg(mdev, "rate=%lld, cir=%lld, exp=%d, man=%d\n",
+                     rate, MLX5_CALC_CIR(cir_man, cir_exp), cir_exp, cir_man);
+       mlx5e_flow_meter_cbs_calc(burst, &cbs_man, &cbs_exp);
+       mlx5_core_dbg(mdev, "burst=%lld, cbs=%lld, exp=%d, man=%d\n",
+                     burst, MLX5_CALC_CBS((u64)cbs_man, cbs_exp), cbs_exp, cbs_man);
+
+       if (!cir_man || !cbs_man)
+               return -EINVAL;
+
+       flow_meters = meter->flow_meters;
+       aso = flow_meters->aso;
+
+       mutex_lock(&flow_meters->aso_lock);
+       aso_wqe = mlx5_aso_get_wqe(aso);
+       ds_cnt = DIV_ROUND_UP(sizeof(struct mlx5_aso_wqe_data), MLX5_SEND_WQE_DS);
+       mlx5_aso_build_wqe(aso, ds_cnt, aso_wqe, meter->obj_id,
+                          MLX5_ACCESS_ASO_OPC_MOD_FLOW_METER);
+
+       aso_ctrl = &aso_wqe->aso_ctrl;
+       memset(aso_ctrl, 0, sizeof(*aso_ctrl));
+       aso_ctrl->data_mask_mode = MLX5_ASO_DATA_MASK_MODE_BYTEWISE_64BYTE << 6;
+       aso_ctrl->condition_1_0_operand = MLX5_ASO_ALWAYS_TRUE |
+                                         MLX5_ASO_ALWAYS_TRUE << 4;
+       aso_ctrl->data_offset_condition_operand = MLX5_ASO_LOGICAL_OR << 6;
+       aso_ctrl->data_mask = cpu_to_be64(0x80FFFFFFULL << (meter->idx ? 0 : 32));
+
+       aso_data = (struct mlx5_wqe_aso_data_seg *)(aso_wqe + 1);
+       memset(aso_data, 0, sizeof(*aso_data));
+       aso_data->bytewise_data[meter->idx * 8] = cpu_to_be32((0x1 << 31) | /* valid */
+                                       (MLX5_FLOW_METER_COLOR_GREEN << MLX5_START_COLOR_SHIFT));
+       if (meter_params->mode == MLX5_RATE_LIMIT_PPS)
+               aso_data->bytewise_data[meter->idx * 8] |=
+                       cpu_to_be32(MLX5_FLOW_METER_MODE_NUM_PACKETS << MLX5_METER_MODE_SHIFT);
+       else
+               aso_data->bytewise_data[meter->idx * 8] |=
+                       cpu_to_be32(MLX5_FLOW_METER_MODE_BYTES_IP_LENGTH << MLX5_METER_MODE_SHIFT);
+
+       aso_data->bytewise_data[meter->idx * 8 + 2] = cpu_to_be32((cbs_exp << MLX5_CBS_EXP_SHIFT) |
+                                                                 (cbs_man << MLX5_CBS_MAN_SHIFT) |
+                                                                 (cir_exp << MLX5_CIR_EXP_SHIFT) |
+                                                                 cir_man);
+
+       mlx5_aso_post_wqe(aso, true, &aso_wqe->ctrl);
+
+       /* With newer FW, the wait for the first ASO WQE is more than 2us, put the wait 10ms. */
+       err = mlx5_aso_poll_cq(aso, true, 10);
+       mutex_unlock(&flow_meters->aso_lock);
+
+       return err;
+}
+
+static int
+mlx5e_flow_meter_create_aso_obj(struct mlx5e_flow_meters *flow_meters, int *obj_id)
+{
+       u32 in[MLX5_ST_SZ_DW(create_flow_meter_aso_obj_in)] = {};
+       u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+       struct mlx5_core_dev *mdev = flow_meters->mdev;
+       void *obj;
+       int err;
+
+       MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+                MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO);
+       MLX5_SET(general_obj_in_cmd_hdr, in, log_obj_range, flow_meters->log_granularity);
+
+       obj = MLX5_ADDR_OF(create_flow_meter_aso_obj_in, in, flow_meter_aso_obj);
+       MLX5_SET(flow_meter_aso_obj, obj, meter_aso_access_pd, flow_meters->pdn);
+
+       err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+       if (!err) {
+               *obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+               mlx5_core_dbg(mdev, "flow meter aso obj(0x%x) created\n", *obj_id);
+       }
+
+       return err;
+}
+
+static void
+mlx5e_flow_meter_destroy_aso_obj(struct mlx5_core_dev *mdev, u32 obj_id)
+{
+       u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
+       u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
+
+       MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
+       MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
+                MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO);
+       MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
+
+       mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
+       mlx5_core_dbg(mdev, "flow meter aso obj(0x%x) destroyed\n", obj_id);
+}
+
+static struct mlx5e_flow_meter_handle *
+__mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters)
+{
+       struct mlx5_core_dev *mdev = flow_meters->mdev;
+       struct mlx5e_flow_meter_aso_obj *meters_obj;
+       struct mlx5e_flow_meter_handle *meter;
+       int err, pos, total;
+       u32 id;
+
+       meter = kzalloc(sizeof(*meter), GFP_KERNEL);
+       if (!meter)
+               return ERR_PTR(-ENOMEM);
+
+       meters_obj = list_first_entry_or_null(&flow_meters->partial_list,
+                                             struct mlx5e_flow_meter_aso_obj,
+                                             entry);
+       /* 2 meters in one object */
+       total = 1 << (flow_meters->log_granularity + 1);
+       if (!meters_obj) {
+               err = mlx5e_flow_meter_create_aso_obj(flow_meters, &id);
+               if (err) {
+                       mlx5_core_err(mdev, "Failed to create flow meter ASO object\n");
+                       goto err_create;
+               }
+
+               meters_obj = kzalloc(sizeof(*meters_obj) + BITS_TO_BYTES(total),
+                                    GFP_KERNEL);
+               if (!meters_obj) {
+                       err = -ENOMEM;
+                       goto err_mem;
+               }
+
+               meters_obj->base_id = id;
+               meters_obj->total_meters = total;
+               list_add(&meters_obj->entry, &flow_meters->partial_list);
+               pos = 0;
+       } else {
+               pos = find_first_zero_bit(meters_obj->meters_map, total);
+               if (bitmap_weight(meters_obj->meters_map, total) == total - 1) {
+                       list_del(&meters_obj->entry);
+                       list_add(&meters_obj->entry, &flow_meters->full_list);
+               }
+       }
+
+       bitmap_set(meters_obj->meters_map, pos, 1);
+       meter->flow_meters = flow_meters;
+       meter->meters_obj = meters_obj;
+       meter->obj_id = meters_obj->base_id + pos / 2;
+       meter->idx = pos % 2;
+
+       mlx5_core_dbg(mdev, "flow meter allocated, obj_id=0x%x, index=%d\n",
+                     meter->obj_id, meter->idx);
+
+       return meter;
+
+err_mem:
+       mlx5e_flow_meter_destroy_aso_obj(mdev, id);
+err_create:
+       kfree(meter);
+       return ERR_PTR(err);
+}
+
+static void
+__mlx5e_flow_meter_free(struct mlx5e_flow_meter_handle *meter)
+{
+       struct mlx5e_flow_meters *flow_meters = meter->flow_meters;
+       struct mlx5_core_dev *mdev = flow_meters->mdev;
+       struct mlx5e_flow_meter_aso_obj *meters_obj;
+       int n, pos;
+
+       meters_obj = meter->meters_obj;
+       pos = (meter->obj_id - meters_obj->base_id) * 2 + meter->idx;
+       bitmap_clear(meters_obj->meters_map, pos, 1);
+       n = bitmap_weight(meters_obj->meters_map, meters_obj->total_meters);
+       if (n == 0) {
+               list_del(&meters_obj->entry);
+               mlx5e_flow_meter_destroy_aso_obj(mdev, meters_obj->base_id);
+               kfree(meters_obj);
+       } else if (n == meters_obj->total_meters - 1) {
+               list_del(&meters_obj->entry);
+               list_add(&meters_obj->entry, &flow_meters->partial_list);
+       }
+
+       mlx5_core_dbg(mdev, "flow meter freed, obj_id=0x%x, index=%d\n",
+                     meter->obj_id, meter->idx);
+       kfree(meter);
+}
+
+struct mlx5e_flow_meter_handle *
+mlx5e_tc_meter_get(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params)
+{
+       struct mlx5e_flow_meters *flow_meters;
+       struct mlx5e_flow_meter_handle *meter;
+       int err;
+
+       flow_meters = mlx5e_get_flow_meters(mdev);
+       if (!flow_meters)
+               return ERR_PTR(-EOPNOTSUPP);
+
+       mutex_lock(&flow_meters->sync_lock);
+       hash_for_each_possible(flow_meters->hashtbl, meter, hlist, params->index)
+               if (meter->params.index == params->index)
+                       goto add_ref;
+
+       meter = __mlx5e_flow_meter_alloc(flow_meters);
+       if (IS_ERR(meter)) {
+               err = PTR_ERR(meter);
+               goto err_alloc;
+       }
+
+       hash_add(flow_meters->hashtbl, &meter->hlist, params->index);
+       meter->params.index = params->index;
+
+add_ref:
+       meter->refcnt++;
+
+       if (meter->params.mode != params->mode || meter->params.rate != params->rate ||
+           meter->params.burst != params->burst) {
+               err = mlx5e_tc_meter_modify(mdev, meter, params);
+               if (err)
+                       goto err_update;
+
+               meter->params.mode = params->mode;
+               meter->params.rate = params->rate;
+               meter->params.burst = params->burst;
+       }
+
+       mutex_unlock(&flow_meters->sync_lock);
+       return meter;
+
+err_update:
+       if (--meter->refcnt == 0) {
+               hash_del(&meter->hlist);
+               __mlx5e_flow_meter_free(meter);
+       }
+err_alloc:
+       mutex_unlock(&flow_meters->sync_lock);
+       return ERR_PTR(err);
+}
+
+void
+mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter)
+{
+       struct mlx5e_flow_meters *flow_meters = meter->flow_meters;
+
+       mutex_lock(&flow_meters->sync_lock);
+       if (--meter->refcnt == 0) {
+               hash_del(&meter->hlist);
+               __mlx5e_flow_meter_free(meter);
+       }
+       mutex_unlock(&flow_meters->sync_lock);
+}
+
+struct mlx5_flow_table *
+mlx5e_tc_meter_get_post_meter_ft(struct mlx5e_flow_meters *flow_meters)
+{
+       return mlx5e_post_meter_get_ft(flow_meters->post_meter);
+}
+
+struct mlx5e_flow_meters *
+mlx5e_flow_meters_init(struct mlx5e_priv *priv,
+                      enum mlx5_flow_namespace_type ns_type,
+                      struct mlx5e_post_act *post_act)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct mlx5e_flow_meters *flow_meters;
+       int err;
+
+       if (!(MLX5_CAP_GEN_64(mdev, general_obj_types) &
+             MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_FLOW_METER_ASO))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       if (IS_ERR_OR_NULL(post_act)) {
+               netdev_dbg(priv->netdev,
+                          "flow meter offload is not supported, post action is missing\n");
+               return ERR_PTR(-EOPNOTSUPP);
+       }
+
+       flow_meters = kzalloc(sizeof(*flow_meters), GFP_KERNEL);
+       if (!flow_meters)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx5_core_alloc_pd(mdev, &flow_meters->pdn);
+       if (err) {
+               mlx5_core_err(mdev, "Failed to alloc pd for flow meter aso, err=%d\n", err);
+               goto err_out;
+       }
+
+       flow_meters->aso = mlx5_aso_create(mdev, flow_meters->pdn);
+       if (IS_ERR(flow_meters->aso)) {
+               mlx5_core_warn(mdev, "Failed to create aso wqe for flow meter\n");
+               err = PTR_ERR(flow_meters->aso);
+               goto err_sq;
+       }
+
+       flow_meters->post_meter = mlx5e_post_meter_init(priv, ns_type, post_act);
+       if (IS_ERR(flow_meters->post_meter)) {
+               err = PTR_ERR(flow_meters->post_meter);
+               goto err_post_meter;
+       }
+
+       mutex_init(&flow_meters->sync_lock);
+       INIT_LIST_HEAD(&flow_meters->partial_list);
+       INIT_LIST_HEAD(&flow_meters->full_list);
+
+       flow_meters->ns_type = ns_type;
+       flow_meters->mdev = mdev;
+       flow_meters->post_act = post_act;
+       mutex_init(&flow_meters->aso_lock);
+       flow_meters->log_granularity = min_t(int, 6,
+                                            MLX5_CAP_QOS(mdev, log_meter_aso_max_alloc));
+
+       return flow_meters;
+
+err_post_meter:
+       mlx5_aso_destroy(flow_meters->aso);
+err_sq:
+       mlx5_core_dealloc_pd(mdev, flow_meters->pdn);
+err_out:
+       kfree(flow_meters);
+       return ERR_PTR(err);
+}
+
+void
+mlx5e_flow_meters_cleanup(struct mlx5e_flow_meters *flow_meters)
+{
+       if (IS_ERR_OR_NULL(flow_meters))
+               return;
+
+       mlx5e_post_meter_cleanup(flow_meters->post_meter);
+       mlx5_aso_destroy(flow_meters->aso);
+       mlx5_core_dealloc_pd(flow_meters->mdev, flow_meters->pdn);
+
+       kfree(flow_meters);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h
new file mode 100644 (file)
index 0000000..78885db
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_EN_FLOW_METER_H__
+#define __MLX5_EN_FLOW_METER_H__
+
+struct mlx5e_flow_meter_aso_obj;
+struct mlx5e_flow_meters;
+struct mlx5_flow_attr;
+
+enum mlx5e_flow_meter_mode {
+       MLX5_RATE_LIMIT_BPS,
+       MLX5_RATE_LIMIT_PPS,
+};
+
+struct mlx5e_flow_meter_params {
+       enum mlx5e_flow_meter_mode mode;
+        /* police action index */
+       u32 index;
+       u64 rate;
+       u64 burst;
+};
+
+struct mlx5e_flow_meter_handle {
+       struct mlx5e_flow_meters *flow_meters;
+       struct mlx5e_flow_meter_aso_obj *meters_obj;
+       u32 obj_id;
+       u8 idx;
+
+       int refcnt;
+       struct hlist_node hlist;
+       struct mlx5e_flow_meter_params params;
+};
+
+struct mlx5e_meter_attr {
+       struct mlx5e_flow_meter_params params;
+       struct mlx5e_flow_meter_handle *meter;
+};
+
+int
+mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
+                     struct mlx5e_flow_meter_handle *meter,
+                     struct mlx5e_flow_meter_params *meter_params);
+
+struct mlx5e_flow_meter_handle *
+mlx5e_tc_meter_get(struct mlx5_core_dev *mdev, struct mlx5e_flow_meter_params *params);
+void
+mlx5e_tc_meter_put(struct mlx5e_flow_meter_handle *meter);
+
+struct mlx5_flow_table *
+mlx5e_tc_meter_get_post_meter_ft(struct mlx5e_flow_meters *flow_meters);
+
+struct mlx5e_flow_meters *
+mlx5e_flow_meters_init(struct mlx5e_priv *priv,
+                      enum mlx5_flow_namespace_type ns_type,
+                      struct mlx5e_post_act *post_action);
+void
+mlx5e_flow_meters_cleanup(struct mlx5e_flow_meters *flow_meters);
+
+#endif /* __MLX5_EN_FLOW_METER_H__ */
index dea137d..2093cc2 100644 (file)
@@ -22,9 +22,9 @@ struct mlx5e_post_act_handle {
        u32 id;
 };
 
-#define MLX5_POST_ACTION_BITS (mlx5e_tc_attr_to_reg_mappings[FTEID_TO_REG].mlen)
-#define MLX5_POST_ACTION_MAX GENMASK(MLX5_POST_ACTION_BITS - 1, 0)
-#define MLX5_POST_ACTION_MASK MLX5_POST_ACTION_MAX
+#define MLX5_POST_ACTION_BITS MLX5_REG_MAPPING_MBITS(FTEID_TO_REG)
+#define MLX5_POST_ACTION_MASK MLX5_REG_MAPPING_MASK(FTEID_TO_REG)
+#define MLX5_POST_ACTION_MAX MLX5_POST_ACTION_MASK
 
 struct mlx5e_post_act *
 mlx5e_tc_post_act_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c
new file mode 100644 (file)
index 0000000..efa2035
--- /dev/null
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include "en/tc_priv.h"
+#include "post_meter.h"
+#include "en/tc/post_act.h"
+
+#define MLX5_PACKET_COLOR_BITS MLX5_REG_MAPPING_MBITS(PACKET_COLOR_TO_REG)
+#define MLX5_PACKET_COLOR_MASK MLX5_REG_MAPPING_MASK(PACKET_COLOR_TO_REG)
+
+struct mlx5e_post_meter_priv {
+       struct mlx5_flow_table *ft;
+       struct mlx5_flow_group *fg;
+       struct mlx5_flow_handle *fwd_green_rule;
+       struct mlx5_flow_handle *drop_red_rule;
+};
+
+struct mlx5_flow_table *
+mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter)
+{
+       return post_meter->ft;
+}
+
+static int
+mlx5e_post_meter_table_create(struct mlx5e_priv *priv,
+                             enum mlx5_flow_namespace_type ns_type,
+                             struct mlx5e_post_meter_priv *post_meter)
+{
+       struct mlx5_flow_table_attr ft_attr = {};
+       struct mlx5_flow_namespace *root_ns;
+
+       root_ns = mlx5_get_flow_namespace(priv->mdev, ns_type);
+       if (!root_ns) {
+               mlx5_core_warn(priv->mdev, "Failed to get namespace for flow meter\n");
+               return -EOPNOTSUPP;
+       }
+
+       ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
+       ft_attr.prio = FDB_SLOW_PATH;
+       ft_attr.max_fte = 2;
+       ft_attr.level = 1;
+
+       post_meter->ft = mlx5_create_flow_table(root_ns, &ft_attr);
+       if (IS_ERR(post_meter->ft)) {
+               mlx5_core_warn(priv->mdev, "Failed to create post_meter table\n");
+               return PTR_ERR(post_meter->ft);
+       }
+
+       return 0;
+}
+
+static int
+mlx5e_post_meter_fg_create(struct mlx5e_priv *priv,
+                          struct mlx5e_post_meter_priv *post_meter)
+{
+       int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+       void *misc2, *match_criteria;
+       u32 *flow_group_in;
+       int err = 0;
+
+       flow_group_in = kvzalloc(inlen, GFP_KERNEL);
+       if (!flow_group_in)
+               return -ENOMEM;
+
+       MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
+                MLX5_MATCH_MISC_PARAMETERS_2);
+       match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
+                                     match_criteria);
+       misc2 = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters_2);
+       MLX5_SET(fte_match_set_misc2, misc2, metadata_reg_c_5, MLX5_PACKET_COLOR_MASK);
+       MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
+       MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
+
+       post_meter->fg = mlx5_create_flow_group(post_meter->ft, flow_group_in);
+       if (IS_ERR(post_meter->fg)) {
+               mlx5_core_warn(priv->mdev, "Failed to create post_meter flow group\n");
+               err = PTR_ERR(post_meter->fg);
+       }
+
+       kvfree(flow_group_in);
+       return err;
+}
+
+static int
+mlx5e_post_meter_rules_create(struct mlx5e_priv *priv,
+                             struct mlx5e_post_meter_priv *post_meter,
+                             struct mlx5e_post_act *post_act)
+{
+       struct mlx5_flow_destination dest = {};
+       struct mlx5_flow_act flow_act = {};
+       struct mlx5_flow_handle *rule;
+       struct mlx5_flow_spec *spec;
+       int err;
+
+       spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
+                                   MLX5_FLOW_METER_COLOR_RED, MLX5_PACKET_COLOR_MASK);
+       flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+       flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
+
+       rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, NULL, 0);
+       if (IS_ERR(rule)) {
+               mlx5_core_warn(priv->mdev, "Failed to create post_meter flow drop rule\n");
+               err = PTR_ERR(rule);
+               goto err_red;
+       }
+       post_meter->drop_red_rule = rule;
+
+       mlx5e_tc_match_to_reg_match(spec, PACKET_COLOR_TO_REG,
+                                   MLX5_FLOW_METER_COLOR_GREEN, MLX5_PACKET_COLOR_MASK);
+       flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+       dest.ft = mlx5e_tc_post_act_get_ft(post_act);
+
+       rule = mlx5_add_flow_rules(post_meter->ft, spec, &flow_act, &dest, 1);
+       if (IS_ERR(rule)) {
+               mlx5_core_warn(priv->mdev, "Failed to create post_meter flow fwd rule\n");
+               err = PTR_ERR(rule);
+               goto err_green;
+       }
+       post_meter->fwd_green_rule = rule;
+
+       kvfree(spec);
+       return 0;
+
+err_green:
+       mlx5_del_flow_rules(post_meter->drop_red_rule);
+err_red:
+       kvfree(spec);
+       return err;
+}
+
+static void
+mlx5e_post_meter_rules_destroy(struct mlx5e_post_meter_priv *post_meter)
+{
+       mlx5_del_flow_rules(post_meter->drop_red_rule);
+       mlx5_del_flow_rules(post_meter->fwd_green_rule);
+}
+
+static void
+mlx5e_post_meter_fg_destroy(struct mlx5e_post_meter_priv *post_meter)
+{
+       mlx5_destroy_flow_group(post_meter->fg);
+}
+
+static void
+mlx5e_post_meter_table_destroy(struct mlx5e_post_meter_priv *post_meter)
+{
+       mlx5_destroy_flow_table(post_meter->ft);
+}
+
+struct mlx5e_post_meter_priv *
+mlx5e_post_meter_init(struct mlx5e_priv *priv,
+                     enum mlx5_flow_namespace_type ns_type,
+                     struct mlx5e_post_act *post_act)
+{
+       struct mlx5e_post_meter_priv *post_meter;
+       int err;
+
+       post_meter = kzalloc(sizeof(*post_meter), GFP_KERNEL);
+       if (!post_meter)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx5e_post_meter_table_create(priv, ns_type, post_meter);
+       if (err)
+               goto err_ft;
+
+       err = mlx5e_post_meter_fg_create(priv, post_meter);
+       if (err)
+               goto err_fg;
+
+       err = mlx5e_post_meter_rules_create(priv, post_meter, post_act);
+       if (err)
+               goto err_rules;
+
+       return post_meter;
+
+err_rules:
+       mlx5e_post_meter_fg_destroy(post_meter);
+err_fg:
+       mlx5e_post_meter_table_destroy(post_meter);
+err_ft:
+       kfree(post_meter);
+       return ERR_PTR(err);
+}
+
+void
+mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter)
+{
+       mlx5e_post_meter_rules_destroy(post_meter);
+       mlx5e_post_meter_fg_destroy(post_meter);
+       mlx5e_post_meter_table_destroy(post_meter);
+       kfree(post_meter);
+}
+
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.h
new file mode 100644 (file)
index 0000000..c74f3cb
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_EN_POST_METER_H__
+#define __MLX5_EN_POST_METER_H__
+
+#define packet_color_to_reg { \
+       .mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_5, \
+       .moffset = 0, \
+       .mlen = 8, \
+       .soffset = MLX5_BYTE_OFF(fte_match_param, \
+                                misc_parameters_2.metadata_reg_c_5), \
+}
+
+struct mlx5e_post_meter_priv;
+
+struct mlx5_flow_table *
+mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter);
+
+struct mlx5e_post_meter_priv *
+mlx5e_post_meter_init(struct mlx5e_priv *priv,
+                     enum mlx5_flow_namespace_type ns_type,
+                     struct mlx5e_post_act *post_act);
+void
+mlx5e_post_meter_cleanup(struct mlx5e_post_meter_priv *post_meter);
+
+#endif /* __MLX5_EN_POST_METER_H__ */
index 25f51f8..af959fa 100644 (file)
@@ -36,8 +36,8 @@
 #define MLX5_CT_STATE_RELATED_BIT BIT(5)
 #define MLX5_CT_STATE_INVALID_BIT BIT(6)
 
-#define MLX5_CT_LABELS_BITS (mlx5e_tc_attr_to_reg_mappings[LABELS_TO_REG].mlen)
-#define MLX5_CT_LABELS_MASK GENMASK(MLX5_CT_LABELS_BITS - 1, 0)
+#define MLX5_CT_LABELS_BITS MLX5_REG_MAPPING_MBITS(LABELS_TO_REG)
+#define MLX5_CT_LABELS_MASK MLX5_REG_MAPPING_MASK(LABELS_TO_REG)
 
 /* Statically allocate modify actions for
  * ipv6 and port nat (5) + tuple fields (4) + nic mode zone restore (1) = 10.
index 00a3ba8..5bbd6b9 100644 (file)
@@ -62,10 +62,11 @@ struct mlx5_ct_attr {
                                 misc_parameters_2.metadata_reg_c_4),\
 }
 
+/* 8 LSB of metadata C5 are reserved for packet color */
 #define fteid_to_reg_ct {\
        .mfield = MLX5_ACTION_IN_FIELD_METADATA_REG_C_5,\
-       .moffset = 0,\
-       .mlen = 32,\
+       .moffset = 8,\
+       .mlen = 24,\
        .soffset = MLX5_BYTE_OFF(fte_match_param,\
                                 misc_parameters_2.metadata_reg_c_5),\
 }
@@ -84,10 +85,8 @@ struct mlx5_ct_attr {
        .mlen = ESW_ZONE_ID_BITS,\
 }
 
-#define REG_MAPPING_MLEN(reg) (mlx5e_tc_attr_to_reg_mappings[reg].mlen)
-#define REG_MAPPING_MOFFSET(reg) (mlx5e_tc_attr_to_reg_mappings[reg].moffset)
-#define MLX5_CT_ZONE_BITS (mlx5e_tc_attr_to_reg_mappings[ZONE_TO_REG].mlen)
-#define MLX5_CT_ZONE_MASK GENMASK(MLX5_CT_ZONE_BITS - 1, 0)
+#define MLX5_CT_ZONE_BITS MLX5_REG_MAPPING_MBITS(ZONE_TO_REG)
+#define MLX5_CT_ZONE_MASK MLX5_REG_MAPPING_MASK(ZONE_TO_REG)
 
 #if IS_ENABLED(CONFIG_MLX5_TC_CT)
 
index 3b74a6f..d2bdfd6 100644 (file)
@@ -203,7 +203,13 @@ struct mlx5_fc *mlx5e_tc_get_counter(struct mlx5e_tc_flow *flow);
 struct mlx5e_tc_int_port_priv *
 mlx5e_get_int_port_priv(struct mlx5e_priv *priv);
 
+struct mlx5e_flow_meters *mlx5e_get_flow_meters(struct mlx5_core_dev *dev);
+
 void *mlx5e_get_match_headers_value(u32 flags, struct mlx5_flow_spec *spec);
 void *mlx5e_get_match_headers_criteria(u32 flags, struct mlx5_flow_spec *spec);
 
+int mlx5e_policer_validate(const struct flow_action *action,
+                          const struct flow_action_entry *act,
+                          struct netlink_ext_ack *extack);
+
 #endif /* __MLX5_EN_TC_PRIV_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec_fs.h
deleted file mode 100644 (file)
index e4eeb2b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
-/* Copyright (c) 2020, Mellanox Technologies inc. All rights reserved. */
-
-#ifndef __MLX5_IPSEC_STEERING_H__
-#define __MLX5_IPSEC_STEERING_H__
-
-#include "en.h"
-#include "ipsec.h"
-#include "ipsec_offload.h"
-#include "en/fs.h"
-
-void mlx5e_accel_ipsec_fs_cleanup(struct mlx5e_ipsec *ipsec);
-int mlx5e_accel_ipsec_fs_init(struct mlx5e_ipsec *ipsec);
-int mlx5e_accel_ipsec_fs_add_rule(struct mlx5e_priv *priv,
-                                 struct mlx5_accel_esp_xfrm_attrs *attrs,
-                                 u32 ipsec_obj_id,
-                                 struct mlx5e_ipsec_rule *ipsec_rule);
-void mlx5e_accel_ipsec_fs_del_rule(struct mlx5e_priv *priv,
-                                  struct mlx5_accel_esp_xfrm_attrs *attrs,
-                                  struct mlx5e_ipsec_rule *ipsec_rule);
-#endif /* __MLX5_IPSEC_STEERING_H__ */
index 4b6f0d1..cc5cb30 100644 (file)
@@ -458,7 +458,7 @@ bool mlx5e_ktls_handle_tx_skb(struct net_device *netdev, struct mlx5e_txqsq *sq,
        int datalen;
        u32 seq;
 
-       datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+       datalen = skb->len - skb_tcp_all_headers(skb);
        if (!datalen)
                return true;
 
index adf5cc6..dec183c 100644 (file)
@@ -62,6 +62,7 @@ struct mlx5_tc_int_port_priv;
 struct mlx5e_rep_bond;
 struct mlx5e_tc_tun_encap;
 struct mlx5e_post_act;
+struct mlx5e_flow_meters;
 
 struct mlx5_rep_uplink_priv {
        /* indirect block callbacks are invoked on bind/unbind events
@@ -97,6 +98,8 @@ struct mlx5_rep_uplink_priv {
 
        /* OVS internal port support */
        struct mlx5e_tc_int_port_priv *int_port_priv;
+
+       struct mlx5e_flow_meters *flow_meters;
 };
 
 struct mlx5e_rep_priv {
index 3a39a50..5e70e99 100644 (file)
@@ -59,6 +59,7 @@
 #include "en/tc_tun_encap.h"
 #include "en/tc/sample.h"
 #include "en/tc/act/act.h"
+#include "en/tc/post_meter.h"
 #include "lib/devcom.h"
 #include "lib/geneve.h"
 #include "lib/fs_chains.h"
@@ -104,6 +105,7 @@ struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[] = {
                .mlen = 16,
        },
        [NIC_ZONE_RESTORE_TO_REG] = nic_zone_restore_to_reg_ct,
+       [PACKET_COLOR_TO_REG] = packet_color_to_reg,
 };
 
 /* To avoid false lock dependency warning set the tc_ht lock
@@ -240,6 +242,30 @@ mlx5e_get_int_port_priv(struct mlx5e_priv *priv)
        return NULL;
 }
 
+struct mlx5e_flow_meters *
+mlx5e_get_flow_meters(struct mlx5_core_dev *dev)
+{
+       struct mlx5_eswitch *esw = dev->priv.eswitch;
+       struct mlx5_rep_uplink_priv *uplink_priv;
+       struct mlx5e_rep_priv *uplink_rpriv;
+       struct mlx5e_priv *priv;
+
+       if (is_mdev_switchdev_mode(dev)) {
+               uplink_rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
+               uplink_priv = &uplink_rpriv->uplink_priv;
+               priv = netdev_priv(uplink_rpriv->netdev);
+               if (!uplink_priv->flow_meters)
+                       uplink_priv->flow_meters =
+                               mlx5e_flow_meters_init(priv,
+                                                      MLX5_FLOW_NAMESPACE_FDB,
+                                                      uplink_priv->post_act);
+               if (!IS_ERR(uplink_priv->flow_meters))
+                       return uplink_priv->flow_meters;
+       }
+
+       return NULL;
+}
+
 static struct mlx5_tc_ct_priv *
 get_ct_priv(struct mlx5e_priv *priv)
 {
@@ -319,12 +345,39 @@ mlx5_tc_rule_delete(struct mlx5e_priv *priv,
        mlx5e_del_offloaded_nic_rule(priv, rule, attr);
 }
 
+static bool
+is_flow_meter_action(struct mlx5_flow_attr *attr)
+{
+       return ((attr->action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) &&
+               (attr->exe_aso_type == MLX5_EXE_ASO_FLOW_METER));
+}
+
+static int
+mlx5e_tc_add_flow_meter(struct mlx5e_priv *priv,
+                       struct mlx5_flow_attr *attr)
+{
+       struct mlx5e_flow_meter_handle *meter;
+
+       meter = mlx5e_tc_meter_get(priv->mdev, &attr->meter_attr.params);
+       if (IS_ERR(meter)) {
+               mlx5_core_err(priv->mdev, "Failed to get flow meter\n");
+               return PTR_ERR(meter);
+       }
+
+       attr->meter_attr.meter = meter;
+       attr->dest_ft = mlx5e_tc_meter_get_post_meter_ft(meter->flow_meters);
+       attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+
+       return 0;
+}
+
 struct mlx5_flow_handle *
 mlx5e_tc_rule_offload(struct mlx5e_priv *priv,
                      struct mlx5_flow_spec *spec,
                      struct mlx5_flow_attr *attr)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+       int err;
 
        if (attr->flags & MLX5_ATTR_FLAG_CT) {
                struct mlx5e_tc_mod_hdr_acts *mod_hdr_acts =
@@ -341,6 +394,12 @@ mlx5e_tc_rule_offload(struct mlx5e_priv *priv,
        if (attr->flags & MLX5_ATTR_FLAG_SAMPLE)
                return mlx5e_tc_sample_offload(get_sample_priv(priv), spec, attr);
 
+       if (is_flow_meter_action(attr)) {
+               err = mlx5e_tc_add_flow_meter(priv, attr);
+               if (err)
+                       return ERR_PTR(err);
+       }
+
        return mlx5_eswitch_add_offloaded_rule(esw, spec, attr);
 }
 
@@ -367,6 +426,9 @@ mlx5e_tc_rule_unoffload(struct mlx5e_priv *priv,
        }
 
        mlx5_eswitch_del_offloaded_rule(esw, rule, attr);
+
+       if (attr->meter_attr.meter)
+               mlx5e_tc_meter_put(attr->meter_attr.meter);
 }
 
 int
@@ -4519,9 +4581,9 @@ static int apply_police_params(struct mlx5e_priv *priv, u64 rate,
        return err;
 }
 
-static int mlx5e_policer_validate(const struct flow_action *action,
-                                 const struct flow_action_entry *act,
-                                 struct netlink_ext_ack *extack)
+int mlx5e_policer_validate(const struct flow_action *action,
+                          const struct flow_action_entry *act,
+                          struct netlink_ext_ack *extack)
 {
        if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
                NL_SET_ERR_MSG_MOD(extack,
@@ -4955,6 +5017,7 @@ void mlx5e_tc_esw_cleanup(struct mlx5_rep_uplink_priv *uplink_priv)
        mlx5e_tc_sample_cleanup(uplink_priv->tc_psample);
        mlx5e_tc_int_port_cleanup(uplink_priv->int_port_priv);
        mlx5_tc_ct_clean(uplink_priv->ct_priv);
+       mlx5e_flow_meters_cleanup(uplink_priv->flow_meters);
        mlx5e_tc_post_act_destroy(uplink_priv->post_act);
 }
 
@@ -5060,7 +5123,7 @@ bool mlx5e_tc_update_skb(struct mlx5_cqe64 *cqe,
 
                tc_skb_ext->chain = chain;
 
-               zone_restore_id = (reg_b >> REG_MAPPING_MOFFSET(NIC_ZONE_RESTORE_TO_REG)) &
+               zone_restore_id = (reg_b >> MLX5_REG_MAPPING_MOFFSET(NIC_ZONE_RESTORE_TO_REG)) &
                        ESW_ZONE_ID_MASK;
 
                if (!mlx5e_tc_ct_restore_flow(tc->ct, skb,
index e2a1250..517f225 100644 (file)
@@ -39,6 +39,7 @@
 #include "en/tc_ct.h"
 #include "en/tc_tun.h"
 #include "en/tc/int_port.h"
+#include "en/tc/meter.h"
 #include "en_rep.h"
 
 #define MLX5E_TC_FLOW_ID_MASK 0x0000ffff
@@ -71,6 +72,7 @@ struct mlx5_flow_attr {
        struct mlx5_modify_hdr *modify_hdr;
        struct mlx5_ct_attr ct_attr;
        struct mlx5e_sample_attr sample_attr;
+       struct mlx5e_meter_attr meter_attr;
        struct mlx5e_tc_flow_parse_attr *parse_attr;
        u32 chain;
        u16 prio;
@@ -83,6 +85,7 @@ struct mlx5_flow_attr {
        u8 tun_ip_version;
        int tunnel_id; /* mapped tunnel id */
        u32 flags;
+       u32 exe_aso_type;
        struct list_head list;
        struct mlx5e_post_act_handle *post_act_handle;
        struct {
@@ -229,6 +232,7 @@ enum mlx5e_tc_attr_to_reg {
        FTEID_TO_REG,
        NIC_CHAIN_TO_REG,
        NIC_ZONE_RESTORE_TO_REG,
+       PACKET_COLOR_TO_REG,
 };
 
 struct mlx5e_tc_attr_to_reg_mapping {
@@ -241,6 +245,10 @@ struct mlx5e_tc_attr_to_reg_mapping {
 
 extern struct mlx5e_tc_attr_to_reg_mapping mlx5e_tc_attr_to_reg_mappings[];
 
+#define MLX5_REG_MAPPING_MOFFSET(reg_id) (mlx5e_tc_attr_to_reg_mappings[reg_id].moffset)
+#define MLX5_REG_MAPPING_MBITS(reg_id) (mlx5e_tc_attr_to_reg_mappings[reg_id].mlen)
+#define MLX5_REG_MAPPING_MASK(reg_id) (GENMASK(mlx5e_tc_attr_to_reg_mappings[reg_id].mlen - 1, 0))
+
 bool mlx5e_is_valid_eswitch_fwd_dev(struct mlx5e_priv *priv,
                                    struct net_device *out_dev);
 
index 50d14ce..64d78fd 100644 (file)
@@ -152,14 +152,14 @@ mlx5e_tx_get_gso_ihs(struct mlx5e_txqsq *sq, struct sk_buff *skb, int *hopbyhop)
 
        *hopbyhop = 0;
        if (skb->encapsulation) {
-               ihs = skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb);
+               ihs = skb_tcp_all_headers(skb);
                stats->tso_inner_packets++;
                stats->tso_inner_bytes += skb->len - ihs;
        } else {
                if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) {
                        ihs = skb_transport_offset(skb) + sizeof(struct udphdr);
                } else {
-                       ihs = skb_transport_offset(skb) + tcp_hdrlen(skb);
+                       ihs = skb_tcp_all_headers(skb);
                        if (ipv6_has_hopopt_jumbo(skb)) {
                                *hopbyhop = sizeof(struct hop_jumbo_hdr);
                                ihs -= sizeof(struct hop_jumbo_hdr);
index 719ef26..b938632 100644 (file)
@@ -1152,8 +1152,6 @@ mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, int num_vfs)
 {
        const u32 *out;
 
-       WARN_ON_ONCE(esw->mode != MLX5_ESWITCH_NONE);
-
        if (num_vfs < 0)
                return;
 
@@ -1186,6 +1184,9 @@ static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw)
        int total_vports;
        int err;
 
+       if (esw->flags & MLX5_ESWITCH_VPORT_ACL_NS_CREATED)
+               return 0;
+
        total_vports = mlx5_eswitch_get_total_vports(dev);
 
        if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support)) {
@@ -1203,6 +1204,7 @@ static int mlx5_esw_acls_ns_init(struct mlx5_eswitch *esw)
        } else {
                esw_warn(dev, "ingress ACL is not supported by FW\n");
        }
+       esw->flags |= MLX5_ESWITCH_VPORT_ACL_NS_CREATED;
        return 0;
 
 err:
@@ -1215,6 +1217,7 @@ static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
 {
        struct mlx5_core_dev *dev = esw->dev;
 
+       esw->flags &= ~MLX5_ESWITCH_VPORT_ACL_NS_CREATED;
        if (MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
                mlx5_fs_ingress_acls_cleanup(dev);
        if (MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
@@ -1224,7 +1227,6 @@ static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
 /**
  * mlx5_eswitch_enable_locked - Enable eswitch
  * @esw:       Pointer to eswitch
- * @mode:      Eswitch mode to enable
  * @num_vfs:   Enable eswitch for given number of VFs. This is optional.
  *             Valid value are 0, > 0 and MLX5_ESWITCH_IGNORE_NUM_VFS.
  *             Caller should pass num_vfs > 0 when enabling eswitch for
@@ -1238,7 +1240,7 @@ static void mlx5_esw_acls_ns_cleanup(struct mlx5_eswitch *esw)
  * mode. If num_vfs >=0 is provided, it setup VF related eswitch vports.
  * It returns 0 on success or error code on failure.
  */
-int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs)
+int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
 {
        int err;
 
@@ -1257,9 +1259,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs)
 
        mlx5_eswitch_update_num_of_vfs(esw, num_vfs);
 
-       esw->mode = mode;
-
-       if (mode == MLX5_ESWITCH_LEGACY) {
+       if (esw->mode == MLX5_ESWITCH_LEGACY) {
                err = esw_legacy_enable(esw);
        } else {
                mlx5_rescan_drivers(esw->dev);
@@ -1269,22 +1269,19 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs)
        if (err)
                goto abort;
 
+       esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;
+
        mlx5_eswitch_event_handlers_register(esw);
 
        esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
-                mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
+                esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
                 esw->esw_funcs.num_vfs, esw->enabled_vports);
 
-       mlx5_esw_mode_change_notify(esw, mode);
+       mlx5_esw_mode_change_notify(esw, esw->mode);
 
        return 0;
 
 abort:
-       esw->mode = MLX5_ESWITCH_NONE;
-
-       if (mode == MLX5_ESWITCH_OFFLOADS)
-               mlx5_rescan_drivers(esw->dev);
-
        mlx5_esw_acls_ns_cleanup(esw);
        return err;
 }
@@ -1305,14 +1302,14 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
        if (!mlx5_esw_allowed(esw))
                return 0;
 
-       toggle_lag = esw->mode == MLX5_ESWITCH_NONE;
+       toggle_lag = !mlx5_esw_is_fdb_created(esw);
 
        if (toggle_lag)
                mlx5_lag_disable_change(esw->dev);
 
        down_write(&esw->mode_lock);
-       if (esw->mode == MLX5_ESWITCH_NONE) {
-               ret = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY, num_vfs);
+       if (!mlx5_esw_is_fdb_created(esw)) {
+               ret = mlx5_eswitch_enable_locked(esw, num_vfs);
        } else {
                enum mlx5_eswitch_vport_event vport_events;
 
@@ -1330,55 +1327,79 @@ int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs)
        return ret;
 }
 
-void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw, bool clear_vf)
+/* When disabling sriov, free driver level resources. */
+void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf)
 {
-       struct devlink *devlink = priv_to_devlink(esw->dev);
-       int old_mode;
-
-       lockdep_assert_held_write(&esw->mode_lock);
-
-       if (esw->mode == MLX5_ESWITCH_NONE)
+       if (!mlx5_esw_allowed(esw))
                return;
 
-       esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
+       down_write(&esw->mode_lock);
+       /* If driver is unloaded, this function is called twice by remove_one()
+        * and mlx5_unload(). Prevent the second call.
+        */
+       if (!esw->esw_funcs.num_vfs && !clear_vf)
+               goto unlock;
+
+       esw_info(esw->dev, "Unload vfs: mode(%s), nvfs(%d), active vports(%d)\n",
                 esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
                 esw->esw_funcs.num_vfs, esw->enabled_vports);
 
-       /* Notify eswitch users that it is exiting from current mode.
-        * So that it can do necessary cleanup before the eswitch is disabled.
+       mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
+       if (clear_vf)
+               mlx5_eswitch_clear_vf_vports_info(esw);
+       /* If disabling sriov in switchdev mode, free meta rules here
+        * because it depends on num_vfs.
         */
-       mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_NONE);
+       if (esw->mode == MLX5_ESWITCH_OFFLOADS) {
+               struct devlink *devlink = priv_to_devlink(esw->dev);
 
-       mlx5_eswitch_event_handlers_unregister(esw);
+               esw_offloads_del_send_to_vport_meta_rules(esw);
+               devlink_rate_nodes_destroy(devlink);
+       }
 
-       if (esw->mode == MLX5_ESWITCH_LEGACY)
-               esw_legacy_disable(esw);
-       else if (esw->mode == MLX5_ESWITCH_OFFLOADS)
-               esw_offloads_disable(esw);
+       esw->esw_funcs.num_vfs = 0;
 
-       old_mode = esw->mode;
-       esw->mode = MLX5_ESWITCH_NONE;
+unlock:
+       up_write(&esw->mode_lock);
+}
 
-       if (old_mode == MLX5_ESWITCH_OFFLOADS)
-               mlx5_rescan_drivers(esw->dev);
+/* Free resources for corresponding eswitch mode. It is called by devlink
+ * when changing eswitch mode or modprobe when unloading driver.
+ */
+void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
+{
+       struct devlink *devlink = priv_to_devlink(esw->dev);
+
+       /* Notify eswitch users that it is exiting from current mode.
+        * So that it can do necessary cleanup before the eswitch is disabled.
+        */
+       mlx5_esw_mode_change_notify(esw, MLX5_ESWITCH_LEGACY);
 
-       devlink_rate_nodes_destroy(devlink);
+       mlx5_eswitch_event_handlers_unregister(esw);
 
+       esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
+                esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
+                esw->esw_funcs.num_vfs, esw->enabled_vports);
+
+       esw->fdb_table.flags &= ~MLX5_ESW_FDB_CREATED;
+       if (esw->mode == MLX5_ESWITCH_OFFLOADS)
+               esw_offloads_disable(esw);
+       else if (esw->mode == MLX5_ESWITCH_LEGACY)
+               esw_legacy_disable(esw);
        mlx5_esw_acls_ns_cleanup(esw);
 
-       if (clear_vf)
-               mlx5_eswitch_clear_vf_vports_info(esw);
+       if (esw->mode == MLX5_ESWITCH_OFFLOADS)
+               devlink_rate_nodes_destroy(devlink);
 }
 
-void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf)
+void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
 {
        if (!mlx5_esw_allowed(esw))
                return;
 
        mlx5_lag_disable_change(esw->dev);
        down_write(&esw->mode_lock);
-       mlx5_eswitch_disable_locked(esw, clear_vf);
-       esw->esw_funcs.num_vfs = 0;
+       mlx5_eswitch_disable_locked(esw);
        up_write(&esw->mode_lock);
        mlx5_lag_enable_change(esw->dev);
 }
@@ -1573,7 +1594,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
        refcount_set(&esw->qos.refcnt, 0);
 
        esw->enabled_vports = 0;
-       esw->mode = MLX5_ESWITCH_NONE;
+       esw->mode = MLX5_ESWITCH_LEGACY;
        esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
        if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) &&
            MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
@@ -1875,7 +1896,7 @@ u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
 {
        struct mlx5_eswitch *esw = dev->priv.eswitch;
 
-       return mlx5_esw_allowed(esw) ? esw->mode : MLX5_ESWITCH_NONE;
+       return mlx5_esw_allowed(esw) ? esw->mode : MLX5_ESWITCH_LEGACY;
 }
 EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
 
@@ -1995,8 +2016,6 @@ int mlx5_esw_try_lock(struct mlx5_eswitch *esw)
  */
 void mlx5_esw_unlock(struct mlx5_eswitch *esw)
 {
-       if (!mlx5_esw_allowed(esw))
-               return;
        up_write(&esw->mode_lock);
 }
 
index 2754a73..c19604b 100644 (file)
@@ -282,10 +282,15 @@ struct mlx5_esw_functions {
 enum {
        MLX5_ESWITCH_VPORT_MATCH_METADATA = BIT(0),
        MLX5_ESWITCH_REG_C1_LOOPBACK_ENABLED = BIT(1),
+       MLX5_ESWITCH_VPORT_ACL_NS_CREATED = BIT(2),
 };
 
 struct mlx5_esw_bridge_offloads;
 
+enum {
+       MLX5_ESW_FDB_CREATED = BIT(0),
+};
+
 struct mlx5_eswitch {
        struct mlx5_core_dev    *dev;
        struct mlx5_nb          nb;
@@ -337,6 +342,7 @@ void esw_offloads_disable(struct mlx5_eswitch *esw);
 int esw_offloads_enable(struct mlx5_eswitch *esw);
 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw);
 int esw_offloads_init_reps(struct mlx5_eswitch *esw);
+void esw_offloads_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw);
 
 bool mlx5_esw_vport_match_metadata_supported(const struct mlx5_eswitch *esw);
 int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable);
@@ -350,10 +356,11 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev);
 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw);
 
 #define MLX5_ESWITCH_IGNORE_NUM_VFS (-1)
-int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int mode, int num_vfs);
+int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs);
 int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs);
-void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw, bool clear_vf);
-void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf);
+void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf);
+void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw);
+void mlx5_eswitch_disable(struct mlx5_eswitch *esw);
 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
                               u16 vport, const u8 *mac);
 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
@@ -575,6 +582,11 @@ mlx5_esw_devlink_port_index_to_vport_num(unsigned int dl_port_index)
        return dl_port_index & 0xffff;
 }
 
+static inline bool mlx5_esw_is_fdb_created(struct mlx5_eswitch *esw)
+{
+       return esw->fdb_table.flags & MLX5_ESW_FDB_CREATED;
+}
+
 /* TODO: This mlx5e_tc function shouldn't be called by eswitch */
 void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw);
 
@@ -719,7 +731,8 @@ int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw);
 static inline int  mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; }
 static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {}
 static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int num_vfs) { return 0; }
-static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf) {}
+static inline void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw, bool clear_vf) {}
+static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {}
 static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; }
 static inline
 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, u16 vport, int link_state) { return 0; }
index 2ce3728..e224ec7 100644 (file)
@@ -1040,6 +1040,15 @@ static void mlx5_eswitch_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw)
                mlx5_del_flow_rules(flows[i]);
 
        kvfree(flows);
+       /* If changing eswitch mode from switchdev to legacy, but num_vfs is not 0,
+        * meta rules could be freed again. So set it to NULL.
+        */
+       esw->fdb_table.offloads.send_to_vport_meta_rules = NULL;
+}
+
+void esw_offloads_del_send_to_vport_meta_rules(struct mlx5_eswitch *esw)
+{
+       mlx5_eswitch_del_send_to_vport_meta_rules(esw);
 }
 
 static int
@@ -2034,7 +2043,7 @@ static int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, u8 *mode)
        if (!MLX5_CAP_GEN(dev, vport_group_manager))
                return -EOPNOTSUPP;
 
-       if (esw->mode == MLX5_ESWITCH_NONE)
+       if (!mlx5_esw_is_fdb_created(esw))
                return -EOPNOTSUPP;
 
        switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
@@ -2170,18 +2179,18 @@ static int esw_offloads_start(struct mlx5_eswitch *esw,
 {
        int err, err1;
 
-       mlx5_eswitch_disable_locked(esw, false);
-       err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_OFFLOADS,
-                                        esw->dev->priv.sriov.num_vfs);
+       esw->mode = MLX5_ESWITCH_OFFLOADS;
+       err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "Failed setting eswitch to offloads");
-               err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY,
-                                                 MLX5_ESWITCH_IGNORE_NUM_VFS);
+               esw->mode = MLX5_ESWITCH_LEGACY;
+               err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
                if (err1) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Failed setting eswitch back to legacy");
                }
+               mlx5_rescan_drivers(esw->dev);
        }
        if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
                if (mlx5_eswitch_inline_mode_get(esw,
@@ -2894,7 +2903,7 @@ int mlx5_esw_offloads_vport_metadata_set(struct mlx5_eswitch *esw, bool enable)
        int err = 0;
 
        down_write(&esw->mode_lock);
-       if (esw->mode != MLX5_ESWITCH_NONE) {
+       if (mlx5_esw_is_fdb_created(esw)) {
                err = -EBUSY;
                goto done;
        }
@@ -3229,13 +3238,12 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
 {
        int err, err1;
 
-       mlx5_eswitch_disable_locked(esw, false);
-       err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_LEGACY,
-                                        MLX5_ESWITCH_IGNORE_NUM_VFS);
+       esw->mode = MLX5_ESWITCH_LEGACY;
+       err = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
        if (err) {
                NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy");
-               err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_OFFLOADS,
-                                                 MLX5_ESWITCH_IGNORE_NUM_VFS);
+               esw->mode = MLX5_ESWITCH_OFFLOADS;
+               err1 = mlx5_eswitch_enable_locked(esw, MLX5_ESWITCH_IGNORE_NUM_VFS);
                if (err1) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Failed setting eswitch back to offloads");
@@ -3334,15 +3342,6 @@ static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
        return 0;
 }
 
-static int eswitch_devlink_esw_mode_check(const struct mlx5_eswitch *esw)
-{
-       /* devlink commands in NONE eswitch mode are currently supported only
-        * on ECPF.
-        */
-       return (esw->mode == MLX5_ESWITCH_NONE &&
-               !mlx5_core_is_ecpf_esw_manager(esw->dev)) ? -EOPNOTSUPP : 0;
-}
-
 /* FIXME: devl_unlock() followed by devl_lock() inside driver callback
  * is never correct and prone to races. It's a transitional workaround,
  * never repeat this pattern.
@@ -3399,6 +3398,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
        if (cur_mlx5_mode == mlx5_mode)
                goto unlock;
 
+       mlx5_eswitch_disable_locked(esw);
        if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV) {
                if (mlx5_devlink_trap_get_num_active(esw->dev)) {
                        NL_SET_ERR_MSG_MOD(extack,
@@ -3409,6 +3409,7 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
                err = esw_offloads_start(esw, extack);
        } else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
                err = esw_offloads_stop(esw, extack);
+               mlx5_rescan_drivers(esw->dev);
        } else {
                err = -EINVAL;
        }
@@ -3431,12 +3432,7 @@ int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
                return PTR_ERR(esw);
 
        mlx5_eswtich_mode_callback_enter(devlink, esw);
-       err = eswitch_devlink_esw_mode_check(esw);
-       if (err)
-               goto unlock;
-
        err = esw_mode_to_devlink(esw->mode, mode);
-unlock:
        mlx5_eswtich_mode_callback_exit(devlink, esw);
        return err;
 }
@@ -3485,9 +3481,6 @@ int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode,
                return PTR_ERR(esw);
 
        mlx5_eswtich_mode_callback_enter(devlink, esw);
-       err = eswitch_devlink_esw_mode_check(esw);
-       if (err)
-               goto out;
 
        switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
        case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
@@ -3539,12 +3532,7 @@ int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
                return PTR_ERR(esw);
 
        mlx5_eswtich_mode_callback_enter(devlink, esw);
-       err = eswitch_devlink_esw_mode_check(esw);
-       if (err)
-               goto unlock;
-
        err = esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
-unlock:
        mlx5_eswtich_mode_callback_exit(devlink, esw);
        return err;
 }
@@ -3555,16 +3543,13 @@ int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink,
 {
        struct mlx5_core_dev *dev = devlink_priv(devlink);
        struct mlx5_eswitch *esw;
-       int err;
+       int err = 0;
 
        esw = mlx5_devlink_eswitch_get(devlink);
        if (IS_ERR(esw))
                return PTR_ERR(esw);
 
        mlx5_eswtich_mode_callback_enter(devlink, esw);
-       err = eswitch_devlink_esw_mode_check(esw);
-       if (err)
-               goto unlock;
 
        if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
            (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, reformat) ||
@@ -3615,21 +3600,15 @@ int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink,
                                        enum devlink_eswitch_encap_mode *encap)
 {
        struct mlx5_eswitch *esw;
-       int err;
 
        esw = mlx5_devlink_eswitch_get(devlink);
        if (IS_ERR(esw))
                return PTR_ERR(esw);
 
        mlx5_eswtich_mode_callback_enter(devlink, esw);
-       err = eswitch_devlink_esw_mode_check(esw);
-       if (err)
-               goto unlock;
-
        *encap = esw->offloads.encap;
-unlock:
        mlx5_eswtich_mode_callback_exit(devlink, esw);
-       return err;
+       return 0;
 }
 
 static bool
index 2ccf7be..735dc80 100644 (file)
@@ -479,6 +479,30 @@ static int mlx5_set_extended_dest(struct mlx5_core_dev *dev,
 
        return 0;
 }
+
+static void
+mlx5_cmd_set_fte_flow_meter(struct fs_fte *fte, void *in_flow_context)
+{
+       void *exe_aso_ctrl;
+       void *execute_aso;
+
+       execute_aso = MLX5_ADDR_OF(flow_context, in_flow_context,
+                                  execute_aso[0]);
+       MLX5_SET(execute_aso, execute_aso, valid, 1);
+       MLX5_SET(execute_aso, execute_aso, aso_object_id,
+                fte->action.exe_aso.object_id);
+
+       exe_aso_ctrl = MLX5_ADDR_OF(execute_aso, execute_aso, exe_aso_ctrl);
+       MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, return_reg_id,
+                fte->action.exe_aso.return_reg_id);
+       MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, aso_type,
+                fte->action.exe_aso.type);
+       MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, init_color,
+                fte->action.exe_aso.flow_meter.init_color);
+       MLX5_SET(exe_aso_ctrl_flow_meter, exe_aso_ctrl, meter_id,
+                fte->action.exe_aso.flow_meter.meter_idx);
+}
+
 static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
                            int opmod, int modify_mask,
                            struct mlx5_flow_table *ft,
@@ -663,6 +687,15 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
                         list_size);
        }
 
+       if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) {
+               if (fte->action.exe_aso.type == MLX5_EXE_ASO_FLOW_METER) {
+                       mlx5_cmd_set_fte_flow_meter(fte, in_flow_context);
+               } else {
+                       err = -EOPNOTSUPP;
+                       goto err_out;
+               }
+       }
+
        err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
 err_out:
        kvfree(in);
index 21e5c70..f1b908d 100644 (file)
@@ -2895,6 +2895,14 @@ static int create_fdb_bypass(struct mlx5_flow_steering *steering)
        return 0;
 }
 
+static void cleanup_fdb_root_ns(struct mlx5_flow_steering *steering)
+{
+       cleanup_root_ns(steering->fdb_root_ns);
+       steering->fdb_root_ns = NULL;
+       kfree(steering->fdb_sub_ns);
+       steering->fdb_sub_ns = NULL;
+}
+
 static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
 {
        struct fs_prio *maj_prio;
@@ -2945,10 +2953,7 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
        return 0;
 
 out_err:
-       cleanup_root_ns(steering->fdb_root_ns);
-       kfree(steering->fdb_sub_ns);
-       steering->fdb_sub_ns = NULL;
-       steering->fdb_root_ns = NULL;
+       cleanup_fdb_root_ns(steering);
        return err;
 }
 
@@ -3108,10 +3113,7 @@ void mlx5_fs_core_cleanup(struct mlx5_core_dev *dev)
        struct mlx5_flow_steering *steering = dev->priv.steering;
 
        cleanup_root_ns(steering->root_ns);
-       cleanup_root_ns(steering->fdb_root_ns);
-       steering->fdb_root_ns = NULL;
-       kfree(steering->fdb_sub_ns);
-       steering->fdb_sub_ns = NULL;
+       cleanup_fdb_root_ns(steering);
        cleanup_root_ns(steering->port_sel_root_ns);
        cleanup_root_ns(steering->sniffer_rx_root_ns);
        cleanup_root_ns(steering->sniffer_tx_root_ns);
index 2a8fc54..641505d 100644 (file)
@@ -632,6 +632,7 @@ static int mlx5_deactivate_lag(struct mlx5_lag *ldev)
 static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
 {
 #ifdef CONFIG_MLX5_ESWITCH
+       struct mlx5_core_dev *dev;
        u8 mode;
 #endif
        int i;
@@ -641,11 +642,11 @@ static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev)
                        return false;
 
 #ifdef CONFIG_MLX5_ESWITCH
-       mode = mlx5_eswitch_mode(ldev->pf[MLX5_LAG_P1].dev);
-
-       if (mode != MLX5_ESWITCH_NONE && mode != MLX5_ESWITCH_OFFLOADS)
+       dev = ldev->pf[MLX5_LAG_P1].dev;
+       if ((mlx5_sriov_is_enabled(dev)) && !is_mdev_switchdev_mode(dev))
                return false;
 
+       mode = mlx5_eswitch_mode(dev);
        for (i = 0; i < ldev->ports; i++)
                if (mlx5_eswitch_mode(ldev->pf[i].dev) != mode)
                        return false;
@@ -760,8 +761,7 @@ static bool mlx5_lag_is_roce_lag(struct mlx5_lag *ldev)
 
 #ifdef CONFIG_MLX5_ESWITCH
        for (i = 0; i < ldev->ports; i++)
-               roce_lag = roce_lag &&
-                       ldev->pf[i].dev->priv.eswitch->mode == MLX5_ESWITCH_NONE;
+               roce_lag = roce_lag && is_mdev_legacy_mode(ldev->pf[i].dev);
 #endif
 
        return roce_lag;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
new file mode 100644 (file)
index 0000000..21e1450
--- /dev/null
@@ -0,0 +1,433 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+
+#include <linux/mlx5/device.h>
+#include <linux/mlx5/transobj.h>
+#include "aso.h"
+#include "wq.h"
+
+struct mlx5_aso_cq {
+       /* data path - accessed per cqe */
+       struct mlx5_cqwq           wq;
+
+       /* data path - accessed per napi poll */
+       struct mlx5_core_cq        mcq;
+
+       /* control */
+       struct mlx5_core_dev      *mdev;
+       struct mlx5_wq_ctrl        wq_ctrl;
+} ____cacheline_aligned_in_smp;
+
+struct mlx5_aso {
+       /* data path */
+       u16                        cc;
+       u16                        pc;
+
+       struct mlx5_wqe_ctrl_seg  *doorbell_cseg;
+       struct mlx5_aso_cq         cq;
+
+       /* read only */
+       struct mlx5_wq_cyc         wq;
+       void __iomem              *uar_map;
+       u32                        sqn;
+
+       /* control path */
+       struct mlx5_wq_ctrl        wq_ctrl;
+
+} ____cacheline_aligned_in_smp;
+
+static void mlx5_aso_free_cq(struct mlx5_aso_cq *cq)
+{
+       mlx5_wq_destroy(&cq->wq_ctrl);
+}
+
+static int mlx5_aso_alloc_cq(struct mlx5_core_dev *mdev, int numa_node,
+                            void *cqc_data, struct mlx5_aso_cq *cq)
+{
+       struct mlx5_core_cq *mcq = &cq->mcq;
+       struct mlx5_wq_param param;
+       int err;
+       u32 i;
+
+       param.buf_numa_node = numa_node;
+       param.db_numa_node = numa_node;
+
+       err = mlx5_cqwq_create(mdev, &param, cqc_data, &cq->wq, &cq->wq_ctrl);
+       if (err)
+               return err;
+
+       mcq->cqe_sz     = 64;
+       mcq->set_ci_db  = cq->wq_ctrl.db.db;
+       mcq->arm_db     = cq->wq_ctrl.db.db + 1;
+
+       for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
+               struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
+
+               cqe->op_own = 0xf1;
+       }
+
+       cq->mdev = mdev;
+
+       return 0;
+}
+
+static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)
+{
+       u32 out[MLX5_ST_SZ_DW(create_cq_out)];
+       struct mlx5_core_dev *mdev = cq->mdev;
+       struct mlx5_core_cq *mcq = &cq->mcq;
+       void *in, *cqc;
+       int inlen, eqn;
+       int err;
+
+       err = mlx5_vector2eqn(mdev, 0, &eqn);
+       if (err)
+               return err;
+
+       inlen = MLX5_ST_SZ_BYTES(create_cq_in) +
+               sizeof(u64) * cq->wq_ctrl.buf.npages;
+       in = kvzalloc(inlen, GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context);
+
+       memcpy(cqc, cqc_data, MLX5_ST_SZ_BYTES(cqc));
+
+       mlx5_fill_page_frag_array(&cq->wq_ctrl.buf,
+                                 (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
+
+       MLX5_SET(cqc,   cqc, cq_period_mode, DIM_CQ_PERIOD_MODE_START_FROM_EQE);
+       MLX5_SET(cqc,   cqc, c_eqn_or_apu_element, eqn);
+       MLX5_SET(cqc,   cqc, uar_page,      mdev->priv.uar->index);
+       MLX5_SET(cqc,   cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
+                                           MLX5_ADAPTER_PAGE_SHIFT);
+       MLX5_SET64(cqc, cqc, dbr_addr,      cq->wq_ctrl.db.dma);
+
+       err = mlx5_core_create_cq(mdev, mcq, in, inlen, out, sizeof(out));
+
+       kvfree(in);
+
+       return err;
+}
+
+static void mlx5_aso_destroy_cq(struct mlx5_aso_cq *cq)
+{
+       mlx5_core_destroy_cq(cq->mdev, &cq->mcq);
+       mlx5_wq_destroy(&cq->wq_ctrl);
+}
+
+static int mlx5_aso_create_cq(struct mlx5_core_dev *mdev, int numa_node,
+                             struct mlx5_aso_cq *cq)
+{
+       void *cqc_data;
+       int err;
+
+       cqc_data = kvzalloc(MLX5_ST_SZ_BYTES(cqc), GFP_KERNEL);
+       if (!cqc_data)
+               return -ENOMEM;
+
+       MLX5_SET(cqc, cqc_data, log_cq_size, 1);
+       MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
+       if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
+               MLX5_SET(cqc, cqc_data, cqe_sz, CQE_STRIDE_128_PAD);
+
+       err = mlx5_aso_alloc_cq(mdev, numa_node, cqc_data, cq);
+       if (err) {
+               mlx5_core_err(mdev, "Failed to alloc aso wq cq, err=%d\n", err);
+               goto err_out;
+       }
+
+       err = create_aso_cq(cq, cqc_data);
+       if (err) {
+               mlx5_core_err(mdev, "Failed to create aso wq cq, err=%d\n", err);
+               goto err_free_cq;
+       }
+
+       kvfree(cqc_data);
+       return 0;
+
+err_free_cq:
+       mlx5_aso_free_cq(cq);
+err_out:
+       kvfree(cqc_data);
+       return err;
+}
+
+static int mlx5_aso_alloc_sq(struct mlx5_core_dev *mdev, int numa_node,
+                            void *sqc_data, struct mlx5_aso *sq)
+{
+       void *sqc_wq = MLX5_ADDR_OF(sqc, sqc_data, wq);
+       struct mlx5_wq_cyc *wq = &sq->wq;
+       struct mlx5_wq_param param;
+       int err;
+
+       sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
+
+       param.db_numa_node = numa_node;
+       param.buf_numa_node = numa_node;
+       err = mlx5_wq_cyc_create(mdev, &param, sqc_wq, wq, &sq->wq_ctrl);
+       if (err)
+               return err;
+       wq->db = &wq->db[MLX5_SND_DBR];
+
+       return 0;
+}
+
+static int create_aso_sq(struct mlx5_core_dev *mdev, int pdn,
+                        void *sqc_data, struct mlx5_aso *sq)
+{
+       void *in, *sqc, *wq;
+       int inlen, err;
+
+       inlen = MLX5_ST_SZ_BYTES(create_sq_in) +
+               sizeof(u64) * sq->wq_ctrl.buf.npages;
+       in = kvzalloc(inlen, GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
+       wq = MLX5_ADDR_OF(sqc, sqc, wq);
+
+       memcpy(sqc, sqc_data, MLX5_ST_SZ_BYTES(sqc));
+       MLX5_SET(sqc,  sqc, cqn, sq->cq.mcq.cqn);
+
+       MLX5_SET(sqc,  sqc, state, MLX5_SQC_STATE_RST);
+       MLX5_SET(sqc,  sqc, flush_in_error_en, 1);
+
+       MLX5_SET(wq,   wq, wq_type,       MLX5_WQ_TYPE_CYCLIC);
+       MLX5_SET(wq,   wq, uar_page,      mdev->mlx5e_res.hw_objs.bfreg.index);
+       MLX5_SET(wq,   wq, log_wq_pg_sz,  sq->wq_ctrl.buf.page_shift -
+                                         MLX5_ADAPTER_PAGE_SHIFT);
+       MLX5_SET64(wq, wq, dbr_addr,      sq->wq_ctrl.db.dma);
+
+       mlx5_fill_page_frag_array(&sq->wq_ctrl.buf,
+                                 (__be64 *)MLX5_ADDR_OF(wq, wq, pas));
+
+       err = mlx5_core_create_sq(mdev, in, inlen, &sq->sqn);
+
+       kvfree(in);
+
+       return err;
+}
+
+static int mlx5_aso_set_sq_rdy(struct mlx5_core_dev *mdev, u32 sqn)
+{
+       void *in, *sqc;
+       int inlen, err;
+
+       inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
+       in = kvzalloc(inlen, GFP_KERNEL);
+       if (!in)
+               return -ENOMEM;
+
+       MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RST);
+       sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
+       MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY);
+
+       err = mlx5_core_modify_sq(mdev, sqn, in);
+
+       kvfree(in);
+
+       return err;
+}
+
+static int mlx5_aso_create_sq_rdy(struct mlx5_core_dev *mdev, u32 pdn,
+                                 void *sqc_data, struct mlx5_aso *sq)
+{
+       int err;
+
+       err = create_aso_sq(mdev, pdn, sqc_data, sq);
+       if (err)
+               return err;
+
+       err = mlx5_aso_set_sq_rdy(mdev, sq->sqn);
+       if (err)
+               mlx5_core_destroy_sq(mdev, sq->sqn);
+
+       return err;
+}
+
+static void mlx5_aso_free_sq(struct mlx5_aso *sq)
+{
+       mlx5_wq_destroy(&sq->wq_ctrl);
+}
+
+static void mlx5_aso_destroy_sq(struct mlx5_aso *sq)
+{
+       mlx5_core_destroy_sq(sq->cq.mdev, sq->sqn);
+       mlx5_aso_free_sq(sq);
+}
+
+static int mlx5_aso_create_sq(struct mlx5_core_dev *mdev, int numa_node,
+                             u32 pdn, struct mlx5_aso *sq)
+{
+       void *sqc_data, *wq;
+       int err;
+
+       sqc_data = kvzalloc(MLX5_ST_SZ_BYTES(sqc), GFP_KERNEL);
+       if (!sqc_data)
+               return -ENOMEM;
+
+       wq = MLX5_ADDR_OF(sqc, sqc_data, wq);
+       MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
+       MLX5_SET(wq, wq, pd, pdn);
+       MLX5_SET(wq, wq, log_wq_sz, 1);
+
+       err = mlx5_aso_alloc_sq(mdev, numa_node, sqc_data, sq);
+       if (err) {
+               mlx5_core_err(mdev, "Failed to alloc aso wq sq, err=%d\n", err);
+               goto err_out;
+       }
+
+       err = mlx5_aso_create_sq_rdy(mdev, pdn, sqc_data, sq);
+       if (err) {
+               mlx5_core_err(mdev, "Failed to open aso wq sq, err=%d\n", err);
+               goto err_free_asosq;
+       }
+
+       mlx5_core_dbg(mdev, "aso sq->sqn = 0x%x\n", sq->sqn);
+
+       kvfree(sqc_data);
+       return 0;
+
+err_free_asosq:
+       mlx5_aso_free_sq(sq);
+err_out:
+       kvfree(sqc_data);
+       return err;
+}
+
+struct mlx5_aso *mlx5_aso_create(struct mlx5_core_dev *mdev, u32 pdn)
+{
+       int numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
+       struct mlx5_aso *aso;
+       int err;
+
+       aso = kzalloc(sizeof(*aso), GFP_KERNEL);
+       if (!aso)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlx5_aso_create_cq(mdev, numa_node, &aso->cq);
+       if (err)
+               goto err_cq;
+
+       err = mlx5_aso_create_sq(mdev, numa_node, pdn, aso);
+       if (err)
+               goto err_sq;
+
+       return aso;
+
+err_sq:
+       mlx5_aso_destroy_cq(&aso->cq);
+err_cq:
+       kfree(aso);
+       return ERR_PTR(err);
+}
+
+void mlx5_aso_destroy(struct mlx5_aso *aso)
+{
+       if (IS_ERR_OR_NULL(aso))
+               return;
+
+       mlx5_aso_destroy_sq(aso);
+       mlx5_aso_destroy_cq(&aso->cq);
+       kfree(aso);
+}
+
+void mlx5_aso_build_wqe(struct mlx5_aso *aso, u8 ds_cnt,
+                       struct mlx5_aso_wqe *aso_wqe,
+                       u32 obj_id, u32 opc_mode)
+{
+       struct mlx5_wqe_ctrl_seg *cseg = &aso_wqe->ctrl;
+
+       cseg->opmod_idx_opcode = cpu_to_be32((opc_mode << MLX5_WQE_CTRL_WQE_OPC_MOD_SHIFT) |
+                                            (aso->pc << MLX5_WQE_CTRL_WQE_INDEX_SHIFT) |
+                                            MLX5_OPCODE_ACCESS_ASO);
+       cseg->qpn_ds     = cpu_to_be32((aso->sqn << MLX5_WQE_CTRL_QPN_SHIFT) | ds_cnt);
+       cseg->fm_ce_se   = MLX5_WQE_CTRL_CQ_UPDATE;
+       cseg->general_id = cpu_to_be32(obj_id);
+}
+
+void *mlx5_aso_get_wqe(struct mlx5_aso *aso)
+{
+       u16 pi;
+
+       pi = mlx5_wq_cyc_ctr2ix(&aso->wq, aso->pc);
+       return mlx5_wq_cyc_get_wqe(&aso->wq, pi);
+}
+
+void mlx5_aso_post_wqe(struct mlx5_aso *aso, bool with_data,
+                      struct mlx5_wqe_ctrl_seg *doorbell_cseg)
+{
+       doorbell_cseg->fm_ce_se |= MLX5_WQE_CTRL_CQ_UPDATE;
+       /* ensure wqe is visible to device before updating doorbell record */
+       dma_wmb();
+
+       if (with_data)
+               aso->pc += MLX5_ASO_WQEBBS_DATA;
+       else
+               aso->pc += MLX5_ASO_WQEBBS;
+       *aso->wq.db = cpu_to_be32(aso->pc);
+
+       /* ensure doorbell record is visible to device before ringing the
+        * doorbell
+        */
+       wmb();
+
+       mlx5_write64((__be32 *)doorbell_cseg, aso->uar_map);
+
+       /* Ensure doorbell is written on uar_page before poll_cq */
+       WRITE_ONCE(doorbell_cseg, NULL);
+}
+
+int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data, u32 interval_ms)
+{
+       struct mlx5_aso_cq *cq = &aso->cq;
+       struct mlx5_cqe64 *cqe;
+       unsigned long expires;
+
+       cqe = mlx5_cqwq_get_cqe(&cq->wq);
+
+       expires = jiffies + msecs_to_jiffies(interval_ms);
+       while (!cqe && time_is_after_jiffies(expires)) {
+               usleep_range(2, 10);
+               cqe = mlx5_cqwq_get_cqe(&cq->wq);
+       }
+
+       if (!cqe)
+               return -ETIMEDOUT;
+
+       /* sq->cc must be updated only after mlx5_cqwq_update_db_record(),
+        * otherwise a cq overrun may occur
+        */
+       mlx5_cqwq_pop(&cq->wq);
+
+       if (unlikely(get_cqe_opcode(cqe) != MLX5_CQE_REQ)) {
+               struct mlx5_err_cqe *err_cqe;
+
+               mlx5_core_err(cq->mdev, "Bad OP in ASOSQ CQE: 0x%x\n",
+                             get_cqe_opcode(cqe));
+
+               err_cqe = (struct mlx5_err_cqe *)cqe;
+               mlx5_core_err(cq->mdev, "vendor_err_synd=%x\n",
+                             err_cqe->vendor_err_synd);
+               mlx5_core_err(cq->mdev, "syndrome=%x\n",
+                             err_cqe->syndrome);
+               print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET,
+                              16, 1, err_cqe,
+                              sizeof(*err_cqe), false);
+       }
+
+       mlx5_cqwq_update_db_record(&cq->wq);
+
+       /* ensure cq space is freed before enabling more cqes */
+       wmb();
+
+       if (with_data)
+               aso->cc += MLX5_ASO_WQEBBS_DATA;
+       else
+               aso->cc += MLX5_ASO_WQEBBS;
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.h
new file mode 100644 (file)
index 0000000..b3bbf28
--- /dev/null
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#ifndef __MLX5_LIB_ASO_H__
+#define __MLX5_LIB_ASO_H__
+
+#include <linux/mlx5/qp.h>
+#include "mlx5_core.h"
+
+#define MLX5_ASO_WQEBBS \
+       (DIV_ROUND_UP(sizeof(struct mlx5_aso_wqe), MLX5_SEND_WQE_BB))
+#define MLX5_ASO_WQEBBS_DATA \
+       (DIV_ROUND_UP(sizeof(struct mlx5_aso_wqe_data), MLX5_SEND_WQE_BB))
+#define MLX5_WQE_CTRL_WQE_OPC_MOD_SHIFT 24
+
+struct mlx5_wqe_aso_ctrl_seg {
+       __be32  va_h;
+       __be32  va_l; /* include read_enable */
+       __be32  l_key;
+       u8      data_mask_mode;
+       u8      condition_1_0_operand;
+       u8      condition_1_0_offset;
+       u8      data_offset_condition_operand;
+       __be32  condition_0_data;
+       __be32  condition_0_mask;
+       __be32  condition_1_data;
+       __be32  condition_1_mask;
+       __be64  bitwise_data;
+       __be64  data_mask;
+};
+
+struct mlx5_wqe_aso_data_seg {
+       __be32  bytewise_data[16];
+};
+
+struct mlx5_aso_wqe {
+       struct mlx5_wqe_ctrl_seg      ctrl;
+       struct mlx5_wqe_aso_ctrl_seg  aso_ctrl;
+};
+
+struct mlx5_aso_wqe_data {
+       struct mlx5_wqe_ctrl_seg      ctrl;
+       struct mlx5_wqe_aso_ctrl_seg  aso_ctrl;
+       struct mlx5_wqe_aso_data_seg  aso_data;
+};
+
+enum {
+       MLX5_ASO_LOGICAL_AND,
+       MLX5_ASO_LOGICAL_OR,
+};
+
+enum {
+       MLX5_ASO_ALWAYS_FALSE,
+       MLX5_ASO_ALWAYS_TRUE,
+       MLX5_ASO_EQUAL,
+       MLX5_ASO_NOT_EQUAL,
+       MLX5_ASO_GREATER_OR_EQUAL,
+       MLX5_ASO_LESSER_OR_EQUAL,
+       MLX5_ASO_LESSER,
+       MLX5_ASO_GREATER,
+       MLX5_ASO_CYCLIC_GREATER,
+       MLX5_ASO_CYCLIC_LESSER,
+};
+
+enum {
+       MLX5_ASO_DATA_MASK_MODE_BITWISE_64BIT,
+       MLX5_ASO_DATA_MASK_MODE_BYTEWISE_64BYTE,
+       MLX5_ASO_DATA_MASK_MODE_CALCULATED_64BYTE,
+};
+
+enum {
+       MLX5_ACCESS_ASO_OPC_MOD_FLOW_METER = 0x2,
+};
+
+struct mlx5_aso;
+
+void *mlx5_aso_get_wqe(struct mlx5_aso *aso);
+void mlx5_aso_build_wqe(struct mlx5_aso *aso, u8 ds_cnt,
+                       struct mlx5_aso_wqe *aso_wqe,
+                       u32 obj_id, u32 opc_mode);
+void mlx5_aso_post_wqe(struct mlx5_aso *aso, bool with_data,
+                      struct mlx5_wqe_ctrl_seg *doorbell_cseg);
+int mlx5_aso_poll_cq(struct mlx5_aso *aso, bool with_data, u32 interval_ms);
+
+struct mlx5_aso *mlx5_aso_create(struct mlx5_core_dev *mdev, u32 pdn);
+void mlx5_aso_destroy(struct mlx5_aso *aso);
+#endif /* __MLX5_LIB_ASO_H__ */
index 3d5e57f..7e02cbe 100644 (file)
@@ -12,13 +12,16 @@ struct mlx5_dm {
        spinlock_t lock;
        unsigned long *steering_sw_icm_alloc_blocks;
        unsigned long *header_modify_sw_icm_alloc_blocks;
+       unsigned long *header_modify_pattern_sw_icm_alloc_blocks;
 };
 
 struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
 {
+       u64 header_modify_pattern_icm_blocks = 0;
        u64 header_modify_icm_blocks = 0;
        u64 steering_icm_blocks = 0;
        struct mlx5_dm *dm;
+       bool support_v2;
 
        if (!(MLX5_CAP_GEN_64(dev, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_SW_ICM))
                return NULL;
@@ -53,8 +56,27 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
                        goto err_modify_hdr;
        }
 
+       support_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) &&
+                    MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2) &&
+                    MLX5_CAP64_DEV_MEM(dev, header_modify_pattern_sw_icm_start_address);
+
+       if (support_v2) {
+               header_modify_pattern_icm_blocks =
+                       BIT(MLX5_CAP_DEV_MEM(dev, log_header_modify_pattern_sw_icm_size) -
+                           MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
+
+               dm->header_modify_pattern_sw_icm_alloc_blocks =
+                       kcalloc(BITS_TO_LONGS(header_modify_pattern_icm_blocks),
+                               sizeof(unsigned long), GFP_KERNEL);
+               if (!dm->header_modify_pattern_sw_icm_alloc_blocks)
+                       goto err_pattern;
+       }
+
        return dm;
 
+err_pattern:
+       kfree(dm->header_modify_sw_icm_alloc_blocks);
+
 err_modify_hdr:
        kfree(dm->steering_sw_icm_alloc_blocks);
 
@@ -86,6 +108,14 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
                kfree(dm->header_modify_sw_icm_alloc_blocks);
        }
 
+       if (dm->header_modify_pattern_sw_icm_alloc_blocks) {
+               WARN_ON(!bitmap_empty(dm->header_modify_pattern_sw_icm_alloc_blocks,
+                                     BIT(MLX5_CAP_DEV_MEM(dev,
+                                                          log_header_modify_pattern_sw_icm_size) -
+                                         MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
+               kfree(dm->header_modify_pattern_sw_icm_alloc_blocks);
+       }
+
        kfree(dm);
 }
 
@@ -130,6 +160,13 @@ int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
                                                log_header_modify_sw_icm_size);
                block_map = dm->header_modify_sw_icm_alloc_blocks;
                break;
+       case MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN:
+               icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
+                                                   header_modify_pattern_sw_icm_start_address);
+               log_icm_size = MLX5_CAP_DEV_MEM(dev,
+                                               log_header_modify_pattern_sw_icm_size);
+               block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
+               break;
        default:
                return -EINVAL;
        }
@@ -203,6 +240,11 @@ int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type
                icm_start_addr = MLX5_CAP64_DEV_MEM(dev, header_modify_sw_icm_start_address);
                block_map = dm->header_modify_sw_icm_alloc_blocks;
                break;
+       case MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN:
+               icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
+                                                   header_modify_pattern_sw_icm_start_address);
+               block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
+               break;
        default:
                return -EINVAL;
        }
index c9b4e50..a9e51c1 100644 (file)
@@ -314,13 +314,6 @@ struct mlx5_reg_host_endianness {
        u8      rsvd[15];
 };
 
-#define CAP_MASK(pos, size) ((u64)((1 << (size)) - 1) << (pos))
-
-enum {
-       MLX5_CAP_BITS_RW_MASK = CAP_MASK(MLX5_CAP_OFF_CMDIF_CSUM, 2) |
-                               MLX5_DEV_CAP_FLAG_DCT,
-};
-
 static u16 to_fw_pkey_sz(struct mlx5_core_dev *dev, u32 size)
 {
        switch (size) {
@@ -1257,6 +1250,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
 {
        mlx5_sf_dev_table_destroy(dev);
        mlx5_sriov_detach(dev);
+       mlx5_eswitch_disable(dev->priv.eswitch);
        mlx5_lag_remove_mdev(dev);
        mlx5_ec_cleanup(dev);
        mlx5_sf_hw_table_destroy(dev);
index 3be659c..7d955a4 100644 (file)
@@ -501,7 +501,7 @@ static int mlx5_sf_esw_event(struct notifier_block *nb, unsigned long event, voi
        case MLX5_ESWITCH_OFFLOADS:
                mlx5_sf_table_enable(table);
                break;
-       case MLX5_ESWITCH_NONE:
+       case MLX5_ESWITCH_LEGACY:
                mlx5_sf_table_disable(table);
                break;
        default:
index 2935614..5757cd6 100644 (file)
@@ -145,8 +145,7 @@ mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf)
                sriov->vfs_ctx[vf].enabled = 0;
        }
 
-       if (MLX5_ESWITCH_MANAGER(dev))
-               mlx5_eswitch_disable(dev->priv.eswitch, clear_vf);
+       mlx5_eswitch_disable_sriov(dev->priv.eswitch, clear_vf);
 
        if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages))
                mlx5_core_warn(dev, "timeout reclaiming VFs pages\n");
index 84621b4..b03e1c6 100644 (file)
@@ -19,8 +19,6 @@
 #include "mlxbf_gige.h"
 #include "mlxbf_gige_regs.h"
 
-#define DRV_NAME    "mlxbf_gige"
-
 /* Allocate SKB whose payload pointer aligns with the Bluefield
  * hardware DMA limitation, i.e. DMA operation can't cross
  * a 4KB boundary.  A maximum packet size of 2KB is assumed in the
@@ -427,7 +425,7 @@ static struct platform_driver mlxbf_gige_driver = {
        .remove = mlxbf_gige_remove,
        .shutdown = mlxbf_gige_shutdown,
        .driver = {
-               .name = DRV_NAME,
+               .name = KBUILD_MODNAME,
                .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match),
        },
 };
index 1a465fd..c2d6d64 100644 (file)
@@ -12,7 +12,6 @@ mlxsw_i2c-objs                        := i2c.o
 obj-$(CONFIG_MLXSW_SPECTRUM)   += mlxsw_spectrum.o
 mlxsw_spectrum-objs            := spectrum.o spectrum_buffers.o \
                                   spectrum_switchdev.o spectrum_router.o \
-                                  spectrum_router_xm.o \
                                   spectrum1_kvdl.o spectrum2_kvdl.o \
                                   spectrum_kvdl.o \
                                   spectrum_acl_tcam.o spectrum_acl_ctcam.o \
@@ -29,7 +28,8 @@ mlxsw_spectrum-objs           := spectrum.o spectrum_buffers.o \
                                   spectrum_qdisc.o spectrum_span.o \
                                   spectrum_nve.o spectrum_nve_vxlan.o \
                                   spectrum_dpipe.o spectrum_trap.o \
-                                  spectrum_ethtool.o spectrum_policer.o
+                                  spectrum_ethtool.o spectrum_policer.o \
+                                  spectrum_pgt.o
 mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB)    += spectrum_dcb.o
 mlxsw_spectrum-$(CONFIG_PTP_1588_CLOCK)                += spectrum_ptp.o
 obj-$(CONFIG_MLXSW_MINIMAL)    += mlxsw_minimal.o
index 51b260d..666d6b6 100644 (file)
@@ -343,23 +343,6 @@ static inline int mlxsw_cmd_boardinfo(struct mlxsw_core *mlxsw_core,
                                  0, 0, false, out_mbox, MLXSW_CMD_MBOX_SIZE);
 }
 
-/* cmd_mbox_xm_num_local_ports
- * Number of local_ports connected to the xm.
- * Each local port is a 4x
- * Spectrum-2/3: 25G
- * Spectrum-4: 50G
- */
-MLXSW_ITEM32(cmd_mbox, boardinfo, xm_num_local_ports, 0x00, 4, 3);
-
-/* cmd_mbox_xm_exists
- * An XM (eXtanded Mezanine, e.g. used for the XLT) is connected on the board.
- */
-MLXSW_ITEM32(cmd_mbox, boardinfo, xm_exists, 0x00, 0, 1);
-
-/* cmd_mbox_xm_local_port_entry
- */
-MLXSW_ITEM_BIT_ARRAY(cmd_mbox, boardinfo, xm_local_port_entry, 0x04, 4, 8);
-
 /* cmd_mbox_boardinfo_intapin
  * When PCIe interrupt messages are being used, this value is used for clearing
  * an interrupt. When using MSI-X, this register is not used.
@@ -650,6 +633,12 @@ MLXSW_ITEM32(cmd_mbox, config_profile,
  */
 MLXSW_ITEM32(cmd_mbox, config_profile, set_ar_sec, 0x0C, 15, 1);
 
+/* cmd_mbox_config_set_ubridge
+ * Capability bit. Setting a bit to 1 configures the profile
+ * according to the mailbox contents.
+ */
+MLXSW_ITEM32(cmd_mbox, config_profile, set_ubridge, 0x0C, 22, 1);
+
 /* cmd_mbox_config_set_kvd_linear_size
  * Capability bit. Setting a bit to 1 configures the profile
  * according to the mailbox contents.
@@ -674,12 +663,6 @@ MLXSW_ITEM32(cmd_mbox, config_profile, set_kvd_hash_double_size, 0x0C, 26, 1);
  */
 MLXSW_ITEM32(cmd_mbox, config_profile, set_cqe_version, 0x08, 0, 1);
 
-/* cmd_mbox_config_set_kvh_xlt_cache_mode
- * Capability bit. Setting a bit to 1 configures the profile
- * according to the mailbox contents.
- */
-MLXSW_ITEM32(cmd_mbox, config_profile, set_kvh_xlt_cache_mode, 0x08, 3, 1);
-
 /* cmd_mbox_config_profile_max_vepa_channels
  * Maximum number of VEPA channels per port (0 through 16)
  * 0 - multi-channel VEPA is disabled
@@ -736,16 +719,25 @@ MLXSW_ITEM32(cmd_mbox, config_profile, max_flood_tables, 0x30, 16, 4);
  */
 MLXSW_ITEM32(cmd_mbox, config_profile, max_vid_flood_tables, 0x30, 8, 4);
 
+enum mlxsw_cmd_mbox_config_profile_flood_mode {
+       /* Mixed mode, where:
+        * max_flood_tables indicates the number of single-entry tables.
+        * max_vid_flood_tables indicates the number of per-VID tables.
+        * max_fid_offset_flood_tables indicates the number of FID-offset
+        * tables. max_fid_flood_tables indicates the number of per-FID tables.
+        * Reserved when unified bridge model is used.
+        */
+       MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_MIXED = 3,
+       /* Controlled flood tables. Reserved when legacy bridge model is
+        * used.
+        */
+       MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED = 4,
+};
+
 /* cmd_mbox_config_profile_flood_mode
  * Flooding mode to use.
- * 0-2 - Backward compatible modes for SwitchX devices.
- * 3 - Mixed mode, where:
- * max_flood_tables indicates the number of single-entry tables.
- * max_vid_flood_tables indicates the number of per-VID tables.
- * max_fid_offset_flood_tables indicates the number of FID-offset tables.
- * max_fid_flood_tables indicates the number of per-FID tables.
  */
-MLXSW_ITEM32(cmd_mbox, config_profile, flood_mode, 0x30, 0, 2);
+MLXSW_ITEM32(cmd_mbox, config_profile, flood_mode, 0x30, 0, 3);
 
 /* cmd_mbox_config_profile_max_fid_offset_flood_tables
  * Maximum number of FID-offset flooding tables.
@@ -806,12 +798,12 @@ MLXSW_ITEM32(cmd_mbox, config_profile, adaptive_routing_group_cap, 0x4C, 0, 16);
  */
 MLXSW_ITEM32(cmd_mbox, config_profile, arn, 0x50, 31, 1);
 
-/* cmd_mbox_config_profile_kvh_xlt_cache_mode
- * KVH XLT cache mode:
- * 0 - XLT can use all KVH as best-effort
- * 1 - XLT cache uses 1/2 KVH
+/* cmd_mbox_config_profile_ubridge
+ * Unified Bridge
+ * 0 - non unified bridge
+ * 1 - unified bridge
  */
-MLXSW_ITEM32(cmd_mbox, config_profile, kvh_xlt_cache_mode, 0x50, 8, 4);
+MLXSW_ITEM32(cmd_mbox, config_profile, ubridge, 0x50, 4, 1);
 
 /* cmd_mbox_config_kvd_linear_size
  * KVD Linear Size
index fc52832..ab1cebf 100644 (file)
@@ -3151,18 +3151,6 @@ mlxsw_core_port_linecard_get(struct mlxsw_core *mlxsw_core,
        return mlxsw_core_port->linecard;
 }
 
-bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u16 local_port)
-{
-       const struct mlxsw_bus_info *bus_info = mlxsw_core->bus_info;
-       int i;
-
-       for (i = 0; i < bus_info->xm_local_ports_count; i++)
-               if (bus_info->xm_local_ports[i] == local_port)
-                       return true;
-       return false;
-}
-EXPORT_SYMBOL(mlxsw_core_port_is_xm);
-
 void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core,
                                      bool (*selector)(void *priv, u16 local_port),
                                      void *priv)
index c2a8912..a3491ef 100644 (file)
@@ -261,7 +261,6 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core,
 struct mlxsw_linecard *
 mlxsw_core_port_linecard_get(struct mlxsw_core *mlxsw_core,
                             u16 local_port);
-bool mlxsw_core_port_is_xm(const struct mlxsw_core *mlxsw_core, u16 local_port);
 void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core,
                                      bool (*selector)(void *priv,
                                                       u16 local_port),
@@ -296,8 +295,8 @@ struct mlxsw_config_profile {
                used_max_pkey:1,
                used_ar_sec:1,
                used_adaptive_routing_group_cap:1,
-               used_kvd_sizes:1,
-               used_kvh_xlt_cache_mode:1;
+               used_ubridge:1,
+               used_kvd_sizes:1;
        u8      max_vepa_channels;
        u16     max_mid;
        u16     max_pgt;
@@ -316,10 +315,10 @@ struct mlxsw_config_profile {
        u8      ar_sec;
        u16     adaptive_routing_group_cap;
        u8      arn;
+       u8      ubridge;
        u32     kvd_linear_size;
        u8      kvd_hash_single_parts;
        u8      kvd_hash_double_parts;
-       u8      kvh_xlt_cache_mode;
        struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT];
 };
 
@@ -478,8 +477,6 @@ struct mlxsw_fw_rev {
        u16 can_reset_minor;
 };
 
-#define MLXSW_BUS_INFO_XM_LOCAL_PORTS_MAX 4
-
 struct mlxsw_bus_info {
        const char *device_kind;
        const char *device_name;
@@ -488,10 +485,7 @@ struct mlxsw_bus_info {
        u8 vsd[MLXSW_CMD_BOARDINFO_VSD_LEN];
        u8 psid[MLXSW_CMD_BOARDINFO_PSID_LEN];
        u8 low_frequency:1,
-          read_frc_capable:1,
-          xm_exists:1;
-       u8 xm_local_ports_count;
-       u8 xm_local_ports[MLXSW_BUS_INFO_XM_LOCAL_PORTS_MAX];
+          read_frc_capable:1;
 };
 
 struct mlxsw_hwmon;
index fa33cae..636db9a 100644 (file)
@@ -1164,7 +1164,7 @@ EXPORT_SYMBOL(mlxsw_afa_block_append_vlan_modify);
  * trap control. In addition, the Trap / Discard action enables activating
  * SPAN (port mirroring).
  *
- * The Trap with userdef action action has the same functionality as
+ * The Trap with userdef action has the same functionality as
  * the Trap action with addition of user defined value that can be set
  * and used by higher layer applications.
  */
index 34bec9c..0107cbc 100644 (file)
@@ -180,7 +180,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index,
                } else {
                        /* When reading upper pages 1, 2 and 3 the offset
                         * starts at 0 and I2C high address is used. Please refer
-                        * refer to "Memory Organization" figure in SFF-8472
+                        * to "Memory Organization" figure in SFF-8472
                         * specification for graphical depiction.
                         */
                        i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH;
index d9660d4..d9bf584 100644 (file)
@@ -359,8 +359,7 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
        /* Create port objects for each valid entry */
        devl_lock(devlink);
        for (i = 0; i < mlxsw_m->max_ports; i++) {
-               if (mlxsw_m->module_to_port[i] > 0 &&
-                   !mlxsw_core_port_is_xm(mlxsw_m->core, i)) {
+               if (mlxsw_m->module_to_port[i] > 0) {
                        err = mlxsw_m_port_create(mlxsw_m,
                                                  mlxsw_m->module_to_port[i],
                                                  i);
index f91dde4..41f0f68 100644 (file)
@@ -1235,6 +1235,11 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
                mlxsw_cmd_mbox_config_profile_adaptive_routing_group_cap_set(
                        mbox, profile->adaptive_routing_group_cap);
        }
+       if (profile->used_ubridge) {
+               mlxsw_cmd_mbox_config_profile_set_ubridge_set(mbox, 1);
+               mlxsw_cmd_mbox_config_profile_ubridge_set(mbox,
+                                                         profile->ubridge);
+       }
        if (profile->used_kvd_sizes && MLXSW_RES_VALID(res, KVD_SIZE)) {
                err = mlxsw_pci_profile_get_kvd_sizes(mlxsw_pci, profile, res);
                if (err)
@@ -1252,12 +1257,6 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
                mlxsw_cmd_mbox_config_profile_kvd_hash_double_size_set(mbox,
                                        MLXSW_RES_GET(res, KVD_DOUBLE_SIZE));
        }
-       if (profile->used_kvh_xlt_cache_mode) {
-               mlxsw_cmd_mbox_config_profile_set_kvh_xlt_cache_mode_set(
-                       mbox, 1);
-               mlxsw_cmd_mbox_config_profile_kvh_xlt_cache_mode_set(
-                       mbox, profile->kvh_xlt_cache_mode);
-       }
 
        for (i = 0; i < MLXSW_CONFIG_PROFILE_SWID_COUNT; i++)
                mlxsw_pci_config_profile_swid_config(mlxsw_pci, mbox, i,
@@ -1271,30 +1270,6 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
        return mlxsw_cmd_config_profile_set(mlxsw_pci->core, mbox);
 }
 
-static int mlxsw_pci_boardinfo_xm_process(struct mlxsw_pci *mlxsw_pci,
-                                         struct mlxsw_bus_info *bus_info,
-                                         char *mbox)
-{
-       int count = mlxsw_cmd_mbox_boardinfo_xm_num_local_ports_get(mbox);
-       int i;
-
-       if (!mlxsw_cmd_mbox_boardinfo_xm_exists_get(mbox))
-               return 0;
-
-       bus_info->xm_exists = true;
-
-       if (count > MLXSW_BUS_INFO_XM_LOCAL_PORTS_MAX) {
-               dev_err(&mlxsw_pci->pdev->dev, "Invalid number of XM local ports\n");
-               return -EINVAL;
-       }
-       bus_info->xm_local_ports_count = count;
-       for (i = 0; i < count; i++)
-               bus_info->xm_local_ports[i] =
-                       mlxsw_cmd_mbox_boardinfo_xm_local_port_entry_get(mbox,
-                                                                        i);
-       return 0;
-}
-
 static int mlxsw_pci_boardinfo(struct mlxsw_pci *mlxsw_pci, char *mbox)
 {
        struct mlxsw_bus_info *bus_info = &mlxsw_pci->bus_info;
@@ -1306,8 +1281,7 @@ static int mlxsw_pci_boardinfo(struct mlxsw_pci *mlxsw_pci, char *mbox)
                return err;
        mlxsw_cmd_mbox_boardinfo_vsd_memcpy_from(mbox, bus_info->vsd);
        mlxsw_cmd_mbox_boardinfo_psid_memcpy_from(mbox, bus_info->psid);
-
-       return mlxsw_pci_boardinfo_xm_process(mlxsw_pci, bus_info, mbox);
+       return 0;
 }
 
 static int mlxsw_pci_fw_area_init(struct mlxsw_pci *mlxsw_pci, char *mbox,
@@ -1582,6 +1556,14 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
        if (err)
                goto err_config_profile;
 
+       /* Some resources depend on unified bridge model, which is configured
+        * as part of config_profile. Query the resources again to get correct
+        * values.
+        */
+       err = mlxsw_core_resources_query(mlxsw_core, mbox, res);
+       if (err)
+               goto err_requery_resources;
+
        err = mlxsw_pci_aqs_init(mlxsw_pci, mbox);
        if (err)
                goto err_aqs_init;
@@ -1599,6 +1581,7 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
 err_request_eq_irq:
        mlxsw_pci_aqs_fini(mlxsw_pci);
 err_aqs_init:
+err_requery_resources:
 err_config_profile:
 err_cqe_v_check:
 err_query_resources:
index 741fd29..ac4d4ea 100644 (file)
@@ -15,8 +15,6 @@
 #define MLXSW_PORT_SWID_TYPE_IB                1
 #define MLXSW_PORT_SWID_TYPE_ETH       2
 
-#define MLXSW_PORT_MID                 0xd000
-
 #define MLXSW_PORT_MAX_IB_PHY_PORTS    36
 #define MLXSW_PORT_MAX_IB_PORTS                (MLXSW_PORT_MAX_IB_PHY_PORTS + 1)
 
index 93af6c9..17ce28e 100644 (file)
@@ -322,6 +322,18 @@ MLXSW_ITEM32_INDEXED(reg, sfd, rec_action, MLXSW_REG_SFD_BASE_LEN, 28, 4,
 MLXSW_ITEM32_INDEXED(reg, sfd, uc_sub_port, MLXSW_REG_SFD_BASE_LEN, 16, 8,
                     MLXSW_REG_SFD_REC_LEN, 0x08, false);
 
+/* reg_sfd_uc_set_vid
+ * Set VID.
+ * 0 - Do not update VID.
+ * 1 - Set VID.
+ * For Spectrum-2 when set_vid=0 and smpe_valid=1, the smpe will modify the vid.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_set_vid, MLXSW_REG_SFD_BASE_LEN, 31, 1,
+                    MLXSW_REG_SFD_REC_LEN, 0x08, false);
+
 /* reg_sfd_uc_fid_vid
  * Filtering ID or VLAN ID
  * For SwitchX and SwitchX-2:
@@ -335,6 +347,15 @@ MLXSW_ITEM32_INDEXED(reg, sfd, uc_sub_port, MLXSW_REG_SFD_BASE_LEN, 16, 8,
 MLXSW_ITEM32_INDEXED(reg, sfd, uc_fid_vid, MLXSW_REG_SFD_BASE_LEN, 0, 16,
                     MLXSW_REG_SFD_REC_LEN, 0x08, false);
 
+/* reg_sfd_uc_vid
+ * New VID when set_vid=1.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and when set_vid=0.
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_vid, MLXSW_REG_SFD_BASE_LEN, 16, 12,
+                    MLXSW_REG_SFD_REC_LEN, 0x0C, false);
+
 /* reg_sfd_uc_system_port
  * Unique port identifier for the final destination of the packet.
  * Access: RW
@@ -359,7 +380,7 @@ static inline void mlxsw_reg_sfd_rec_pack(char *payload, int rec_index,
 
 static inline void mlxsw_reg_sfd_uc_pack(char *payload, int rec_index,
                                         enum mlxsw_reg_sfd_rec_policy policy,
-                                        const char *mac, u16 fid_vid,
+                                        const char *mac, u16 fid_vid, u16 vid,
                                         enum mlxsw_reg_sfd_rec_action action,
                                         u16 local_port)
 {
@@ -368,6 +389,8 @@ static inline void mlxsw_reg_sfd_uc_pack(char *payload, int rec_index,
        mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy);
        mlxsw_reg_sfd_uc_sub_port_set(payload, rec_index, 0);
        mlxsw_reg_sfd_uc_fid_vid_set(payload, rec_index, fid_vid);
+       mlxsw_reg_sfd_uc_set_vid_set(payload, rec_index, vid ? true : false);
+       mlxsw_reg_sfd_uc_vid_set(payload, rec_index, vid);
        mlxsw_reg_sfd_uc_system_port_set(payload, rec_index, local_port);
 }
 
@@ -379,6 +402,18 @@ static inline void mlxsw_reg_sfd_uc_pack(char *payload, int rec_index,
 MLXSW_ITEM32_INDEXED(reg, sfd, uc_lag_sub_port, MLXSW_REG_SFD_BASE_LEN, 16, 8,
                     MLXSW_REG_SFD_REC_LEN, 0x08, false);
 
+/* reg_sfd_uc_lag_set_vid
+ * Set VID.
+ * 0 - Do not update VID.
+ * 1 - Set VID.
+ * For Spectrum-2 when set_vid=0 and smpe_valid=1, the smpe will modify the vid.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32_INDEXED(reg, sfd, uc_lag_set_vid, MLXSW_REG_SFD_BASE_LEN, 31, 1,
+                    MLXSW_REG_SFD_REC_LEN, 0x08, false);
+
 /* reg_sfd_uc_lag_fid_vid
  * Filtering ID or VLAN ID
  * For SwitchX and SwitchX-2:
@@ -393,8 +428,10 @@ MLXSW_ITEM32_INDEXED(reg, sfd, uc_lag_fid_vid, MLXSW_REG_SFD_BASE_LEN, 0, 16,
                     MLXSW_REG_SFD_REC_LEN, 0x08, false);
 
 /* reg_sfd_uc_lag_lag_vid
- * Indicates VID in case of vFIDs. Reserved for FIDs.
+ * New vlan ID.
  * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and set_vid=0.
  */
 MLXSW_ITEM32_INDEXED(reg, sfd, uc_lag_lag_vid, MLXSW_REG_SFD_BASE_LEN, 16, 12,
                     MLXSW_REG_SFD_REC_LEN, 0x0C, false);
@@ -419,6 +456,7 @@ mlxsw_reg_sfd_uc_lag_pack(char *payload, int rec_index,
        mlxsw_reg_sfd_rec_policy_set(payload, rec_index, policy);
        mlxsw_reg_sfd_uc_lag_sub_port_set(payload, rec_index, 0);
        mlxsw_reg_sfd_uc_lag_fid_vid_set(payload, rec_index, fid_vid);
+       mlxsw_reg_sfd_uc_lag_set_vid_set(payload, rec_index, true);
        mlxsw_reg_sfd_uc_lag_lag_vid_set(payload, rec_index, lag_vid);
        mlxsw_reg_sfd_uc_lag_lag_id_set(payload, rec_index, lag_id);
 }
@@ -997,7 +1035,7 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u16 local_port,
  * to packet types used for flooding.
  */
 #define MLXSW_REG_SFGC_ID 0x2011
-#define MLXSW_REG_SFGC_LEN 0x10
+#define MLXSW_REG_SFGC_LEN 0x14
 
 MLXSW_REG_DEFINE(sfgc, MLXSW_REG_SFGC_ID, MLXSW_REG_SFGC_LEN);
 
@@ -1019,9 +1057,10 @@ enum mlxsw_reg_sfgc_type {
  */
 MLXSW_ITEM32(reg, sfgc, type, 0x00, 0, 4);
 
-enum mlxsw_reg_sfgc_bridge_type {
-       MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID = 0,
-       MLXSW_REG_SFGC_BRIDGE_TYPE_VFID = 1,
+/* bridge_type is used in SFGC and SFMR. */
+enum mlxsw_reg_bridge_type {
+       MLXSW_REG_BRIDGE_TYPE_0 = 0, /* Used for .1q FIDs. */
+       MLXSW_REG_BRIDGE_TYPE_1 = 1, /* Used for .1d FIDs. */
 };
 
 /* reg_sfgc_bridge_type
@@ -1054,12 +1093,6 @@ MLXSW_ITEM32(reg, sfgc, table_type, 0x04, 16, 3);
  */
 MLXSW_ITEM32(reg, sfgc, flood_table, 0x04, 0, 6);
 
-/* reg_sfgc_mid
- * The multicast ID for the swid. Not supported for Spectrum
- * Access: RW
- */
-MLXSW_ITEM32(reg, sfgc, mid, 0x08, 0, 16);
-
 /* reg_sfgc_counter_set_type
  * Counter Set Type for flow counters.
  * Access: RW
@@ -1072,18 +1105,26 @@ MLXSW_ITEM32(reg, sfgc, counter_set_type, 0x0C, 24, 8);
  */
 MLXSW_ITEM32(reg, sfgc, counter_index, 0x0C, 0, 24);
 
+/* reg_sfgc_mid_base
+ * MID Base.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32(reg, sfgc, mid_base, 0x10, 0, 16);
+
 static inline void
 mlxsw_reg_sfgc_pack(char *payload, enum mlxsw_reg_sfgc_type type,
-                   enum mlxsw_reg_sfgc_bridge_type bridge_type,
+                   enum mlxsw_reg_bridge_type bridge_type,
                    enum mlxsw_flood_table_type table_type,
-                   unsigned int flood_table)
+                   unsigned int flood_table, u16 mid_base)
 {
        MLXSW_REG_ZERO(sfgc, payload);
        mlxsw_reg_sfgc_type_set(payload, type);
        mlxsw_reg_sfgc_bridge_type_set(payload, bridge_type);
        mlxsw_reg_sfgc_table_type_set(payload, table_type);
        mlxsw_reg_sfgc_flood_table_set(payload, flood_table);
-       mlxsw_reg_sfgc_mid_set(payload, MLXSW_PORT_MID);
+       mlxsw_reg_sfgc_mid_base_set(payload, mid_base);
 }
 
 /* SFDF - Switch Filtering DB Flush
@@ -1516,7 +1557,7 @@ static inline void mlxsw_reg_spmlr_pack(char *payload, u16 local_port,
  * virtualized ports.
  */
 #define MLXSW_REG_SVFA_ID 0x201C
-#define MLXSW_REG_SVFA_LEN 0x10
+#define MLXSW_REG_SVFA_LEN 0x18
 
 MLXSW_REG_DEFINE(svfa, MLXSW_REG_SVFA_ID, MLXSW_REG_SVFA_LEN);
 
@@ -1537,6 +1578,7 @@ MLXSW_ITEM32_LP(reg, svfa, 0x00, 16, 0x00, 12);
 enum mlxsw_reg_svfa_mt {
        MLXSW_REG_SVFA_MT_VID_TO_FID,
        MLXSW_REG_SVFA_MT_PORT_VID_TO_FID,
+       MLXSW_REG_SVFA_MT_VNI_TO_FID,
 };
 
 /* reg_svfa_mapping_table
@@ -1586,20 +1628,76 @@ MLXSW_ITEM32(reg, svfa, counter_set_type, 0x08, 24, 8);
  */
 MLXSW_ITEM32(reg, svfa, counter_index, 0x08, 0, 24);
 
-static inline void mlxsw_reg_svfa_pack(char *payload, u16 local_port,
-                                      enum mlxsw_reg_svfa_mt mt, bool valid,
-                                      u16 fid, u16 vid)
+/* reg_svfa_vni
+ * Virtual Network Identifier.
+ * Access: Index
+ *
+ * Note: Reserved when mapping_table is not 2 (VNI mapping table).
+ */
+MLXSW_ITEM32(reg, svfa, vni, 0x10, 0, 24);
+
+/* reg_svfa_irif_v
+ * Ingress RIF valid.
+ * 0 - Ingress RIF is not valid, no ingress RIF assigned.
+ * 1 - Ingress RIF valid.
+ * Must not be set for a non enabled RIF.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32(reg, svfa, irif_v, 0x14, 24, 1);
+
+/* reg_svfa_irif
+ * Ingress RIF (Router Interface).
+ * Range is 0..cap_max_router_interfaces-1.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and when irif_v=0.
+ */
+MLXSW_ITEM32(reg, svfa, irif, 0x14, 0, 16);
+
+static inline void __mlxsw_reg_svfa_pack(char *payload,
+                                        enum mlxsw_reg_svfa_mt mt, bool valid,
+                                        u16 fid, bool irif_v, u16 irif)
 {
        MLXSW_REG_ZERO(svfa, payload);
-       local_port = mt == MLXSW_REG_SVFA_MT_VID_TO_FID ? 0 : local_port;
        mlxsw_reg_svfa_swid_set(payload, 0);
-       mlxsw_reg_svfa_local_port_set(payload, local_port);
        mlxsw_reg_svfa_mapping_table_set(payload, mt);
        mlxsw_reg_svfa_v_set(payload, valid);
        mlxsw_reg_svfa_fid_set(payload, fid);
+       mlxsw_reg_svfa_irif_v_set(payload, irif_v);
+       mlxsw_reg_svfa_irif_set(payload, irif_v ? irif : 0);
+}
+
+static inline void mlxsw_reg_svfa_port_vid_pack(char *payload, u16 local_port,
+                                               bool valid, u16 fid, u16 vid,
+                                               bool irif_v, u16 irif)
+{
+       enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
+
+       __mlxsw_reg_svfa_pack(payload, mt, valid, fid, irif_v, irif);
+       mlxsw_reg_svfa_local_port_set(payload, local_port);
        mlxsw_reg_svfa_vid_set(payload, vid);
 }
 
+static inline void mlxsw_reg_svfa_vid_pack(char *payload, bool valid, u16 fid,
+                                          u16 vid, bool irif_v, u16 irif)
+{
+       enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
+
+       __mlxsw_reg_svfa_pack(payload, mt, valid, fid, irif_v, irif);
+       mlxsw_reg_svfa_vid_set(payload, vid);
+}
+
+static inline void mlxsw_reg_svfa_vni_pack(char *payload, bool valid, u16 fid,
+                                          u32 vni, bool irif_v, u16 irif)
+{
+       enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VNI_TO_FID;
+
+       __mlxsw_reg_svfa_pack(payload, mt, valid, fid, irif_v, irif);
+       mlxsw_reg_svfa_vni_set(payload, vni);
+}
+
 /*  SPVTR - Switch Port VLAN Stacking Register
  *  ------------------------------------------
  *  The Switch Port VLAN Stacking register configures the VLAN mode of the port
@@ -1741,7 +1839,7 @@ static inline void mlxsw_reg_svpe_pack(char *payload, u16 local_port,
  * Creates and configures FIDs.
  */
 #define MLXSW_REG_SFMR_ID 0x201F
-#define MLXSW_REG_SFMR_LEN 0x18
+#define MLXSW_REG_SFMR_LEN 0x30
 
 MLXSW_REG_DEFINE(sfmr, MLXSW_REG_SFMR_ID, MLXSW_REG_SFMR_LEN);
 
@@ -1764,6 +1862,28 @@ MLXSW_ITEM32(reg, sfmr, op, 0x00, 24, 4);
  */
 MLXSW_ITEM32(reg, sfmr, fid, 0x00, 0, 16);
 
+/* reg_sfmr_flood_rsp
+ * Router sub-port flooding table.
+ * 0 - Regular flooding table.
+ * 1 - Router sub-port flooding table. For this FID the flooding is per
+ * router-sub-port local_port. Must not be set for a FID which is not a
+ * router-sub-port and must be set prior to enabling the relevant RIF.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32(reg, sfmr, flood_rsp, 0x08, 31, 1);
+
+/* reg_sfmr_flood_bridge_type
+ * Flood bridge type (see SFGC.bridge_type).
+ * 0 - type_0.
+ * 1 - type_1.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and when flood_rsp=1.
+ */
+MLXSW_ITEM32(reg, sfmr, flood_bridge_type, 0x08, 28, 1);
+
 /* reg_sfmr_fid_offset
  * FID offset.
  * Used to point into the flooding table selected by SFGC register if
@@ -1800,15 +1920,57 @@ MLXSW_ITEM32(reg, sfmr, vv, 0x10, 31, 1);
 
 /* reg_sfmr_vni
  * Virtual Network Identifier.
+ * When legacy bridge model is used, a given VNI can only be assigned to one
+ * FID. When unified bridge model is used, it configures only the FID->VNI,
+ * the VNI->FID is done by SVFA.
  * Access: RW
- *
- * Note: A given VNI can only be assigned to one FID.
  */
 MLXSW_ITEM32(reg, sfmr, vni, 0x10, 0, 24);
 
+/* reg_sfmr_irif_v
+ * Ingress RIF valid.
+ * 0 - Ingress RIF is not valid, no ingress RIF assigned.
+ * 1 - Ingress RIF valid.
+ * Must not be set for a non valid RIF.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32(reg, sfmr, irif_v, 0x14, 24, 1);
+
+/* reg_sfmr_irif
+ * Ingress RIF (Router Interface).
+ * Range is 0..cap_max_router_interfaces-1.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and when irif_v=0.
+ */
+MLXSW_ITEM32(reg, sfmr, irif, 0x14, 0, 16);
+
+/* reg_sfmr_smpe_valid
+ * SMPE is valid.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used, when flood_rsp=1 and on
+ * Spectrum-1.
+ */
+MLXSW_ITEM32(reg, sfmr, smpe_valid, 0x28, 20, 1);
+
+/* reg_sfmr_smpe
+ * Switch multicast port to egress VID.
+ * Range is 0..cap_max_rmpe-1
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used, when flood_rsp=1 and on
+ * Spectrum-1.
+ */
+MLXSW_ITEM32(reg, sfmr, smpe, 0x28, 0, 16);
+
 static inline void mlxsw_reg_sfmr_pack(char *payload,
                                       enum mlxsw_reg_sfmr_op op, u16 fid,
-                                      u16 fid_offset)
+                                      u16 fid_offset, bool flood_rsp,
+                                      enum mlxsw_reg_bridge_type bridge_type,
+                                      bool smpe_valid, u16 smpe)
 {
        MLXSW_REG_ZERO(sfmr, payload);
        mlxsw_reg_sfmr_op_set(payload, op);
@@ -1816,6 +1978,10 @@ static inline void mlxsw_reg_sfmr_pack(char *payload,
        mlxsw_reg_sfmr_fid_offset_set(payload, fid_offset);
        mlxsw_reg_sfmr_vtfp_set(payload, false);
        mlxsw_reg_sfmr_vv_set(payload, false);
+       mlxsw_reg_sfmr_flood_rsp_set(payload, flood_rsp);
+       mlxsw_reg_sfmr_flood_bridge_type_set(payload, bridge_type);
+       mlxsw_reg_sfmr_smpe_valid_set(payload, smpe_valid);
+       mlxsw_reg_sfmr_smpe_set(payload, smpe);
 }
 
 /* SPVMLR - Switch Port VLAN MAC Learning Register
@@ -2013,6 +2179,45 @@ static inline void mlxsw_reg_spevet_pack(char *payload, u16 local_port,
        mlxsw_reg_spevet_et_vlan_set(payload, et_vlan);
 }
 
+/* SMPE - Switch Multicast Port to Egress VID
+ * ------------------------------------------
+ * The switch multicast port to egress VID maps
+ * {egress_port, SMPE index} -> {VID}.
+ */
+#define MLXSW_REG_SMPE_ID 0x202B
+#define MLXSW_REG_SMPE_LEN 0x0C
+
+MLXSW_REG_DEFINE(smpe, MLXSW_REG_SMPE_ID, MLXSW_REG_SMPE_LEN);
+
+/* reg_smpe_local_port
+ * Local port number.
+ * CPU port is not supported.
+ * Access: Index
+ */
+MLXSW_ITEM32_LP(reg, smpe, 0x00, 16, 0x00, 12);
+
+/* reg_smpe_smpe_index
+ * Switch multicast port to egress VID.
+ * Range is 0..cap_max_rmpe-1.
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, smpe, smpe_index, 0x04, 0, 16);
+
+/* reg_smpe_evid
+ * Egress VID.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, smpe, evid, 0x08, 0, 12);
+
+static inline void mlxsw_reg_smpe_pack(char *payload, u16 local_port,
+                                      u16 smpe_index, u16 evid)
+{
+       MLXSW_REG_ZERO(smpe, payload);
+       mlxsw_reg_smpe_local_port_set(payload, local_port);
+       mlxsw_reg_smpe_smpe_index_set(payload, smpe_index);
+       mlxsw_reg_smpe_evid_set(payload, evid);
+}
+
 /* SFTR-V2 - Switch Flooding Table Version 2 Register
  * --------------------------------------------------
  * The switch flooding table is used for flooding packet replication. The table
@@ -2107,6 +2312,23 @@ MLXSW_ITEM32(reg, smid2, swid, 0x00, 24, 8);
  */
 MLXSW_ITEM32(reg, smid2, mid, 0x00, 0, 16);
 
+/* reg_smid2_smpe_valid
+ * SMPE is valid.
+ * When not valid, the egress VID will not be modified by the SMPE table.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and on Spectrum-2.
+ */
+MLXSW_ITEM32(reg, smid2, smpe_valid, 0x08, 20, 1);
+
+/* reg_smid2_smpe
+ * Switch multicast port to egress VID.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and on Spectrum-2.
+ */
+MLXSW_ITEM32(reg, smid2, smpe, 0x08, 0, 16);
+
 /* reg_smid2_port
  * Local port memebership (1 bit per port).
  * Access: RW
@@ -2120,13 +2342,15 @@ MLXSW_ITEM_BIT_ARRAY(reg, smid2, port, 0x20, 0x80, 1);
 MLXSW_ITEM_BIT_ARRAY(reg, smid2, port_mask, 0xA0, 0x80, 1);
 
 static inline void mlxsw_reg_smid2_pack(char *payload, u16 mid, u16 port,
-                                       bool set)
+                                       bool set, bool smpe_valid, u16 smpe)
 {
        MLXSW_REG_ZERO(smid2, payload);
        mlxsw_reg_smid2_swid_set(payload, 0);
        mlxsw_reg_smid2_mid_set(payload, mid);
        mlxsw_reg_smid2_port_set(payload, port, set);
        mlxsw_reg_smid2_port_mask_set(payload, port, 1);
+       mlxsw_reg_smid2_smpe_valid_set(payload, smpe_valid);
+       mlxsw_reg_smid2_smpe_set(payload, smpe_valid ? smpe : 0);
 }
 
 /* CWTP - Congetion WRED ECN TClass Profile
@@ -6701,31 +6925,32 @@ MLXSW_ITEM32(reg, ritr, if_vrrp_id_ipv4, 0x1C, 0, 8);
 
 /* VLAN Interface */
 
-/* reg_ritr_vlan_if_vid
+/* reg_ritr_vlan_if_vlan_id
  * VLAN ID.
  * Access: RW
  */
-MLXSW_ITEM32(reg, ritr, vlan_if_vid, 0x08, 0, 12);
+MLXSW_ITEM32(reg, ritr, vlan_if_vlan_id, 0x08, 0, 12);
+
+/* reg_ritr_vlan_if_efid
+ * Egress FID.
+ * Used to connect the RIF to a bridge.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used and on Spectrum-1.
+ */
+MLXSW_ITEM32(reg, ritr, vlan_if_efid, 0x0C, 0, 16);
 
 /* FID Interface */
 
 /* reg_ritr_fid_if_fid
- * Filtering ID. Used to connect a bridge to the router. Only FIDs from
- * the vFID range are supported.
+ * Filtering ID. Used to connect a bridge to the router.
+ * When legacy bridge model is used, only FIDs from the vFID range are
+ * supported. When unified bridge model is used, this is the egress FID for
+ * router to bridge.
  * Access: RW
  */
 MLXSW_ITEM32(reg, ritr, fid_if_fid, 0x08, 0, 16);
 
-static inline void mlxsw_reg_ritr_fid_set(char *payload,
-                                         enum mlxsw_reg_ritr_if_type rif_type,
-                                         u16 fid)
-{
-       if (rif_type == MLXSW_REG_RITR_FID_IF)
-               mlxsw_reg_ritr_fid_if_fid_set(payload, fid);
-       else
-               mlxsw_reg_ritr_vlan_if_vid_set(payload, fid);
-}
-
 /* Sub-port Interface */
 
 /* reg_ritr_sp_if_lag
@@ -6742,6 +6967,16 @@ MLXSW_ITEM32(reg, ritr, sp_if_lag, 0x08, 24, 1);
  */
 MLXSW_ITEM32(reg, ritr, sp_if_system_port, 0x08, 0, 16);
 
+/* reg_ritr_sp_if_efid
+ * Egress filtering ID.
+ * Used to connect the eRIF to a bridge if eRIF-ACL has modified the DMAC or
+ * the VID.
+ * Access: RW
+ *
+ * Note: Reserved when legacy bridge model is used.
+ */
+MLXSW_ITEM32(reg, ritr, sp_if_efid, 0x0C, 0, 16);
+
 /* reg_ritr_sp_if_vid
  * VLAN ID.
  * Access: RW
@@ -6881,10 +7116,11 @@ static inline void mlxsw_reg_ritr_rif_pack(char *payload, u16 rif)
 }
 
 static inline void mlxsw_reg_ritr_sp_if_pack(char *payload, bool lag,
-                                            u16 system_port, u16 vid)
+                                            u16 system_port, u16 efid, u16 vid)
 {
        mlxsw_reg_ritr_sp_if_lag_set(payload, lag);
        mlxsw_reg_ritr_sp_if_system_port_set(payload, system_port);
+       mlxsw_reg_ritr_sp_if_efid_set(payload, efid);
        mlxsw_reg_ritr_sp_if_vid_set(payload, vid);
 }
 
@@ -6918,6 +7154,20 @@ static inline void mlxsw_reg_ritr_mac_pack(char *payload, const char *mac)
 }
 
 static inline void
+mlxsw_reg_ritr_vlan_if_pack(char *payload, bool enable, u16 rif, u16 vr_id,
+                           u16 mtu, const char *mac, u8 mac_profile_id,
+                           u16 vlan_id, u16 efid)
+{
+       enum mlxsw_reg_ritr_if_type type = MLXSW_REG_RITR_VLAN_IF;
+
+       mlxsw_reg_ritr_pack(payload, enable, type, rif, vr_id, mtu);
+       mlxsw_reg_ritr_if_mac_memcpy_to(payload, mac);
+       mlxsw_reg_ritr_if_mac_profile_id_set(payload, mac_profile_id);
+       mlxsw_reg_ritr_vlan_if_vlan_id_set(payload, vlan_id);
+       mlxsw_reg_ritr_vlan_if_efid_set(payload, efid);
+}
+
+static inline void
 mlxsw_reg_ritr_loopback_ipip_common_pack(char *payload,
                            enum mlxsw_reg_ritr_loopback_ipip_type ipip_type,
                            enum mlxsw_reg_ritr_loopback_ipip_options options,
@@ -7848,11 +8098,10 @@ static inline void mlxsw_reg_ralue_pack4(char *payload,
                                         enum mlxsw_reg_ralxx_protocol protocol,
                                         enum mlxsw_reg_ralue_op op,
                                         u16 virtual_router, u8 prefix_len,
-                                        u32 *dip)
+                                        u32 dip)
 {
        mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len);
-       if (dip)
-               mlxsw_reg_ralue_dip4_set(payload, *dip);
+       mlxsw_reg_ralue_dip4_set(payload, dip);
 }
 
 static inline void mlxsw_reg_ralue_pack6(char *payload,
@@ -7862,8 +8111,7 @@ static inline void mlxsw_reg_ralue_pack6(char *payload,
                                         const void *dip)
 {
        mlxsw_reg_ralue_pack(payload, protocol, op, virtual_router, prefix_len);
-       if (dip)
-               mlxsw_reg_ralue_dip6_memcpy_to(payload, dip);
+       mlxsw_reg_ralue_dip6_memcpy_to(payload, dip);
 }
 
 static inline void
@@ -8926,656 +9174,62 @@ mlxsw_reg_rmft2_ipv6_pack(char *payload, bool v, u16 offset, u16 virtual_router,
        mlxsw_reg_rmft2_sip6_mask_memcpy_to(payload, (void *)&sip6_mask);
 }
 
-/* RXLTE - Router XLT Enable Register
- * ----------------------------------
- * The RXLTE enables XLT (eXtended Lookup Table) LPM lookups if a capable
- * XM is present on the system.
- */
-
-#define MLXSW_REG_RXLTE_ID 0x8050
-#define MLXSW_REG_RXLTE_LEN 0x0C
-
-MLXSW_REG_DEFINE(rxlte, MLXSW_REG_RXLTE_ID, MLXSW_REG_RXLTE_LEN);
-
-/* reg_rxlte_virtual_router
- * Virtual router ID associated with the router interface.
- * Range is 0..cap_max_virtual_routers-1
- * Access: Index
- */
-MLXSW_ITEM32(reg, rxlte, virtual_router, 0x00, 0, 16);
-
-enum mlxsw_reg_rxlte_protocol {
-       MLXSW_REG_RXLTE_PROTOCOL_IPV4,
-       MLXSW_REG_RXLTE_PROTOCOL_IPV6,
-};
-
-/* reg_rxlte_protocol
- * Access: Index
- */
-MLXSW_ITEM32(reg, rxlte, protocol, 0x04, 0, 4);
-
-/* reg_rxlte_lpm_xlt_en
- * Access: RW
- */
-MLXSW_ITEM32(reg, rxlte, lpm_xlt_en, 0x08, 0, 1);
-
-static inline void mlxsw_reg_rxlte_pack(char *payload, u16 virtual_router,
-                                       enum mlxsw_reg_rxlte_protocol protocol,
-                                       bool lpm_xlt_en)
-{
-       MLXSW_REG_ZERO(rxlte, payload);
-       mlxsw_reg_rxlte_virtual_router_set(payload, virtual_router);
-       mlxsw_reg_rxlte_protocol_set(payload, protocol);
-       mlxsw_reg_rxlte_lpm_xlt_en_set(payload, lpm_xlt_en);
-}
-
-/* RXLTM - Router XLT M select Register
- * ------------------------------------
- * The RXLTM configures and selects the M for the XM lookups.
- */
-
-#define MLXSW_REG_RXLTM_ID 0x8051
-#define MLXSW_REG_RXLTM_LEN 0x14
-
-MLXSW_REG_DEFINE(rxltm, MLXSW_REG_RXLTM_ID, MLXSW_REG_RXLTM_LEN);
-
-/* reg_rxltm_m0_val_v6
- * Global M0 value For IPv6.
- * Range 0..128
- * Access: RW
- */
-MLXSW_ITEM32(reg, rxltm, m0_val_v6, 0x10, 16, 8);
-
-/* reg_rxltm_m0_val_v4
- * Global M0 value For IPv4.
- * Range 0..32
- * Access: RW
- */
-MLXSW_ITEM32(reg, rxltm, m0_val_v4, 0x10, 0, 6);
-
-static inline void mlxsw_reg_rxltm_pack(char *payload, u8 m0_val_v4, u8 m0_val_v6)
-{
-       MLXSW_REG_ZERO(rxltm, payload);
-       mlxsw_reg_rxltm_m0_val_v6_set(payload, m0_val_v6);
-       mlxsw_reg_rxltm_m0_val_v4_set(payload, m0_val_v4);
-}
-
-/* RLCMLD - Router LPM Cache ML Delete Register
- * --------------------------------------------
- * The RLCMLD register is used to bulk delete the XLT-LPM cache ML entries.
- * This can be used by SW when L is increased or decreased, thus need to
- * remove entries with old ML values.
- */
-
-#define MLXSW_REG_RLCMLD_ID 0x8055
-#define MLXSW_REG_RLCMLD_LEN 0x30
-
-MLXSW_REG_DEFINE(rlcmld, MLXSW_REG_RLCMLD_ID, MLXSW_REG_RLCMLD_LEN);
-
-enum mlxsw_reg_rlcmld_select {
-       MLXSW_REG_RLCMLD_SELECT_ML_ENTRIES,
-       MLXSW_REG_RLCMLD_SELECT_M_ENTRIES,
-       MLXSW_REG_RLCMLD_SELECT_M_AND_ML_ENTRIES,
-};
-
-/* reg_rlcmld_select
- * Which entries to delete.
- * Access: Index
- */
-MLXSW_ITEM32(reg, rlcmld, select, 0x00, 16, 2);
-
-enum mlxsw_reg_rlcmld_filter_fields {
-       MLXSW_REG_RLCMLD_FILTER_FIELDS_BY_PROTOCOL = 0x04,
-       MLXSW_REG_RLCMLD_FILTER_FIELDS_BY_VIRTUAL_ROUTER = 0x08,
-       MLXSW_REG_RLCMLD_FILTER_FIELDS_BY_DIP = 0x10,
-};
-
-/* reg_rlcmld_filter_fields
- * If a bit is '0' then the relevant field is ignored.
- * Access: Index
+/* REIV - Router Egress Interface to VID Register
+ * ----------------------------------------------
+ * The REIV register maps {eRIF, egress_port} -> VID.
+ * This mapping is done at the egress, after the ACLs.
+ * This mapping always takes effect after router, regardless of cast
+ * (for unicast/multicast/port-base multicast), regardless of eRIF type and
+ * regardless of bridge decisions (e.g. SFD for unicast or SMPE).
+ * Reserved when the RIF is a loopback RIF.
+ *
+ * Note: Reserved when legacy bridge model is used.
  */
-MLXSW_ITEM32(reg, rlcmld, filter_fields, 0x00, 0, 8);
+#define MLXSW_REG_REIV_ID 0x8034
+#define MLXSW_REG_REIV_BASE_LEN 0x20 /* base length, without records */
+#define MLXSW_REG_REIV_REC_LEN 0x04 /* record length */
+#define MLXSW_REG_REIV_REC_MAX_COUNT 256 /* firmware limitation */
+#define MLXSW_REG_REIV_LEN (MLXSW_REG_REIV_BASE_LEN +  \
+                           MLXSW_REG_REIV_REC_LEN *    \
+                           MLXSW_REG_REIV_REC_MAX_COUNT)
 
-enum mlxsw_reg_rlcmld_protocol {
-       MLXSW_REG_RLCMLD_PROTOCOL_UC_IPV4,
-       MLXSW_REG_RLCMLD_PROTOCOL_UC_IPV6,
-};
-
-/* reg_rlcmld_protocol
- * Access: Index
- */
-MLXSW_ITEM32(reg, rlcmld, protocol, 0x08, 0, 4);
+MLXSW_REG_DEFINE(reiv, MLXSW_REG_REIV_ID, MLXSW_REG_REIV_LEN);
 
-/* reg_rlcmld_virtual_router
- * Virtual router ID.
- * Range is 0..cap_max_virtual_routers-1
+/* reg_reiv_port_page
+ * Port page - elport_record[0] is 256*port_page.
  * Access: Index
  */
-MLXSW_ITEM32(reg, rlcmld, virtual_router, 0x0C, 0, 16);
+MLXSW_ITEM32(reg, reiv, port_page, 0x00, 0, 4);
 
-/* reg_rlcmld_dip
- * The prefix of the route or of the marker that the object of the LPM
- * is compared with. The most significant bits of the dip are the prefix.
+/* reg_reiv_erif
+ * Egress RIF.
+ * Range is 0..cap_max_router_interfaces-1.
  * Access: Index
  */
-MLXSW_ITEM32(reg, rlcmld, dip4, 0x1C, 0, 32);
-MLXSW_ITEM_BUF(reg, rlcmld, dip6, 0x10, 16);
-
-/* reg_rlcmld_dip_mask
- * per bit:
- * 0: no match
- * 1: match
- * Access: Index
- */
-MLXSW_ITEM32(reg, rlcmld, dip_mask4, 0x2C, 0, 32);
-MLXSW_ITEM_BUF(reg, rlcmld, dip_mask6, 0x20, 16);
-
-static inline void __mlxsw_reg_rlcmld_pack(char *payload,
-                                          enum mlxsw_reg_rlcmld_select select,
-                                          enum mlxsw_reg_rlcmld_protocol protocol,
-                                          u16 virtual_router)
-{
-       u8 filter_fields = MLXSW_REG_RLCMLD_FILTER_FIELDS_BY_PROTOCOL |
-                          MLXSW_REG_RLCMLD_FILTER_FIELDS_BY_VIRTUAL_ROUTER |
-                          MLXSW_REG_RLCMLD_FILTER_FIELDS_BY_DIP;
-
-       MLXSW_REG_ZERO(rlcmld, payload);
-       mlxsw_reg_rlcmld_select_set(payload, select);
-       mlxsw_reg_rlcmld_filter_fields_set(payload, filter_fields);
-       mlxsw_reg_rlcmld_protocol_set(payload, protocol);
-       mlxsw_reg_rlcmld_virtual_router_set(payload, virtual_router);
-}
-
-static inline void mlxsw_reg_rlcmld_pack4(char *payload,
-                                         enum mlxsw_reg_rlcmld_select select,
-                                         u16 virtual_router,
-                                         u32 dip, u32 dip_mask)
-{
-       __mlxsw_reg_rlcmld_pack(payload, select,
-                               MLXSW_REG_RLCMLD_PROTOCOL_UC_IPV4,
-                               virtual_router);
-       mlxsw_reg_rlcmld_dip4_set(payload, dip);
-       mlxsw_reg_rlcmld_dip_mask4_set(payload, dip_mask);
-}
-
-static inline void mlxsw_reg_rlcmld_pack6(char *payload,
-                                         enum mlxsw_reg_rlcmld_select select,
-                                         u16 virtual_router,
-                                         const void *dip, const void *dip_mask)
-{
-       __mlxsw_reg_rlcmld_pack(payload, select,
-                               MLXSW_REG_RLCMLD_PROTOCOL_UC_IPV6,
-                               virtual_router);
-       mlxsw_reg_rlcmld_dip6_memcpy_to(payload, dip);
-       mlxsw_reg_rlcmld_dip_mask6_memcpy_to(payload, dip_mask);
-}
+MLXSW_ITEM32(reg, reiv, erif, 0x04, 0, 16);
 
-/* RLPMCE - Router LPM Cache Enable Register
- * -----------------------------------------
- * Allows disabling the LPM cache. Can be changed on the fly.
- */
-
-#define MLXSW_REG_RLPMCE_ID 0x8056
-#define MLXSW_REG_RLPMCE_LEN 0x4
-
-MLXSW_REG_DEFINE(rlpmce, MLXSW_REG_RLPMCE_ID, MLXSW_REG_RLPMCE_LEN);
-
-/* reg_rlpmce_flush
- * Flush:
- * 0: do not flush the cache (default)
- * 1: flush (clear) the cache
- * Access: WO
- */
-MLXSW_ITEM32(reg, rlpmce, flush, 0x00, 4, 1);
-
-/* reg_rlpmce_disable
- * LPM cache:
- * 0: enabled (default)
- * 1: disabled
- * Access: RW
- */
-MLXSW_ITEM32(reg, rlpmce, disable, 0x00, 0, 1);
-
-static inline void mlxsw_reg_rlpmce_pack(char *payload, bool flush,
-                                        bool disable)
-{
-       MLXSW_REG_ZERO(rlpmce, payload);
-       mlxsw_reg_rlpmce_flush_set(payload, flush);
-       mlxsw_reg_rlpmce_disable_set(payload, disable);
-}
-
-/* Note that XLTQ, XMDR, XRMT and XRALXX register positions violate the rule
- * of ordering register definitions by the ID. However, XRALXX pack helpers are
- * using RALXX pack helpers, RALXX registers have higher IDs.
- * Also XMDR is using RALUE enums. XLRQ and XRMT are just put alongside with the
- * related registers.
- */
-
-/* XLTQ - XM Lookup Table Query Register
- * -------------------------------------
- */
-#define MLXSW_REG_XLTQ_ID 0x7802
-#define MLXSW_REG_XLTQ_LEN 0x2C
-
-MLXSW_REG_DEFINE(xltq, MLXSW_REG_XLTQ_ID, MLXSW_REG_XLTQ_LEN);
-
-enum mlxsw_reg_xltq_xm_device_id {
-       MLXSW_REG_XLTQ_XM_DEVICE_ID_UNKNOWN,
-       MLXSW_REG_XLTQ_XM_DEVICE_ID_XLT = 0xCF71,
-};
-
-/* reg_xltq_xm_device_id
- * XM device ID.
- * Access: RO
- */
-MLXSW_ITEM32(reg, xltq, xm_device_id, 0x04, 0, 16);
-
-/* reg_xltq_xlt_cap_ipv4_lpm
- * Access: RO
- */
-MLXSW_ITEM32(reg, xltq, xlt_cap_ipv4_lpm, 0x10, 0, 1);
-
-/* reg_xltq_xlt_cap_ipv6_lpm
- * Access: RO
- */
-MLXSW_ITEM32(reg, xltq, xlt_cap_ipv6_lpm, 0x10, 1, 1);
-
-/* reg_xltq_cap_xlt_entries
- * Number of XLT entries
- * Note: SW must not fill more than 80% in order to avoid overflow
- * Access: RO
- */
-MLXSW_ITEM32(reg, xltq, cap_xlt_entries, 0x20, 0, 32);
-
-/* reg_xltq_cap_xlt_mtable
- * XLT M-Table max size
- * Access: RO
- */
-MLXSW_ITEM32(reg, xltq, cap_xlt_mtable, 0x24, 0, 32);
-
-static inline void mlxsw_reg_xltq_pack(char *payload)
-{
-       MLXSW_REG_ZERO(xltq, payload);
-}
-
-static inline void mlxsw_reg_xltq_unpack(char *payload, u16 *xm_device_id, bool *xlt_cap_ipv4_lpm,
-                                        bool *xlt_cap_ipv6_lpm, u32 *cap_xlt_entries,
-                                        u32 *cap_xlt_mtable)
-{
-       *xm_device_id = mlxsw_reg_xltq_xm_device_id_get(payload);
-       *xlt_cap_ipv4_lpm = mlxsw_reg_xltq_xlt_cap_ipv4_lpm_get(payload);
-       *xlt_cap_ipv6_lpm = mlxsw_reg_xltq_xlt_cap_ipv6_lpm_get(payload);
-       *cap_xlt_entries = mlxsw_reg_xltq_cap_xlt_entries_get(payload);
-       *cap_xlt_mtable = mlxsw_reg_xltq_cap_xlt_mtable_get(payload);
-}
-
-/* XMDR - XM Direct Register
- * -------------------------
- * The XMDR allows direct access to the XM device via the switch.
- * Working in synchronous mode. FW waits for response from the XLT
- * for each command. FW acks the XMDR accordingly.
- */
-#define MLXSW_REG_XMDR_ID 0x7803
-#define MLXSW_REG_XMDR_BASE_LEN 0x20
-#define MLXSW_REG_XMDR_TRANS_LEN 0x80
-#define MLXSW_REG_XMDR_LEN (MLXSW_REG_XMDR_BASE_LEN + \
-                           MLXSW_REG_XMDR_TRANS_LEN)
-
-MLXSW_REG_DEFINE(xmdr, MLXSW_REG_XMDR_ID, MLXSW_REG_XMDR_LEN);
-
-/* reg_xmdr_bulk_entry
- * Bulk_entry
- * 0: Last entry - immediate flush of XRT-cache
- * 1: Bulk entry - do not flush the XRT-cache
- * Access: OP
- */
-MLXSW_ITEM32(reg, xmdr, bulk_entry, 0x04, 8, 1);
-
-/* reg_xmdr_num_rec
- * Number of records for Direct access to XM
- * Supported: 0..4 commands (except NOP which is a filler)
- * 0 commands is reserved when bulk_entry = 1.
- * 0 commands is allowed when bulk_entry = 0 for immediate XRT-cache flush.
+/* reg_reiv_rec_update
+ * Update enable (when write):
+ * 0 - Do not update the entry.
+ * 1 - Update the entry.
  * Access: OP
  */
-MLXSW_ITEM32(reg, xmdr, num_rec, 0x04, 0, 4);
-
-/* reg_xmdr_reply_vect
- * Reply Vector
- * Bit i for command index i+1
- * values per bit:
- * 0: failed
- * 1: succeeded
- * e.g. if commands 1, 2, 4 succeeded and command 3 failed then binary
- * value will be 0b1011
- * Access: RO
- */
-MLXSW_ITEM_BIT_ARRAY(reg, xmdr, reply_vect, 0x08, 4, 1);
-
-static inline void mlxsw_reg_xmdr_pack(char *payload, bool bulk_entry)
-{
-       MLXSW_REG_ZERO(xmdr, payload);
-       mlxsw_reg_xmdr_bulk_entry_set(payload, bulk_entry);
-}
-
-enum mlxsw_reg_xmdr_c_cmd_id {
-       MLXSW_REG_XMDR_C_CMD_ID_LT_ROUTE_V4 = 0x30,
-       MLXSW_REG_XMDR_C_CMD_ID_LT_ROUTE_V6 = 0x31,
-};
-
-#define MLXSW_REG_XMDR_C_LT_ROUTE_V4_LEN 32
-#define MLXSW_REG_XMDR_C_LT_ROUTE_V6_LEN 48
-
-/* reg_xmdr_c_cmd_id
- */
-MLXSW_ITEM32(reg, xmdr_c, cmd_id, 0x00, 24, 8);
-
-/* reg_xmdr_c_seq_number
- */
-MLXSW_ITEM32(reg, xmdr_c, seq_number, 0x00, 12, 12);
-
-enum mlxsw_reg_xmdr_c_ltr_op {
-       /* Activity is set */
-       MLXSW_REG_XMDR_C_LTR_OP_WRITE = 0,
-       /* There is no update mask. All fields are updated. */
-       MLXSW_REG_XMDR_C_LTR_OP_UPDATE = 1,
-       MLXSW_REG_XMDR_C_LTR_OP_DELETE = 2,
-};
-
-/* reg_xmdr_c_ltr_op
- * Operation.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_op, 0x04, 24, 8);
-
-/* reg_xmdr_c_ltr_trap_action
- * Trap action.
- * Values are defined in enum mlxsw_reg_ralue_trap_action.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_trap_action, 0x04, 20, 4);
-
-enum mlxsw_reg_xmdr_c_ltr_trap_id_num {
-       MLXSW_REG_XMDR_C_LTR_TRAP_ID_NUM_RTR_INGRESS0,
-       MLXSW_REG_XMDR_C_LTR_TRAP_ID_NUM_RTR_INGRESS1,
-       MLXSW_REG_XMDR_C_LTR_TRAP_ID_NUM_RTR_INGRESS2,
-       MLXSW_REG_XMDR_C_LTR_TRAP_ID_NUM_RTR_INGRESS3,
-};
-
-/* reg_xmdr_c_ltr_trap_id_num
- * Trap-ID number.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_trap_id_num, 0x04, 16, 4);
-
-/* reg_xmdr_c_ltr_virtual_router
- * Virtual Router ID.
- * Range is 0..cap_max_virtual_routers-1
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_virtual_router, 0x04, 0, 16);
-
-/* reg_xmdr_c_ltr_prefix_len
- * Number of bits in the prefix of the LPM route.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_prefix_len, 0x08, 24, 8);
-
-/* reg_xmdr_c_ltr_bmp_len
- * The best match prefix length in the case that there is no match for
- * longer prefixes.
- * If (entry_type != MARKER_ENTRY), bmp_len must be equal to prefix_len
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_bmp_len, 0x08, 16, 8);
-
-/* reg_xmdr_c_ltr_entry_type
- * Entry type.
- * Values are defined in enum mlxsw_reg_ralue_entry_type.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_entry_type, 0x08, 4, 4);
-
-enum mlxsw_reg_xmdr_c_ltr_action_type {
-       MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_LOCAL,
-       MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_REMOTE,
-       MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_IP2ME,
-};
-
-/* reg_xmdr_c_ltr_action_type
- * Action Type.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_action_type, 0x08, 0, 4);
-
-/* reg_xmdr_c_ltr_erif
- * Egress Router Interface.
- * Only relevant in case of LOCAL action.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_erif, 0x10, 0, 16);
+MLXSW_ITEM32_INDEXED(reg, reiv, rec_update, MLXSW_REG_REIV_BASE_LEN, 31, 1,
+                    MLXSW_REG_REIV_REC_LEN, 0x00, false);
 
-/* reg_xmdr_c_ltr_adjacency_index
- * Points to the first entry of the group-based ECMP.
- * Only relevant in case of REMOTE action.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_adjacency_index, 0x10, 0, 24);
-
-#define MLXSW_REG_XMDR_C_LTR_POINTER_TO_TUNNEL_DISABLED_MAGIC 0xFFFFFF
-
-/* reg_xmdr_c_ltr_pointer_to_tunnel
- * Only relevant in case of IP2ME action.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_pointer_to_tunnel, 0x10, 0, 24);
-
-/* reg_xmdr_c_ltr_ecmp_size
- * Amount of sequential entries starting
- * from the adjacency_index (the number of ECMPs).
- * The valid range is 1-64, 512, 1024, 2048 and 4096.
- * Only relevant in case of REMOTE action.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_ecmp_size, 0x14, 0, 32);
-
-/* reg_xmdr_c_ltr_dip*
- * The prefix of the route or of the marker that the object of the LPM
- * is compared with. The most significant bits of the dip are the prefix.
- * The least significant bits must be '0' if the prefix_len is smaller
- * than 128 for IPv6 or smaller than 32 for IPv4.
- */
-MLXSW_ITEM32(reg, xmdr_c, ltr_dip4, 0x1C, 0, 32);
-MLXSW_ITEM_BUF(reg, xmdr_c, ltr_dip6, 0x1C, 16);
-
-static inline void
-mlxsw_reg_xmdr_c_ltr_pack(char *xmdr_payload, unsigned int trans_offset,
-                         enum mlxsw_reg_xmdr_c_cmd_id cmd_id, u16 seq_number,
-                         enum mlxsw_reg_xmdr_c_ltr_op op, u16 virtual_router,
-                         u8 prefix_len)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-       u8 num_rec = mlxsw_reg_xmdr_num_rec_get(xmdr_payload);
-
-       mlxsw_reg_xmdr_num_rec_set(xmdr_payload, num_rec + 1);
-
-       mlxsw_reg_xmdr_c_cmd_id_set(payload, cmd_id);
-       mlxsw_reg_xmdr_c_seq_number_set(payload, seq_number);
-       mlxsw_reg_xmdr_c_ltr_op_set(payload, op);
-       mlxsw_reg_xmdr_c_ltr_virtual_router_set(payload, virtual_router);
-       mlxsw_reg_xmdr_c_ltr_prefix_len_set(payload, prefix_len);
-       mlxsw_reg_xmdr_c_ltr_entry_type_set(payload,
-                                           MLXSW_REG_RALUE_ENTRY_TYPE_ROUTE_ENTRY);
-       mlxsw_reg_xmdr_c_ltr_bmp_len_set(payload, prefix_len);
-}
-
-static inline unsigned int
-mlxsw_reg_xmdr_c_ltr_pack4(char *xmdr_payload, unsigned int trans_offset,
-                          u16 seq_number, enum mlxsw_reg_xmdr_c_ltr_op op,
-                          u16 virtual_router, u8 prefix_len, u32 *dip)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-
-       mlxsw_reg_xmdr_c_ltr_pack(xmdr_payload, trans_offset,
-                                 MLXSW_REG_XMDR_C_CMD_ID_LT_ROUTE_V4,
-                                 seq_number, op, virtual_router, prefix_len);
-       if (dip)
-               mlxsw_reg_xmdr_c_ltr_dip4_set(payload, *dip);
-       return MLXSW_REG_XMDR_C_LT_ROUTE_V4_LEN;
-}
-
-static inline unsigned int
-mlxsw_reg_xmdr_c_ltr_pack6(char *xmdr_payload, unsigned int trans_offset,
-                          u16 seq_number, enum mlxsw_reg_xmdr_c_ltr_op op,
-                          u16 virtual_router, u8 prefix_len, const void *dip)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-
-       mlxsw_reg_xmdr_c_ltr_pack(xmdr_payload, trans_offset,
-                                 MLXSW_REG_XMDR_C_CMD_ID_LT_ROUTE_V6,
-                                 seq_number, op, virtual_router, prefix_len);
-       if (dip)
-               mlxsw_reg_xmdr_c_ltr_dip6_memcpy_to(payload, dip);
-       return MLXSW_REG_XMDR_C_LT_ROUTE_V6_LEN;
-}
-
-static inline void
-mlxsw_reg_xmdr_c_ltr_act_remote_pack(char *xmdr_payload, unsigned int trans_offset,
-                                    enum mlxsw_reg_ralue_trap_action trap_action,
-                                    enum mlxsw_reg_xmdr_c_ltr_trap_id_num trap_id_num,
-                                    u32 adjacency_index, u16 ecmp_size)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-
-       mlxsw_reg_xmdr_c_ltr_action_type_set(payload, MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_REMOTE);
-       mlxsw_reg_xmdr_c_ltr_trap_action_set(payload, trap_action);
-       mlxsw_reg_xmdr_c_ltr_trap_id_num_set(payload, trap_id_num);
-       mlxsw_reg_xmdr_c_ltr_adjacency_index_set(payload, adjacency_index);
-       mlxsw_reg_xmdr_c_ltr_ecmp_size_set(payload, ecmp_size);
-}
-
-static inline void
-mlxsw_reg_xmdr_c_ltr_act_local_pack(char *xmdr_payload, unsigned int trans_offset,
-                                   enum mlxsw_reg_ralue_trap_action trap_action,
-                                   enum mlxsw_reg_xmdr_c_ltr_trap_id_num trap_id_num, u16 erif)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-
-       mlxsw_reg_xmdr_c_ltr_action_type_set(payload, MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_LOCAL);
-       mlxsw_reg_xmdr_c_ltr_trap_action_set(payload, trap_action);
-       mlxsw_reg_xmdr_c_ltr_trap_id_num_set(payload, trap_id_num);
-       mlxsw_reg_xmdr_c_ltr_erif_set(payload, erif);
-}
-
-static inline void mlxsw_reg_xmdr_c_ltr_act_ip2me_pack(char *xmdr_payload,
-                                                      unsigned int trans_offset)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-
-       mlxsw_reg_xmdr_c_ltr_action_type_set(payload, MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_IP2ME);
-       mlxsw_reg_xmdr_c_ltr_pointer_to_tunnel_set(payload,
-                                                  MLXSW_REG_XMDR_C_LTR_POINTER_TO_TUNNEL_DISABLED_MAGIC);
-}
-
-static inline void mlxsw_reg_xmdr_c_ltr_act_ip2me_tun_pack(char *xmdr_payload,
-                                                          unsigned int trans_offset,
-                                                          u32 pointer_to_tunnel)
-{
-       char *payload = xmdr_payload + MLXSW_REG_XMDR_BASE_LEN + trans_offset;
-
-       mlxsw_reg_xmdr_c_ltr_action_type_set(payload, MLXSW_REG_XMDR_C_LTR_ACTION_TYPE_IP2ME);
-       mlxsw_reg_xmdr_c_ltr_pointer_to_tunnel_set(payload, pointer_to_tunnel);
-}
-
-/* XRMT - XM Router M Table Register
- * ---------------------------------
- * The XRMT configures the M-Table for the XLT-LPM.
- */
-#define MLXSW_REG_XRMT_ID 0x7810
-#define MLXSW_REG_XRMT_LEN 0x14
-
-MLXSW_REG_DEFINE(xrmt, MLXSW_REG_XRMT_ID, MLXSW_REG_XRMT_LEN);
-
-/* reg_xrmt_index
- * Index in M-Table.
- * Range 0..cap_xlt_mtable-1
- * Access: Index
- */
-MLXSW_ITEM32(reg, xrmt, index, 0x04, 0, 20);
-
-/* reg_xrmt_l0_val
+/* reg_reiv_rec_evid
+ * Egress VID.
+ * Range is 0..4095.
  * Access: RW
  */
-MLXSW_ITEM32(reg, xrmt, l0_val, 0x10, 24, 8);
-
-static inline void mlxsw_reg_xrmt_pack(char *payload, u32 index, u8 l0_val)
-{
-       MLXSW_REG_ZERO(xrmt, payload);
-       mlxsw_reg_xrmt_index_set(payload, index);
-       mlxsw_reg_xrmt_l0_val_set(payload, l0_val);
-}
-
-/* XRALTA - XM Router Algorithmic LPM Tree Allocation Register
- * -----------------------------------------------------------
- * The XRALTA is used to allocate the XLT LPM trees.
- *
- * This register embeds original RALTA register.
- */
-#define MLXSW_REG_XRALTA_ID 0x7811
-#define MLXSW_REG_XRALTA_LEN 0x08
-#define MLXSW_REG_XRALTA_RALTA_OFFSET 0x04
+MLXSW_ITEM32_INDEXED(reg, reiv, rec_evid, MLXSW_REG_REIV_BASE_LEN, 0, 12,
+                    MLXSW_REG_REIV_REC_LEN, 0x00, false);
 
-MLXSW_REG_DEFINE(xralta, MLXSW_REG_XRALTA_ID, MLXSW_REG_XRALTA_LEN);
-
-static inline void mlxsw_reg_xralta_pack(char *payload, bool alloc,
-                                        enum mlxsw_reg_ralxx_protocol protocol,
-                                        u8 tree_id)
+static inline void mlxsw_reg_reiv_pack(char *payload, u8 port_page, u16 erif)
 {
-       char *ralta_payload = payload + MLXSW_REG_XRALTA_RALTA_OFFSET;
-
-       MLXSW_REG_ZERO(xralta, payload);
-       mlxsw_reg_ralta_pack(ralta_payload, alloc, protocol, tree_id);
-}
-
-/* XRALST - XM Router Algorithmic LPM Structure Tree Register
- * ----------------------------------------------------------
- * The XRALST is used to set and query the structure of an XLT LPM tree.
- *
- * This register embeds original RALST register.
- */
-#define MLXSW_REG_XRALST_ID 0x7812
-#define MLXSW_REG_XRALST_LEN 0x108
-#define MLXSW_REG_XRALST_RALST_OFFSET 0x04
-
-MLXSW_REG_DEFINE(xralst, MLXSW_REG_XRALST_ID, MLXSW_REG_XRALST_LEN);
-
-static inline void mlxsw_reg_xralst_pack(char *payload, u8 root_bin, u8 tree_id)
-{
-       char *ralst_payload = payload + MLXSW_REG_XRALST_RALST_OFFSET;
-
-       MLXSW_REG_ZERO(xralst, payload);
-       mlxsw_reg_ralst_pack(ralst_payload, root_bin, tree_id);
-}
-
-static inline void mlxsw_reg_xralst_bin_pack(char *payload, u8 bin_number,
-                                            u8 left_child_bin,
-                                            u8 right_child_bin)
-{
-       char *ralst_payload = payload + MLXSW_REG_XRALST_RALST_OFFSET;
-
-       mlxsw_reg_ralst_bin_pack(ralst_payload, bin_number, left_child_bin,
-                                right_child_bin);
-}
-
-/* XRALTB - XM Router Algorithmic LPM Tree Binding Register
- * --------------------------------------------------------
- * The XRALTB register is used to bind virtual router and protocol
- * to an allocated LPM tree.
- *
- * This register embeds original RALTB register.
- */
-#define MLXSW_REG_XRALTB_ID 0x7813
-#define MLXSW_REG_XRALTB_LEN 0x08
-#define MLXSW_REG_XRALTB_RALTB_OFFSET 0x04
-
-MLXSW_REG_DEFINE(xraltb, MLXSW_REG_XRALTB_ID, MLXSW_REG_XRALTB_LEN);
-
-static inline void mlxsw_reg_xraltb_pack(char *payload, u16 virtual_router,
-                                        enum mlxsw_reg_ralxx_protocol protocol,
-                                        u8 tree_id)
-{
-       char *raltb_payload = payload + MLXSW_REG_XRALTB_RALTB_OFFSET;
-
-       MLXSW_REG_ZERO(xraltb, payload);
-       mlxsw_reg_raltb_pack(raltb_payload, virtual_router, protocol, tree_id);
+       MLXSW_REG_ZERO(reiv, payload);
+       mlxsw_reg_reiv_port_page_set(payload, port_page);
+       mlxsw_reg_reiv_erif_set(payload, erif);
 }
 
 /* MFCR - Management Fan Control Register
@@ -13011,6 +12665,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
        MLXSW_REG(spvmlr),
        MLXSW_REG(spvc),
        MLXSW_REG(spevet),
+       MLXSW_REG(smpe),
        MLXSW_REG(sftr2),
        MLXSW_REG(smid2),
        MLXSW_REG(cwtp),
@@ -13084,16 +12739,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
        MLXSW_REG(rigr2),
        MLXSW_REG(recr2),
        MLXSW_REG(rmft2),
-       MLXSW_REG(rxlte),
-       MLXSW_REG(rxltm),
-       MLXSW_REG(rlcmld),
-       MLXSW_REG(rlpmce),
-       MLXSW_REG(xltq),
-       MLXSW_REG(xmdr),
-       MLXSW_REG(xrmt),
-       MLXSW_REG(xralta),
-       MLXSW_REG(xralst),
-       MLXSW_REG(xraltb),
+       MLXSW_REG(reiv),
        MLXSW_REG(mfcr),
        MLXSW_REG(mfsc),
        MLXSW_REG(mfsm),
index daacf62..826e47f 100644 (file)
@@ -11,6 +11,7 @@ enum mlxsw_res_id {
        MLXSW_RES_ID_KVD_SIZE,
        MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE,
        MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE,
+       MLXSW_RES_ID_PGT_SIZE,
        MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE,
        MLXSW_RES_ID_MAX_KVD_ACTION_SETS,
        MLXSW_RES_ID_MAX_TRAP_GROUPS,
@@ -69,6 +70,7 @@ static u16 mlxsw_res_ids[] = {
        [MLXSW_RES_ID_KVD_SIZE] = 0x1001,
        [MLXSW_RES_ID_KVD_SINGLE_MIN_SIZE] = 0x1002,
        [MLXSW_RES_ID_KVD_DOUBLE_MIN_SIZE] = 0x1003,
+       [MLXSW_RES_ID_PGT_SIZE] = 0x1004,
        [MLXSW_RES_ID_MAX_KVD_LINEAR_RANGE] = 0x1005,
        [MLXSW_RES_ID_MAX_KVD_ACTION_SETS] = 0x1007,
        [MLXSW_RES_ID_MAX_TRAP_GROUPS] = 0x2201,
index cafd206..a703ca2 100644 (file)
@@ -2105,9 +2105,6 @@ static int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp)
                return -ENOMEM;
 
        for (i = 1; i < max_ports; i++) {
-               if (mlxsw_core_port_is_xm(mlxsw_sp->core, i))
-                       continue;
-
                port_mapping = &mlxsw_sp->port_mapping[i];
                err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, port_mapping);
                if (err)
@@ -3013,6 +3010,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
                return err;
        }
 
+       err = mlxsw_sp_pgt_init(mlxsw_sp);
+       if (err) {
+               dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize PGT\n");
+               goto err_pgt_init;
+       }
+
        err = mlxsw_sp_fids_init(mlxsw_sp);
        if (err) {
                dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");
@@ -3204,6 +3207,8 @@ err_traps_init:
 err_policers_init:
        mlxsw_sp_fids_fini(mlxsw_sp);
 err_fids_init:
+       mlxsw_sp_pgt_fini(mlxsw_sp);
+err_pgt_init:
        mlxsw_sp_kvdl_fini(mlxsw_sp);
        mlxsw_sp_parsing_fini(mlxsw_sp);
        return err;
@@ -3235,7 +3240,9 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
        mlxsw_sp->router_ops = &mlxsw_sp1_router_ops;
        mlxsw_sp->listeners = mlxsw_sp1_listener;
        mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener);
+       mlxsw_sp->fid_family_arr = mlxsw_sp1_fid_family_arr;
        mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1;
+       mlxsw_sp->pgt_smpe_index_valid = true;
 
        return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
 }
@@ -3267,7 +3274,9 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
        mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;
        mlxsw_sp->listeners = mlxsw_sp2_listener;
        mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);
+       mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr;
        mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2;
+       mlxsw_sp->pgt_smpe_index_valid = false;
 
        return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
 }
@@ -3299,7 +3308,9 @@ static int mlxsw_sp3_init(struct mlxsw_core *mlxsw_core,
        mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;
        mlxsw_sp->listeners = mlxsw_sp2_listener;
        mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);
+       mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr;
        mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;
+       mlxsw_sp->pgt_smpe_index_valid = false;
 
        return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
 }
@@ -3331,7 +3342,9 @@ static int mlxsw_sp4_init(struct mlxsw_core *mlxsw_core,
        mlxsw_sp->router_ops = &mlxsw_sp2_router_ops;
        mlxsw_sp->listeners = mlxsw_sp2_listener;
        mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp2_listener);
+       mlxsw_sp->fid_family_arr = mlxsw_sp2_fid_family_arr;
        mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4;
+       mlxsw_sp->pgt_smpe_index_valid = false;
 
        return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack);
 }
@@ -3364,28 +3377,20 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
        mlxsw_sp_traps_fini(mlxsw_sp);
        mlxsw_sp_policers_fini(mlxsw_sp);
        mlxsw_sp_fids_fini(mlxsw_sp);
+       mlxsw_sp_pgt_fini(mlxsw_sp);
        mlxsw_sp_kvdl_fini(mlxsw_sp);
        mlxsw_sp_parsing_fini(mlxsw_sp);
 }
 
-/* Per-FID flood tables are used for both "true" 802.1D FIDs and emulated
- * 802.1Q FIDs
- */
-#define MLXSW_SP_FID_FLOOD_TABLE_SIZE  (MLXSW_SP_FID_8021D_MAX + \
-                                        VLAN_VID_MASK - 1)
-
 static const struct mlxsw_config_profile mlxsw_sp1_config_profile = {
-       .used_max_mid                   = 1,
-       .max_mid                        = MLXSW_SP_MID_MAX,
-       .used_flood_tables              = 1,
-       .used_flood_mode                = 1,
-       .flood_mode                     = 3,
-       .max_fid_flood_tables           = 3,
-       .fid_flood_table_size           = MLXSW_SP_FID_FLOOD_TABLE_SIZE,
+       .used_flood_mode                = 1,
+       .flood_mode                     = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,
        .used_max_ib_mc                 = 1,
        .max_ib_mc                      = 0,
        .used_max_pkey                  = 1,
        .max_pkey                       = 0,
+       .used_ubridge                   = 1,
+       .ubridge                        = 1,
        .used_kvd_sizes                 = 1,
        .kvd_hash_single_parts          = 59,
        .kvd_hash_double_parts          = 41,
@@ -3399,19 +3404,14 @@ static const struct mlxsw_config_profile mlxsw_sp1_config_profile = {
 };
 
 static const struct mlxsw_config_profile mlxsw_sp2_config_profile = {
-       .used_max_mid                   = 1,
-       .max_mid                        = MLXSW_SP_MID_MAX,
-       .used_flood_tables              = 1,
-       .used_flood_mode                = 1,
-       .flood_mode                     = 3,
-       .max_fid_flood_tables           = 3,
-       .fid_flood_table_size           = MLXSW_SP_FID_FLOOD_TABLE_SIZE,
+       .used_flood_mode                = 1,
+       .flood_mode                     = MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED,
        .used_max_ib_mc                 = 1,
        .max_ib_mc                      = 0,
        .used_max_pkey                  = 1,
        .max_pkey                       = 0,
-       .used_kvh_xlt_cache_mode        = 1,
-       .kvh_xlt_cache_mode             = 1,
+       .used_ubridge                   = 1,
+       .ubridge                        = 1,
        .swid_config                    = {
                {
                        .used_type      = 1,
@@ -3585,6 +3585,25 @@ mlxsw_sp_resources_rif_mac_profile_register(struct mlxsw_core *mlxsw_core)
                                         &size_params);
 }
 
+static int mlxsw_sp_resources_rifs_register(struct mlxsw_core *mlxsw_core)
+{
+       struct devlink *devlink = priv_to_devlink(mlxsw_core);
+       struct devlink_resource_size_params size_params;
+       u64 max_rifs;
+
+       if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_RIFS))
+               return -EIO;
+
+       max_rifs = MLXSW_CORE_RES_GET(mlxsw_core, MAX_RIFS);
+       devlink_resource_size_params_init(&size_params, max_rifs, max_rifs,
+                                         1, DEVLINK_RESOURCE_UNIT_ENTRY);
+
+       return devlink_resource_register(devlink, "rifs", max_rifs,
+                                        MLXSW_SP_RESOURCE_RIFS,
+                                        DEVLINK_RESOURCE_ID_PARENT_TOP,
+                                        &size_params);
+}
+
 static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
 {
        int err;
@@ -3609,8 +3628,13 @@ static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core)
        if (err)
                goto err_resources_rif_mac_profile_register;
 
+       err = mlxsw_sp_resources_rifs_register(mlxsw_core);
+       if (err)
+               goto err_resources_rifs_register;
+
        return 0;
 
+err_resources_rifs_register:
 err_resources_rif_mac_profile_register:
 err_policer_resources_register:
 err_resources_counter_register:
@@ -3643,8 +3667,13 @@ static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core)
        if (err)
                goto err_resources_rif_mac_profile_register;
 
+       err = mlxsw_sp_resources_rifs_register(mlxsw_core);
+       if (err)
+               goto err_resources_rifs_register;
+
        return 0;
 
+err_resources_rifs_register:
 err_resources_rif_mac_profile_register:
 err_policer_resources_register:
 err_resources_counter_register:
index a60d2bb..50a9380 100644 (file)
@@ -68,6 +68,7 @@ enum mlxsw_sp_resource_id {
        MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
        MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
        MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
+       MLXSW_SP_RESOURCE_RIFS,
 };
 
 struct mlxsw_sp_port;
@@ -111,15 +112,6 @@ enum mlxsw_sp_nve_type {
        MLXSW_SP_NVE_TYPE_VXLAN,
 };
 
-struct mlxsw_sp_mid {
-       struct list_head list;
-       unsigned char addr[ETH_ALEN];
-       u16 fid;
-       u16 mid;
-       bool in_hw;
-       unsigned long *ports_in_mid; /* bits array */
-};
-
 struct mlxsw_sp_sb;
 struct mlxsw_sp_bridge;
 struct mlxsw_sp_router;
@@ -142,6 +134,7 @@ struct mlxsw_sp_ptp_ops;
 struct mlxsw_sp_span_ops;
 struct mlxsw_sp_qdisc_state;
 struct mlxsw_sp_mall_entry;
+struct mlxsw_sp_pgt;
 
 struct mlxsw_sp_port_mapping {
        u8 module;
@@ -210,10 +203,13 @@ struct mlxsw_sp {
        const struct mlxsw_sp_mall_ops *mall_ops;
        const struct mlxsw_sp_router_ops *router_ops;
        const struct mlxsw_listener *listeners;
+       const struct mlxsw_sp_fid_family **fid_family_arr;
        size_t listeners_count;
        u32 lowest_shaper_bs;
        struct rhashtable ipv6_addr_ht;
        struct mutex ipv6_addr_ht_lock; /* Protects ipv6_addr_ht */
+       struct mlxsw_sp_pgt *pgt;
+       bool pgt_smpe_index_valid;
 };
 
 struct mlxsw_sp_ptp_ops {
@@ -389,6 +385,31 @@ struct mlxsw_sp_port_type_speed_ops {
        u32 (*ptys_proto_cap_masked_get)(u32 eth_proto_cap);
 };
 
+struct mlxsw_sp_ports_bitmap {
+       unsigned long *bitmap;
+       unsigned int nbits;
+};
+
+static inline int
+mlxsw_sp_port_bitmap_init(struct mlxsw_sp *mlxsw_sp,
+                         struct mlxsw_sp_ports_bitmap *ports_bm)
+{
+       unsigned int nbits = mlxsw_core_max_ports(mlxsw_sp->core);
+
+       ports_bm->nbits = nbits;
+       ports_bm->bitmap = bitmap_zalloc(nbits, GFP_KERNEL);
+       if (!ports_bm->bitmap)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static inline void
+mlxsw_sp_port_bitmap_fini(struct mlxsw_sp_ports_bitmap *ports_bm)
+{
+       bitmap_free(ports_bm->bitmap);
+}
+
 static inline u8 mlxsw_sp_tunnel_ecn_decap(u8 outer_ecn, u8 inner_ecn,
                                           bool *trap_en)
 {
@@ -715,6 +736,7 @@ union mlxsw_sp_l3addr {
        struct in6_addr addr6;
 };
 
+u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
 int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
                         struct netlink_ext_ack *extack);
 void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
@@ -1236,7 +1258,6 @@ int mlxsw_sp_setup_tc_block_qevent_mark(struct mlxsw_sp_port *mlxsw_sp_port,
 
 /* spectrum_fid.c */
 bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index);
-bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid);
 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
                                                  u16 fid_index);
 int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex);
@@ -1264,7 +1285,8 @@ void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
                                 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid);
 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid);
-void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
+int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif);
+void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid);
 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid);
 enum mlxsw_sp_rif_type
 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
@@ -1286,6 +1308,9 @@ void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port);
 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp);
 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp);
 
+extern const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[];
+extern const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[];
+
 /* spectrum_mr.c */
 enum mlxsw_sp_mr_route_prio {
        MLXSW_SP_MR_ROUTE_PRIO_SG,
@@ -1443,4 +1468,16 @@ int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp);
 void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp);
 int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core);
 
+/* spectrum_pgt.c */
+int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid);
+void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base);
+int mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base,
+                                u16 count);
+void mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base,
+                                u16 count);
+int mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid,
+                               u16 smpe, u16 local_port, bool member);
+int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp);
+void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp);
+
 #endif
index 10ae111..24ff305 100644 (file)
@@ -15,7 +15,7 @@ struct mlxsw_sp2_kvdl_part_info {
         * usage bits we need and how many indexes there are
         * represented by a single bit. This could be got from FW
         * querying appropriate resources. So have the resource
-        * ids for for this purpose in partition definition.
+        * ids for this purpose in partition definition.
         */
        enum mlxsw_res_id usage_bit_count_res_id;
        enum mlxsw_res_id index_range_res_id;
index ce80931..045a24c 100644 (file)
@@ -22,11 +22,18 @@ struct mlxsw_sp_fid_core {
        unsigned int *port_fid_mappings;
 };
 
+struct mlxsw_sp_fid_port_vid {
+       struct list_head list;
+       u16 local_port;
+       u16 vid;
+};
+
 struct mlxsw_sp_fid {
        struct list_head list;
        struct mlxsw_sp_rif *rif;
        refcount_t ref_count;
        u16 fid_index;
+       u16 fid_offset;
        struct mlxsw_sp_fid_family *fid_family;
        struct rhash_head ht_node;
 
@@ -37,6 +44,7 @@ struct mlxsw_sp_fid {
        int nve_ifindex;
        u8 vni_valid:1,
           nve_flood_index_valid:1;
+       struct list_head port_vid_list; /* Ordered by local port. */
 };
 
 struct mlxsw_sp_fid_8021q {
@@ -63,7 +71,6 @@ static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
 
 struct mlxsw_sp_flood_table {
        enum mlxsw_sp_flood_type packet_type;
-       enum mlxsw_reg_sfgc_bridge_type bridge_type;
        enum mlxsw_flood_table_type table_type;
        int table_index;
 };
@@ -76,18 +83,18 @@ struct mlxsw_sp_fid_ops {
                           u16 *p_fid_index);
        bool (*compare)(const struct mlxsw_sp_fid *fid,
                        const void *arg);
-       u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
        int (*port_vid_map)(struct mlxsw_sp_fid *fid,
                            struct mlxsw_sp_port *port, u16 vid);
        void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
                               struct mlxsw_sp_port *port, u16 vid);
-       int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni);
+       int (*vni_set)(struct mlxsw_sp_fid *fid);
        void (*vni_clear)(struct mlxsw_sp_fid *fid);
-       int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid,
-                                  u32 nve_flood_index);
+       int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
        void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
        void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
                                  const struct net_device *nve_dev);
+       int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
+                                    const struct mlxsw_sp_rif *rif);
 };
 
 struct mlxsw_sp_fid_family {
@@ -102,7 +109,10 @@ struct mlxsw_sp_fid_family {
        enum mlxsw_sp_rif_type rif_type;
        const struct mlxsw_sp_fid_ops *ops;
        struct mlxsw_sp *mlxsw_sp;
-       u8 lag_vid_valid:1;
+       bool flood_rsp;
+       enum mlxsw_reg_bridge_type bridge_type;
+       u16 pgt_base;
+       bool smpe_index_valid;
 };
 
 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
@@ -137,11 +147,6 @@ bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index)
        return fid_family->start_index == fid_index;
 }
 
-bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
-{
-       return fid->fid_family->lag_vid_valid;
-}
-
 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
                                                  u16 fid_index)
 {
@@ -206,17 +211,20 @@ int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
        const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
        int err;
 
-       if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid))
+       if (WARN_ON(fid->nve_flood_index_valid))
                return -EINVAL;
 
-       err = ops->nve_flood_index_set(fid, nve_flood_index);
-       if (err)
-               return err;
-
        fid->nve_flood_index = nve_flood_index;
        fid->nve_flood_index_valid = true;
+       err = ops->nve_flood_index_set(fid);
+       if (err)
+               goto err_nve_flood_index_set;
 
        return 0;
+
+err_nve_flood_index_set:
+       fid->nve_flood_index_valid = false;
+       return err;
 }
 
 void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
@@ -224,7 +232,7 @@ void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
        struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
        const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
 
-       if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid))
+       if (WARN_ON(!fid->nve_flood_index_valid))
                return;
 
        fid->nve_flood_index_valid = false;
@@ -244,7 +252,7 @@ int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
        struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
        int err;
 
-       if (WARN_ON(!ops->vni_set || fid->vni_valid))
+       if (WARN_ON(fid->vni_valid))
                return -EINVAL;
 
        fid->nve_type = type;
@@ -256,15 +264,15 @@ int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
        if (err)
                return err;
 
-       err = ops->vni_set(fid, vni);
+       fid->vni_valid = true;
+       err = ops->vni_set(fid);
        if (err)
                goto err_vni_set;
 
-       fid->vni_valid = true;
-
        return 0;
 
 err_vni_set:
+       fid->vni_valid = false;
        rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
                               mlxsw_sp_fid_vni_ht_params);
        return err;
@@ -276,7 +284,7 @@ void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
        const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
        struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
 
-       if (WARN_ON(!ops->vni_clear || !fid->vni_valid))
+       if (WARN_ON(!fid->vni_valid))
                return;
 
        fid->vni_valid = false;
@@ -316,34 +324,43 @@ mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
        return NULL;
 }
 
+static u16
+mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
+{
+       return fid_family->end_index - fid_family->start_index + 1;
+}
+
+static u16
+mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family,
+                            const struct mlxsw_sp_flood_table *flood_table,
+                            u16 fid_offset)
+{
+       u16 num_fids;
+
+       num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
+       return fid_family->pgt_base + num_fids * flood_table->table_index +
+              fid_offset;
+}
+
 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
                           enum mlxsw_sp_flood_type packet_type, u16 local_port,
                           bool member)
 {
        struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
-       const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
        const struct mlxsw_sp_flood_table *flood_table;
-       char *sftr2_pl;
-       int err;
+       u16 mid_index;
 
-       if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
+       if (WARN_ON(!fid_family->flood_tables))
                return -EINVAL;
 
        flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
        if (!flood_table)
                return -ESRCH;
 
-       sftr2_pl = kmalloc(MLXSW_REG_SFTR2_LEN, GFP_KERNEL);
-       if (!sftr2_pl)
-               return -ENOMEM;
-
-       mlxsw_reg_sftr2_pack(sftr2_pl, flood_table->table_index,
-                            ops->flood_index(fid), flood_table->table_type, 1,
-                            local_port, member);
-       err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr2),
-                             sftr2_pl);
-       kfree(sftr2_pl);
-       return err;
+       mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
+                                                fid->fid_offset);
+       return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
+                                          fid->fid_index, local_port, member);
 }
 
 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
@@ -370,11 +387,6 @@ enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
        return fid->fid_family->type;
 }
 
-void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
-{
-       fid->rif = rif;
-}
-
 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
 {
        return fid->rif;
@@ -405,6 +417,7 @@ static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
        u16 vid = *(u16 *) arg;
 
        mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
+       fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
 }
 
 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
@@ -413,38 +426,341 @@ static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
                       MLXSW_REG_SFMR_OP_DESTROY_FID;
 }
 
-static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
-                          u16 fid_offset, bool valid)
+static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
 {
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        char sfmr_pl[MLXSW_REG_SFMR_LEN];
+       u16 smpe;
+
+       smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
 
-       mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
-                           fid_offset);
+       mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index,
+                           fid->fid_offset, fid->fid_family->flood_rsp,
+                           fid->fid_family->bridge_type,
+                           fid->fid_family->smpe_index_valid, smpe);
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
 }
 
-static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
-                              __be32 vni, bool vni_valid, u32 nve_flood_index,
-                              bool nve_flood_index_valid)
+static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
+                               const struct mlxsw_sp_rif *rif)
 {
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        char sfmr_pl[MLXSW_REG_SFMR_LEN];
+       u16 smpe;
+
+       smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
+
+       mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID,
+                           fid->fid_index, fid->fid_offset,
+                           fid->fid_family->flood_rsp,
+                           fid->fid_family->bridge_type,
+                           fid->fid_family->smpe_index_valid, smpe);
+       mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);
+       mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
+       mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
+       mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
+
+       if (rif) {
+               mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
+               mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
+       }
 
-       mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index,
-                           0);
-       mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid);
-       mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni));
-       mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid);
-       mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index);
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
 }
 
-static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
+static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
+                                      const struct mlxsw_sp_rif *rif,
+                                      bool valid)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       char svfa_pl[MLXSW_REG_SVFA_LEN];
+       bool irif_valid;
+       u16 irif_index;
+
+       irif_valid = !!rif;
+       irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
+
+       mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
+                               be32_to_cpu(fid->vni), irif_valid, irif_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
+}
+
+static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                         const struct mlxsw_sp_rif *rif)
+{
+       return mlxsw_sp_fid_edit_op(fid, rif);
+}
+
+static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                             const struct mlxsw_sp_rif *rif)
+{
+       if (!fid->vni_valid)
+               return 0;
+
+       return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
+}
+
+static int
+mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
+                           const struct mlxsw_sp_rif *rif)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       char svfa_pl[MLXSW_REG_SVFA_LEN];
+       bool irif_valid;
+       u16 irif_index;
+
+       irif_valid = !!rif;
+       irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
+
+       mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
+                               irif_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
+}
+
+static int
+mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                        const struct mlxsw_sp_rif *rif)
+{
+       struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
+
+       /* Update the global VID => FID mapping we created when the FID was
+        * configured.
+        */
+       return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
+}
+
+static int
+mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
+                                           struct mlxsw_sp_fid_port_vid *pv,
+                                           bool irif_valid, u16 irif_index)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       char svfa_pl[MLXSW_REG_SVFA_LEN];
+
+       mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
+                                    fid->fid_index, pv->vid, irif_valid,
+                                    irif_index);
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
+}
+
+static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
+                                          const struct mlxsw_sp_rif *rif)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       struct mlxsw_sp_fid_port_vid *pv;
+       u16 irif_index;
+       int err;
+
+       err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
+       if (err)
+               return err;
+
+       irif_index = mlxsw_sp_rif_index(rif);
+
+       list_for_each_entry(pv, &fid->port_vid_list, list) {
+               /* If port is not in virtual mode, then it does not have any
+                * {Port, VID}->FID mappings that need to be updated with the
+                * ingress RIF.
+                */
+               if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
+                       continue;
+
+               err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
+                                                                 true,
+                                                                 irif_index);
+               if (err)
+                       goto err_port_vid_to_fid_rif_update_one;
+       }
+
+       return 0;
+
+err_port_vid_to_fid_rif_update_one:
+       list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
+               if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
+                       continue;
+
+               mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
+       }
+
+       fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
+       return err;
+}
+
+static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       struct mlxsw_sp_fid_port_vid *pv;
+
+       list_for_each_entry(pv, &fid->port_vid_list, list) {
+               /* If port is not in virtual mode, then it does not have any
+                * {Port, VID}->FID mappings that need to be updated.
+                */
+               if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
+                       continue;
+
+               mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
+       }
+
+       fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
+}
+
+static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
+                                   bool valid, u8 port_page)
+{
+       u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
+       u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       struct mlxsw_sp_fid_port_vid *port_vid;
+       u8 rec_num, entries_num = 0;
+       char *reiv_pl;
+       int err;
+
+       reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
+       if (!reiv_pl)
+               return -ENOMEM;
+
+       mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
+
+       list_for_each_entry(port_vid, &fid->port_vid_list, list) {
+               /* port_vid_list is sorted by local_port. */
+               if (port_vid->local_port < local_port_start)
+                       continue;
+
+               if (port_vid->local_port > local_port_end)
+                       break;
+
+               rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
+               mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
+               mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,
+                                           valid ? port_vid->vid : 0);
+               entries_num++;
+       }
+
+       if (!entries_num) {
+               kfree(reiv_pl);
+               return 0;
+       }
+
+       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
+       if (err)
+               goto err_reg_write;
+
+       kfree(reiv_pl);
+       return 0;
+
+err_reg_write:
+       kfree(reiv_pl);
+       return err;
+}
+
+static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
+                                             u16 rif_index, bool valid)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       u8 num_port_pages;
+       int err, i;
+
+       num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /
+                        MLXSW_REG_REIV_REC_MAX_COUNT + 1;
+
+       for (i = 0; i < num_port_pages; i++) {
+               err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);
+               if (err)
+                       goto err_reiv_handle;
+       }
+
+       return 0;
+
+err_reiv_handle:
+       for (; i >= 0; i--)
+               mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
+       return err;
+}
+
+int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
+{
+       u16 rif_index = mlxsw_sp_rif_index(rif);
+       int err;
+
+       err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
+       if (err)
+               return err;
+
+       err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
+       if (err)
+               goto err_vni_to_fid_rif_update;
+
+       err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
+       if (err)
+               goto err_vid_to_fid_rif_set;
+
+       err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);
+       if (err)
+               goto err_erif_eport_to_vid_map;
+
+       fid->rif = rif;
+       return 0;
+
+err_erif_eport_to_vid_map:
+       mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
+err_vid_to_fid_rif_set:
+       mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
+err_vni_to_fid_rif_update:
+       mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
+       return err;
+}
+
+void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
+{
+       u16 rif_index;
+
+       if (!fid->rif)
+               return;
+
+       rif_index = mlxsw_sp_rif_index(fid->rif);
+       fid->rif = NULL;
+
+       mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);
+       mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
+       mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
+       mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
+}
+
+static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
+{
+       int err;
+
+       err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);
+       if (err)
+               return err;
+
+       err = mlxsw_sp_fid_edit_op(fid, fid->rif);
+       if (err)
+               goto err_fid_edit_op;
+
+       return 0;
+
+err_fid_edit_op:
+       mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
+       return err;
+}
+
+static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
                                       u16 local_port, u16 vid, bool valid)
 {
-       enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
        char svfa_pl[MLXSW_REG_SVFA_LEN];
+       bool irif_valid = false;
+       u16 irif_index = 0;
+
+       if (fid->rif) {
+               irif_valid = true;
+               irif_index = mlxsw_sp_rif_index(fid->rif);
+       }
 
-       mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
+       mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
+                                    vid, irif_valid, irif_index);
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
 }
 
@@ -459,20 +775,19 @@ static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
        int br_ifindex = *(int *) arg;
 
        mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
+       fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
 }
 
 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
 {
-       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
-
-       return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
+       return mlxsw_sp_fid_op(fid, true);
 }
 
 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
 {
        if (fid->vni_valid)
                mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
-       mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
+       mlxsw_sp_fid_op(fid, false);
 }
 
 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
@@ -498,14 +813,8 @@ mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
        return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
 }
 
-static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
-{
-       return fid->fid_index - VLAN_N_VID;
-}
-
 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
 {
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
        int err;
 
@@ -517,7 +826,7 @@ static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
                if (!fid)
                        continue;
 
-               err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
+               err = __mlxsw_sp_fid_port_vid_map(fid,
                                                  mlxsw_sp_port->local_port,
                                                  vid, true);
                if (err)
@@ -540,8 +849,7 @@ err_fid_port_vid_map:
                if (!fid)
                        continue;
 
-               __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
-                                           mlxsw_sp_port->local_port, vid,
+               __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
                                            false);
        }
        return err;
@@ -549,7 +857,6 @@ err_fid_port_vid_map:
 
 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
 {
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
 
        mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
@@ -562,12 +869,108 @@ static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
                if (!fid)
                        continue;
 
-               __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
-                                           mlxsw_sp_port->local_port, vid,
+               __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
                                            false);
        }
 }
 
+static int
+mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
+                              u16 vid)
+{
+       struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
+
+       port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
+       if (!port_vid)
+               return -ENOMEM;
+
+       port_vid->local_port = local_port;
+       port_vid->vid = vid;
+
+       list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
+               if (tmp_port_vid->local_port > local_port)
+                       break;
+       }
+
+       list_add_tail(&port_vid->list, &tmp_port_vid->list);
+       return 0;
+}
+
+static void
+mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
+                              u16 vid)
+{
+       struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
+
+       list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
+               if (port_vid->local_port != local_port || port_vid->vid != vid)
+                       continue;
+
+               list_del(&port_vid->list);
+               kfree(port_vid);
+               return;
+       }
+}
+
+static int
+mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
+                          u16 vid, bool valid)
+{
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       char smpe_pl[MLXSW_REG_SMPE_LEN];
+
+       mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,
+                           valid ? vid : 0);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);
+}
+
+static int
+mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
+                                      u16 local_port, u16 vid, bool valid)
+{
+       u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
+       u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
+       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+       u16 rif_index = mlxsw_sp_rif_index(fid->rif);
+       char *reiv_pl;
+       int err;
+
+       reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
+       if (!reiv_pl)
+               return -ENOMEM;
+
+       mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
+       mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
+       mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);
+       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
+       kfree(reiv_pl);
+       return err;
+}
+
+static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
+                                u16 vid, bool valid)
+{
+       int err;
+
+       err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
+       if (err)
+               return err;
+
+       if (!fid->rif)
+               return 0;
+
+       err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
+                                                    valid);
+       if (err)
+               goto err_erif_eport_to_vid_map_one;
+
+       return 0;
+
+err_erif_eport_to_vid_map_one:
+       mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
+       return err;
+}
+
 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
                                           struct mlxsw_sp_port *mlxsw_sp_port,
                                           u16 vid)
@@ -576,11 +979,20 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
        u16 local_port = mlxsw_sp_port->local_port;
        int err;
 
-       err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
-                                         mlxsw_sp_port->local_port, vid, true);
+       err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
+                                         true);
        if (err)
                return err;
 
+       err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
+       if (err)
+               goto err_fid_evid_map;
+
+       err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
+                                            vid);
+       if (err)
+               goto err_port_vid_list_add;
+
        if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
                err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
                if (err)
@@ -591,8 +1003,11 @@ static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
 
 err_port_vp_mode_trans:
        mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
-       __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
-                                   mlxsw_sp_port->local_port, vid, false);
+       mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
+err_port_vid_list_add:
+       mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
+err_fid_evid_map:
+       __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
        return err;
 }
 
@@ -606,43 +1021,29 @@ mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
        if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
                mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
        mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
-       __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
-                                   mlxsw_sp_port->local_port, vid, false);
+       mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
+       mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
+       __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
 }
 
-static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
+static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
 {
-       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
-
-       return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
-                                  true, fid->nve_flood_index,
-                                  fid->nve_flood_index_valid);
+       return mlxsw_sp_fid_vni_op(fid);
 }
 
 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
 {
-       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
-
-       mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
-                           fid->nve_flood_index, fid->nve_flood_index_valid);
+       mlxsw_sp_fid_vni_op(fid);
 }
 
-static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
-                                                 u32 nve_flood_index)
+static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
 {
-       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
-
-       return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
-                                  fid->vni, fid->vni_valid, nve_flood_index,
-                                  true);
+       return mlxsw_sp_fid_edit_op(fid, fid->rif);
 }
 
 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
 {
-       struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
-
-       mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
-                           fid->vni_valid, 0, false);
+       mlxsw_sp_fid_edit_op(fid, fid->rif);
 }
 
 static void
@@ -652,13 +1053,19 @@ mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
        br_fdb_clear_offload(nve_dev, 0);
 }
 
+static int
+mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                        const struct mlxsw_sp_rif *rif)
+{
+       return 0;
+}
+
 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
        .setup                  = mlxsw_sp_fid_8021d_setup,
        .configure              = mlxsw_sp_fid_8021d_configure,
        .deconfigure            = mlxsw_sp_fid_8021d_deconfigure,
        .index_alloc            = mlxsw_sp_fid_8021d_index_alloc,
        .compare                = mlxsw_sp_fid_8021d_compare,
-       .flood_index            = mlxsw_sp_fid_8021d_flood_index,
        .port_vid_map           = mlxsw_sp_fid_8021d_port_vid_map,
        .port_vid_unmap         = mlxsw_sp_fid_8021d_port_vid_unmap,
        .vni_set                = mlxsw_sp_fid_8021d_vni_set,
@@ -666,42 +1073,32 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
        .nve_flood_index_set    = mlxsw_sp_fid_8021d_nve_flood_index_set,
        .nve_flood_index_clear  = mlxsw_sp_fid_8021d_nve_flood_index_clear,
        .fdb_clear_offload      = mlxsw_sp_fid_8021d_fdb_clear_offload,
+       .vid_to_fid_rif_update  = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
 };
 
+#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
+#define MLXSW_SP_FID_RFID_MAX (11 * 1024)
+#define MLXSW_SP_FID_8021Q_PGT_BASE 0
+#define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX)
+
 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
        {
                .packet_type    = MLXSW_SP_FLOOD_TYPE_UC,
-               .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
-               .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID,
+               .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
                .table_index    = 0,
        },
        {
                .packet_type    = MLXSW_SP_FLOOD_TYPE_MC,
-               .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
-               .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID,
+               .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
                .table_index    = 1,
        },
        {
                .packet_type    = MLXSW_SP_FLOOD_TYPE_BC,
-               .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
-               .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID,
+               .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
                .table_index    = 2,
        },
 };
 
-/* Range and flood configuration must match mlxsw_config_profile */
-static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
-       .type                   = MLXSW_SP_FID_TYPE_8021D,
-       .fid_size               = sizeof(struct mlxsw_sp_fid_8021d),
-       .start_index            = VLAN_N_VID,
-       .end_index              = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
-       .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
-       .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
-       .rif_type               = MLXSW_SP_RIF_TYPE_FID,
-       .ops                    = &mlxsw_sp_fid_8021d_ops,
-       .lag_vid_valid          = 1,
-};
-
 static bool
 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
 {
@@ -717,48 +1114,19 @@ mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
        br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
 }
 
-static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = {
-       .setup                  = mlxsw_sp_fid_8021q_setup,
-       .configure              = mlxsw_sp_fid_8021d_configure,
-       .deconfigure            = mlxsw_sp_fid_8021d_deconfigure,
-       .index_alloc            = mlxsw_sp_fid_8021d_index_alloc,
-       .compare                = mlxsw_sp_fid_8021q_compare,
-       .flood_index            = mlxsw_sp_fid_8021d_flood_index,
-       .port_vid_map           = mlxsw_sp_fid_8021d_port_vid_map,
-       .port_vid_unmap         = mlxsw_sp_fid_8021d_port_vid_unmap,
-       .vni_set                = mlxsw_sp_fid_8021d_vni_set,
-       .vni_clear              = mlxsw_sp_fid_8021d_vni_clear,
-       .nve_flood_index_set    = mlxsw_sp_fid_8021d_nve_flood_index_set,
-       .nve_flood_index_clear  = mlxsw_sp_fid_8021d_nve_flood_index_clear,
-       .fdb_clear_offload      = mlxsw_sp_fid_8021q_fdb_clear_offload,
-};
-
-/* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */
-#define MLXSW_SP_FID_8021Q_EMU_START   (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX)
-#define MLXSW_SP_FID_8021Q_EMU_END     (MLXSW_SP_FID_8021Q_EMU_START + \
-                                        VLAN_VID_MASK - 2)
-
-/* Range and flood configuration must match mlxsw_config_profile */
-static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = {
-       .type                   = MLXSW_SP_FID_TYPE_8021Q,
-       .fid_size               = sizeof(struct mlxsw_sp_fid_8021q),
-       .start_index            = MLXSW_SP_FID_8021Q_EMU_START,
-       .end_index              = MLXSW_SP_FID_8021Q_EMU_END,
-       .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
-       .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
-       .rif_type               = MLXSW_SP_RIF_TYPE_VLAN,
-       .ops                    = &mlxsw_sp_fid_8021q_emu_ops,
-       .lag_vid_valid          = 1,
-};
+static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
+{
+       fid->fid_offset = 0;
+}
 
 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
 {
-       /* rFIDs are allocated by the device during init */
-       return 0;
+       return mlxsw_sp_fid_op(fid, true);
 }
 
 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
 {
+       mlxsw_sp_fid_op(fid, false);
 }
 
 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
@@ -787,9 +1155,28 @@ static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
        u16 local_port = mlxsw_sp_port->local_port;
        int err;
 
-       /* We only need to transition the port to virtual mode since
-        * {Port, VID} => FID is done by the firmware upon RIF creation.
+       err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
+                                            vid);
+       if (err)
+               return err;
+
+       /* Using legacy bridge model, we only need to transition the port to
+        * virtual mode since {Port, VID} => FID is done by the firmware upon
+        * RIF creation. Using unified bridge model, we need to map
+        * {Port, VID} => FID and map egress VID.
         */
+       err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
+                                         true);
+       if (err)
+               goto err_port_vid_map;
+
+       if (fid->rif) {
+               err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
+                                                            vid, true);
+               if (err)
+                       goto err_erif_eport_to_vid_map_one;
+       }
+
        if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
                err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
                if (err)
@@ -800,6 +1187,13 @@ static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
 
 err_port_vp_mode_trans:
        mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
+       if (fid->rif)
+               mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
+                                                      false);
+err_erif_eport_to_vid_map_one:
+       __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
+err_port_vid_map:
+       mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
        return err;
 }
 
@@ -813,39 +1207,69 @@ mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
        if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
                mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
        mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
+
+       if (fid->rif)
+               mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
+                                                      false);
+       __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
+       mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
+}
+
+static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
+{
+       return -EOPNOTSUPP;
+}
+
+static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
+{
+       WARN_ON_ONCE(1);
+}
+
+static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
+{
+       return -EOPNOTSUPP;
+}
+
+static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
+{
+       WARN_ON_ONCE(1);
+}
+
+static int
+mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
+                                       const struct mlxsw_sp_rif *rif)
+{
+       return 0;
 }
 
 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
+       .setup                  = mlxsw_sp_fid_rfid_setup,
        .configure              = mlxsw_sp_fid_rfid_configure,
        .deconfigure            = mlxsw_sp_fid_rfid_deconfigure,
        .index_alloc            = mlxsw_sp_fid_rfid_index_alloc,
        .compare                = mlxsw_sp_fid_rfid_compare,
        .port_vid_map           = mlxsw_sp_fid_rfid_port_vid_map,
        .port_vid_unmap         = mlxsw_sp_fid_rfid_port_vid_unmap,
+       .vni_set                = mlxsw_sp_fid_rfid_vni_set,
+       .vni_clear              = mlxsw_sp_fid_rfid_vni_clear,
+       .nve_flood_index_set    = mlxsw_sp_fid_rfid_nve_flood_index_set,
+       .nve_flood_index_clear  = mlxsw_sp_fid_rfid_nve_flood_index_clear,
+       .vid_to_fid_rif_update  = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
 };
 
-#define MLXSW_SP_RFID_BASE     (15 * 1024)
-#define MLXSW_SP_RFID_MAX      1024
-
-static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
-       .type                   = MLXSW_SP_FID_TYPE_RFID,
-       .fid_size               = sizeof(struct mlxsw_sp_fid),
-       .start_index            = MLXSW_SP_RFID_BASE,
-       .end_index              = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
-       .rif_type               = MLXSW_SP_RIF_TYPE_SUBPORT,
-       .ops                    = &mlxsw_sp_fid_rfid_ops,
-};
+static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
+{
+       fid->fid_offset = 0;
+}
 
 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
 {
-       struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
-
-       return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
+       return mlxsw_sp_fid_op(fid, true);
 }
 
 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
 {
-       mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
+       mlxsw_sp_fid_op(fid, false);
 }
 
 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
@@ -862,26 +1286,252 @@ static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
        return true;
 }
 
+static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
+{
+       return -EOPNOTSUPP;
+}
+
+static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
+{
+       WARN_ON_ONCE(1);
+}
+
+static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
+{
+       return -EOPNOTSUPP;
+}
+
+static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
+{
+       WARN_ON_ONCE(1);
+}
+
 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
+       .setup                  = mlxsw_sp_fid_dummy_setup,
        .configure              = mlxsw_sp_fid_dummy_configure,
        .deconfigure            = mlxsw_sp_fid_dummy_deconfigure,
        .index_alloc            = mlxsw_sp_fid_dummy_index_alloc,
        .compare                = mlxsw_sp_fid_dummy_compare,
+       .vni_set                = mlxsw_sp_fid_dummy_vni_set,
+       .vni_clear              = mlxsw_sp_fid_dummy_vni_clear,
+       .nve_flood_index_set    = mlxsw_sp_fid_dummy_nve_flood_index_set,
+       .nve_flood_index_clear  = mlxsw_sp_fid_dummy_nve_flood_index_clear,
+};
+
+static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
+       int err;
+
+       err = mlxsw_sp_fid_op(fid, true);
+       if (err)
+               return err;
+
+       err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
+       if (err)
+               goto err_vid_to_fid_map;
+
+       return 0;
+
+err_vid_to_fid_map:
+       mlxsw_sp_fid_op(fid, false);
+       return err;
+}
+
+static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
+{
+       struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
+
+       if (fid->vni_valid)
+               mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
+
+       mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
+       mlxsw_sp_fid_op(fid, false);
+}
+
+static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
+                                          struct mlxsw_sp_port *mlxsw_sp_port,
+                                          u16 vid)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       u8 local_port = mlxsw_sp_port->local_port;
+       int err;
+
+       /* In case there are no {Port, VID} => FID mappings on the port,
+        * we can use the global VID => FID mapping we created when the
+        * FID was configured, otherwise, configure new mapping.
+        */
+       if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
+               err =  __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
+               if (err)
+                       return err;
+       }
+
+       err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
+       if (err)
+               goto err_fid_evid_map;
+
+       err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
+                                            vid);
+       if (err)
+               goto err_port_vid_list_add;
+
+       return 0;
+
+err_port_vid_list_add:
+        mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
+err_fid_evid_map:
+       if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
+               __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
+       return err;
+}
+
+static void
+mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
+                                 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       u8 local_port = mlxsw_sp_port->local_port;
+
+       mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
+       mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
+       if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
+               __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
+       .setup                  = mlxsw_sp_fid_8021q_setup,
+       .configure              = mlxsw_sp_fid_8021q_configure,
+       .deconfigure            = mlxsw_sp_fid_8021q_deconfigure,
+       .index_alloc            = mlxsw_sp_fid_8021d_index_alloc,
+       .compare                = mlxsw_sp_fid_8021q_compare,
+       .port_vid_map           = mlxsw_sp_fid_8021q_port_vid_map,
+       .port_vid_unmap         = mlxsw_sp_fid_8021q_port_vid_unmap,
+       .vni_set                = mlxsw_sp_fid_8021d_vni_set,
+       .vni_clear              = mlxsw_sp_fid_8021d_vni_clear,
+       .nve_flood_index_set    = mlxsw_sp_fid_8021d_nve_flood_index_set,
+       .nve_flood_index_clear  = mlxsw_sp_fid_8021d_nve_flood_index_clear,
+       .fdb_clear_offload      = mlxsw_sp_fid_8021q_fdb_clear_offload,
+       .vid_to_fid_rif_update  = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
+};
+
+/* There are 4K-2 802.1Q FIDs */
+#define MLXSW_SP_FID_8021Q_START       1 /* FID 0 is reserved. */
+#define MLXSW_SP_FID_8021Q_END         (MLXSW_SP_FID_8021Q_START + \
+                                        MLXSW_SP_FID_8021Q_MAX - 1)
+
+/* There are 1K 802.1D FIDs */
+#define MLXSW_SP_FID_8021D_START       (MLXSW_SP_FID_8021Q_END + 1)
+#define MLXSW_SP_FID_8021D_END         (MLXSW_SP_FID_8021D_START + \
+                                        MLXSW_SP_FID_8021D_MAX - 1)
+
+/* There is one dummy FID */
+#define MLXSW_SP_FID_DUMMY             (MLXSW_SP_FID_8021D_END + 1)
+
+/* There are 11K rFIDs */
+#define MLXSW_SP_RFID_START            (MLXSW_SP_FID_DUMMY + 1)
+#define MLXSW_SP_RFID_END              (MLXSW_SP_RFID_START + \
+                                        MLXSW_SP_FID_RFID_MAX - 1)
+
+static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
+       .type                   = MLXSW_SP_FID_TYPE_8021Q,
+       .fid_size               = sizeof(struct mlxsw_sp_fid_8021q),
+       .start_index            = MLXSW_SP_FID_8021Q_START,
+       .end_index              = MLXSW_SP_FID_8021Q_END,
+       .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
+       .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
+       .rif_type               = MLXSW_SP_RIF_TYPE_VLAN,
+       .ops                    = &mlxsw_sp_fid_8021q_ops,
+       .flood_rsp              = false,
+       .bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
+       .pgt_base               = MLXSW_SP_FID_8021Q_PGT_BASE,
+       .smpe_index_valid       = false,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
+       .type                   = MLXSW_SP_FID_TYPE_8021D,
+       .fid_size               = sizeof(struct mlxsw_sp_fid_8021d),
+       .start_index            = MLXSW_SP_FID_8021D_START,
+       .end_index              = MLXSW_SP_FID_8021D_END,
+       .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
+       .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
+       .rif_type               = MLXSW_SP_RIF_TYPE_FID,
+       .ops                    = &mlxsw_sp_fid_8021d_ops,
+       .bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
+       .pgt_base               = MLXSW_SP_FID_8021D_PGT_BASE,
+       .smpe_index_valid       = false,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
+       .type                   = MLXSW_SP_FID_TYPE_DUMMY,
+       .fid_size               = sizeof(struct mlxsw_sp_fid),
+       .start_index            = MLXSW_SP_FID_DUMMY,
+       .end_index              = MLXSW_SP_FID_DUMMY,
+       .ops                    = &mlxsw_sp_fid_dummy_ops,
+       .smpe_index_valid       = false,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
+       .type                   = MLXSW_SP_FID_TYPE_RFID,
+       .fid_size               = sizeof(struct mlxsw_sp_fid),
+       .start_index            = MLXSW_SP_RFID_START,
+       .end_index              = MLXSW_SP_RFID_END,
+       .rif_type               = MLXSW_SP_RIF_TYPE_SUBPORT,
+       .ops                    = &mlxsw_sp_fid_rfid_ops,
+       .flood_rsp              = true,
+       .smpe_index_valid       = false,
+};
+
+const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
+       [MLXSW_SP_FID_TYPE_8021Q]       = &mlxsw_sp1_fid_8021q_family,
+       [MLXSW_SP_FID_TYPE_8021D]       = &mlxsw_sp1_fid_8021d_family,
+       [MLXSW_SP_FID_TYPE_DUMMY]       = &mlxsw_sp1_fid_dummy_family,
+       [MLXSW_SP_FID_TYPE_RFID]        = &mlxsw_sp_fid_rfid_family,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
+       .type                   = MLXSW_SP_FID_TYPE_8021Q,
+       .fid_size               = sizeof(struct mlxsw_sp_fid_8021q),
+       .start_index            = MLXSW_SP_FID_8021Q_START,
+       .end_index              = MLXSW_SP_FID_8021Q_END,
+       .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
+       .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
+       .rif_type               = MLXSW_SP_RIF_TYPE_VLAN,
+       .ops                    = &mlxsw_sp_fid_8021q_ops,
+       .flood_rsp              = false,
+       .bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
+       .pgt_base               = MLXSW_SP_FID_8021Q_PGT_BASE,
+       .smpe_index_valid       = true,
 };
 
-static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
+       .type                   = MLXSW_SP_FID_TYPE_8021D,
+       .fid_size               = sizeof(struct mlxsw_sp_fid_8021d),
+       .start_index            = MLXSW_SP_FID_8021D_START,
+       .end_index              = MLXSW_SP_FID_8021D_END,
+       .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
+       .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
+       .rif_type               = MLXSW_SP_RIF_TYPE_FID,
+       .ops                    = &mlxsw_sp_fid_8021d_ops,
+       .bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
+       .pgt_base               = MLXSW_SP_FID_8021D_PGT_BASE,
+       .smpe_index_valid       = true,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
        .type                   = MLXSW_SP_FID_TYPE_DUMMY,
        .fid_size               = sizeof(struct mlxsw_sp_fid),
-       .start_index            = VLAN_N_VID - 1,
-       .end_index              = VLAN_N_VID - 1,
+       .start_index            = MLXSW_SP_FID_DUMMY,
+       .end_index              = MLXSW_SP_FID_DUMMY,
        .ops                    = &mlxsw_sp_fid_dummy_ops,
+       .smpe_index_valid       = false,
 };
 
-static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
-       [MLXSW_SP_FID_TYPE_8021Q]       = &mlxsw_sp_fid_8021q_emu_family,
-       [MLXSW_SP_FID_TYPE_8021D]       = &mlxsw_sp_fid_8021d_family,
+const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
+       [MLXSW_SP_FID_TYPE_8021Q]       = &mlxsw_sp2_fid_8021q_family,
+       [MLXSW_SP_FID_TYPE_8021D]       = &mlxsw_sp2_fid_8021d_family,
+       [MLXSW_SP_FID_TYPE_DUMMY]       = &mlxsw_sp2_fid_dummy_family,
        [MLXSW_SP_FID_TYPE_RFID]        = &mlxsw_sp_fid_rfid_family,
-       [MLXSW_SP_FID_TYPE_DUMMY]       = &mlxsw_sp_fid_dummy_family,
 };
 
 static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
@@ -919,6 +1569,8 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
        fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
        if (!fid)
                return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&fid->port_vid_list);
        fid->fid_family = fid_family;
 
        err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
@@ -927,8 +1579,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
        fid->fid_index = fid_index;
        __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
 
-       if (fid->fid_family->ops->setup)
-               fid->fid_family->ops->setup(fid, arg);
+       fid->fid_family->ops->setup(fid, arg);
 
        err = fid->fid_family->ops->configure(fid);
        if (err)
@@ -967,6 +1618,7 @@ void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
        fid->fid_family->ops->deconfigure(fid);
        __clear_bit(fid->fid_index - fid_family->start_index,
                    fid_family->fids_bitmap);
+       WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
        kfree(fid);
 }
 
@@ -1010,26 +1662,49 @@ mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
                              const struct mlxsw_sp_flood_table *flood_table)
 {
        enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
+       struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
        const int *sfgc_packet_types;
-       int i;
+       u16 num_fids, mid_base;
+       int err, i;
+
+       mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
+       num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
+       err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids);
+       if (err)
+               return err;
 
        sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
        for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
-               struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
                char sfgc_pl[MLXSW_REG_SFGC_LEN];
-               int err;
 
                if (!sfgc_packet_types[i])
                        continue;
-               mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
-                                   flood_table->table_type,
-                                   flood_table->table_index);
+
+               mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,
+                                   flood_table->table_type, 0, mid_base);
+
                err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
                if (err)
-                       return err;
+                       goto err_reg_write;
        }
 
        return 0;
+
+err_reg_write:
+       mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
+       return err;
+}
+
+static void
+mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family,
+                             const struct mlxsw_sp_flood_table *flood_table)
+{
+       struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+       u16 num_fids, mid_base;
+
+       mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
+       num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
+       mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
 }
 
 static int
@@ -1050,6 +1725,19 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
        return 0;
 }
 
+static void
+mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
+{
+       int i;
+
+       for (i = 0; i < fid_family->nr_flood_tables; i++) {
+               const struct mlxsw_sp_flood_table *flood_table;
+
+               flood_table = &fid_family->flood_tables[i];
+               mlxsw_sp_fid_flood_table_fini(fid_family, flood_table);
+       }
+}
+
 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
                                        const struct mlxsw_sp_fid_family *tmpl)
 {
@@ -1091,6 +1779,10 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
                               struct mlxsw_sp_fid_family *fid_family)
 {
        mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
+
+       if (fid_family->flood_tables)
+               mlxsw_sp_fid_flood_tables_fini(fid_family);
+
        bitmap_free(fid_family->fids_bitmap);
        WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
        kfree(fid_family);
@@ -1144,7 +1836,7 @@ int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
 
        for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
                err = mlxsw_sp_fid_family_register(mlxsw_sp,
-                                                  mlxsw_sp_fid_family_arr[i]);
+                                                  mlxsw_sp->fid_family_arr[i]);
 
                if (err)
                        goto err_fid_ops_register;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_pgt.c
new file mode 100644 (file)
index 0000000..7dd3dba
--- /dev/null
@@ -0,0 +1,346 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <linux/refcount.h>
+#include <linux/idr.h>
+
+#include "spectrum.h"
+#include "reg.h"
+
+struct mlxsw_sp_pgt {
+       struct idr pgt_idr;
+       u16 end_index; /* Exclusive. */
+       struct mutex lock; /* Protects PGT. */
+       bool smpe_index_valid;
+};
+
+struct mlxsw_sp_pgt_entry {
+       struct list_head ports_list;
+       u16 index;
+       u16 smpe_index;
+};
+
+struct mlxsw_sp_pgt_entry_port {
+       struct list_head list; /* Member of 'ports_list'. */
+       u16 local_port;
+};
+
+int mlxsw_sp_pgt_mid_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_mid)
+{
+       int index, err = 0;
+
+       mutex_lock(&mlxsw_sp->pgt->lock);
+       index = idr_alloc(&mlxsw_sp->pgt->pgt_idr, NULL, 0,
+                         mlxsw_sp->pgt->end_index, GFP_KERNEL);
+
+       if (index < 0) {
+               err = index;
+               goto err_idr_alloc;
+       }
+
+       *p_mid = index;
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+       return 0;
+
+err_idr_alloc:
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+       return err;
+}
+
+void mlxsw_sp_pgt_mid_free(struct mlxsw_sp *mlxsw_sp, u16 mid_base)
+{
+       mutex_lock(&mlxsw_sp->pgt->lock);
+       WARN_ON(idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base));
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+}
+
+int
+mlxsw_sp_pgt_mid_alloc_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count)
+{
+       unsigned int idr_cursor;
+       int i, err;
+
+       mutex_lock(&mlxsw_sp->pgt->lock);
+
+       /* This function is supposed to be called several times as part of
+        * driver init, in specific order. Verify that the mid_index is the
+        * first free index in the idr, to be able to free the indexes in case
+        * of error.
+        */
+       idr_cursor = idr_get_cursor(&mlxsw_sp->pgt->pgt_idr);
+       if (WARN_ON(idr_cursor != mid_base)) {
+               err = -EINVAL;
+               goto err_idr_cursor;
+       }
+
+       for (i = 0; i < count; i++) {
+               err = idr_alloc_cyclic(&mlxsw_sp->pgt->pgt_idr, NULL,
+                                      mid_base, mid_base + count, GFP_KERNEL);
+               if (err < 0)
+                       goto err_idr_alloc_cyclic;
+       }
+
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+       return 0;
+
+err_idr_alloc_cyclic:
+       for (i--; i >= 0; i--)
+               idr_remove(&mlxsw_sp->pgt->pgt_idr, mid_base + i);
+err_idr_cursor:
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+       return err;
+}
+
+void
+mlxsw_sp_pgt_mid_free_range(struct mlxsw_sp *mlxsw_sp, u16 mid_base, u16 count)
+{
+       struct idr *pgt_idr = &mlxsw_sp->pgt->pgt_idr;
+       int i;
+
+       mutex_lock(&mlxsw_sp->pgt->lock);
+
+       for (i = 0; i < count; i++)
+               WARN_ON_ONCE(idr_remove(pgt_idr, mid_base + i));
+
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+}
+
+static struct mlxsw_sp_pgt_entry_port *
+mlxsw_sp_pgt_entry_port_lookup(struct mlxsw_sp_pgt_entry *pgt_entry,
+                              u16 local_port)
+{
+       struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
+
+       list_for_each_entry(pgt_entry_port, &pgt_entry->ports_list, list) {
+               if (pgt_entry_port->local_port == local_port)
+                       return pgt_entry_port;
+       }
+
+       return NULL;
+}
+
+static struct mlxsw_sp_pgt_entry *
+mlxsw_sp_pgt_entry_create(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe)
+{
+       struct mlxsw_sp_pgt_entry *pgt_entry;
+       void *ret;
+       int err;
+
+       pgt_entry = kzalloc(sizeof(*pgt_entry), GFP_KERNEL);
+       if (!pgt_entry)
+               return ERR_PTR(-ENOMEM);
+
+       ret = idr_replace(&pgt->pgt_idr, pgt_entry, mid);
+       if (IS_ERR(ret)) {
+               err = PTR_ERR(ret);
+               goto err_idr_replace;
+       }
+
+       INIT_LIST_HEAD(&pgt_entry->ports_list);
+       pgt_entry->index = mid;
+       pgt_entry->smpe_index = smpe;
+       return pgt_entry;
+
+err_idr_replace:
+       kfree(pgt_entry);
+       return ERR_PTR(err);
+}
+
+static void mlxsw_sp_pgt_entry_destroy(struct mlxsw_sp_pgt *pgt,
+                                      struct mlxsw_sp_pgt_entry *pgt_entry)
+{
+       WARN_ON(!list_empty(&pgt_entry->ports_list));
+
+       pgt_entry = idr_replace(&pgt->pgt_idr, NULL, pgt_entry->index);
+       if (WARN_ON(IS_ERR(pgt_entry)))
+               return;
+
+       kfree(pgt_entry);
+}
+
+static struct mlxsw_sp_pgt_entry *
+mlxsw_sp_pgt_entry_get(struct mlxsw_sp_pgt *pgt, u16 mid, u16 smpe)
+{
+       struct mlxsw_sp_pgt_entry *pgt_entry;
+
+       pgt_entry = idr_find(&pgt->pgt_idr, mid);
+       if (pgt_entry)
+               return pgt_entry;
+
+       return mlxsw_sp_pgt_entry_create(pgt, mid, smpe);
+}
+
+static void mlxsw_sp_pgt_entry_put(struct mlxsw_sp_pgt *pgt, u16 mid)
+{
+       struct mlxsw_sp_pgt_entry *pgt_entry;
+
+       pgt_entry = idr_find(&pgt->pgt_idr, mid);
+       if (WARN_ON(!pgt_entry))
+               return;
+
+       if (list_empty(&pgt_entry->ports_list))
+               mlxsw_sp_pgt_entry_destroy(pgt, pgt_entry);
+}
+
+static void mlxsw_sp_pgt_smid2_port_set(char *smid2_pl, u16 local_port,
+                                       bool member)
+{
+       mlxsw_reg_smid2_port_set(smid2_pl, local_port, member);
+       mlxsw_reg_smid2_port_mask_set(smid2_pl, local_port, 1);
+}
+
+static int
+mlxsw_sp_pgt_entry_port_write(struct mlxsw_sp *mlxsw_sp,
+                             const struct mlxsw_sp_pgt_entry *pgt_entry,
+                             u16 local_port, bool member)
+{
+       char *smid2_pl;
+       int err;
+
+       smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL);
+       if (!smid2_pl)
+               return -ENOMEM;
+
+       mlxsw_reg_smid2_pack(smid2_pl, pgt_entry->index, 0, 0,
+                            mlxsw_sp->pgt->smpe_index_valid,
+                            pgt_entry->smpe_index);
+
+       mlxsw_sp_pgt_smid2_port_set(smid2_pl, local_port, member);
+       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl);
+
+       kfree(smid2_pl);
+
+       return err;
+}
+
+static struct mlxsw_sp_pgt_entry_port *
+mlxsw_sp_pgt_entry_port_create(struct mlxsw_sp *mlxsw_sp,
+                              struct mlxsw_sp_pgt_entry *pgt_entry,
+                              u16 local_port)
+{
+       struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
+       int err;
+
+       pgt_entry_port = kzalloc(sizeof(*pgt_entry_port), GFP_KERNEL);
+       if (!pgt_entry_port)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry, local_port,
+                                           true);
+       if (err)
+               goto err_pgt_entry_port_write;
+
+       pgt_entry_port->local_port = local_port;
+       list_add(&pgt_entry_port->list, &pgt_entry->ports_list);
+
+       return pgt_entry_port;
+
+err_pgt_entry_port_write:
+       kfree(pgt_entry_port);
+       return ERR_PTR(err);
+}
+
+static void
+mlxsw_sp_pgt_entry_port_destroy(struct mlxsw_sp *mlxsw_sp,
+                               struct mlxsw_sp_pgt_entry *pgt_entry,
+                               struct mlxsw_sp_pgt_entry_port *pgt_entry_port)
+
+{
+       list_del(&pgt_entry_port->list);
+       mlxsw_sp_pgt_entry_port_write(mlxsw_sp, pgt_entry,
+                                     pgt_entry_port->local_port, false);
+       kfree(pgt_entry_port);
+}
+
+static int mlxsw_sp_pgt_entry_port_add(struct mlxsw_sp *mlxsw_sp, u16 mid,
+                                      u16 smpe, u16 local_port)
+{
+       struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
+       struct mlxsw_sp_pgt_entry *pgt_entry;
+       int err;
+
+       mutex_lock(&mlxsw_sp->pgt->lock);
+
+       pgt_entry = mlxsw_sp_pgt_entry_get(mlxsw_sp->pgt, mid, smpe);
+       if (IS_ERR(pgt_entry)) {
+               err = PTR_ERR(pgt_entry);
+               goto err_pgt_entry_get;
+       }
+
+       pgt_entry_port = mlxsw_sp_pgt_entry_port_create(mlxsw_sp, pgt_entry,
+                                                       local_port);
+       if (IS_ERR(pgt_entry_port)) {
+               err = PTR_ERR(pgt_entry_port);
+               goto err_pgt_entry_port_get;
+       }
+
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+       return 0;
+
+err_pgt_entry_port_get:
+       mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid);
+err_pgt_entry_get:
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+       return err;
+}
+
+static void mlxsw_sp_pgt_entry_port_del(struct mlxsw_sp *mlxsw_sp,
+                                       u16 mid, u16 smpe, u16 local_port)
+{
+       struct mlxsw_sp_pgt_entry_port *pgt_entry_port;
+       struct mlxsw_sp_pgt_entry *pgt_entry;
+
+       mutex_lock(&mlxsw_sp->pgt->lock);
+
+       pgt_entry = idr_find(&mlxsw_sp->pgt->pgt_idr, mid);
+       if (!pgt_entry)
+               goto out;
+
+       pgt_entry_port = mlxsw_sp_pgt_entry_port_lookup(pgt_entry, local_port);
+       if (!pgt_entry_port)
+               goto out;
+
+       mlxsw_sp_pgt_entry_port_destroy(mlxsw_sp, pgt_entry, pgt_entry_port);
+       mlxsw_sp_pgt_entry_put(mlxsw_sp->pgt, mid);
+
+out:
+       mutex_unlock(&mlxsw_sp->pgt->lock);
+}
+
+int mlxsw_sp_pgt_entry_port_set(struct mlxsw_sp *mlxsw_sp, u16 mid,
+                               u16 smpe, u16 local_port, bool member)
+{
+       if (member)
+               return mlxsw_sp_pgt_entry_port_add(mlxsw_sp, mid, smpe,
+                                                  local_port);
+
+       mlxsw_sp_pgt_entry_port_del(mlxsw_sp, mid, smpe, local_port);
+       return 0;
+}
+
+int mlxsw_sp_pgt_init(struct mlxsw_sp *mlxsw_sp)
+{
+       struct mlxsw_sp_pgt *pgt;
+
+       if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, PGT_SIZE))
+               return -EIO;
+
+       pgt = kzalloc(sizeof(*mlxsw_sp->pgt), GFP_KERNEL);
+       if (!pgt)
+               return -ENOMEM;
+
+       idr_init(&pgt->pgt_idr);
+       pgt->end_index = MLXSW_CORE_RES_GET(mlxsw_sp->core, PGT_SIZE);
+       mutex_init(&pgt->lock);
+       pgt->smpe_index_valid = mlxsw_sp->pgt_smpe_index_valid;
+       mlxsw_sp->pgt = pgt;
+       return 0;
+}
+
+void mlxsw_sp_pgt_fini(struct mlxsw_sp *mlxsw_sp)
+{
+       mutex_destroy(&mlxsw_sp->pgt->lock);
+       WARN_ON(!idr_is_empty(&mlxsw_sp->pgt->pgt_idr));
+       idr_destroy(&mlxsw_sp->pgt->pgt_idr);
+       kfree(mlxsw_sp->pgt);
+}
index 0d8a006..09009e8 100644 (file)
@@ -443,65 +443,12 @@ struct mlxsw_sp_fib_entry_decap {
        u32 tunnel_index;
 };
 
-static struct mlxsw_sp_fib_entry_priv *
-mlxsw_sp_fib_entry_priv_create(const struct mlxsw_sp_router_ll_ops *ll_ops)
-{
-       struct mlxsw_sp_fib_entry_priv *priv;
-
-       if (!ll_ops->fib_entry_priv_size)
-               /* No need to have priv */
-               return NULL;
-
-       priv = kzalloc(sizeof(*priv) + ll_ops->fib_entry_priv_size, GFP_KERNEL);
-       if (!priv)
-               return ERR_PTR(-ENOMEM);
-       refcount_set(&priv->refcnt, 1);
-       return priv;
-}
-
-static void
-mlxsw_sp_fib_entry_priv_destroy(struct mlxsw_sp_fib_entry_priv *priv)
-{
-       kfree(priv);
-}
-
-static void mlxsw_sp_fib_entry_priv_hold(struct mlxsw_sp_fib_entry_priv *priv)
-{
-       refcount_inc(&priv->refcnt);
-}
-
-static void mlxsw_sp_fib_entry_priv_put(struct mlxsw_sp_fib_entry_priv *priv)
-{
-       if (!priv || !refcount_dec_and_test(&priv->refcnt))
-               return;
-       mlxsw_sp_fib_entry_priv_destroy(priv);
-}
-
-static void mlxsw_sp_fib_entry_op_ctx_priv_hold(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                               struct mlxsw_sp_fib_entry_priv *priv)
-{
-       if (!priv)
-               return;
-       mlxsw_sp_fib_entry_priv_hold(priv);
-       list_add(&priv->list, &op_ctx->fib_entry_priv_list);
-}
-
-static void mlxsw_sp_fib_entry_op_ctx_priv_put_all(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
-{
-       struct mlxsw_sp_fib_entry_priv *priv, *tmp;
-
-       list_for_each_entry_safe(priv, tmp, &op_ctx->fib_entry_priv_list, list)
-               mlxsw_sp_fib_entry_priv_put(priv);
-       INIT_LIST_HEAD(&op_ctx->fib_entry_priv_list);
-}
-
 struct mlxsw_sp_fib_entry {
        struct mlxsw_sp_fib_node *fib_node;
        enum mlxsw_sp_fib_entry_type type;
        struct list_head nexthop_group_node;
        struct mlxsw_sp_nexthop_group *nh_group;
        struct mlxsw_sp_fib_entry_decap decap; /* Valid for decap entries. */
-       struct mlxsw_sp_fib_entry_priv *priv;
 };
 
 struct mlxsw_sp_fib4_entry {
@@ -537,7 +484,6 @@ struct mlxsw_sp_fib {
        struct mlxsw_sp_vr *vr;
        struct mlxsw_sp_lpm_tree *lpm_tree;
        enum mlxsw_sp_l3proto proto;
-       const struct mlxsw_sp_router_ll_ops *ll_ops;
 };
 
 struct mlxsw_sp_vr {
@@ -551,45 +497,16 @@ struct mlxsw_sp_vr {
        refcount_t ul_rif_refcnt;
 };
 
-static int mlxsw_sp_router_ll_basic_init(struct mlxsw_sp *mlxsw_sp, u16 vr_id,
-                                        enum mlxsw_sp_l3proto proto)
-{
-       return 0;
-}
-
-static int mlxsw_sp_router_ll_basic_ralta_write(struct mlxsw_sp *mlxsw_sp, char *xralta_pl)
-{
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta),
-                              xralta_pl + MLXSW_REG_XRALTA_RALTA_OFFSET);
-}
-
-static int mlxsw_sp_router_ll_basic_ralst_write(struct mlxsw_sp *mlxsw_sp, char *xralst_pl)
-{
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst),
-                              xralst_pl + MLXSW_REG_XRALST_RALST_OFFSET);
-}
-
-static int mlxsw_sp_router_ll_basic_raltb_write(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl)
-{
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb),
-                              xraltb_pl + MLXSW_REG_XRALTB_RALTB_OFFSET);
-}
-
 static const struct rhashtable_params mlxsw_sp_fib_ht_params;
 
 static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
                                                struct mlxsw_sp_vr *vr,
                                                enum mlxsw_sp_l3proto proto)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
        struct mlxsw_sp_lpm_tree *lpm_tree;
        struct mlxsw_sp_fib *fib;
        int err;
 
-       err = ll_ops->init(mlxsw_sp, vr->id, proto);
-       if (err)
-               return ERR_PTR(err);
-
        lpm_tree = mlxsw_sp->router->lpm.proto_trees[proto];
        fib = kzalloc(sizeof(*fib), GFP_KERNEL);
        if (!fib)
@@ -601,7 +518,6 @@ static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp *mlxsw_sp,
        fib->proto = proto;
        fib->vr = vr;
        fib->lpm_tree = lpm_tree;
-       fib->ll_ops = ll_ops;
        mlxsw_sp_lpm_tree_hold(lpm_tree);
        err = mlxsw_sp_vr_lpm_tree_bind(mlxsw_sp, fib, lpm_tree->id);
        if (err)
@@ -640,36 +556,33 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
 }
 
 static int mlxsw_sp_lpm_tree_alloc(struct mlxsw_sp *mlxsw_sp,
-                                  const struct mlxsw_sp_router_ll_ops *ll_ops,
                                   struct mlxsw_sp_lpm_tree *lpm_tree)
 {
-       char xralta_pl[MLXSW_REG_XRALTA_LEN];
+       char ralta_pl[MLXSW_REG_RALTA_LEN];
 
-       mlxsw_reg_xralta_pack(xralta_pl, true,
-                             (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
-                             lpm_tree->id);
-       return ll_ops->ralta_write(mlxsw_sp, xralta_pl);
+       mlxsw_reg_ralta_pack(ralta_pl, true,
+                            (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
+                            lpm_tree->id);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
 }
 
 static void mlxsw_sp_lpm_tree_free(struct mlxsw_sp *mlxsw_sp,
-                                  const struct mlxsw_sp_router_ll_ops *ll_ops,
                                   struct mlxsw_sp_lpm_tree *lpm_tree)
 {
-       char xralta_pl[MLXSW_REG_XRALTA_LEN];
+       char ralta_pl[MLXSW_REG_RALTA_LEN];
 
-       mlxsw_reg_xralta_pack(xralta_pl, false,
-                             (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
-                             lpm_tree->id);
-       ll_ops->ralta_write(mlxsw_sp, xralta_pl);
+       mlxsw_reg_ralta_pack(ralta_pl, false,
+                            (enum mlxsw_reg_ralxx_protocol) lpm_tree->proto,
+                            lpm_tree->id);
+       mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralta), ralta_pl);
 }
 
 static int
 mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
-                                 const struct mlxsw_sp_router_ll_ops *ll_ops,
                                  struct mlxsw_sp_prefix_usage *prefix_usage,
                                  struct mlxsw_sp_lpm_tree *lpm_tree)
 {
-       char xralst_pl[MLXSW_REG_XRALST_LEN];
+       char ralst_pl[MLXSW_REG_RALST_LEN];
        u8 root_bin = 0;
        u8 prefix;
        u8 last_prefix = MLXSW_REG_RALST_BIN_NO_CHILD;
@@ -677,20 +590,19 @@ mlxsw_sp_lpm_tree_left_struct_set(struct mlxsw_sp *mlxsw_sp,
        mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage)
                root_bin = prefix;
 
-       mlxsw_reg_xralst_pack(xralst_pl, root_bin, lpm_tree->id);
+       mlxsw_reg_ralst_pack(ralst_pl, root_bin, lpm_tree->id);
        mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) {
                if (prefix == 0)
                        continue;
-               mlxsw_reg_xralst_bin_pack(xralst_pl, prefix, last_prefix,
-                                         MLXSW_REG_RALST_BIN_NO_CHILD);
+               mlxsw_reg_ralst_bin_pack(ralst_pl, prefix, last_prefix,
+                                        MLXSW_REG_RALST_BIN_NO_CHILD);
                last_prefix = prefix;
        }
-       return ll_ops->ralst_write(mlxsw_sp, xralst_pl);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralst), ralst_pl);
 }
 
 static struct mlxsw_sp_lpm_tree *
 mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
-                        const struct mlxsw_sp_router_ll_ops *ll_ops,
                         struct mlxsw_sp_prefix_usage *prefix_usage,
                         enum mlxsw_sp_l3proto proto)
 {
@@ -701,11 +613,12 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
        if (!lpm_tree)
                return ERR_PTR(-EBUSY);
        lpm_tree->proto = proto;
-       err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, ll_ops, lpm_tree);
+       err = mlxsw_sp_lpm_tree_alloc(mlxsw_sp, lpm_tree);
        if (err)
                return ERR_PTR(err);
 
-       err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, ll_ops, prefix_usage, lpm_tree);
+       err = mlxsw_sp_lpm_tree_left_struct_set(mlxsw_sp, prefix_usage,
+                                               lpm_tree);
        if (err)
                goto err_left_struct_set;
        memcpy(&lpm_tree->prefix_usage, prefix_usage,
@@ -716,15 +629,14 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp,
        return lpm_tree;
 
 err_left_struct_set:
-       mlxsw_sp_lpm_tree_free(mlxsw_sp, ll_ops, lpm_tree);
+       mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
        return ERR_PTR(err);
 }
 
 static void mlxsw_sp_lpm_tree_destroy(struct mlxsw_sp *mlxsw_sp,
-                                     const struct mlxsw_sp_router_ll_ops *ll_ops,
                                      struct mlxsw_sp_lpm_tree *lpm_tree)
 {
-       mlxsw_sp_lpm_tree_free(mlxsw_sp, ll_ops, lpm_tree);
+       mlxsw_sp_lpm_tree_free(mlxsw_sp, lpm_tree);
 }
 
 static struct mlxsw_sp_lpm_tree *
@@ -732,7 +644,6 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
                      struct mlxsw_sp_prefix_usage *prefix_usage,
                      enum mlxsw_sp_l3proto proto)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = mlxsw_sp->router->proto_ll_ops[proto];
        struct mlxsw_sp_lpm_tree *lpm_tree;
        int i;
 
@@ -746,7 +657,7 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
                        return lpm_tree;
                }
        }
-       return mlxsw_sp_lpm_tree_create(mlxsw_sp, ll_ops, prefix_usage, proto);
+       return mlxsw_sp_lpm_tree_create(mlxsw_sp, prefix_usage, proto);
 }
 
 static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
@@ -757,11 +668,8 @@ static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree)
 static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp,
                                  struct mlxsw_sp_lpm_tree *lpm_tree)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops =
-                               mlxsw_sp->router->proto_ll_ops[lpm_tree->proto];
-
        if (--lpm_tree->ref_count == 0)
-               mlxsw_sp_lpm_tree_destroy(mlxsw_sp, ll_ops, lpm_tree);
+               mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree);
 }
 
 #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */
@@ -851,23 +759,23 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
 static int mlxsw_sp_vr_lpm_tree_bind(struct mlxsw_sp *mlxsw_sp,
                                     const struct mlxsw_sp_fib *fib, u8 tree_id)
 {
-       char xraltb_pl[MLXSW_REG_XRALTB_LEN];
+       char raltb_pl[MLXSW_REG_RALTB_LEN];
 
-       mlxsw_reg_xraltb_pack(xraltb_pl, fib->vr->id,
-                             (enum mlxsw_reg_ralxx_protocol) fib->proto,
-                             tree_id);
-       return fib->ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
+       mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
+                            (enum mlxsw_reg_ralxx_protocol) fib->proto,
+                            tree_id);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
 }
 
 static int mlxsw_sp_vr_lpm_tree_unbind(struct mlxsw_sp *mlxsw_sp,
                                       const struct mlxsw_sp_fib *fib)
 {
-       char xraltb_pl[MLXSW_REG_XRALTB_LEN];
+       char raltb_pl[MLXSW_REG_RALTB_LEN];
 
        /* Bind to tree 0 which is default */
-       mlxsw_reg_xraltb_pack(xraltb_pl, fib->vr->id,
-                             (enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
-       return fib->ll_ops->raltb_write(mlxsw_sp, xraltb_pl);
+       mlxsw_reg_raltb_pack(raltb_pl, fib->vr->id,
+                            (enum mlxsw_reg_ralxx_protocol) fib->proto, 0);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(raltb), raltb_pl);
 }
 
 static u32 mlxsw_sp_fix_tb_id(u32 tb_id)
@@ -5780,14 +5688,13 @@ mlxsw_sp_fib_entry_hw_flags_clear(struct mlxsw_sp *mlxsw_sp,
 static void
 mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
                                    struct mlxsw_sp_fib_entry *fib_entry,
-                                   enum mlxsw_sp_fib_entry_op op)
+                                   enum mlxsw_reg_ralue_op op)
 {
        switch (op) {
-       case MLXSW_SP_FIB_ENTRY_OP_WRITE:
-       case MLXSW_SP_FIB_ENTRY_OP_UPDATE:
+       case MLXSW_REG_RALUE_OP_WRITE_WRITE:
                mlxsw_sp_fib_entry_hw_flags_set(mlxsw_sp, fib_entry);
                break;
-       case MLXSW_SP_FIB_ENTRY_OP_DELETE:
+       case MLXSW_REG_RALUE_OP_WRITE_DELETE:
                mlxsw_sp_fib_entry_hw_flags_clear(mlxsw_sp, fib_entry);
                break;
        default:
@@ -5795,140 +5702,39 @@ mlxsw_sp_fib_entry_hw_flags_refresh(struct mlxsw_sp *mlxsw_sp,
        }
 }
 
-struct mlxsw_sp_fib_entry_op_ctx_basic {
-       char ralue_pl[MLXSW_REG_RALUE_LEN];
-};
-
 static void
-mlxsw_sp_router_ll_basic_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                       enum mlxsw_sp_l3proto proto,
-                                       enum mlxsw_sp_fib_entry_op op,
-                                       u16 virtual_router, u8 prefix_len,
-                                       unsigned char *addr,
-                                       struct mlxsw_sp_fib_entry_priv *priv)
+mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl,
+                             const struct mlxsw_sp_fib_entry *fib_entry,
+                             enum mlxsw_reg_ralue_op op)
 {
-       struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
-       enum mlxsw_reg_ralxx_protocol ralxx_proto;
-       char *ralue_pl = op_ctx_basic->ralue_pl;
-       enum mlxsw_reg_ralue_op ralue_op;
-
-       ralxx_proto = (enum mlxsw_reg_ralxx_protocol) proto;
+       struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
+       enum mlxsw_reg_ralxx_protocol proto;
+       u32 *p_dip;
 
-       switch (op) {
-       case MLXSW_SP_FIB_ENTRY_OP_WRITE:
-       case MLXSW_SP_FIB_ENTRY_OP_UPDATE:
-               ralue_op = MLXSW_REG_RALUE_OP_WRITE_WRITE;
-               break;
-       case MLXSW_SP_FIB_ENTRY_OP_DELETE:
-               ralue_op = MLXSW_REG_RALUE_OP_WRITE_DELETE;
-               break;
-       default:
-               WARN_ON_ONCE(1);
-               return;
-       }
+       proto = (enum mlxsw_reg_ralxx_protocol) fib->proto;
 
-       switch (proto) {
+       switch (fib->proto) {
        case MLXSW_SP_L3_PROTO_IPV4:
-               mlxsw_reg_ralue_pack4(ralue_pl, ralxx_proto, ralue_op,
-                                     virtual_router, prefix_len, (u32 *) addr);
+               p_dip = (u32 *) fib_entry->fib_node->key.addr;
+               mlxsw_reg_ralue_pack4(ralue_pl, proto, op, fib->vr->id,
+                                     fib_entry->fib_node->key.prefix_len,
+                                     *p_dip);
                break;
        case MLXSW_SP_L3_PROTO_IPV6:
-               mlxsw_reg_ralue_pack6(ralue_pl, ralxx_proto, ralue_op,
-                                     virtual_router, prefix_len, addr);
+               mlxsw_reg_ralue_pack6(ralue_pl, proto, op, fib->vr->id,
+                                     fib_entry->fib_node->key.prefix_len,
+                                     fib_entry->fib_node->key.addr);
                break;
        }
 }
 
-static void
-mlxsw_sp_router_ll_basic_fib_entry_act_remote_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                  enum mlxsw_reg_ralue_trap_action trap_action,
-                                                  u16 trap_id, u32 adjacency_index, u16 ecmp_size)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_ralue_act_remote_pack(op_ctx_basic->ralue_pl, trap_action,
-                                       trap_id, adjacency_index, ecmp_size);
-}
-
-static void
-mlxsw_sp_router_ll_basic_fib_entry_act_local_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                 enum mlxsw_reg_ralue_trap_action trap_action,
-                                                 u16 trap_id, u16 local_erif)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_ralue_act_local_pack(op_ctx_basic->ralue_pl, trap_action,
-                                      trap_id, local_erif);
-}
-
-static void
-mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_ralue_act_ip2me_pack(op_ctx_basic->ralue_pl);
-}
-
-static void
-mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_tun_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                     u32 tunnel_ptr)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_ralue_act_ip2me_tun_pack(op_ctx_basic->ralue_pl, tunnel_ptr);
-}
-
-static int
-mlxsw_sp_router_ll_basic_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
-                                         struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                         bool *postponed_for_bulk)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_basic *op_ctx_basic = (void *) op_ctx->ll_priv;
-
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue),
-                              op_ctx_basic->ralue_pl);
-}
-
-static bool
-mlxsw_sp_router_ll_basic_fib_entry_is_committed(struct mlxsw_sp_fib_entry_priv *priv)
-{
-       return true;
-}
-
-static void mlxsw_sp_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                   struct mlxsw_sp_fib_entry *fib_entry,
-                                   enum mlxsw_sp_fib_entry_op op)
-{
-       struct mlxsw_sp_fib *fib = fib_entry->fib_node->fib;
-
-       mlxsw_sp_fib_entry_op_ctx_priv_hold(op_ctx, fib_entry->priv);
-       fib->ll_ops->fib_entry_pack(op_ctx, fib->proto, op, fib->vr->id,
-                                   fib_entry->fib_node->key.prefix_len,
-                                   fib_entry->fib_node->key.addr,
-                                   fib_entry->priv);
-}
-
-static int mlxsw_sp_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
-                                    struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                    const struct mlxsw_sp_router_ll_ops *ll_ops)
-{
-       bool postponed_for_bulk = false;
-       int err;
-
-       err = ll_ops->fib_entry_commit(mlxsw_sp, op_ctx, &postponed_for_bulk);
-       if (!postponed_for_bulk)
-               mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
-       return err;
-}
-
 static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
-                                       struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                        struct mlxsw_sp_fib_entry *fib_entry,
-                                       enum mlxsw_sp_fib_entry_op op)
+                                       enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
        struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group;
        struct mlxsw_sp_nexthop_group_info *nhgi = nh_group->nhgi;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
        enum mlxsw_reg_ralue_trap_action trap_action;
        u16 trap_id = 0;
        u32 adjacency_index = 0;
@@ -5951,20 +5757,19 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp,
                trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
        }
 
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_remote_pack(op_ctx, trap_action, trap_id,
-                                         adjacency_index, ecmp_size);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_remote_pack(ralue_pl, trap_action, trap_id,
+                                       adjacency_index, ecmp_size);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
-                                      struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                       struct mlxsw_sp_fib_entry *fib_entry,
-                                      enum mlxsw_sp_fib_entry_op op)
+                                      enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
        struct mlxsw_sp_rif *rif = fib_entry->nh_group->nhgi->nh_rif;
        enum mlxsw_reg_ralue_trap_action trap_action;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
        u16 trap_id = 0;
        u16 rif_index = 0;
 
@@ -5976,64 +5781,61 @@ static int mlxsw_sp_fib_entry_op_local(struct mlxsw_sp *mlxsw_sp,
                trap_id = MLXSW_TRAP_ID_RTR_INGRESS0;
        }
 
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_local_pack(op_ctx, trap_action, trap_id, rif_index);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id,
+                                      rif_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,
-                                     struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                      struct mlxsw_sp_fib_entry *fib_entry,
-                                     enum mlxsw_sp_fib_entry_op op)
+                                     enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
 
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_ip2me_pack(op_ctx);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_ip2me_pack(ralue_pl);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp,
-                                          struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                           struct mlxsw_sp_fib_entry *fib_entry,
-                                          enum mlxsw_sp_fib_entry_op op)
+                                          enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
        enum mlxsw_reg_ralue_trap_action trap_action;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
 
        trap_action = MLXSW_REG_RALUE_TRAP_ACTION_DISCARD_ERROR;
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_local_pack(op_ctx, trap_action, 0, 0);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, 0, 0);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int
 mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp,
-                                 struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                  struct mlxsw_sp_fib_entry *fib_entry,
-                                 enum mlxsw_sp_fib_entry_op op)
+                                 enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
        enum mlxsw_reg_ralue_trap_action trap_action;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
        u16 trap_id;
 
        trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP;
        trap_id = MLXSW_TRAP_ID_RTR_INGRESS1;
 
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_local_pack(op_ctx, trap_action, trap_id, 0);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int
 mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
-                                struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                 struct mlxsw_sp_fib_entry *fib_entry,
-                                enum mlxsw_sp_fib_entry_op op)
+                                enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
        struct mlxsw_sp_ipip_entry *ipip_entry = fib_entry->decap.ipip_entry;
        const struct mlxsw_sp_ipip_ops *ipip_ops;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
        int err;
 
        if (WARN_ON(!ipip_entry))
@@ -6045,55 +5847,54 @@ mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp,
        if (err)
                return err;
 
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_ip2me_tun_pack(op_ctx,
-                                            fib_entry->decap.tunnel_index);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,
+                                          fib_entry->decap.tunnel_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int mlxsw_sp_fib_entry_op_nve_decap(struct mlxsw_sp *mlxsw_sp,
-                                          struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                           struct mlxsw_sp_fib_entry *fib_entry,
-                                          enum mlxsw_sp_fib_entry_op op)
+                                          enum mlxsw_reg_ralue_op op)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
+       char ralue_pl[MLXSW_REG_RALUE_LEN];
 
-       mlxsw_sp_fib_entry_pack(op_ctx, fib_entry, op);
-       ll_ops->fib_entry_act_ip2me_tun_pack(op_ctx,
-                                            fib_entry->decap.tunnel_index);
-       return mlxsw_sp_fib_entry_commit(mlxsw_sp, op_ctx, ll_ops);
+       mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op);
+       mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,
+                                          fib_entry->decap.tunnel_index);
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl);
 }
 
 static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
-                                  struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                   struct mlxsw_sp_fib_entry *fib_entry,
-                                  enum mlxsw_sp_fib_entry_op op)
+                                  enum mlxsw_reg_ralue_op op)
 {
        switch (fib_entry->type) {
        case MLXSW_SP_FIB_ENTRY_TYPE_REMOTE:
-               return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_remote(mlxsw_sp, fib_entry, op);
        case MLXSW_SP_FIB_ENTRY_TYPE_LOCAL:
-               return mlxsw_sp_fib_entry_op_local(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_local(mlxsw_sp, fib_entry, op);
        case MLXSW_SP_FIB_ENTRY_TYPE_TRAP:
-               return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op);
        case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE:
-               return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op);
        case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE:
-               return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry,
+                                                        op);
        case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:
-               return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,
+                                                       fib_entry, op);
        case MLXSW_SP_FIB_ENTRY_TYPE_NVE_DECAP:
-               return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, op_ctx, fib_entry, op);
+               return mlxsw_sp_fib_entry_op_nve_decap(mlxsw_sp, fib_entry, op);
        }
        return -EINVAL;
 }
 
 static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
-                                struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                 struct mlxsw_sp_fib_entry *fib_entry,
-                                enum mlxsw_sp_fib_entry_op op)
+                                enum mlxsw_reg_ralue_op op)
 {
-       int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, op_ctx, fib_entry, op);
+       int err = __mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry, op);
 
        if (err)
                return err;
@@ -6103,35 +5904,18 @@ static int mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,
        return err;
 }
 
-static int __mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
-                                      struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                      struct mlxsw_sp_fib_entry *fib_entry,
-                                      bool is_new)
-{
-       return mlxsw_sp_fib_entry_op(mlxsw_sp, op_ctx, fib_entry,
-                                    is_new ? MLXSW_SP_FIB_ENTRY_OP_WRITE :
-                                             MLXSW_SP_FIB_ENTRY_OP_UPDATE);
-}
-
 static int mlxsw_sp_fib_entry_update(struct mlxsw_sp *mlxsw_sp,
                                     struct mlxsw_sp_fib_entry *fib_entry)
 {
-       struct mlxsw_sp_fib_entry_op_ctx *op_ctx = mlxsw_sp->router->ll_op_ctx;
-
-       mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
-       return __mlxsw_sp_fib_entry_update(mlxsw_sp, op_ctx, fib_entry, false);
+       return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
+                                    MLXSW_REG_RALUE_OP_WRITE_WRITE);
 }
 
 static int mlxsw_sp_fib_entry_del(struct mlxsw_sp *mlxsw_sp,
-                                 struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                  struct mlxsw_sp_fib_entry *fib_entry)
 {
-       const struct mlxsw_sp_router_ll_ops *ll_ops = fib_entry->fib_node->fib->ll_ops;
-
-       if (!ll_ops->fib_entry_is_committed(fib_entry->priv))
-               return 0;
-       return mlxsw_sp_fib_entry_op(mlxsw_sp, op_ctx, fib_entry,
-                                    MLXSW_SP_FIB_ENTRY_OP_DELETE);
+       return mlxsw_sp_fib_entry_op(mlxsw_sp, fib_entry,
+                                    MLXSW_REG_RALUE_OP_WRITE_DELETE);
 }
 
 static int
@@ -6226,12 +6010,6 @@ mlxsw_sp_fib4_entry_create(struct mlxsw_sp *mlxsw_sp,
                return ERR_PTR(-ENOMEM);
        fib_entry = &fib4_entry->common;
 
-       fib_entry->priv = mlxsw_sp_fib_entry_priv_create(fib_node->fib->ll_ops);
-       if (IS_ERR(fib_entry->priv)) {
-               err = PTR_ERR(fib_entry->priv);
-               goto err_fib_entry_priv_create;
-       }
-
        err = mlxsw_sp_nexthop4_group_get(mlxsw_sp, fib_entry, fen_info->fi);
        if (err)
                goto err_nexthop4_group_get;
@@ -6260,8 +6038,6 @@ err_fib4_entry_type_set:
 err_nexthop_group_vr_link:
        mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
 err_nexthop4_group_get:
-       mlxsw_sp_fib_entry_priv_put(fib_entry->priv);
-err_fib_entry_priv_create:
        kfree(fib4_entry);
        return ERR_PTR(err);
 }
@@ -6276,7 +6052,6 @@ static void mlxsw_sp_fib4_entry_destroy(struct mlxsw_sp *mlxsw_sp,
        mlxsw_sp_nexthop_group_vr_unlink(fib4_entry->common.nh_group,
                                         fib_node->fib);
        mlxsw_sp_nexthop4_group_put(mlxsw_sp, &fib4_entry->common);
-       mlxsw_sp_fib_entry_priv_put(fib4_entry->common.priv);
        kfree(fib4_entry);
 }
 
@@ -6514,16 +6289,14 @@ static void mlxsw_sp_fib_node_put(struct mlxsw_sp *mlxsw_sp,
 }
 
 static int mlxsw_sp_fib_node_entry_link(struct mlxsw_sp *mlxsw_sp,
-                                       struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                        struct mlxsw_sp_fib_entry *fib_entry)
 {
        struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
-       bool is_new = !fib_node->fib_entry;
        int err;
 
        fib_node->fib_entry = fib_entry;
 
-       err = __mlxsw_sp_fib_entry_update(mlxsw_sp, op_ctx, fib_entry, is_new);
+       err = mlxsw_sp_fib_entry_update(mlxsw_sp, fib_entry);
        if (err)
                goto err_fib_entry_update;
 
@@ -6534,25 +6307,14 @@ err_fib_entry_update:
        return err;
 }
 
-static int __mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
-                                           struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                           struct mlxsw_sp_fib_entry *fib_entry)
+static void
+mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
+                              struct mlxsw_sp_fib_entry *fib_entry)
 {
        struct mlxsw_sp_fib_node *fib_node = fib_entry->fib_node;
-       int err;
 
-       err = mlxsw_sp_fib_entry_del(mlxsw_sp, op_ctx, fib_entry);
+       mlxsw_sp_fib_entry_del(mlxsw_sp, fib_entry);
        fib_node->fib_entry = NULL;
-       return err;
-}
-
-static void mlxsw_sp_fib_node_entry_unlink(struct mlxsw_sp *mlxsw_sp,
-                                          struct mlxsw_sp_fib_entry *fib_entry)
-{
-       struct mlxsw_sp_fib_entry_op_ctx *op_ctx = mlxsw_sp->router->ll_op_ctx;
-
-       mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
-       __mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, op_ctx, fib_entry);
 }
 
 static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
@@ -6574,7 +6336,6 @@ static bool mlxsw_sp_fib4_allow_replace(struct mlxsw_sp_fib4_entry *fib4_entry)
 
 static int
 mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
-                            struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                             const struct fib_entry_notifier_info *fen_info)
 {
        struct mlxsw_sp_fib4_entry *fib4_entry, *fib4_replaced;
@@ -6609,7 +6370,7 @@ mlxsw_sp_router_fib4_replace(struct mlxsw_sp *mlxsw_sp,
        }
 
        replaced = fib_node->fib_entry;
-       err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, op_ctx, &fib4_entry->common);
+       err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib4_entry->common);
        if (err) {
                dev_warn(mlxsw_sp->bus_info->dev, "Failed to link FIB entry to node\n");
                goto err_fib_node_entry_link;
@@ -6634,23 +6395,20 @@ err_fib4_entry_create:
        return err;
 }
 
-static int mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
-                                   struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                   struct fib_entry_notifier_info *fen_info)
+static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
+                                    struct fib_entry_notifier_info *fen_info)
 {
        struct mlxsw_sp_fib4_entry *fib4_entry;
        struct mlxsw_sp_fib_node *fib_node;
-       int err;
 
        fib4_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
        if (!fib4_entry)
-               return 0;
+               return;
        fib_node = fib4_entry->common.fib_node;
 
-       err = __mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, op_ctx, &fib4_entry->common);
+       mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib4_entry->common);
        mlxsw_sp_fib4_entry_destroy(mlxsw_sp, fib4_entry);
        mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
-       return err;
 }
 
 static bool mlxsw_sp_fib6_rt_should_ignore(const struct fib6_info *rt)
@@ -6958,9 +6716,9 @@ static void mlxsw_sp_nexthop6_group_put(struct mlxsw_sp *mlxsw_sp,
        mlxsw_sp_nexthop6_group_destroy(mlxsw_sp, nh_grp);
 }
 
-static int mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
-                                         struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                         struct mlxsw_sp_fib6_entry *fib6_entry)
+static int
+mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
+                              struct mlxsw_sp_fib6_entry *fib6_entry)
 {
        struct mlxsw_sp_nexthop_group *old_nh_grp = fib6_entry->common.nh_group;
        struct mlxsw_sp_fib_node *fib_node = fib6_entry->common.fib_node;
@@ -6983,8 +6741,7 @@ static int mlxsw_sp_nexthop6_group_update(struct mlxsw_sp *mlxsw_sp,
         * currently associated with it in the device's table is that
         * of the old group. Start using the new one instead.
         */
-       err = __mlxsw_sp_fib_entry_update(mlxsw_sp, op_ctx,
-                                         &fib6_entry->common, false);
+       err = mlxsw_sp_fib_entry_update(mlxsw_sp, &fib6_entry->common);
        if (err)
                goto err_fib_entry_update;
 
@@ -7008,7 +6765,6 @@ err_nexthop6_group_get:
 
 static int
 mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
-                               struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                struct mlxsw_sp_fib6_entry *fib6_entry,
                                struct fib6_info **rt_arr, unsigned int nrt6)
 {
@@ -7026,7 +6782,7 @@ mlxsw_sp_fib6_entry_nexthop_add(struct mlxsw_sp *mlxsw_sp,
                fib6_entry->nrt6++;
        }
 
-       err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, op_ctx, fib6_entry);
+       err = mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
        if (err)
                goto err_rt6_unwind;
 
@@ -7045,7 +6801,6 @@ err_rt6_unwind:
 
 static void
 mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
-                               struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
                                struct mlxsw_sp_fib6_entry *fib6_entry,
                                struct fib6_info **rt_arr, unsigned int nrt6)
 {
@@ -7063,7 +6818,7 @@ mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,
                mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
        }
 
-       mlxsw_sp_nexthop6_group_update(mlxsw_sp, op_ctx, fib6_entry);
+       mlxsw_sp_nexthop6_group_update(mlxsw_sp, fib6_entry);
 }
 
 static int
@@ -7149,12 +6904,6 @@ mlxsw_sp_fib6_entry_create(struct mlxsw_sp *mlxsw_sp,
                return ERR_PTR(-ENOMEM);
        fib_entry = &fib6_entry->common;
 
-       fib_entry->priv = mlxsw_sp_fib_entry_priv_create(fib_node->fib->ll_ops);
-       if (IS_ERR(fib_entry->priv)) {
-               err = PTR_ERR(fib_entry->priv);
-               goto err_fib_entry_priv_create;
-       }
-
        INIT_LIST_HEAD(&fib6_entry->rt6_list);
 
        for (i = 0; i < nrt6; i++) {
@@ -7196,8 +6945,6 @@ err_rt6_unwind:
                list_del(&mlxsw_sp_rt6->list);
                mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);
        }
-       mlxsw_sp_fib_entry_priv_put(fib_entry->priv);
-err_fib_entry_priv_create:
        kfree(fib6_entry);
        return ERR_PTR(err);
 }
@@ -7220,7 +6967,6 @@ static void mlxsw_sp_fib6_entry_destroy(struct mlxsw_sp *mlxsw_sp,
        mlxsw_sp_nexthop6_group_put(mlxsw_sp, &fib6_entry->common);
        mlxsw_sp_fib6_entry_rt_destroy_all(fib6_entry);
        WARN_ON(fib6_entry->nrt6);
-       mlxsw_sp_fib_entry_priv_put(fib6_entry->common.priv);
        kfree(fib6_entry);
 }
 
@@ -7278,8 +7024,8 @@ static bool mlxsw_sp_fib6_allow_replace(struct mlxsw_sp_fib6_entry *fib6_entry)
 }
 
 static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
-                                       struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                       struct fib6_info **rt_arr, unsigned int nrt6)
+                                       struct fib6_info **rt_arr,
+                                       unsigned int nrt6)
 {
        struct mlxsw_sp_fib6_entry *fib6_entry, *fib6_replaced;
        struct mlxsw_sp_fib_entry *replaced;
@@ -7318,7 +7064,7 @@ static int mlxsw_sp_router_fib6_replace(struct mlxsw_sp *mlxsw_sp,
        }
 
        replaced = fib_node->fib_entry;
-       err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, op_ctx, &fib6_entry->common);
+       err = mlxsw_sp_fib_node_entry_link(mlxsw_sp, &fib6_entry->common);
        if (err)
                goto err_fib_node_entry_link;
 
@@ -7342,8 +7088,8 @@ err_fib6_entry_create:
 }
 
 static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
-                                      struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                      struct fib6_info **rt_arr, unsigned int nrt6)
+                                      struct fib6_info **rt_arr,
+                                      unsigned int nrt6)
 {
        struct mlxsw_sp_fib6_entry *fib6_entry;
        struct mlxsw_sp_fib_node *fib_node;
@@ -7371,7 +7117,8 @@ static int mlxsw_sp_router_fib6_append(struct mlxsw_sp *mlxsw_sp,
 
        fib6_entry = container_of(fib_node->fib_entry,
                                  struct mlxsw_sp_fib6_entry, common);
-       err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, op_ctx, fib6_entry, rt_arr, nrt6);
+       err = mlxsw_sp_fib6_entry_nexthop_add(mlxsw_sp, fib6_entry, rt_arr,
+                                             nrt6);
        if (err)
                goto err_fib6_entry_nexthop_add;
 
@@ -7382,17 +7129,16 @@ err_fib6_entry_nexthop_add:
        return err;
 }
 
-static int mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
-                                   struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                   struct fib6_info **rt_arr, unsigned int nrt6)
+static void mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
+                                    struct fib6_info **rt_arr,
+                                    unsigned int nrt6)
 {
        struct mlxsw_sp_fib6_entry *fib6_entry;
        struct mlxsw_sp_fib_node *fib_node;
        struct fib6_info *rt = rt_arr[0];
-       int err;
 
        if (mlxsw_sp_fib6_rt_should_ignore(rt))
-               return 0;
+               return;
 
        /* Multipath routes are first added to the FIB trie and only then
         * notified. If we vetoed the addition, we will get a delete
@@ -7401,22 +7147,22 @@ static int mlxsw_sp_router_fib6_del(struct mlxsw_sp *mlxsw_sp,
         */
        fib6_entry = mlxsw_sp_fib6_entry_lookup(mlxsw_sp, rt);
        if (!fib6_entry)
-               return 0;
+               return;
 
        /* If not all the nexthops are deleted, then only reduce the nexthop
         * group.
         */
        if (nrt6 != fib6_entry->nrt6) {
-               mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, op_ctx, fib6_entry, rt_arr, nrt6);
-               return 0;
+               mlxsw_sp_fib6_entry_nexthop_del(mlxsw_sp, fib6_entry, rt_arr,
+                                               nrt6);
+               return;
        }
 
        fib_node = fib6_entry->common.fib_node;
 
-       err = __mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, op_ctx, &fib6_entry->common);
+       mlxsw_sp_fib_node_entry_unlink(mlxsw_sp, &fib6_entry->common);
        mlxsw_sp_fib6_entry_destroy(mlxsw_sp, fib6_entry);
        mlxsw_sp_fib_node_put(mlxsw_sp, fib_node);
-       return err;
 }
 
 static struct mlxsw_sp_mr_table *
@@ -7569,15 +7315,15 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
        }
 }
 
-struct mlxsw_sp_fib6_event {
+struct mlxsw_sp_fib6_event_work {
        struct fib6_info **rt_arr;
        unsigned int nrt6;
 };
 
-struct mlxsw_sp_fib_event {
-       struct list_head list; /* node in fib queue */
+struct mlxsw_sp_fib_event_work {
+       struct work_struct work;
        union {
-               struct mlxsw_sp_fib6_event fib6_event;
+               struct mlxsw_sp_fib6_event_work fib6_work;
                struct fib_entry_notifier_info fen_info;
                struct fib_rule_notifier_info fr_info;
                struct fib_nh_notifier_info fnh_info;
@@ -7586,12 +7332,11 @@ struct mlxsw_sp_fib_event {
        };
        struct mlxsw_sp *mlxsw_sp;
        unsigned long event;
-       int family;
 };
 
 static int
-mlxsw_sp_router_fib6_event_init(struct mlxsw_sp_fib6_event *fib6_event,
-                               struct fib6_entry_notifier_info *fen6_info)
+mlxsw_sp_router_fib6_work_init(struct mlxsw_sp_fib6_event_work *fib6_work,
+                              struct fib6_entry_notifier_info *fen6_info)
 {
        struct fib6_info *rt = fen6_info->rt;
        struct fib6_info **rt_arr;
@@ -7605,8 +7350,8 @@ mlxsw_sp_router_fib6_event_init(struct mlxsw_sp_fib6_event *fib6_event,
        if (!rt_arr)
                return -ENOMEM;
 
-       fib6_event->rt_arr = rt_arr;
-       fib6_event->nrt6 = nrt6;
+       fib6_work->rt_arr = rt_arr;
+       fib6_work->nrt6 = nrt6;
 
        rt_arr[0] = rt;
        fib6_info_hold(rt);
@@ -7628,242 +7373,182 @@ mlxsw_sp_router_fib6_event_init(struct mlxsw_sp_fib6_event *fib6_event,
 }
 
 static void
-mlxsw_sp_router_fib6_event_fini(struct mlxsw_sp_fib6_event *fib6_event)
+mlxsw_sp_router_fib6_work_fini(struct mlxsw_sp_fib6_event_work *fib6_work)
 {
        int i;
 
-       for (i = 0; i < fib6_event->nrt6; i++)
-               mlxsw_sp_rt6_release(fib6_event->rt_arr[i]);
-       kfree(fib6_event->rt_arr);
+       for (i = 0; i < fib6_work->nrt6; i++)
+               mlxsw_sp_rt6_release(fib6_work->rt_arr[i]);
+       kfree(fib6_work->rt_arr);
 }
 
-static void mlxsw_sp_router_fib4_event_process(struct mlxsw_sp *mlxsw_sp,
-                                              struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                              struct mlxsw_sp_fib_event *fib_event)
+static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
 {
+       struct mlxsw_sp_fib_event_work *fib_work =
+               container_of(work, struct mlxsw_sp_fib_event_work, work);
+       struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
        int err;
 
+       mutex_lock(&mlxsw_sp->router->lock);
        mlxsw_sp_span_respin(mlxsw_sp);
 
-       switch (fib_event->event) {
+       switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
-               err = mlxsw_sp_router_fib4_replace(mlxsw_sp, op_ctx, &fib_event->fen_info);
+               err = mlxsw_sp_router_fib4_replace(mlxsw_sp,
+                                                  &fib_work->fen_info);
                if (err) {
-                       mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
                        dev_warn(mlxsw_sp->bus_info->dev, "FIB replace failed.\n");
                        mlxsw_sp_fib4_offload_failed_flag_set(mlxsw_sp,
-                                                             &fib_event->fen_info);
+                                                             &fib_work->fen_info);
                }
-               fib_info_put(fib_event->fen_info.fi);
+               fib_info_put(fib_work->fen_info.fi);
                break;
        case FIB_EVENT_ENTRY_DEL:
-               err = mlxsw_sp_router_fib4_del(mlxsw_sp, op_ctx, &fib_event->fen_info);
-               if (err)
-                       mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
-               fib_info_put(fib_event->fen_info.fi);
+               mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info);
+               fib_info_put(fib_work->fen_info.fi);
                break;
        case FIB_EVENT_NH_ADD:
        case FIB_EVENT_NH_DEL:
-               mlxsw_sp_nexthop4_event(mlxsw_sp, fib_event->event, fib_event->fnh_info.fib_nh);
-               fib_info_put(fib_event->fnh_info.fib_nh->nh_parent);
+               mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event,
+                                       fib_work->fnh_info.fib_nh);
+               fib_info_put(fib_work->fnh_info.fib_nh->nh_parent);
                break;
        }
+       mutex_unlock(&mlxsw_sp->router->lock);
+       kfree(fib_work);
 }
 
-static void mlxsw_sp_router_fib6_event_process(struct mlxsw_sp *mlxsw_sp,
-                                              struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                              struct mlxsw_sp_fib_event *fib_event)
+static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
 {
-       struct mlxsw_sp_fib6_event *fib6_event = &fib_event->fib6_event;
+       struct mlxsw_sp_fib_event_work *fib_work =
+                   container_of(work, struct mlxsw_sp_fib_event_work, work);
+       struct mlxsw_sp_fib6_event_work *fib6_work = &fib_work->fib6_work;
+       struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
        int err;
 
+       mutex_lock(&mlxsw_sp->router->lock);
        mlxsw_sp_span_respin(mlxsw_sp);
 
-       switch (fib_event->event) {
+       switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
-               err = mlxsw_sp_router_fib6_replace(mlxsw_sp, op_ctx, fib_event->fib6_event.rt_arr,
-                                                  fib_event->fib6_event.nrt6);
+               err = mlxsw_sp_router_fib6_replace(mlxsw_sp,
+                                                  fib6_work->rt_arr,
+                                                  fib6_work->nrt6);
                if (err) {
-                       mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
                        dev_warn(mlxsw_sp->bus_info->dev, "FIB replace failed.\n");
                        mlxsw_sp_fib6_offload_failed_flag_set(mlxsw_sp,
-                                                             fib6_event->rt_arr,
-                                                             fib6_event->nrt6);
+                                                             fib6_work->rt_arr,
+                                                             fib6_work->nrt6);
                }
-               mlxsw_sp_router_fib6_event_fini(&fib_event->fib6_event);
+               mlxsw_sp_router_fib6_work_fini(fib6_work);
                break;
        case FIB_EVENT_ENTRY_APPEND:
-               err = mlxsw_sp_router_fib6_append(mlxsw_sp, op_ctx, fib_event->fib6_event.rt_arr,
-                                                 fib_event->fib6_event.nrt6);
+               err = mlxsw_sp_router_fib6_append(mlxsw_sp,
+                                                 fib6_work->rt_arr,
+                                                 fib6_work->nrt6);
                if (err) {
-                       mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
                        dev_warn(mlxsw_sp->bus_info->dev, "FIB append failed.\n");
                        mlxsw_sp_fib6_offload_failed_flag_set(mlxsw_sp,
-                                                             fib6_event->rt_arr,
-                                                             fib6_event->nrt6);
+                                                             fib6_work->rt_arr,
+                                                             fib6_work->nrt6);
                }
-               mlxsw_sp_router_fib6_event_fini(&fib_event->fib6_event);
+               mlxsw_sp_router_fib6_work_fini(fib6_work);
                break;
        case FIB_EVENT_ENTRY_DEL:
-               err = mlxsw_sp_router_fib6_del(mlxsw_sp, op_ctx, fib_event->fib6_event.rt_arr,
-                                              fib_event->fib6_event.nrt6);
-               if (err)
-                       mlxsw_sp_fib_entry_op_ctx_priv_put_all(op_ctx);
-               mlxsw_sp_router_fib6_event_fini(&fib_event->fib6_event);
+               mlxsw_sp_router_fib6_del(mlxsw_sp,
+                                        fib6_work->rt_arr,
+                                        fib6_work->nrt6);
+               mlxsw_sp_router_fib6_work_fini(fib6_work);
                break;
        }
+       mutex_unlock(&mlxsw_sp->router->lock);
+       kfree(fib_work);
 }
 
-static void mlxsw_sp_router_fibmr_event_process(struct mlxsw_sp *mlxsw_sp,
-                                               struct mlxsw_sp_fib_event *fib_event)
+static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work)
 {
+       struct mlxsw_sp_fib_event_work *fib_work =
+               container_of(work, struct mlxsw_sp_fib_event_work, work);
+       struct mlxsw_sp *mlxsw_sp = fib_work->mlxsw_sp;
        bool replace;
        int err;
 
        rtnl_lock();
        mutex_lock(&mlxsw_sp->router->lock);
-       switch (fib_event->event) {
+       switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_ADD:
-               replace = fib_event->event == FIB_EVENT_ENTRY_REPLACE;
+               replace = fib_work->event == FIB_EVENT_ENTRY_REPLACE;
 
-               err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_event->men_info, replace);
+               err = mlxsw_sp_router_fibmr_add(mlxsw_sp, &fib_work->men_info,
+                                               replace);
                if (err)
                        dev_warn(mlxsw_sp->bus_info->dev, "MR entry add failed.\n");
-               mr_cache_put(fib_event->men_info.mfc);
+               mr_cache_put(fib_work->men_info.mfc);
                break;
        case FIB_EVENT_ENTRY_DEL:
-               mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_event->men_info);
-               mr_cache_put(fib_event->men_info.mfc);
+               mlxsw_sp_router_fibmr_del(mlxsw_sp, &fib_work->men_info);
+               mr_cache_put(fib_work->men_info.mfc);
                break;
        case FIB_EVENT_VIF_ADD:
                err = mlxsw_sp_router_fibmr_vif_add(mlxsw_sp,
-                                                   &fib_event->ven_info);
+                                                   &fib_work->ven_info);
                if (err)
                        dev_warn(mlxsw_sp->bus_info->dev, "MR VIF add failed.\n");
-               dev_put(fib_event->ven_info.dev);
+               dev_put(fib_work->ven_info.dev);
                break;
        case FIB_EVENT_VIF_DEL:
-               mlxsw_sp_router_fibmr_vif_del(mlxsw_sp, &fib_event->ven_info);
-               dev_put(fib_event->ven_info.dev);
+               mlxsw_sp_router_fibmr_vif_del(mlxsw_sp,
+                                             &fib_work->ven_info);
+               dev_put(fib_work->ven_info.dev);
                break;
        }
        mutex_unlock(&mlxsw_sp->router->lock);
        rtnl_unlock();
+       kfree(fib_work);
 }
 
-static void mlxsw_sp_router_fib_event_work(struct work_struct *work)
-{
-       struct mlxsw_sp_router *router = container_of(work, struct mlxsw_sp_router, fib_event_work);
-       struct mlxsw_sp_fib_entry_op_ctx *op_ctx = router->ll_op_ctx;
-       struct mlxsw_sp *mlxsw_sp = router->mlxsw_sp;
-       struct mlxsw_sp_fib_event *next_fib_event;
-       struct mlxsw_sp_fib_event *fib_event;
-       int last_family = AF_UNSPEC;
-       LIST_HEAD(fib_event_queue);
-
-       spin_lock_bh(&router->fib_event_queue_lock);
-       list_splice_init(&router->fib_event_queue, &fib_event_queue);
-       spin_unlock_bh(&router->fib_event_queue_lock);
-
-       /* Router lock is held here to make sure per-instance
-        * operation context is not used in between FIB4/6 events
-        * processing.
-        */
-       mutex_lock(&router->lock);
-       mlxsw_sp_fib_entry_op_ctx_clear(op_ctx);
-       list_for_each_entry_safe(fib_event, next_fib_event,
-                                &fib_event_queue, list) {
-               /* Check if the next entry in the queue exists and it is
-                * of the same type (family and event) as the currect one.
-                * In that case it is permitted to do the bulking
-                * of multiple FIB entries to a single register write.
-                */
-               op_ctx->bulk_ok = !list_is_last(&fib_event->list, &fib_event_queue) &&
-                                 fib_event->family == next_fib_event->family &&
-                                 fib_event->event == next_fib_event->event;
-               op_ctx->event = fib_event->event;
-
-               /* In case family of this and the previous entry are different, context
-                * reinitialization is going to be needed now, indicate that.
-                * Note that since last_family is initialized to AF_UNSPEC, this is always
-                * going to happen for the first entry processed in the work.
-                */
-               if (fib_event->family != last_family)
-                       op_ctx->initialized = false;
-
-               switch (fib_event->family) {
-               case AF_INET:
-                       mlxsw_sp_router_fib4_event_process(mlxsw_sp, op_ctx,
-                                                          fib_event);
-                       break;
-               case AF_INET6:
-                       mlxsw_sp_router_fib6_event_process(mlxsw_sp, op_ctx,
-                                                          fib_event);
-                       break;
-               case RTNL_FAMILY_IP6MR:
-               case RTNL_FAMILY_IPMR:
-                       /* Unlock here as inside FIBMR the lock is taken again
-                        * under RTNL. The per-instance operation context
-                        * is not used by FIBMR.
-                        */
-                       mutex_unlock(&router->lock);
-                       mlxsw_sp_router_fibmr_event_process(mlxsw_sp,
-                                                           fib_event);
-                       mutex_lock(&router->lock);
-                       break;
-               default:
-                       WARN_ON_ONCE(1);
-               }
-               last_family = fib_event->family;
-               kfree(fib_event);
-               cond_resched();
-       }
-       WARN_ON_ONCE(!list_empty(&router->ll_op_ctx->fib_entry_priv_list));
-       mutex_unlock(&router->lock);
-}
-
-static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event *fib_event,
+static void mlxsw_sp_router_fib4_event(struct mlxsw_sp_fib_event_work *fib_work,
                                       struct fib_notifier_info *info)
 {
        struct fib_entry_notifier_info *fen_info;
        struct fib_nh_notifier_info *fnh_info;
 
-       switch (fib_event->event) {
+       switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_DEL:
                fen_info = container_of(info, struct fib_entry_notifier_info,
                                        info);
-               fib_event->fen_info = *fen_info;
+               fib_work->fen_info = *fen_info;
                /* Take reference on fib_info to prevent it from being
-                * freed while event is queued. Release it afterwards.
+                * freed while work is queued. Release it afterwards.
                 */
-               fib_info_hold(fib_event->fen_info.fi);
+               fib_info_hold(fib_work->fen_info.fi);
                break;
        case FIB_EVENT_NH_ADD:
        case FIB_EVENT_NH_DEL:
                fnh_info = container_of(info, struct fib_nh_notifier_info,
                                        info);
-               fib_event->fnh_info = *fnh_info;
-               fib_info_hold(fib_event->fnh_info.fib_nh->nh_parent);
+               fib_work->fnh_info = *fnh_info;
+               fib_info_hold(fib_work->fnh_info.fib_nh->nh_parent);
                break;
        }
 }
 
-static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event *fib_event,
+static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event_work *fib_work,
                                      struct fib_notifier_info *info)
 {
        struct fib6_entry_notifier_info *fen6_info;
        int err;
 
-       switch (fib_event->event) {
+       switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_APPEND:
        case FIB_EVENT_ENTRY_DEL:
                fen6_info = container_of(info, struct fib6_entry_notifier_info,
                                         info);
-               err = mlxsw_sp_router_fib6_event_init(&fib_event->fib6_event,
-                                                     fen6_info);
+               err = mlxsw_sp_router_fib6_work_init(&fib_work->fib6_work,
+                                                    fen6_info);
                if (err)
                        return err;
                break;
@@ -7873,20 +7558,20 @@ static int mlxsw_sp_router_fib6_event(struct mlxsw_sp_fib_event *fib_event,
 }
 
 static void
-mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event *fib_event,
+mlxsw_sp_router_fibmr_event(struct mlxsw_sp_fib_event_work *fib_work,
                            struct fib_notifier_info *info)
 {
-       switch (fib_event->event) {
+       switch (fib_work->event) {
        case FIB_EVENT_ENTRY_REPLACE:
        case FIB_EVENT_ENTRY_ADD:
        case FIB_EVENT_ENTRY_DEL:
-               memcpy(&fib_event->men_info, info, sizeof(fib_event->men_info));
-               mr_cache_hold(fib_event->men_info.mfc);
+               memcpy(&fib_work->men_info, info, sizeof(fib_work->men_info));
+               mr_cache_hold(fib_work->men_info.mfc);
                break;
        case FIB_EVENT_VIF_ADD:
        case FIB_EVENT_VIF_DEL:
-               memcpy(&fib_event->ven_info, info, sizeof(fib_event->ven_info));
-               dev_hold(fib_event->ven_info.dev);
+               memcpy(&fib_work->ven_info, info, sizeof(fib_work->ven_info));
+               dev_hold(fib_work->ven_info.dev);
                break;
        }
 }
@@ -7940,7 +7625,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event,
 static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
                                     unsigned long event, void *ptr)
 {
-       struct mlxsw_sp_fib_event *fib_event;
+       struct mlxsw_sp_fib_event_work *fib_work;
        struct fib_notifier_info *info = ptr;
        struct mlxsw_sp_router *router;
        int err;
@@ -7972,39 +7657,37 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb,
                break;
        }
 
-       fib_event = kzalloc(sizeof(*fib_event), GFP_ATOMIC);
-       if (!fib_event)
+       fib_work = kzalloc(sizeof(*fib_work), GFP_ATOMIC);
+       if (!fib_work)
                return NOTIFY_BAD;
 
-       fib_event->mlxsw_sp = router->mlxsw_sp;
-       fib_event->event = event;
-       fib_event->family = info->family;
+       fib_work->mlxsw_sp = router->mlxsw_sp;
+       fib_work->event = event;
 
        switch (info->family) {
        case AF_INET:
-               mlxsw_sp_router_fib4_event(fib_event, info);
+               INIT_WORK(&fib_work->work, mlxsw_sp_router_fib4_event_work);
+               mlxsw_sp_router_fib4_event(fib_work, info);
                break;
        case AF_INET6:
-               err = mlxsw_sp_router_fib6_event(fib_event, info);
+               INIT_WORK(&fib_work->work, mlxsw_sp_router_fib6_event_work);
+               err = mlxsw_sp_router_fib6_event(fib_work, info);
                if (err)
                        goto err_fib_event;
                break;
        case RTNL_FAMILY_IP6MR:
        case RTNL_FAMILY_IPMR:
-               mlxsw_sp_router_fibmr_event(fib_event, info);
+               INIT_WORK(&fib_work->work, mlxsw_sp_router_fibmr_event_work);
+               mlxsw_sp_router_fibmr_event(fib_work, info);
                break;
        }
 
-       /* Enqueue the event and trigger the work */
-       spin_lock_bh(&router->fib_event_queue_lock);
-       list_add_tail(&fib_event->list, &router->fib_event_queue);
-       spin_unlock_bh(&router->fib_event_queue_lock);
-       mlxsw_core_schedule_work(&router->fib_event_work);
+       mlxsw_core_schedule_work(&fib_work->work);
 
        return NOTIFY_DONE;
 
 err_fib_event:
-       kfree(fib_event);
+       kfree(fib_work);
        return NOTIFY_BAD;
 }
 
@@ -8463,6 +8146,7 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
                mlxsw_sp_rif_counters_alloc(rif);
        }
 
+       atomic_inc(&mlxsw_sp->router->rifs_count);
        return rif;
 
 err_stats_enable:
@@ -8492,6 +8176,7 @@ static void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)
        struct mlxsw_sp_vr *vr;
        int i;
 
+       atomic_dec(&mlxsw_sp->router->rifs_count);
        mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif);
        vr = &mlxsw_sp->router->vrs[rif->vr_id];
 
@@ -8650,6 +8335,13 @@ static u64 mlxsw_sp_rif_mac_profiles_occ_get(void *priv)
        return atomic_read(&mlxsw_sp->router->rif_mac_profiles_count);
 }
 
+static u64 mlxsw_sp_rifs_occ_get(void *priv)
+{
+       const struct mlxsw_sp *mlxsw_sp = priv;
+
+       return atomic_read(&mlxsw_sp->router->rifs_count);
+}
+
 static struct mlxsw_sp_rif_mac_profile *
 mlxsw_sp_rif_mac_profile_create(struct mlxsw_sp *mlxsw_sp, const char *mac,
                                struct netlink_ext_ack *extack)
@@ -9624,17 +9316,18 @@ static int mlxsw_sp_rif_subport_op(struct mlxsw_sp_rif *rif, bool enable)
        struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
        struct mlxsw_sp_rif_subport *rif_subport;
        char ritr_pl[MLXSW_REG_RITR_LEN];
+       u16 efid;
 
        rif_subport = mlxsw_sp_rif_subport_rif(rif);
        mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
                            rif->rif_index, rif->vr_id, rif->dev->mtu);
        mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
        mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
+       efid = mlxsw_sp_fid_index(rif->fid);
        mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
                                  rif_subport->lag ? rif_subport->lag_id :
                                                     rif_subport->system_port,
-                                 rif_subport->vid);
-
+                                 efid, 0);
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 }
 
@@ -9659,9 +9352,15 @@ static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif,
        if (err)
                goto err_rif_fdb_op;
 
-       mlxsw_sp_fid_rif_set(rif->fid, rif);
+       err = mlxsw_sp_fid_rif_set(rif->fid, rif);
+       if (err)
+               goto err_fid_rif_set;
+
        return 0;
 
+err_fid_rif_set:
+       mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                           mlxsw_sp_fid_index(rif->fid), false);
 err_rif_fdb_op:
        mlxsw_sp_rif_subport_op(rif, false);
 err_rif_subport_op:
@@ -9673,7 +9372,7 @@ static void mlxsw_sp_rif_subport_deconfigure(struct mlxsw_sp_rif *rif)
 {
        struct mlxsw_sp_fid *fid = rif->fid;
 
-       mlxsw_sp_fid_rif_set(fid, NULL);
+       mlxsw_sp_fid_rif_unset(fid);
        mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
                            mlxsw_sp_fid_index(fid), false);
        mlxsw_sp_rif_macvlan_flush(rif);
@@ -9697,10 +9396,9 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_subport_ops = {
        .fid_get                = mlxsw_sp_rif_subport_fid_get,
 };
 
-static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
-                                   enum mlxsw_reg_ritr_if_type type,
-                                   u16 vid_fid, bool enable)
+static int mlxsw_sp_rif_fid_op(struct mlxsw_sp_rif *rif, u16 fid, bool enable)
 {
+       enum mlxsw_reg_ritr_if_type type = MLXSW_REG_RITR_FID_IF;
        struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
        char ritr_pl[MLXSW_REG_RITR_LEN];
 
@@ -9708,7 +9406,7 @@ static int mlxsw_sp_rif_vlan_fid_op(struct mlxsw_sp_rif *rif,
                            rif->dev->mtu);
        mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
        mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
-       mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);
+       mlxsw_reg_ritr_fid_if_fid_set(ritr_pl, fid);
 
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 }
@@ -9732,10 +9430,9 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif,
                return err;
        rif->mac_profile_id = mac_profile;
 
-       err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
-                                      true);
+       err = mlxsw_sp_rif_fid_op(rif, fid_index, true);
        if (err)
-               goto err_rif_vlan_fid_op;
+               goto err_rif_fid_op;
 
        err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
                                     mlxsw_sp_router_port(mlxsw_sp), true);
@@ -9752,9 +9449,15 @@ static int mlxsw_sp_rif_fid_configure(struct mlxsw_sp_rif *rif,
        if (err)
                goto err_rif_fdb_op;
 
-       mlxsw_sp_fid_rif_set(rif->fid, rif);
+       err = mlxsw_sp_fid_rif_set(rif->fid, rif);
+       if (err)
+               goto err_fid_rif_set;
+
        return 0;
 
+err_fid_rif_set:
+       mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                           mlxsw_sp_fid_index(rif->fid), false);
 err_rif_fdb_op:
        mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
                               mlxsw_sp_router_port(mlxsw_sp), false);
@@ -9762,8 +9465,8 @@ err_fid_bc_flood_set:
        mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
                               mlxsw_sp_router_port(mlxsw_sp), false);
 err_fid_mc_flood_set:
-       mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
-err_rif_vlan_fid_op:
+       mlxsw_sp_rif_fid_op(rif, fid_index, false);
+err_rif_fid_op:
        mlxsw_sp_rif_mac_profile_put(mlxsw_sp, mac_profile);
        return err;
 }
@@ -9774,7 +9477,7 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
        struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
        struct mlxsw_sp_fid *fid = rif->fid;
 
-       mlxsw_sp_fid_rif_set(fid, NULL);
+       mlxsw_sp_fid_rif_unset(fid);
        mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
                            mlxsw_sp_fid_index(fid), false);
        mlxsw_sp_rif_macvlan_flush(rif);
@@ -9782,7 +9485,7 @@ static void mlxsw_sp_rif_fid_deconfigure(struct mlxsw_sp_rif *rif)
                               mlxsw_sp_router_port(mlxsw_sp), false);
        mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
                               mlxsw_sp_router_port(mlxsw_sp), false);
-       mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
+       mlxsw_sp_rif_fid_op(rif, fid_index, false);
        mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
 }
 
@@ -9859,11 +9562,119 @@ static void mlxsw_sp_rif_vlan_fdb_del(struct mlxsw_sp_rif *rif, const char *mac)
                                 NULL);
 }
 
-static const struct mlxsw_sp_rif_ops mlxsw_sp_rif_vlan_emu_ops = {
+static int mlxsw_sp_rif_vlan_op(struct mlxsw_sp_rif *rif, u16 vid, u16 efid,
+                               bool enable)
+{
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+       char ritr_pl[MLXSW_REG_RITR_LEN];
+
+       mlxsw_reg_ritr_vlan_if_pack(ritr_pl, enable, rif->rif_index, rif->vr_id,
+                                   rif->dev->mtu, rif->dev->dev_addr,
+                                   rif->mac_profile_id, vid, efid);
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+}
+
+static int mlxsw_sp_rif_vlan_configure(struct mlxsw_sp_rif *rif, u16 efid,
+                                      struct netlink_ext_ack *extack)
+{
+       u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+       u8 mac_profile;
+       int err;
+
+       err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, rif->addr,
+                                          &mac_profile, extack);
+       if (err)
+               return err;
+       rif->mac_profile_id = mac_profile;
+
+       err = mlxsw_sp_rif_vlan_op(rif, vid, efid, true);
+       if (err)
+               goto err_rif_vlan_fid_op;
+
+       err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
+                                    mlxsw_sp_router_port(mlxsw_sp), true);
+       if (err)
+               goto err_fid_mc_flood_set;
+
+       err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+                                    mlxsw_sp_router_port(mlxsw_sp), true);
+       if (err)
+               goto err_fid_bc_flood_set;
+
+       err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                                 mlxsw_sp_fid_index(rif->fid), true);
+       if (err)
+               goto err_rif_fdb_op;
+
+       err = mlxsw_sp_fid_rif_set(rif->fid, rif);
+       if (err)
+               goto err_fid_rif_set;
+
+       return 0;
+
+err_fid_rif_set:
+       mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                           mlxsw_sp_fid_index(rif->fid), false);
+err_rif_fdb_op:
+       mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+                              mlxsw_sp_router_port(mlxsw_sp), false);
+err_fid_bc_flood_set:
+       mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
+                              mlxsw_sp_router_port(mlxsw_sp), false);
+err_fid_mc_flood_set:
+       mlxsw_sp_rif_vlan_op(rif, vid, 0, false);
+err_rif_vlan_fid_op:
+       mlxsw_sp_rif_mac_profile_put(mlxsw_sp, mac_profile);
+       return err;
+}
+
+static void mlxsw_sp_rif_vlan_deconfigure(struct mlxsw_sp_rif *rif)
+{
+       u16 vid = mlxsw_sp_fid_8021q_vid(rif->fid);
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+
+       mlxsw_sp_fid_rif_unset(rif->fid);
+       mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
+                           mlxsw_sp_fid_index(rif->fid), false);
+       mlxsw_sp_rif_macvlan_flush(rif);
+       mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_BC,
+                              mlxsw_sp_router_port(mlxsw_sp), false);
+       mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
+                              mlxsw_sp_router_port(mlxsw_sp), false);
+       mlxsw_sp_rif_vlan_op(rif, vid, 0, false);
+       mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
+}
+
+static int mlxsw_sp1_rif_vlan_configure(struct mlxsw_sp_rif *rif,
+                                       struct netlink_ext_ack *extack)
+{
+       return mlxsw_sp_rif_vlan_configure(rif, 0, extack);
+}
+
+static const struct mlxsw_sp_rif_ops mlxsw_sp1_rif_vlan_ops = {
        .type                   = MLXSW_SP_RIF_TYPE_VLAN,
        .rif_size               = sizeof(struct mlxsw_sp_rif),
-       .configure              = mlxsw_sp_rif_fid_configure,
-       .deconfigure            = mlxsw_sp_rif_fid_deconfigure,
+       .configure              = mlxsw_sp1_rif_vlan_configure,
+       .deconfigure            = mlxsw_sp_rif_vlan_deconfigure,
+       .fid_get                = mlxsw_sp_rif_vlan_fid_get,
+       .fdb_del                = mlxsw_sp_rif_vlan_fdb_del,
+};
+
+static int mlxsw_sp2_rif_vlan_configure(struct mlxsw_sp_rif *rif,
+                                       struct netlink_ext_ack *extack)
+{
+       u16 efid = mlxsw_sp_fid_index(rif->fid);
+
+       return mlxsw_sp_rif_vlan_configure(rif, efid, extack);
+}
+
+static const struct mlxsw_sp_rif_ops mlxsw_sp2_rif_vlan_ops = {
+       .type                   = MLXSW_SP_RIF_TYPE_VLAN,
+       .rif_size               = sizeof(struct mlxsw_sp_rif),
+       .configure              = mlxsw_sp2_rif_vlan_configure,
+       .deconfigure            = mlxsw_sp_rif_vlan_deconfigure,
        .fid_get                = mlxsw_sp_rif_vlan_fid_get,
        .fdb_del                = mlxsw_sp_rif_vlan_fdb_del,
 };
@@ -9938,7 +9749,7 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp1_rif_ipip_lb_ops = {
 
 static const struct mlxsw_sp_rif_ops *mlxsw_sp1_rif_ops_arr[] = {
        [MLXSW_SP_RIF_TYPE_SUBPORT]     = &mlxsw_sp_rif_subport_ops,
-       [MLXSW_SP_RIF_TYPE_VLAN]        = &mlxsw_sp_rif_vlan_emu_ops,
+       [MLXSW_SP_RIF_TYPE_VLAN]        = &mlxsw_sp1_rif_vlan_ops,
        [MLXSW_SP_RIF_TYPE_FID]         = &mlxsw_sp_rif_fid_ops,
        [MLXSW_SP_RIF_TYPE_IPIP_LB]     = &mlxsw_sp1_rif_ipip_lb_ops,
 };
@@ -9981,6 +9792,7 @@ mlxsw_sp_ul_rif_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_vr *vr,
        if (err)
                goto ul_rif_op_err;
 
+       atomic_inc(&mlxsw_sp->router->rifs_count);
        return ul_rif;
 
 ul_rif_op_err:
@@ -9993,6 +9805,7 @@ static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif)
 {
        struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
 
+       atomic_dec(&mlxsw_sp->router->rifs_count);
        mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, false);
        mlxsw_sp->router->rifs[ul_rif->rif_index] = NULL;
        kfree(ul_rif);
@@ -10124,7 +9937,7 @@ static const struct mlxsw_sp_rif_ops mlxsw_sp2_rif_ipip_lb_ops = {
 
 static const struct mlxsw_sp_rif_ops *mlxsw_sp2_rif_ops_arr[] = {
        [MLXSW_SP_RIF_TYPE_SUBPORT]     = &mlxsw_sp_rif_subport_ops,
-       [MLXSW_SP_RIF_TYPE_VLAN]        = &mlxsw_sp_rif_vlan_emu_ops,
+       [MLXSW_SP_RIF_TYPE_VLAN]        = &mlxsw_sp2_rif_vlan_ops,
        [MLXSW_SP_RIF_TYPE_FID]         = &mlxsw_sp_rif_fid_ops,
        [MLXSW_SP_RIF_TYPE_IPIP_LB]     = &mlxsw_sp2_rif_ipip_lb_ops,
 };
@@ -10148,10 +9961,15 @@ static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
 
        idr_init(&mlxsw_sp->router->rif_mac_profiles_idr);
        atomic_set(&mlxsw_sp->router->rif_mac_profiles_count, 0);
+       atomic_set(&mlxsw_sp->router->rifs_count, 0);
        devlink_resource_occ_get_register(devlink,
                                          MLXSW_SP_RESOURCE_RIF_MAC_PROFILES,
                                          mlxsw_sp_rif_mac_profiles_occ_get,
                                          mlxsw_sp);
+       devlink_resource_occ_get_register(devlink,
+                                         MLXSW_SP_RESOURCE_RIFS,
+                                         mlxsw_sp_rifs_occ_get,
+                                         mlxsw_sp);
 
        return 0;
 }
@@ -10161,9 +9979,11 @@ static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
        int i;
 
+       WARN_ON_ONCE(atomic_read(&mlxsw_sp->router->rifs_count));
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
                WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
 
+       devlink_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_RIFS);
        devlink_resource_occ_get_unregister(devlink,
                                            MLXSW_SP_RESOURCE_RIF_MAC_PROFILES);
        WARN_ON(!idr_is_empty(&mlxsw_sp->router->rif_mac_profiles_idr));
@@ -10545,46 +10365,6 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl);
 }
 
-static const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_basic_ops = {
-       .init = mlxsw_sp_router_ll_basic_init,
-       .ralta_write = mlxsw_sp_router_ll_basic_ralta_write,
-       .ralst_write = mlxsw_sp_router_ll_basic_ralst_write,
-       .raltb_write = mlxsw_sp_router_ll_basic_raltb_write,
-       .fib_entry_op_ctx_size = sizeof(struct mlxsw_sp_fib_entry_op_ctx_basic),
-       .fib_entry_pack = mlxsw_sp_router_ll_basic_fib_entry_pack,
-       .fib_entry_act_remote_pack = mlxsw_sp_router_ll_basic_fib_entry_act_remote_pack,
-       .fib_entry_act_local_pack = mlxsw_sp_router_ll_basic_fib_entry_act_local_pack,
-       .fib_entry_act_ip2me_pack = mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_pack,
-       .fib_entry_act_ip2me_tun_pack = mlxsw_sp_router_ll_basic_fib_entry_act_ip2me_tun_pack,
-       .fib_entry_commit = mlxsw_sp_router_ll_basic_fib_entry_commit,
-       .fib_entry_is_committed = mlxsw_sp_router_ll_basic_fib_entry_is_committed,
-};
-
-static int mlxsw_sp_router_ll_op_ctx_init(struct mlxsw_sp_router *router)
-{
-       size_t max_size = 0;
-       int i;
-
-       for (i = 0; i < MLXSW_SP_L3_PROTO_MAX; i++) {
-               size_t size = router->proto_ll_ops[i]->fib_entry_op_ctx_size;
-
-               if (size > max_size)
-                       max_size = size;
-       }
-       router->ll_op_ctx = kzalloc(sizeof(*router->ll_op_ctx) + max_size,
-                                   GFP_KERNEL);
-       if (!router->ll_op_ctx)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&router->ll_op_ctx->fib_entry_priv_list);
-       return 0;
-}
-
-static void mlxsw_sp_router_ll_op_ctx_fini(struct mlxsw_sp_router *router)
-{
-       WARN_ON(!list_empty(&router->ll_op_ctx->fib_entry_priv_list));
-       kfree(router->ll_op_ctx);
-}
-
 static int mlxsw_sp_lb_rif_init(struct mlxsw_sp *mlxsw_sp)
 {
        u16 lb_rif_index;
@@ -10658,23 +10438,9 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
        if (err)
                goto err_router_ops_init;
 
-       err = mlxsw_sp_router_xm_init(mlxsw_sp);
-       if (err)
-               goto err_xm_init;
-
-       router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV4] = mlxsw_sp_router_xm_ipv4_is_supported(mlxsw_sp) ?
-                                                      &mlxsw_sp_router_ll_xm_ops :
-                                                      &mlxsw_sp_router_ll_basic_ops;
-       router->proto_ll_ops[MLXSW_SP_L3_PROTO_IPV6] = &mlxsw_sp_router_ll_basic_ops;
-
-       err = mlxsw_sp_router_ll_op_ctx_init(router);
-       if (err)
-               goto err_ll_op_ctx_init;
-
        INIT_LIST_HEAD(&mlxsw_sp->router->nh_res_grp_list);
        INIT_DELAYED_WORK(&mlxsw_sp->router->nh_grp_activity_dw,
                          mlxsw_sp_nh_grp_activity_work);
-
        INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
        err = __mlxsw_sp_router_init(mlxsw_sp);
        if (err)
@@ -10727,10 +10493,6 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
        if (err)
                goto err_dscp_init;
 
-       INIT_WORK(&router->fib_event_work, mlxsw_sp_router_fib_event_work);
-       INIT_LIST_HEAD(&router->fib_event_queue);
-       spin_lock_init(&router->fib_event_queue_lock);
-
        router->inetaddr_nb.notifier_call = mlxsw_sp_inetaddr_event;
        err = register_inetaddr_notifier(&router->inetaddr_nb);
        if (err)
@@ -10785,7 +10547,6 @@ err_register_inet6addr_notifier:
        unregister_inetaddr_notifier(&router->inetaddr_nb);
 err_register_inetaddr_notifier:
        mlxsw_core_flush_owq();
-       WARN_ON(!list_empty(&router->fib_event_queue));
 err_dscp_init:
 err_mp_hash_init:
        mlxsw_sp_neigh_fini(mlxsw_sp);
@@ -10809,10 +10570,6 @@ err_rifs_init:
        __mlxsw_sp_router_fini(mlxsw_sp);
 err_router_init:
        cancel_delayed_work_sync(&mlxsw_sp->router->nh_grp_activity_dw);
-       mlxsw_sp_router_ll_op_ctx_fini(router);
-err_ll_op_ctx_init:
-       mlxsw_sp_router_xm_fini(mlxsw_sp);
-err_xm_init:
 err_router_ops_init:
        mutex_destroy(&mlxsw_sp->router->lock);
        kfree(mlxsw_sp->router);
@@ -10831,7 +10588,6 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
        unregister_inet6addr_notifier(&mlxsw_sp->router->inet6addr_nb);
        unregister_inetaddr_notifier(&mlxsw_sp->router->inetaddr_nb);
        mlxsw_core_flush_owq();
-       WARN_ON(!list_empty(&mlxsw_sp->router->fib_event_queue));
        mlxsw_sp_neigh_fini(mlxsw_sp);
        mlxsw_sp_lb_rif_fini(mlxsw_sp);
        mlxsw_sp_vrs_fini(mlxsw_sp);
@@ -10843,8 +10599,6 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
        mlxsw_sp_rifs_fini(mlxsw_sp);
        __mlxsw_sp_router_fini(mlxsw_sp);
        cancel_delayed_work_sync(&mlxsw_sp->router->nh_grp_activity_dw);
-       mlxsw_sp_router_ll_op_ctx_fini(mlxsw_sp->router);
-       mlxsw_sp_router_xm_fini(mlxsw_sp);
        mutex_destroy(&mlxsw_sp->router->lock);
        kfree(mlxsw_sp->router);
 }
index 37411b7..c5dfb97 100644 (file)
@@ -15,32 +15,12 @@ struct mlxsw_sp_router_nve_decap {
        u8 valid:1;
 };
 
-struct mlxsw_sp_fib_entry_op_ctx {
-       u8 bulk_ok:1, /* Indicate to the low-level op it is ok to bulk
-                      * the actual entry with the one that is the next
-                      * in queue.
-                      */
-          initialized:1; /* Bit that the low-level op sets in case
-                          * the context priv is initialized.
-                          */
-       struct list_head fib_entry_priv_list;
-       unsigned long event;
-       unsigned long ll_priv[];
-};
-
-static inline void
-mlxsw_sp_fib_entry_op_ctx_clear(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
-{
-       WARN_ON_ONCE(!list_empty(&op_ctx->fib_entry_priv_list));
-       memset(op_ctx, 0, sizeof(*op_ctx));
-       INIT_LIST_HEAD(&op_ctx->fib_entry_priv_list);
-}
-
 struct mlxsw_sp_router {
        struct mlxsw_sp *mlxsw_sp;
        struct mlxsw_sp_rif **rifs;
        struct idr rif_mac_profiles_idr;
        atomic_t rif_mac_profiles_count;
+       atomic_t rifs_count;
        u8 max_rif_mac_profile;
        struct mlxsw_sp_vr *vrs;
        struct rhashtable neigh_ht;
@@ -72,14 +52,8 @@ struct mlxsw_sp_router {
        const struct mlxsw_sp_ipip_ops **ipip_ops_arr;
        struct mlxsw_sp_router_nve_decap nve_decap_config;
        struct mutex lock; /* Protects shared router resources */
-       struct work_struct fib_event_work;
-       struct list_head fib_event_queue;
-       spinlock_t fib_event_queue_lock; /* Protects fib event queue list */
-       /* One set of ops for each protocol: IPv4 and IPv6 */
-       const struct mlxsw_sp_router_ll_ops *proto_ll_ops[MLXSW_SP_L3_PROTO_MAX];
        struct mlxsw_sp_fib_entry_op_ctx *ll_op_ctx;
        u16 lb_rif_index;
-       struct mlxsw_sp_router_xm *xm;
        const struct mlxsw_sp_adj_grp_size_range *adj_grp_size_ranges;
        size_t adj_grp_size_ranges_count;
        struct delayed_work nh_grp_activity_dw;
@@ -89,48 +63,6 @@ struct mlxsw_sp_router {
        u32 adj_trap_index;
 };
 
-struct mlxsw_sp_fib_entry_priv {
-       refcount_t refcnt;
-       struct list_head list; /* Member in op_ctx->fib_entry_priv_list */
-       unsigned long priv[];
-};
-
-enum mlxsw_sp_fib_entry_op {
-       MLXSW_SP_FIB_ENTRY_OP_WRITE,
-       MLXSW_SP_FIB_ENTRY_OP_UPDATE,
-       MLXSW_SP_FIB_ENTRY_OP_DELETE,
-};
-
-/* Low-level router ops. Basically this is to handle the different
- * register sets to work with ordinary and XM trees and FIB entries.
- */
-struct mlxsw_sp_router_ll_ops {
-       int (*init)(struct mlxsw_sp *mlxsw_sp, u16 vr_id,
-                   enum mlxsw_sp_l3proto proto);
-       int (*ralta_write)(struct mlxsw_sp *mlxsw_sp, char *xralta_pl);
-       int (*ralst_write)(struct mlxsw_sp *mlxsw_sp, char *xralst_pl);
-       int (*raltb_write)(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl);
-       size_t fib_entry_op_ctx_size;
-       size_t fib_entry_priv_size;
-       void (*fib_entry_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                              enum mlxsw_sp_l3proto proto, enum mlxsw_sp_fib_entry_op op,
-                              u16 virtual_router, u8 prefix_len, unsigned char *addr,
-                              struct mlxsw_sp_fib_entry_priv *priv);
-       void (*fib_entry_act_remote_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                         enum mlxsw_reg_ralue_trap_action trap_action,
-                                         u16 trap_id, u32 adjacency_index, u16 ecmp_size);
-       void (*fib_entry_act_local_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                        enum mlxsw_reg_ralue_trap_action trap_action,
-                                        u16 trap_id, u16 local_erif);
-       void (*fib_entry_act_ip2me_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx);
-       void (*fib_entry_act_ip2me_tun_pack)(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                            u32 tunnel_ptr);
-       int (*fib_entry_commit)(struct mlxsw_sp *mlxsw_sp,
-                               struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                               bool *postponed_for_bulk);
-       bool (*fib_entry_is_committed)(struct mlxsw_sp_fib_entry_priv *priv);
-};
-
 struct mlxsw_sp_rif_ipip_lb;
 struct mlxsw_sp_rif_ipip_lb_config {
        enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt;
@@ -150,7 +82,6 @@ struct mlxsw_sp_ipip_entry;
 
 struct mlxsw_sp_rif *mlxsw_sp_rif_by_index(const struct mlxsw_sp *mlxsw_sp,
                                           u16 rif_index);
-u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
 u16 mlxsw_sp_ipip_lb_rif_index(const struct mlxsw_sp_rif_ipip_lb *rif);
 u16 mlxsw_sp_ipip_lb_ul_vr_id(const struct mlxsw_sp_rif_ipip_lb *rif);
 u16 mlxsw_sp_ipip_lb_ul_rif_id(const struct mlxsw_sp_rif_ipip_lb *lb_rif);
@@ -232,10 +163,4 @@ int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp);
 struct net_device *
 mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev);
 
-extern const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_xm_ops;
-
-int mlxsw_sp_router_xm_init(struct mlxsw_sp *mlxsw_sp);
-void mlxsw_sp_router_xm_fini(struct mlxsw_sp *mlxsw_sp);
-bool mlxsw_sp_router_xm_ipv4_is_supported(const struct mlxsw_sp *mlxsw_sp);
-
 #endif /* _MLXSW_ROUTER_H_*/
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router_xm.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router_xm.c
deleted file mode 100644 (file)
index d213af7..0000000
+++ /dev/null
@@ -1,812 +0,0 @@
-// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
-/* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/rhashtable.h>
-
-#include "spectrum.h"
-#include "core.h"
-#include "reg.h"
-#include "spectrum_router.h"
-
-#define MLXSW_SP_ROUTER_XM_M_VAL 16
-
-static const u8 mlxsw_sp_router_xm_m_val[] = {
-       [MLXSW_SP_L3_PROTO_IPV4] = MLXSW_SP_ROUTER_XM_M_VAL,
-       [MLXSW_SP_L3_PROTO_IPV6] = 0, /* Currently unused. */
-};
-
-#define MLXSW_SP_ROUTER_XM_L_VAL_MAX 16
-
-struct mlxsw_sp_router_xm {
-       bool ipv4_supported;
-       bool ipv6_supported;
-       unsigned int entries_size;
-       struct rhashtable ltable_ht;
-       struct rhashtable flush_ht; /* Stores items about to be flushed from cache */
-       unsigned int flush_count;
-       bool flush_all_mode;
-};
-
-struct mlxsw_sp_router_xm_ltable_node {
-       struct rhash_head ht_node; /* Member of router_xm->ltable_ht */
-       u16 mindex;
-       u8 current_lvalue;
-       refcount_t refcnt;
-       unsigned int lvalue_ref[MLXSW_SP_ROUTER_XM_L_VAL_MAX + 1];
-};
-
-static const struct rhashtable_params mlxsw_sp_router_xm_ltable_ht_params = {
-       .key_offset = offsetof(struct mlxsw_sp_router_xm_ltable_node, mindex),
-       .head_offset = offsetof(struct mlxsw_sp_router_xm_ltable_node, ht_node),
-       .key_len = sizeof(u16),
-       .automatic_shrinking = true,
-};
-
-struct mlxsw_sp_router_xm_flush_info {
-       bool all;
-       enum mlxsw_sp_l3proto proto;
-       u16 virtual_router;
-       u8 prefix_len;
-       unsigned char addr[sizeof(struct in6_addr)];
-};
-
-struct mlxsw_sp_router_xm_fib_entry {
-       bool committed;
-       struct mlxsw_sp_router_xm_ltable_node *ltable_node; /* Parent node */
-       u16 mindex; /* Store for processing from commit op */
-       u8 lvalue;
-       struct mlxsw_sp_router_xm_flush_info flush_info;
-};
-
-#define MLXSW_SP_ROUTE_LL_XM_ENTRIES_MAX \
-       (MLXSW_REG_XMDR_TRANS_LEN / MLXSW_REG_XMDR_C_LT_ROUTE_V4_LEN)
-
-struct mlxsw_sp_fib_entry_op_ctx_xm {
-       bool initialized;
-       char xmdr_pl[MLXSW_REG_XMDR_LEN];
-       unsigned int trans_offset; /* Offset of the current command within one
-                                   * transaction of XMDR register.
-                                   */
-       unsigned int trans_item_len; /* The current command length. This is used
-                                     * to advance 'trans_offset' when the next
-                                     * command is appended.
-                                     */
-       unsigned int entries_count;
-       struct mlxsw_sp_router_xm_fib_entry *entries[MLXSW_SP_ROUTE_LL_XM_ENTRIES_MAX];
-};
-
-static int mlxsw_sp_router_ll_xm_init(struct mlxsw_sp *mlxsw_sp, u16 vr_id,
-                                     enum mlxsw_sp_l3proto proto)
-{
-       char rxlte_pl[MLXSW_REG_RXLTE_LEN];
-
-       mlxsw_reg_rxlte_pack(rxlte_pl, vr_id,
-                            (enum mlxsw_reg_rxlte_protocol) proto, true);
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rxlte), rxlte_pl);
-}
-
-static int mlxsw_sp_router_ll_xm_ralta_write(struct mlxsw_sp *mlxsw_sp, char *xralta_pl)
-{
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(xralta), xralta_pl);
-}
-
-static int mlxsw_sp_router_ll_xm_ralst_write(struct mlxsw_sp *mlxsw_sp, char *xralst_pl)
-{
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(xralst), xralst_pl);
-}
-
-static int mlxsw_sp_router_ll_xm_raltb_write(struct mlxsw_sp *mlxsw_sp, char *xraltb_pl)
-{
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(xraltb), xraltb_pl);
-}
-
-static u16 mlxsw_sp_router_ll_xm_mindex_get4(const u32 addr)
-{
-       /* Currently the M-index is set to linear mode. That means it is defined
-        * as 16 MSB of IP address.
-        */
-       return addr >> MLXSW_SP_ROUTER_XM_L_VAL_MAX;
-}
-
-static u16 mlxsw_sp_router_ll_xm_mindex_get6(const unsigned char *addr)
-{
-       WARN_ON_ONCE(1);
-       return 0; /* currently unused */
-}
-
-static void mlxsw_sp_router_ll_xm_op_ctx_check_init(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                   struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm)
-{
-       if (op_ctx->initialized)
-               return;
-       op_ctx->initialized = true;
-
-       mlxsw_reg_xmdr_pack(op_ctx_xm->xmdr_pl, true);
-       op_ctx_xm->trans_offset = 0;
-       op_ctx_xm->entries_count = 0;
-}
-
-static void mlxsw_sp_router_ll_xm_fib_entry_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                enum mlxsw_sp_l3proto proto,
-                                                enum mlxsw_sp_fib_entry_op op,
-                                                u16 virtual_router, u8 prefix_len,
-                                                unsigned char *addr,
-                                                struct mlxsw_sp_fib_entry_priv *priv)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm = (void *) op_ctx->ll_priv;
-       struct mlxsw_sp_router_xm_fib_entry *fib_entry = (void *) priv->priv;
-       struct mlxsw_sp_router_xm_flush_info *flush_info;
-       enum mlxsw_reg_xmdr_c_ltr_op xmdr_c_ltr_op;
-       unsigned int len;
-
-       mlxsw_sp_router_ll_xm_op_ctx_check_init(op_ctx, op_ctx_xm);
-
-       switch (op) {
-       case MLXSW_SP_FIB_ENTRY_OP_WRITE:
-               xmdr_c_ltr_op = MLXSW_REG_XMDR_C_LTR_OP_WRITE;
-               break;
-       case MLXSW_SP_FIB_ENTRY_OP_UPDATE:
-               xmdr_c_ltr_op = MLXSW_REG_XMDR_C_LTR_OP_UPDATE;
-               break;
-       case MLXSW_SP_FIB_ENTRY_OP_DELETE:
-               xmdr_c_ltr_op = MLXSW_REG_XMDR_C_LTR_OP_DELETE;
-               break;
-       default:
-               WARN_ON_ONCE(1);
-               return;
-       }
-
-       switch (proto) {
-       case MLXSW_SP_L3_PROTO_IPV4:
-               len = mlxsw_reg_xmdr_c_ltr_pack4(op_ctx_xm->xmdr_pl, op_ctx_xm->trans_offset,
-                                                op_ctx_xm->entries_count, xmdr_c_ltr_op,
-                                                virtual_router, prefix_len, (u32 *) addr);
-               fib_entry->mindex = mlxsw_sp_router_ll_xm_mindex_get4(*((u32 *) addr));
-               break;
-       case MLXSW_SP_L3_PROTO_IPV6:
-               len = mlxsw_reg_xmdr_c_ltr_pack6(op_ctx_xm->xmdr_pl, op_ctx_xm->trans_offset,
-                                                op_ctx_xm->entries_count, xmdr_c_ltr_op,
-                                                virtual_router, prefix_len, addr);
-               fib_entry->mindex = mlxsw_sp_router_ll_xm_mindex_get6(addr);
-               break;
-       default:
-               WARN_ON_ONCE(1);
-               return;
-       }
-       if (!op_ctx_xm->trans_offset)
-               op_ctx_xm->trans_item_len = len;
-       else
-               WARN_ON_ONCE(op_ctx_xm->trans_item_len != len);
-
-       op_ctx_xm->entries[op_ctx_xm->entries_count] = fib_entry;
-
-       fib_entry->lvalue = prefix_len > mlxsw_sp_router_xm_m_val[proto] ?
-                              prefix_len - mlxsw_sp_router_xm_m_val[proto] : 0;
-
-       flush_info = &fib_entry->flush_info;
-       flush_info->proto = proto;
-       flush_info->virtual_router = virtual_router;
-       flush_info->prefix_len = prefix_len;
-       if (addr)
-               memcpy(flush_info->addr, addr, sizeof(flush_info->addr));
-       else
-               memset(flush_info->addr, 0, sizeof(flush_info->addr));
-}
-
-static void
-mlxsw_sp_router_ll_xm_fib_entry_act_remote_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                               enum mlxsw_reg_ralue_trap_action trap_action,
-                                               u16 trap_id, u32 adjacency_index, u16 ecmp_size)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_xmdr_c_ltr_act_remote_pack(op_ctx_xm->xmdr_pl, op_ctx_xm->trans_offset,
-                                            trap_action, trap_id, adjacency_index, ecmp_size);
-}
-
-static void
-mlxsw_sp_router_ll_xm_fib_entry_act_local_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                             enum mlxsw_reg_ralue_trap_action trap_action,
-                                              u16 trap_id, u16 local_erif)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_xmdr_c_ltr_act_local_pack(op_ctx_xm->xmdr_pl, op_ctx_xm->trans_offset,
-                                           trap_action, trap_id, local_erif);
-}
-
-static void
-mlxsw_sp_router_ll_xm_fib_entry_act_ip2me_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_xmdr_c_ltr_act_ip2me_pack(op_ctx_xm->xmdr_pl, op_ctx_xm->trans_offset);
-}
-
-static void
-mlxsw_sp_router_ll_xm_fib_entry_act_ip2me_tun_pack(struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                  u32 tunnel_ptr)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm = (void *) op_ctx->ll_priv;
-
-       mlxsw_reg_xmdr_c_ltr_act_ip2me_tun_pack(op_ctx_xm->xmdr_pl, op_ctx_xm->trans_offset,
-                                               tunnel_ptr);
-}
-
-static struct mlxsw_sp_router_xm_ltable_node *
-mlxsw_sp_router_xm_ltable_node_get(struct mlxsw_sp_router_xm *router_xm, u16 mindex)
-{
-       struct mlxsw_sp_router_xm_ltable_node *ltable_node;
-       int err;
-
-       ltable_node = rhashtable_lookup_fast(&router_xm->ltable_ht, &mindex,
-                                            mlxsw_sp_router_xm_ltable_ht_params);
-       if (ltable_node) {
-               refcount_inc(&ltable_node->refcnt);
-               return ltable_node;
-       }
-       ltable_node = kzalloc(sizeof(*ltable_node), GFP_KERNEL);
-       if (!ltable_node)
-               return ERR_PTR(-ENOMEM);
-       ltable_node->mindex = mindex;
-       refcount_set(&ltable_node->refcnt, 1);
-
-       err = rhashtable_insert_fast(&router_xm->ltable_ht, &ltable_node->ht_node,
-                                    mlxsw_sp_router_xm_ltable_ht_params);
-       if (err)
-               goto err_insert;
-
-       return ltable_node;
-
-err_insert:
-       kfree(ltable_node);
-       return ERR_PTR(err);
-}
-
-static void mlxsw_sp_router_xm_ltable_node_put(struct mlxsw_sp_router_xm *router_xm,
-                                              struct mlxsw_sp_router_xm_ltable_node *ltable_node)
-{
-       if (!refcount_dec_and_test(&ltable_node->refcnt))
-               return;
-       rhashtable_remove_fast(&router_xm->ltable_ht, &ltable_node->ht_node,
-                              mlxsw_sp_router_xm_ltable_ht_params);
-       kfree(ltable_node);
-}
-
-static int mlxsw_sp_router_xm_ltable_lvalue_set(struct mlxsw_sp *mlxsw_sp,
-                                               struct mlxsw_sp_router_xm_ltable_node *ltable_node)
-{
-       char xrmt_pl[MLXSW_REG_XRMT_LEN];
-
-       mlxsw_reg_xrmt_pack(xrmt_pl, ltable_node->mindex, ltable_node->current_lvalue);
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(xrmt), xrmt_pl);
-}
-
-struct mlxsw_sp_router_xm_flush_node {
-       struct rhash_head ht_node; /* Member of router_xm->flush_ht */
-       struct list_head list;
-       struct mlxsw_sp_router_xm_flush_info flush_info;
-       struct delayed_work dw;
-       struct mlxsw_sp *mlxsw_sp;
-       unsigned long start_jiffies;
-       unsigned int reuses; /* By how many flush calls this was reused. */
-       refcount_t refcnt;
-};
-
-static const struct rhashtable_params mlxsw_sp_router_xm_flush_ht_params = {
-       .key_offset = offsetof(struct mlxsw_sp_router_xm_flush_node, flush_info),
-       .head_offset = offsetof(struct mlxsw_sp_router_xm_flush_node, ht_node),
-       .key_len = sizeof(struct mlxsw_sp_router_xm_flush_info),
-       .automatic_shrinking = true,
-};
-
-static struct mlxsw_sp_router_xm_flush_node *
-mlxsw_sp_router_xm_cache_flush_node_create(struct mlxsw_sp *mlxsw_sp,
-                                          struct mlxsw_sp_router_xm_flush_info *flush_info)
-{
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-       struct mlxsw_sp_router_xm_flush_node *flush_node;
-       int err;
-
-       flush_node = kzalloc(sizeof(*flush_node), GFP_KERNEL);
-       if (!flush_node)
-               return ERR_PTR(-ENOMEM);
-
-       flush_node->flush_info = *flush_info;
-       err = rhashtable_insert_fast(&router_xm->flush_ht, &flush_node->ht_node,
-                                    mlxsw_sp_router_xm_flush_ht_params);
-       if (err) {
-               kfree(flush_node);
-               return ERR_PTR(err);
-       }
-       router_xm->flush_count++;
-       flush_node->mlxsw_sp = mlxsw_sp;
-       flush_node->start_jiffies = jiffies;
-       refcount_set(&flush_node->refcnt, 1);
-       return flush_node;
-}
-
-static void
-mlxsw_sp_router_xm_cache_flush_node_hold(struct mlxsw_sp_router_xm_flush_node *flush_node)
-{
-       if (!flush_node)
-               return;
-       refcount_inc(&flush_node->refcnt);
-}
-
-static void
-mlxsw_sp_router_xm_cache_flush_node_put(struct mlxsw_sp_router_xm_flush_node *flush_node)
-{
-       if (!flush_node || !refcount_dec_and_test(&flush_node->refcnt))
-               return;
-       kfree(flush_node);
-}
-
-static void
-mlxsw_sp_router_xm_cache_flush_node_destroy(struct mlxsw_sp *mlxsw_sp,
-                                           struct mlxsw_sp_router_xm_flush_node *flush_node)
-{
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-
-       router_xm->flush_count--;
-       rhashtable_remove_fast(&router_xm->flush_ht, &flush_node->ht_node,
-                              mlxsw_sp_router_xm_flush_ht_params);
-       mlxsw_sp_router_xm_cache_flush_node_put(flush_node);
-}
-
-static u32 mlxsw_sp_router_xm_flush_mask4(u8 prefix_len)
-{
-       return GENMASK(31, 32 - prefix_len);
-}
-
-static unsigned char *mlxsw_sp_router_xm_flush_mask6(u8 prefix_len)
-{
-       static unsigned char mask[sizeof(struct in6_addr)];
-
-       memset(mask, 0, sizeof(mask));
-       memset(mask, 0xff, prefix_len / 8);
-       mask[prefix_len / 8] = GENMASK(8, 8 - prefix_len % 8);
-       return mask;
-}
-
-#define MLXSW_SP_ROUTER_XM_CACHE_PARALLEL_FLUSHES_LIMIT 15
-#define MLXSW_SP_ROUTER_XM_CACHE_FLUSH_ALL_MIN_REUSES 15
-#define MLXSW_SP_ROUTER_XM_CACHE_DELAY 50 /* usecs */
-#define MLXSW_SP_ROUTER_XM_CACHE_MAX_WAIT (MLXSW_SP_ROUTER_XM_CACHE_DELAY * 10)
-
-static void mlxsw_sp_router_xm_cache_flush_work(struct work_struct *work)
-{
-       struct mlxsw_sp_router_xm_flush_info *flush_info;
-       struct mlxsw_sp_router_xm_flush_node *flush_node;
-       char rlcmld_pl[MLXSW_REG_RLCMLD_LEN];
-       enum mlxsw_reg_rlcmld_select select;
-       struct mlxsw_sp *mlxsw_sp;
-       u32 addr4;
-       int err;
-
-       flush_node = container_of(work, struct mlxsw_sp_router_xm_flush_node,
-                                 dw.work);
-       mlxsw_sp = flush_node->mlxsw_sp;
-       flush_info = &flush_node->flush_info;
-
-       if (flush_info->all) {
-               char rlpmce_pl[MLXSW_REG_RLPMCE_LEN];
-
-               mlxsw_reg_rlpmce_pack(rlpmce_pl, true, false);
-               err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rlpmce),
-                                     rlpmce_pl);
-               if (err)
-                       dev_err(mlxsw_sp->bus_info->dev, "Failed to flush XM cache\n");
-
-               if (flush_node->reuses <
-                   MLXSW_SP_ROUTER_XM_CACHE_FLUSH_ALL_MIN_REUSES)
-                       /* Leaving flush-all mode. */
-                       mlxsw_sp->router->xm->flush_all_mode = false;
-               goto out;
-       }
-
-       select = MLXSW_REG_RLCMLD_SELECT_M_AND_ML_ENTRIES;
-
-       switch (flush_info->proto) {
-       case MLXSW_SP_L3_PROTO_IPV4:
-               addr4 = *((u32 *) flush_info->addr);
-               addr4 &= mlxsw_sp_router_xm_flush_mask4(flush_info->prefix_len);
-
-               /* In case the flush prefix length is bigger than M-value,
-                * it makes no sense to flush M entries. So just flush
-                * the ML entries.
-                */
-               if (flush_info->prefix_len > MLXSW_SP_ROUTER_XM_M_VAL)
-                       select = MLXSW_REG_RLCMLD_SELECT_ML_ENTRIES;
-
-               mlxsw_reg_rlcmld_pack4(rlcmld_pl, select,
-                                      flush_info->virtual_router, addr4,
-                                      mlxsw_sp_router_xm_flush_mask4(flush_info->prefix_len));
-               break;
-       case MLXSW_SP_L3_PROTO_IPV6:
-               mlxsw_reg_rlcmld_pack6(rlcmld_pl, select,
-                                      flush_info->virtual_router, flush_info->addr,
-                                      mlxsw_sp_router_xm_flush_mask6(flush_info->prefix_len));
-               break;
-       default:
-               WARN_ON(true);
-               goto out;
-       }
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rlcmld), rlcmld_pl);
-       if (err)
-               dev_err(mlxsw_sp->bus_info->dev, "Failed to flush XM cache\n");
-
-out:
-       mlxsw_sp_router_xm_cache_flush_node_destroy(mlxsw_sp, flush_node);
-}
-
-static bool
-mlxsw_sp_router_xm_cache_flush_may_cancel(struct mlxsw_sp_router_xm_flush_node *flush_node)
-{
-       unsigned long max_wait = usecs_to_jiffies(MLXSW_SP_ROUTER_XM_CACHE_MAX_WAIT);
-       unsigned long delay = usecs_to_jiffies(MLXSW_SP_ROUTER_XM_CACHE_DELAY);
-
-       /* In case there is the same flushing work pending, check
-        * if we can consolidate with it. We can do it up to MAX_WAIT.
-        * Cancel the delayed work. If the work was still pending.
-        */
-       if (time_is_before_jiffies(flush_node->start_jiffies + max_wait - delay) &&
-           cancel_delayed_work_sync(&flush_node->dw))
-               return true;
-       return false;
-}
-
-static int
-mlxsw_sp_router_xm_cache_flush_schedule(struct mlxsw_sp *mlxsw_sp,
-                                       struct mlxsw_sp_router_xm_flush_info *flush_info)
-{
-       unsigned long delay = usecs_to_jiffies(MLXSW_SP_ROUTER_XM_CACHE_DELAY);
-       struct mlxsw_sp_router_xm_flush_info flush_all_info = {.all = true};
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-       struct mlxsw_sp_router_xm_flush_node *flush_node;
-
-       /* Check if the queued number of flushes reached critical amount after
-        * which it is better to just flush the whole cache.
-        */
-       if (router_xm->flush_count == MLXSW_SP_ROUTER_XM_CACHE_PARALLEL_FLUSHES_LIMIT)
-               /* Entering flush-all mode. */
-               router_xm->flush_all_mode = true;
-
-       if (router_xm->flush_all_mode)
-               flush_info = &flush_all_info;
-
-       rcu_read_lock();
-       flush_node = rhashtable_lookup_fast(&router_xm->flush_ht, flush_info,
-                                           mlxsw_sp_router_xm_flush_ht_params);
-       /* Take a reference so the object is not freed before possible
-        * delayed work cancel could be done.
-        */
-       mlxsw_sp_router_xm_cache_flush_node_hold(flush_node);
-       rcu_read_unlock();
-
-       if (flush_node && mlxsw_sp_router_xm_cache_flush_may_cancel(flush_node)) {
-               flush_node->reuses++;
-               mlxsw_sp_router_xm_cache_flush_node_put(flush_node);
-                /* Original work was within wait period and was canceled.
-                 * That means that the reference is still held and the
-                 * flush_node_put() call above did not free the flush_node.
-                 * Reschedule it with fresh delay.
-                 */
-               goto schedule_work;
-       } else {
-               mlxsw_sp_router_xm_cache_flush_node_put(flush_node);
-       }
-
-       flush_node = mlxsw_sp_router_xm_cache_flush_node_create(mlxsw_sp, flush_info);
-       if (IS_ERR(flush_node))
-               return PTR_ERR(flush_node);
-       INIT_DELAYED_WORK(&flush_node->dw, mlxsw_sp_router_xm_cache_flush_work);
-
-schedule_work:
-       mlxsw_core_schedule_dw(&flush_node->dw, delay);
-       return 0;
-}
-
-static int
-mlxsw_sp_router_xm_ml_entry_add(struct mlxsw_sp *mlxsw_sp,
-                               struct mlxsw_sp_router_xm_fib_entry *fib_entry)
-{
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-       struct mlxsw_sp_router_xm_ltable_node *ltable_node;
-       u8 lvalue = fib_entry->lvalue;
-       int err;
-
-       ltable_node = mlxsw_sp_router_xm_ltable_node_get(router_xm,
-                                                        fib_entry->mindex);
-       if (IS_ERR(ltable_node))
-               return PTR_ERR(ltable_node);
-       if (lvalue > ltable_node->current_lvalue) {
-               /* The L-value is bigger then the one currently set, update. */
-               ltable_node->current_lvalue = lvalue;
-               err = mlxsw_sp_router_xm_ltable_lvalue_set(mlxsw_sp,
-                                                          ltable_node);
-               if (err)
-                       goto err_lvalue_set;
-
-               /* The L value for prefix/M is increased.
-                * Therefore, all entries in M and ML caches matching
-                * {prefix/M, proto, VR} need to be flushed. Set the flush
-                * prefix length to M to achieve that.
-                */
-               fib_entry->flush_info.prefix_len = MLXSW_SP_ROUTER_XM_M_VAL;
-       }
-
-       ltable_node->lvalue_ref[lvalue]++;
-       fib_entry->ltable_node = ltable_node;
-
-       return 0;
-
-err_lvalue_set:
-       mlxsw_sp_router_xm_ltable_node_put(router_xm, ltable_node);
-       return err;
-}
-
-static void
-mlxsw_sp_router_xm_ml_entry_del(struct mlxsw_sp *mlxsw_sp,
-                               struct mlxsw_sp_router_xm_fib_entry *fib_entry)
-{
-       struct mlxsw_sp_router_xm_ltable_node *ltable_node =
-                                                       fib_entry->ltable_node;
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-       u8 lvalue = fib_entry->lvalue;
-
-       ltable_node->lvalue_ref[lvalue]--;
-       if (lvalue == ltable_node->current_lvalue && lvalue &&
-           !ltable_node->lvalue_ref[lvalue]) {
-               u8 new_lvalue = lvalue - 1;
-
-               /* Find the biggest L-value left out there. */
-               while (new_lvalue > 0 && !ltable_node->lvalue_ref[lvalue])
-                       new_lvalue--;
-
-               ltable_node->current_lvalue = new_lvalue;
-               mlxsw_sp_router_xm_ltable_lvalue_set(mlxsw_sp, ltable_node);
-
-               /* The L value for prefix/M is decreased.
-                * Therefore, all entries in M and ML caches matching
-                * {prefix/M, proto, VR} need to be flushed. Set the flush
-                * prefix length to M to achieve that.
-                */
-               fib_entry->flush_info.prefix_len = MLXSW_SP_ROUTER_XM_M_VAL;
-       }
-       mlxsw_sp_router_xm_ltable_node_put(router_xm, ltable_node);
-}
-
-static int
-mlxsw_sp_router_xm_ml_entries_add(struct mlxsw_sp *mlxsw_sp,
-                                 struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm)
-{
-       struct mlxsw_sp_router_xm_fib_entry *fib_entry;
-       int err;
-       int i;
-
-       for (i = 0; i < op_ctx_xm->entries_count; i++) {
-               fib_entry = op_ctx_xm->entries[i];
-               err = mlxsw_sp_router_xm_ml_entry_add(mlxsw_sp, fib_entry);
-               if (err)
-                       goto rollback;
-       }
-       return 0;
-
-rollback:
-       for (i--; i >= 0; i--) {
-               fib_entry = op_ctx_xm->entries[i];
-               mlxsw_sp_router_xm_ml_entry_del(mlxsw_sp, fib_entry);
-       }
-       return err;
-}
-
-static void
-mlxsw_sp_router_xm_ml_entries_del(struct mlxsw_sp *mlxsw_sp,
-                                 struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm)
-{
-       struct mlxsw_sp_router_xm_fib_entry *fib_entry;
-       int i;
-
-       for (i = 0; i < op_ctx_xm->entries_count; i++) {
-               fib_entry = op_ctx_xm->entries[i];
-               mlxsw_sp_router_xm_ml_entry_del(mlxsw_sp, fib_entry);
-       }
-}
-
-static void
-mlxsw_sp_router_xm_ml_entries_cache_flush(struct mlxsw_sp *mlxsw_sp,
-                                         struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm)
-{
-       struct mlxsw_sp_router_xm_fib_entry *fib_entry;
-       int err;
-       int i;
-
-       for (i = 0; i < op_ctx_xm->entries_count; i++) {
-               fib_entry = op_ctx_xm->entries[i];
-               err = mlxsw_sp_router_xm_cache_flush_schedule(mlxsw_sp,
-                                                             &fib_entry->flush_info);
-               if (err)
-                       dev_err(mlxsw_sp->bus_info->dev, "Failed to flush XM cache\n");
-       }
-}
-
-static int mlxsw_sp_router_ll_xm_fib_entry_commit(struct mlxsw_sp *mlxsw_sp,
-                                                 struct mlxsw_sp_fib_entry_op_ctx *op_ctx,
-                                                 bool *postponed_for_bulk)
-{
-       struct mlxsw_sp_fib_entry_op_ctx_xm *op_ctx_xm = (void *) op_ctx->ll_priv;
-       struct mlxsw_sp_router_xm_fib_entry *fib_entry;
-       u8 num_rec;
-       int err;
-       int i;
-
-       op_ctx_xm->trans_offset += op_ctx_xm->trans_item_len;
-       op_ctx_xm->entries_count++;
-
-       /* Check if bulking is possible and there is still room for another
-        * FIB entry record. The size of 'trans_item_len' is either size of IPv4
-        * command or size of IPv6 command. Not possible to mix those in a
-        * single XMDR write.
-        */
-       if (op_ctx->bulk_ok &&
-           op_ctx_xm->trans_offset + op_ctx_xm->trans_item_len <= MLXSW_REG_XMDR_TRANS_LEN) {
-               if (postponed_for_bulk)
-                       *postponed_for_bulk = true;
-               return 0;
-       }
-
-       if (op_ctx->event == FIB_EVENT_ENTRY_REPLACE) {
-               /* The L-table is updated inside. It has to be done before
-                * the prefix is inserted.
-                */
-               err = mlxsw_sp_router_xm_ml_entries_add(mlxsw_sp, op_ctx_xm);
-               if (err)
-                       goto out;
-       }
-
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(xmdr), op_ctx_xm->xmdr_pl);
-       if (err)
-               goto out;
-       num_rec = mlxsw_reg_xmdr_num_rec_get(op_ctx_xm->xmdr_pl);
-       if (num_rec > op_ctx_xm->entries_count) {
-               dev_err(mlxsw_sp->bus_info->dev, "Invalid XMDR number of records\n");
-               err = -EIO;
-               goto out;
-       }
-       for (i = 0; i < num_rec; i++) {
-               if (!mlxsw_reg_xmdr_reply_vect_get(op_ctx_xm->xmdr_pl, i)) {
-                       dev_err(mlxsw_sp->bus_info->dev, "Command send over XMDR failed\n");
-                       err = -EIO;
-                       goto out;
-               } else {
-                       fib_entry = op_ctx_xm->entries[i];
-                       fib_entry->committed = true;
-               }
-       }
-
-       if (op_ctx->event == FIB_EVENT_ENTRY_DEL)
-               /* The L-table is updated inside. It has to be done after
-                * the prefix was removed.
-                */
-               mlxsw_sp_router_xm_ml_entries_del(mlxsw_sp, op_ctx_xm);
-
-       /* At the very end, do the XLT cache flushing to evict stale
-        * M and ML cache entries after prefixes were inserted/removed.
-        */
-       mlxsw_sp_router_xm_ml_entries_cache_flush(mlxsw_sp, op_ctx_xm);
-
-out:
-       /* Next pack call is going to do reinitialization */
-       op_ctx->initialized = false;
-       return err;
-}
-
-static bool mlxsw_sp_router_ll_xm_fib_entry_is_committed(struct mlxsw_sp_fib_entry_priv *priv)
-{
-       struct mlxsw_sp_router_xm_fib_entry *fib_entry = (void *) priv->priv;
-
-       return fib_entry->committed;
-}
-
-const struct mlxsw_sp_router_ll_ops mlxsw_sp_router_ll_xm_ops = {
-       .init = mlxsw_sp_router_ll_xm_init,
-       .ralta_write = mlxsw_sp_router_ll_xm_ralta_write,
-       .ralst_write = mlxsw_sp_router_ll_xm_ralst_write,
-       .raltb_write = mlxsw_sp_router_ll_xm_raltb_write,
-       .fib_entry_op_ctx_size = sizeof(struct mlxsw_sp_fib_entry_op_ctx_xm),
-       .fib_entry_priv_size = sizeof(struct mlxsw_sp_router_xm_fib_entry),
-       .fib_entry_pack = mlxsw_sp_router_ll_xm_fib_entry_pack,
-       .fib_entry_act_remote_pack = mlxsw_sp_router_ll_xm_fib_entry_act_remote_pack,
-       .fib_entry_act_local_pack = mlxsw_sp_router_ll_xm_fib_entry_act_local_pack,
-       .fib_entry_act_ip2me_pack = mlxsw_sp_router_ll_xm_fib_entry_act_ip2me_pack,
-       .fib_entry_act_ip2me_tun_pack = mlxsw_sp_router_ll_xm_fib_entry_act_ip2me_tun_pack,
-       .fib_entry_commit = mlxsw_sp_router_ll_xm_fib_entry_commit,
-       .fib_entry_is_committed = mlxsw_sp_router_ll_xm_fib_entry_is_committed,
-};
-
-#define MLXSW_SP_ROUTER_XM_MINDEX_SIZE (64 * 1024)
-
-int mlxsw_sp_router_xm_init(struct mlxsw_sp *mlxsw_sp)
-{
-       struct mlxsw_sp_router_xm *router_xm;
-       char rxltm_pl[MLXSW_REG_RXLTM_LEN];
-       char xltq_pl[MLXSW_REG_XLTQ_LEN];
-       u32 mindex_size;
-       u16 device_id;
-       int err;
-
-       if (!mlxsw_sp->bus_info->xm_exists)
-               return 0;
-
-       router_xm = kzalloc(sizeof(*router_xm), GFP_KERNEL);
-       if (!router_xm)
-               return -ENOMEM;
-
-       mlxsw_reg_xltq_pack(xltq_pl);
-       err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(xltq), xltq_pl);
-       if (err)
-               goto err_xltq_query;
-       mlxsw_reg_xltq_unpack(xltq_pl, &device_id, &router_xm->ipv4_supported,
-                             &router_xm->ipv6_supported, &router_xm->entries_size, &mindex_size);
-
-       if (device_id != MLXSW_REG_XLTQ_XM_DEVICE_ID_XLT) {
-               dev_err(mlxsw_sp->bus_info->dev, "Invalid XM device id\n");
-               err = -EINVAL;
-               goto err_device_id_check;
-       }
-
-       if (mindex_size != MLXSW_SP_ROUTER_XM_MINDEX_SIZE) {
-               dev_err(mlxsw_sp->bus_info->dev, "Unexpected M-index size\n");
-               err = -EINVAL;
-               goto err_mindex_size_check;
-       }
-
-       mlxsw_reg_rxltm_pack(rxltm_pl, mlxsw_sp_router_xm_m_val[MLXSW_SP_L3_PROTO_IPV4],
-                            mlxsw_sp_router_xm_m_val[MLXSW_SP_L3_PROTO_IPV6]);
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rxltm), rxltm_pl);
-       if (err)
-               goto err_rxltm_write;
-
-       err = rhashtable_init(&router_xm->ltable_ht, &mlxsw_sp_router_xm_ltable_ht_params);
-       if (err)
-               goto err_ltable_ht_init;
-
-       err = rhashtable_init(&router_xm->flush_ht, &mlxsw_sp_router_xm_flush_ht_params);
-       if (err)
-               goto err_flush_ht_init;
-
-       mlxsw_sp->router->xm = router_xm;
-       return 0;
-
-err_flush_ht_init:
-       rhashtable_destroy(&router_xm->ltable_ht);
-err_ltable_ht_init:
-err_rxltm_write:
-err_mindex_size_check:
-err_device_id_check:
-err_xltq_query:
-       kfree(router_xm);
-       return err;
-}
-
-void mlxsw_sp_router_xm_fini(struct mlxsw_sp *mlxsw_sp)
-{
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-
-       if (!mlxsw_sp->bus_info->xm_exists)
-               return;
-
-       rhashtable_destroy(&router_xm->flush_ht);
-       rhashtable_destroy(&router_xm->ltable_ht);
-       kfree(router_xm);
-}
-
-bool mlxsw_sp_router_xm_ipv4_is_supported(const struct mlxsw_sp *mlxsw_sp)
-{
-       struct mlxsw_sp_router_xm *router_xm = mlxsw_sp->router->xm;
-
-       return router_xm && router_xm->ipv4_supported;
-}
index a6d2e80..4efccd9 100644 (file)
@@ -48,7 +48,8 @@ struct mlxsw_sp_bridge_device {
        struct net_device *dev;
        struct list_head list;
        struct list_head ports_list;
-       struct list_head mids_list;
+       struct list_head mdb_list;
+       struct rhashtable mdb_ht;
        u8 vlan_enabled:1,
           multicast_enabled:1,
           mrouter:1;
@@ -102,6 +103,33 @@ struct mlxsw_sp_switchdev_ops {
        void (*init)(struct mlxsw_sp *mlxsw_sp);
 };
 
+struct mlxsw_sp_mdb_entry_key {
+       unsigned char addr[ETH_ALEN];
+       u16 fid;
+};
+
+struct mlxsw_sp_mdb_entry {
+       struct list_head list;
+       struct rhash_head ht_node;
+       struct mlxsw_sp_mdb_entry_key key;
+       u16 mid;
+       struct list_head ports_list;
+       u16 ports_count;
+};
+
+struct mlxsw_sp_mdb_entry_port {
+       struct list_head list; /* Member of 'ports_list'. */
+       u16 local_port;
+       refcount_t refcount;
+       bool mrouter;
+};
+
+static const struct rhashtable_params mlxsw_sp_mdb_ht_params = {
+       .key_offset = offsetof(struct mlxsw_sp_mdb_entry, key),
+       .head_offset = offsetof(struct mlxsw_sp_mdb_entry, ht_node),
+       .key_len = sizeof(struct mlxsw_sp_mdb_entry_key),
+};
+
 static int
 mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
                               struct mlxsw_sp_bridge_port *bridge_port,
@@ -109,12 +137,13 @@ mlxsw_sp_bridge_port_fdb_flush(struct mlxsw_sp *mlxsw_sp,
 
 static void
 mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
-                              struct mlxsw_sp_bridge_port *bridge_port);
+                              struct mlxsw_sp_bridge_port *bridge_port,
+                              u16 fid_index);
 
-static void
-mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
+static int
+mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp *mlxsw_sp,
                                   struct mlxsw_sp_bridge_device
-                                  *bridge_device);
+                                  *bridge_device, bool mc_enabled);
 
 static void
 mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -237,6 +266,10 @@ mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
        if (!bridge_device)
                return ERR_PTR(-ENOMEM);
 
+       err = rhashtable_init(&bridge_device->mdb_ht, &mlxsw_sp_mdb_ht_params);
+       if (err)
+               goto err_mdb_rhashtable_init;
+
        bridge_device->dev = br_dev;
        bridge_device->vlan_enabled = vlan_enabled;
        bridge_device->multicast_enabled = br_multicast_enabled(br_dev);
@@ -254,7 +287,8 @@ mlxsw_sp_bridge_device_create(struct mlxsw_sp_bridge *bridge,
        } else {
                bridge_device->ops = bridge->bridge_8021d_ops;
        }
-       INIT_LIST_HEAD(&bridge_device->mids_list);
+       INIT_LIST_HEAD(&bridge_device->mdb_list);
+
        if (list_empty(&bridge->bridges_list))
                mlxsw_sp_fdb_notify_work_schedule(bridge->mlxsw_sp, false);
        list_add(&bridge_device->list, &bridge->bridges_list);
@@ -273,6 +307,8 @@ err_vxlan_init:
        list_del(&bridge_device->list);
        if (bridge_device->vlan_enabled)
                bridge->vlan_enabled_exists = false;
+       rhashtable_destroy(&bridge_device->mdb_ht);
+err_mdb_rhashtable_init:
        kfree(bridge_device);
        return ERR_PTR(err);
 }
@@ -290,7 +326,8 @@ mlxsw_sp_bridge_device_destroy(struct mlxsw_sp_bridge *bridge,
        if (bridge_device->vlan_enabled)
                bridge->vlan_enabled_exists = false;
        WARN_ON(!list_empty(&bridge_device->ports_list));
-       WARN_ON(!list_empty(&bridge_device->mids_list));
+       WARN_ON(!list_empty(&bridge_device->mdb_list));
+       rhashtable_destroy(&bridge_device->mdb_ht);
        kfree(bridge_device);
 }
 
@@ -643,6 +680,64 @@ err_port_bridge_vlan_flood_set:
 }
 
 static int
+mlxsw_sp_bridge_vlans_flood_set(struct mlxsw_sp_bridge_vlan *bridge_vlan,
+                               enum mlxsw_sp_flood_type packet_type,
+                               bool member)
+{
+       struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
+       int err;
+
+       list_for_each_entry(mlxsw_sp_port_vlan, &bridge_vlan->port_vlan_list,
+                           bridge_vlan_node) {
+               u16 local_port = mlxsw_sp_port_vlan->mlxsw_sp_port->local_port;
+
+               err = mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid,
+                                            packet_type, local_port, member);
+               if (err)
+                       goto err_fid_flood_set;
+       }
+
+       return 0;
+
+err_fid_flood_set:
+       list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
+                                            &bridge_vlan->port_vlan_list,
+                                            list) {
+               u16 local_port = mlxsw_sp_port_vlan->mlxsw_sp_port->local_port;
+
+               mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid, packet_type,
+                                      local_port, !member);
+       }
+
+       return err;
+}
+
+static int
+mlxsw_sp_bridge_ports_flood_table_set(struct mlxsw_sp_bridge_port *bridge_port,
+                                     enum mlxsw_sp_flood_type packet_type,
+                                     bool member)
+{
+       struct mlxsw_sp_bridge_vlan *bridge_vlan;
+       int err;
+
+       list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) {
+               err = mlxsw_sp_bridge_vlans_flood_set(bridge_vlan, packet_type,
+                                                     member);
+               if (err)
+                       goto err_bridge_vlans_flood_set;
+       }
+
+       return 0;
+
+err_bridge_vlans_flood_set:
+       list_for_each_entry_continue_reverse(bridge_vlan,
+                                            &bridge_port->vlans_list, list)
+               mlxsw_sp_bridge_vlans_flood_set(bridge_vlan, packet_type,
+                                               !member);
+       return err;
+}
+
+static int
 mlxsw_sp_port_bridge_vlan_learning_set(struct mlxsw_sp_port *mlxsw_sp_port,
                                       struct mlxsw_sp_bridge_vlan *bridge_vlan,
                                       bool set)
@@ -813,6 +908,9 @@ static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
        if (!bridge_port)
                return 0;
 
+       mlxsw_sp_port_mrouter_update_mdb(mlxsw_sp_port, bridge_port,
+                                        is_port_mrouter);
+
        if (!bridge_port->bridge_device->multicast_enabled)
                goto out;
 
@@ -822,8 +920,6 @@ static int mlxsw_sp_port_attr_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port,
        if (err)
                return err;
 
-       mlxsw_sp_port_mrouter_update_mdb(mlxsw_sp_port, bridge_port,
-                                        is_port_mrouter);
 out:
        bridge_port->mrouter = is_port_mrouter;
        return 0;
@@ -842,6 +938,7 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
                                         struct net_device *orig_dev,
                                         bool mc_disabled)
 {
+       enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC;
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_bridge_device *bridge_device;
        struct mlxsw_sp_bridge_port *bridge_port;
@@ -854,43 +951,184 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port,
        if (!bridge_device)
                return 0;
 
-       if (bridge_device->multicast_enabled != !mc_disabled) {
-               bridge_device->multicast_enabled = !mc_disabled;
-               mlxsw_sp_bridge_mdb_mc_enable_sync(mlxsw_sp_port,
-                                                  bridge_device);
-       }
+       if (bridge_device->multicast_enabled == !mc_disabled)
+               return 0;
+
+       bridge_device->multicast_enabled = !mc_disabled;
+       err = mlxsw_sp_bridge_mdb_mc_enable_sync(mlxsw_sp, bridge_device,
+                                                !mc_disabled);
+       if (err)
+               goto err_mc_enable_sync;
 
        list_for_each_entry(bridge_port, &bridge_device->ports_list, list) {
-               enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC;
                bool member = mlxsw_sp_mc_flood(bridge_port);
 
-               err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port,
-                                                          bridge_port,
-                                                          packet_type, member);
+               err = mlxsw_sp_bridge_ports_flood_table_set(bridge_port,
+                                                           packet_type,
+                                                           member);
                if (err)
-                       return err;
+                       goto err_flood_table_set;
        }
 
-       bridge_device->multicast_enabled = !mc_disabled;
-
        return 0;
+
+err_flood_table_set:
+       list_for_each_entry_continue_reverse(bridge_port,
+                                            &bridge_device->ports_list, list) {
+               bool member = mlxsw_sp_mc_flood(bridge_port);
+
+               mlxsw_sp_bridge_ports_flood_table_set(bridge_port, packet_type,
+                                                     !member);
+       }
+       mlxsw_sp_bridge_mdb_mc_enable_sync(mlxsw_sp, bridge_device,
+                                          mc_disabled);
+err_mc_enable_sync:
+       bridge_device->multicast_enabled = mc_disabled;
+       return err;
+}
+
+static struct mlxsw_sp_mdb_entry_port *
+mlxsw_sp_mdb_entry_port_lookup(struct mlxsw_sp_mdb_entry *mdb_entry,
+                              u16 local_port)
+{
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
+
+       list_for_each_entry(mdb_entry_port, &mdb_entry->ports_list, list) {
+               if (mdb_entry_port->local_port == local_port)
+                       return mdb_entry_port;
+       }
+
+       return NULL;
 }
 
-static int mlxsw_sp_smid_router_port_set(struct mlxsw_sp *mlxsw_sp,
-                                        u16 mid_idx, bool add)
+static struct mlxsw_sp_mdb_entry_port *
+mlxsw_sp_mdb_entry_port_get(struct mlxsw_sp *mlxsw_sp,
+                           struct mlxsw_sp_mdb_entry *mdb_entry,
+                           u16 local_port)
 {
-       char *smid2_pl;
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
        int err;
 
-       smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL);
-       if (!smid2_pl)
-               return -ENOMEM;
+       mdb_entry_port = mlxsw_sp_mdb_entry_port_lookup(mdb_entry, local_port);
+       if (mdb_entry_port) {
+               if (mdb_entry_port->mrouter &&
+                   refcount_read(&mdb_entry_port->refcount) == 1)
+                       mdb_entry->ports_count++;
 
-       mlxsw_reg_smid2_pack(smid2_pl, mid_idx,
-                            mlxsw_sp_router_port(mlxsw_sp), add);
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl);
-       kfree(smid2_pl);
-       return err;
+               refcount_inc(&mdb_entry_port->refcount);
+               return mdb_entry_port;
+       }
+
+       err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, mdb_entry->mid,
+                                         mdb_entry->key.fid, local_port, true);
+       if (err)
+               return ERR_PTR(err);
+
+       mdb_entry_port = kzalloc(sizeof(*mdb_entry_port), GFP_KERNEL);
+       if (!mdb_entry_port) {
+               err = -ENOMEM;
+               goto err_mdb_entry_port_alloc;
+       }
+
+       mdb_entry_port->local_port = local_port;
+       refcount_set(&mdb_entry_port->refcount, 1);
+       list_add(&mdb_entry_port->list, &mdb_entry->ports_list);
+       mdb_entry->ports_count++;
+
+       return mdb_entry_port;
+
+err_mdb_entry_port_alloc:
+       mlxsw_sp_pgt_entry_port_set(mlxsw_sp, mdb_entry->mid,
+                                   mdb_entry->key.fid, local_port, false);
+       return ERR_PTR(err);
+}
+
+static void
+mlxsw_sp_mdb_entry_port_put(struct mlxsw_sp *mlxsw_sp,
+                           struct mlxsw_sp_mdb_entry *mdb_entry,
+                           u16 local_port, bool force)
+{
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
+
+       mdb_entry_port = mlxsw_sp_mdb_entry_port_lookup(mdb_entry, local_port);
+       if (!mdb_entry_port)
+               return;
+
+       if (!force && !refcount_dec_and_test(&mdb_entry_port->refcount)) {
+               if (mdb_entry_port->mrouter &&
+                   refcount_read(&mdb_entry_port->refcount) == 1)
+                       mdb_entry->ports_count--;
+               return;
+       }
+
+       mdb_entry->ports_count--;
+       list_del(&mdb_entry_port->list);
+       kfree(mdb_entry_port);
+       mlxsw_sp_pgt_entry_port_set(mlxsw_sp, mdb_entry->mid,
+                                   mdb_entry->key.fid, local_port, false);
+}
+
+static __always_unused struct mlxsw_sp_mdb_entry_port *
+mlxsw_sp_mdb_entry_mrouter_port_get(struct mlxsw_sp *mlxsw_sp,
+                                   struct mlxsw_sp_mdb_entry *mdb_entry,
+                                   u16 local_port)
+{
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
+       int err;
+
+       mdb_entry_port = mlxsw_sp_mdb_entry_port_lookup(mdb_entry, local_port);
+       if (mdb_entry_port) {
+               if (!mdb_entry_port->mrouter)
+                       refcount_inc(&mdb_entry_port->refcount);
+               return mdb_entry_port;
+       }
+
+       err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, mdb_entry->mid,
+                                         mdb_entry->key.fid, local_port, true);
+       if (err)
+               return ERR_PTR(err);
+
+       mdb_entry_port = kzalloc(sizeof(*mdb_entry_port), GFP_KERNEL);
+       if (!mdb_entry_port) {
+               err = -ENOMEM;
+               goto err_mdb_entry_port_alloc;
+       }
+
+       mdb_entry_port->local_port = local_port;
+       refcount_set(&mdb_entry_port->refcount, 1);
+       mdb_entry_port->mrouter = true;
+       list_add(&mdb_entry_port->list, &mdb_entry->ports_list);
+
+       return mdb_entry_port;
+
+err_mdb_entry_port_alloc:
+       mlxsw_sp_pgt_entry_port_set(mlxsw_sp, mdb_entry->mid,
+                                   mdb_entry->key.fid, local_port, false);
+       return ERR_PTR(err);
+}
+
+static __always_unused void
+mlxsw_sp_mdb_entry_mrouter_port_put(struct mlxsw_sp *mlxsw_sp,
+                                   struct mlxsw_sp_mdb_entry *mdb_entry,
+                                   u16 local_port)
+{
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
+
+       mdb_entry_port = mlxsw_sp_mdb_entry_port_lookup(mdb_entry, local_port);
+       if (!mdb_entry_port)
+               return;
+
+       if (!mdb_entry_port->mrouter)
+               return;
+
+       mdb_entry_port->mrouter = false;
+       if (!refcount_dec_and_test(&mdb_entry_port->refcount))
+               return;
+
+       list_del(&mdb_entry_port->list);
+       kfree(mdb_entry_port);
+       mlxsw_sp_pgt_entry_port_set(mlxsw_sp, mdb_entry->mid,
+                                   mdb_entry->key.fid, local_port, false);
 }
 
 static void
@@ -898,10 +1136,17 @@ mlxsw_sp_bridge_mrouter_update_mdb(struct mlxsw_sp *mlxsw_sp,
                                   struct mlxsw_sp_bridge_device *bridge_device,
                                   bool add)
 {
-       struct mlxsw_sp_mid *mid;
+       u16 local_port = mlxsw_sp_router_port(mlxsw_sp);
+       struct mlxsw_sp_mdb_entry *mdb_entry;
 
-       list_for_each_entry(mid, &bridge_device->mids_list, list)
-               mlxsw_sp_smid_router_port_set(mlxsw_sp, mid->mid, add);
+       list_for_each_entry(mdb_entry, &bridge_device->mdb_list, list) {
+               if (add)
+                       mlxsw_sp_mdb_entry_mrouter_port_get(mlxsw_sp, mdb_entry,
+                                                           local_port);
+               else
+                       mlxsw_sp_mdb_entry_mrouter_port_put(mlxsw_sp, mdb_entry,
+                                                           local_port);
+       }
 }
 
 static int
@@ -1127,14 +1372,13 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
        struct mlxsw_sp_bridge_vlan *bridge_vlan;
        struct mlxsw_sp_bridge_port *bridge_port;
        u16 vid = mlxsw_sp_port_vlan->vid;
-       bool last_port, last_vlan;
+       bool last_port;
 
        if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q &&
                    mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D))
                return;
 
        bridge_port = mlxsw_sp_port_vlan->bridge_port;
-       last_vlan = list_is_singular(&bridge_port->vlans_list);
        bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid);
        last_port = list_is_singular(&bridge_vlan->port_vlan_list);
 
@@ -1146,8 +1390,9 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
                mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp,
                                               bridge_port,
                                               mlxsw_sp_fid_index(fid));
-       if (last_vlan)
-               mlxsw_sp_bridge_port_mdb_flush(mlxsw_sp_port, bridge_port);
+
+       mlxsw_sp_bridge_port_mdb_flush(mlxsw_sp_port, bridge_port,
+                                      mlxsw_sp_fid_index(fid));
 
        mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan);
 
@@ -1436,7 +1681,8 @@ static int mlxsw_sp_port_fdb_tunnel_uc_op(struct mlxsw_sp *mlxsw_sp,
 }
 
 static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u16 local_port,
-                                    const char *mac, u16 fid, bool adding,
+                                    const char *mac, u16 fid, u16 vid,
+                                    bool adding,
                                     enum mlxsw_reg_sfd_rec_action action,
                                     enum mlxsw_reg_sfd_rec_policy policy)
 {
@@ -1449,7 +1695,8 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u16 local_port,
                return -ENOMEM;
 
        mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
-       mlxsw_reg_sfd_uc_pack(sfd_pl, 0, policy, mac, fid, action, local_port);
+       mlxsw_reg_sfd_uc_pack(sfd_pl, 0, policy, mac, fid, vid, action,
+                             local_port);
        num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
        if (err)
@@ -1464,18 +1711,18 @@ out:
 }
 
 static int mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u16 local_port,
-                                  const char *mac, u16 fid, bool adding,
-                                  bool dynamic)
+                                  const char *mac, u16 fid, u16 vid,
+                                  bool adding, bool dynamic)
 {
-       return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding,
-                                        MLXSW_REG_SFD_REC_ACTION_NOP,
+       return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, vid,
+                                        adding, MLXSW_REG_SFD_REC_ACTION_NOP,
                                         mlxsw_sp_sfd_rec_policy(dynamic));
 }
 
 int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid,
                        bool adding)
 {
-       return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, adding,
+       return __mlxsw_sp_port_fdb_uc_op(mlxsw_sp, 0, mac, fid, 0, adding,
                                         MLXSW_REG_SFD_REC_ACTION_FORWARD_IP_ROUTER,
                                         MLXSW_REG_SFD_REC_POLICY_STATIC_ENTRY);
 }
@@ -1537,7 +1784,7 @@ mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port,
        if (!bridge_port->lagged)
                return mlxsw_sp_port_fdb_uc_op(mlxsw_sp,
                                               bridge_port->system_port,
-                                              fdb_info->addr, fid_index,
+                                              fdb_info->addr, fid_index, vid,
                                               adding, false);
        else
                return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp,
@@ -1546,8 +1793,9 @@ mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port,
                                                   vid, adding, false);
 }
 
-static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
-                               u16 fid, u16 mid_idx, bool adding)
+static int mlxsw_sp_mdb_entry_write(struct mlxsw_sp *mlxsw_sp,
+                                   const struct mlxsw_sp_mdb_entry *mdb_entry,
+                                   bool adding)
 {
        char *sfd_pl;
        u8 num_rec;
@@ -1558,8 +1806,9 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
                return -ENOMEM;
 
        mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
-       mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid,
-                             MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx);
+       mlxsw_reg_sfd_mc_pack(sfd_pl, 0, mdb_entry->key.addr,
+                             mdb_entry->key.fid, MLXSW_REG_SFD_REC_ACTION_NOP,
+                             mdb_entry->mid);
        num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
        if (err)
@@ -1573,79 +1822,17 @@ out:
        return err;
 }
 
-static int mlxsw_sp_port_smid_full_entry(struct mlxsw_sp *mlxsw_sp, u16 mid_idx,
-                                        long *ports_bitmap,
-                                        bool set_router_port)
-{
-       char *smid2_pl;
-       int err, i;
-
-       smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL);
-       if (!smid2_pl)
-               return -ENOMEM;
-
-       mlxsw_reg_smid2_pack(smid2_pl, mid_idx, 0, false);
-       for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
-               if (mlxsw_sp->ports[i])
-                       mlxsw_reg_smid2_port_mask_set(smid2_pl, i, 1);
-       }
-
-       mlxsw_reg_smid2_port_mask_set(smid2_pl,
-                                     mlxsw_sp_router_port(mlxsw_sp), 1);
-
-       for_each_set_bit(i, ports_bitmap, mlxsw_core_max_ports(mlxsw_sp->core))
-               mlxsw_reg_smid2_port_set(smid2_pl, i, 1);
-
-       mlxsw_reg_smid2_port_set(smid2_pl, mlxsw_sp_router_port(mlxsw_sp),
-                                set_router_port);
-
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl);
-       kfree(smid2_pl);
-       return err;
-}
-
-static int mlxsw_sp_port_smid_set(struct mlxsw_sp_port *mlxsw_sp_port,
-                                 u16 mid_idx, bool add)
-{
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
-       char *smid2_pl;
-       int err;
-
-       smid2_pl = kmalloc(MLXSW_REG_SMID2_LEN, GFP_KERNEL);
-       if (!smid2_pl)
-               return -ENOMEM;
-
-       mlxsw_reg_smid2_pack(smid2_pl, mid_idx, mlxsw_sp_port->local_port, add);
-       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smid2), smid2_pl);
-       kfree(smid2_pl);
-       return err;
-}
-
-static struct
-mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp_bridge_device *bridge_device,
-                               const unsigned char *addr,
-                               u16 fid)
-{
-       struct mlxsw_sp_mid *mid;
-
-       list_for_each_entry(mid, &bridge_device->mids_list, list) {
-               if (ether_addr_equal(mid->addr, addr) && mid->fid == fid)
-                       return mid;
-       }
-       return NULL;
-}
-
 static void
 mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp *mlxsw_sp,
                                      struct mlxsw_sp_bridge_port *bridge_port,
-                                     unsigned long *ports_bitmap)
+                                     struct mlxsw_sp_ports_bitmap *ports_bm)
 {
        struct mlxsw_sp_port *mlxsw_sp_port;
        u64 max_lag_members, i;
        int lag_id;
 
        if (!bridge_port->lagged) {
-               set_bit(bridge_port->system_port, ports_bitmap);
+               set_bit(bridge_port->system_port, ports_bm->bitmap);
        } else {
                max_lag_members = MLXSW_CORE_RES_GET(mlxsw_sp->core,
                                                     MAX_LAG_MEMBERS);
@@ -1655,13 +1842,13 @@ mlxsw_sp_bridge_port_get_ports_bitmap(struct mlxsw_sp *mlxsw_sp,
                                                                 lag_id, i);
                        if (mlxsw_sp_port)
                                set_bit(mlxsw_sp_port->local_port,
-                                       ports_bitmap);
+                                       ports_bm->bitmap);
                }
        }
 }
 
 static void
-mlxsw_sp_mc_get_mrouters_bitmap(unsigned long *flood_bitmap,
+mlxsw_sp_mc_get_mrouters_bitmap(struct mlxsw_sp_ports_bitmap *flood_bm,
                                struct mlxsw_sp_bridge_device *bridge_device,
                                struct mlxsw_sp *mlxsw_sp)
 {
@@ -1671,116 +1858,226 @@ mlxsw_sp_mc_get_mrouters_bitmap(unsigned long *flood_bitmap,
                if (bridge_port->mrouter) {
                        mlxsw_sp_bridge_port_get_ports_bitmap(mlxsw_sp,
                                                              bridge_port,
-                                                             flood_bitmap);
+                                                             flood_bm);
                }
        }
 }
 
-static bool
-mlxsw_sp_mc_write_mdb_entry(struct mlxsw_sp *mlxsw_sp,
-                           struct mlxsw_sp_mid *mid,
-                           struct mlxsw_sp_bridge_device *bridge_device)
+static int mlxsw_sp_mc_mdb_mrouters_add(struct mlxsw_sp *mlxsw_sp,
+                                       struct mlxsw_sp_ports_bitmap *ports_bm,
+                                       struct mlxsw_sp_mdb_entry *mdb_entry)
+{
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
+       unsigned int nbits = ports_bm->nbits;
+       int i;
+
+       for_each_set_bit(i, ports_bm->bitmap, nbits) {
+               mdb_entry_port = mlxsw_sp_mdb_entry_mrouter_port_get(mlxsw_sp,
+                                                                    mdb_entry,
+                                                                    i);
+               if (IS_ERR(mdb_entry_port)) {
+                       nbits = i;
+                       goto err_mrouter_port_get;
+               }
+       }
+
+       return 0;
+
+err_mrouter_port_get:
+       for_each_set_bit(i, ports_bm->bitmap, nbits)
+               mlxsw_sp_mdb_entry_mrouter_port_put(mlxsw_sp, mdb_entry, i);
+       return PTR_ERR(mdb_entry_port);
+}
+
+static void mlxsw_sp_mc_mdb_mrouters_del(struct mlxsw_sp *mlxsw_sp,
+                                        struct mlxsw_sp_ports_bitmap *ports_bm,
+                                        struct mlxsw_sp_mdb_entry *mdb_entry)
+{
+       int i;
+
+       for_each_set_bit(i, ports_bm->bitmap, ports_bm->nbits)
+               mlxsw_sp_mdb_entry_mrouter_port_put(mlxsw_sp, mdb_entry, i);
+}
+
+static int
+mlxsw_sp_mc_mdb_mrouters_set(struct mlxsw_sp *mlxsw_sp,
+                            struct mlxsw_sp_bridge_device *bridge_device,
+                            struct mlxsw_sp_mdb_entry *mdb_entry, bool add)
 {
-       long *flood_bitmap;
-       int num_of_ports;
-       u16 mid_idx;
+       struct mlxsw_sp_ports_bitmap ports_bm;
        int err;
 
-       mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
-                                     MLXSW_SP_MID_MAX);
-       if (mid_idx == MLXSW_SP_MID_MAX)
-               return false;
+       err = mlxsw_sp_port_bitmap_init(mlxsw_sp, &ports_bm);
+       if (err)
+               return err;
 
-       num_of_ports = mlxsw_core_max_ports(mlxsw_sp->core);
-       flood_bitmap = bitmap_alloc(num_of_ports, GFP_KERNEL);
-       if (!flood_bitmap)
-               return false;
+       mlxsw_sp_mc_get_mrouters_bitmap(&ports_bm, bridge_device, mlxsw_sp);
+
+       if (add)
+               err = mlxsw_sp_mc_mdb_mrouters_add(mlxsw_sp, &ports_bm,
+                                                  mdb_entry);
+       else
+               mlxsw_sp_mc_mdb_mrouters_del(mlxsw_sp, &ports_bm, mdb_entry);
+
+       mlxsw_sp_port_bitmap_fini(&ports_bm);
+       return err;
+}
 
-       bitmap_copy(flood_bitmap, mid->ports_in_mid, num_of_ports);
-       mlxsw_sp_mc_get_mrouters_bitmap(flood_bitmap, bridge_device, mlxsw_sp);
+static struct mlxsw_sp_mdb_entry *
+mlxsw_sp_mc_mdb_entry_init(struct mlxsw_sp *mlxsw_sp,
+                          struct mlxsw_sp_bridge_device *bridge_device,
+                          const unsigned char *addr, u16 fid, u16 local_port)
+{
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
+       struct mlxsw_sp_mdb_entry *mdb_entry;
+       int err;
+
+       mdb_entry = kzalloc(sizeof(*mdb_entry), GFP_KERNEL);
+       if (!mdb_entry)
+               return ERR_PTR(-ENOMEM);
 
-       mid->mid = mid_idx;
-       err = mlxsw_sp_port_smid_full_entry(mlxsw_sp, mid_idx, flood_bitmap,
-                                           bridge_device->mrouter);
-       bitmap_free(flood_bitmap);
+       ether_addr_copy(mdb_entry->key.addr, addr);
+       mdb_entry->key.fid = fid;
+       err = mlxsw_sp_pgt_mid_alloc(mlxsw_sp, &mdb_entry->mid);
        if (err)
-               return false;
+               goto err_pgt_mid_alloc;
+
+       INIT_LIST_HEAD(&mdb_entry->ports_list);
 
-       err = mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid_idx,
-                                  true);
+       err = mlxsw_sp_mc_mdb_mrouters_set(mlxsw_sp, bridge_device, mdb_entry,
+                                          true);
        if (err)
-               return false;
+               goto err_mdb_mrouters_set;
 
-       set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
-       mid->in_hw = true;
-       return true;
+       mdb_entry_port = mlxsw_sp_mdb_entry_port_get(mlxsw_sp, mdb_entry,
+                                                    local_port);
+       if (IS_ERR(mdb_entry_port)) {
+               err = PTR_ERR(mdb_entry_port);
+               goto err_mdb_entry_port_get;
+       }
+
+       if (bridge_device->multicast_enabled) {
+               err = mlxsw_sp_mdb_entry_write(mlxsw_sp, mdb_entry, true);
+               if (err)
+                       goto err_mdb_entry_write;
+       }
+
+       err = rhashtable_insert_fast(&bridge_device->mdb_ht,
+                                    &mdb_entry->ht_node,
+                                    mlxsw_sp_mdb_ht_params);
+       if (err)
+               goto err_rhashtable_insert;
+
+       list_add_tail(&mdb_entry->list, &bridge_device->mdb_list);
+
+       return mdb_entry;
+
+err_rhashtable_insert:
+       if (bridge_device->multicast_enabled)
+               mlxsw_sp_mdb_entry_write(mlxsw_sp, mdb_entry, false);
+err_mdb_entry_write:
+       mlxsw_sp_mdb_entry_port_put(mlxsw_sp, mdb_entry, local_port, false);
+err_mdb_entry_port_get:
+       mlxsw_sp_mc_mdb_mrouters_set(mlxsw_sp, bridge_device, mdb_entry, false);
+err_mdb_mrouters_set:
+       mlxsw_sp_pgt_mid_free(mlxsw_sp, mdb_entry->mid);
+err_pgt_mid_alloc:
+       kfree(mdb_entry);
+       return ERR_PTR(err);
 }
 
-static int mlxsw_sp_mc_remove_mdb_entry(struct mlxsw_sp *mlxsw_sp,
-                                       struct mlxsw_sp_mid *mid)
+static void
+mlxsw_sp_mc_mdb_entry_fini(struct mlxsw_sp *mlxsw_sp,
+                          struct mlxsw_sp_mdb_entry *mdb_entry,
+                          struct mlxsw_sp_bridge_device *bridge_device,
+                          u16 local_port, bool force)
 {
-       if (!mid->in_hw)
-               return 0;
-
-       clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
-       mid->in_hw = false;
-       return mlxsw_sp_port_mdb_op(mlxsw_sp, mid->addr, mid->fid, mid->mid,
-                                   false);
+       list_del(&mdb_entry->list);
+       rhashtable_remove_fast(&bridge_device->mdb_ht, &mdb_entry->ht_node,
+                              mlxsw_sp_mdb_ht_params);
+       if (bridge_device->multicast_enabled)
+               mlxsw_sp_mdb_entry_write(mlxsw_sp, mdb_entry, false);
+       mlxsw_sp_mdb_entry_port_put(mlxsw_sp, mdb_entry, local_port, force);
+       mlxsw_sp_mc_mdb_mrouters_set(mlxsw_sp, bridge_device, mdb_entry, false);
+       WARN_ON(!list_empty(&mdb_entry->ports_list));
+       mlxsw_sp_pgt_mid_free(mlxsw_sp, mdb_entry->mid);
+       kfree(mdb_entry);
 }
 
-static struct
-mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
-                                 struct mlxsw_sp_bridge_device *bridge_device,
-                                 const unsigned char *addr,
-                                 u16 fid)
+static struct mlxsw_sp_mdb_entry *
+mlxsw_sp_mc_mdb_entry_get(struct mlxsw_sp *mlxsw_sp,
+                         struct mlxsw_sp_bridge_device *bridge_device,
+                         const unsigned char *addr, u16 fid, u16 local_port)
 {
-       struct mlxsw_sp_mid *mid;
+       struct mlxsw_sp_mdb_entry_key key = {};
+       struct mlxsw_sp_mdb_entry *mdb_entry;
 
-       mid = kzalloc(sizeof(*mid), GFP_KERNEL);
-       if (!mid)
-               return NULL;
+       ether_addr_copy(key.addr, addr);
+       key.fid = fid;
+       mdb_entry = rhashtable_lookup_fast(&bridge_device->mdb_ht, &key,
+                                          mlxsw_sp_mdb_ht_params);
+       if (mdb_entry) {
+               struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
 
-       mid->ports_in_mid = bitmap_zalloc(mlxsw_core_max_ports(mlxsw_sp->core),
-                                         GFP_KERNEL);
-       if (!mid->ports_in_mid)
-               goto err_ports_in_mid_alloc;
+               mdb_entry_port = mlxsw_sp_mdb_entry_port_get(mlxsw_sp,
+                                                            mdb_entry,
+                                                            local_port);
+               if (IS_ERR(mdb_entry_port))
+                       return ERR_CAST(mdb_entry_port);
 
-       ether_addr_copy(mid->addr, addr);
-       mid->fid = fid;
-       mid->in_hw = false;
+               return mdb_entry;
+       }
 
-       if (!bridge_device->multicast_enabled)
-               goto out;
+       return mlxsw_sp_mc_mdb_entry_init(mlxsw_sp, bridge_device, addr, fid,
+                                         local_port);
+}
 
-       if (!mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid, bridge_device))
-               goto err_write_mdb_entry;
+static bool
+mlxsw_sp_mc_mdb_entry_remove(struct mlxsw_sp_mdb_entry *mdb_entry,
+                            struct mlxsw_sp_mdb_entry_port *removed_entry_port,
+                            bool force)
+{
+       if (mdb_entry->ports_count > 1)
+               return false;
 
-out:
-       list_add_tail(&mid->list, &bridge_device->mids_list);
-       return mid;
+       if (force)
+               return true;
 
-err_write_mdb_entry:
-       bitmap_free(mid->ports_in_mid);
-err_ports_in_mid_alloc:
-       kfree(mid);
-       return NULL;
+       if (!removed_entry_port->mrouter &&
+           refcount_read(&removed_entry_port->refcount) > 1)
+               return false;
+
+       if (removed_entry_port->mrouter &&
+           refcount_read(&removed_entry_port->refcount) > 2)
+               return false;
+
+       return true;
 }
 
-static int mlxsw_sp_port_remove_from_mid(struct mlxsw_sp_port *mlxsw_sp_port,
-                                        struct mlxsw_sp_mid *mid)
+static void
+mlxsw_sp_mc_mdb_entry_put(struct mlxsw_sp *mlxsw_sp,
+                         struct mlxsw_sp_bridge_device *bridge_device,
+                         struct mlxsw_sp_mdb_entry *mdb_entry, u16 local_port,
+                         bool force)
 {
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
-       int err = 0;
+       struct mlxsw_sp_mdb_entry_port *mdb_entry_port;
 
-       clear_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
-       if (bitmap_empty(mid->ports_in_mid,
-                        mlxsw_core_max_ports(mlxsw_sp->core))) {
-               err = mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
-               list_del(&mid->list);
-               bitmap_free(mid->ports_in_mid);
-               kfree(mid);
-       }
-       return err;
+       mdb_entry_port = mlxsw_sp_mdb_entry_port_lookup(mdb_entry, local_port);
+       if (!mdb_entry_port)
+               return;
+
+       /* Avoid a temporary situation in which the MDB entry points to an empty
+        * PGT entry, as otherwise packets will be temporarily dropped instead
+        * of being flooded. Instead, in this situation, call
+        * mlxsw_sp_mc_mdb_entry_fini(), which first deletes the MDB entry and
+        * then releases the PGT entry.
+        */
+       if (mlxsw_sp_mc_mdb_entry_remove(mdb_entry, mdb_entry_port, force))
+               mlxsw_sp_mc_mdb_entry_fini(mlxsw_sp, mdb_entry, bridge_device,
+                                          local_port, force);
+       else
+               mlxsw_sp_mdb_entry_port_put(mlxsw_sp, mdb_entry, local_port,
+                                           force);
 }
 
 static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -1789,12 +2086,10 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
        struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct net_device *orig_dev = mdb->obj.orig_dev;
        struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
-       struct net_device *dev = mlxsw_sp_port->dev;
        struct mlxsw_sp_bridge_device *bridge_device;
        struct mlxsw_sp_bridge_port *bridge_port;
-       struct mlxsw_sp_mid *mid;
+       struct mlxsw_sp_mdb_entry *mdb_entry;
        u16 fid_index;
-       int err = 0;
 
        bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
        if (!bridge_port)
@@ -1809,54 +2104,35 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port,
 
        fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
 
-       mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
-       if (!mid) {
-               mid = __mlxsw_sp_mc_alloc(mlxsw_sp, bridge_device, mdb->addr,
-                                         fid_index);
-               if (!mid) {
-                       netdev_err(dev, "Unable to allocate MC group\n");
-                       return -ENOMEM;
-               }
-       }
-       set_bit(mlxsw_sp_port->local_port, mid->ports_in_mid);
-
-       if (!bridge_device->multicast_enabled)
-               return 0;
-
-       if (bridge_port->mrouter)
-               return 0;
-
-       err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, true);
-       if (err) {
-               netdev_err(dev, "Unable to set SMID\n");
-               goto err_out;
-       }
+       mdb_entry = mlxsw_sp_mc_mdb_entry_get(mlxsw_sp, bridge_device,
+                                             mdb->addr, fid_index,
+                                             mlxsw_sp_port->local_port);
+       if (IS_ERR(mdb_entry))
+               return PTR_ERR(mdb_entry);
 
        return 0;
-
-err_out:
-       mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
-       return err;
 }
 
-static void
-mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp_port *mlxsw_sp_port,
-                                  struct mlxsw_sp_bridge_device
-                                  *bridge_device)
+static int
+mlxsw_sp_bridge_mdb_mc_enable_sync(struct mlxsw_sp *mlxsw_sp,
+                                  struct mlxsw_sp_bridge_device *bridge_device,
+                                  bool mc_enabled)
 {
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
-       struct mlxsw_sp_mid *mid;
-       bool mc_enabled;
-
-       mc_enabled = bridge_device->multicast_enabled;
+       struct mlxsw_sp_mdb_entry *mdb_entry;
+       int err;
 
-       list_for_each_entry(mid, &bridge_device->mids_list, list) {
-               if (mc_enabled)
-                       mlxsw_sp_mc_write_mdb_entry(mlxsw_sp, mid,
-                                                   bridge_device);
-               else
-                       mlxsw_sp_mc_remove_mdb_entry(mlxsw_sp, mid);
+       list_for_each_entry(mdb_entry, &bridge_device->mdb_list, list) {
+               err = mlxsw_sp_mdb_entry_write(mlxsw_sp, mdb_entry, mc_enabled);
+               if (err)
+                       goto err_mdb_entry_write;
        }
+       return 0;
+
+err_mdb_entry_write:
+       list_for_each_entry_continue_reverse(mdb_entry,
+                                            &bridge_device->mdb_list, list)
+               mlxsw_sp_mdb_entry_write(mlxsw_sp, mdb_entry, !mc_enabled);
+       return err;
 }
 
 static void
@@ -1864,14 +2140,20 @@ mlxsw_sp_port_mrouter_update_mdb(struct mlxsw_sp_port *mlxsw_sp_port,
                                 struct mlxsw_sp_bridge_port *bridge_port,
                                 bool add)
 {
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_bridge_device *bridge_device;
-       struct mlxsw_sp_mid *mid;
+       u16 local_port = mlxsw_sp_port->local_port;
+       struct mlxsw_sp_mdb_entry *mdb_entry;
 
        bridge_device = bridge_port->bridge_device;
 
-       list_for_each_entry(mid, &bridge_device->mids_list, list) {
-               if (!test_bit(mlxsw_sp_port->local_port, mid->ports_in_mid))
-                       mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, add);
+       list_for_each_entry(mdb_entry, &bridge_device->mdb_list, list) {
+               if (add)
+                       mlxsw_sp_mdb_entry_mrouter_port_get(mlxsw_sp, mdb_entry,
+                                                           local_port);
+               else
+                       mlxsw_sp_mdb_entry_mrouter_port_put(mlxsw_sp, mdb_entry,
+                                                           local_port);
        }
 }
 
@@ -1949,28 +2231,6 @@ static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
        return 0;
 }
 
-static int
-__mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
-                       struct mlxsw_sp_bridge_port *bridge_port,
-                       struct mlxsw_sp_mid *mid)
-{
-       struct net_device *dev = mlxsw_sp_port->dev;
-       int err;
-
-       if (bridge_port->bridge_device->multicast_enabled &&
-           !bridge_port->mrouter) {
-               err = mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false);
-               if (err)
-                       netdev_err(dev, "Unable to remove port from SMID\n");
-       }
-
-       err = mlxsw_sp_port_remove_from_mid(mlxsw_sp_port, mid);
-       if (err)
-               netdev_err(dev, "Unable to remove MC SFD\n");
-
-       return err;
-}
-
 static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
                                 const struct switchdev_obj_port_mdb *mdb)
 {
@@ -1980,7 +2240,8 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
        struct mlxsw_sp_bridge_device *bridge_device;
        struct net_device *dev = mlxsw_sp_port->dev;
        struct mlxsw_sp_bridge_port *bridge_port;
-       struct mlxsw_sp_mid *mid;
+       struct mlxsw_sp_mdb_entry_key key = {};
+       struct mlxsw_sp_mdb_entry *mdb_entry;
        u16 fid_index;
 
        bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev);
@@ -1996,32 +2257,44 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port,
 
        fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid);
 
-       mid = __mlxsw_sp_mc_get(bridge_device, mdb->addr, fid_index);
-       if (!mid) {
+       ether_addr_copy(key.addr, mdb->addr);
+       key.fid = fid_index;
+       mdb_entry = rhashtable_lookup_fast(&bridge_device->mdb_ht, &key,
+                                          mlxsw_sp_mdb_ht_params);
+       if (!mdb_entry) {
                netdev_err(dev, "Unable to remove port from MC DB\n");
                return -EINVAL;
        }
 
-       return __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port, mid);
+       mlxsw_sp_mc_mdb_entry_put(mlxsw_sp, bridge_device, mdb_entry,
+                                 mlxsw_sp_port->local_port, false);
+       return 0;
 }
 
 static void
 mlxsw_sp_bridge_port_mdb_flush(struct mlxsw_sp_port *mlxsw_sp_port,
-                              struct mlxsw_sp_bridge_port *bridge_port)
+                              struct mlxsw_sp_bridge_port *bridge_port,
+                              u16 fid_index)
 {
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_bridge_device *bridge_device;
-       struct mlxsw_sp_mid *mid, *tmp;
+       struct mlxsw_sp_mdb_entry *mdb_entry, *tmp;
+       u16 local_port = mlxsw_sp_port->local_port;
 
        bridge_device = bridge_port->bridge_device;
 
-       list_for_each_entry_safe(mid, tmp, &bridge_device->mids_list, list) {
-               if (test_bit(mlxsw_sp_port->local_port, mid->ports_in_mid)) {
-                       __mlxsw_sp_port_mdb_del(mlxsw_sp_port, bridge_port,
-                                               mid);
-               } else if (bridge_device->multicast_enabled &&
-                          bridge_port->mrouter) {
-                       mlxsw_sp_port_smid_set(mlxsw_sp_port, mid->mid, false);
-               }
+       list_for_each_entry_safe(mdb_entry, tmp, &bridge_device->mdb_list,
+                                list) {
+               if (mdb_entry->key.fid != fid_index)
+                       continue;
+
+               if (bridge_port->mrouter)
+                       mlxsw_sp_mdb_entry_mrouter_port_put(mlxsw_sp,
+                                                           mdb_entry,
+                                                           local_port);
+
+               mlxsw_sp_mc_mdb_entry_put(mlxsw_sp, bridge_device, mdb_entry,
+                                         local_port, true);
        }
 }
 
@@ -2633,10 +2906,9 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
        struct mlxsw_sp_bridge_device *bridge_device;
        struct mlxsw_sp_bridge_port *bridge_port;
        struct mlxsw_sp_port *mlxsw_sp_port;
+       u16 local_port, vid, fid, evid = 0;
        enum switchdev_notifier_type type;
        char mac[ETH_ALEN];
-       u16 local_port;
-       u16 vid, fid;
        bool do_notification = true;
        int err;
 
@@ -2667,9 +2939,10 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
 
        bridge_device = bridge_port->bridge_device;
        vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
+       evid = mlxsw_sp_port_vlan->vid;
 
 do_fdb_op:
-       err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
+       err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, evid,
                                      adding, true);
        if (err) {
                dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
@@ -2729,8 +3002,7 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
 
        bridge_device = bridge_port->bridge_device;
        vid = bridge_device->vlan_enabled ? mlxsw_sp_port_vlan->vid : 0;
-       lag_vid = mlxsw_sp_fid_lag_vid_valid(mlxsw_sp_port_vlan->fid) ?
-                 mlxsw_sp_port_vlan->vid : 0;
+       lag_vid = mlxsw_sp_port_vlan->vid;
 
 do_fdb_op:
        err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
index ed4d0d3..d0baba3 100644 (file)
@@ -953,16 +953,16 @@ static const struct mlxsw_sp_trap_item mlxsw_sp_trap_items_arr[] = {
                .trap = MLXSW_SP_TRAP_CONTROL(ARP_REQUEST, NEIGH_DISCOVERY,
                                              MIRROR),
                .listeners_arr = {
-                       MLXSW_SP_RXL_MARK(ARPBC, NEIGH_DISCOVERY, MIRROR_TO_CPU,
-                                         false),
+                       MLXSW_SP_RXL_MARK(ROUTER_ARPBC, NEIGH_DISCOVERY,
+                                         TRAP_TO_CPU, false),
                },
        },
        {
                .trap = MLXSW_SP_TRAP_CONTROL(ARP_RESPONSE, NEIGH_DISCOVERY,
                                              MIRROR),
                .listeners_arr = {
-                       MLXSW_SP_RXL_MARK(ARPUC, NEIGH_DISCOVERY, MIRROR_TO_CPU,
-                                         false),
+                       MLXSW_SP_RXL_MARK(ROUTER_ARPUC, NEIGH_DISCOVERY,
+                                         TRAP_TO_CPU, false),
                },
        },
        {
index d888498..8da1696 100644 (file)
@@ -27,8 +27,6 @@ enum {
        MLXSW_TRAP_ID_PKT_SAMPLE = 0x38,
        MLXSW_TRAP_ID_FID_MISS = 0x3D,
        MLXSW_TRAP_ID_DECAP_ECN0 = 0x40,
-       MLXSW_TRAP_ID_ARPBC = 0x50,
-       MLXSW_TRAP_ID_ARPUC = 0x51,
        MLXSW_TRAP_ID_MTUERROR = 0x52,
        MLXSW_TRAP_ID_TTLERROR = 0x53,
        MLXSW_TRAP_ID_LBERROR = 0x54,
@@ -71,6 +69,8 @@ enum {
        MLXSW_TRAP_ID_IPV6_BFD = 0xD1,
        MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6,
        MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7,
+       MLXSW_TRAP_ID_ROUTER_ARPBC = 0xE0,
+       MLXSW_TRAP_ID_ROUTER_ARPUC = 0xE1,
        MLXSW_TRAP_ID_DISCARD_NON_ROUTABLE = 0x11A,
        MLXSW_TRAP_ID_DISCARD_ROUTER2 = 0x130,
        MLXSW_TRAP_ID_DISCARD_ROUTER3 = 0x131,
index c8fe8b3..b1c74e6 100644 (file)
@@ -155,8 +155,8 @@ static int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset,
        return 0;
 }
 
-static int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
-                                     u16 timeout)
+int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
+                              u16 timeout)
 {
        u16 timeout_cnt = 0;
        u32 val;
@@ -192,7 +192,7 @@ static int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter,
        return 0;
 }
 
-static void lan743x_hs_syslock_release(struct lan743x_adapter *adapter)
+void lan743x_hs_syslock_release(struct lan743x_adapter *adapter)
 {
        u32 val;
 
@@ -1149,7 +1149,12 @@ static void lan743x_ethtool_get_wol(struct net_device *netdev,
        wol->supported |= WAKE_BCAST | WAKE_UCAST | WAKE_MCAST |
                WAKE_MAGIC | WAKE_PHY | WAKE_ARP;
 
+       if (adapter->is_pci11x1x)
+               wol->supported |= WAKE_MAGICSECURE;
+
        wol->wolopts |= adapter->wolopts;
+       if (adapter->wolopts & WAKE_MAGICSECURE)
+               memcpy(wol->sopass, adapter->sopass, sizeof(wol->sopass));
 }
 
 static int lan743x_ethtool_set_wol(struct net_device *netdev,
@@ -1170,6 +1175,13 @@ static int lan743x_ethtool_set_wol(struct net_device *netdev,
                adapter->wolopts |= WAKE_PHY;
        if (wol->wolopts & WAKE_ARP)
                adapter->wolopts |= WAKE_ARP;
+       if (wol->wolopts & WAKE_MAGICSECURE &&
+           wol->wolopts & WAKE_MAGIC) {
+               memcpy(adapter->sopass, wol->sopass, sizeof(wol->sopass));
+               adapter->wolopts |= WAKE_MAGICSECURE;
+       } else {
+               memset(adapter->sopass, 0, sizeof(u8) * SOPASS_MAX);
+       }
 
        device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts);
 
@@ -1178,6 +1190,49 @@ static int lan743x_ethtool_set_wol(struct net_device *netdev,
 }
 #endif /* CONFIG_PM */
 
+static void lan743x_common_regs(struct net_device *dev,
+                               struct ethtool_regs *regs, void *p)
+
+{
+       struct lan743x_adapter *adapter = netdev_priv(dev);
+       u32 *rb = p;
+
+       memset(p, 0, (MAX_LAN743X_ETH_REGS * sizeof(u32)));
+
+       rb[ETH_PRIV_FLAGS] = adapter->flags;
+       rb[ETH_ID_REV]     = lan743x_csr_read(adapter, ID_REV);
+       rb[ETH_FPGA_REV]   = lan743x_csr_read(adapter, FPGA_REV);
+       rb[ETH_STRAP_READ] = lan743x_csr_read(adapter, STRAP_READ);
+       rb[ETH_INT_STS]    = lan743x_csr_read(adapter, INT_STS);
+       rb[ETH_HW_CFG]     = lan743x_csr_read(adapter, HW_CFG);
+       rb[ETH_PMT_CTL]    = lan743x_csr_read(adapter, PMT_CTL);
+       rb[ETH_E2P_CMD]    = lan743x_csr_read(adapter, E2P_CMD);
+       rb[ETH_E2P_DATA]   = lan743x_csr_read(adapter, E2P_DATA);
+       rb[ETH_MAC_CR]     = lan743x_csr_read(adapter, MAC_CR);
+       rb[ETH_MAC_RX]     = lan743x_csr_read(adapter, MAC_RX);
+       rb[ETH_MAC_TX]     = lan743x_csr_read(adapter, MAC_TX);
+       rb[ETH_FLOW]       = lan743x_csr_read(adapter, MAC_FLOW);
+       rb[ETH_MII_ACC]    = lan743x_csr_read(adapter, MAC_MII_ACC);
+       rb[ETH_MII_DATA]   = lan743x_csr_read(adapter, MAC_MII_DATA);
+       rb[ETH_EEE_TX_LPI_REQ_DLY]  = lan743x_csr_read(adapter,
+                                                      MAC_EEE_TX_LPI_REQ_DLY_CNT);
+       rb[ETH_WUCSR]      = lan743x_csr_read(adapter, MAC_WUCSR);
+       rb[ETH_WK_SRC]     = lan743x_csr_read(adapter, MAC_WK_SRC);
+}
+
+static int lan743x_get_regs_len(struct net_device *dev)
+{
+       return MAX_LAN743X_ETH_REGS * sizeof(u32);
+}
+
+static void lan743x_get_regs(struct net_device *dev,
+                            struct ethtool_regs *regs, void *p)
+{
+       regs->version = LAN743X_ETH_REG_VERSION;
+
+       lan743x_common_regs(dev, regs, p);
+}
+
 const struct ethtool_ops lan743x_ethtool_ops = {
        .get_drvinfo = lan743x_ethtool_get_drvinfo,
        .get_msglevel = lan743x_ethtool_get_msglevel,
@@ -1202,6 +1257,8 @@ const struct ethtool_ops lan743x_ethtool_ops = {
        .set_eee = lan743x_ethtool_set_eee,
        .get_link_ksettings = phy_ethtool_get_link_ksettings,
        .set_link_ksettings = phy_ethtool_set_link_ksettings,
+       .get_regs_len = lan743x_get_regs_len,
+       .get_regs = lan743x_get_regs,
 #ifdef CONFIG_PM
        .get_wol = lan743x_ethtool_get_wol,
        .set_wol = lan743x_ethtool_set_wol,
index d0d11a7..7f5996a 100644 (file)
@@ -6,6 +6,32 @@
 
 #include "linux/ethtool.h"
 
+#define LAN743X_ETH_REG_VERSION         1
+
+enum {
+       ETH_PRIV_FLAGS,
+       ETH_ID_REV,
+       ETH_FPGA_REV,
+       ETH_STRAP_READ,
+       ETH_INT_STS,
+       ETH_HW_CFG,
+       ETH_PMT_CTL,
+       ETH_E2P_CMD,
+       ETH_E2P_DATA,
+       ETH_MAC_CR,
+       ETH_MAC_RX,
+       ETH_MAC_TX,
+       ETH_FLOW,
+       ETH_MII_ACC,
+       ETH_MII_DATA,
+       ETH_EEE_TX_LPI_REQ_DLY,
+       ETH_WUCSR,
+       ETH_WK_SRC,
+
+       /* Add new registers above */
+       MAX_LAN743X_ETH_REGS
+};
+
 extern const struct ethtool_ops lan743x_ethtool_ops;
 
 #endif /* _LAN743X_ETHTOOL_H */
index af81236..a9a1dea 100644 (file)
 #define MMD_ACCESS_WRITE       1
 #define MMD_ACCESS_READ                2
 #define MMD_ACCESS_READ_INC    3
+#define PCS_POWER_STATE_DOWN   0x6
+#define PCS_POWER_STATE_UP     0x4
 
 static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
 {
        u32 chip_rev;
+       u32 cfg_load;
+       u32 hw_cfg;
        u32 strap;
+       int ret;
+
+       /* Timeout = 100 (i.e. 1 sec (10 msce * 100)) */
+       ret = lan743x_hs_syslock_acquire(adapter, 100);
+       if (ret < 0) {
+               netif_err(adapter, drv, adapter->netdev,
+                         "Sys Lock acquire failed ret:%d\n", ret);
+               return;
+       }
 
-       strap = lan743x_csr_read(adapter, STRAP_READ);
-       if (strap & STRAP_READ_USE_SGMII_EN_) {
+       cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG);
+       lan743x_hs_syslock_release(adapter);
+       hw_cfg = lan743x_csr_read(adapter, HW_CFG);
+
+       if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ ||
+           hw_cfg & HW_CFG_RST_PROTECT_) {
+               strap = lan743x_csr_read(adapter, STRAP_READ);
                if (strap & STRAP_READ_SGMII_EN_)
                        adapter->is_sgmii_en = true;
                else
                        adapter->is_sgmii_en = false;
-               netif_dbg(adapter, drv, adapter->netdev,
-                         "STRAP_READ: 0x%08X\n", strap);
        } else {
                chip_rev = lan743x_csr_read(adapter, FPGA_REV);
                if (chip_rev) {
@@ -43,12 +59,12 @@ static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
                                adapter->is_sgmii_en = true;
                        else
                                adapter->is_sgmii_en = false;
-                       netif_dbg(adapter, drv, adapter->netdev,
-                                 "FPGA_REV: 0x%08X\n", chip_rev);
                } else {
                        adapter->is_sgmii_en = false;
                }
        }
+       netif_dbg(adapter, drv, adapter->netdev,
+                 "SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis");
 }
 
 static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
@@ -909,6 +925,318 @@ static int lan743x_mdiobus_c45_write(struct mii_bus *bus,
        return ret;
 }
 
+static int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter)
+{
+       u32 data;
+       int ret;
+
+       ret = readx_poll_timeout(LAN743X_CSR_READ_OP, SGMII_ACC, data,
+                                !(data & SGMII_ACC_SGMII_BZY_), 100, 1000000);
+       if (ret < 0)
+               netif_err(adapter, drv, adapter->netdev,
+                         "%s: error %d sgmii wait timeout\n", __func__, ret);
+
+       return ret;
+}
+
+static int lan743x_sgmii_read(struct lan743x_adapter *adapter, u8 mmd, u16 addr)
+{
+       u32 mmd_access;
+       int ret;
+       u32 val;
+
+       if (mmd > 31) {
+               netif_err(adapter, probe, adapter->netdev,
+                         "%s mmd should <= 31\n", __func__);
+               return -EINVAL;
+       }
+
+       mutex_lock(&adapter->sgmii_rw_lock);
+       /* Load Register Address */
+       mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
+       mmd_access |= (addr | SGMII_ACC_SGMII_BZY_);
+       lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
+       ret = lan743x_sgmii_wait_till_not_busy(adapter);
+       if (ret < 0)
+               goto sgmii_unlock;
+
+       val = lan743x_csr_read(adapter, SGMII_DATA);
+       ret = (int)(val & SGMII_DATA_MASK_);
+
+sgmii_unlock:
+       mutex_unlock(&adapter->sgmii_rw_lock);
+
+       return ret;
+}
+
+static int lan743x_sgmii_write(struct lan743x_adapter *adapter,
+                              u8 mmd, u16 addr, u16 val)
+{
+       u32 mmd_access;
+       int ret;
+
+       if (mmd > 31) {
+               netif_err(adapter, probe, adapter->netdev,
+                         "%s mmd should <= 31\n", __func__);
+               return -EINVAL;
+       }
+       mutex_lock(&adapter->sgmii_rw_lock);
+       /* Load Register Data */
+       lan743x_csr_write(adapter, SGMII_DATA, (u32)(val & SGMII_DATA_MASK_));
+       /* Load Register Address */
+       mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
+       mmd_access |= (addr | SGMII_ACC_SGMII_BZY_ | SGMII_ACC_SGMII_WR_);
+       lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
+       ret = lan743x_sgmii_wait_till_not_busy(adapter);
+       mutex_unlock(&adapter->sgmii_rw_lock);
+
+       return ret;
+}
+
+static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter,
+                                 u16 baud)
+{
+       int mpllctrl0;
+       int mpllctrl1;
+       int miscctrl1;
+       int ret;
+
+       mpllctrl0 = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
+                                      VR_MII_GEN2_4_MPLL_CTRL0);
+       if (mpllctrl0 < 0)
+               return mpllctrl0;
+
+       mpllctrl0 &= ~VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_;
+       if (baud == VR_MII_BAUD_RATE_1P25GBPS) {
+               mpllctrl1 = VR_MII_MPLL_MULTIPLIER_100;
+               /* mpll_baud_clk/4 */
+               miscctrl1 = 0xA;
+       } else {
+               mpllctrl1 = VR_MII_MPLL_MULTIPLIER_125;
+               /* mpll_baud_clk/2 */
+               miscctrl1 = 0x5;
+       }
+
+       ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
+                                 VR_MII_GEN2_4_MPLL_CTRL0, mpllctrl0);
+       if (ret < 0)
+               return ret;
+
+       ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
+                                 VR_MII_GEN2_4_MPLL_CTRL1, mpllctrl1);
+       if (ret < 0)
+               return ret;
+
+       return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
+                                 VR_MII_GEN2_4_MISC_CTRL1, miscctrl1);
+}
+
+static int lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter *adapter,
+                                      bool enable)
+{
+       if (enable)
+               return lan743x_sgmii_mpll_set(adapter,
+                                             VR_MII_BAUD_RATE_3P125GBPS);
+       else
+               return lan743x_sgmii_mpll_set(adapter,
+                                             VR_MII_BAUD_RATE_1P25GBPS);
+}
+
+static int lan743x_is_sgmii_2_5G_mode(struct lan743x_adapter *adapter,
+                                     bool *status)
+{
+       int ret;
+
+       ret = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
+                                VR_MII_GEN2_4_MPLL_CTRL1);
+       if (ret < 0)
+               return ret;
+
+       if (ret == VR_MII_MPLL_MULTIPLIER_125 ||
+           ret == VR_MII_MPLL_MULTIPLIER_50)
+               *status = true;
+       else
+               *status = false;
+
+       return 0;
+}
+
+static int lan743x_sgmii_aneg_update(struct lan743x_adapter *adapter)
+{
+       enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd;
+       int mii_ctrl;
+       int dgt_ctrl;
+       int an_ctrl;
+       int ret;
+
+       if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE)
+               /* Switch to 2.5 Gbps */
+               ret = lan743x_sgmii_2_5G_mode_set(adapter, true);
+       else
+               /* Switch to 10/100/1000 Mbps clock */
+               ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
+       if (ret < 0)
+               return ret;
+
+       /* Enable SGMII Auto NEG */
+       mii_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
+       if (mii_ctrl < 0)
+               return mii_ctrl;
+
+       an_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, VR_MII_AN_CTRL);
+       if (an_ctrl < 0)
+               return an_ctrl;
+
+       dgt_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
+                                     VR_MII_DIG_CTRL1);
+       if (dgt_ctrl < 0)
+               return dgt_ctrl;
+
+       if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) {
+               mii_ctrl &= ~(BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100);
+               mii_ctrl |= BMCR_SPEED1000;
+               dgt_ctrl |= VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
+               dgt_ctrl &= ~VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
+               /* In order for Auto-Negotiation to operate properly at
+                * 2.5 Gbps the 1.6ms link timer values must be adjusted
+                * The VR_MII_LINK_TIMER_CTRL Register must be set to
+                * 16'h7A1 and The CL37_TMR_OVR_RIDE bit of the
+                * VR_MII_DIG_CTRL1 Register set to 1
+                */
+               ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
+                                         VR_MII_LINK_TIMER_CTRL, 0x7A1);
+               if (ret < 0)
+                       return ret;
+       } else {
+               mii_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+               an_ctrl &= ~VR_MII_AN_CTRL_SGMII_LINK_STS_;
+               dgt_ctrl &= ~VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
+               dgt_ctrl |= VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
+       }
+
+       ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR,
+                                 mii_ctrl);
+       if (ret < 0)
+               return ret;
+
+       ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
+                                 VR_MII_DIG_CTRL1, dgt_ctrl);
+       if (ret < 0)
+               return ret;
+
+       return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
+                                 VR_MII_AN_CTRL, an_ctrl);
+}
+
+static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state)
+{
+       u8 wait_cnt = 0;
+       u32 dig_sts;
+
+       do {
+               dig_sts = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
+                                            VR_MII_DIG_STS);
+               if (((dig_sts & VR_MII_DIG_STS_PSEQ_STATE_MASK_) >>
+                     VR_MII_DIG_STS_PSEQ_STATE_POS_) == state)
+                       break;
+               usleep_range(1000, 2000);
+       } while (wait_cnt++ < 10);
+
+       if (wait_cnt >= 10)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int lan743x_sgmii_config(struct lan743x_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct phy_device *phydev = netdev->phydev;
+       enum lan743x_sgmii_lsd lsd = POWER_DOWN;
+       int mii_ctl;
+       bool status;
+       int ret;
+
+       switch (phydev->speed) {
+       case SPEED_2500:
+               if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER)
+                       lsd = LINK_2500_MASTER;
+               else
+                       lsd = LINK_2500_SLAVE;
+               break;
+       case SPEED_1000:
+               if (phydev->master_slave_state == MASTER_SLAVE_STATE_MASTER)
+                       lsd = LINK_1000_MASTER;
+               else
+                       lsd = LINK_1000_SLAVE;
+               break;
+       case SPEED_100:
+               if (phydev->duplex)
+                       lsd = LINK_100FD;
+               else
+                       lsd = LINK_100HD;
+               break;
+       case SPEED_10:
+               if (phydev->duplex)
+                       lsd = LINK_10FD;
+               else
+                       lsd = LINK_10HD;
+               break;
+       default:
+               netif_err(adapter, drv, adapter->netdev,
+                         "Invalid speed %d\n", phydev->speed);
+               return -EINVAL;
+       }
+
+       adapter->sgmii_lsd = lsd;
+       ret = lan743x_sgmii_aneg_update(adapter);
+       if (ret < 0) {
+               netif_err(adapter, drv, adapter->netdev,
+                         "error %d SGMII cfg failed\n", ret);
+               return ret;
+       }
+
+       ret = lan743x_is_sgmii_2_5G_mode(adapter, &status);
+       if (ret < 0) {
+               netif_err(adapter, drv, adapter->netdev,
+                         "erro %d SGMII get mode failed\n", ret);
+               return ret;
+       }
+
+       if (status)
+               netif_dbg(adapter, drv, adapter->netdev,
+                         "SGMII 2.5G mode enable\n");
+       else
+               netif_dbg(adapter, drv, adapter->netdev,
+                         "SGMII 1G mode enable\n");
+
+       /* SGMII/1000/2500BASE-X PCS power down */
+       mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
+       if (mii_ctl < 0)
+               return mii_ctl;
+
+       mii_ctl |= BMCR_PDOWN;
+       ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
+       if (ret < 0)
+               return ret;
+
+       ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN);
+       if (ret < 0)
+               return ret;
+
+       /* SGMII/1000/2500BASE-X PCS power up */
+       mii_ctl &= ~BMCR_PDOWN;
+       ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
+       if (ret < 0)
+               return ret;
+
+       ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
 static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
                                    u8 *addr)
 {
@@ -1124,6 +1452,10 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
                        data |= MAC_CR_CFG_H_;
                        data &= ~MAC_CR_CFG_L_;
                break;
+               case SPEED_2500:
+                       data |= MAC_CR_CFG_H_;
+                       data |= MAC_CR_CFG_L_;
+               break;
                }
                lan743x_csr_write(adapter, MAC_CR, data);
 
@@ -1135,6 +1467,10 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
                lan743x_phy_update_flowcontrol(adapter, local_advertisement,
                                               remote_advertisement);
                lan743x_ptp_update_latency(adapter, phydev->speed);
+               if (phydev->interface == PHY_INTERFACE_MODE_SGMII ||
+                   phydev->interface == PHY_INTERFACE_MODE_1000BASEX ||
+                   phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
+                       lan743x_sgmii_config(adapter);
        }
 }
 
@@ -2875,6 +3211,7 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
                adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
                pci11x1x_strap_get_status(adapter);
                spin_lock_init(&adapter->eth_syslock_spinlock);
+               mutex_init(&adapter->sgmii_rw_lock);
        } else {
                adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS;
                adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS;
@@ -3124,6 +3461,7 @@ static void lan743x_pm_set_wol(struct lan743x_adapter *adapter)
        const u8 ipv6_multicast[3] = { 0x33, 0x33 };
        const u8 arp_type[2] = { 0x08, 0x06 };
        int mask_index;
+       u32 sopass;
        u32 pmtctl;
        u32 wucsr;
        u32 macrx;
@@ -3218,6 +3556,14 @@ static void lan743x_pm_set_wol(struct lan743x_adapter *adapter)
                pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
        }
 
+       if (adapter->wolopts & WAKE_MAGICSECURE) {
+               sopass = *(u32 *)adapter->sopass;
+               lan743x_csr_write(adapter, MAC_MP_SO_LO, sopass);
+               sopass = *(u16 *)&adapter->sopass[4];
+               lan743x_csr_write(adapter, MAC_MP_SO_HI, sopass);
+               wucsr |= MAC_MP_SO_EN_;
+       }
+
        lan743x_csr_write(adapter, MAC_WUCSR, wucsr);
        lan743x_csr_write(adapter, PMT_CTL, pmtctl);
        lan743x_csr_write(adapter, MAC_RX, macrx);
@@ -3228,6 +3574,7 @@ static int lan743x_pm_suspend(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct lan743x_adapter *adapter = netdev_priv(netdev);
+       u32 data;
 
        lan743x_pcidev_shutdown(pdev);
 
@@ -3239,6 +3586,18 @@ static int lan743x_pm_suspend(struct device *dev)
        if (adapter->wolopts)
                lan743x_pm_set_wol(adapter);
 
+       if (adapter->is_pci11x1x) {
+               /* Save HW_CFG to config again in PM resume */
+               data = lan743x_csr_read(adapter, HW_CFG);
+               adapter->hw_cfg = data;
+               data |= (HW_CFG_RST_PROTECT_PCIE_ |
+                        HW_CFG_D3_RESET_DIS_ |
+                        HW_CFG_D3_VAUX_OVR_ |
+                        HW_CFG_HOT_RESET_DIS_ |
+                        HW_CFG_RST_PROTECT_);
+               lan743x_csr_write(adapter, HW_CFG, data);
+       }
+
        /* Host sets PME_En, put D3hot */
        return pci_prepare_to_sleep(pdev);
 }
@@ -3254,6 +3613,10 @@ static int lan743x_pm_resume(struct device *dev)
        pci_restore_state(pdev);
        pci_save_state(pdev);
 
+       /* Restore HW_CFG that was saved during pm suspend */
+       if (adapter->is_pci11x1x)
+               lan743x_csr_write(adapter, HW_CFG, adapter->hw_cfg);
+
        ret = lan743x_hardware_init(adapter, pdev);
        if (ret) {
                netif_err(adapter, probe, adapter->netdev,
@@ -3270,6 +3633,9 @@ static int lan743x_pm_resume(struct device *dev)
                lan743x_netdev_open(netdev);
 
        netif_device_attach(netdev);
+       ret = lan743x_csr_read(adapter, MAC_WK_SRC);
+       netif_info(adapter, drv, adapter->netdev,
+                  "Wakeup source : 0x%08X\n", ret);
 
        return 0;
 }
index 1ca5f32..72adae4 100644 (file)
 #define STRAP_READ_ADV_PM_DISABLE_     BIT(0)
 
 #define HW_CFG                                 (0x010)
+#define HW_CFG_RST_PROTECT_PCIE_               BIT(19)
+#define HW_CFG_HOT_RESET_DIS_                  BIT(15)
+#define HW_CFG_D3_VAUX_OVR_                    BIT(14)
+#define HW_CFG_D3_RESET_DIS_                   BIT(13)
+#define HW_CFG_RST_PROTECT_                    BIT(12)
 #define HW_CFG_RELOAD_TYPE_ALL_                        (0x00000FC0)
 #define HW_CFG_EE_OTP_RELOAD_                  BIT(4)
 #define HW_CFG_LRST_                           BIT(1)
 #define CONFIG_REG_ADDR_BASE           (0x0000)
 #define ETH_EEPROM_REG_ADDR_BASE       (0x0E00)
 #define ETH_OTP_REG_ADDR_BASE          (0x1000)
+#define GEN_SYS_CONFIG_LOAD_STARTED_REG        (0x0078)
+#define ETH_SYS_CONFIG_LOAD_STARTED_REG (ETH_SYS_REG_ADDR_BASE + \
+                                        CONFIG_REG_ADDR_BASE + \
+                                        GEN_SYS_CONFIG_LOAD_STARTED_REG)
+#define GEN_SYS_LOAD_STARTED_REG_ETH_  BIT(4)
 #define SYS_LOCK_REG                   (0x00A0)
 #define SYS_LOCK_REG_MAIN_LOCK_                BIT(7)
 #define SYS_LOCK_REG_GEN_PERI_LOCK_    BIT(5)
 #define MAC_EEE_TX_LPI_REQ_DLY_CNT             (0x130)
 
 #define MAC_WUCSR                              (0x140)
+#define MAC_MP_SO_EN_                          BIT(21)
 #define MAC_WUCSR_RFE_WAKE_EN_                 BIT(14)
 #define MAC_WUCSR_PFDA_EN_                     BIT(3)
 #define MAC_WUCSR_WAKE_EN_                     BIT(2)
 #define MAC_WUCSR_BCST_EN_                     BIT(0)
 
 #define MAC_WK_SRC                             (0x144)
+#define MAC_MP_SO_HI                           (0x148)
+#define MAC_MP_SO_LO                           (0x14C)
 
 #define MAC_WUF_CFG0                   (0x150)
 #define MAC_NUM_OF_WUF_CFG             (32)
 
 #define MAC_WUCSR2                     (0x600)
 
+#define SGMII_ACC                      (0x720)
+#define SGMII_ACC_SGMII_BZY_           BIT(31)
+#define SGMII_ACC_SGMII_WR_            BIT(30)
+#define SGMII_ACC_SGMII_MMD_SHIFT_     (16)
+#define SGMII_ACC_SGMII_MMD_MASK_      GENMASK(20, 16)
+#define SGMII_ACC_SGMII_MMD_VSR_       BIT(15)
+#define SGMII_ACC_SGMII_ADDR_SHIFT_    (0)
+#define SGMII_ACC_SGMII_ADDR_MASK_     GENMASK(15, 0)
+#define SGMII_DATA                     (0x724)
+#define SGMII_DATA_SHIFT_              (0)
+#define SGMII_DATA_MASK_               GENMASK(15, 0)
 #define SGMII_CTL                      (0x728)
 #define SGMII_CTL_SGMII_ENABLE_                BIT(31)
 #define SGMII_CTL_LINK_STATUS_SOURCE_  BIT(8)
 #define SGMII_CTL_SGMII_POWER_DN_      BIT(1)
 
+/* Vendor Specific SGMII MMD details */
+#define SR_VSMMD_PCS_ID1               0x0004
+#define SR_VSMMD_PCS_ID2               0x0005
+#define SR_VSMMD_STS                   0x0008
+#define SR_VSMMD_CTRL                  0x0009
+
+#define VR_MII_DIG_CTRL1                       0x8000
+#define VR_MII_DIG_CTRL1_VR_RST_               BIT(15)
+#define VR_MII_DIG_CTRL1_R2TLBE_               BIT(14)
+#define VR_MII_DIG_CTRL1_EN_VSMMD1_            BIT(13)
+#define VR_MII_DIG_CTRL1_CS_EN_                        BIT(10)
+#define VR_MII_DIG_CTRL1_MAC_AUTO_SW_          BIT(9)
+#define VR_MII_DIG_CTRL1_INIT_                 BIT(8)
+#define VR_MII_DIG_CTRL1_DTXLANED_0_           BIT(4)
+#define VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_    BIT(3)
+#define VR_MII_DIG_CTRL1_EN_2_5G_MODE_         BIT(2)
+#define VR_MII_DIG_CTRL1_BYP_PWRUP_            BIT(1)
+#define VR_MII_DIG_CTRL1_PHY_MODE_CTRL_                BIT(0)
+#define VR_MII_AN_CTRL                         0x8001
+#define VR_MII_AN_CTRL_MII_CTRL_               BIT(8)
+#define VR_MII_AN_CTRL_SGMII_LINK_STS_         BIT(4)
+#define VR_MII_AN_CTRL_TX_CONFIG_              BIT(3)
+#define VR_MII_AN_CTRL_1000BASE_X_             (0)
+#define VR_MII_AN_CTRL_SGMII_MODE_             (2)
+#define VR_MII_AN_CTRL_QSGMII_MODE_            (3)
+#define VR_MII_AN_CTRL_PCS_MODE_SHIFT_         (1)
+#define VR_MII_AN_CTRL_PCS_MODE_MASK_          GENMASK(2, 1)
+#define VR_MII_AN_CTRL_MII_AN_INTR_EN_         BIT(0)
+#define VR_MII_AN_INTR_STS                     0x8002
+#define VR_MII_AN_INTR_STS_LINK_UP_            BIT(4)
+#define VR_MII_AN_INTR_STS_SPEED_MASK_         GENMASK(3, 2)
+#define VR_MII_AN_INTR_STS_1000_MBPS_          BIT(3)
+#define VR_MII_AN_INTR_STS_100_MBPS_           BIT(2)
+#define VR_MII_AN_INTR_STS_10_MBPS_            (0)
+#define VR_MII_AN_INTR_STS_FDX_                        BIT(1)
+#define VR_MII_AN_INTR_STS_CL37_ANCMPLT_INTR_  BIT(0)
+
+#define VR_MII_LINK_TIMER_CTRL                 0x800A
+#define VR_MII_DIG_STS                          0x8010
+#define VR_MII_DIG_STS_PSEQ_STATE_MASK_         GENMASK(4, 2)
+#define VR_MII_DIG_STS_PSEQ_STATE_POS_          (2)
+#define VR_MII_GEN2_4_MPLL_CTRL0               0x8078
+#define VR_MII_MPLL_CTRL0_REF_CLK_DIV2_                BIT(12)
+#define VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_      BIT(4)
+#define VR_MII_GEN2_4_MPLL_CTRL1               0x8079
+#define VR_MII_MPLL_CTRL1_MPLL_MULTIPLIER_     GENMASK(6, 0)
+#define VR_MII_BAUD_RATE_3P125GBPS             (3125)
+#define VR_MII_BAUD_RATE_1P25GBPS              (1250)
+#define VR_MII_MPLL_MULTIPLIER_125             (125)
+#define VR_MII_MPLL_MULTIPLIER_100             (100)
+#define VR_MII_MPLL_MULTIPLIER_50              (50)
+#define VR_MII_MPLL_MULTIPLIER_40              (40)
+#define VR_MII_GEN2_4_MISC_CTRL1               0x809A
+#define VR_MII_CTRL1_RX_RATE_0_MASK_           GENMASK(3, 2)
+#define VR_MII_CTRL1_RX_RATE_0_SHIFT_          (2)
+#define VR_MII_CTRL1_TX_RATE_0_MASK_           GENMASK(1, 0)
+#define VR_MII_MPLL_BAUD_CLK                   (0)
+#define VR_MII_MPLL_BAUD_CLK_DIV_2             (1)
+#define VR_MII_MPLL_BAUD_CLK_DIV_4             (2)
+
 #define INT_STS                                (0x780)
 #define INT_BIT_DMA_RX_(channel)       BIT(24 + (channel))
 #define INT_BIT_ALL_RX_                        (0x0F000000)
@@ -906,12 +990,28 @@ struct lan743x_rx {
        struct sk_buff *skb_head, *skb_tail;
 };
 
+/* SGMII Link Speed Duplex status */
+enum lan743x_sgmii_lsd {
+       POWER_DOWN = 0,
+       LINK_DOWN,
+       ANEG_BUSY,
+       LINK_10HD,
+       LINK_10FD,
+       LINK_100HD,
+       LINK_100FD,
+       LINK_1000_MASTER,
+       LINK_1000_SLAVE,
+       LINK_2500_MASTER,
+       LINK_2500_SLAVE
+};
+
 struct lan743x_adapter {
        struct net_device       *netdev;
        struct mii_bus          *mdiobus;
        int                     msg_enable;
 #ifdef CONFIG_PM
        u32                     wolopts;
+       u8                      sopass[SOPASS_MAX];
 #endif
        struct pci_dev          *pdev;
        struct lan743x_csr      csr;
@@ -931,12 +1031,16 @@ struct lan743x_adapter {
        spinlock_t              eth_syslock_spinlock;
        bool                    eth_syslock_en;
        u32                     eth_syslock_acquire_cnt;
+       struct mutex            sgmii_rw_lock;
+       /* SGMII Link Speed & Duplex status */
+       enum                    lan743x_sgmii_lsd sgmii_lsd;
        u8                      max_tx_channels;
        u8                      used_tx_channels;
        u8                      max_vector_count;
 
 #define LAN743X_ADAPTER_FLAG_OTP               BIT(0)
        u32                     flags;
+       u32                     hw_cfg;
 };
 
 #define LAN743X_COMPONENT_FLAG_RX(channel)  BIT(20 + (channel))
@@ -1049,5 +1153,7 @@ struct lan743x_rx_buffer_info {
 
 u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset);
 void lan743x_csr_write(struct lan743x_adapter *adapter, int offset, u32 data);
+int lan743x_hs_syslock_acquire(struct lan743x_adapter *adapter, u16 timeout);
+void lan743x_hs_syslock_release(struct lan743x_adapter *adapter);
 
 #endif /* _LAN743X_H */
index 5edc8b7..ec07f7d 100644 (file)
@@ -394,15 +394,13 @@ static int sparx5_handle_port_mdb_add(struct net_device *dev,
        struct sparx5 *spx5 = port->sparx5;
        u16 pgid_idx, vid;
        u32 mact_entry;
+       bool is_host;
        int res, err;
 
        if (!sparx5_netdevice_check(dev))
                return -EOPNOTSUPP;
 
-       if (netif_is_bridge_master(v->obj.orig_dev)) {
-               sparx5_mact_learn(spx5, PGID_CPU, v->addr, v->vid);
-               return 0;
-       }
+       is_host = netif_is_bridge_master(v->obj.orig_dev);
 
        /* When VLAN unaware the vlan value is not parsed and we receive vid 0.
         * Fall back to bridge vid 1.
@@ -419,17 +417,33 @@ static int sparx5_handle_port_mdb_add(struct net_device *dev,
 
                /* MC_IDX starts after the port masks in the PGID table */
                pgid_idx += SPX5_PORTS;
-               sparx5_pgid_update_mask(port, pgid_idx, true);
+
+               if (is_host)
+                       spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
+                                ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5,
+                                ANA_AC_PGID_MISC_CFG(pgid_idx));
+               else
+                       sparx5_pgid_update_mask(port, pgid_idx, true);
+
        } else {
                err = sparx5_pgid_alloc_mcast(spx5, &pgid_idx);
                if (err) {
                        netdev_warn(dev, "multicast pgid table full\n");
                        return err;
                }
-               sparx5_pgid_update_mask(port, pgid_idx, true);
+
+               if (is_host)
+                       spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
+                                ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5,
+                                ANA_AC_PGID_MISC_CFG(pgid_idx));
+               else
+                       sparx5_pgid_update_mask(port, pgid_idx, true);
+
                err = sparx5_mact_learn(spx5, pgid_idx, v->addr, vid);
+
                if (err) {
                        netdev_warn(dev, "could not learn mac address %pM\n", v->addr);
+                       sparx5_pgid_free(spx5, pgid_idx);
                        sparx5_pgid_update_mask(port, pgid_idx, false);
                        return err;
                }
@@ -466,17 +480,12 @@ static int sparx5_handle_port_mdb_del(struct net_device *dev,
        struct sparx5_port *port = netdev_priv(dev);
        struct sparx5 *spx5 = port->sparx5;
        u16 pgid_idx, vid;
-       u32 mact_entry, res, pgid_entry[3];
-       int err;
+       u32 mact_entry, res, pgid_entry[3], misc_cfg;
+       bool host_ena;
 
        if (!sparx5_netdevice_check(dev))
                return -EOPNOTSUPP;
 
-       if (netif_is_bridge_master(v->obj.orig_dev)) {
-               sparx5_mact_forget(spx5, v->addr, v->vid);
-               return 0;
-       }
-
        if (!br_vlan_enabled(spx5->hw_bridge_dev))
                vid = 1;
        else
@@ -489,15 +498,21 @@ static int sparx5_handle_port_mdb_del(struct net_device *dev,
 
                /* MC_IDX starts after the port masks in the PGID table */
                pgid_idx += SPX5_PORTS;
-               sparx5_pgid_update_mask(port, pgid_idx, false);
+
+               if (netif_is_bridge_master(v->obj.orig_dev))
+                       spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(0),
+                                ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5,
+                                ANA_AC_PGID_MISC_CFG(pgid_idx));
+               else
+                       sparx5_pgid_update_mask(port, pgid_idx, false);
+
+               misc_cfg = spx5_rd(spx5, ANA_AC_PGID_MISC_CFG(pgid_idx));
+               host_ena = ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_GET(misc_cfg);
 
                sparx5_pgid_read_mask(spx5, pgid_idx, pgid_entry);
-               if (bitmap_empty((unsigned long *)pgid_entry, SPX5_PORTS)) {
-                       /* No ports are in MC group. Remove entry */
-                       err = sparx5_mdb_del_entry(dev, spx5, v->addr, vid, pgid_idx);
-                       if (err)
-                               return err;
-               }
+               if (bitmap_empty((unsigned long *)pgid_entry, SPX5_PORTS) && !host_ena)
+                       /* No ports or CPU are in MC group. Remove entry */
+                       return sparx5_mdb_del_entry(dev, spx5, v->addr, vid, pgid_idx);
        }
 
        return 0;
index 41ecd15..4a6efe6 100644 (file)
@@ -348,6 +348,7 @@ struct gdma_context {
        struct completion       eq_test_event;
        u32                     test_event_eq_id;
 
+       bool                    is_pf;
        void __iomem            *bar0_va;
        void __iomem            *shm_base;
        void __iomem            *db_page_base;
@@ -469,6 +470,15 @@ struct gdma_eqe {
 #define GDMA_REG_DB_PAGE_SIZE  0x10
 #define GDMA_REG_SHM_OFFSET    0x18
 
+#define GDMA_PF_REG_DB_PAGE_SIZE       0xD0
+#define GDMA_PF_REG_DB_PAGE_OFF                0xC8
+#define GDMA_PF_REG_SHM_OFF            0x70
+
+#define GDMA_SRIOV_REG_CFG_BASE_OFF    0x108
+
+#define MANA_PF_DEVICE_ID 0x00B9
+#define MANA_VF_DEVICE_ID 0x00BA
+
 struct gdma_posted_wqe_info {
        u32 wqe_size_in_bu;
 };
index 49b85ca..5f92401 100644 (file)
@@ -18,7 +18,24 @@ static u64 mana_gd_r64(struct gdma_context *g, u64 offset)
        return readq(g->bar0_va + offset);
 }
 
-static void mana_gd_init_registers(struct pci_dev *pdev)
+static void mana_gd_init_pf_regs(struct pci_dev *pdev)
+{
+       struct gdma_context *gc = pci_get_drvdata(pdev);
+       void __iomem *sriov_base_va;
+       u64 sriov_base_off;
+
+       gc->db_page_size = mana_gd_r32(gc, GDMA_PF_REG_DB_PAGE_SIZE) & 0xFFFF;
+       gc->db_page_base = gc->bar0_va +
+                               mana_gd_r64(gc, GDMA_PF_REG_DB_PAGE_OFF);
+
+       sriov_base_off = mana_gd_r64(gc, GDMA_SRIOV_REG_CFG_BASE_OFF);
+
+       sriov_base_va = gc->bar0_va + sriov_base_off;
+       gc->shm_base = sriov_base_va +
+                       mana_gd_r64(gc, sriov_base_off + GDMA_PF_REG_SHM_OFF);
+}
+
+static void mana_gd_init_vf_regs(struct pci_dev *pdev)
 {
        struct gdma_context *gc = pci_get_drvdata(pdev);
 
@@ -30,6 +47,16 @@ static void mana_gd_init_registers(struct pci_dev *pdev)
        gc->shm_base = gc->bar0_va + mana_gd_r64(gc, GDMA_REG_SHM_OFFSET);
 }
 
+static void mana_gd_init_registers(struct pci_dev *pdev)
+{
+       struct gdma_context *gc = pci_get_drvdata(pdev);
+
+       if (gc->is_pf)
+               mana_gd_init_pf_regs(pdev);
+       else
+               mana_gd_init_vf_regs(pdev);
+}
+
 static int mana_gd_query_max_resources(struct pci_dev *pdev)
 {
        struct gdma_context *gc = pci_get_drvdata(pdev);
@@ -1304,6 +1331,11 @@ static void mana_gd_cleanup(struct pci_dev *pdev)
        mana_gd_remove_irqs(pdev);
 }
 
+static bool mana_is_pf(unsigned short dev_id)
+{
+       return dev_id == MANA_PF_DEVICE_ID;
+}
+
 static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        struct gdma_context *gc;
@@ -1340,10 +1372,10 @@ static int mana_gd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!bar0_va)
                goto free_gc;
 
+       gc->is_pf = mana_is_pf(pdev->device);
        gc->bar0_va = bar0_va;
        gc->dev = &pdev->dev;
 
-
        err = mana_gd_setup(pdev);
        if (err)
                goto unmap_bar;
@@ -1438,7 +1470,8 @@ static void mana_gd_shutdown(struct pci_dev *pdev)
 #endif
 
 static const struct pci_device_id mana_id_table[] = {
-       { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, 0x00BA) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_PF_DEVICE_ID) },
+       { PCI_DEVICE(PCI_VENDOR_ID_MICROSOFT, MANA_VF_DEVICE_ID) },
        { }
 };
 
index 078d6a5..543a5d5 100644 (file)
@@ -158,6 +158,14 @@ static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self,
                        hwc->rxq->msg_buf->gpa_mkey = val;
                        hwc->txq->msg_buf->gpa_mkey = val;
                        break;
+
+               case HWC_INIT_DATA_PF_DEST_RQ_ID:
+                       hwc->pf_dest_vrq_id = val;
+                       break;
+
+               case HWC_INIT_DATA_PF_DEST_CQ_ID:
+                       hwc->pf_dest_vrcq_id = val;
+                       break;
                }
 
                break;
@@ -773,10 +781,13 @@ void mana_hwc_destroy_channel(struct gdma_context *gc)
 int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
                          const void *req, u32 resp_len, void *resp)
 {
+       struct gdma_context *gc = hwc->gdma_dev->gdma_context;
        struct hwc_work_request *tx_wr;
        struct hwc_wq *txq = hwc->txq;
        struct gdma_req_hdr *req_msg;
        struct hwc_caller_ctx *ctx;
+       u32 dest_vrcq = 0;
+       u32 dest_vrq = 0;
        u16 msg_id;
        int err;
 
@@ -803,7 +814,12 @@ int mana_hwc_send_request(struct hw_channel_context *hwc, u32 req_len,
 
        tx_wr->msg_size = req_len;
 
-       err = mana_hwc_post_tx_wqe(txq, tx_wr, 0, 0, false);
+       if (gc->is_pf) {
+               dest_vrq = hwc->pf_dest_vrq_id;
+               dest_vrcq = hwc->pf_dest_vrcq_id;
+       }
+
+       err = mana_hwc_post_tx_wqe(txq, tx_wr, dest_vrq, dest_vrcq, false);
        if (err) {
                dev_err(hwc->dev, "HWC: Failed to post send WQE: %d\n", err);
                goto out;
index 31c6e83..6a757a6 100644 (file)
@@ -20,6 +20,8 @@
 #define HWC_INIT_DATA_MAX_NUM_CQS      7
 #define HWC_INIT_DATA_PDID             8
 #define HWC_INIT_DATA_GPA_MKEY         9
+#define HWC_INIT_DATA_PF_DEST_RQ_ID    10
+#define HWC_INIT_DATA_PF_DEST_CQ_ID    11
 
 /* Structures labeled with "HW DATA" are exchanged with the hardware. All of
  * them are naturally aligned and hence don't need __packed.
@@ -178,6 +180,9 @@ struct hw_channel_context {
        struct semaphore sema;
        struct gdma_resource inflight_msg_res;
 
+       u32 pf_dest_vrq_id;
+       u32 pf_dest_vrcq_id;
+
        struct hwc_caller_ctx *caller_ctx;
 };
 
index d36405a..d58be64 100644 (file)
@@ -53,12 +53,14 @@ struct mana_stats_rx {
        u64 bytes;
        u64 xdp_drop;
        u64 xdp_tx;
+       u64 xdp_redirect;
        struct u64_stats_sync syncp;
 };
 
 struct mana_stats_tx {
        u64 packets;
        u64 bytes;
+       u64 xdp_xmit;
        struct u64_stats_sync syncp;
 };
 
@@ -311,6 +313,8 @@ struct mana_rxq {
        struct bpf_prog __rcu *bpf_prog;
        struct xdp_rxq_info xdp_rxq;
        struct page *xdp_save_page;
+       bool xdp_flush;
+       int xdp_rc; /* XDP redirect return code */
 
        /* MUST BE THE LAST MEMBER:
         * Each receive buffer has an associated mana_recv_buf_oob.
@@ -374,6 +378,7 @@ struct mana_port_context {
        unsigned int num_queues;
 
        mana_handle_t port_handle;
+       mana_handle_t pf_filter_handle;
 
        u16 port_idx;
 
@@ -395,6 +400,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming);
 void mana_remove(struct gdma_dev *gd, bool suspending);
 
 void mana_xdp_tx(struct sk_buff *skb, struct net_device *ndev);
+int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames,
+                 u32 flags);
 u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
                 struct xdp_buff *xdp, void *buf_va, uint pkt_len);
 struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
@@ -420,6 +427,12 @@ enum mana_command_code {
        MANA_FENCE_RQ           = 0x20006,
        MANA_CONFIG_VPORT_RX    = 0x20007,
        MANA_QUERY_VPORT_CONFIG = 0x20008,
+
+       /* Privileged commands for the PF mode */
+       MANA_REGISTER_FILTER    = 0x28000,
+       MANA_DEREGISTER_FILTER  = 0x28001,
+       MANA_REGISTER_HW_PORT   = 0x28003,
+       MANA_DEREGISTER_HW_PORT = 0x28004,
 };
 
 /* Query Device Configuration */
@@ -547,6 +560,63 @@ struct mana_cfg_rx_steer_resp {
        struct gdma_resp_hdr hdr;
 }; /* HW DATA */
 
+/* Register HW vPort */
+struct mana_register_hw_vport_req {
+       struct gdma_req_hdr hdr;
+       u16 attached_gfid;
+       u8 is_pf_default_vport;
+       u8 reserved1;
+       u8 allow_all_ether_types;
+       u8 reserved2;
+       u8 reserved3;
+       u8 reserved4;
+}; /* HW DATA */
+
+struct mana_register_hw_vport_resp {
+       struct gdma_resp_hdr hdr;
+       mana_handle_t hw_vport_handle;
+}; /* HW DATA */
+
+/* Deregister HW vPort */
+struct mana_deregister_hw_vport_req {
+       struct gdma_req_hdr hdr;
+       mana_handle_t hw_vport_handle;
+}; /* HW DATA */
+
+struct mana_deregister_hw_vport_resp {
+       struct gdma_resp_hdr hdr;
+}; /* HW DATA */
+
+/* Register filter */
+struct mana_register_filter_req {
+       struct gdma_req_hdr hdr;
+       mana_handle_t vport;
+       u8 mac_addr[6];
+       u8 reserved1;
+       u8 reserved2;
+       u8 reserved3;
+       u8 reserved4;
+       u16 reserved5;
+       u32 reserved6;
+       u32 reserved7;
+       u32 reserved8;
+}; /* HW DATA */
+
+struct mana_register_filter_resp {
+       struct gdma_resp_hdr hdr;
+       mana_handle_t filter_handle;
+}; /* HW DATA */
+
+/* Deregister filter */
+struct mana_deregister_filter_req {
+       struct gdma_req_hdr hdr;
+       mana_handle_t filter_handle;
+}; /* HW DATA */
+
+struct mana_deregister_filter_resp {
+       struct gdma_resp_hdr hdr;
+}; /* HW DATA */
+
 #define MANA_MAX_NUM_QUEUES 64
 
 #define MANA_SHORT_VPORT_OFFSET_MAX ((1U << 8) - 1)
index 1d2f948..421fd39 100644 (file)
@@ -32,9 +32,55 @@ void mana_xdp_tx(struct sk_buff *skb, struct net_device *ndev)
        ndev->stats.tx_dropped++;
 }
 
+static int mana_xdp_xmit_fm(struct net_device *ndev, struct xdp_frame *frame,
+                           u16 q_idx)
+{
+       struct sk_buff *skb;
+
+       skb = xdp_build_skb_from_frame(frame, ndev);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       skb_set_queue_mapping(skb, q_idx);
+
+       mana_xdp_tx(skb, ndev);
+
+       return 0;
+}
+
+int mana_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames,
+                 u32 flags)
+{
+       struct mana_port_context *apc = netdev_priv(ndev);
+       struct mana_stats_tx *tx_stats;
+       int i, count = 0;
+       u16 q_idx;
+
+       if (unlikely(!apc->port_is_up))
+               return 0;
+
+       q_idx = smp_processor_id() % ndev->real_num_tx_queues;
+
+       for (i = 0; i < n; i++) {
+               if (mana_xdp_xmit_fm(ndev, frames[i], q_idx))
+                       break;
+
+               count++;
+       }
+
+       tx_stats = &apc->tx_qp[q_idx].txq.stats;
+
+       u64_stats_update_begin(&tx_stats->syncp);
+       tx_stats->xdp_xmit += count;
+       u64_stats_update_end(&tx_stats->syncp);
+
+       return count;
+}
+
 u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
                 struct xdp_buff *xdp, void *buf_va, uint pkt_len)
 {
+       struct mana_stats_rx *rx_stats;
        struct bpf_prog *prog;
        u32 act = XDP_PASS;
 
@@ -49,12 +95,30 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
 
        act = bpf_prog_run_xdp(prog, xdp);
 
+       rx_stats = &rxq->stats;
+
        switch (act) {
        case XDP_PASS:
        case XDP_TX:
        case XDP_DROP:
                break;
 
+       case XDP_REDIRECT:
+               rxq->xdp_rc = xdp_do_redirect(ndev, xdp, prog);
+               if (!rxq->xdp_rc) {
+                       rxq->xdp_flush = true;
+
+                       u64_stats_update_begin(&rx_stats->syncp);
+                       rx_stats->packets++;
+                       rx_stats->bytes += pkt_len;
+                       rx_stats->xdp_redirect++;
+                       u64_stats_update_end(&rx_stats->syncp);
+
+                       break;
+               }
+
+               fallthrough;
+
        case XDP_ABORTED:
                trace_xdp_exception(ndev, prog, act);
                break;
index b1d7738..9259a74 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/inetdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/filter.h>
 #include <linux/mm.h>
 
 #include <net/checksum.h>
@@ -382,6 +383,7 @@ static const struct net_device_ops mana_devops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_get_stats64        = mana_get_stats64,
        .ndo_bpf                = mana_bpf,
+       .ndo_xdp_xmit           = mana_xdp_xmit,
 };
 
 static void mana_cleanup_port_context(struct mana_port_context *apc)
@@ -446,6 +448,119 @@ static int mana_verify_resp_hdr(const struct gdma_resp_hdr *resp_hdr,
        return 0;
 }
 
+static int mana_pf_register_hw_vport(struct mana_port_context *apc)
+{
+       struct mana_register_hw_vport_resp resp = {};
+       struct mana_register_hw_vport_req req = {};
+       int err;
+
+       mana_gd_init_req_hdr(&req.hdr, MANA_REGISTER_HW_PORT,
+                            sizeof(req), sizeof(resp));
+       req.attached_gfid = 1;
+       req.is_pf_default_vport = 1;
+       req.allow_all_ether_types = 1;
+
+       err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+                               sizeof(resp));
+       if (err) {
+               netdev_err(apc->ndev, "Failed to register hw vPort: %d\n", err);
+               return err;
+       }
+
+       err = mana_verify_resp_hdr(&resp.hdr, MANA_REGISTER_HW_PORT,
+                                  sizeof(resp));
+       if (err || resp.hdr.status) {
+               netdev_err(apc->ndev, "Failed to register hw vPort: %d, 0x%x\n",
+                          err, resp.hdr.status);
+               return err ? err : -EPROTO;
+       }
+
+       apc->port_handle = resp.hw_vport_handle;
+       return 0;
+}
+
+static void mana_pf_deregister_hw_vport(struct mana_port_context *apc)
+{
+       struct mana_deregister_hw_vport_resp resp = {};
+       struct mana_deregister_hw_vport_req req = {};
+       int err;
+
+       mana_gd_init_req_hdr(&req.hdr, MANA_DEREGISTER_HW_PORT,
+                            sizeof(req), sizeof(resp));
+       req.hw_vport_handle = apc->port_handle;
+
+       err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+                               sizeof(resp));
+       if (err) {
+               netdev_err(apc->ndev, "Failed to unregister hw vPort: %d\n",
+                          err);
+               return;
+       }
+
+       err = mana_verify_resp_hdr(&resp.hdr, MANA_DEREGISTER_HW_PORT,
+                                  sizeof(resp));
+       if (err || resp.hdr.status)
+               netdev_err(apc->ndev,
+                          "Failed to deregister hw vPort: %d, 0x%x\n",
+                          err, resp.hdr.status);
+}
+
+static int mana_pf_register_filter(struct mana_port_context *apc)
+{
+       struct mana_register_filter_resp resp = {};
+       struct mana_register_filter_req req = {};
+       int err;
+
+       mana_gd_init_req_hdr(&req.hdr, MANA_REGISTER_FILTER,
+                            sizeof(req), sizeof(resp));
+       req.vport = apc->port_handle;
+       memcpy(req.mac_addr, apc->mac_addr, ETH_ALEN);
+
+       err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+                               sizeof(resp));
+       if (err) {
+               netdev_err(apc->ndev, "Failed to register filter: %d\n", err);
+               return err;
+       }
+
+       err = mana_verify_resp_hdr(&resp.hdr, MANA_REGISTER_FILTER,
+                                  sizeof(resp));
+       if (err || resp.hdr.status) {
+               netdev_err(apc->ndev, "Failed to register filter: %d, 0x%x\n",
+                          err, resp.hdr.status);
+               return err ? err : -EPROTO;
+       }
+
+       apc->pf_filter_handle = resp.filter_handle;
+       return 0;
+}
+
+static void mana_pf_deregister_filter(struct mana_port_context *apc)
+{
+       struct mana_deregister_filter_resp resp = {};
+       struct mana_deregister_filter_req req = {};
+       int err;
+
+       mana_gd_init_req_hdr(&req.hdr, MANA_DEREGISTER_FILTER,
+                            sizeof(req), sizeof(resp));
+       req.filter_handle = apc->pf_filter_handle;
+
+       err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+                               sizeof(resp));
+       if (err) {
+               netdev_err(apc->ndev, "Failed to unregister filter: %d\n",
+                          err);
+               return;
+       }
+
+       err = mana_verify_resp_hdr(&resp.hdr, MANA_DEREGISTER_FILTER,
+                                  sizeof(resp));
+       if (err || resp.hdr.status)
+               netdev_err(apc->ndev,
+                          "Failed to deregister filter: %d, 0x%x\n",
+                          err, resp.hdr.status);
+}
+
 static int mana_query_device_cfg(struct mana_context *ac, u32 proto_major_ver,
                                 u32 proto_minor_ver, u32 proto_micro_ver,
                                 u16 *max_num_vports)
@@ -1007,6 +1122,9 @@ static void mana_rx_skb(void *buf_va, struct mana_rxcomp_oob *cqe,
 
        act = mana_run_xdp(ndev, rxq, &xdp, buf_va, pkt_len);
 
+       if (act == XDP_REDIRECT && !rxq->xdp_rc)
+               return;
+
        if (act != XDP_PASS && act != XDP_TX)
                goto drop_xdp;
 
@@ -1162,11 +1280,14 @@ drop:
 static void mana_poll_rx_cq(struct mana_cq *cq)
 {
        struct gdma_comp *comp = cq->gdma_comp_buf;
+       struct mana_rxq *rxq = cq->rxq;
        int comp_read, i;
 
        comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER);
        WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER);
 
+       rxq->xdp_flush = false;
+
        for (i = 0; i < comp_read; i++) {
                if (WARN_ON_ONCE(comp[i].is_sq))
                        return;
@@ -1175,8 +1296,11 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
                if (WARN_ON_ONCE(comp[i].wq_num != cq->rxq->gdma_id))
                        return;
 
-               mana_process_rx_cqe(cq->rxq, cq, &comp[i]);
+               mana_process_rx_cqe(rxq, cq, &comp[i]);
        }
+
+       if (rxq->xdp_flush)
+               xdp_do_flush();
 }
 
 static void mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
@@ -1653,6 +1777,7 @@ out:
 
 static void mana_destroy_vport(struct mana_port_context *apc)
 {
+       struct gdma_dev *gd = apc->ac->gdma_dev;
        struct mana_rxq *rxq;
        u32 rxq_idx;
 
@@ -1666,6 +1791,9 @@ static void mana_destroy_vport(struct mana_port_context *apc)
        }
 
        mana_destroy_txq(apc);
+
+       if (gd->gdma_context->is_pf)
+               mana_pf_deregister_hw_vport(apc);
 }
 
 static int mana_create_vport(struct mana_port_context *apc,
@@ -1676,6 +1804,12 @@ static int mana_create_vport(struct mana_port_context *apc,
 
        apc->default_rxobj = INVALID_MANA_HANDLE;
 
+       if (gd->gdma_context->is_pf) {
+               err = mana_pf_register_hw_vport(apc);
+               if (err)
+                       return err;
+       }
+
        err = mana_cfg_vport(apc, gd->pdid, gd->doorbell);
        if (err)
                return err;
@@ -1755,6 +1889,7 @@ reset_apc:
 int mana_alloc_queues(struct net_device *ndev)
 {
        struct mana_port_context *apc = netdev_priv(ndev);
+       struct gdma_dev *gd = apc->ac->gdma_dev;
        int err;
 
        err = mana_create_vport(apc, ndev);
@@ -1781,6 +1916,12 @@ int mana_alloc_queues(struct net_device *ndev)
        if (err)
                goto destroy_vport;
 
+       if (gd->gdma_context->is_pf) {
+               err = mana_pf_register_filter(apc);
+               if (err)
+                       goto destroy_vport;
+       }
+
        mana_chn_setxdp(apc, mana_xdp_get(apc));
 
        return 0;
@@ -1825,6 +1966,7 @@ int mana_attach(struct net_device *ndev)
 static int mana_dealloc_queues(struct net_device *ndev)
 {
        struct mana_port_context *apc = netdev_priv(ndev);
+       struct gdma_dev *gd = apc->ac->gdma_dev;
        struct mana_txq *txq;
        int i, err;
 
@@ -1833,6 +1975,9 @@ static int mana_dealloc_queues(struct net_device *ndev)
 
        mana_chn_setxdp(apc, NULL);
 
+       if (gd->gdma_context->is_pf)
+               mana_pf_deregister_filter(apc);
+
        /* No packet can be transmitted now since apc->port_is_up is false.
         * There is still a tiny chance that mana_poll_tx_cq() can re-enable
         * a txq because it may not timely see apc->port_is_up being cleared
@@ -1915,6 +2060,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
        apc->max_queues = gc->max_num_queues;
        apc->num_queues = gc->max_num_queues;
        apc->port_handle = INVALID_MANA_HANDLE;
+       apc->pf_filter_handle = INVALID_MANA_HANDLE;
        apc->port_idx = port_idx;
 
        ndev->netdev_ops = &mana_devops;
index e13f245..c530db7 100644 (file)
@@ -23,7 +23,7 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
        if (stringset != ETH_SS_STATS)
                return -EINVAL;
 
-       return ARRAY_SIZE(mana_eth_stats) + num_queues * 6;
+       return ARRAY_SIZE(mana_eth_stats) + num_queues * 8;
 }
 
 static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
@@ -50,6 +50,8 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
                p += ETH_GSTRING_LEN;
                sprintf(p, "rx_%d_xdp_tx", i);
                p += ETH_GSTRING_LEN;
+               sprintf(p, "rx_%d_xdp_redirect", i);
+               p += ETH_GSTRING_LEN;
        }
 
        for (i = 0; i < num_queues; i++) {
@@ -57,6 +59,8 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
                p += ETH_GSTRING_LEN;
                sprintf(p, "tx_%d_bytes", i);
                p += ETH_GSTRING_LEN;
+               sprintf(p, "tx_%d_xdp_xmit", i);
+               p += ETH_GSTRING_LEN;
        }
 }
 
@@ -70,6 +74,8 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
        struct mana_stats_tx *tx_stats;
        unsigned int start;
        u64 packets, bytes;
+       u64 xdp_redirect;
+       u64 xdp_xmit;
        u64 xdp_drop;
        u64 xdp_tx;
        int q, i = 0;
@@ -89,12 +95,14 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
                        bytes = rx_stats->bytes;
                        xdp_drop = rx_stats->xdp_drop;
                        xdp_tx = rx_stats->xdp_tx;
+                       xdp_redirect = rx_stats->xdp_redirect;
                } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
 
                data[i++] = packets;
                data[i++] = bytes;
                data[i++] = xdp_drop;
                data[i++] = xdp_tx;
+               data[i++] = xdp_redirect;
        }
 
        for (q = 0; q < num_queues; q++) {
@@ -104,10 +112,12 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
                        start = u64_stats_fetch_begin_irq(&tx_stats->syncp);
                        packets = tx_stats->packets;
                        bytes = tx_stats->bytes;
+                       xdp_xmit = tx_stats->xdp_xmit;
                } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start));
 
                data[i++] = packets;
                data[i++] = bytes;
+               data[i++] = xdp_xmit;
        }
 }
 
index 8da7e25..d4649e4 100644 (file)
@@ -3367,6 +3367,7 @@ int ocelot_init(struct ocelot *ocelot)
        mutex_init(&ocelot->ptp_lock);
        mutex_init(&ocelot->mact_lock);
        mutex_init(&ocelot->fwd_domain_lock);
+       mutex_init(&ocelot->tas_lock);
        spin_lock_init(&ocelot->ptp_clock_lock);
        spin_lock_init(&ocelot->ts_id_lock);
        snprintf(queue_name, sizeof(queue_name), "%s-stats",
index 87ad213..09c703e 100644 (file)
@@ -72,6 +72,10 @@ int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
        ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 
        spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
+
+       if (ocelot->ops->tas_clock_adjust)
+               ocelot->ops->tas_clock_adjust(ocelot);
+
        return 0;
 }
 EXPORT_SYMBOL(ocelot_ptp_settime64);
@@ -105,6 +109,9 @@ int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
                ocelot_write_rix(ocelot, val, PTP_PIN_CFG, TOD_ACC_PIN);
 
                spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
+
+               if (ocelot->ops->tas_clock_adjust)
+                       ocelot->ops->tas_clock_adjust(ocelot);
        } else {
                /* Fall back using ocelot_ptp_settime64 which is not exact. */
                struct timespec64 ts;
@@ -117,6 +124,7 @@ int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 
                ocelot_ptp_settime64(ptp, &ts);
        }
+
        return 0;
 }
 EXPORT_SYMBOL(ocelot_ptp_adjtime);
index 61497c3..971dde8 100644 (file)
@@ -2692,7 +2692,7 @@ again:
                 * send loop that we are still in the
                 * header portion of the TSO packet.
                 * TSO header can be at most 1KB long */
-               cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb));
+               cum_len = -skb_tcp_all_headers(skb);
 
                /* for IPv6 TSO, the checksum offset stores the
                 * TCP header length, to save the firmware from
index 50bca48..9aae7f1 100644 (file)
@@ -158,7 +158,7 @@ MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
 I. Board Compatibility
 
 This driver is designed for National Semiconductor DP83815 PCI Ethernet NIC.
-It also works with other chips in in the DP83810 series.
+It also works with other chips in the DP83810 series.
 
 II. Board-specific settings
 
index 0c0d127..09a89e7 100644 (file)
@@ -32,28 +32,4 @@ config S2IO
          To compile this driver as a module, choose M here. The module
          will be called s2io.
 
-config VXGE
-       tristate "Neterion (Exar) X3100 Series 10GbE PCIe Server Adapter"
-       depends on PCI
-       help
-         This driver supports Exar Corp's X3100 Series 10 GbE PCIe
-         I/O Virtualized Server Adapter.  These were originally released from
-         Neterion, which was later acquired by Exar.  So, the adapters might be
-         labeled as either one, depending on its age.
-
-         More specific information on configuring the driver is in
-         <file:Documentation/networking/device_drivers/ethernet/neterion/vxge.rst>.
-
-         To compile this driver as a module, choose M here. The module
-         will be called vxge.
-
-config VXGE_DEBUG_TRACE_ALL
-       bool "Enabling All Debug trace statements in driver"
-       default n
-       depends on VXGE
-       help
-         Say Y here if you want to enabling all the debug trace statements in
-         the vxge driver. By default only few debug trace statements are
-         enabled.
-
 endif # NET_VENDOR_NETERION
index 87ede8a..de98b4e 100644 (file)
@@ -4,4 +4,3 @@
 #
 
 obj-$(CONFIG_S2IO) += s2io.o
-obj-$(CONFIG_VXGE) += vxge/
index 6dd451a..30f955e 100644 (file)
@@ -2156,7 +2156,7 @@ static int verify_xena_quiescence(struct s2io_nic *sp)
 
        /*
         * In PCI 33 mode, the P_PLL is not used, and therefore,
-        * the the P_PLL_LOCK bit in the adapter_status register will
+        * the P_PLL_LOCK bit in the adapter_status register will
         * not be asserted.
         */
        if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
@@ -3817,7 +3817,7 @@ static irqreturn_t s2io_test_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Test interrupt path by forcing a software IRQ */
+/* Test interrupt path by forcing a software IRQ */
 static int s2io_test_msi(struct s2io_nic *sp)
 {
        struct pci_dev *pdev = sp->pdev;
@@ -5492,7 +5492,7 @@ s2io_ethtool_gringparam(struct net_device *dev,
 }
 
 /**
- * s2io_ethtool_getpause_data -Pause frame frame generation and reception.
+ * s2io_ethtool_getpause_data -Pause frame generation and reception.
  * @dev: pointer to netdev
  * @ep : pointer to the structure with pause parameters given by ethtool.
  * Description:
@@ -7449,7 +7449,7 @@ aggregate:
  *  @link : inidicates whether link is UP/DOWN.
  *  Description:
  *  This function stops/starts the Tx queue depending on whether the link
- *  status of the NIC is is down or up. This is called by the Alarm
+ *  status of the NIC is down or up. This is called by the Alarm
  *  interrupt handler whenever a link change interrupt comes up.
  *  Return value:
  *  void.
@@ -7732,7 +7732,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
         * Setting the device configuration parameters.
         * Most of these parameters can be specified by the user during
         * module insertion as they are module loadable parameters. If
-        * these parameters are not not specified during load time, they
+        * these parameters are not specified during load time, they
         * are initialized with default values.
         */
        config = &sp->config;
diff --git a/drivers/net/ethernet/neterion/vxge/Makefile b/drivers/net/ethernet/neterion/vxge/Makefile
deleted file mode 100644 (file)
index 0820e81..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for Exar Corp's X3100 Series 10 GbE PCIe I/O
-# Virtualized Server Adapter linux driver
-
-obj-$(CONFIG_VXGE) += vxge.o
-
-vxge-objs := vxge-config.o vxge-traffic.o vxge-ethtool.o vxge-main.o
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
deleted file mode 100644 (file)
index a3204a7..0000000
+++ /dev/null
@@ -1,5099 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-config.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#include <linux/vmalloc.h>
-#include <linux/etherdevice.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "vxge-traffic.h"
-#include "vxge-config.h"
-#include "vxge-main.h"
-
-#define VXGE_HW_VPATH_STATS_PIO_READ(offset) {                         \
-       status = __vxge_hw_vpath_stats_access(vpath,                    \
-                                             VXGE_HW_STATS_OP_READ,    \
-                                             offset,                   \
-                                             &val64);                  \
-       if (status != VXGE_HW_OK)                                       \
-               return status;                                          \
-}
-
-static void
-vxge_hw_vpath_set_zero_rx_frm_len(struct vxge_hw_vpath_reg __iomem *vp_reg)
-{
-       u64 val64;
-
-       val64 = readq(&vp_reg->rxmac_vcfg0);
-       val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
-       writeq(val64, &vp_reg->rxmac_vcfg0);
-       val64 = readq(&vp_reg->rxmac_vcfg0);
-}
-
-/*
- * vxge_hw_vpath_wait_receive_idle - Wait for Rx to become idle
- */
-int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-       struct __vxge_hw_virtualpath *vpath;
-       u64 val64, rxd_count, rxd_spat;
-       int count = 0, total_count = 0;
-
-       vpath = &hldev->virtual_paths[vp_id];
-       vp_reg = vpath->vp_reg;
-
-       vxge_hw_vpath_set_zero_rx_frm_len(vp_reg);
-
-       /* Check that the ring controller for this vpath has enough free RxDs
-        * to send frames to the host.  This is done by reading the
-        * PRC_RXD_DOORBELL_VPn register and comparing the read value to the
-        * RXD_SPAT value for the vpath.
-        */
-       val64 = readq(&vp_reg->prc_cfg6);
-       rxd_spat = VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val64) + 1;
-       /* Use a factor of 2 when comparing rxd_count against rxd_spat for some
-        * leg room.
-        */
-       rxd_spat *= 2;
-
-       do {
-               mdelay(1);
-
-               rxd_count = readq(&vp_reg->prc_rxd_doorbell);
-
-               /* Check that the ring controller for this vpath does
-                * not have any frame in its pipeline.
-                */
-               val64 = readq(&vp_reg->frm_in_progress_cnt);
-               if ((rxd_count <= rxd_spat) || (val64 > 0))
-                       count = 0;
-               else
-                       count++;
-               total_count++;
-       } while ((count < VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT) &&
-                       (total_count < VXGE_HW_MAX_POLLING_COUNT));
-
-       if (total_count >= VXGE_HW_MAX_POLLING_COUNT)
-               printk(KERN_ALERT "%s: Still Receiving traffic. Abort wait\n",
-                       __func__);
-
-       return total_count;
-}
-
-/* vxge_hw_device_wait_receive_idle - This function waits until all frames
- * stored in the frame buffer for each vpath assigned to the given
- * function (hldev) have been sent to the host.
- */
-void vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev)
-{
-       int i, total_count = 0;
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
-                       continue;
-
-               total_count += vxge_hw_vpath_wait_receive_idle(hldev, i);
-               if (total_count >= VXGE_HW_MAX_POLLING_COUNT)
-                       break;
-       }
-}
-
-/*
- * __vxge_hw_device_register_poll
- * Will poll certain register for specified amount of time.
- * Will poll until masked bit is not cleared.
- */
-static enum vxge_hw_status
-__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis)
-{
-       u64 val64;
-       u32 i = 0;
-
-       udelay(10);
-
-       do {
-               val64 = readq(reg);
-               if (!(val64 & mask))
-                       return VXGE_HW_OK;
-               udelay(100);
-       } while (++i <= 9);
-
-       i = 0;
-       do {
-               val64 = readq(reg);
-               if (!(val64 & mask))
-                       return VXGE_HW_OK;
-               mdelay(1);
-       } while (++i <= max_millis);
-
-       return VXGE_HW_FAIL;
-}
-
-static inline enum vxge_hw_status
-__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
-                         u64 mask, u32 max_millis)
-{
-       __vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr);
-       wmb();
-       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr);
-       wmb();
-
-       return __vxge_hw_device_register_poll(addr, mask, max_millis);
-}
-
-static enum vxge_hw_status
-vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action,
-                    u32 fw_memo, u32 offset, u64 *data0, u64 *data1,
-                    u64 *steer_ctrl)
-{
-       struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
-       enum vxge_hw_status status;
-       u64 val64;
-       u32 retry = 0, max_retry = 3;
-
-       spin_lock(&vpath->lock);
-       if (!vpath->vp_open) {
-               spin_unlock(&vpath->lock);
-               max_retry = 100;
-       }
-
-       writeq(*data0, &vp_reg->rts_access_steer_data0);
-       writeq(*data1, &vp_reg->rts_access_steer_data1);
-       wmb();
-
-       val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) |
-               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(fw_memo) |
-               VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset) |
-               VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE |
-               *steer_ctrl;
-
-       status = __vxge_hw_pio_mem_write64(val64,
-                                          &vp_reg->rts_access_steer_ctrl,
-                                          VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
-                                          VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
-       /* The __vxge_hw_device_register_poll can udelay for a significant
-        * amount of time, blocking other process from the CPU.  If it delays
-        * for ~5secs, a NMI error can occur.  A way around this is to give up
-        * the processor via msleep, but this is not allowed is under lock.
-        * So, only allow it to sleep for ~4secs if open.  Otherwise, delay for
-        * 1sec and sleep for 10ms until the firmware operation has completed
-        * or timed-out.
-        */
-       while ((status != VXGE_HW_OK) && retry++ < max_retry) {
-               if (!vpath->vp_open)
-                       msleep(20);
-               status = __vxge_hw_device_register_poll(
-                                       &vp_reg->rts_access_steer_ctrl,
-                                       VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE,
-                                       VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-       }
-
-       if (status != VXGE_HW_OK)
-               goto out;
-
-       val64 = readq(&vp_reg->rts_access_steer_ctrl);
-       if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) {
-               *data0 = readq(&vp_reg->rts_access_steer_data0);
-               *data1 = readq(&vp_reg->rts_access_steer_data1);
-               *steer_ctrl = val64;
-       } else
-               status = VXGE_HW_FAIL;
-
-out:
-       if (vpath->vp_open)
-               spin_unlock(&vpath->lock);
-       return status;
-}
-
-enum vxge_hw_status
-vxge_hw_upgrade_read_version(struct __vxge_hw_device *hldev, u32 *major,
-                            u32 *minor, u32 *build)
-{
-       u64 data0 = 0, data1 = 0, steer_ctrl = 0;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status;
-
-       vpath = &hldev->virtual_paths[hldev->first_vp_id];
-
-       status = vxge_hw_vpath_fw_api(vpath,
-                                     VXGE_HW_FW_UPGRADE_ACTION,
-                                     VXGE_HW_FW_UPGRADE_MEMO,
-                                     VXGE_HW_FW_UPGRADE_OFFSET_READ,
-                                     &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK)
-               return status;
-
-       *major = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data0);
-       *minor = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data0);
-       *build = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data0);
-
-       return status;
-}
-
-enum vxge_hw_status vxge_hw_flash_fw(struct __vxge_hw_device *hldev)
-{
-       u64 data0 = 0, data1 = 0, steer_ctrl = 0;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status;
-       u32 ret;
-
-       vpath = &hldev->virtual_paths[hldev->first_vp_id];
-
-       status = vxge_hw_vpath_fw_api(vpath,
-                                     VXGE_HW_FW_UPGRADE_ACTION,
-                                     VXGE_HW_FW_UPGRADE_MEMO,
-                                     VXGE_HW_FW_UPGRADE_OFFSET_COMMIT,
-                                     &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR, "%s: FW upgrade failed", __func__);
-               goto exit;
-       }
-
-       ret = VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(steer_ctrl) & 0x7F;
-       if (ret != 1) {
-               vxge_debug_init(VXGE_ERR, "%s: FW commit failed with error %d",
-                               __func__, ret);
-               status = VXGE_HW_FAIL;
-       }
-
-exit:
-       return status;
-}
-
-enum vxge_hw_status
-vxge_update_fw_image(struct __vxge_hw_device *hldev, const u8 *fwdata, int size)
-{
-       u64 data0 = 0, data1 = 0, steer_ctrl = 0;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status;
-       int ret_code, sec_code;
-
-       vpath = &hldev->virtual_paths[hldev->first_vp_id];
-
-       /* send upgrade start command */
-       status = vxge_hw_vpath_fw_api(vpath,
-                                     VXGE_HW_FW_UPGRADE_ACTION,
-                                     VXGE_HW_FW_UPGRADE_MEMO,
-                                     VXGE_HW_FW_UPGRADE_OFFSET_START,
-                                     &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR, " %s: Upgrade start cmd failed",
-                               __func__);
-               return status;
-       }
-
-       /* Transfer fw image to adapter 16 bytes at a time */
-       for (; size > 0; size -= VXGE_HW_FW_UPGRADE_BLK_SIZE) {
-               steer_ctrl = 0;
-
-               /* The next 128bits of fwdata to be loaded onto the adapter */
-               data0 = *((u64 *)fwdata);
-               data1 = *((u64 *)fwdata + 1);
-
-               status = vxge_hw_vpath_fw_api(vpath,
-                                             VXGE_HW_FW_UPGRADE_ACTION,
-                                             VXGE_HW_FW_UPGRADE_MEMO,
-                                             VXGE_HW_FW_UPGRADE_OFFSET_SEND,
-                                             &data0, &data1, &steer_ctrl);
-               if (status != VXGE_HW_OK) {
-                       vxge_debug_init(VXGE_ERR, "%s: Upgrade send failed",
-                                       __func__);
-                       goto out;
-               }
-
-               ret_code = VXGE_HW_UPGRADE_GET_RET_ERR_CODE(data0);
-               switch (ret_code) {
-               case VXGE_HW_FW_UPGRADE_OK:
-                       /* All OK, send next 16 bytes. */
-                       break;
-               case VXGE_FW_UPGRADE_BYTES2SKIP:
-                       /* skip bytes in the stream */
-                       fwdata += (data0 >> 8) & 0xFFFFFFFF;
-                       break;
-               case VXGE_HW_FW_UPGRADE_DONE:
-                       goto out;
-               case VXGE_HW_FW_UPGRADE_ERR:
-                       sec_code = VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(data0);
-                       switch (sec_code) {
-                       case VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1:
-                       case VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7:
-                               printk(KERN_ERR
-                                      "corrupted data from .ncf file\n");
-                               break;
-                       case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3:
-                       case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4:
-                       case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5:
-                       case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6:
-                       case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8:
-                               printk(KERN_ERR "invalid .ncf file\n");
-                               break;
-                       case VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW:
-                               printk(KERN_ERR "buffer overflow\n");
-                               break;
-                       case VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH:
-                               printk(KERN_ERR "failed to flash the image\n");
-                               break;
-                       case VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN:
-                               printk(KERN_ERR
-                                      "generic error. Unknown error type\n");
-                               break;
-                       default:
-                               printk(KERN_ERR "Unknown error of type %d\n",
-                                      sec_code);
-                               break;
-                       }
-                       status = VXGE_HW_FAIL;
-                       goto out;
-               default:
-                       printk(KERN_ERR "Unknown FW error: %d\n", ret_code);
-                       status = VXGE_HW_FAIL;
-                       goto out;
-               }
-               /* point to next 16 bytes */
-               fwdata += VXGE_HW_FW_UPGRADE_BLK_SIZE;
-       }
-out:
-       return status;
-}
-
-enum vxge_hw_status
-vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev,
-                               struct eprom_image *img)
-{
-       u64 data0 = 0, data1 = 0, steer_ctrl = 0;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status;
-       int i;
-
-       vpath = &hldev->virtual_paths[hldev->first_vp_id];
-
-       for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) {
-               data0 = VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(i);
-               data1 = steer_ctrl = 0;
-
-               status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_FW_API_GET_EPROM_REV,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-               if (status != VXGE_HW_OK)
-                       break;
-
-               img[i].is_valid = VXGE_HW_GET_EPROM_IMAGE_VALID(data0);
-               img[i].index = VXGE_HW_GET_EPROM_IMAGE_INDEX(data0);
-               img[i].type = VXGE_HW_GET_EPROM_IMAGE_TYPE(data0);
-               img[i].version = VXGE_HW_GET_EPROM_IMAGE_REV(data0);
-       }
-
-       return status;
-}
-
-/*
- * __vxge_hw_channel_free - Free memory allocated for channel
- * This function deallocates memory from the channel and various arrays
- * in the channel
- */
-static void __vxge_hw_channel_free(struct __vxge_hw_channel *channel)
-{
-       kfree(channel->work_arr);
-       kfree(channel->free_arr);
-       kfree(channel->reserve_arr);
-       kfree(channel->orig_arr);
-       kfree(channel);
-}
-
-/*
- * __vxge_hw_channel_initialize - Initialize a channel
- * This function initializes a channel by properly setting the
- * various references
- */
-static enum vxge_hw_status
-__vxge_hw_channel_initialize(struct __vxge_hw_channel *channel)
-{
-       u32 i;
-       struct __vxge_hw_virtualpath *vpath;
-
-       vpath = channel->vph->vpath;
-
-       if ((channel->reserve_arr != NULL) && (channel->orig_arr != NULL)) {
-               for (i = 0; i < channel->length; i++)
-                       channel->orig_arr[i] = channel->reserve_arr[i];
-       }
-
-       switch (channel->type) {
-       case VXGE_HW_CHANNEL_TYPE_FIFO:
-               vpath->fifoh = (struct __vxge_hw_fifo *)channel;
-               channel->stats = &((struct __vxge_hw_fifo *)
-                               channel)->stats->common_stats;
-               break;
-       case VXGE_HW_CHANNEL_TYPE_RING:
-               vpath->ringh = (struct __vxge_hw_ring *)channel;
-               channel->stats = &((struct __vxge_hw_ring *)
-                               channel)->stats->common_stats;
-               break;
-       default:
-               break;
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_channel_reset - Resets a channel
- * This function resets a channel by properly setting the various references
- */
-static enum vxge_hw_status
-__vxge_hw_channel_reset(struct __vxge_hw_channel *channel)
-{
-       u32 i;
-
-       for (i = 0; i < channel->length; i++) {
-               if (channel->reserve_arr != NULL)
-                       channel->reserve_arr[i] = channel->orig_arr[i];
-               if (channel->free_arr != NULL)
-                       channel->free_arr[i] = NULL;
-               if (channel->work_arr != NULL)
-                       channel->work_arr[i] = NULL;
-       }
-       channel->free_ptr = channel->length;
-       channel->reserve_ptr = channel->length;
-       channel->reserve_top = 0;
-       channel->post_index = 0;
-       channel->compl_index = 0;
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_pci_e_init
- * Initialize certain PCI/PCI-X configuration registers
- * with recommended values. Save config space for future hw resets.
- */
-static void __vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
-{
-       u16 cmd = 0;
-
-       /* Set the PErr Repconse bit and SERR in PCI command register. */
-       pci_read_config_word(hldev->pdev, PCI_COMMAND, &cmd);
-       cmd |= 0x140;
-       pci_write_config_word(hldev->pdev, PCI_COMMAND, cmd);
-
-       pci_save_state(hldev->pdev);
-}
-
-/* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset
- * in progress
- * This routine checks the vpath reset in progress register is turned zero
- */
-static enum vxge_hw_status
-__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
-{
-       enum vxge_hw_status status;
-       status = __vxge_hw_device_register_poll(vpath_rst_in_prog,
-                       VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(0x1ffff),
-                       VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-       return status;
-}
-
-/*
- * _hw_legacy_swapper_set - Set the swapper bits for the legacy secion.
- * Set the swapper bits appropriately for the lagacy section.
- */
-static enum vxge_hw_status
-__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       val64 = readq(&legacy_reg->toc_swapper_fb);
-
-       wmb();
-
-       switch (val64) {
-       case VXGE_HW_SWAPPER_INITIAL_VALUE:
-               return status;
-
-       case VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED:
-               writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
-                       &legacy_reg->pifm_rd_swap_en);
-               writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
-                       &legacy_reg->pifm_rd_flip_en);
-               writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
-                       &legacy_reg->pifm_wr_swap_en);
-               writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
-                       &legacy_reg->pifm_wr_flip_en);
-               break;
-
-       case VXGE_HW_SWAPPER_BYTE_SWAPPED:
-               writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE,
-                       &legacy_reg->pifm_rd_swap_en);
-               writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE,
-                       &legacy_reg->pifm_wr_swap_en);
-               break;
-
-       case VXGE_HW_SWAPPER_BIT_FLIPPED:
-               writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE,
-                       &legacy_reg->pifm_rd_flip_en);
-               writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE,
-                       &legacy_reg->pifm_wr_flip_en);
-               break;
-       }
-
-       wmb();
-
-       val64 = readq(&legacy_reg->toc_swapper_fb);
-
-       if (val64 != VXGE_HW_SWAPPER_INITIAL_VALUE)
-               status = VXGE_HW_ERR_SWAPPER_CTRL;
-
-       return status;
-}
-
-/*
- * __vxge_hw_device_toc_get
- * This routine sets the swapper and reads the toc pointer and returns the
- * memory mapped address of the toc
- */
-static struct vxge_hw_toc_reg __iomem *
-__vxge_hw_device_toc_get(void __iomem *bar0)
-{
-       u64 val64;
-       struct vxge_hw_toc_reg __iomem *toc = NULL;
-       enum vxge_hw_status status;
-
-       struct vxge_hw_legacy_reg __iomem *legacy_reg =
-               (struct vxge_hw_legacy_reg __iomem *)bar0;
-
-       status = __vxge_hw_legacy_swapper_set(legacy_reg);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       val64 = readq(&legacy_reg->toc_first_pointer);
-       toc = bar0 + val64;
-exit:
-       return toc;
-}
-
-/*
- * __vxge_hw_device_reg_addr_get
- * This routine sets the swapper and reads the toc pointer and initializes the
- * register location pointers in the device object. It waits until the ric is
- * completed initializing registers.
- */
-static enum vxge_hw_status
-__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
-{
-       u64 val64;
-       u32 i;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       hldev->legacy_reg = hldev->bar0;
-
-       hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0);
-       if (hldev->toc_reg  == NULL) {
-               status = VXGE_HW_FAIL;
-               goto exit;
-       }
-
-       val64 = readq(&hldev->toc_reg->toc_common_pointer);
-       hldev->common_reg = hldev->bar0 + val64;
-
-       val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer);
-       hldev->mrpcim_reg = hldev->bar0 + val64;
-
-       for (i = 0; i < VXGE_HW_TITAN_SRPCIM_REG_SPACES; i++) {
-               val64 = readq(&hldev->toc_reg->toc_srpcim_pointer[i]);
-               hldev->srpcim_reg[i] = hldev->bar0 + val64;
-       }
-
-       for (i = 0; i < VXGE_HW_TITAN_VPMGMT_REG_SPACES; i++) {
-               val64 = readq(&hldev->toc_reg->toc_vpmgmt_pointer[i]);
-               hldev->vpmgmt_reg[i] = hldev->bar0 + val64;
-       }
-
-       for (i = 0; i < VXGE_HW_TITAN_VPATH_REG_SPACES; i++) {
-               val64 = readq(&hldev->toc_reg->toc_vpath_pointer[i]);
-               hldev->vpath_reg[i] = hldev->bar0 + val64;
-       }
-
-       val64 = readq(&hldev->toc_reg->toc_kdfc);
-
-       switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val64)) {
-       case 0:
-               hldev->kdfc = hldev->bar0 + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64) ;
-               break;
-       default:
-               break;
-       }
-
-       status = __vxge_hw_device_vpath_reset_in_prog_check(
-                       (u64 __iomem *)&hldev->common_reg->vpath_rst_in_prog);
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_device_access_rights_get: Get Access Rights of the driver
- * This routine returns the Access Rights of the driver
- */
-static u32
-__vxge_hw_device_access_rights_get(u32 host_type, u32 func_id)
-{
-       u32 access_rights = VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH;
-
-       switch (host_type) {
-       case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION:
-               if (func_id == 0) {
-                       access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
-                                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
-               }
-               break;
-       case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION:
-               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
-                               VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
-               break;
-       case VXGE_HW_NO_MR_SR_VH0_FUNCTION0:
-               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
-                               VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
-               break;
-       case VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION:
-       case VXGE_HW_SR_VH_VIRTUAL_FUNCTION:
-       case VXGE_HW_MR_SR_VH0_INVALID_CONFIG:
-               break;
-       case VXGE_HW_SR_VH_FUNCTION0:
-       case VXGE_HW_VH_NORMAL_FUNCTION:
-               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
-               break;
-       }
-
-       return access_rights;
-}
-/*
- * __vxge_hw_device_is_privilaged
- * This routine checks if the device function is privilaged or not
- */
-
-enum vxge_hw_status
-__vxge_hw_device_is_privilaged(u32 host_type, u32 func_id)
-{
-       if (__vxge_hw_device_access_rights_get(host_type,
-               func_id) &
-               VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)
-               return VXGE_HW_OK;
-       else
-               return VXGE_HW_ERR_PRIVILEGED_OPERATION;
-}
-
-/*
- * __vxge_hw_vpath_func_id_get - Get the function id of the vpath.
- * Returns the function number of the vpath.
- */
-static u32
-__vxge_hw_vpath_func_id_get(struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg)
-{
-       u64 val64;
-
-       val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1);
-
-       return
-        (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64);
-}
-
-/*
- * __vxge_hw_device_host_info_get
- * This routine returns the host type assignments
- */
-static void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
-{
-       u64 val64;
-       u32 i;
-
-       val64 = readq(&hldev->common_reg->host_type_assignments);
-
-       hldev->host_type =
-          (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
-
-       hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments);
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!(hldev->vpath_assignments & vxge_mBIT(i)))
-                       continue;
-
-               hldev->func_id =
-                       __vxge_hw_vpath_func_id_get(hldev->vpmgmt_reg[i]);
-
-               hldev->access_rights = __vxge_hw_device_access_rights_get(
-                       hldev->host_type, hldev->func_id);
-
-               hldev->virtual_paths[i].vp_open = VXGE_HW_VP_NOT_OPEN;
-               hldev->virtual_paths[i].vp_reg = hldev->vpath_reg[i];
-
-               hldev->first_vp_id = i;
-               break;
-       }
-}
-
-/*
- * __vxge_hw_verify_pci_e_info - Validate the pci-e link parameters such as
- * link width and signalling rate.
- */
-static enum vxge_hw_status
-__vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev)
-{
-       struct pci_dev *dev = hldev->pdev;
-       u16 lnk;
-
-       /* Get the negotiated link width and speed from PCI config space */
-       pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnk);
-
-       if ((lnk & PCI_EXP_LNKSTA_CLS) != 1)
-               return VXGE_HW_ERR_INVALID_PCI_INFO;
-
-       switch ((lnk & PCI_EXP_LNKSTA_NLW) >> 4) {
-       case PCIE_LNK_WIDTH_RESRV:
-       case PCIE_LNK_X1:
-       case PCIE_LNK_X2:
-       case PCIE_LNK_X4:
-       case PCIE_LNK_X8:
-               break;
-       default:
-               return VXGE_HW_ERR_INVALID_PCI_INFO;
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_initialize
- * Initialize Titan-V hardware.
- */
-static enum vxge_hw_status
-__vxge_hw_device_initialize(struct __vxge_hw_device *hldev)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (VXGE_HW_OK == __vxge_hw_device_is_privilaged(hldev->host_type,
-                               hldev->func_id)) {
-               /* Validate the pci-e link width and speed */
-               status = __vxge_hw_verify_pci_e_info(hldev);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-       }
-
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_fw_ver_get - Get the fw version
- * Returns FW Version
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_fw_ver_get(struct __vxge_hw_virtualpath *vpath,
-                          struct vxge_hw_device_hw_info *hw_info)
-{
-       struct vxge_hw_device_version *fw_version = &hw_info->fw_version;
-       struct vxge_hw_device_date *fw_date = &hw_info->fw_date;
-       struct vxge_hw_device_version *flash_version = &hw_info->flash_version;
-       struct vxge_hw_device_date *flash_date = &hw_info->flash_date;
-       u64 data0 = 0, data1 = 0, steer_ctrl = 0;
-       enum vxge_hw_status status;
-
-       status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       fw_date->day =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(data0);
-       fw_date->month =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(data0);
-       fw_date->year =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(data0);
-
-       snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d",
-                fw_date->month, fw_date->day, fw_date->year);
-
-       fw_version->major =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data0);
-       fw_version->minor =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data0);
-       fw_version->build =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data0);
-
-       snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
-                fw_version->major, fw_version->minor, fw_version->build);
-
-       flash_date->day =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data1);
-       flash_date->month =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data1);
-       flash_date->year =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data1);
-
-       snprintf(flash_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d",
-                flash_date->month, flash_date->day, flash_date->year);
-
-       flash_version->major =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data1);
-       flash_version->minor =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data1);
-       flash_version->build =
-           (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data1);
-
-       snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d",
-                flash_version->major, flash_version->minor,
-                flash_version->build);
-
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_card_info_get - Get the serial numbers,
- * part number and product description.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_card_info_get(struct __vxge_hw_virtualpath *vpath,
-                             struct vxge_hw_device_hw_info *hw_info)
-{
-       __be64 *serial_number = (void *)hw_info->serial_number;
-       __be64 *product_desc = (void *)hw_info->product_desc;
-       __be64 *part_number = (void *)hw_info->part_number;
-       enum vxge_hw_status status;
-       u64 data0, data1 = 0, steer_ctrl = 0;
-       u32 i, j = 0;
-
-       data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER;
-
-       status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK)
-               return status;
-
-       serial_number[0] = cpu_to_be64(data0);
-       serial_number[1] = cpu_to_be64(data1);
-
-       data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER;
-       data1 = steer_ctrl = 0;
-
-       status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK)
-               return status;
-
-       part_number[0] = cpu_to_be64(data0);
-       part_number[1] = cpu_to_be64(data1);
-
-       for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0;
-            i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) {
-               data0 = i;
-               data1 = steer_ctrl = 0;
-
-               status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-               if (status != VXGE_HW_OK)
-                       return status;
-
-               product_desc[j++] = cpu_to_be64(data0);
-               product_desc[j++] = cpu_to_be64(data1);
-       }
-
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode
- * Returns pci function mode
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath,
-                                 struct vxge_hw_device_hw_info *hw_info)
-{
-       u64 data0, data1 = 0, steer_ctrl = 0;
-       enum vxge_hw_status status;
-
-       data0 = 0;
-
-       status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_FW_API_GET_FUNC_MODE,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-       if (status != VXGE_HW_OK)
-               return status;
-
-       hw_info->function_mode = VXGE_HW_GET_FUNC_MODE_VAL(data0);
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath
- *               from MAC address table.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_addr_get(struct __vxge_hw_virtualpath *vpath,
-                        u8 *macaddr, u8 *macaddr_mask)
-{
-       u64 action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY,
-           data0 = 0, data1 = 0, steer_ctrl = 0;
-       enum vxge_hw_status status;
-       int i;
-
-       do {
-               status = vxge_hw_vpath_fw_api(vpath, action,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
-                       0, &data0, &data1, &steer_ctrl);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data0);
-               data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(
-                                                                       data1);
-
-               for (i = ETH_ALEN; i > 0; i--) {
-                       macaddr[i - 1] = (u8) (data0 & 0xFF);
-                       data0 >>= 8;
-
-                       macaddr_mask[i - 1] = (u8) (data1 & 0xFF);
-                       data1 >>= 8;
-               }
-
-               action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY;
-               data0 = 0, data1 = 0, steer_ctrl = 0;
-
-       } while (!is_valid_ether_addr(macaddr));
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_device_hw_info_get - Get the hw information
- * @bar0: the bar
- * @hw_info: the hw_info struct
- *
- * Returns the vpath mask that has the bits set for each vpath allocated
- * for the driver, FW version information, and the first mac address for
- * each vpath
- */
-enum vxge_hw_status
-vxge_hw_device_hw_info_get(void __iomem *bar0,
-                          struct vxge_hw_device_hw_info *hw_info)
-{
-       u32 i;
-       u64 val64;
-       struct vxge_hw_toc_reg __iomem *toc;
-       struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg;
-       struct vxge_hw_common_reg __iomem *common_reg;
-       struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg;
-       enum vxge_hw_status status;
-       struct __vxge_hw_virtualpath vpath;
-
-       memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info));
-
-       toc = __vxge_hw_device_toc_get(bar0);
-       if (toc == NULL) {
-               status = VXGE_HW_ERR_CRITICAL;
-               goto exit;
-       }
-
-       val64 = readq(&toc->toc_common_pointer);
-       common_reg = bar0 + val64;
-
-       status = __vxge_hw_device_vpath_reset_in_prog_check(
-               (u64 __iomem *)&common_reg->vpath_rst_in_prog);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       hw_info->vpath_mask = readq(&common_reg->vpath_assignments);
-
-       val64 = readq(&common_reg->host_type_assignments);
-
-       hw_info->host_type =
-          (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
-                       continue;
-
-               val64 = readq(&toc->toc_vpmgmt_pointer[i]);
-
-               vpmgmt_reg = bar0 + val64;
-
-               hw_info->func_id = __vxge_hw_vpath_func_id_get(vpmgmt_reg);
-               if (__vxge_hw_device_access_rights_get(hw_info->host_type,
-                       hw_info->func_id) &
-                       VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) {
-
-                       val64 = readq(&toc->toc_mrpcim_pointer);
-
-                       mrpcim_reg = bar0 + val64;
-
-                       writeq(0, &mrpcim_reg->xgmac_gen_fw_memo_mask);
-                       wmb();
-               }
-
-               val64 = readq(&toc->toc_vpath_pointer[i]);
-
-               spin_lock_init(&vpath.lock);
-               vpath.vp_reg = bar0 + val64;
-               vpath.vp_open = VXGE_HW_VP_NOT_OPEN;
-
-               status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               status = __vxge_hw_vpath_fw_ver_get(&vpath, hw_info);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               status = __vxge_hw_vpath_card_info_get(&vpath, hw_info);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               break;
-       }
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
-                       continue;
-
-               val64 = readq(&toc->toc_vpath_pointer[i]);
-               vpath.vp_reg = bar0 + val64;
-               vpath.vp_open = VXGE_HW_VP_NOT_OPEN;
-
-               status =  __vxge_hw_vpath_addr_get(&vpath,
-                               hw_info->mac_addrs[i],
-                               hw_info->mac_addr_masks[i]);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-       }
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_blockpool_destroy - Deallocates the block pool
- */
-static void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool)
-{
-       struct __vxge_hw_device *hldev;
-       struct list_head *p, *n;
-
-       if (!blockpool)
-               return;
-
-       hldev = blockpool->hldev;
-
-       list_for_each_safe(p, n, &blockpool->free_block_list) {
-               dma_unmap_single(&hldev->pdev->dev,
-                                ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
-                                ((struct __vxge_hw_blockpool_entry *)p)->length,
-                                DMA_BIDIRECTIONAL);
-
-               vxge_os_dma_free(hldev->pdev,
-                       ((struct __vxge_hw_blockpool_entry *)p)->memblock,
-                       &((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
-
-               list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
-               kfree(p);
-               blockpool->pool_size--;
-       }
-
-       list_for_each_safe(p, n, &blockpool->free_entry_list) {
-               list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
-               kfree(p);
-       }
-
-       return;
-}
-
-/*
- * __vxge_hw_blockpool_create - Create block pool
- */
-static enum vxge_hw_status
-__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev,
-                          struct __vxge_hw_blockpool *blockpool,
-                          u32 pool_size,
-                          u32 pool_max)
-{
-       u32 i;
-       struct __vxge_hw_blockpool_entry *entry = NULL;
-       void *memblock;
-       dma_addr_t dma_addr;
-       struct pci_dev *dma_handle;
-       struct pci_dev *acc_handle;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (blockpool == NULL) {
-               status = VXGE_HW_FAIL;
-               goto blockpool_create_exit;
-       }
-
-       blockpool->hldev = hldev;
-       blockpool->block_size = VXGE_HW_BLOCK_SIZE;
-       blockpool->pool_size = 0;
-       blockpool->pool_max = pool_max;
-       blockpool->req_out = 0;
-
-       INIT_LIST_HEAD(&blockpool->free_block_list);
-       INIT_LIST_HEAD(&blockpool->free_entry_list);
-
-       for (i = 0; i < pool_size + pool_max; i++) {
-               entry = kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
-                               GFP_KERNEL);
-               if (entry == NULL) {
-                       __vxge_hw_blockpool_destroy(blockpool);
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-                       goto blockpool_create_exit;
-               }
-               list_add(&entry->item, &blockpool->free_entry_list);
-       }
-
-       for (i = 0; i < pool_size; i++) {
-               memblock = vxge_os_dma_malloc(
-                               hldev->pdev,
-                               VXGE_HW_BLOCK_SIZE,
-                               &dma_handle,
-                               &acc_handle);
-               if (memblock == NULL) {
-                       __vxge_hw_blockpool_destroy(blockpool);
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-                       goto blockpool_create_exit;
-               }
-
-               dma_addr = dma_map_single(&hldev->pdev->dev, memblock,
-                                         VXGE_HW_BLOCK_SIZE,
-                                         DMA_BIDIRECTIONAL);
-               if (unlikely(dma_mapping_error(&hldev->pdev->dev, dma_addr))) {
-                       vxge_os_dma_free(hldev->pdev, memblock, &acc_handle);
-                       __vxge_hw_blockpool_destroy(blockpool);
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-                       goto blockpool_create_exit;
-               }
-
-               if (!list_empty(&blockpool->free_entry_list))
-                       entry = (struct __vxge_hw_blockpool_entry *)
-                               list_first_entry(&blockpool->free_entry_list,
-                                       struct __vxge_hw_blockpool_entry,
-                                       item);
-
-               if (entry == NULL)
-                       entry =
-                           kzalloc(sizeof(struct __vxge_hw_blockpool_entry),
-                                       GFP_KERNEL);
-               if (entry != NULL) {
-                       list_del(&entry->item);
-                       entry->length = VXGE_HW_BLOCK_SIZE;
-                       entry->memblock = memblock;
-                       entry->dma_addr = dma_addr;
-                       entry->acc_handle = acc_handle;
-                       entry->dma_handle = dma_handle;
-                       list_add(&entry->item,
-                                         &blockpool->free_block_list);
-                       blockpool->pool_size++;
-               } else {
-                       __vxge_hw_blockpool_destroy(blockpool);
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-                       goto blockpool_create_exit;
-               }
-       }
-
-blockpool_create_exit:
-       return status;
-}
-
-/*
- * __vxge_hw_device_fifo_config_check - Check fifo configuration.
- * Check the fifo configuration
- */
-static enum vxge_hw_status
-__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config)
-{
-       if ((fifo_config->fifo_blocks < VXGE_HW_MIN_FIFO_BLOCKS) ||
-           (fifo_config->fifo_blocks > VXGE_HW_MAX_FIFO_BLOCKS))
-               return VXGE_HW_BADCFG_FIFO_BLOCKS;
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_vpath_config_check - Check vpath configuration.
- * Check the vpath configuration
- */
-static enum vxge_hw_status
-__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config)
-{
-       enum vxge_hw_status status;
-
-       if ((vp_config->min_bandwidth < VXGE_HW_VPATH_BANDWIDTH_MIN) ||
-           (vp_config->min_bandwidth > VXGE_HW_VPATH_BANDWIDTH_MAX))
-               return VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH;
-
-       status = __vxge_hw_device_fifo_config_check(&vp_config->fifo);
-       if (status != VXGE_HW_OK)
-               return status;
-
-       if ((vp_config->mtu != VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) &&
-               ((vp_config->mtu < VXGE_HW_VPATH_MIN_INITIAL_MTU) ||
-               (vp_config->mtu > VXGE_HW_VPATH_MAX_INITIAL_MTU)))
-               return VXGE_HW_BADCFG_VPATH_MTU;
-
-       if ((vp_config->rpa_strip_vlan_tag !=
-               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) &&
-               (vp_config->rpa_strip_vlan_tag !=
-               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE) &&
-               (vp_config->rpa_strip_vlan_tag !=
-               VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE))
-               return VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG;
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_config_check - Check device configuration.
- * Check the device configuration
- */
-static enum vxge_hw_status
-__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config)
-{
-       u32 i;
-       enum vxge_hw_status status;
-
-       if ((new_config->intr_mode != VXGE_HW_INTR_MODE_IRQLINE) &&
-           (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX) &&
-           (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) &&
-           (new_config->intr_mode != VXGE_HW_INTR_MODE_DEF))
-               return VXGE_HW_BADCFG_INTR_MODE;
-
-       if ((new_config->rts_mac_en != VXGE_HW_RTS_MAC_DISABLE) &&
-           (new_config->rts_mac_en != VXGE_HW_RTS_MAC_ENABLE))
-               return VXGE_HW_BADCFG_RTS_MAC_EN;
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               status = __vxge_hw_device_vpath_config_check(
-                               &new_config->vp_config[i]);
-               if (status != VXGE_HW_OK)
-                       return status;
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * vxge_hw_device_initialize - Initialize Titan device.
- * Initialize Titan device. Note that all the arguments of this public API
- * are 'IN', including @hldev. Driver cooperates with
- * OS to find new Titan device, locate its PCI and memory spaces.
- *
- * When done, the driver allocates sizeof(struct __vxge_hw_device) bytes for HW
- * to enable the latter to perform Titan hardware initialization.
- */
-enum vxge_hw_status
-vxge_hw_device_initialize(
-       struct __vxge_hw_device **devh,
-       struct vxge_hw_device_attr *attr,
-       struct vxge_hw_device_config *device_config)
-{
-       u32 i;
-       u32 nblocks = 0;
-       struct __vxge_hw_device *hldev = NULL;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       status = __vxge_hw_device_config_check(device_config);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       hldev = vzalloc(sizeof(struct __vxge_hw_device));
-       if (hldev == NULL) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       hldev->magic = VXGE_HW_DEVICE_MAGIC;
-
-       vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_ALL);
-
-       /* apply config */
-       memcpy(&hldev->config, device_config,
-               sizeof(struct vxge_hw_device_config));
-
-       hldev->bar0 = attr->bar0;
-       hldev->pdev = attr->pdev;
-
-       hldev->uld_callbacks = attr->uld_callbacks;
-
-       __vxge_hw_device_pci_e_init(hldev);
-
-       status = __vxge_hw_device_reg_addr_get(hldev);
-       if (status != VXGE_HW_OK) {
-               vfree(hldev);
-               goto exit;
-       }
-
-       __vxge_hw_device_host_info_get(hldev);
-
-       /* Incrementing for stats blocks */
-       nblocks++;
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!(hldev->vpath_assignments & vxge_mBIT(i)))
-                       continue;
-
-               if (device_config->vp_config[i].ring.enable ==
-                       VXGE_HW_RING_ENABLE)
-                       nblocks += device_config->vp_config[i].ring.ring_blocks;
-
-               if (device_config->vp_config[i].fifo.enable ==
-                       VXGE_HW_FIFO_ENABLE)
-                       nblocks += device_config->vp_config[i].fifo.fifo_blocks;
-               nblocks++;
-       }
-
-       if (__vxge_hw_blockpool_create(hldev,
-               &hldev->block_pool,
-               device_config->dma_blockpool_initial + nblocks,
-               device_config->dma_blockpool_max + nblocks) != VXGE_HW_OK) {
-
-               vxge_hw_device_terminate(hldev);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       status = __vxge_hw_device_initialize(hldev);
-       if (status != VXGE_HW_OK) {
-               vxge_hw_device_terminate(hldev);
-               goto exit;
-       }
-
-       *devh = hldev;
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_terminate - Terminate Titan device.
- * Terminate HW device.
- */
-void
-vxge_hw_device_terminate(struct __vxge_hw_device *hldev)
-{
-       vxge_assert(hldev->magic == VXGE_HW_DEVICE_MAGIC);
-
-       hldev->magic = VXGE_HW_DEVICE_DEAD;
-       __vxge_hw_blockpool_destroy(&hldev->block_pool);
-       vfree(hldev);
-}
-
-/*
- * __vxge_hw_vpath_stats_access - Get the statistics from the given location
- *                           and offset and perform an operation
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath,
-                            u32 operation, u32 offset, u64 *stat)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto vpath_stats_access_exit;
-       }
-
-       vp_reg = vpath->vp_reg;
-
-       val64 =  VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(operation) |
-                VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE |
-                VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(offset);
-
-       status = __vxge_hw_pio_mem_write64(val64,
-                               &vp_reg->xmac_stats_access_cmd,
-                               VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE,
-                               vpath->hldev->config.device_poll_millis);
-       if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
-               *stat = readq(&vp_reg->xmac_stats_access_data);
-       else
-               *stat = 0;
-
-vpath_stats_access_exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_xmac_tx_stats_get - Get the TX Statistics of a vpath
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_xmac_tx_stats_get(struct __vxge_hw_virtualpath *vpath,
-                       struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats)
-{
-       u64 *val64;
-       int i;
-       u32 offset = VXGE_HW_STATS_VPATH_TX_OFFSET;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       val64 = (u64 *)vpath_tx_stats;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-
-       for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_tx_stats) / 8; i++) {
-               status = __vxge_hw_vpath_stats_access(vpath,
-                                       VXGE_HW_STATS_OP_READ,
-                                       offset, val64);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-               offset++;
-               val64++;
-       }
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_xmac_rx_stats_get - Get the RX Statistics of a vpath
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath,
-                       struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats)
-{
-       u64 *val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       int i;
-       u32 offset = VXGE_HW_STATS_VPATH_RX_OFFSET;
-       val64 = (u64 *) vpath_rx_stats;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-       for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_rx_stats) / 8; i++) {
-               status = __vxge_hw_vpath_stats_access(vpath,
-                                       VXGE_HW_STATS_OP_READ,
-                                       offset >> 3, val64);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               offset += 8;
-               val64++;
-       }
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_stats_get - Get the vpath hw statistics.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_stats_get(struct __vxge_hw_virtualpath *vpath,
-                         struct vxge_hw_vpath_stats_hw_info *hw_stats)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-       vp_reg = vpath->vp_reg;
-
-       val64 = readq(&vp_reg->vpath_debug_stats0);
-       hw_stats->ini_num_mwr_sent =
-               (u32)VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(val64);
-
-       val64 = readq(&vp_reg->vpath_debug_stats1);
-       hw_stats->ini_num_mrd_sent =
-               (u32)VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(val64);
-
-       val64 = readq(&vp_reg->vpath_debug_stats2);
-       hw_stats->ini_num_cpl_rcvd =
-               (u32)VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(val64);
-
-       val64 = readq(&vp_reg->vpath_debug_stats3);
-       hw_stats->ini_num_mwr_byte_sent =
-               VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(val64);
-
-       val64 = readq(&vp_reg->vpath_debug_stats4);
-       hw_stats->ini_num_cpl_byte_rcvd =
-               VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(val64);
-
-       val64 = readq(&vp_reg->vpath_debug_stats5);
-       hw_stats->wrcrdtarb_xoff =
-               (u32)VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(val64);
-
-       val64 = readq(&vp_reg->vpath_debug_stats6);
-       hw_stats->rdcrdtarb_xoff =
-               (u32)VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(val64);
-
-       val64 = readq(&vp_reg->vpath_genstats_count01);
-       hw_stats->vpath_genstats_count0 =
-       (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(
-               val64);
-
-       val64 = readq(&vp_reg->vpath_genstats_count01);
-       hw_stats->vpath_genstats_count1 =
-       (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(
-               val64);
-
-       val64 = readq(&vp_reg->vpath_genstats_count23);
-       hw_stats->vpath_genstats_count2 =
-       (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(
-               val64);
-
-       val64 = readq(&vp_reg->vpath_genstats_count01);
-       hw_stats->vpath_genstats_count3 =
-       (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(
-               val64);
-
-       val64 = readq(&vp_reg->vpath_genstats_count4);
-       hw_stats->vpath_genstats_count4 =
-       (u32)VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(
-               val64);
-
-       val64 = readq(&vp_reg->vpath_genstats_count5);
-       hw_stats->vpath_genstats_count5 =
-       (u32)VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(
-               val64);
-
-       status = __vxge_hw_vpath_xmac_tx_stats_get(vpath, &hw_stats->tx_stats);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status = __vxge_hw_vpath_xmac_rx_stats_get(vpath, &hw_stats->rx_stats);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       VXGE_HW_VPATH_STATS_PIO_READ(
-               VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET);
-
-       hw_stats->prog_event_vnum0 =
-                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(val64);
-
-       hw_stats->prog_event_vnum1 =
-                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(val64);
-
-       VXGE_HW_VPATH_STATS_PIO_READ(
-               VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET);
-
-       hw_stats->prog_event_vnum2 =
-                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(val64);
-
-       hw_stats->prog_event_vnum3 =
-                       (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(val64);
-
-       val64 = readq(&vp_reg->rx_multi_cast_stats);
-       hw_stats->rx_multi_cast_frame_discard =
-               (u16)VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(val64);
-
-       val64 = readq(&vp_reg->rx_frm_transferred);
-       hw_stats->rx_frm_transferred =
-               (u32)VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(val64);
-
-       val64 = readq(&vp_reg->rxd_returned);
-       hw_stats->rxd_returned =
-               (u16)VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(val64);
-
-       val64 = readq(&vp_reg->dbg_stats_rx_mpa);
-       hw_stats->rx_mpa_len_fail_frms =
-               (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(val64);
-       hw_stats->rx_mpa_mrk_fail_frms =
-               (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(val64);
-       hw_stats->rx_mpa_crc_fail_frms =
-               (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(val64);
-
-       val64 = readq(&vp_reg->dbg_stats_rx_fau);
-       hw_stats->rx_permitted_frms =
-               (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(val64);
-       hw_stats->rx_vp_reset_discarded_frms =
-       (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val64);
-       hw_stats->rx_wol_frms =
-               (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(val64);
-
-       val64 = readq(&vp_reg->tx_vp_reset_discarded_frms);
-       hw_stats->tx_vp_reset_discarded_frms =
-       (u16)VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(
-               val64);
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_stats_get - Get the device hw statistics.
- * Returns the vpath h/w stats for the device.
- */
-enum vxge_hw_status
-vxge_hw_device_stats_get(struct __vxge_hw_device *hldev,
-                       struct vxge_hw_device_stats_hw_info *hw_stats)
-{
-       u32 i;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!(hldev->vpaths_deployed & vxge_mBIT(i)) ||
-                       (hldev->virtual_paths[i].vp_open ==
-                               VXGE_HW_VP_NOT_OPEN))
-                       continue;
-
-               memcpy(hldev->virtual_paths[i].hw_stats_sav,
-                               hldev->virtual_paths[i].hw_stats,
-                               sizeof(struct vxge_hw_vpath_stats_hw_info));
-
-               status = __vxge_hw_vpath_stats_get(
-                       &hldev->virtual_paths[i],
-                       hldev->virtual_paths[i].hw_stats);
-       }
-
-       memcpy(hw_stats, &hldev->stats.hw_dev_info_stats,
-                       sizeof(struct vxge_hw_device_stats_hw_info));
-
-       return status;
-}
-
-/*
- * vxge_hw_driver_stats_get - Get the device sw statistics.
- * Returns the vpath s/w stats for the device.
- */
-enum vxge_hw_status vxge_hw_driver_stats_get(
-                       struct __vxge_hw_device *hldev,
-                       struct vxge_hw_device_stats_sw_info *sw_stats)
-{
-       memcpy(sw_stats, &hldev->stats.sw_dev_info_stats,
-               sizeof(struct vxge_hw_device_stats_sw_info));
-
-       return VXGE_HW_OK;
-}
-
-/*
- * vxge_hw_mrpcim_stats_access - Access the statistics from the given location
- *                           and offset and perform an operation
- * Get the statistics from the given location and offset.
- */
-enum vxge_hw_status
-vxge_hw_mrpcim_stats_access(struct __vxge_hw_device *hldev,
-                           u32 operation, u32 location, u32 offset, u64 *stat)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       status = __vxge_hw_device_is_privilaged(hldev->host_type,
-                       hldev->func_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       val64 = VXGE_HW_XMAC_STATS_SYS_CMD_OP(operation) |
-               VXGE_HW_XMAC_STATS_SYS_CMD_STROBE |
-               VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(location) |
-               VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(offset);
-
-       status = __vxge_hw_pio_mem_write64(val64,
-                               &hldev->mrpcim_reg->xmac_stats_sys_cmd,
-                               VXGE_HW_XMAC_STATS_SYS_CMD_STROBE,
-                               hldev->config.device_poll_millis);
-
-       if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
-               *stat = readq(&hldev->mrpcim_reg->xmac_stats_sys_data);
-       else
-               *stat = 0;
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_xmac_aggr_stats_get - Get the Statistics on aggregate port
- * Get the Statistics on aggregate port
- */
-static enum vxge_hw_status
-vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *hldev, u32 port,
-                                  struct vxge_hw_xmac_aggr_stats *aggr_stats)
-{
-       u64 *val64;
-       int i;
-       u32 offset = VXGE_HW_STATS_AGGRn_OFFSET;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       val64 = (u64 *)aggr_stats;
-
-       status = __vxge_hw_device_is_privilaged(hldev->host_type,
-                       hldev->func_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       for (i = 0; i < sizeof(struct vxge_hw_xmac_aggr_stats) / 8; i++) {
-               status = vxge_hw_mrpcim_stats_access(hldev,
-                                       VXGE_HW_STATS_OP_READ,
-                                       VXGE_HW_STATS_LOC_AGGR,
-                                       ((offset + (104 * port)) >> 3), val64);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               offset += 8;
-               val64++;
-       }
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port
- * Get the Statistics on port
- */
-static enum vxge_hw_status
-vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *hldev, u32 port,
-                                  struct vxge_hw_xmac_port_stats *port_stats)
-{
-       u64 *val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       int i;
-       u32 offset = 0x0;
-       val64 = (u64 *) port_stats;
-
-       status = __vxge_hw_device_is_privilaged(hldev->host_type,
-                       hldev->func_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       for (i = 0; i < sizeof(struct vxge_hw_xmac_port_stats) / 8; i++) {
-               status = vxge_hw_mrpcim_stats_access(hldev,
-                                       VXGE_HW_STATS_OP_READ,
-                                       VXGE_HW_STATS_LOC_AGGR,
-                                       ((offset + (608 * port)) >> 3), val64);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               offset += 8;
-               val64++;
-       }
-
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_xmac_stats_get - Get the XMAC Statistics
- * Get the XMAC Statistics
- */
-enum vxge_hw_status
-vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *hldev,
-                             struct vxge_hw_xmac_stats *xmac_stats)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       u32 i;
-
-       status = vxge_hw_device_xmac_aggr_stats_get(hldev,
-                                       0, &xmac_stats->aggr_stats[0]);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status = vxge_hw_device_xmac_aggr_stats_get(hldev,
-                               1, &xmac_stats->aggr_stats[1]);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       for (i = 0; i <= VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) {
-
-               status = vxge_hw_device_xmac_port_stats_get(hldev,
-                                       i, &xmac_stats->port_stats[i]);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-       }
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
-               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
-                       continue;
-
-               status = __vxge_hw_vpath_xmac_tx_stats_get(
-                                       &hldev->virtual_paths[i],
-                                       &xmac_stats->vpath_tx_stats[i]);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-
-               status = __vxge_hw_vpath_xmac_rx_stats_get(
-                                       &hldev->virtual_paths[i],
-                                       &xmac_stats->vpath_rx_stats[i]);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-       }
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_debug_set - Set the debug module, level and timestamp
- * This routine is used to dynamically change the debug output
- */
-void vxge_hw_device_debug_set(struct __vxge_hw_device *hldev,
-                             enum vxge_debug_level level, u32 mask)
-{
-       if (hldev == NULL)
-               return;
-
-#if defined(VXGE_DEBUG_TRACE_MASK) || \
-       defined(VXGE_DEBUG_ERR_MASK)
-       hldev->debug_module_mask = mask;
-       hldev->debug_level = level;
-#endif
-
-#if defined(VXGE_DEBUG_ERR_MASK)
-       hldev->level_err = level & VXGE_ERR;
-#endif
-
-#if defined(VXGE_DEBUG_TRACE_MASK)
-       hldev->level_trace = level & VXGE_TRACE;
-#endif
-}
-
-/*
- * vxge_hw_device_error_level_get - Get the error level
- * This routine returns the current error level set
- */
-u32 vxge_hw_device_error_level_get(struct __vxge_hw_device *hldev)
-{
-#if defined(VXGE_DEBUG_ERR_MASK)
-       if (hldev == NULL)
-               return VXGE_ERR;
-       else
-               return hldev->level_err;
-#else
-       return 0;
-#endif
-}
-
-/*
- * vxge_hw_device_trace_level_get - Get the trace level
- * This routine returns the current trace level set
- */
-u32 vxge_hw_device_trace_level_get(struct __vxge_hw_device *hldev)
-{
-#if defined(VXGE_DEBUG_TRACE_MASK)
-       if (hldev == NULL)
-               return VXGE_TRACE;
-       else
-               return hldev->level_trace;
-#else
-       return 0;
-#endif
-}
-
-/*
- * vxge_hw_getpause_data -Pause frame frame generation and reception.
- * Returns the Pause frame generation and reception capability of the NIC.
- */
-enum vxge_hw_status vxge_hw_device_getpause_data(struct __vxge_hw_device *hldev,
-                                                u32 port, u32 *tx, u32 *rx)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
-               status = VXGE_HW_ERR_INVALID_DEVICE;
-               goto exit;
-       }
-
-       if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) {
-               status = VXGE_HW_ERR_INVALID_PORT;
-               goto exit;
-       }
-
-       if (!(hldev->access_rights & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
-               status = VXGE_HW_ERR_PRIVILEGED_OPERATION;
-               goto exit;
-       }
-
-       val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
-       if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN)
-               *tx = 1;
-       if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN)
-               *rx = 1;
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_setpause_data -  set/reset pause frame generation.
- * It can be used to set or reset Pause frame generation or reception
- * support of the NIC.
- */
-enum vxge_hw_status vxge_hw_device_setpause_data(struct __vxge_hw_device *hldev,
-                                                u32 port, u32 tx, u32 rx)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
-               status = VXGE_HW_ERR_INVALID_DEVICE;
-               goto exit;
-       }
-
-       if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) {
-               status = VXGE_HW_ERR_INVALID_PORT;
-               goto exit;
-       }
-
-       status = __vxge_hw_device_is_privilaged(hldev->host_type,
-                       hldev->func_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
-       if (tx)
-               val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN;
-       else
-               val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN;
-       if (rx)
-               val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN;
-       else
-               val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN;
-
-       writeq(val64, &hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
-exit:
-       return status;
-}
-
-u16 vxge_hw_device_link_width_get(struct __vxge_hw_device *hldev)
-{
-       struct pci_dev *dev = hldev->pdev;
-       u16 lnk;
-
-       pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnk);
-       return (lnk & VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH) >> 4;
-}
-
-/*
- * __vxge_hw_ring_block_memblock_idx - Return the memblock index
- * This function returns the index of memory block
- */
-static inline u32
-__vxge_hw_ring_block_memblock_idx(u8 *block)
-{
-       return (u32)*((u64 *)(block + VXGE_HW_RING_MEMBLOCK_IDX_OFFSET));
-}
-
-/*
- * __vxge_hw_ring_block_memblock_idx_set - Sets the memblock index
- * This function sets index to a memory block
- */
-static inline void
-__vxge_hw_ring_block_memblock_idx_set(u8 *block, u32 memblock_idx)
-{
-       *((u64 *)(block + VXGE_HW_RING_MEMBLOCK_IDX_OFFSET)) = memblock_idx;
-}
-
-/*
- * __vxge_hw_ring_block_next_pointer_set - Sets the next block pointer
- * in RxD block
- * Sets the next block pointer in RxD block
- */
-static inline void
-__vxge_hw_ring_block_next_pointer_set(u8 *block, dma_addr_t dma_next)
-{
-       *((u64 *)(block + VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET)) = dma_next;
-}
-
-/*
- * __vxge_hw_ring_first_block_address_get - Returns the dma address of the
- *             first block
- * Returns the dma address of the first RxD block
- */
-static u64 __vxge_hw_ring_first_block_address_get(struct __vxge_hw_ring *ring)
-{
-       struct vxge_hw_mempool_dma *dma_object;
-
-       dma_object = ring->mempool->memblocks_dma_arr;
-       vxge_assert(dma_object != NULL);
-
-       return dma_object->addr;
-}
-
-/*
- * __vxge_hw_ring_item_dma_addr - Return the dma address of an item
- * This function returns the dma address of a given item
- */
-static dma_addr_t __vxge_hw_ring_item_dma_addr(struct vxge_hw_mempool *mempoolh,
-                                              void *item)
-{
-       u32 memblock_idx;
-       void *memblock;
-       struct vxge_hw_mempool_dma *memblock_dma_object;
-       ptrdiff_t dma_item_offset;
-
-       /* get owner memblock index */
-       memblock_idx = __vxge_hw_ring_block_memblock_idx(item);
-
-       /* get owner memblock by memblock index */
-       memblock = mempoolh->memblocks_arr[memblock_idx];
-
-       /* get memblock DMA object by memblock index */
-       memblock_dma_object = mempoolh->memblocks_dma_arr + memblock_idx;
-
-       /* calculate offset in the memblock of this item */
-       dma_item_offset = (u8 *)item - (u8 *)memblock;
-
-       return memblock_dma_object->addr + dma_item_offset;
-}
-
-/*
- * __vxge_hw_ring_rxdblock_link - Link the RxD blocks
- * This function returns the dma address of a given item
- */
-static void __vxge_hw_ring_rxdblock_link(struct vxge_hw_mempool *mempoolh,
-                                        struct __vxge_hw_ring *ring, u32 from,
-                                        u32 to)
-{
-       u8 *to_item , *from_item;
-       dma_addr_t to_dma;
-
-       /* get "from" RxD block */
-       from_item = mempoolh->items_arr[from];
-       vxge_assert(from_item);
-
-       /* get "to" RxD block */
-       to_item = mempoolh->items_arr[to];
-       vxge_assert(to_item);
-
-       /* return address of the beginning of previous RxD block */
-       to_dma = __vxge_hw_ring_item_dma_addr(mempoolh, to_item);
-
-       /* set next pointer for this RxD block to point on
-        * previous item's DMA start address */
-       __vxge_hw_ring_block_next_pointer_set(from_item, to_dma);
-}
-
-/*
- * __vxge_hw_ring_mempool_item_alloc - Allocate List blocks for RxD
- * block callback
- * This function is callback passed to __vxge_hw_mempool_create to create memory
- * pool for RxD block
- */
-static void
-__vxge_hw_ring_mempool_item_alloc(struct vxge_hw_mempool *mempoolh,
-                                 u32 memblock_index,
-                                 struct vxge_hw_mempool_dma *dma_object,
-                                 u32 index, u32 is_last)
-{
-       u32 i;
-       void *item = mempoolh->items_arr[index];
-       struct __vxge_hw_ring *ring =
-               (struct __vxge_hw_ring *)mempoolh->userdata;
-
-       /* format rxds array */
-       for (i = 0; i < ring->rxds_per_block; i++) {
-               void *rxdblock_priv;
-               void *uld_priv;
-               struct vxge_hw_ring_rxd_1 *rxdp;
-
-               u32 reserve_index = ring->channel.reserve_ptr -
-                               (index * ring->rxds_per_block + i + 1);
-               u32 memblock_item_idx;
-
-               ring->channel.reserve_arr[reserve_index] = ((u8 *)item) +
-                                               i * ring->rxd_size;
-
-               /* Note: memblock_item_idx is index of the item within
-                *       the memblock. For instance, in case of three RxD-blocks
-                *       per memblock this value can be 0, 1 or 2. */
-               rxdblock_priv = __vxge_hw_mempool_item_priv(mempoolh,
-                                       memblock_index, item,
-                                       &memblock_item_idx);
-
-               rxdp = ring->channel.reserve_arr[reserve_index];
-
-               uld_priv = ((u8 *)rxdblock_priv + ring->rxd_priv_size * i);
-
-               /* pre-format Host_Control */
-               rxdp->host_control = (u64)(size_t)uld_priv;
-       }
-
-       __vxge_hw_ring_block_memblock_idx_set(item, memblock_index);
-
-       if (is_last) {
-               /* link last one with first one */
-               __vxge_hw_ring_rxdblock_link(mempoolh, ring, index, 0);
-       }
-
-       if (index > 0) {
-               /* link this RxD block with previous one */
-               __vxge_hw_ring_rxdblock_link(mempoolh, ring, index - 1, index);
-       }
-}
-
-/*
- * __vxge_hw_ring_replenish - Initial replenish of RxDs
- * This function replenishes the RxDs from reserve array to work array
- */
-static enum vxge_hw_status
-vxge_hw_ring_replenish(struct __vxge_hw_ring *ring)
-{
-       void *rxd;
-       struct __vxge_hw_channel *channel;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       channel = &ring->channel;
-
-       while (vxge_hw_channel_dtr_count(channel) > 0) {
-
-               status = vxge_hw_ring_rxd_reserve(ring, &rxd);
-
-               vxge_assert(status == VXGE_HW_OK);
-
-               if (ring->rxd_init) {
-                       status = ring->rxd_init(rxd, channel->userdata);
-                       if (status != VXGE_HW_OK) {
-                               vxge_hw_ring_rxd_free(ring, rxd);
-                               goto exit;
-                       }
-               }
-
-               vxge_hw_ring_rxd_post(ring, rxd);
-       }
-       status = VXGE_HW_OK;
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_channel_allocate - Allocate memory for channel
- * This function allocates required memory for the channel and various arrays
- * in the channel
- */
-static struct __vxge_hw_channel *
-__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph,
-                          enum __vxge_hw_channel_type type,
-                          u32 length, u32 per_dtr_space,
-                          void *userdata)
-{
-       struct __vxge_hw_channel *channel;
-       struct __vxge_hw_device *hldev;
-       int size = 0;
-       u32 vp_id;
-
-       hldev = vph->vpath->hldev;
-       vp_id = vph->vpath->vp_id;
-
-       switch (type) {
-       case VXGE_HW_CHANNEL_TYPE_FIFO:
-               size = sizeof(struct __vxge_hw_fifo);
-               break;
-       case VXGE_HW_CHANNEL_TYPE_RING:
-               size = sizeof(struct __vxge_hw_ring);
-               break;
-       default:
-               break;
-       }
-
-       channel = kzalloc(size, GFP_KERNEL);
-       if (channel == NULL)
-               goto exit0;
-       INIT_LIST_HEAD(&channel->item);
-
-       channel->common_reg = hldev->common_reg;
-       channel->first_vp_id = hldev->first_vp_id;
-       channel->type = type;
-       channel->devh = hldev;
-       channel->vph = vph;
-       channel->userdata = userdata;
-       channel->per_dtr_space = per_dtr_space;
-       channel->length = length;
-       channel->vp_id = vp_id;
-
-       channel->work_arr = kcalloc(length, sizeof(void *), GFP_KERNEL);
-       if (channel->work_arr == NULL)
-               goto exit1;
-
-       channel->free_arr = kcalloc(length, sizeof(void *), GFP_KERNEL);
-       if (channel->free_arr == NULL)
-               goto exit1;
-       channel->free_ptr = length;
-
-       channel->reserve_arr = kcalloc(length, sizeof(void *), GFP_KERNEL);
-       if (channel->reserve_arr == NULL)
-               goto exit1;
-       channel->reserve_ptr = length;
-       channel->reserve_top = 0;
-
-       channel->orig_arr = kcalloc(length, sizeof(void *), GFP_KERNEL);
-       if (channel->orig_arr == NULL)
-               goto exit1;
-
-       return channel;
-exit1:
-       __vxge_hw_channel_free(channel);
-
-exit0:
-       return NULL;
-}
-
-/*
- * vxge_hw_blockpool_block_add - callback for vxge_os_dma_malloc_async
- * Adds a block to block pool
- */
-static void vxge_hw_blockpool_block_add(struct __vxge_hw_device *devh,
-                                       void *block_addr,
-                                       u32 length,
-                                       struct pci_dev *dma_h,
-                                       struct pci_dev *acc_handle)
-{
-       struct __vxge_hw_blockpool *blockpool;
-       struct __vxge_hw_blockpool_entry *entry = NULL;
-       dma_addr_t dma_addr;
-
-       blockpool = &devh->block_pool;
-
-       if (block_addr == NULL) {
-               blockpool->req_out--;
-               goto exit;
-       }
-
-       dma_addr = dma_map_single(&devh->pdev->dev, block_addr, length,
-                                 DMA_BIDIRECTIONAL);
-
-       if (unlikely(dma_mapping_error(&devh->pdev->dev, dma_addr))) {
-               vxge_os_dma_free(devh->pdev, block_addr, &acc_handle);
-               blockpool->req_out--;
-               goto exit;
-       }
-
-       if (!list_empty(&blockpool->free_entry_list))
-               entry = (struct __vxge_hw_blockpool_entry *)
-                       list_first_entry(&blockpool->free_entry_list,
-                               struct __vxge_hw_blockpool_entry,
-                               item);
-
-       if (entry == NULL)
-               entry = vmalloc(sizeof(struct __vxge_hw_blockpool_entry));
-       else
-               list_del(&entry->item);
-
-       if (entry) {
-               entry->length = length;
-               entry->memblock = block_addr;
-               entry->dma_addr = dma_addr;
-               entry->acc_handle = acc_handle;
-               entry->dma_handle = dma_h;
-               list_add(&entry->item, &blockpool->free_block_list);
-               blockpool->pool_size++;
-       }
-
-       blockpool->req_out--;
-
-exit:
-       return;
-}
-
-static inline void
-vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh, unsigned long size)
-{
-       void *vaddr;
-
-       vaddr = kmalloc(size, GFP_KERNEL | GFP_DMA);
-       vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev);
-}
-
-/*
- * __vxge_hw_blockpool_blocks_add - Request additional blocks
- */
-static
-void __vxge_hw_blockpool_blocks_add(struct __vxge_hw_blockpool *blockpool)
-{
-       u32 nreq = 0, i;
-
-       if ((blockpool->pool_size  +  blockpool->req_out) <
-               VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE) {
-               nreq = VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE;
-               blockpool->req_out += nreq;
-       }
-
-       for (i = 0; i < nreq; i++)
-               vxge_os_dma_malloc_async(
-                       (blockpool->hldev)->pdev,
-                       blockpool->hldev, VXGE_HW_BLOCK_SIZE);
-}
-
-/*
- * __vxge_hw_blockpool_malloc - Allocate a memory block from pool
- * Allocates a block of memory of given size, either from block pool
- * or by calling vxge_os_dma_malloc()
- */
-static void *__vxge_hw_blockpool_malloc(struct __vxge_hw_device *devh, u32 size,
-                                       struct vxge_hw_mempool_dma *dma_object)
-{
-       struct __vxge_hw_blockpool_entry *entry = NULL;
-       struct __vxge_hw_blockpool  *blockpool;
-       void *memblock = NULL;
-
-       blockpool = &devh->block_pool;
-
-       if (size != blockpool->block_size) {
-
-               memblock = vxge_os_dma_malloc(devh->pdev, size,
-                                               &dma_object->handle,
-                                               &dma_object->acc_handle);
-
-               if (!memblock)
-                       goto exit;
-
-               dma_object->addr = dma_map_single(&devh->pdev->dev, memblock,
-                                                 size, DMA_BIDIRECTIONAL);
-
-               if (unlikely(dma_mapping_error(&devh->pdev->dev, dma_object->addr))) {
-                       vxge_os_dma_free(devh->pdev, memblock,
-                               &dma_object->acc_handle);
-                       memblock = NULL;
-                       goto exit;
-               }
-
-       } else {
-
-               if (!list_empty(&blockpool->free_block_list))
-                       entry = (struct __vxge_hw_blockpool_entry *)
-                               list_first_entry(&blockpool->free_block_list,
-                                       struct __vxge_hw_blockpool_entry,
-                                       item);
-
-               if (entry != NULL) {
-                       list_del(&entry->item);
-                       dma_object->addr = entry->dma_addr;
-                       dma_object->handle = entry->dma_handle;
-                       dma_object->acc_handle = entry->acc_handle;
-                       memblock = entry->memblock;
-
-                       list_add(&entry->item,
-                               &blockpool->free_entry_list);
-                       blockpool->pool_size--;
-               }
-
-               if (memblock != NULL)
-                       __vxge_hw_blockpool_blocks_add(blockpool);
-       }
-exit:
-       return memblock;
-}
-
-/*
- * __vxge_hw_blockpool_blocks_remove - Free additional blocks
- */
-static void
-__vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool)
-{
-       struct list_head *p, *n;
-
-       list_for_each_safe(p, n, &blockpool->free_block_list) {
-
-               if (blockpool->pool_size < blockpool->pool_max)
-                       break;
-
-               dma_unmap_single(&(blockpool->hldev)->pdev->dev,
-                                ((struct __vxge_hw_blockpool_entry *)p)->dma_addr,
-                                ((struct __vxge_hw_blockpool_entry *)p)->length,
-                                DMA_BIDIRECTIONAL);
-
-               vxge_os_dma_free(
-                       (blockpool->hldev)->pdev,
-                       ((struct __vxge_hw_blockpool_entry *)p)->memblock,
-                       &((struct __vxge_hw_blockpool_entry *)p)->acc_handle);
-
-               list_del(&((struct __vxge_hw_blockpool_entry *)p)->item);
-
-               list_add(p, &blockpool->free_entry_list);
-
-               blockpool->pool_size--;
-
-       }
-}
-
-/*
- * __vxge_hw_blockpool_free - Frees the memory allcoated with
- *                             __vxge_hw_blockpool_malloc
- */
-static void __vxge_hw_blockpool_free(struct __vxge_hw_device *devh,
-                                    void *memblock, u32 size,
-                                    struct vxge_hw_mempool_dma *dma_object)
-{
-       struct __vxge_hw_blockpool_entry *entry = NULL;
-       struct __vxge_hw_blockpool  *blockpool;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       blockpool = &devh->block_pool;
-
-       if (size != blockpool->block_size) {
-               dma_unmap_single(&devh->pdev->dev, dma_object->addr, size,
-                                DMA_BIDIRECTIONAL);
-               vxge_os_dma_free(devh->pdev, memblock, &dma_object->acc_handle);
-       } else {
-
-               if (!list_empty(&blockpool->free_entry_list))
-                       entry = (struct __vxge_hw_blockpool_entry *)
-                               list_first_entry(&blockpool->free_entry_list,
-                                       struct __vxge_hw_blockpool_entry,
-                                       item);
-
-               if (entry == NULL)
-                       entry = vmalloc(sizeof(
-                                       struct __vxge_hw_blockpool_entry));
-               else
-                       list_del(&entry->item);
-
-               if (entry != NULL) {
-                       entry->length = size;
-                       entry->memblock = memblock;
-                       entry->dma_addr = dma_object->addr;
-                       entry->acc_handle = dma_object->acc_handle;
-                       entry->dma_handle = dma_object->handle;
-                       list_add(&entry->item,
-                                       &blockpool->free_block_list);
-                       blockpool->pool_size++;
-                       status = VXGE_HW_OK;
-               } else
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-
-               if (status == VXGE_HW_OK)
-                       __vxge_hw_blockpool_blocks_remove(blockpool);
-       }
-}
-
-/*
- * vxge_hw_mempool_destroy
- */
-static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool)
-{
-       u32 i, j;
-       struct __vxge_hw_device *devh = mempool->devh;
-
-       for (i = 0; i < mempool->memblocks_allocated; i++) {
-               struct vxge_hw_mempool_dma *dma_object;
-
-               vxge_assert(mempool->memblocks_arr[i]);
-               vxge_assert(mempool->memblocks_dma_arr + i);
-
-               dma_object = mempool->memblocks_dma_arr + i;
-
-               for (j = 0; j < mempool->items_per_memblock; j++) {
-                       u32 index = i * mempool->items_per_memblock + j;
-
-                       /* to skip last partially filled(if any) memblock */
-                       if (index >= mempool->items_current)
-                               break;
-               }
-
-               vfree(mempool->memblocks_priv_arr[i]);
-
-               __vxge_hw_blockpool_free(devh, mempool->memblocks_arr[i],
-                               mempool->memblock_size, dma_object);
-       }
-
-       vfree(mempool->items_arr);
-       vfree(mempool->memblocks_dma_arr);
-       vfree(mempool->memblocks_priv_arr);
-       vfree(mempool->memblocks_arr);
-       vfree(mempool);
-}
-
-/*
- * __vxge_hw_mempool_grow
- * Will resize mempool up to %num_allocate value.
- */
-static enum vxge_hw_status
-__vxge_hw_mempool_grow(struct vxge_hw_mempool *mempool, u32 num_allocate,
-                      u32 *num_allocated)
-{
-       u32 i, first_time = mempool->memblocks_allocated == 0 ? 1 : 0;
-       u32 n_items = mempool->items_per_memblock;
-       u32 start_block_idx = mempool->memblocks_allocated;
-       u32 end_block_idx = mempool->memblocks_allocated + num_allocate;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       *num_allocated = 0;
-
-       if (end_block_idx > mempool->memblocks_max) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       for (i = start_block_idx; i < end_block_idx; i++) {
-               u32 j;
-               u32 is_last = ((end_block_idx - 1) == i);
-               struct vxge_hw_mempool_dma *dma_object =
-                       mempool->memblocks_dma_arr + i;
-               void *the_memblock;
-
-               /* allocate memblock's private part. Each DMA memblock
-                * has a space allocated for item's private usage upon
-                * mempool's user request. Each time mempool grows, it will
-                * allocate new memblock and its private part at once.
-                * This helps to minimize memory usage a lot. */
-               mempool->memblocks_priv_arr[i] =
-                       vzalloc(array_size(mempool->items_priv_size, n_items));
-               if (mempool->memblocks_priv_arr[i] == NULL) {
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-                       goto exit;
-               }
-
-               /* allocate DMA-capable memblock */
-               mempool->memblocks_arr[i] =
-                       __vxge_hw_blockpool_malloc(mempool->devh,
-                               mempool->memblock_size, dma_object);
-               if (mempool->memblocks_arr[i] == NULL) {
-                       vfree(mempool->memblocks_priv_arr[i]);
-                       status = VXGE_HW_ERR_OUT_OF_MEMORY;
-                       goto exit;
-               }
-
-               (*num_allocated)++;
-               mempool->memblocks_allocated++;
-
-               memset(mempool->memblocks_arr[i], 0, mempool->memblock_size);
-
-               the_memblock = mempool->memblocks_arr[i];
-
-               /* fill the items hash array */
-               for (j = 0; j < n_items; j++) {
-                       u32 index = i * n_items + j;
-
-                       if (first_time && index >= mempool->items_initial)
-                               break;
-
-                       mempool->items_arr[index] =
-                               ((char *)the_memblock + j*mempool->item_size);
-
-                       /* let caller to do more job on each item */
-                       if (mempool->item_func_alloc != NULL)
-                               mempool->item_func_alloc(mempool, i,
-                                       dma_object, index, is_last);
-
-                       mempool->items_current = index + 1;
-               }
-
-               if (first_time && mempool->items_current ==
-                                       mempool->items_initial)
-                       break;
-       }
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_mempool_create
- * This function will create memory pool object. Pool may grow but will
- * never shrink. Pool consists of number of dynamically allocated blocks
- * with size enough to hold %items_initial number of items. Memory is
- * DMA-able but client must map/unmap before interoperating with the device.
- */
-static struct vxge_hw_mempool *
-__vxge_hw_mempool_create(struct __vxge_hw_device *devh,
-                        u32 memblock_size,
-                        u32 item_size,
-                        u32 items_priv_size,
-                        u32 items_initial,
-                        u32 items_max,
-                        const struct vxge_hw_mempool_cbs *mp_callback,
-                        void *userdata)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       u32 memblocks_to_allocate;
-       struct vxge_hw_mempool *mempool = NULL;
-       u32 allocated;
-
-       if (memblock_size < item_size) {
-               status = VXGE_HW_FAIL;
-               goto exit;
-       }
-
-       mempool = vzalloc(sizeof(struct vxge_hw_mempool));
-       if (mempool == NULL) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       mempool->devh                   = devh;
-       mempool->memblock_size          = memblock_size;
-       mempool->items_max              = items_max;
-       mempool->items_initial          = items_initial;
-       mempool->item_size              = item_size;
-       mempool->items_priv_size        = items_priv_size;
-       mempool->item_func_alloc        = mp_callback->item_func_alloc;
-       mempool->userdata               = userdata;
-
-       mempool->memblocks_allocated = 0;
-
-       mempool->items_per_memblock = memblock_size / item_size;
-
-       mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) /
-                                       mempool->items_per_memblock;
-
-       /* allocate array of memblocks */
-       mempool->memblocks_arr =
-               vzalloc(array_size(sizeof(void *), mempool->memblocks_max));
-       if (mempool->memblocks_arr == NULL) {
-               __vxge_hw_mempool_destroy(mempool);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               mempool = NULL;
-               goto exit;
-       }
-
-       /* allocate array of private parts of items per memblocks */
-       mempool->memblocks_priv_arr =
-               vzalloc(array_size(sizeof(void *), mempool->memblocks_max));
-       if (mempool->memblocks_priv_arr == NULL) {
-               __vxge_hw_mempool_destroy(mempool);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               mempool = NULL;
-               goto exit;
-       }
-
-       /* allocate array of memblocks DMA objects */
-       mempool->memblocks_dma_arr =
-               vzalloc(array_size(sizeof(struct vxge_hw_mempool_dma),
-                                  mempool->memblocks_max));
-       if (mempool->memblocks_dma_arr == NULL) {
-               __vxge_hw_mempool_destroy(mempool);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               mempool = NULL;
-               goto exit;
-       }
-
-       /* allocate hash array of items */
-       mempool->items_arr = vzalloc(array_size(sizeof(void *),
-                                               mempool->items_max));
-       if (mempool->items_arr == NULL) {
-               __vxge_hw_mempool_destroy(mempool);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               mempool = NULL;
-               goto exit;
-       }
-
-       /* calculate initial number of memblocks */
-       memblocks_to_allocate = (mempool->items_initial +
-                                mempool->items_per_memblock - 1) /
-                                               mempool->items_per_memblock;
-
-       /* pre-allocate the mempool */
-       status = __vxge_hw_mempool_grow(mempool, memblocks_to_allocate,
-                                       &allocated);
-       if (status != VXGE_HW_OK) {
-               __vxge_hw_mempool_destroy(mempool);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               mempool = NULL;
-               goto exit;
-       }
-
-exit:
-       return mempool;
-}
-
-/*
- * __vxge_hw_ring_abort - Returns the RxD
- * This function terminates the RxDs of ring
- */
-static enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring)
-{
-       void *rxdh;
-       struct __vxge_hw_channel *channel;
-
-       channel = &ring->channel;
-
-       for (;;) {
-               vxge_hw_channel_dtr_try_complete(channel, &rxdh);
-
-               if (rxdh == NULL)
-                       break;
-
-               vxge_hw_channel_dtr_complete(channel);
-
-               if (ring->rxd_term)
-                       ring->rxd_term(rxdh, VXGE_HW_RXD_STATE_POSTED,
-                               channel->userdata);
-
-               vxge_hw_channel_dtr_free(channel, rxdh);
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_ring_reset - Resets the ring
- * This function resets the ring during vpath reset operation
- */
-static enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_channel *channel;
-
-       channel = &ring->channel;
-
-       __vxge_hw_ring_abort(ring);
-
-       status = __vxge_hw_channel_reset(channel);
-
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       if (ring->rxd_init) {
-               status = vxge_hw_ring_replenish(ring);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-       }
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_ring_delete - Removes the ring
- * This function freeup the memory pool and removes the ring
- */
-static enum vxge_hw_status
-__vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_ring *ring = vp->vpath->ringh;
-
-       __vxge_hw_ring_abort(ring);
-
-       if (ring->mempool)
-               __vxge_hw_mempool_destroy(ring->mempool);
-
-       vp->vpath->ringh = NULL;
-       __vxge_hw_channel_free(&ring->channel);
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_ring_create - Create a Ring
- * This function creates Ring and initializes it.
- */
-static enum vxge_hw_status
-__vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
-                     struct vxge_hw_ring_attr *attr)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_ring *ring;
-       u32 ring_length;
-       struct vxge_hw_ring_config *config;
-       struct __vxge_hw_device *hldev;
-       u32 vp_id;
-       static const struct vxge_hw_mempool_cbs ring_mp_callback = {
-               .item_func_alloc = __vxge_hw_ring_mempool_item_alloc,
-       };
-
-       if ((vp == NULL) || (attr == NULL)) {
-               status = VXGE_HW_FAIL;
-               goto exit;
-       }
-
-       hldev = vp->vpath->hldev;
-       vp_id = vp->vpath->vp_id;
-
-       config = &hldev->config.vp_config[vp_id].ring;
-
-       ring_length = config->ring_blocks *
-                       vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
-
-       ring = (struct __vxge_hw_ring *)__vxge_hw_channel_allocate(vp,
-                                               VXGE_HW_CHANNEL_TYPE_RING,
-                                               ring_length,
-                                               attr->per_rxd_space,
-                                               attr->userdata);
-       if (ring == NULL) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       vp->vpath->ringh = ring;
-       ring->vp_id = vp_id;
-       ring->vp_reg = vp->vpath->vp_reg;
-       ring->common_reg = hldev->common_reg;
-       ring->stats = &vp->vpath->sw_stats->ring_stats;
-       ring->config = config;
-       ring->callback = attr->callback;
-       ring->rxd_init = attr->rxd_init;
-       ring->rxd_term = attr->rxd_term;
-       ring->buffer_mode = config->buffer_mode;
-       ring->tim_rti_cfg1_saved = vp->vpath->tim_rti_cfg1_saved;
-       ring->tim_rti_cfg3_saved = vp->vpath->tim_rti_cfg3_saved;
-       ring->rxds_limit = config->rxds_limit;
-
-       ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode);
-       ring->rxd_priv_size =
-               sizeof(struct __vxge_hw_ring_rxd_priv) + attr->per_rxd_space;
-       ring->per_rxd_space = attr->per_rxd_space;
-
-       ring->rxd_priv_size =
-               ((ring->rxd_priv_size + VXGE_CACHE_LINE_SIZE - 1) /
-               VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
-
-       /* how many RxDs can fit into one block. Depends on configured
-        * buffer_mode. */
-       ring->rxds_per_block =
-               vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
-
-       /* calculate actual RxD block private size */
-       ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block;
-       ring->mempool = __vxge_hw_mempool_create(hldev,
-                               VXGE_HW_BLOCK_SIZE,
-                               VXGE_HW_BLOCK_SIZE,
-                               ring->rxdblock_priv_size,
-                               ring->config->ring_blocks,
-                               ring->config->ring_blocks,
-                               &ring_mp_callback,
-                               ring);
-       if (ring->mempool == NULL) {
-               __vxge_hw_ring_delete(vp);
-               return VXGE_HW_ERR_OUT_OF_MEMORY;
-       }
-
-       status = __vxge_hw_channel_initialize(&ring->channel);
-       if (status != VXGE_HW_OK) {
-               __vxge_hw_ring_delete(vp);
-               goto exit;
-       }
-
-       /* Note:
-        * Specifying rxd_init callback means two things:
-        * 1) rxds need to be initialized by driver at channel-open time;
-        * 2) rxds need to be posted at channel-open time
-        *    (that's what the initial_replenish() below does)
-        * Currently we don't have a case when the 1) is done without the 2).
-        */
-       if (ring->rxd_init) {
-               status = vxge_hw_ring_replenish(ring);
-               if (status != VXGE_HW_OK) {
-                       __vxge_hw_ring_delete(vp);
-                       goto exit;
-               }
-       }
-
-       /* initial replenish will increment the counter in its post() routine,
-        * we have to reset it */
-       ring->stats->common_stats.usage_cnt = 0;
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_device_config_default_get - Initialize device config with defaults.
- * Initialize Titan device config with default values.
- */
-enum vxge_hw_status
-vxge_hw_device_config_default_get(struct vxge_hw_device_config *device_config)
-{
-       u32 i;
-
-       device_config->dma_blockpool_initial =
-                                       VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE;
-       device_config->dma_blockpool_max = VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE;
-       device_config->intr_mode = VXGE_HW_INTR_MODE_DEF;
-       device_config->rth_en = VXGE_HW_RTH_DEFAULT;
-       device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_DEFAULT;
-       device_config->device_poll_millis =  VXGE_HW_DEF_DEVICE_POLL_MILLIS;
-       device_config->rts_mac_en =  VXGE_HW_RTS_MAC_DEFAULT;
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               device_config->vp_config[i].vp_id = i;
-
-               device_config->vp_config[i].min_bandwidth =
-                               VXGE_HW_VPATH_BANDWIDTH_DEFAULT;
-
-               device_config->vp_config[i].ring.enable = VXGE_HW_RING_DEFAULT;
-
-               device_config->vp_config[i].ring.ring_blocks =
-                               VXGE_HW_DEF_RING_BLOCKS;
-
-               device_config->vp_config[i].ring.buffer_mode =
-                               VXGE_HW_RING_RXD_BUFFER_MODE_DEFAULT;
-
-               device_config->vp_config[i].ring.scatter_mode =
-                               VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].ring.rxds_limit =
-                               VXGE_HW_DEF_RING_RXDS_LIMIT;
-
-               device_config->vp_config[i].fifo.enable = VXGE_HW_FIFO_ENABLE;
-
-               device_config->vp_config[i].fifo.fifo_blocks =
-                               VXGE_HW_MIN_FIFO_BLOCKS;
-
-               device_config->vp_config[i].fifo.max_frags =
-                               VXGE_HW_MAX_FIFO_FRAGS;
-
-               device_config->vp_config[i].fifo.memblock_size =
-                               VXGE_HW_DEF_FIFO_MEMBLOCK_SIZE;
-
-               device_config->vp_config[i].fifo.alignment_size =
-                               VXGE_HW_DEF_FIFO_ALIGNMENT_SIZE;
-
-               device_config->vp_config[i].fifo.intr =
-                               VXGE_HW_FIFO_QUEUE_INTR_DEFAULT;
-
-               device_config->vp_config[i].fifo.no_snoop_bits =
-                               VXGE_HW_FIFO_NO_SNOOP_DEFAULT;
-               device_config->vp_config[i].tti.intr_enable =
-                               VXGE_HW_TIM_INTR_DEFAULT;
-
-               device_config->vp_config[i].tti.btimer_val =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.timer_ac_en =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.timer_ci_en =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.timer_ri_en =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.rtimer_val =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.util_sel =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.ltimer_val =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.urange_a =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.uec_a =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.urange_b =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.uec_b =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.urange_c =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.uec_c =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].tti.uec_d =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.intr_enable =
-                               VXGE_HW_TIM_INTR_DEFAULT;
-
-               device_config->vp_config[i].rti.btimer_val =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.timer_ac_en =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.timer_ci_en =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.timer_ri_en =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.rtimer_val =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.util_sel =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.ltimer_val =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.urange_a =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.uec_a =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.urange_b =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.uec_b =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.urange_c =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.uec_c =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].rti.uec_d =
-                               VXGE_HW_USE_FLASH_DEFAULT;
-
-               device_config->vp_config[i].mtu =
-                               VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU;
-
-               device_config->vp_config[i].rpa_strip_vlan_tag =
-                       VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT;
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_vpath_swapper_set - Set the swapper bits for the vpath.
- * Set the swapper bits appropriately for the vpath.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg)
-{
-#ifndef __BIG_ENDIAN
-       u64 val64;
-
-       val64 = readq(&vpath_reg->vpath_general_cfg1);
-       wmb();
-       val64 |= VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN;
-       writeq(val64, &vpath_reg->vpath_general_cfg1);
-       wmb();
-#endif
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_kdfc_swapper_set - Set the swapper bits for the kdfc.
- * Set the swapper bits appropriately for the vpath.
- */
-static enum vxge_hw_status
-__vxge_hw_kdfc_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg,
-                          struct vxge_hw_vpath_reg __iomem *vpath_reg)
-{
-       u64 val64;
-
-       val64 = readq(&legacy_reg->pifm_wr_swap_en);
-
-       if (val64 == VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE) {
-               val64 = readq(&vpath_reg->kdfcctl_cfg0);
-               wmb();
-
-               val64 |= VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0 |
-                       VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1  |
-                       VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2;
-
-               writeq(val64, &vpath_reg->kdfcctl_cfg0);
-               wmb();
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * vxge_hw_mgmt_reg_read - Read Titan register.
- */
-enum vxge_hw_status
-vxge_hw_mgmt_reg_read(struct __vxge_hw_device *hldev,
-                     enum vxge_hw_mgmt_reg_type type,
-                     u32 index, u32 offset, u64 *value)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
-               status = VXGE_HW_ERR_INVALID_DEVICE;
-               goto exit;
-       }
-
-       switch (type) {
-       case vxge_hw_mgmt_reg_type_legacy:
-               if (offset > sizeof(struct vxge_hw_legacy_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->legacy_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_toc:
-               if (offset > sizeof(struct vxge_hw_toc_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->toc_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_common:
-               if (offset > sizeof(struct vxge_hw_common_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->common_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_mrpcim:
-               if (!(hldev->access_rights &
-                       VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
-                       status = VXGE_HW_ERR_PRIVILEGED_OPERATION;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_mrpcim_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->mrpcim_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_srpcim:
-               if (!(hldev->access_rights &
-                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM)) {
-                       status = VXGE_HW_ERR_PRIVILEGED_OPERATION;
-                       break;
-               }
-               if (index > VXGE_HW_TITAN_SRPCIM_REG_SPACES - 1) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_srpcim_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->srpcim_reg[index] +
-                               offset);
-               break;
-       case vxge_hw_mgmt_reg_type_vpmgmt:
-               if ((index > VXGE_HW_TITAN_VPMGMT_REG_SPACES - 1) ||
-                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_vpmgmt_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->vpmgmt_reg[index] +
-                               offset);
-               break;
-       case vxge_hw_mgmt_reg_type_vpath:
-               if ((index > VXGE_HW_TITAN_VPATH_REG_SPACES - 1) ||
-                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (index > VXGE_HW_TITAN_VPATH_REG_SPACES - 1) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_vpath_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               *value = readq((void __iomem *)hldev->vpath_reg[index] +
-                               offset);
-               break;
-       default:
-               status = VXGE_HW_ERR_INVALID_TYPE;
-               break;
-       }
-
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_strip_fcs_check - Check for FCS strip.
- */
-enum vxge_hw_status
-vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask)
-{
-       struct vxge_hw_vpmgmt_reg       __iomem *vpmgmt_reg;
-       int i = 0, j = 0;
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!((vpath_mask) & vxge_mBIT(i)))
-                       continue;
-               vpmgmt_reg = hldev->vpmgmt_reg[i];
-               for (j = 0; j < VXGE_HW_MAC_MAX_MAC_PORT_ID; j++) {
-                       if (readq(&vpmgmt_reg->rxmac_cfg0_port_vpmgmt_clone[j])
-                       & VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS)
-                               return VXGE_HW_FAIL;
-               }
-       }
-       return VXGE_HW_OK;
-}
-/*
- * vxge_hw_mgmt_reg_Write - Write Titan register.
- */
-enum vxge_hw_status
-vxge_hw_mgmt_reg_write(struct __vxge_hw_device *hldev,
-                     enum vxge_hw_mgmt_reg_type type,
-                     u32 index, u32 offset, u64 value)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
-               status = VXGE_HW_ERR_INVALID_DEVICE;
-               goto exit;
-       }
-
-       switch (type) {
-       case vxge_hw_mgmt_reg_type_legacy:
-               if (offset > sizeof(struct vxge_hw_legacy_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->legacy_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_toc:
-               if (offset > sizeof(struct vxge_hw_toc_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->toc_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_common:
-               if (offset > sizeof(struct vxge_hw_common_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->common_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_mrpcim:
-               if (!(hldev->access_rights &
-                       VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
-                       status = VXGE_HW_ERR_PRIVILEGED_OPERATION;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_mrpcim_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->mrpcim_reg + offset);
-               break;
-       case vxge_hw_mgmt_reg_type_srpcim:
-               if (!(hldev->access_rights &
-                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM)) {
-                       status = VXGE_HW_ERR_PRIVILEGED_OPERATION;
-                       break;
-               }
-               if (index > VXGE_HW_TITAN_SRPCIM_REG_SPACES - 1) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_srpcim_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->srpcim_reg[index] +
-                       offset);
-
-               break;
-       case vxge_hw_mgmt_reg_type_vpmgmt:
-               if ((index > VXGE_HW_TITAN_VPMGMT_REG_SPACES - 1) ||
-                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_vpmgmt_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->vpmgmt_reg[index] +
-                       offset);
-               break;
-       case vxge_hw_mgmt_reg_type_vpath:
-               if ((index > VXGE_HW_TITAN_VPATH_REG_SPACES-1) ||
-                       (!(hldev->vpath_assignments & vxge_mBIT(index)))) {
-                       status = VXGE_HW_ERR_INVALID_INDEX;
-                       break;
-               }
-               if (offset > sizeof(struct vxge_hw_vpath_reg) - 8) {
-                       status = VXGE_HW_ERR_INVALID_OFFSET;
-                       break;
-               }
-               writeq(value, (void __iomem *)hldev->vpath_reg[index] +
-                       offset);
-               break;
-       default:
-               status = VXGE_HW_ERR_INVALID_TYPE;
-               break;
-       }
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_fifo_abort - Returns the TxD
- * This function terminates the TxDs of fifo
- */
-static enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo)
-{
-       void *txdlh;
-
-       for (;;) {
-               vxge_hw_channel_dtr_try_complete(&fifo->channel, &txdlh);
-
-               if (txdlh == NULL)
-                       break;
-
-               vxge_hw_channel_dtr_complete(&fifo->channel);
-
-               if (fifo->txdl_term) {
-                       fifo->txdl_term(txdlh,
-                       VXGE_HW_TXDL_STATE_POSTED,
-                       fifo->channel.userdata);
-               }
-
-               vxge_hw_channel_dtr_free(&fifo->channel, txdlh);
-       }
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_fifo_reset - Resets the fifo
- * This function resets the fifo during vpath reset operation
- */
-static enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       __vxge_hw_fifo_abort(fifo);
-       status = __vxge_hw_channel_reset(&fifo->channel);
-
-       return status;
-}
-
-/*
- * __vxge_hw_fifo_delete - Removes the FIFO
- * This function freeup the memory pool and removes the FIFO
- */
-static enum vxge_hw_status
-__vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_fifo *fifo = vp->vpath->fifoh;
-
-       __vxge_hw_fifo_abort(fifo);
-
-       if (fifo->mempool)
-               __vxge_hw_mempool_destroy(fifo->mempool);
-
-       vp->vpath->fifoh = NULL;
-
-       __vxge_hw_channel_free(&fifo->channel);
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_fifo_mempool_item_alloc - Allocate List blocks for TxD
- * list callback
- * This function is callback passed to __vxge_hw_mempool_create to create memory
- * pool for TxD list
- */
-static void
-__vxge_hw_fifo_mempool_item_alloc(
-       struct vxge_hw_mempool *mempoolh,
-       u32 memblock_index, struct vxge_hw_mempool_dma *dma_object,
-       u32 index, u32 is_last)
-{
-       u32 memblock_item_idx;
-       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
-       struct vxge_hw_fifo_txd *txdp =
-               (struct vxge_hw_fifo_txd *)mempoolh->items_arr[index];
-       struct __vxge_hw_fifo *fifo =
-                       (struct __vxge_hw_fifo *)mempoolh->userdata;
-       void *memblock = mempoolh->memblocks_arr[memblock_index];
-
-       vxge_assert(txdp);
-
-       txdp->host_control = (u64) (size_t)
-       __vxge_hw_mempool_item_priv(mempoolh, memblock_index, txdp,
-                                       &memblock_item_idx);
-
-       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdp);
-
-       vxge_assert(txdl_priv);
-
-       fifo->channel.reserve_arr[fifo->channel.reserve_ptr - 1 - index] = txdp;
-
-       /* pre-format HW's TxDL's private */
-       txdl_priv->dma_offset = (char *)txdp - (char *)memblock;
-       txdl_priv->dma_addr = dma_object->addr + txdl_priv->dma_offset;
-       txdl_priv->dma_handle = dma_object->handle;
-       txdl_priv->memblock   = memblock;
-       txdl_priv->first_txdp = txdp;
-       txdl_priv->next_txdl_priv = NULL;
-       txdl_priv->alloc_frags = 0;
-}
-
-/*
- * __vxge_hw_fifo_create - Create a FIFO
- * This function creates FIFO and initializes it.
- */
-static enum vxge_hw_status
-__vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp,
-                     struct vxge_hw_fifo_attr *attr)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_fifo *fifo;
-       struct vxge_hw_fifo_config *config;
-       u32 txdl_size, txdl_per_memblock;
-       struct vxge_hw_mempool_cbs fifo_mp_callback;
-       struct __vxge_hw_virtualpath *vpath;
-
-       if ((vp == NULL) || (attr == NULL)) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-       vpath = vp->vpath;
-       config = &vpath->hldev->config.vp_config[vpath->vp_id].fifo;
-
-       txdl_size = config->max_frags * sizeof(struct vxge_hw_fifo_txd);
-
-       txdl_per_memblock = config->memblock_size / txdl_size;
-
-       fifo = (struct __vxge_hw_fifo *)__vxge_hw_channel_allocate(vp,
-                                       VXGE_HW_CHANNEL_TYPE_FIFO,
-                                       config->fifo_blocks * txdl_per_memblock,
-                                       attr->per_txdl_space, attr->userdata);
-
-       if (fifo == NULL) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       vpath->fifoh = fifo;
-       fifo->nofl_db = vpath->nofl_db;
-
-       fifo->vp_id = vpath->vp_id;
-       fifo->vp_reg = vpath->vp_reg;
-       fifo->stats = &vpath->sw_stats->fifo_stats;
-
-       fifo->config = config;
-
-       /* apply "interrupts per txdl" attribute */
-       fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ;
-       fifo->tim_tti_cfg1_saved = vpath->tim_tti_cfg1_saved;
-       fifo->tim_tti_cfg3_saved = vpath->tim_tti_cfg3_saved;
-
-       if (fifo->config->intr)
-               fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST;
-
-       fifo->no_snoop_bits = config->no_snoop_bits;
-
-       /*
-        * FIFO memory management strategy:
-        *
-        * TxDL split into three independent parts:
-        *      - set of TxD's
-        *      - TxD HW private part
-        *      - driver private part
-        *
-        * Adaptative memory allocation used. i.e. Memory allocated on
-        * demand with the size which will fit into one memory block.
-        * One memory block may contain more than one TxDL.
-        *
-        * During "reserve" operations more memory can be allocated on demand
-        * for example due to FIFO full condition.
-        *
-        * Pool of memory memblocks never shrinks except in __vxge_hw_fifo_close
-        * routine which will essentially stop the channel and free resources.
-        */
-
-       /* TxDL common private size == TxDL private  +  driver private */
-       fifo->priv_size =
-               sizeof(struct __vxge_hw_fifo_txdl_priv) + attr->per_txdl_space;
-       fifo->priv_size = ((fifo->priv_size  +  VXGE_CACHE_LINE_SIZE - 1) /
-                       VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
-
-       fifo->per_txdl_space = attr->per_txdl_space;
-
-       /* recompute txdl size to be cacheline aligned */
-       fifo->txdl_size = txdl_size;
-       fifo->txdl_per_memblock = txdl_per_memblock;
-
-       fifo->txdl_term = attr->txdl_term;
-       fifo->callback = attr->callback;
-
-       if (fifo->txdl_per_memblock == 0) {
-               __vxge_hw_fifo_delete(vp);
-               status = VXGE_HW_ERR_INVALID_BLOCK_SIZE;
-               goto exit;
-       }
-
-       fifo_mp_callback.item_func_alloc = __vxge_hw_fifo_mempool_item_alloc;
-
-       fifo->mempool =
-               __vxge_hw_mempool_create(vpath->hldev,
-                       fifo->config->memblock_size,
-                       fifo->txdl_size,
-                       fifo->priv_size,
-                       (fifo->config->fifo_blocks * fifo->txdl_per_memblock),
-                       (fifo->config->fifo_blocks * fifo->txdl_per_memblock),
-                       &fifo_mp_callback,
-                       fifo);
-
-       if (fifo->mempool == NULL) {
-               __vxge_hw_fifo_delete(vp);
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto exit;
-       }
-
-       status = __vxge_hw_channel_initialize(&fifo->channel);
-       if (status != VXGE_HW_OK) {
-               __vxge_hw_fifo_delete(vp);
-               goto exit;
-       }
-
-       vxge_assert(fifo->channel.reserve_ptr);
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_pci_read - Read the content of given address
- *                          in pci config space.
- * Read from the vpath pci config space.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_pci_read(struct __vxge_hw_virtualpath *vpath,
-                        u32 phy_func_0, u32 offset, u32 *val)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
-
-       val64 = VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(offset);
-
-       if (phy_func_0)
-               val64 |= VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0;
-
-       writeq(val64, &vp_reg->pci_config_access_cfg1);
-       wmb();
-       writeq(VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ,
-                       &vp_reg->pci_config_access_cfg2);
-       wmb();
-
-       status = __vxge_hw_device_register_poll(
-                       &vp_reg->pci_config_access_cfg2,
-                       VXGE_HW_INTR_MASK_ALL, VXGE_HW_DEF_DEVICE_POLL_MILLIS);
-
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       val64 = readq(&vp_reg->pci_config_access_status);
-
-       if (val64 & VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR) {
-               status = VXGE_HW_FAIL;
-               *val = 0;
-       } else
-               *val = (u32)vxge_bVALn(val64, 32, 32);
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_device_flick_link_led - Flick (blink) link LED.
- * @hldev: HW device.
- * @on_off: TRUE if flickering to be on, FALSE to be off
- *
- * Flicker the link LED.
- */
-enum vxge_hw_status
-vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev, u64 on_off)
-{
-       struct __vxge_hw_virtualpath *vpath;
-       u64 data0, data1 = 0, steer_ctrl = 0;
-       enum vxge_hw_status status;
-
-       if (hldev == NULL) {
-               status = VXGE_HW_ERR_INVALID_DEVICE;
-               goto exit;
-       }
-
-       vpath = &hldev->virtual_paths[hldev->first_vp_id];
-
-       data0 = on_off;
-       status = vxge_hw_vpath_fw_api(vpath,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO,
-                       0, &data0, &data1, &steer_ctrl);
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_rts_table_get - Get the entries from RTS access tables
- */
-enum vxge_hw_status
-__vxge_hw_vpath_rts_table_get(struct __vxge_hw_vpath_handle *vp,
-                             u32 action, u32 rts_table, u32 offset,
-                             u64 *data0, u64 *data1)
-{
-       enum vxge_hw_status status;
-       u64 steer_ctrl = 0;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       if ((rts_table ==
-            VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) ||
-           (rts_table ==
-            VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) ||
-           (rts_table ==
-            VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) ||
-           (rts_table ==
-            VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) {
-               steer_ctrl = VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL;
-       }
-
-       status = vxge_hw_vpath_fw_api(vp->vpath, action, rts_table, offset,
-                                     data0, data1, &steer_ctrl);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) &&
-           (rts_table !=
-            VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT))
-               *data1 = 0;
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_rts_table_set - Set the entries of RTS access tables
- */
-enum vxge_hw_status
-__vxge_hw_vpath_rts_table_set(struct __vxge_hw_vpath_handle *vp, u32 action,
-                             u32 rts_table, u32 offset, u64 steer_data0,
-                             u64 steer_data1)
-{
-       u64 data0, data1 = 0, steer_ctrl = 0;
-       enum vxge_hw_status status;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       data0 = steer_data0;
-
-       if ((rts_table == VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) ||
-           (rts_table ==
-            VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT))
-               data1 = steer_data1;
-
-       status = vxge_hw_vpath_fw_api(vp->vpath, action, rts_table, offset,
-                                     &data0, &data1, &steer_ctrl);
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_rts_rth_set - Set/configure RTS hashing.
- */
-enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
-                       struct __vxge_hw_vpath_handle *vp,
-                       enum vxge_hw_rth_algoritms algorithm,
-                       struct vxge_hw_rth_hash_types *hash_type,
-                       u16 bucket_size)
-{
-       u64 data0, data1;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_rts_table_get(vp,
-                    VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY,
-                    VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG,
-                       0, &data0, &data1);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       data0 &= ~(VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(0xf) |
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(0x3));
-
-       data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN |
-       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(bucket_size) |
-       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(algorithm);
-
-       if (hash_type->hash_type_tcpipv4_en)
-               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN;
-
-       if (hash_type->hash_type_ipv4_en)
-               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN;
-
-       if (hash_type->hash_type_tcpipv6_en)
-               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN;
-
-       if (hash_type->hash_type_ipv6_en)
-               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN;
-
-       if (hash_type->hash_type_tcpipv6ex_en)
-               data0 |=
-               VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN;
-
-       if (hash_type->hash_type_ipv6ex_en)
-               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN;
-
-       if (VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(data0))
-               data0 &= ~VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE;
-       else
-               data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE;
-
-       status = __vxge_hw_vpath_rts_table_set(vp,
-               VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY,
-               VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG,
-               0, data0, 0);
-exit:
-       return status;
-}
-
-static void
-vxge_hw_rts_rth_data0_data1_get(u32 j, u64 *data0, u64 *data1,
-                               u16 flag, u8 *itable)
-{
-       switch (flag) {
-       case 1:
-               *data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(j)|
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN |
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(
-                       itable[j]);
-               fallthrough;
-       case 2:
-               *data0 |=
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(j)|
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN |
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(
-                       itable[j]);
-               fallthrough;
-       case 3:
-               *data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(j)|
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN |
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(
-                       itable[j]);
-               fallthrough;
-       case 4:
-               *data1 |=
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(j)|
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN |
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(
-                       itable[j]);
-               return;
-       default:
-               return;
-       }
-}
-/*
- * vxge_hw_vpath_rts_rth_itable_set - Set/configure indirection table (IT).
- */
-enum vxge_hw_status vxge_hw_vpath_rts_rth_itable_set(
-                       struct __vxge_hw_vpath_handle **vpath_handles,
-                       u32 vpath_count,
-                       u8 *mtable,
-                       u8 *itable,
-                       u32 itable_size)
-{
-       u32 i, j, action, rts_table;
-       u64 data0;
-       u64 data1;
-       u32 max_entries;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_vpath_handle *vp = vpath_handles[0];
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       max_entries = (((u32)1) << itable_size);
-
-       if (vp->vpath->hldev->config.rth_it_type
-                               == VXGE_HW_RTH_IT_TYPE_SOLO_IT) {
-               action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY;
-               rts_table =
-                       VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT;
-
-               for (j = 0; j < max_entries; j++) {
-
-                       data1 = 0;
-
-                       data0 =
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(
-                               itable[j]);
-
-                       status = __vxge_hw_vpath_rts_table_set(vpath_handles[0],
-                               action, rts_table, j, data0, data1);
-
-                       if (status != VXGE_HW_OK)
-                               goto exit;
-               }
-
-               for (j = 0; j < max_entries; j++) {
-
-                       data1 = 0;
-
-                       data0 =
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN |
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(
-                               itable[j]);
-
-                       status = __vxge_hw_vpath_rts_table_set(
-                               vpath_handles[mtable[itable[j]]], action,
-                               rts_table, j, data0, data1);
-
-                       if (status != VXGE_HW_OK)
-                               goto exit;
-               }
-       } else {
-               action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY;
-               rts_table =
-                       VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT;
-               for (i = 0; i < vpath_count; i++) {
-
-                       for (j = 0; j < max_entries;) {
-
-                               data0 = 0;
-                               data1 = 0;
-
-                               while (j < max_entries) {
-                                       if (mtable[itable[j]] != i) {
-                                               j++;
-                                               continue;
-                                       }
-                                       vxge_hw_rts_rth_data0_data1_get(j,
-                                               &data0, &data1, 1, itable);
-                                       j++;
-                                       break;
-                               }
-
-                               while (j < max_entries) {
-                                       if (mtable[itable[j]] != i) {
-                                               j++;
-                                               continue;
-                                       }
-                                       vxge_hw_rts_rth_data0_data1_get(j,
-                                               &data0, &data1, 2, itable);
-                                       j++;
-                                       break;
-                               }
-
-                               while (j < max_entries) {
-                                       if (mtable[itable[j]] != i) {
-                                               j++;
-                                               continue;
-                                       }
-                                       vxge_hw_rts_rth_data0_data1_get(j,
-                                               &data0, &data1, 3, itable);
-                                       j++;
-                                       break;
-                               }
-
-                               while (j < max_entries) {
-                                       if (mtable[itable[j]] != i) {
-                                               j++;
-                                               continue;
-                                       }
-                                       vxge_hw_rts_rth_data0_data1_get(j,
-                                               &data0, &data1, 4, itable);
-                                       j++;
-                                       break;
-                               }
-
-                               if (data0 != 0) {
-                                       status = __vxge_hw_vpath_rts_table_set(
-                                                       vpath_handles[i],
-                                                       action, rts_table,
-                                                       0, data0, data1);
-
-                                       if (status != VXGE_HW_OK)
-                                               goto exit;
-                               }
-                       }
-               }
-       }
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_check_leak - Check for memory leak
- * @ring: Handle to the ring object used for receive
- *
- * If PRC_RXD_DOORBELL_VPn.NEW_QW_CNT is larger or equal to
- * PRC_CFG6_VPn.RXD_SPAT then a leak has occurred.
- * Returns: VXGE_HW_FAIL, if leak has occurred.
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_check_leak(struct __vxge_hw_ring *ring)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       u64 rxd_new_count, rxd_spat;
-
-       if (ring == NULL)
-               return status;
-
-       rxd_new_count = readl(&ring->vp_reg->prc_rxd_doorbell);
-       rxd_spat = readq(&ring->vp_reg->prc_cfg6);
-       rxd_spat = VXGE_HW_PRC_CFG6_RXD_SPAT(rxd_spat);
-
-       if (rxd_new_count >= rxd_spat)
-               status = VXGE_HW_FAIL;
-
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_mgmt_read
- * This routine reads the vpath_mgmt registers
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_mgmt_read(
-       struct __vxge_hw_device *hldev,
-       struct __vxge_hw_virtualpath *vpath)
-{
-       u32 i, mtu = 0, max_pyld = 0;
-       u64 val64;
-
-       for (i = 0; i < VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) {
-
-               val64 = readq(&vpath->vpmgmt_reg->
-                               rxmac_cfg0_port_vpmgmt_clone[i]);
-               max_pyld =
-                       (u32)
-                       VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN
-                       (val64);
-               if (mtu < max_pyld)
-                       mtu = max_pyld;
-       }
-
-       vpath->max_mtu = mtu + VXGE_HW_MAC_HEADER_MAX_SIZE;
-
-       val64 = readq(&vpath->vpmgmt_reg->xmac_vsport_choices_vp);
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (val64 & vxge_mBIT(i))
-                       vpath->vsport_number = i;
-       }
-
-       val64 = readq(&vpath->vpmgmt_reg->xgmac_gen_status_vpmgmt_clone);
-
-       if (val64 & VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK)
-               VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_UP);
-       else
-               VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_DOWN);
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_vpath_reset_check - Check if resetting the vpath completed
- * This routine checks the vpath_rst_in_prog register to see if
- * adapter completed the reset process for the vpath
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath)
-{
-       enum vxge_hw_status status;
-
-       status = __vxge_hw_device_register_poll(
-                       &vpath->hldev->common_reg->vpath_rst_in_prog,
-                       VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(
-                               1 << (16 - vpath->vp_id)),
-                       vpath->hldev->config.device_poll_millis);
-
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_reset
- * This routine resets the vpath on the device
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_reset(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       u64 val64;
-
-       val64 = VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(1 << (16 - vp_id));
-
-       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
-                               &hldev->common_reg->cmn_rsthdlr_cfg0);
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_vpath_sw_reset
- * This routine resets the vpath structures
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_virtualpath *vpath;
-
-       vpath = &hldev->virtual_paths[vp_id];
-
-       if (vpath->ringh) {
-               status = __vxge_hw_ring_reset(vpath->ringh);
-               if (status != VXGE_HW_OK)
-                       goto exit;
-       }
-
-       if (vpath->fifoh)
-               status = __vxge_hw_fifo_reset(vpath->fifoh);
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_prc_configure
- * This routine configures the prc registers of virtual path using the config
- * passed
- */
-static void
-__vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       struct vxge_hw_vp_config *vp_config;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       vpath = &hldev->virtual_paths[vp_id];
-       vp_reg = vpath->vp_reg;
-       vp_config = vpath->vp_config;
-
-       if (vp_config->ring.enable == VXGE_HW_RING_DISABLE)
-               return;
-
-       val64 = readq(&vp_reg->prc_cfg1);
-       val64 |= VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE;
-       writeq(val64, &vp_reg->prc_cfg1);
-
-       val64 = readq(&vpath->vp_reg->prc_cfg6);
-       val64 |= VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN;
-       writeq(val64, &vpath->vp_reg->prc_cfg6);
-
-       val64 = readq(&vp_reg->prc_cfg7);
-
-       if (vpath->vp_config->ring.scatter_mode !=
-               VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT) {
-
-               val64 &= ~VXGE_HW_PRC_CFG7_SCATTER_MODE(0x3);
-
-               switch (vpath->vp_config->ring.scatter_mode) {
-               case VXGE_HW_RING_SCATTER_MODE_A:
-                       val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE(
-                                       VXGE_HW_PRC_CFG7_SCATTER_MODE_A);
-                       break;
-               case VXGE_HW_RING_SCATTER_MODE_B:
-                       val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE(
-                                       VXGE_HW_PRC_CFG7_SCATTER_MODE_B);
-                       break;
-               case VXGE_HW_RING_SCATTER_MODE_C:
-                       val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE(
-                                       VXGE_HW_PRC_CFG7_SCATTER_MODE_C);
-                       break;
-               }
-       }
-
-       writeq(val64, &vp_reg->prc_cfg7);
-
-       writeq(VXGE_HW_PRC_CFG5_RXD0_ADD(
-                               __vxge_hw_ring_first_block_address_get(
-                                       vpath->ringh) >> 3), &vp_reg->prc_cfg5);
-
-       val64 = readq(&vp_reg->prc_cfg4);
-       val64 |= VXGE_HW_PRC_CFG4_IN_SVC;
-       val64 &= ~VXGE_HW_PRC_CFG4_RING_MODE(0x3);
-
-       val64 |= VXGE_HW_PRC_CFG4_RING_MODE(
-                       VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER);
-
-       if (hldev->config.rth_en == VXGE_HW_RTH_DISABLE)
-               val64 |= VXGE_HW_PRC_CFG4_RTH_DISABLE;
-       else
-               val64 &= ~VXGE_HW_PRC_CFG4_RTH_DISABLE;
-
-       writeq(val64, &vp_reg->prc_cfg4);
-}
-
-/*
- * __vxge_hw_vpath_kdfc_configure
- * This routine configures the kdfc registers of virtual path using the
- * config passed
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_kdfc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       u64 val64;
-       u64 vpath_stride;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_virtualpath *vpath;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       vpath = &hldev->virtual_paths[vp_id];
-       vp_reg = vpath->vp_reg;
-       status = __vxge_hw_kdfc_swapper_set(hldev->legacy_reg, vp_reg);
-
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       val64 = readq(&vp_reg->kdfc_drbl_triplet_total);
-
-       vpath->max_kdfc_db =
-               (u32)VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(
-                       val64+1)/2;
-
-       if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
-
-               vpath->max_nofl_db = vpath->max_kdfc_db;
-
-               if (vpath->max_nofl_db <
-                       ((vpath->vp_config->fifo.memblock_size /
-                       (vpath->vp_config->fifo.max_frags *
-                       sizeof(struct vxge_hw_fifo_txd))) *
-                       vpath->vp_config->fifo.fifo_blocks)) {
-
-                       return VXGE_HW_BADCFG_FIFO_BLOCKS;
-               }
-               val64 = VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(
-                               (vpath->max_nofl_db*2)-1);
-       }
-
-       writeq(val64, &vp_reg->kdfc_fifo_trpl_partition);
-
-       writeq(VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE,
-               &vp_reg->kdfc_fifo_trpl_ctrl);
-
-       val64 = readq(&vp_reg->kdfc_trpl_fifo_0_ctrl);
-
-       val64 &= ~(VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(0x3) |
-                  VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0xFF));
-
-       val64 |= VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(
-                VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY) |
-#ifndef __BIG_ENDIAN
-                VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN |
-#endif
-                VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0);
-
-       writeq(val64, &vp_reg->kdfc_trpl_fifo_0_ctrl);
-       writeq((u64)0, &vp_reg->kdfc_trpl_fifo_0_wb_address);
-       wmb();
-       vpath_stride = readq(&hldev->toc_reg->toc_kdfc_vpath_stride);
-
-       vpath->nofl_db =
-               (struct __vxge_hw_non_offload_db_wrapper __iomem *)
-               (hldev->kdfc + (vp_id *
-               VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(
-                                       vpath_stride)));
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vpath_mac_configure
- * This routine configures the mac of virtual path using the config passed
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       struct vxge_hw_vp_config *vp_config;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       vpath = &hldev->virtual_paths[vp_id];
-       vp_reg = vpath->vp_reg;
-       vp_config = vpath->vp_config;
-
-       writeq(VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(
-                       vpath->vsport_number), &vp_reg->xmac_vsport_choice);
-
-       if (vp_config->ring.enable == VXGE_HW_RING_ENABLE) {
-
-               val64 = readq(&vp_reg->xmac_rpa_vcfg);
-
-               if (vp_config->rpa_strip_vlan_tag !=
-                       VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) {
-                       if (vp_config->rpa_strip_vlan_tag)
-                               val64 |= VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG;
-                       else
-                               val64 &= ~VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG;
-               }
-
-               writeq(val64, &vp_reg->xmac_rpa_vcfg);
-               val64 = readq(&vp_reg->rxmac_vcfg0);
-
-               if (vp_config->mtu !=
-                               VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) {
-                       val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
-                       if ((vp_config->mtu  +
-                               VXGE_HW_MAC_HEADER_MAX_SIZE) < vpath->max_mtu)
-                               val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(
-                                       vp_config->mtu  +
-                                       VXGE_HW_MAC_HEADER_MAX_SIZE);
-                       else
-                               val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(
-                                       vpath->max_mtu);
-               }
-
-               writeq(val64, &vp_reg->rxmac_vcfg0);
-
-               val64 = readq(&vp_reg->rxmac_vcfg1);
-
-               val64 &= ~(VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(0x3) |
-                       VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE);
-
-               if (hldev->config.rth_it_type ==
-                               VXGE_HW_RTH_IT_TYPE_MULTI_IT) {
-                       val64 |= VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(
-                               0x2) |
-                               VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE;
-               }
-
-               writeq(val64, &vp_reg->rxmac_vcfg1);
-       }
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_vpath_tim_configure
- * This routine configures the tim registers of virtual path using the config
- * passed
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-       struct vxge_hw_vp_config *config;
-
-       vpath = &hldev->virtual_paths[vp_id];
-       vp_reg = vpath->vp_reg;
-       config = vpath->vp_config;
-
-       writeq(0, &vp_reg->tim_dest_addr);
-       writeq(0, &vp_reg->tim_vpath_map);
-       writeq(0, &vp_reg->tim_bitmap);
-       writeq(0, &vp_reg->tim_remap);
-
-       if (config->ring.enable == VXGE_HW_RING_ENABLE)
-               writeq(VXGE_HW_TIM_RING_ASSN_INT_NUM(
-                       (vp_id * VXGE_HW_MAX_INTR_PER_VP) +
-                       VXGE_HW_VPATH_INTR_RX), &vp_reg->tim_ring_assn);
-
-       val64 = readq(&vp_reg->tim_pci_cfg);
-       val64 |= VXGE_HW_TIM_PCI_CFG_ADD_PAD;
-       writeq(val64, &vp_reg->tim_pci_cfg);
-
-       if (config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
-
-               val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
-
-               if (config->tti.btimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
-                               0x3ffffff);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
-                                       config->tti.btimer_val);
-               }
-
-               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN;
-
-               if (config->tti.timer_ac_en != VXGE_HW_USE_FLASH_DEFAULT) {
-                       if (config->tti.timer_ac_en)
-                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
-                       else
-                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
-               }
-
-               if (config->tti.timer_ci_en != VXGE_HW_USE_FLASH_DEFAULT) {
-                       if (config->tti.timer_ci_en)
-                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
-                       else
-                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
-               }
-
-               if (config->tti.urange_a != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(
-                                       config->tti.urange_a);
-               }
-
-               if (config->tti.urange_b != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(
-                                       config->tti.urange_b);
-               }
-
-               if (config->tti.urange_c != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(
-                                       config->tti.urange_c);
-               }
-
-               writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
-               vpath->tim_tti_cfg1_saved = val64;
-
-               val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]);
-
-               if (config->tti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(
-                                               config->tti.uec_a);
-               }
-
-               if (config->tti.uec_b != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(
-                                               config->tti.uec_b);
-               }
-
-               if (config->tti.uec_c != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(
-                                               config->tti.uec_c);
-               }
-
-               if (config->tti.uec_d != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(
-                                               config->tti.uec_d);
-               }
-
-               writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]);
-               val64 = readq(&vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]);
-
-               if (config->tti.timer_ri_en != VXGE_HW_USE_FLASH_DEFAULT) {
-                       if (config->tti.timer_ri_en)
-                               val64 |= VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
-                       else
-                               val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
-               }
-
-               if (config->tti.rtimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
-                                       0x3ffffff);
-                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
-                                       config->tti.rtimer_val);
-               }
-
-               if (config->tti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(vp_id);
-               }
-
-               if (config->tti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
-                                       0x3ffffff);
-                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
-                                       config->tti.ltimer_val);
-               }
-
-               writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]);
-               vpath->tim_tti_cfg3_saved = val64;
-       }
-
-       if (config->ring.enable == VXGE_HW_RING_ENABLE) {
-
-               val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]);
-
-               if (config->rti.btimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
-                                       0x3ffffff);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(
-                                       config->rti.btimer_val);
-               }
-
-               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN;
-
-               if (config->rti.timer_ac_en != VXGE_HW_USE_FLASH_DEFAULT) {
-                       if (config->rti.timer_ac_en)
-                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
-                       else
-                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC;
-               }
-
-               if (config->rti.timer_ci_en != VXGE_HW_USE_FLASH_DEFAULT) {
-                       if (config->rti.timer_ci_en)
-                               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
-                       else
-                               val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
-               }
-
-               if (config->rti.urange_a != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(
-                                       config->rti.urange_a);
-               }
-
-               if (config->rti.urange_b != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(
-                                       config->rti.urange_b);
-               }
-
-               if (config->rti.urange_c != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(
-                                       config->rti.urange_c);
-               }
-
-               writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]);
-               vpath->tim_rti_cfg1_saved = val64;
-
-               val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]);
-
-               if (config->rti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(
-                                               config->rti.uec_a);
-               }
-
-               if (config->rti.uec_b != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(
-                                               config->rti.uec_b);
-               }
-
-               if (config->rti.uec_c != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(
-                                               config->rti.uec_c);
-               }
-
-               if (config->rti.uec_d != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(0xffff);
-                       val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(
-                                               config->rti.uec_d);
-               }
-
-               writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]);
-               val64 = readq(&vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]);
-
-               if (config->rti.timer_ri_en != VXGE_HW_USE_FLASH_DEFAULT) {
-                       if (config->rti.timer_ri_en)
-                               val64 |= VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
-                       else
-                               val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI;
-               }
-
-               if (config->rti.rtimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
-                                       0x3ffffff);
-                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(
-                                       config->rti.rtimer_val);
-               }
-
-               if (config->rti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f);
-                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(vp_id);
-               }
-
-               if (config->rti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) {
-                       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
-                                       0x3ffffff);
-                       val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(
-                                       config->rti.ltimer_val);
-               }
-
-               writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]);
-               vpath->tim_rti_cfg3_saved = val64;
-       }
-
-       val64 = 0;
-       writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_EINTA]);
-       writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_EINTA]);
-       writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_EINTA]);
-       writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_BMAP]);
-       writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_BMAP]);
-       writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_BMAP]);
-
-       val64 = VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_PRD(150);
-       val64 |= VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_DIV(0);
-       val64 |= VXGE_HW_TIM_WRKLD_CLC_CNT_RX_TX(3);
-       writeq(val64, &vp_reg->tim_wrkld_clc);
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_vpath_initialize
- * This routine is the final phase of init which initializes the
- * registers of the vpath using the configuration passed.
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       u64 val64;
-       u32 val32;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_virtualpath *vpath;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       vpath = &hldev->virtual_paths[vp_id];
-
-       if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) {
-               status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE;
-               goto exit;
-       }
-       vp_reg = vpath->vp_reg;
-
-       status =  __vxge_hw_vpath_swapper_set(vpath->vp_reg);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status =  __vxge_hw_vpath_mac_configure(hldev, vp_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status =  __vxge_hw_vpath_kdfc_configure(hldev, vp_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status = __vxge_hw_vpath_tim_configure(hldev, vp_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       val64 = readq(&vp_reg->rtdma_rd_optimization_ctrl);
-
-       /* Get MRRS value from device control */
-       status  = __vxge_hw_vpath_pci_read(vpath, 1, 0x78, &val32);
-       if (status == VXGE_HW_OK) {
-               val32 = (val32 & VXGE_HW_PCI_EXP_DEVCTL_READRQ) >> 12;
-               val64 &=
-                   ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(7));
-               val64 |=
-                   VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val32);
-
-               val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE;
-       }
-
-       val64 &= ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(7));
-       val64 |=
-           VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(
-                   VXGE_HW_MAX_PAYLOAD_SIZE_512);
-
-       val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN;
-       writeq(val64, &vp_reg->rtdma_rd_optimization_ctrl);
-
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_vp_terminate - Terminate Virtual Path structure
- * This routine closes all channels it opened and freeup memory
- */
-static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
-{
-       struct __vxge_hw_virtualpath *vpath;
-
-       vpath = &hldev->virtual_paths[vp_id];
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN)
-               goto exit;
-
-       VXGE_HW_DEVICE_TIM_INT_MASK_RESET(vpath->hldev->tim_int_mask0,
-               vpath->hldev->tim_int_mask1, vpath->vp_id);
-       hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL;
-
-       /* If the whole struct __vxge_hw_virtualpath is zeroed, nothing will
-        * work after the interface is brought down.
-        */
-       spin_lock(&vpath->lock);
-       vpath->vp_open = VXGE_HW_VP_NOT_OPEN;
-       spin_unlock(&vpath->lock);
-
-       vpath->vpmgmt_reg = NULL;
-       vpath->nofl_db = NULL;
-       vpath->max_mtu = 0;
-       vpath->vsport_number = 0;
-       vpath->max_kdfc_db = 0;
-       vpath->max_nofl_db = 0;
-       vpath->ringh = NULL;
-       vpath->fifoh = NULL;
-       memset(&vpath->vpath_handles, 0, sizeof(struct list_head));
-       vpath->stats_block = NULL;
-       vpath->hw_stats = NULL;
-       vpath->hw_stats_sav = NULL;
-       vpath->sw_stats = NULL;
-
-exit:
-       return;
-}
-
-/*
- * __vxge_hw_vp_initialize - Initialize Virtual Path structure
- * This routine is the initial phase of init which resets the vpath and
- * initializes the software support structures.
- */
-static enum vxge_hw_status
-__vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
-                       struct vxge_hw_vp_config *config)
-{
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) {
-               status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE;
-               goto exit;
-       }
-
-       vpath = &hldev->virtual_paths[vp_id];
-
-       spin_lock_init(&vpath->lock);
-       vpath->vp_id = vp_id;
-       vpath->vp_open = VXGE_HW_VP_OPEN;
-       vpath->hldev = hldev;
-       vpath->vp_config = config;
-       vpath->vp_reg = hldev->vpath_reg[vp_id];
-       vpath->vpmgmt_reg = hldev->vpmgmt_reg[vp_id];
-
-       __vxge_hw_vpath_reset(hldev, vp_id);
-
-       status = __vxge_hw_vpath_reset_check(vpath);
-       if (status != VXGE_HW_OK) {
-               memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_mgmt_read(hldev, vpath);
-       if (status != VXGE_HW_OK) {
-               memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
-               goto exit;
-       }
-
-       INIT_LIST_HEAD(&vpath->vpath_handles);
-
-       vpath->sw_stats = &hldev->stats.sw_dev_info_stats.vpath_info[vp_id];
-
-       VXGE_HW_DEVICE_TIM_INT_MASK_SET(hldev->tim_int_mask0,
-               hldev->tim_int_mask1, vp_id);
-
-       status = __vxge_hw_vpath_initialize(hldev, vp_id);
-       if (status != VXGE_HW_OK)
-               __vxge_hw_vp_terminate(hldev, vp_id);
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_mtu_set - Set MTU.
- * Set new MTU value. Example, to use jumbo frames:
- * vxge_hw_vpath_mtu_set(my_device, 9600);
- */
-enum vxge_hw_status
-vxge_hw_vpath_mtu_set(struct __vxge_hw_vpath_handle *vp, u32 new_mtu)
-{
-       u64 val64;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_virtualpath *vpath;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-       vpath = vp->vpath;
-
-       new_mtu += VXGE_HW_MAC_HEADER_MAX_SIZE;
-
-       if ((new_mtu < VXGE_HW_MIN_MTU) || (new_mtu > vpath->max_mtu))
-               status = VXGE_HW_ERR_INVALID_MTU_SIZE;
-
-       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
-
-       val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff);
-       val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(new_mtu);
-
-       writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
-
-       vpath->vp_config->mtu = new_mtu - VXGE_HW_MAC_HEADER_MAX_SIZE;
-
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_stats_enable - Enable vpath h/wstatistics.
- * Enable the DMA vpath statistics. The function is to be called to re-enable
- * the adapter to update stats into the host memory
- */
-static enum vxge_hw_status
-vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vp)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_virtualpath *vpath;
-
-       vpath = vp->vpath;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-
-       memcpy(vpath->hw_stats_sav, vpath->hw_stats,
-                       sizeof(struct vxge_hw_vpath_stats_hw_info));
-
-       status = __vxge_hw_vpath_stats_get(vpath, vpath->hw_stats);
-exit:
-       return status;
-}
-
-/*
- * __vxge_hw_blockpool_block_allocate - Allocates a block from block pool
- * This function allocates a block from block pool or from the system
- */
-static struct __vxge_hw_blockpool_entry *
-__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size)
-{
-       struct __vxge_hw_blockpool_entry *entry = NULL;
-       struct __vxge_hw_blockpool  *blockpool;
-
-       blockpool = &devh->block_pool;
-
-       if (size == blockpool->block_size) {
-
-               if (!list_empty(&blockpool->free_block_list))
-                       entry = (struct __vxge_hw_blockpool_entry *)
-                               list_first_entry(&blockpool->free_block_list,
-                                       struct __vxge_hw_blockpool_entry,
-                                       item);
-
-               if (entry != NULL) {
-                       list_del(&entry->item);
-                       blockpool->pool_size--;
-               }
-       }
-
-       if (entry != NULL)
-               __vxge_hw_blockpool_blocks_add(blockpool);
-
-       return entry;
-}
-
-/*
- * vxge_hw_vpath_open - Open a virtual path on a given adapter
- * This function is used to open access to virtual path of an
- * adapter for offload, GRO operations. This function returns
- * synchronously.
- */
-enum vxge_hw_status
-vxge_hw_vpath_open(struct __vxge_hw_device *hldev,
-                  struct vxge_hw_vpath_attr *attr,
-                  struct __vxge_hw_vpath_handle **vpath_handle)
-{
-       struct __vxge_hw_virtualpath *vpath;
-       struct __vxge_hw_vpath_handle *vp;
-       enum vxge_hw_status status;
-
-       vpath = &hldev->virtual_paths[attr->vp_id];
-
-       if (vpath->vp_open == VXGE_HW_VP_OPEN) {
-               status = VXGE_HW_ERR_INVALID_STATE;
-               goto vpath_open_exit1;
-       }
-
-       status = __vxge_hw_vp_initialize(hldev, attr->vp_id,
-                       &hldev->config.vp_config[attr->vp_id]);
-       if (status != VXGE_HW_OK)
-               goto vpath_open_exit1;
-
-       vp = vzalloc(sizeof(struct __vxge_hw_vpath_handle));
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto vpath_open_exit2;
-       }
-
-       vp->vpath = vpath;
-
-       if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) {
-               status = __vxge_hw_fifo_create(vp, &attr->fifo_attr);
-               if (status != VXGE_HW_OK)
-                       goto vpath_open_exit6;
-       }
-
-       if (vpath->vp_config->ring.enable == VXGE_HW_RING_ENABLE) {
-               status = __vxge_hw_ring_create(vp, &attr->ring_attr);
-               if (status != VXGE_HW_OK)
-                       goto vpath_open_exit7;
-
-               __vxge_hw_vpath_prc_configure(hldev, attr->vp_id);
-       }
-
-       vpath->fifoh->tx_intr_num =
-               (attr->vp_id * VXGE_HW_MAX_INTR_PER_VP)  +
-                       VXGE_HW_VPATH_INTR_TX;
-
-       vpath->stats_block = __vxge_hw_blockpool_block_allocate(hldev,
-                               VXGE_HW_BLOCK_SIZE);
-       if (vpath->stats_block == NULL) {
-               status = VXGE_HW_ERR_OUT_OF_MEMORY;
-               goto vpath_open_exit8;
-       }
-
-       vpath->hw_stats = vpath->stats_block->memblock;
-       memset(vpath->hw_stats, 0,
-               sizeof(struct vxge_hw_vpath_stats_hw_info));
-
-       hldev->stats.hw_dev_info_stats.vpath_info[attr->vp_id] =
-                                               vpath->hw_stats;
-
-       vpath->hw_stats_sav =
-               &hldev->stats.hw_dev_info_stats.vpath_info_sav[attr->vp_id];
-       memset(vpath->hw_stats_sav, 0,
-                       sizeof(struct vxge_hw_vpath_stats_hw_info));
-
-       writeq(vpath->stats_block->dma_addr, &vpath->vp_reg->stats_cfg);
-
-       status = vxge_hw_vpath_stats_enable(vp);
-       if (status != VXGE_HW_OK)
-               goto vpath_open_exit8;
-
-       list_add(&vp->item, &vpath->vpath_handles);
-
-       hldev->vpaths_deployed |= vxge_mBIT(vpath->vp_id);
-
-       *vpath_handle = vp;
-
-       attr->fifo_attr.userdata = vpath->fifoh;
-       attr->ring_attr.userdata = vpath->ringh;
-
-       return VXGE_HW_OK;
-
-vpath_open_exit8:
-       if (vpath->ringh != NULL)
-               __vxge_hw_ring_delete(vp);
-vpath_open_exit7:
-       if (vpath->fifoh != NULL)
-               __vxge_hw_fifo_delete(vp);
-vpath_open_exit6:
-       vfree(vp);
-vpath_open_exit2:
-       __vxge_hw_vp_terminate(hldev, attr->vp_id);
-vpath_open_exit1:
-
-       return status;
-}
-
-/**
- * vxge_hw_vpath_rx_doorbell_init - Close the handle got from previous vpath
- * (vpath) open
- * @vp: Handle got from previous vpath open
- *
- * This function is used to close access to virtual path opened
- * earlier.
- */
-void vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_virtualpath *vpath = vp->vpath;
-       struct __vxge_hw_ring *ring = vpath->ringh;
-       struct vxgedev *vdev = netdev_priv(vpath->hldev->ndev);
-       u64 new_count, val64, val164;
-
-       if (vdev->titan1) {
-               new_count = readq(&vpath->vp_reg->rxdmem_size);
-               new_count &= 0x1fff;
-       } else
-               new_count = ring->config->ring_blocks * VXGE_HW_BLOCK_SIZE / 8;
-
-       val164 = VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count);
-
-       writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val164),
-               &vpath->vp_reg->prc_rxd_doorbell);
-       readl(&vpath->vp_reg->prc_rxd_doorbell);
-
-       val164 /= 2;
-       val64 = readq(&vpath->vp_reg->prc_cfg6);
-       val64 = VXGE_HW_PRC_CFG6_RXD_SPAT(val64);
-       val64 &= 0x1ff;
-
-       /*
-        * Each RxD is of 4 qwords
-        */
-       new_count -= (val64 + 1);
-       val64 = min(val164, new_count) / 4;
-
-       ring->rxds_limit = min(ring->rxds_limit, val64);
-       if (ring->rxds_limit < 4)
-               ring->rxds_limit = 4;
-}
-
-/*
- * __vxge_hw_blockpool_block_free - Frees a block from block pool
- * @devh: Hal device
- * @entry: Entry of block to be freed
- *
- * This function frees a block from block pool
- */
-static void
-__vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh,
-                              struct __vxge_hw_blockpool_entry *entry)
-{
-       struct __vxge_hw_blockpool  *blockpool;
-
-       blockpool = &devh->block_pool;
-
-       if (entry->length == blockpool->block_size) {
-               list_add(&entry->item, &blockpool->free_block_list);
-               blockpool->pool_size++;
-       }
-
-       __vxge_hw_blockpool_blocks_remove(blockpool);
-}
-
-/*
- * vxge_hw_vpath_close - Close the handle got from previous vpath (vpath) open
- * This function is used to close access to virtual path opened
- * earlier.
- */
-enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_virtualpath *vpath = NULL;
-       struct __vxge_hw_device *devh = NULL;
-       u32 vp_id = vp->vpath->vp_id;
-       u32 is_empty = TRUE;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       vpath = vp->vpath;
-       devh = vpath->hldev;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto vpath_close_exit;
-       }
-
-       list_del(&vp->item);
-
-       if (!list_empty(&vpath->vpath_handles)) {
-               list_add(&vp->item, &vpath->vpath_handles);
-               is_empty = FALSE;
-       }
-
-       if (!is_empty) {
-               status = VXGE_HW_FAIL;
-               goto vpath_close_exit;
-       }
-
-       devh->vpaths_deployed &= ~vxge_mBIT(vp_id);
-
-       if (vpath->ringh != NULL)
-               __vxge_hw_ring_delete(vp);
-
-       if (vpath->fifoh != NULL)
-               __vxge_hw_fifo_delete(vp);
-
-       if (vpath->stats_block != NULL)
-               __vxge_hw_blockpool_block_free(devh, vpath->stats_block);
-
-       vfree(vp);
-
-       __vxge_hw_vp_terminate(devh, vp_id);
-
-vpath_close_exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_reset - Resets vpath
- * This function is used to request a reset of vpath
- */
-enum vxge_hw_status vxge_hw_vpath_reset(struct __vxge_hw_vpath_handle *vp)
-{
-       enum vxge_hw_status status;
-       u32 vp_id;
-       struct __vxge_hw_virtualpath *vpath = vp->vpath;
-
-       vp_id = vpath->vp_id;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_reset(vpath->hldev, vp_id);
-       if (status == VXGE_HW_OK)
-               vpath->sw_stats->soft_reset_cnt++;
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_recover_from_reset - Poll for reset complete and re-initialize.
- * This function poll's for the vpath reset completion and re initializes
- * the vpath.
- */
-enum vxge_hw_status
-vxge_hw_vpath_recover_from_reset(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_virtualpath *vpath = NULL;
-       enum vxge_hw_status status;
-       struct __vxge_hw_device *hldev;
-       u32 vp_id;
-
-       vp_id = vp->vpath->vp_id;
-       vpath = vp->vpath;
-       hldev = vpath->hldev;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_reset_check(vpath);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status = __vxge_hw_vpath_sw_reset(hldev, vp_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       status = __vxge_hw_vpath_initialize(hldev, vp_id);
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       if (vpath->ringh != NULL)
-               __vxge_hw_vpath_prc_configure(hldev, vp_id);
-
-       memset(vpath->hw_stats, 0,
-               sizeof(struct vxge_hw_vpath_stats_hw_info));
-
-       memset(vpath->hw_stats_sav, 0,
-               sizeof(struct vxge_hw_vpath_stats_hw_info));
-
-       writeq(vpath->stats_block->dma_addr,
-               &vpath->vp_reg->stats_cfg);
-
-       status = vxge_hw_vpath_stats_enable(vp);
-
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_enable - Enable vpath.
- * This routine clears the vpath reset thereby enabling a vpath
- * to start forwarding frames and generating interrupts.
- */
-void
-vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_device *hldev;
-       u64 val64;
-
-       hldev = vp->vpath->hldev;
-
-       val64 = VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(
-               1 << (16 - vp->vpath->vp_id));
-
-       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
-               &hldev->common_reg->cmn_rsthdlr_cfg1);
-}
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.h b/drivers/net/ethernet/neterion/vxge/vxge-config.h
deleted file mode 100644 (file)
index 0cd0750..0000000
+++ /dev/null
@@ -1,2086 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-config.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#ifndef VXGE_CONFIG_H
-#define VXGE_CONFIG_H
-#include <linux/hardirq.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-
-#ifndef VXGE_CACHE_LINE_SIZE
-#define VXGE_CACHE_LINE_SIZE 128
-#endif
-
-#ifndef VXGE_ALIGN
-#define VXGE_ALIGN(adrs, size) \
-       (((size) - (((u64)adrs) & ((size)-1))) & ((size)-1))
-#endif
-
-#define VXGE_HW_MIN_MTU                                ETH_MIN_MTU
-#define VXGE_HW_MAX_MTU                                9600
-#define VXGE_HW_DEFAULT_MTU                    1500
-
-#define VXGE_HW_MAX_ROM_IMAGES                 8
-
-struct eprom_image {
-       u8 is_valid:1;
-       u8 index;
-       u8 type;
-       u16 version;
-};
-
-#ifdef VXGE_DEBUG_ASSERT
-/**
- * vxge_assert
- * @test: C-condition to check
- * @fmt: printf like format string
- *
- * This function implements traditional assert. By default assertions
- * are enabled. It can be disabled by undefining VXGE_DEBUG_ASSERT macro in
- * compilation
- * time.
- */
-#define vxge_assert(test) BUG_ON(!(test))
-#else
-#define vxge_assert(test)
-#endif /* end of VXGE_DEBUG_ASSERT */
-
-/**
- * enum vxge_debug_level
- * @VXGE_NONE: debug disabled
- * @VXGE_ERR: all errors going to be logged out
- * @VXGE_TRACE: all errors plus all kind of verbose tracing print outs
- *                 going to be logged out. Very noisy.
- *
- * This enumeration going to be used to switch between different
- * debug levels during runtime if DEBUG macro defined during
- * compilation. If DEBUG macro not defined than code will be
- * compiled out.
- */
-enum vxge_debug_level {
-       VXGE_NONE   = 0,
-       VXGE_TRACE  = 1,
-       VXGE_ERR    = 2
-};
-
-#define NULL_VPID                                      0xFFFFFFFF
-#ifdef CONFIG_VXGE_DEBUG_TRACE_ALL
-#define VXGE_DEBUG_MODULE_MASK  0xffffffff
-#define VXGE_DEBUG_TRACE_MASK   0xffffffff
-#define VXGE_DEBUG_ERR_MASK     0xffffffff
-#define VXGE_DEBUG_MASK         0x000001ff
-#else
-#define VXGE_DEBUG_MODULE_MASK  0x20000000
-#define VXGE_DEBUG_TRACE_MASK   0x20000000
-#define VXGE_DEBUG_ERR_MASK     0x20000000
-#define VXGE_DEBUG_MASK         0x00000001
-#endif
-
-/*
- * @VXGE_COMPONENT_LL: do debug for vxge link layer module
- * @VXGE_COMPONENT_ALL: activate debug for all modules with no exceptions
- *
- * This enumeration going to be used to distinguish modules
- * or libraries during compilation and runtime.  Makefile must declare
- * VXGE_DEBUG_MODULE_MASK macro and set it to proper value.
- */
-#define        VXGE_COMPONENT_LL                               0x20000000
-#define        VXGE_COMPONENT_ALL                              0xffffffff
-
-#define VXGE_HW_BASE_INF       100
-#define VXGE_HW_BASE_ERR       200
-#define VXGE_HW_BASE_BADCFG    300
-
-enum vxge_hw_status {
-       VXGE_HW_OK                                = 0,
-       VXGE_HW_FAIL                              = 1,
-       VXGE_HW_PENDING                           = 2,
-       VXGE_HW_COMPLETIONS_REMAIN                = 3,
-
-       VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS = VXGE_HW_BASE_INF + 1,
-       VXGE_HW_INF_OUT_OF_DESCRIPTORS            = VXGE_HW_BASE_INF + 2,
-
-       VXGE_HW_ERR_INVALID_HANDLE                = VXGE_HW_BASE_ERR + 1,
-       VXGE_HW_ERR_OUT_OF_MEMORY                 = VXGE_HW_BASE_ERR + 2,
-       VXGE_HW_ERR_VPATH_NOT_AVAILABLE           = VXGE_HW_BASE_ERR + 3,
-       VXGE_HW_ERR_VPATH_NOT_OPEN                = VXGE_HW_BASE_ERR + 4,
-       VXGE_HW_ERR_WRONG_IRQ                     = VXGE_HW_BASE_ERR + 5,
-       VXGE_HW_ERR_SWAPPER_CTRL                  = VXGE_HW_BASE_ERR + 6,
-       VXGE_HW_ERR_INVALID_MTU_SIZE              = VXGE_HW_BASE_ERR + 7,
-       VXGE_HW_ERR_INVALID_INDEX                 = VXGE_HW_BASE_ERR + 8,
-       VXGE_HW_ERR_INVALID_TYPE                  = VXGE_HW_BASE_ERR + 9,
-       VXGE_HW_ERR_INVALID_OFFSET                = VXGE_HW_BASE_ERR + 10,
-       VXGE_HW_ERR_INVALID_DEVICE                = VXGE_HW_BASE_ERR + 11,
-       VXGE_HW_ERR_VERSION_CONFLICT              = VXGE_HW_BASE_ERR + 12,
-       VXGE_HW_ERR_INVALID_PCI_INFO              = VXGE_HW_BASE_ERR + 13,
-       VXGE_HW_ERR_INVALID_TCODE                 = VXGE_HW_BASE_ERR + 14,
-       VXGE_HW_ERR_INVALID_BLOCK_SIZE            = VXGE_HW_BASE_ERR + 15,
-       VXGE_HW_ERR_INVALID_STATE                 = VXGE_HW_BASE_ERR + 16,
-       VXGE_HW_ERR_PRIVILEGED_OPERATION          = VXGE_HW_BASE_ERR + 17,
-       VXGE_HW_ERR_INVALID_PORT                  = VXGE_HW_BASE_ERR + 18,
-       VXGE_HW_ERR_FIFO                          = VXGE_HW_BASE_ERR + 19,
-       VXGE_HW_ERR_VPATH                         = VXGE_HW_BASE_ERR + 20,
-       VXGE_HW_ERR_CRITICAL                      = VXGE_HW_BASE_ERR + 21,
-       VXGE_HW_ERR_SLOT_FREEZE                   = VXGE_HW_BASE_ERR + 22,
-
-       VXGE_HW_BADCFG_RING_INDICATE_MAX_PKTS     = VXGE_HW_BASE_BADCFG + 1,
-       VXGE_HW_BADCFG_FIFO_BLOCKS                = VXGE_HW_BASE_BADCFG + 2,
-       VXGE_HW_BADCFG_VPATH_MTU                  = VXGE_HW_BASE_BADCFG + 3,
-       VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG   = VXGE_HW_BASE_BADCFG + 4,
-       VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH        = VXGE_HW_BASE_BADCFG + 5,
-       VXGE_HW_BADCFG_INTR_MODE                  = VXGE_HW_BASE_BADCFG + 6,
-       VXGE_HW_BADCFG_RTS_MAC_EN                 = VXGE_HW_BASE_BADCFG + 7,
-
-       VXGE_HW_EOF_TRACE_BUF                     = -1
-};
-
-/**
- * enum enum vxge_hw_device_link_state - Link state enumeration.
- * @VXGE_HW_LINK_NONE: Invalid link state.
- * @VXGE_HW_LINK_DOWN: Link is down.
- * @VXGE_HW_LINK_UP: Link is up.
- *
- */
-enum vxge_hw_device_link_state {
-       VXGE_HW_LINK_NONE,
-       VXGE_HW_LINK_DOWN,
-       VXGE_HW_LINK_UP
-};
-
-/**
- * enum enum vxge_hw_fw_upgrade_code - FW upgrade return codes.
- * @VXGE_HW_FW_UPGRADE_OK: All OK send next 16 bytes
- * @VXGE_HW_FW_UPGRADE_DONE:  upload completed
- * @VXGE_HW_FW_UPGRADE_ERR:  upload error
- * @VXGE_FW_UPGRADE_BYTES2SKIP:  skip bytes in the stream
- *
- */
-enum vxge_hw_fw_upgrade_code {
-       VXGE_HW_FW_UPGRADE_OK           = 0,
-       VXGE_HW_FW_UPGRADE_DONE         = 1,
-       VXGE_HW_FW_UPGRADE_ERR          = 2,
-       VXGE_FW_UPGRADE_BYTES2SKIP      = 3
-};
-
-/**
- * enum enum vxge_hw_fw_upgrade_err_code - FW upgrade error codes.
- * @VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1: corrupt data
- * @VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW: buffer overflow
- * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3: invalid .ncf file
- * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4: invalid .ncf file
- * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5: invalid .ncf file
- * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6: invalid .ncf file
- * @VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7: corrupt data
- * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8: invalid .ncf file
- * @VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN: generic error unknown type
- * @VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH: failed to flash image check failed
- */
-enum vxge_hw_fw_upgrade_err_code {
-       VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1           = 1,
-       VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW          = 2,
-       VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3           = 3,
-       VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4           = 4,
-       VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5           = 5,
-       VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6           = 6,
-       VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7           = 7,
-       VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8           = 8,
-       VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN    = 9,
-       VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH          = 10
-};
-
-/**
- * struct vxge_hw_device_date - Date Format
- * @day: Day
- * @month: Month
- * @year: Year
- * @date: Date in string format
- *
- * Structure for returning date
- */
-
-#define VXGE_HW_FW_STRLEN      32
-struct vxge_hw_device_date {
-       u32     day;
-       u32     month;
-       u32     year;
-       char    date[VXGE_HW_FW_STRLEN];
-};
-
-struct vxge_hw_device_version {
-       u32     major;
-       u32     minor;
-       u32     build;
-       char    version[VXGE_HW_FW_STRLEN];
-};
-
-/**
- * struct vxge_hw_fifo_config - Configuration of fifo.
- * @enable: Is this fifo to be commissioned
- * @fifo_blocks: Numbers of TxDL (that is, lists of Tx descriptors)
- *             blocks per queue.
- * @max_frags: Max number of Tx buffers per TxDL (that is, per single
- *             transmit operation).
- *             No more than 256 transmit buffers can be specified.
- * @memblock_size: Fifo descriptors are allocated in blocks of @mem_block_size
- *             bytes. Setting @memblock_size to page size ensures
- *             by-page allocation of descriptors. 128K bytes is the
- *             maximum supported block size.
- * @alignment_size: per Tx fragment DMA-able memory used to align transmit data
- *             (e.g., to align on a cache line).
- * @intr: Boolean. Use 1 to generate interrupt for each completed TxDL.
- *             Use 0 otherwise.
- * @no_snoop_bits: If non-zero, specifies no-snoop PCI operation,
- *             which generally improves latency of the host bridge operation
- *             (see PCI specification). For valid values please refer
- *             to struct vxge_hw_fifo_config{} in the driver sources.
- * Configuration of all Titan fifos.
- * Note: Valid (min, max) range for each attribute is specified in the body of
- * the struct vxge_hw_fifo_config{} structure.
- */
-struct vxge_hw_fifo_config {
-       u32                             enable;
-#define VXGE_HW_FIFO_ENABLE                            1
-#define VXGE_HW_FIFO_DISABLE                           0
-
-       u32                             fifo_blocks;
-#define VXGE_HW_MIN_FIFO_BLOCKS                                2
-#define VXGE_HW_MAX_FIFO_BLOCKS                                128
-
-       u32                             max_frags;
-#define VXGE_HW_MIN_FIFO_FRAGS                         1
-#define VXGE_HW_MAX_FIFO_FRAGS                         256
-
-       u32                             memblock_size;
-#define VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE                 VXGE_HW_BLOCK_SIZE
-#define VXGE_HW_MAX_FIFO_MEMBLOCK_SIZE                 131072
-#define VXGE_HW_DEF_FIFO_MEMBLOCK_SIZE                 8096
-
-       u32                             alignment_size;
-#define VXGE_HW_MIN_FIFO_ALIGNMENT_SIZE                0
-#define VXGE_HW_MAX_FIFO_ALIGNMENT_SIZE                65536
-#define VXGE_HW_DEF_FIFO_ALIGNMENT_SIZE                VXGE_CACHE_LINE_SIZE
-
-       u32                             intr;
-#define VXGE_HW_FIFO_QUEUE_INTR_ENABLE                 1
-#define VXGE_HW_FIFO_QUEUE_INTR_DISABLE                        0
-#define VXGE_HW_FIFO_QUEUE_INTR_DEFAULT                        0
-
-       u32                             no_snoop_bits;
-#define VXGE_HW_FIFO_NO_SNOOP_DISABLED                 0
-#define VXGE_HW_FIFO_NO_SNOOP_TXD                      1
-#define VXGE_HW_FIFO_NO_SNOOP_FRM                      2
-#define VXGE_HW_FIFO_NO_SNOOP_ALL                      3
-#define VXGE_HW_FIFO_NO_SNOOP_DEFAULT                  0
-
-};
-/**
- * struct vxge_hw_ring_config - Ring configurations.
- * @enable: Is this ring to be commissioned
- * @ring_blocks: Numbers of RxD blocks in the ring
- * @buffer_mode: Receive buffer mode (1, 2, 3, or 5); for details please refer
- *             to Titan User Guide.
- * @scatter_mode: Titan supports two receive scatter modes: A and B.
- *             For details please refer to Titan User Guide.
- * @rx_timer_val: The number of 32ns periods that would be counted between two
- *             timer interrupts.
- * @greedy_return: If Set it forces the device to return absolutely all RxD
- *             that are consumed and still on board when a timer interrupt
- *             triggers. If Clear, then if the device has already returned
- *             RxD before current timer interrupt triggered and after the
- *             previous timer interrupt triggered, then the device is not
- *             forced to returned the rest of the consumed RxD that it has
- *             on board which account for a byte count less than the one
- *             programmed into PRC_CFG6.RXD_CRXDT field
- * @rx_timer_ci: TBD
- * @backoff_interval_us: Time (in microseconds), after which Titan
- *             tries to download RxDs posted by the host.
- *             Note that the "backoff" does not happen if host posts receive
- *             descriptors in the timely fashion.
- * Ring configuration.
- */
-struct vxge_hw_ring_config {
-       u32                             enable;
-#define VXGE_HW_RING_ENABLE                                    1
-#define VXGE_HW_RING_DISABLE                                   0
-#define VXGE_HW_RING_DEFAULT                                   1
-
-       u32                             ring_blocks;
-#define VXGE_HW_MIN_RING_BLOCKS                                        1
-#define VXGE_HW_MAX_RING_BLOCKS                                        128
-#define VXGE_HW_DEF_RING_BLOCKS                                        2
-
-       u32                             buffer_mode;
-#define VXGE_HW_RING_RXD_BUFFER_MODE_1                         1
-#define VXGE_HW_RING_RXD_BUFFER_MODE_3                         3
-#define VXGE_HW_RING_RXD_BUFFER_MODE_5                         5
-#define VXGE_HW_RING_RXD_BUFFER_MODE_DEFAULT                   1
-
-       u32                             scatter_mode;
-#define VXGE_HW_RING_SCATTER_MODE_A                            0
-#define VXGE_HW_RING_SCATTER_MODE_B                            1
-#define VXGE_HW_RING_SCATTER_MODE_C                            2
-#define VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT            0xffffffff
-
-       u64                             rxds_limit;
-#define VXGE_HW_DEF_RING_RXDS_LIMIT                            44
-};
-
-/**
- * struct vxge_hw_vp_config - Configuration of virtual path
- * @vp_id: Virtual Path Id
- * @min_bandwidth: Minimum Guaranteed bandwidth
- * @ring: See struct vxge_hw_ring_config{}.
- * @fifo: See struct vxge_hw_fifo_config{}.
- * @tti: Configuration of interrupt associated with Transmit.
- *             see struct vxge_hw_tim_intr_config();
- * @rti: Configuration of interrupt associated with Receive.
- *              see struct vxge_hw_tim_intr_config();
- * @mtu: mtu size used on this port.
- * @rpa_strip_vlan_tag: Strip VLAN Tag enable/disable. Instructs the device to
- *             remove the VLAN tag from all received tagged frames that are not
- *             replicated at the internal L2 switch.
- *             0 - Do not strip the VLAN tag.
- *             1 - Strip the VLAN tag. Regardless of this setting, VLAN tags are
- *                 always placed into the RxDMA descriptor.
- *
- * This structure is used by the driver to pass the configuration parameters to
- * configure Virtual Path.
- */
-struct vxge_hw_vp_config {
-       u32                             vp_id;
-
-#define        VXGE_HW_VPATH_PRIORITY_MIN                      0
-#define        VXGE_HW_VPATH_PRIORITY_MAX                      16
-#define        VXGE_HW_VPATH_PRIORITY_DEFAULT                  0
-
-       u32                             min_bandwidth;
-#define        VXGE_HW_VPATH_BANDWIDTH_MIN                     0
-#define        VXGE_HW_VPATH_BANDWIDTH_MAX                     100
-#define        VXGE_HW_VPATH_BANDWIDTH_DEFAULT                 0
-
-       struct vxge_hw_ring_config              ring;
-       struct vxge_hw_fifo_config              fifo;
-       struct vxge_hw_tim_intr_config  tti;
-       struct vxge_hw_tim_intr_config  rti;
-
-       u32                             mtu;
-#define VXGE_HW_VPATH_MIN_INITIAL_MTU                  VXGE_HW_MIN_MTU
-#define VXGE_HW_VPATH_MAX_INITIAL_MTU                  VXGE_HW_MAX_MTU
-#define VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU    0xffffffff
-
-       u32                             rpa_strip_vlan_tag;
-#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE                        1
-#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE               0
-#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT     0xffffffff
-
-};
-/**
- * struct vxge_hw_device_config - Device configuration.
- * @dma_blockpool_initial: Initial size of DMA Pool
- * @dma_blockpool_max: Maximum blocks in DMA pool
- * @intr_mode: Line, or MSI-X interrupt.
- *
- * @rth_en: Enable Receive Traffic Hashing(RTH) using IT(Indirection Table).
- * @rth_it_type: RTH IT table programming type
- * @rts_mac_en: Enable Receive Traffic Steering using MAC destination address
- * @vp_config: Configuration for virtual paths
- * @device_poll_millis: Specify the interval (in mulliseconds)
- *                     to wait for register reads
- *
- * Titan configuration.
- * Contains per-device configuration parameters, including:
- * - stats sampling interval, etc.
- *
- * In addition, struct vxge_hw_device_config{} includes "subordinate"
- * configurations, including:
- * - fifos and rings;
- * - MAC (done at firmware level).
- *
- * See Titan User Guide for more details.
- * Note: Valid (min, max) range for each attribute is specified in the body of
- * the struct vxge_hw_device_config{} structure. Please refer to the
- * corresponding include file.
- * See also: struct vxge_hw_tim_intr_config{}.
- */
-struct vxge_hw_device_config {
-       u32                                     device_poll_millis;
-#define VXGE_HW_MIN_DEVICE_POLL_MILLIS         1
-#define VXGE_HW_MAX_DEVICE_POLL_MILLIS         100000
-#define VXGE_HW_DEF_DEVICE_POLL_MILLIS         1000
-
-       u32                                     dma_blockpool_initial;
-       u32                                     dma_blockpool_max;
-#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE                0
-#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE    0
-#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE       4
-#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE                4096
-
-#define        VXGE_HW_MAX_PAYLOAD_SIZE_512            2
-
-       u32                                     intr_mode:2,
-#define VXGE_HW_INTR_MODE_IRQLINE              0
-#define VXGE_HW_INTR_MODE_MSIX                 1
-#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT                2
-
-#define VXGE_HW_INTR_MODE_DEF                  0
-
-                                               rth_en:1,
-#define VXGE_HW_RTH_DISABLE                    0
-#define VXGE_HW_RTH_ENABLE                     1
-#define VXGE_HW_RTH_DEFAULT                    0
-
-                                               rth_it_type:1,
-#define VXGE_HW_RTH_IT_TYPE_SOLO_IT            0
-#define VXGE_HW_RTH_IT_TYPE_MULTI_IT           1
-#define VXGE_HW_RTH_IT_TYPE_DEFAULT            0
-
-                                               rts_mac_en:1,
-#define VXGE_HW_RTS_MAC_DISABLE                        0
-#define VXGE_HW_RTS_MAC_ENABLE                 1
-#define VXGE_HW_RTS_MAC_DEFAULT                        0
-
-                                               hwts_en:1;
-#define        VXGE_HW_HWTS_DISABLE                    0
-#define        VXGE_HW_HWTS_ENABLE                     1
-#define        VXGE_HW_HWTS_DEFAULT                    1
-
-       struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS];
-};
-
-/**
- * function vxge_uld_link_up_f - Link-Up callback provided by driver.
- * @devh: HW device handle.
- * Link-up notification callback provided by the driver.
- * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}.
- *
- * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_down_f{},
- * vxge_hw_driver_initialize().
- */
-
-/**
- * function vxge_uld_link_down_f - Link-Down callback provided by
- * driver.
- * @devh: HW device handle.
- *
- * Link-Down notification callback provided by the driver.
- * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}.
- *
- * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{},
- * vxge_hw_driver_initialize().
- */
-
-/**
- * function vxge_uld_crit_err_f - Critical Error notification callback.
- * @devh: HW device handle.
- * (typically - at HW device iinitialization time).
- * @type: Enumerated hw error, e.g.: double ECC.
- * @serr_data: Titan status.
- * @ext_data: Extended data. The contents depends on the @type.
- *
- * Link-Down notification callback provided by the driver.
- * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}.
- *
- * See also: struct vxge_hw_uld_cbs{}, enum vxge_hw_event{},
- * vxge_hw_driver_initialize().
- */
-
-/**
- * struct vxge_hw_uld_cbs - driver "slow-path" callbacks.
- * @link_up: See vxge_uld_link_up_f{}.
- * @link_down: See vxge_uld_link_down_f{}.
- * @crit_err: See vxge_uld_crit_err_f{}.
- *
- * Driver slow-path (per-driver) callbacks.
- * Implemented by driver and provided to HW via
- * vxge_hw_driver_initialize().
- * Note that these callbacks are not mandatory: HW will not invoke
- * a callback if NULL is specified.
- *
- * See also: vxge_hw_driver_initialize().
- */
-struct vxge_hw_uld_cbs {
-       void (*link_up)(struct __vxge_hw_device *devh);
-       void (*link_down)(struct __vxge_hw_device *devh);
-       void (*crit_err)(struct __vxge_hw_device *devh,
-                       enum vxge_hw_event type, u64 ext_data);
-};
-
-/*
- * struct __vxge_hw_blockpool_entry - Block private data structure
- * @item: List header used to link.
- * @length: Length of the block
- * @memblock: Virtual address block
- * @dma_addr: DMA Address of the block.
- * @dma_handle: DMA handle of the block.
- * @acc_handle: DMA acc handle
- *
- * Block is allocated with a header to put the blocks into list.
- *
- */
-struct __vxge_hw_blockpool_entry {
-       struct list_head        item;
-       u32                     length;
-       void                    *memblock;
-       dma_addr_t              dma_addr;
-       struct pci_dev          *dma_handle;
-       struct pci_dev          *acc_handle;
-};
-
-/*
- * struct __vxge_hw_blockpool - Block Pool
- * @hldev: HW device
- * @block_size: size of each block.
- * @Pool_size: Number of blocks in the pool
- * @pool_max: Maximum number of blocks above which to free additional blocks
- * @req_out: Number of block requests with OS out standing
- * @free_block_list: List of free blocks
- *
- * Block pool contains the DMA blocks preallocated.
- *
- */
-struct __vxge_hw_blockpool {
-       struct __vxge_hw_device *hldev;
-       u32                             block_size;
-       u32                             pool_size;
-       u32                             pool_max;
-       u32                             req_out;
-       struct list_head                free_block_list;
-       struct list_head                free_entry_list;
-};
-
-/*
- * enum enum __vxge_hw_channel_type - Enumerated channel types.
- * @VXGE_HW_CHANNEL_TYPE_UNKNOWN: Unknown channel.
- * @VXGE_HW_CHANNEL_TYPE_FIFO: fifo.
- * @VXGE_HW_CHANNEL_TYPE_RING: ring.
- * @VXGE_HW_CHANNEL_TYPE_MAX: Maximum number of HW-supported
- * (and recognized) channel types. Currently: 2.
- *
- * Enumerated channel types. Currently there are only two link-layer
- * channels - Titan fifo and Titan ring. In the future the list will grow.
- */
-enum __vxge_hw_channel_type {
-       VXGE_HW_CHANNEL_TYPE_UNKNOWN                    = 0,
-       VXGE_HW_CHANNEL_TYPE_FIFO                       = 1,
-       VXGE_HW_CHANNEL_TYPE_RING                       = 2,
-       VXGE_HW_CHANNEL_TYPE_MAX                        = 3
-};
-
-/*
- * struct __vxge_hw_channel
- * @item: List item; used to maintain a list of open channels.
- * @type: Channel type. See enum vxge_hw_channel_type{}.
- * @devh: Device handle. HW device object that contains _this_ channel.
- * @vph: Virtual path handle. Virtual Path Object that contains _this_ channel.
- * @length: Channel length. Currently allocated number of descriptors.
- *          The channel length "grows" when more descriptors get allocated.
- *          See _hw_mempool_grow.
- * @reserve_arr: Reserve array. Contains descriptors that can be reserved
- *               by driver for the subsequent send or receive operation.
- *               See vxge_hw_fifo_txdl_reserve(),
- *               vxge_hw_ring_rxd_reserve().
- * @reserve_ptr: Current pointer in the resrve array
- * @reserve_top: Reserve top gives the maximum number of dtrs available in
- *          reserve array.
- * @work_arr: Work array. Contains descriptors posted to the channel.
- *            Note that at any point in time @work_arr contains 3 types of
- *            descriptors:
- *            1) posted but not yet consumed by Titan device;
- *            2) consumed but not yet completed;
- *            3) completed but not yet freed
- *            (via vxge_hw_fifo_txdl_free() or vxge_hw_ring_rxd_free())
- * @post_index: Post index. At any point in time points on the
- *              position in the channel, which'll contain next to-be-posted
- *              descriptor.
- * @compl_index: Completion index. At any point in time points on the
- *               position in the channel, which will contain next
- *               to-be-completed descriptor.
- * @free_arr: Free array. Contains completed descriptors that were freed
- *            (i.e., handed over back to HW) by driver.
- *            See vxge_hw_fifo_txdl_free(), vxge_hw_ring_rxd_free().
- * @free_ptr: current pointer in free array
- * @per_dtr_space: Per-descriptor space (in bytes) that channel user can utilize
- *                 to store per-operation control information.
- * @stats: Pointer to common statistics
- * @userdata: Per-channel opaque (void*) user-defined context, which may be
- *            driver object, ULP connection, etc.
- *            Once channel is open, @userdata is passed back to user via
- *            vxge_hw_channel_callback_f.
- *
- * HW channel object.
- *
- * See also: enum vxge_hw_channel_type{}, enum vxge_hw_channel_flag
- */
-struct __vxge_hw_channel {
-       struct list_head                item;
-       enum __vxge_hw_channel_type     type;
-       struct __vxge_hw_device         *devh;
-       struct __vxge_hw_vpath_handle   *vph;
-       u32                     length;
-       u32                     vp_id;
-       void            **reserve_arr;
-       u32                     reserve_ptr;
-       u32                     reserve_top;
-       void            **work_arr;
-       u32                     post_index ____cacheline_aligned;
-       u32                     compl_index ____cacheline_aligned;
-       void            **free_arr;
-       u32                     free_ptr;
-       void            **orig_arr;
-       u32                     per_dtr_space;
-       void            *userdata;
-       struct vxge_hw_common_reg       __iomem *common_reg;
-       u32                     first_vp_id;
-       struct vxge_hw_vpath_stats_sw_common_info *stats;
-
-} ____cacheline_aligned;
-
-/*
- * struct __vxge_hw_virtualpath - Virtual Path
- *
- * @vp_id: Virtual path id
- * @vp_open: This flag specifies if vxge_hw_vp_open is called from LL Driver
- * @hldev: Hal device
- * @vp_config: Virtual Path Config
- * @vp_reg: VPATH Register map address in BAR0
- * @vpmgmt_reg: VPATH_MGMT register map address
- * @max_mtu: Max mtu that can be supported
- * @vsport_number: vsport attached to this vpath
- * @max_kdfc_db: Maximum kernel mode doorbells
- * @max_nofl_db: Maximum non offload doorbells
- * @tx_intr_num: Interrupt Number associated with the TX
-
- * @ringh: Ring Queue
- * @fifoh: FIFO Queue
- * @vpath_handles: Virtual Path handles list
- * @stats_block: Memory for DMAing stats
- * @stats: Vpath statistics
- *
- * Virtual path structure to encapsulate the data related to a virtual path.
- * Virtual paths are allocated by the HW upon getting configuration from the
- * driver and inserted into the list of virtual paths.
- */
-struct __vxge_hw_virtualpath {
-       u32                             vp_id;
-
-       u32                             vp_open;
-#define VXGE_HW_VP_NOT_OPEN    0
-#define        VXGE_HW_VP_OPEN         1
-
-       struct __vxge_hw_device         *hldev;
-       struct vxge_hw_vp_config        *vp_config;
-       struct vxge_hw_vpath_reg        __iomem *vp_reg;
-       struct vxge_hw_vpmgmt_reg       __iomem *vpmgmt_reg;
-       struct __vxge_hw_non_offload_db_wrapper __iomem *nofl_db;
-
-       u32                             max_mtu;
-       u32                             vsport_number;
-       u32                             max_kdfc_db;
-       u32                             max_nofl_db;
-       u64                             tim_tti_cfg1_saved;
-       u64                             tim_tti_cfg3_saved;
-       u64                             tim_rti_cfg1_saved;
-       u64                             tim_rti_cfg3_saved;
-
-       struct __vxge_hw_ring *____cacheline_aligned ringh;
-       struct __vxge_hw_fifo *____cacheline_aligned fifoh;
-       struct list_head                vpath_handles;
-       struct __vxge_hw_blockpool_entry                *stats_block;
-       struct vxge_hw_vpath_stats_hw_info      *hw_stats;
-       struct vxge_hw_vpath_stats_hw_info      *hw_stats_sav;
-       struct vxge_hw_vpath_stats_sw_info      *sw_stats;
-       spinlock_t lock;
-};
-
-/*
- * struct __vxge_hw_vpath_handle - List item to store callback information
- * @item: List head to keep the item in linked list
- * @vpath: Virtual path to which this item belongs
- *
- * This structure is used to store the callback information.
- */
-struct __vxge_hw_vpath_handle {
-       struct list_head        item;
-       struct __vxge_hw_virtualpath    *vpath;
-};
-
-/*
- * struct __vxge_hw_device
- *
- * HW device object.
- */
-/**
- * struct __vxge_hw_device  - Hal device object
- * @magic: Magic Number
- * @bar0: BAR0 virtual address.
- * @pdev: Physical device handle
- * @config: Confguration passed by the LL driver at initialization
- * @link_state: Link state
- *
- * HW device object. Represents Titan adapter
- */
-struct __vxge_hw_device {
-       u32                             magic;
-#define VXGE_HW_DEVICE_MAGIC           0x12345678
-#define VXGE_HW_DEVICE_DEAD            0xDEADDEAD
-       void __iomem                    *bar0;
-       struct pci_dev                  *pdev;
-       struct net_device               *ndev;
-       struct vxge_hw_device_config    config;
-       enum vxge_hw_device_link_state  link_state;
-
-       const struct vxge_hw_uld_cbs    *uld_callbacks;
-
-       u32                             host_type;
-       u32                             func_id;
-       u32                             access_rights;
-#define VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH      0x1
-#define VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM     0x2
-#define VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM     0x4
-       struct vxge_hw_legacy_reg       __iomem *legacy_reg;
-       struct vxge_hw_toc_reg          __iomem *toc_reg;
-       struct vxge_hw_common_reg       __iomem *common_reg;
-       struct vxge_hw_mrpcim_reg       __iomem *mrpcim_reg;
-       struct vxge_hw_srpcim_reg       __iomem *srpcim_reg \
-                                       [VXGE_HW_TITAN_SRPCIM_REG_SPACES];
-       struct vxge_hw_vpmgmt_reg       __iomem *vpmgmt_reg \
-                                       [VXGE_HW_TITAN_VPMGMT_REG_SPACES];
-       struct vxge_hw_vpath_reg        __iomem *vpath_reg \
-                                       [VXGE_HW_TITAN_VPATH_REG_SPACES];
-       u8                              __iomem *kdfc;
-       u8                              __iomem *usdc;
-       struct __vxge_hw_virtualpath    virtual_paths \
-                                       [VXGE_HW_MAX_VIRTUAL_PATHS];
-       u64                             vpath_assignments;
-       u64                             vpaths_deployed;
-       u32                             first_vp_id;
-       u64                             tim_int_mask0[4];
-       u32                             tim_int_mask1[4];
-
-       struct __vxge_hw_blockpool      block_pool;
-       struct vxge_hw_device_stats     stats;
-       u32                             debug_module_mask;
-       u32                             debug_level;
-       u32                             level_err;
-       u32                             level_trace;
-       u16 eprom_versions[VXGE_HW_MAX_ROM_IMAGES];
-};
-
-#define VXGE_HW_INFO_LEN       64
-/**
- * struct vxge_hw_device_hw_info - Device information
- * @host_type: Host Type
- * @func_id: Function Id
- * @vpath_mask: vpath bit mask
- * @fw_version: Firmware version
- * @fw_date: Firmware Date
- * @flash_version: Firmware version
- * @flash_date: Firmware Date
- * @mac_addrs: Mac addresses for each vpath
- * @mac_addr_masks: Mac address masks for each vpath
- *
- * Returns the vpath mask that has the bits set for each vpath allocated
- * for the driver and the first mac address for each vpath
- */
-struct vxge_hw_device_hw_info {
-       u32             host_type;
-#define VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION                    0
-#define VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION                     1
-#define VXGE_HW_NO_MR_SR_VH0_FUNCTION0                         2
-#define VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION                  3
-#define VXGE_HW_MR_SR_VH0_INVALID_CONFIG                       4
-#define VXGE_HW_SR_VH_FUNCTION0                                        5
-#define VXGE_HW_SR_VH_VIRTUAL_FUNCTION                         6
-#define VXGE_HW_VH_NORMAL_FUNCTION                             7
-       u64             function_mode;
-#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION                  0
-#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION                   1
-#define VXGE_HW_FUNCTION_MODE_SRIOV                            2
-#define VXGE_HW_FUNCTION_MODE_MRIOV                            3
-#define VXGE_HW_FUNCTION_MODE_MRIOV_8                          4
-#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17                        5
-#define VXGE_HW_FUNCTION_MODE_SRIOV_8                          6
-#define VXGE_HW_FUNCTION_MODE_SRIOV_4                          7
-#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2                 8
-#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_4                 9
-#define VXGE_HW_FUNCTION_MODE_MRIOV_4                          10
-
-       u32             func_id;
-       u64             vpath_mask;
-       struct vxge_hw_device_version fw_version;
-       struct vxge_hw_device_date    fw_date;
-       struct vxge_hw_device_version flash_version;
-       struct vxge_hw_device_date    flash_date;
-       u8              serial_number[VXGE_HW_INFO_LEN];
-       u8              part_number[VXGE_HW_INFO_LEN];
-       u8              product_desc[VXGE_HW_INFO_LEN];
-       u8 mac_addrs[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
-       u8 mac_addr_masks[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN];
-};
-
-/**
- * struct vxge_hw_device_attr - Device memory spaces.
- * @bar0: BAR0 virtual address.
- * @pdev: PCI device object.
- *
- * Device memory spaces. Includes configuration, BAR0 etc. per device
- * mapped memories. Also, includes a pointer to OS-specific PCI device object.
- */
-struct vxge_hw_device_attr {
-       void __iomem            *bar0;
-       struct pci_dev          *pdev;
-       const struct vxge_hw_uld_cbs *uld_callbacks;
-};
-
-#define VXGE_HW_DEVICE_LINK_STATE_SET(hldev, ls)       (hldev->link_state = ls)
-
-#define VXGE_HW_DEVICE_TIM_INT_MASK_SET(m0, m1, i) {   \
-       if (i < 16) {                           \
-               m0[0] |= vxge_vBIT(0x8, (i*4), 4);      \
-               m0[1] |= vxge_vBIT(0x4, (i*4), 4);      \
-       }                                       \
-       else {                                  \
-               m1[0] = 0x80000000;             \
-               m1[1] = 0x40000000;             \
-       }                                       \
-}
-
-#define VXGE_HW_DEVICE_TIM_INT_MASK_RESET(m0, m1, i) { \
-       if (i < 16) {                                   \
-               m0[0] &= ~vxge_vBIT(0x8, (i*4), 4);             \
-               m0[1] &= ~vxge_vBIT(0x4, (i*4), 4);             \
-       }                                               \
-       else {                                          \
-               m1[0] = 0;                              \
-               m1[1] = 0;                              \
-       }                                               \
-}
-
-#define VXGE_HW_DEVICE_STATS_PIO_READ(loc, offset) {           \
-       status = vxge_hw_mrpcim_stats_access(hldev, \
-                               VXGE_HW_STATS_OP_READ, \
-                               loc, \
-                               offset, \
-                               &val64);                        \
-       if (status != VXGE_HW_OK)                               \
-               return status;                                          \
-}
-
-/*
- * struct __vxge_hw_ring - Ring channel.
- * @channel: Channel "base" of this ring, the common part of all HW
- *           channels.
- * @mempool: Memory pool, the pool from which descriptors get allocated.
- *           (See vxge_hw_mm.h).
- * @config: Ring configuration, part of device configuration
- *          (see struct vxge_hw_device_config{}).
- * @ring_length: Length of the ring
- * @buffer_mode: 1, 3, or 5. The value specifies a receive buffer mode,
- *          as per Titan User Guide.
- * @rxd_size: RxD sizes for 1-, 3- or 5- buffer modes. As per Titan spec,
- *            1-buffer mode descriptor is 32 byte long, etc.
- * @rxd_priv_size: Per RxD size reserved (by HW) for driver to keep
- *                 per-descriptor data (e.g., DMA handle for Solaris)
- * @per_rxd_space: Per rxd space requested by driver
- * @rxds_per_block: Number of descriptors per hardware-defined RxD
- *                  block. Depends on the (1-, 3-, 5-) buffer mode.
- * @rxdblock_priv_size: Reserved at the end of each RxD block. HW internal
- *                      usage. Not to confuse with @rxd_priv_size.
- * @cmpl_cnt: Completion counter. Is reset to zero upon entering the ISR.
- * @callback: Channel completion callback. HW invokes the callback when there
- *            are new completions on that channel. In many implementations
- *            the @callback executes in the hw interrupt context.
- * @rxd_init: Channel's descriptor-initialize callback.
- *            See vxge_hw_ring_rxd_init_f{}.
- *            If not NULL, HW invokes the callback when opening
- *            the ring.
- * @rxd_term: Channel's descriptor-terminate callback. If not NULL,
- *          HW invokes the callback when closing the corresponding channel.
- *          See also vxge_hw_channel_rxd_term_f{}.
- * @stats: Statistics for ring
- * Ring channel.
- *
- * Note: The structure is cache line aligned to better utilize
- *       CPU cache performance.
- */
-struct __vxge_hw_ring {
-       struct __vxge_hw_channel                channel;
-       struct vxge_hw_mempool                  *mempool;
-       struct vxge_hw_vpath_reg                __iomem *vp_reg;
-       struct vxge_hw_common_reg               __iomem *common_reg;
-       u32                                     ring_length;
-       u32                                     buffer_mode;
-       u32                                     rxd_size;
-       u32                                     rxd_priv_size;
-       u32                                     per_rxd_space;
-       u32                                     rxds_per_block;
-       u32                                     rxdblock_priv_size;
-       u32                                     cmpl_cnt;
-       u32                                     vp_id;
-       u32                                     doorbell_cnt;
-       u32                                     total_db_cnt;
-       u64                                     rxds_limit;
-       u32                                     rtimer;
-       u64                                     tim_rti_cfg1_saved;
-       u64                                     tim_rti_cfg3_saved;
-
-       enum vxge_hw_status (*callback)(
-                       struct __vxge_hw_ring *ringh,
-                       void *rxdh,
-                       u8 t_code,
-                       void *userdata);
-
-       enum vxge_hw_status (*rxd_init)(
-                       void *rxdh,
-                       void *userdata);
-
-       void (*rxd_term)(
-                       void *rxdh,
-                       enum vxge_hw_rxd_state state,
-                       void *userdata);
-
-       struct vxge_hw_vpath_stats_sw_ring_info *stats  ____cacheline_aligned;
-       struct vxge_hw_ring_config              *config;
-} ____cacheline_aligned;
-
-/**
- * enum enum vxge_hw_txdl_state - Descriptor (TXDL) state.
- * @VXGE_HW_TXDL_STATE_NONE: Invalid state.
- * @VXGE_HW_TXDL_STATE_AVAIL: Descriptor is available for reservation.
- * @VXGE_HW_TXDL_STATE_POSTED: Descriptor is posted for processing by the
- * device.
- * @VXGE_HW_TXDL_STATE_FREED: Descriptor is free and can be reused for
- * filling-in and posting later.
- *
- * Titan/HW descriptor states.
- *
- */
-enum vxge_hw_txdl_state {
-       VXGE_HW_TXDL_STATE_NONE = 0,
-       VXGE_HW_TXDL_STATE_AVAIL        = 1,
-       VXGE_HW_TXDL_STATE_POSTED       = 2,
-       VXGE_HW_TXDL_STATE_FREED        = 3
-};
-/*
- * struct __vxge_hw_fifo - Fifo.
- * @channel: Channel "base" of this fifo, the common part of all HW
- *             channels.
- * @mempool: Memory pool, from which descriptors get allocated.
- * @config: Fifo configuration, part of device configuration
- *             (see struct vxge_hw_device_config{}).
- * @interrupt_type: Interrupt type to be used
- * @no_snoop_bits: See struct vxge_hw_fifo_config{}.
- * @txdl_per_memblock: Number of TxDLs (TxD lists) per memblock.
- *             on TxDL please refer to Titan UG.
- * @txdl_size: Configured TxDL size (i.e., number of TxDs in a list), plus
- *             per-TxDL HW private space (struct __vxge_hw_fifo_txdl_priv).
- * @priv_size: Per-Tx descriptor space reserved for driver
- *             usage.
- * @per_txdl_space: Per txdl private space for the driver
- * @callback: Fifo completion callback. HW invokes the callback when there
- *             are new completions on that fifo. In many implementations
- *             the @callback executes in the hw interrupt context.
- * @txdl_term: Fifo's descriptor-terminate callback. If not NULL,
- *             HW invokes the callback when closing the corresponding fifo.
- *             See also vxge_hw_fifo_txdl_term_f{}.
- * @stats: Statistics of this fifo
- *
- * Fifo channel.
- * Note: The structure is cache line aligned.
- */
-struct __vxge_hw_fifo {
-       struct __vxge_hw_channel                channel;
-       struct vxge_hw_mempool                  *mempool;
-       struct vxge_hw_fifo_config              *config;
-       struct vxge_hw_vpath_reg                __iomem *vp_reg;
-       struct __vxge_hw_non_offload_db_wrapper __iomem *nofl_db;
-       u64                                     interrupt_type;
-       u32                                     no_snoop_bits;
-       u32                                     txdl_per_memblock;
-       u32                                     txdl_size;
-       u32                                     priv_size;
-       u32                                     per_txdl_space;
-       u32                                     vp_id;
-       u32                                     tx_intr_num;
-       u32                                     rtimer;
-       u64                                     tim_tti_cfg1_saved;
-       u64                                     tim_tti_cfg3_saved;
-
-       enum vxge_hw_status (*callback)(
-                       struct __vxge_hw_fifo *fifo_handle,
-                       void *txdlh,
-                       enum vxge_hw_fifo_tcode t_code,
-                       void *userdata,
-                       struct sk_buff ***skb_ptr,
-                       int nr_skb,
-                       int *more);
-
-       void (*txdl_term)(
-                       void *txdlh,
-                       enum vxge_hw_txdl_state state,
-                       void *userdata);
-
-       struct vxge_hw_vpath_stats_sw_fifo_info *stats ____cacheline_aligned;
-} ____cacheline_aligned;
-
-/*
- * struct __vxge_hw_fifo_txdl_priv - Transmit descriptor HW-private data.
- * @dma_addr: DMA (mapped) address of _this_ descriptor.
- * @dma_handle: DMA handle used to map the descriptor onto device.
- * @dma_offset: Descriptor's offset in the memory block. HW allocates
- *      descriptors in memory blocks (see struct vxge_hw_fifo_config{})
- *             Each memblock is a contiguous block of DMA-able memory.
- * @frags: Total number of fragments (that is, contiguous data buffers)
- * carried by this TxDL.
- * @align_vaddr_start: Aligned virtual address start
- * @align_vaddr: Virtual address of the per-TxDL area in memory used for
- *             alignement. Used to place one or more mis-aligned fragments
- * @align_dma_addr: DMA address translated from the @align_vaddr.
- * @align_dma_handle: DMA handle that corresponds to @align_dma_addr.
- * @align_dma_acch: DMA access handle corresponds to @align_dma_addr.
- * @align_dma_offset: The current offset into the @align_vaddr area.
- * Grows while filling the descriptor, gets reset.
- * @align_used_frags: Number of fragments used.
- * @alloc_frags: Total number of fragments allocated.
- * @unused: TODO
- * @next_txdl_priv: (TODO).
- * @first_txdp: (TODO).
- * @linked_txdl_priv: Pointer to any linked TxDL for creating contiguous
- *             TxDL list.
- * @txdlh: Corresponding txdlh to this TxDL.
- * @memblock: Pointer to the TxDL memory block or memory page.
- *             on the next send operation.
- * @dma_object: DMA address and handle of the memory block that contains
- *             the descriptor. This member is used only in the "checked"
- *             version of the HW (to enforce certain assertions);
- *             otherwise it gets compiled out.
- * @allocated: True if the descriptor is reserved, 0 otherwise. Internal usage.
- *
- * Per-transmit decsriptor HW-private data. HW uses the space to keep DMA
- * information associated with the descriptor. Note that driver can ask HW
- * to allocate additional per-descriptor space for its own (driver-specific)
- * purposes.
- *
- * See also: struct vxge_hw_ring_rxd_priv{}.
- */
-struct __vxge_hw_fifo_txdl_priv {
-       dma_addr_t              dma_addr;
-       struct pci_dev  *dma_handle;
-       ptrdiff_t               dma_offset;
-       u32                             frags;
-       u8                              *align_vaddr_start;
-       u8                              *align_vaddr;
-       dma_addr_t              align_dma_addr;
-       struct pci_dev  *align_dma_handle;
-       struct pci_dev  *align_dma_acch;
-       ptrdiff_t               align_dma_offset;
-       u32                             align_used_frags;
-       u32                             alloc_frags;
-       u32                             unused;
-       struct __vxge_hw_fifo_txdl_priv *next_txdl_priv;
-       struct vxge_hw_fifo_txd         *first_txdp;
-       void                    *memblock;
-};
-
-/*
- * struct __vxge_hw_non_offload_db_wrapper - Non-offload Doorbell Wrapper
- * @control_0: Bits 0 to 7 - Doorbell type.
- *             Bits 8 to 31 - Reserved.
- *             Bits 32 to 39 - The highest TxD in this TxDL.
- *             Bits 40 to 47 - Reserved.
-       *              Bits 48 to 55 - Reserved.
- *             Bits 56 to 63 - No snoop flags.
- * @txdl_ptr:  The starting location of the TxDL in host memory.
- *
- * Created by the host and written to the adapter via PIO to a Kernel Doorbell
- * FIFO. All non-offload doorbell wrapper fields must be written by the host as
- * part of a doorbell write. Consumed by the adapter but is not written by the
- * adapter.
- */
-struct __vxge_hw_non_offload_db_wrapper {
-       u64             control_0;
-#define        VXGE_HW_NODBW_GET_TYPE(ctrl0)                   vxge_bVALn(ctrl0, 0, 8)
-#define VXGE_HW_NODBW_TYPE(val) vxge_vBIT(val, 0, 8)
-#define        VXGE_HW_NODBW_TYPE_NODBW                                0
-
-#define        VXGE_HW_NODBW_GET_LAST_TXD_NUMBER(ctrl0)        vxge_bVALn(ctrl0, 32, 8)
-#define VXGE_HW_NODBW_LAST_TXD_NUMBER(val) vxge_vBIT(val, 32, 8)
-
-#define        VXGE_HW_NODBW_GET_NO_SNOOP(ctrl0)               vxge_bVALn(ctrl0, 56, 8)
-#define VXGE_HW_NODBW_LIST_NO_SNOOP(val) vxge_vBIT(val, 56, 8)
-#define        VXGE_HW_NODBW_LIST_NO_SNOOP_TXD_READ_TXD0_WRITE         0x2
-#define        VXGE_HW_NODBW_LIST_NO_SNOOP_TX_FRAME_DATA_READ          0x1
-
-       u64             txdl_ptr;
-};
-
-/*
- * TX Descriptor
- */
-
-/**
- * struct vxge_hw_fifo_txd - Transmit Descriptor
- * @control_0: Bits 0 to 6 - Reserved.
- *             Bit 7 - List Ownership. This field should be initialized
- *             to '1' by the driver before the transmit list pointer is
- *             written to the adapter. This field will be set to '0' by the
- *             adapter once it has completed transmitting the frame or frames in
- *             the list. Note - This field is only valid in TxD0. Additionally,
- *             for multi-list sequences, the driver should not release any
- *             buffers until the ownership of the last list in the multi-list
- *             sequence has been returned to the host.
- *             Bits 8 to 11 - Reserved
- *             Bits 12 to 15 - Transfer_Code. This field is only valid in
- *             TxD0. It is used to describe the status of the transmit data
- *             buffer transfer. This field is always overwritten by the
- *             adapter, so this field may be initialized to any value.
- *             Bits 16 to 17 - Host steering. This field allows the host to
- *             override the selection of the physical transmit port.
- *             Attention:
- *             Normal sounds as if learned from the switch rather than from
- *             the aggregation algorythms.
- *             00: Normal. Use Destination/MAC Address
- *             lookup to determine the transmit port.
- *             01: Send on physical Port1.
- *             10: Send on physical Port0.
- *            11: Send on both ports.
- *             Bits 18 to 21 - Reserved
- *             Bits 22 to 23 - Gather_Code. This field is set by the host and
- *             is used to describe how individual buffers comprise a frame.
- *             10: First descriptor of a frame.
- *             00: Middle of a multi-descriptor frame.
- *             01: Last descriptor of a frame.
- *             11: First and last descriptor of a frame (the entire frame
- *             resides in a single buffer).
- *             For multi-descriptor frames, the only valid gather code sequence
- *             is {10, [00], 01}. In other words, the descriptors must be placed
- *             in the list in the correct order.
- *             Bits 24 to 27 - Reserved
- *             Bits 28 to 29 - LSO_Frm_Encap. LSO Frame Encapsulation
- *             definition. Only valid in TxD0. This field allows the host to
- *             indicate the Ethernet encapsulation of an outbound LSO packet.
- *             00 - classic mode (best guess)
- *             01 - LLC
- *             10 - SNAP
- *             11 - DIX
- *             If "classic mode" is selected, the adapter will attempt to
- *             decode the frame's Ethernet encapsulation by examining the L/T
- *             field as follows:
- *             <= 0x05DC LLC/SNAP encoding; must examine DSAP/SSAP to determine
- *             if packet is IPv4 or IPv6.
- *             0x8870 Jumbo-SNAP encoding.
- *             0x0800 IPv4 DIX encoding
- *             0x86DD IPv6 DIX encoding
- *             others illegal encapsulation
- *             Bits 30 - LSO_ Flag. Large Send Offload (LSO) flag.
- *             Set to 1 to perform segmentation offload for TCP/UDP.
- *             This field is valid only in TxD0.
- *             Bits 31 to 33 - Reserved.
- *             Bits 34 to 47 - LSO_MSS. TCP/UDP LSO Maximum Segment Size
- *             This field is meaningful only when LSO_Control is non-zero.
- *             When LSO_Control is set to TCP_LSO, the single (possibly large)
- *             TCP segment described by this TxDL will be sent as a series of
- *             TCP segments each of which contains no more than LSO_MSS
- *             payload bytes.
- *             When LSO_Control is set to UDP_LSO, the single (possibly large)
- *             UDP datagram described by this TxDL will be sent as a series of
- *             UDP datagrams each of which contains no more than LSO_MSS
- *             payload bytes.
- *             All outgoing frames from this TxDL will have LSO_MSS bytes of UDP
- *             or TCP payload, with the exception of the last, which will have
- *             <= LSO_MSS bytes of payload.
- *             Bits 48 to 63 - Buffer_Size. Number of valid bytes in the
- *             buffer to be read by the adapter. This field is written by the
- *             host. A value of 0 is illegal.
- *            Bits 32 to 63 - This value is written by the adapter upon
- *            completion of a UDP or TCP LSO operation and indicates the number
- *             of UDP or TCP payload bytes that were transmitted. 0x0000 will be
- *             returned for any non-LSO operation.
- * @control_1: Bits 0 to 4 - Reserved.
- *             Bit 5 - Tx_CKO_IPv4 Set to a '1' to enable IPv4 header checksum
- *             offload. This field is only valid in the first TxD of a frame.
- *             Bit 6 - Tx_CKO_TCP Set to a '1' to enable TCP checksum offload.
- *             This field is only valid in the first TxD of a frame (the TxD's
- *             gather code must be 10 or 11). The driver should only set this
- *             bit if it can guarantee that TCP is present.
- *             Bit 7 - Tx_CKO_UDP Set to a '1' to enable UDP checksum offload.
- *             This field is only valid in the first TxD of a frame (the TxD's
- *             gather code must be 10 or 11). The driver should only set this
- *             bit if it can guarantee that UDP is present.
- *             Bits 8 to 14 - Reserved.
- *             Bit 15 - Tx_VLAN_Enable VLAN tag insertion flag. Set to a '1' to
- *             instruct the adapter to insert the VLAN tag specified by the
- *             Tx_VLAN_Tag field. This field is only valid in the first TxD of
- *             a frame.
- *             Bits 16 to 31 - Tx_VLAN_Tag. Variable portion of the VLAN tag
- *             to be inserted into the frame by the adapter (the first two bytes
- *             of a VLAN tag are always 0x8100). This field is only valid if the
- *             Tx_VLAN_Enable field is set to '1'.
- *             Bits 32 to 33 - Reserved.
- *             Bits 34 to 39 - Tx_Int_Number. Indicates which Tx interrupt
- *             number the frame associated with. This field is written by the
- *             host. It is only valid in the first TxD of a frame.
- *             Bits 40 to 42 - Reserved.
- *             Bit 43 - Set to 1 to exclude the frame from bandwidth metering
- *             functions. This field is valid only in the first TxD
- *             of a frame.
- *             Bits 44 to 45 - Reserved.
- *             Bit 46 - Tx_Int_Per_List Set to a '1' to instruct the adapter to
- *             generate an interrupt as soon as all of the frames in the list
- *             have been transmitted. In order to have per-frame interrupts,
- *             the driver should place a maximum of one frame per list. This
- *             field is only valid in the first TxD of a frame.
- *             Bit 47 - Tx_Int_Utilization Set to a '1' to instruct the adapter
- *             to count the frame toward the utilization interrupt specified in
- *             the Tx_Int_Number field. This field is only valid in the first
- *             TxD of a frame.
- *             Bits 48 to 63 - Reserved.
- * @buffer_pointer: Buffer start address.
- * @host_control: Host_Control.Opaque 64bit data stored by driver inside the
- *            Titan descriptor prior to posting the latter on the fifo
- *            via vxge_hw_fifo_txdl_post().The %host_control is returned as is
- *            to the driver with each completed descriptor.
- *
- * Transmit descriptor (TxD).Fifo descriptor contains configured number
- * (list) of TxDs. * For more details please refer to Titan User Guide,
- * Section 5.4.2 "Transmit Descriptor (TxD) Format".
- */
-struct vxge_hw_fifo_txd {
-       u64 control_0;
-#define VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER              vxge_mBIT(7)
-
-#define VXGE_HW_FIFO_TXD_T_CODE_GET(ctrl0)             vxge_bVALn(ctrl0, 12, 4)
-#define VXGE_HW_FIFO_TXD_T_CODE(val)                   vxge_vBIT(val, 12, 4)
-#define VXGE_HW_FIFO_TXD_T_CODE_UNUSED         VXGE_HW_FIFO_T_CODE_UNUSED
-
-
-#define VXGE_HW_FIFO_TXD_GATHER_CODE(val)              vxge_vBIT(val, 22, 2)
-#define VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST     VXGE_HW_FIFO_GATHER_CODE_FIRST
-#define VXGE_HW_FIFO_TXD_GATHER_CODE_LAST      VXGE_HW_FIFO_GATHER_CODE_LAST
-
-
-#define VXGE_HW_FIFO_TXD_LSO_EN                                vxge_mBIT(30)
-
-#define VXGE_HW_FIFO_TXD_LSO_MSS(val)                  vxge_vBIT(val, 34, 14)
-
-#define VXGE_HW_FIFO_TXD_BUFFER_SIZE(val)              vxge_vBIT(val, 48, 16)
-
-       u64 control_1;
-#define VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN                        vxge_mBIT(5)
-#define VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN                 vxge_mBIT(6)
-#define VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN                 vxge_mBIT(7)
-#define VXGE_HW_FIFO_TXD_VLAN_ENABLE                   vxge_mBIT(15)
-
-#define VXGE_HW_FIFO_TXD_VLAN_TAG(val)                         vxge_vBIT(val, 16, 16)
-
-#define VXGE_HW_FIFO_TXD_INT_NUMBER(val)               vxge_vBIT(val, 34, 6)
-
-#define VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST             vxge_mBIT(46)
-#define VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ                        vxge_mBIT(47)
-
-       u64 buffer_pointer;
-
-       u64 host_control;
-};
-
-/**
- * struct vxge_hw_ring_rxd_1 - One buffer mode RxD for ring
- * @host_control: This field is exclusively for host use and is "readonly"
- *             from the adapter's perspective.
- * @control_0:Bits 0 to 6 - RTH_Bucket get
- *           Bit 7 - Own Descriptor ownership bit. This bit is set to 1
- *            by the host, and is set to 0 by the adapter.
- *           0 - Host owns RxD and buffer.
- *           1 - The adapter owns RxD and buffer.
- *           Bit 8 - Fast_Path_Eligible When set, indicates that the
- *            received frame meets all of the criteria for fast path processing.
- *            The required criteria are as follows:
- *            !SYN &
- *            (Transfer_Code == "Transfer OK") &
- *            (!Is_IP_Fragment) &
- *            ((Is_IPv4 & computed_L3_checksum == 0xFFFF) |
- *            (Is_IPv6)) &
- *            ((Is_TCP & computed_L4_checksum == 0xFFFF) |
- *            (Is_UDP & (computed_L4_checksum == 0xFFFF |
- *            computed _L4_checksum == 0x0000)))
- *            (same meaning for all RxD buffer modes)
- *           Bit 9 - L3 Checksum Correct
- *           Bit 10 - L4 Checksum Correct
- *           Bit 11 - Reserved
- *           Bit 12 to 15 - This field is written by the adapter. It is
- *            used to report the status of the frame transfer to the host.
- *           0x0 - Transfer OK
- *           0x4 - RDA Failure During Transfer
- *           0x5 - Unparseable Packet, such as unknown IPv6 header.
- *           0x6 - Frame integrity error (FCS or ECC).
- *           0x7 - Buffer Size Error. The provided buffer(s) were not
- *                  appropriately sized and data loss occurred.
- *           0x8 - Internal ECC Error. RxD corrupted.
- *           0x9 - IPv4 Checksum error
- *           0xA - TCP/UDP Checksum error
- *           0xF - Unknown Error or Multiple Error. Indicates an
- *               unknown problem or that more than one of transfer codes is set.
- *           Bit 16 - SYN The adapter sets this field to indicate that
- *                the incoming frame contained a TCP segment with its SYN bit
- *               set and its ACK bit NOT set. (same meaning for all RxD buffer
- *                modes)
- *           Bit 17 - Is ICMP
- *           Bit 18 - RTH_SPDM_HIT Set to 1 if there was a match in the
- *                Socket Pair Direct Match Table and the frame was steered based
- *                on SPDM.
- *           Bit 19 - RTH_IT_HIT Set to 1 if there was a match in the
- *            Indirection Table and the frame was steered based on hash
- *            indirection.
- *           Bit 20 to 23 - RTH_HASH_TYPE Indicates the function (hash
- *               type) that was used to calculate the hash.
- *           Bit 19 - IS_VLAN Set to '1' if the frame was/is VLAN
- *               tagged.
- *           Bit 25 to 26 - ETHER_ENCAP Reflects the Ethernet encapsulation
- *                of the received frame.
- *           0x0 - Ethernet DIX
- *           0x1 - LLC
- *           0x2 - SNAP (includes Jumbo-SNAP)
- *           0x3 - IPX
- *           Bit 27 - IS_IPV4 Set to '1' if the frame contains an IPv4 packet.
- *           Bit 28 - IS_IPV6 Set to '1' if the frame contains an IPv6 packet.
- *           Bit 29 - IS_IP_FRAG Set to '1' if the frame contains a fragmented
- *            IP packet.
- *           Bit 30 - IS_TCP Set to '1' if the frame contains a TCP segment.
- *           Bit 31 - IS_UDP Set to '1' if the frame contains a UDP message.
- *           Bit 32 to 47 - L3_Checksum[0:15] The IPv4 checksum value  that
- *            arrived with the frame. If the resulting computed IPv4 header
- *            checksum for the frame did not produce the expected 0xFFFF value,
- *            then the transfer code would be set to 0x9.
- *           Bit 48 to 63 - L4_Checksum[0:15] The TCP/UDP checksum value that
- *            arrived with the frame. If the resulting computed TCP/UDP checksum
- *            for the frame did not produce the expected 0xFFFF value, then the
- *            transfer code would be set to 0xA.
- * @control_1:Bits 0 to 1 - Reserved
- *            Bits 2 to 15 - Buffer0_Size.This field is set by the host and
- *            eventually overwritten by the adapter. The host writes the
- *            available buffer size in bytes when it passes the descriptor to
- *            the adapter. When a frame is delivered the host, the adapter
- *            populates this field with the number of bytes written into the
- *            buffer. The largest supported buffer is 16, 383 bytes.
- *           Bit 16 to 47 - RTH Hash Value 32-bit RTH hash value. Only valid if
- *           RTH_HASH_TYPE (Control_0, bits 20:23) is nonzero.
- *           Bit 48 to 63 - VLAN_Tag[0:15] The contents of the variable portion
- *            of the VLAN tag, if one was detected by the adapter. This field is
- *            populated even if VLAN-tag stripping is enabled.
- * @buffer0_ptr: Pointer to buffer. This field is populated by the driver.
- *
- * One buffer mode RxD for ring structure
- */
-struct vxge_hw_ring_rxd_1 {
-       u64 host_control;
-       u64 control_0;
-#define VXGE_HW_RING_RXD_RTH_BUCKET_GET(ctrl0)         vxge_bVALn(ctrl0, 0, 7)
-
-#define VXGE_HW_RING_RXD_LIST_OWN_ADAPTER              vxge_mBIT(7)
-
-#define VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(ctrl0) vxge_bVALn(ctrl0, 8, 1)
-
-#define VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(ctrl0)   vxge_bVALn(ctrl0, 9, 1)
-
-#define VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(ctrl0)   vxge_bVALn(ctrl0, 10, 1)
-
-#define VXGE_HW_RING_RXD_T_CODE_GET(ctrl0)             vxge_bVALn(ctrl0, 12, 4)
-#define VXGE_HW_RING_RXD_T_CODE(val)                   vxge_vBIT(val, 12, 4)
-
-#define VXGE_HW_RING_RXD_T_CODE_UNUSED         VXGE_HW_RING_T_CODE_UNUSED
-
-#define VXGE_HW_RING_RXD_SYN_GET(ctrl0)                vxge_bVALn(ctrl0, 16, 1)
-
-#define VXGE_HW_RING_RXD_IS_ICMP_GET(ctrl0)            vxge_bVALn(ctrl0, 17, 1)
-
-#define VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(ctrl0)       vxge_bVALn(ctrl0, 18, 1)
-
-#define VXGE_HW_RING_RXD_RTH_IT_HIT_GET(ctrl0)         vxge_bVALn(ctrl0, 19, 1)
-
-#define VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(ctrl0)      vxge_bVALn(ctrl0, 20, 4)
-
-#define VXGE_HW_RING_RXD_IS_VLAN_GET(ctrl0)            vxge_bVALn(ctrl0, 24, 1)
-
-#define VXGE_HW_RING_RXD_ETHER_ENCAP_GET(ctrl0)                vxge_bVALn(ctrl0, 25, 2)
-
-#define VXGE_HW_RING_RXD_FRAME_PROTO_GET(ctrl0)                vxge_bVALn(ctrl0, 27, 5)
-
-#define VXGE_HW_RING_RXD_L3_CKSUM_GET(ctrl0)   vxge_bVALn(ctrl0, 32, 16)
-
-#define VXGE_HW_RING_RXD_L4_CKSUM_GET(ctrl0)   vxge_bVALn(ctrl0, 48, 16)
-
-       u64 control_1;
-
-#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(ctrl1)     vxge_bVALn(ctrl1, 2, 14)
-#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE(val) vxge_vBIT(val, 2, 14)
-#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK           vxge_vBIT(0x3FFF, 2, 14)
-
-#define VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(ctrl1)    vxge_bVALn(ctrl1, 16, 32)
-
-#define VXGE_HW_RING_RXD_VLAN_TAG_GET(ctrl1)   vxge_bVALn(ctrl1, 48, 16)
-
-       u64 buffer0_ptr;
-};
-
-enum vxge_hw_rth_algoritms {
-       RTH_ALG_JENKINS = 0,
-       RTH_ALG_MS_RSS  = 1,
-       RTH_ALG_CRC32C  = 2
-};
-
-/**
- * struct vxge_hw_rth_hash_types - RTH hash types.
- * @hash_type_tcpipv4_en: Enables RTH field type HashTypeTcpIPv4
- * @hash_type_ipv4_en: Enables RTH field type HashTypeIPv4
- * @hash_type_tcpipv6_en: Enables RTH field type HashTypeTcpIPv6
- * @hash_type_ipv6_en: Enables RTH field type HashTypeIPv6
- * @hash_type_tcpipv6ex_en: Enables RTH field type HashTypeTcpIPv6Ex
- * @hash_type_ipv6ex_en: Enables RTH field type HashTypeIPv6Ex
- *
- * Used to pass RTH hash types to rts_rts_set.
- *
- * See also: vxge_hw_vpath_rts_rth_set(), vxge_hw_vpath_rts_rth_get().
- */
-struct vxge_hw_rth_hash_types {
-       u8 hash_type_tcpipv4_en:1,
-          hash_type_ipv4_en:1,
-          hash_type_tcpipv6_en:1,
-          hash_type_ipv6_en:1,
-          hash_type_tcpipv6ex_en:1,
-          hash_type_ipv6ex_en:1;
-};
-
-void vxge_hw_device_debug_set(
-       struct __vxge_hw_device *devh,
-       enum vxge_debug_level level,
-       u32 mask);
-
-u32
-vxge_hw_device_error_level_get(struct __vxge_hw_device *devh);
-
-u32
-vxge_hw_device_trace_level_get(struct __vxge_hw_device *devh);
-
-/**
- * vxge_hw_ring_rxd_size_get   - Get the size of ring descriptor.
- * @buf_mode: Buffer mode (1, 3 or 5)
- *
- * This function returns the size of RxD for given buffer mode
- */
-static inline u32 vxge_hw_ring_rxd_size_get(u32 buf_mode)
-{
-       return sizeof(struct vxge_hw_ring_rxd_1);
-}
-
-/**
- * vxge_hw_ring_rxds_per_block_get - Get the number of rxds per block.
- * @buf_mode: Buffer mode (1 buffer mode only)
- *
- * This function returns the number of RxD for RxD block for given buffer mode
- */
-static inline u32 vxge_hw_ring_rxds_per_block_get(u32 buf_mode)
-{
-       return (u32)((VXGE_HW_BLOCK_SIZE-16) /
-               sizeof(struct vxge_hw_ring_rxd_1));
-}
-
-/**
- * vxge_hw_ring_rxd_1b_set - Prepare 1-buffer-mode descriptor.
- * @rxdh: Descriptor handle.
- * @dma_pointer: DMA address of        a single receive buffer this descriptor
- * should carry. Note that by the time vxge_hw_ring_rxd_1b_set is called,
- * the receive buffer should be already mapped to the device
- * @size: Size of the receive @dma_pointer buffer.
- *
- * Prepare 1-buffer-mode Rx    descriptor for posting
- * (via        vxge_hw_ring_rxd_post()).
- *
- * This        inline helper-function does not return any parameters and always
- * succeeds.
- *
- */
-static inline
-void vxge_hw_ring_rxd_1b_set(
-       void *rxdh,
-       dma_addr_t dma_pointer,
-       u32 size)
-{
-       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
-       rxdp->buffer0_ptr = dma_pointer;
-       rxdp->control_1 &= ~VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK;
-       rxdp->control_1 |= VXGE_HW_RING_RXD_1_BUFFER0_SIZE(size);
-}
-
-/**
- * vxge_hw_ring_rxd_1b_get - Get data from the completed 1-buf
- * descriptor.
- * @vpath_handle: Virtual Path handle.
- * @rxdh: Descriptor handle.
- * @dma_pointer: DMA address of        a single receive buffer this descriptor
- * carries. Returned by HW.
- * @pkt_length:        Length (in bytes) of the data in the buffer pointed by
- *
- * Retrieve protocol data from the completed 1-buffer-mode Rx descriptor.
- * This        inline helper-function uses completed descriptor to populate receive
- * buffer pointer and other "out" parameters. The function always succeeds.
- *
- */
-static inline
-void vxge_hw_ring_rxd_1b_get(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh,
-       u32 *pkt_length)
-{
-       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
-
-       *pkt_length =
-               (u32)VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(rxdp->control_1);
-}
-
-/**
- * vxge_hw_ring_rxd_1b_info_get - Get extended information associated with
- * a completed receive descriptor for 1b mode.
- * @vpath_handle: Virtual Path handle.
- * @rxdh: Descriptor handle.
- * @rxd_info: Descriptor information
- *
- * Retrieve extended information associated with a completed receive descriptor.
- *
- */
-static inline
-void vxge_hw_ring_rxd_1b_info_get(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh,
-       struct vxge_hw_ring_rxd_info *rxd_info)
-{
-
-       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
-       rxd_info->syn_flag =
-               (u32)VXGE_HW_RING_RXD_SYN_GET(rxdp->control_0);
-       rxd_info->is_icmp =
-               (u32)VXGE_HW_RING_RXD_IS_ICMP_GET(rxdp->control_0);
-       rxd_info->fast_path_eligible =
-               (u32)VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(rxdp->control_0);
-       rxd_info->l3_cksum_valid =
-               (u32)VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(rxdp->control_0);
-       rxd_info->l3_cksum =
-               (u32)VXGE_HW_RING_RXD_L3_CKSUM_GET(rxdp->control_0);
-       rxd_info->l4_cksum_valid =
-               (u32)VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(rxdp->control_0);
-       rxd_info->l4_cksum =
-               (u32)VXGE_HW_RING_RXD_L4_CKSUM_GET(rxdp->control_0);
-       rxd_info->frame =
-               (u32)VXGE_HW_RING_RXD_ETHER_ENCAP_GET(rxdp->control_0);
-       rxd_info->proto =
-               (u32)VXGE_HW_RING_RXD_FRAME_PROTO_GET(rxdp->control_0);
-       rxd_info->is_vlan =
-               (u32)VXGE_HW_RING_RXD_IS_VLAN_GET(rxdp->control_0);
-       rxd_info->vlan =
-               (u32)VXGE_HW_RING_RXD_VLAN_TAG_GET(rxdp->control_1);
-       rxd_info->rth_bucket =
-               (u32)VXGE_HW_RING_RXD_RTH_BUCKET_GET(rxdp->control_0);
-       rxd_info->rth_it_hit =
-               (u32)VXGE_HW_RING_RXD_RTH_IT_HIT_GET(rxdp->control_0);
-       rxd_info->rth_spdm_hit =
-               (u32)VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(rxdp->control_0);
-       rxd_info->rth_hash_type =
-               (u32)VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(rxdp->control_0);
-       rxd_info->rth_value =
-               (u32)VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(rxdp->control_1);
-}
-
-/**
- * vxge_hw_ring_rxd_private_get - Get driver private per-descriptor data
- *                      of 1b mode 3b mode ring.
- * @rxdh: Descriptor handle.
- *
- * Returns: private driver     info associated with the descriptor.
- * driver requests     per-descriptor space via vxge_hw_ring_attr.
- *
- */
-static inline void *vxge_hw_ring_rxd_private_get(void *rxdh)
-{
-       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
-       return (void *)(size_t)rxdp->host_control;
-}
-
-/**
- * vxge_hw_fifo_txdl_cksum_set_bits - Offload checksum.
- * @txdlh: Descriptor handle.
- * @cksum_bits: Specifies which checksums are to be offloaded: IPv4,
- *              and/or TCP and/or UDP.
- *
- * Ask Titan to calculate IPv4 & transport checksums for _this_ transmit
- * descriptor.
- * This API is part of the preparation of the transmit descriptor for posting
- * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include
- * vxge_hw_fifo_txdl_mss_set(), vxge_hw_fifo_txdl_buffer_set_aligned(),
- * and vxge_hw_fifo_txdl_buffer_set().
- * All these APIs fill in the fields of the fifo descriptor,
- * in accordance with the Titan specification.
- *
- */
-static inline void vxge_hw_fifo_txdl_cksum_set_bits(void *txdlh, u64 cksum_bits)
-{
-       struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh;
-       txdp->control_1 |= cksum_bits;
-}
-
-/**
- * vxge_hw_fifo_txdl_mss_set - Set MSS.
- * @txdlh: Descriptor handle.
- * @mss: MSS size for _this_ TCP connection. Passed by TCP stack down to the
- *       driver, which in turn inserts the MSS into the @txdlh.
- *
- * This API is part of the preparation of the transmit descriptor for posting
- * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include
- * vxge_hw_fifo_txdl_buffer_set(), vxge_hw_fifo_txdl_buffer_set_aligned(),
- * and vxge_hw_fifo_txdl_cksum_set_bits().
- * All these APIs fill in the fields of the fifo descriptor,
- * in accordance with the Titan specification.
- *
- */
-static inline void vxge_hw_fifo_txdl_mss_set(void *txdlh, int mss)
-{
-       struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh;
-
-       txdp->control_0 |= VXGE_HW_FIFO_TXD_LSO_EN;
-       txdp->control_0 |= VXGE_HW_FIFO_TXD_LSO_MSS(mss);
-}
-
-/**
- * vxge_hw_fifo_txdl_vlan_set - Set VLAN tag.
- * @txdlh: Descriptor handle.
- * @vlan_tag: 16bit VLAN tag.
- *
- * Insert VLAN tag into specified transmit descriptor.
- * The actual insertion of the tag into outgoing frame is done by the hardware.
- */
-static inline void vxge_hw_fifo_txdl_vlan_set(void *txdlh, u16 vlan_tag)
-{
-       struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh;
-
-       txdp->control_1 |= VXGE_HW_FIFO_TXD_VLAN_ENABLE;
-       txdp->control_1 |= VXGE_HW_FIFO_TXD_VLAN_TAG(vlan_tag);
-}
-
-/**
- * vxge_hw_fifo_txdl_private_get - Retrieve per-descriptor private data.
- * @txdlh: Descriptor handle.
- *
- * Retrieve per-descriptor private data.
- * Note that driver requests per-descriptor space via
- * struct vxge_hw_fifo_attr passed to
- * vxge_hw_vpath_open().
- *
- * Returns: private driver data associated with the descriptor.
- */
-static inline void *vxge_hw_fifo_txdl_private_get(void *txdlh)
-{
-       struct vxge_hw_fifo_txd *txdp  = (struct vxge_hw_fifo_txd *)txdlh;
-
-       return (void *)(size_t)txdp->host_control;
-}
-
-/**
- * struct vxge_hw_ring_attr - Ring open "template".
- * @callback: Ring completion callback. HW invokes the callback when there
- *            are new completions on that ring. In many implementations
- *            the @callback executes in the hw interrupt context.
- * @rxd_init: Ring's descriptor-initialize callback.
- *            See vxge_hw_ring_rxd_init_f{}.
- *            If not NULL, HW invokes the callback when opening
- *            the ring.
- * @rxd_term: Ring's descriptor-terminate callback. If not NULL,
- *          HW invokes the callback when closing the corresponding ring.
- *          See also vxge_hw_ring_rxd_term_f{}.
- * @userdata: User-defined "context" of _that_ ring. Passed back to the
- *            user as one of the @callback, @rxd_init, and @rxd_term arguments.
- * @per_rxd_space: If specified (i.e., greater than zero): extra space
- *              reserved by HW per each receive descriptor.
- *              Can be used to store
- *              and retrieve on completion, information specific
- *              to the driver.
- *
- * Ring open "template". User fills the structure with ring
- * attributes and passes it to vxge_hw_vpath_open().
- */
-struct vxge_hw_ring_attr {
-       enum vxge_hw_status (*callback)(
-                       struct __vxge_hw_ring *ringh,
-                       void *rxdh,
-                       u8 t_code,
-                       void *userdata);
-
-       enum vxge_hw_status (*rxd_init)(
-                       void *rxdh,
-                       void *userdata);
-
-       void (*rxd_term)(
-                       void *rxdh,
-                       enum vxge_hw_rxd_state state,
-                       void *userdata);
-
-       void            *userdata;
-       u32             per_rxd_space;
-};
-
-/**
- * function vxge_hw_fifo_callback_f - FIFO callback.
- * @vpath_handle: Virtual path whose Fifo "containing" 1 or more completed
- *             descriptors.
- * @txdlh: First completed descriptor.
- * @txdl_priv: Pointer to per txdl space allocated
- * @t_code: Transfer code, as per Titan User Guide.
- *          Returned by HW.
- * @host_control: Opaque 64bit data stored by driver inside the Titan
- *            descriptor prior to posting the latter on the fifo
- *            via vxge_hw_fifo_txdl_post(). The @host_control is returned
- *            as is to the driver with each completed descriptor.
- * @userdata: Opaque per-fifo data specified at fifo open
- *            time, via vxge_hw_vpath_open().
- *
- * Fifo completion callback (type declaration). A single per-fifo
- * callback is specified at fifo open time, via
- * vxge_hw_vpath_open(). Typically gets called as part of the processing
- * of the Interrupt Service Routine.
- *
- * Fifo callback gets called by HW if, and only if, there is at least
- * one new completion on a given fifo. Upon processing the first @txdlh driver
- * is _supposed_ to continue consuming completions using:
- *    - vxge_hw_fifo_txdl_next_completed()
- *
- * Note that failure to process new completions in a timely fashion
- * leads to VXGE_HW_INF_OUT_OF_DESCRIPTORS condition.
- *
- * Non-zero @t_code means failure to process transmit descriptor.
- *
- * In the "transmit" case the failure could happen, for instance, when the
- * link is down, in which case Titan completes the descriptor because it
- * is not able to send the data out.
- *
- * For details please refer to Titan User Guide.
- *
- * See also: vxge_hw_fifo_txdl_next_completed(), vxge_hw_fifo_txdl_term_f{}.
- */
-/**
- * function vxge_hw_fifo_txdl_term_f - Terminate descriptor callback.
- * @txdlh: First completed descriptor.
- * @txdl_priv: Pointer to per txdl space allocated
- * @state: One of the enum vxge_hw_txdl_state{} enumerated states.
- * @userdata: Per-fifo user data (a.k.a. context) specified at
- * fifo open time, via vxge_hw_vpath_open().
- *
- * Terminate descriptor callback. Unless NULL is specified in the
- * struct vxge_hw_fifo_attr{} structure passed to vxge_hw_vpath_open()),
- * HW invokes the callback as part of closing fifo, prior to
- * de-allocating the ring and associated data structures
- * (including descriptors).
- * driver should utilize the callback to (for instance) unmap
- * and free DMA data buffers associated with the posted (state =
- * VXGE_HW_TXDL_STATE_POSTED) descriptors,
- * as well as other relevant cleanup functions.
- *
- * See also: struct vxge_hw_fifo_attr{}
- */
-/**
- * struct vxge_hw_fifo_attr - Fifo open "template".
- * @callback: Fifo completion callback. HW invokes the callback when there
- *            are new completions on that fifo. In many implementations
- *            the @callback executes in the hw interrupt context.
- * @txdl_term: Fifo's descriptor-terminate callback. If not NULL,
- *          HW invokes the callback when closing the corresponding fifo.
- *          See also vxge_hw_fifo_txdl_term_f{}.
- * @userdata: User-defined "context" of _that_ fifo. Passed back to the
- *            user as one of the @callback, and @txdl_term arguments.
- * @per_txdl_space: If specified (i.e., greater than zero): extra space
- *              reserved by HW per each transmit descriptor. Can be used to
- *              store, and retrieve on completion, information specific
- *              to the driver.
- *
- * Fifo open "template". User fills the structure with fifo
- * attributes and passes it to vxge_hw_vpath_open().
- */
-struct vxge_hw_fifo_attr {
-
-       enum vxge_hw_status (*callback)(
-                       struct __vxge_hw_fifo *fifo_handle,
-                       void *txdlh,
-                       enum vxge_hw_fifo_tcode t_code,
-                       void *userdata,
-                       struct sk_buff ***skb_ptr,
-                       int nr_skb, int *more);
-
-       void (*txdl_term)(
-                       void *txdlh,
-                       enum vxge_hw_txdl_state state,
-                       void *userdata);
-
-       void            *userdata;
-       u32             per_txdl_space;
-};
-
-/**
- * struct vxge_hw_vpath_attr - Attributes of virtual path
- * @vp_id: Identifier of Virtual Path
- * @ring_attr: Attributes of ring for non-offload receive
- * @fifo_attr: Attributes of fifo for non-offload transmit
- *
- * Attributes of virtual path.  This structure is passed as parameter
- * to the vxge_hw_vpath_open() routine to set the attributes of ring and fifo.
- */
-struct vxge_hw_vpath_attr {
-       u32                             vp_id;
-       struct vxge_hw_ring_attr        ring_attr;
-       struct vxge_hw_fifo_attr        fifo_attr;
-};
-
-enum vxge_hw_status vxge_hw_device_hw_info_get(
-       void __iomem *bar0,
-       struct vxge_hw_device_hw_info *hw_info);
-
-enum vxge_hw_status vxge_hw_device_config_default_get(
-       struct vxge_hw_device_config *device_config);
-
-/**
- * vxge_hw_device_link_state_get - Get link state.
- * @devh: HW device handle.
- *
- * Get link state.
- * Returns: link state.
- */
-static inline
-enum vxge_hw_device_link_state vxge_hw_device_link_state_get(
-       struct __vxge_hw_device *devh)
-{
-       return devh->link_state;
-}
-
-void vxge_hw_device_terminate(struct __vxge_hw_device *devh);
-
-const u8 *
-vxge_hw_device_serial_number_get(struct __vxge_hw_device *devh);
-
-u16 vxge_hw_device_link_width_get(struct __vxge_hw_device *devh);
-
-const u8 *
-vxge_hw_device_product_name_get(struct __vxge_hw_device *devh);
-
-enum vxge_hw_status vxge_hw_device_initialize(
-       struct __vxge_hw_device **devh,
-       struct vxge_hw_device_attr *attr,
-       struct vxge_hw_device_config *device_config);
-
-enum vxge_hw_status vxge_hw_device_getpause_data(
-        struct __vxge_hw_device *devh,
-        u32 port,
-        u32 *tx,
-        u32 *rx);
-
-enum vxge_hw_status vxge_hw_device_setpause_data(
-       struct __vxge_hw_device *devh,
-       u32 port,
-       u32 tx,
-       u32 rx);
-
-static inline void *vxge_os_dma_malloc(struct pci_dev *pdev,
-                       unsigned long size,
-                       struct pci_dev **p_dmah,
-                       struct pci_dev **p_dma_acch)
-{
-       void *vaddr;
-       unsigned long misaligned = 0;
-       int realloc_flag = 0;
-       *p_dma_acch = *p_dmah = NULL;
-
-realloc:
-       vaddr = kmalloc(size, GFP_KERNEL | GFP_DMA);
-       if (vaddr == NULL)
-               return vaddr;
-       misaligned = (unsigned long)VXGE_ALIGN((unsigned long)vaddr,
-                               VXGE_CACHE_LINE_SIZE);
-       if (realloc_flag)
-               goto out;
-
-       if (misaligned) {
-               /* misaligned, free current one and try allocating
-                * size + VXGE_CACHE_LINE_SIZE memory
-                */
-               kfree(vaddr);
-               size += VXGE_CACHE_LINE_SIZE;
-               realloc_flag = 1;
-               goto realloc;
-       }
-out:
-       *(unsigned long *)p_dma_acch = misaligned;
-       vaddr = (void *)((u8 *)vaddr + misaligned);
-       return vaddr;
-}
-
-static inline void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr,
-                       struct pci_dev **p_dma_acch)
-{
-       unsigned long misaligned = *(unsigned long *)p_dma_acch;
-       u8 *tmp = (u8 *)vaddr;
-       tmp -= misaligned;
-       kfree((void *)tmp);
-}
-
-/*
- * __vxge_hw_mempool_item_priv - will return pointer on per item private space
- */
-static inline void*
-__vxge_hw_mempool_item_priv(
-       struct vxge_hw_mempool *mempool,
-       u32 memblock_idx,
-       void *item,
-       u32 *memblock_item_idx)
-{
-       ptrdiff_t offset;
-       void *memblock = mempool->memblocks_arr[memblock_idx];
-
-
-       offset = (u32)((u8 *)item - (u8 *)memblock);
-       vxge_assert(offset >= 0 && (u32)offset < mempool->memblock_size);
-
-       (*memblock_item_idx) = (u32) offset / mempool->item_size;
-       vxge_assert((*memblock_item_idx) < mempool->items_per_memblock);
-
-       return (u8 *)mempool->memblocks_priv_arr[memblock_idx] +
-                           (*memblock_item_idx) * mempool->items_priv_size;
-}
-
-/*
- * __vxge_hw_fifo_txdl_priv - Return the max fragments allocated
- * for the fifo.
- * @fifo: Fifo
- * @txdp: Poniter to a TxD
- */
-static inline struct __vxge_hw_fifo_txdl_priv *
-__vxge_hw_fifo_txdl_priv(
-       struct __vxge_hw_fifo *fifo,
-       struct vxge_hw_fifo_txd *txdp)
-{
-       return (struct __vxge_hw_fifo_txdl_priv *)
-                       (((char *)((ulong)txdp->host_control)) +
-                               fifo->per_txdl_space);
-}
-
-enum vxge_hw_status vxge_hw_vpath_open(
-       struct __vxge_hw_device *devh,
-       struct vxge_hw_vpath_attr *attr,
-       struct __vxge_hw_vpath_handle **vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_close(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status
-vxge_hw_vpath_reset(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status
-vxge_hw_vpath_recover_from_reset(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-void
-vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp);
-
-enum vxge_hw_status
-vxge_hw_vpath_check_leak(struct __vxge_hw_ring *ringh);
-
-enum vxge_hw_status vxge_hw_vpath_mtu_set(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u32 new_mtu);
-
-void
-vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp);
-
-static inline void __vxge_hw_pio_mem_write32_upper(u32 val, void __iomem *addr)
-{
-       writel(val, addr + 4);
-}
-
-static inline void __vxge_hw_pio_mem_write32_lower(u32 val, void __iomem *addr)
-{
-       writel(val, addr);
-}
-
-enum vxge_hw_status
-vxge_hw_device_flick_link_led(struct __vxge_hw_device *devh, u64 on_off);
-
-enum vxge_hw_status
-vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask);
-
-/**
- * vxge_debug_ll
- * @level: level of debug verbosity.
- * @mask: mask for the debug
- * @buf: Circular buffer for tracing
- * @fmt: printf like format string
- *
- * Provides logging facilities. Can be customized on per-module
- * basis or/and with debug levels. Input parameters, except
- * module and level, are the same as posix printf. This function
- * may be compiled out if DEBUG macro was never defined.
- * See also: enum vxge_debug_level{}.
- */
-#if (VXGE_COMPONENT_LL & VXGE_DEBUG_MODULE_MASK)
-#define vxge_debug_ll(level, mask, fmt, ...) do {                             \
-       if ((level >= VXGE_ERR && VXGE_COMPONENT_LL & VXGE_DEBUG_ERR_MASK) ||  \
-           (level >= VXGE_TRACE && VXGE_COMPONENT_LL & VXGE_DEBUG_TRACE_MASK))\
-               if ((mask & VXGE_DEBUG_MASK) == mask)                          \
-                       printk(fmt "\n", ##__VA_ARGS__);                       \
-} while (0)
-#else
-#define vxge_debug_ll(level, mask, fmt, ...)
-#endif
-
-enum vxge_hw_status vxge_hw_vpath_rts_rth_itable_set(
-                       struct __vxge_hw_vpath_handle **vpath_handles,
-                       u32 vpath_count,
-                       u8 *mtable,
-                       u8 *itable,
-                       u32 itable_size);
-
-enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       enum vxge_hw_rth_algoritms algorithm,
-       struct vxge_hw_rth_hash_types *hash_type,
-       u16 bucket_size);
-
-enum vxge_hw_status
-__vxge_hw_device_is_privilaged(u32 host_type, u32 func_id);
-
-#define VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT 5
-#define VXGE_HW_MAX_POLLING_COUNT 100
-
-void
-vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev);
-
-enum vxge_hw_status
-vxge_hw_upgrade_read_version(struct __vxge_hw_device *hldev, u32 *major,
-                            u32 *minor, u32 *build);
-
-enum vxge_hw_status vxge_hw_flash_fw(struct __vxge_hw_device *hldev);
-
-enum vxge_hw_status
-vxge_update_fw_image(struct __vxge_hw_device *hldev, const u8 *filebuf,
-                    int size);
-
-enum vxge_hw_status
-vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev,
-                               struct eprom_image *eprom_image_data);
-
-int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id);
-#endif
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.c
deleted file mode 100644 (file)
index 4d91026..0000000
+++ /dev/null
@@ -1,1154 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-ethtool.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#include <linux/ethtool.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/etherdevice.h>
-
-#include "vxge-ethtool.h"
-
-static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
-       {"\n DRIVER STATISTICS"},
-       {"vpaths_opened"},
-       {"vpath_open_fail_cnt"},
-       {"link_up_cnt"},
-       {"link_down_cnt"},
-       {"tx_frms"},
-       {"tx_errors"},
-       {"tx_bytes"},
-       {"txd_not_free"},
-       {"txd_out_of_desc"},
-       {"rx_frms"},
-       {"rx_errors"},
-       {"rx_bytes"},
-       {"rx_mcast"},
-       {"pci_map_fail_cnt"},
-       {"skb_alloc_fail_cnt"}
-};
-
-/**
- * vxge_ethtool_set_link_ksettings - Sets different link parameters.
- * @dev: device pointer.
- * @cmd: pointer to the structure with parameters given by ethtool to set
- * link information.
- *
- * The function sets different link parameters provided by the user onto
- * the NIC.
- * Return value:
- * 0 on success.
- */
-static int
-vxge_ethtool_set_link_ksettings(struct net_device *dev,
-                               const struct ethtool_link_ksettings *cmd)
-{
-       /* We currently only support 10Gb/FULL */
-       if ((cmd->base.autoneg == AUTONEG_ENABLE) ||
-           (cmd->base.speed != SPEED_10000) ||
-           (cmd->base.duplex != DUPLEX_FULL))
-               return -EINVAL;
-
-       return 0;
-}
-
-/**
- * vxge_ethtool_get_link_ksettings - Return link specific information.
- * @dev: device pointer.
- * @cmd: pointer to the structure with parameters given by ethtool
- * to return link information.
- *
- * Returns link specific information like speed, duplex etc.. to ethtool.
- * Return value :
- * return 0 on success.
- */
-static int vxge_ethtool_get_link_ksettings(struct net_device *dev,
-                                          struct ethtool_link_ksettings *cmd)
-{
-       ethtool_link_ksettings_zero_link_mode(cmd, supported);
-       ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full);
-       ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
-
-       ethtool_link_ksettings_zero_link_mode(cmd, advertising);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseT_Full);
-       ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
-
-       cmd->base.port = PORT_FIBRE;
-
-       if (netif_carrier_ok(dev)) {
-               cmd->base.speed = SPEED_10000;
-               cmd->base.duplex = DUPLEX_FULL;
-       } else {
-               cmd->base.speed = SPEED_UNKNOWN;
-               cmd->base.duplex = DUPLEX_UNKNOWN;
-       }
-
-       cmd->base.autoneg = AUTONEG_DISABLE;
-       return 0;
-}
-
-/**
- * vxge_ethtool_gdrvinfo - Returns driver specific information.
- * @dev: device pointer.
- * @info: pointer to the structure with parameters given by ethtool to
- * return driver information.
- *
- * Returns driver specefic information like name, version etc.. to ethtool.
- */
-static void vxge_ethtool_gdrvinfo(struct net_device *dev,
-                                 struct ethtool_drvinfo *info)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(info->driver));
-       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-       strlcpy(info->fw_version, vdev->fw_version, sizeof(info->fw_version));
-       strlcpy(info->bus_info, pci_name(vdev->pdev), sizeof(info->bus_info));
-}
-
-/**
- * vxge_ethtool_gregs - dumps the entire space of Titan into the buffer.
- * @dev: device pointer.
- * @regs: pointer to the structure with parameters given by ethtool for
- * dumping the registers.
- * @space: The input argument into which all the registers are dumped.
- *
- * Dumps the vpath register space of Titan NIC into the user given
- * buffer area.
- */
-static void vxge_ethtool_gregs(struct net_device *dev,
-                              struct ethtool_regs *regs, void *space)
-{
-       int index, offset;
-       enum vxge_hw_status status;
-       u64 reg;
-       u64 *reg_space = (u64 *)space;
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct __vxge_hw_device *hldev = vdev->devh;
-
-       regs->len = sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
-       regs->version = vdev->pdev->subsystem_device;
-       for (index = 0; index < vdev->no_of_vpath; index++) {
-               for (offset = 0; offset < sizeof(struct vxge_hw_vpath_reg);
-                               offset += 8) {
-                       status = vxge_hw_mgmt_reg_read(hldev,
-                                       vxge_hw_mgmt_reg_type_vpath,
-                                       vdev->vpaths[index].device_id,
-                                       offset, &reg);
-                       if (status != VXGE_HW_OK) {
-                               vxge_debug_init(VXGE_ERR,
-                                       "%s:%d Getting reg dump Failed",
-                                               __func__, __LINE__);
-                               return;
-                       }
-                       *reg_space++ = reg;
-               }
-       }
-}
-
-/**
- * vxge_ethtool_idnic - To physically identify the nic on the system.
- * @dev : device pointer.
- * @state : requested LED state
- *
- * Used to physically identify the NIC on the system.
- * 0 on success
- */
-static int vxge_ethtool_idnic(struct net_device *dev,
-                             enum ethtool_phys_id_state state)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct __vxge_hw_device *hldev = vdev->devh;
-
-       switch (state) {
-       case ETHTOOL_ID_ACTIVE:
-               vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON);
-               break;
-
-       case ETHTOOL_ID_INACTIVE:
-               vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * vxge_ethtool_getpause_data - Pause frame frame generation and reception.
- * @dev : device pointer.
- * @ep : pointer to the structure with pause parameters given by ethtool.
- * Description:
- * Returns the Pause frame generation and reception capability of the NIC.
- * Return value:
- *  void
- */
-static void vxge_ethtool_getpause_data(struct net_device *dev,
-                                      struct ethtool_pauseparam *ep)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct __vxge_hw_device *hldev = vdev->devh;
-
-       vxge_hw_device_getpause_data(hldev, 0, &ep->tx_pause, &ep->rx_pause);
-}
-
-/**
- * vxge_ethtool_setpause_data -  set/reset pause frame generation.
- * @dev : device pointer.
- * @ep : pointer to the structure with pause parameters given by ethtool.
- * Description:
- * It can be used to set or reset Pause frame generation or reception
- * support of the NIC.
- * Return value:
- * int, returns 0 on Success
- */
-static int vxge_ethtool_setpause_data(struct net_device *dev,
-                                     struct ethtool_pauseparam *ep)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct __vxge_hw_device *hldev = vdev->devh;
-
-       vxge_hw_device_setpause_data(hldev, 0, ep->tx_pause, ep->rx_pause);
-
-       vdev->config.tx_pause_enable = ep->tx_pause;
-       vdev->config.rx_pause_enable = ep->rx_pause;
-
-       return 0;
-}
-
-static void vxge_get_ethtool_stats(struct net_device *dev,
-                                  struct ethtool_stats *estats, u64 *tmp_stats)
-{
-       int j, k;
-       enum vxge_hw_status status;
-       enum vxge_hw_status swstatus;
-       struct vxge_vpath *vpath = NULL;
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct __vxge_hw_device *hldev = vdev->devh;
-       struct vxge_hw_xmac_stats *xmac_stats;
-       struct vxge_hw_device_stats_sw_info *sw_stats;
-       struct vxge_hw_device_stats_hw_info *hw_stats;
-
-       u64 *ptr = tmp_stats;
-
-       memset(tmp_stats, 0,
-               vxge_ethtool_get_sset_count(dev, ETH_SS_STATS) * sizeof(u64));
-
-       xmac_stats = kzalloc(sizeof(struct vxge_hw_xmac_stats), GFP_KERNEL);
-       if (xmac_stats == NULL) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : %d Memory Allocation failed for xmac_stats",
-                                __func__, __LINE__);
-               return;
-       }
-
-       sw_stats = kzalloc(sizeof(struct vxge_hw_device_stats_sw_info),
-                               GFP_KERNEL);
-       if (sw_stats == NULL) {
-               kfree(xmac_stats);
-               vxge_debug_init(VXGE_ERR,
-                       "%s : %d Memory Allocation failed for sw_stats",
-                       __func__, __LINE__);
-               return;
-       }
-
-       hw_stats = kzalloc(sizeof(struct vxge_hw_device_stats_hw_info),
-                               GFP_KERNEL);
-       if (hw_stats == NULL) {
-               kfree(xmac_stats);
-               kfree(sw_stats);
-               vxge_debug_init(VXGE_ERR,
-                       "%s : %d Memory Allocation failed for hw_stats",
-                       __func__, __LINE__);
-               return;
-       }
-
-       *ptr++ = 0;
-       status = vxge_hw_device_xmac_stats_get(hldev, xmac_stats);
-       if (status != VXGE_HW_OK) {
-               if (status != VXGE_HW_ERR_PRIVILEGED_OPERATION) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s : %d Failure in getting xmac stats",
-                               __func__, __LINE__);
-               }
-       }
-       swstatus = vxge_hw_driver_stats_get(hldev, sw_stats);
-       if (swstatus != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : %d Failure in getting sw stats",
-                       __func__, __LINE__);
-       }
-
-       status = vxge_hw_device_stats_get(hldev, hw_stats);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : %d hw_stats_get error", __func__, __LINE__);
-       }
-
-       for (k = 0; k < vdev->no_of_vpath; k++) {
-               struct vxge_hw_vpath_stats_hw_info *vpath_info;
-
-               vpath = &vdev->vpaths[k];
-               j = vpath->device_id;
-               vpath_info = hw_stats->vpath_info[j];
-               if (!vpath_info) {
-                       memset(ptr, 0, (VXGE_HW_VPATH_TX_STATS_LEN +
-                               VXGE_HW_VPATH_RX_STATS_LEN) * sizeof(u64));
-                       ptr += (VXGE_HW_VPATH_TX_STATS_LEN +
-                               VXGE_HW_VPATH_RX_STATS_LEN);
-                       continue;
-               }
-
-               *ptr++ = vpath_info->tx_stats.tx_ttl_eth_frms;
-               *ptr++ = vpath_info->tx_stats.tx_ttl_eth_octets;
-               *ptr++ = vpath_info->tx_stats.tx_data_octets;
-               *ptr++ = vpath_info->tx_stats.tx_mcast_frms;
-               *ptr++ = vpath_info->tx_stats.tx_bcast_frms;
-               *ptr++ = vpath_info->tx_stats.tx_ucast_frms;
-               *ptr++ = vpath_info->tx_stats.tx_tagged_frms;
-               *ptr++ = vpath_info->tx_stats.tx_vld_ip;
-               *ptr++ = vpath_info->tx_stats.tx_vld_ip_octets;
-               *ptr++ = vpath_info->tx_stats.tx_icmp;
-               *ptr++ = vpath_info->tx_stats.tx_tcp;
-               *ptr++ = vpath_info->tx_stats.tx_rst_tcp;
-               *ptr++ = vpath_info->tx_stats.tx_udp;
-               *ptr++ = vpath_info->tx_stats.tx_unknown_protocol;
-               *ptr++ = vpath_info->tx_stats.tx_lost_ip;
-               *ptr++ = vpath_info->tx_stats.tx_parse_error;
-               *ptr++ = vpath_info->tx_stats.tx_tcp_offload;
-               *ptr++ = vpath_info->tx_stats.tx_retx_tcp_offload;
-               *ptr++ = vpath_info->tx_stats.tx_lost_ip_offload;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_eth_frms;
-               *ptr++ = vpath_info->rx_stats.rx_vld_frms;
-               *ptr++ = vpath_info->rx_stats.rx_offload_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_eth_octets;
-               *ptr++ = vpath_info->rx_stats.rx_data_octets;
-               *ptr++ = vpath_info->rx_stats.rx_offload_octets;
-               *ptr++ = vpath_info->rx_stats.rx_vld_mcast_frms;
-               *ptr++ = vpath_info->rx_stats.rx_vld_bcast_frms;
-               *ptr++ = vpath_info->rx_stats.rx_accepted_ucast_frms;
-               *ptr++ = vpath_info->rx_stats.rx_accepted_nucast_frms;
-               *ptr++ = vpath_info->rx_stats.rx_tagged_frms;
-               *ptr++ = vpath_info->rx_stats.rx_long_frms;
-               *ptr++ = vpath_info->rx_stats.rx_usized_frms;
-               *ptr++ = vpath_info->rx_stats.rx_osized_frms;
-               *ptr++ = vpath_info->rx_stats.rx_frag_frms;
-               *ptr++ = vpath_info->rx_stats.rx_jabber_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_64_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_65_127_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_128_255_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_256_511_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_512_1023_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_1024_1518_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_1519_4095_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_4096_8191_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_8192_max_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ttl_gt_max_frms;
-               *ptr++ = vpath_info->rx_stats.rx_ip;
-               *ptr++ = vpath_info->rx_stats.rx_accepted_ip;
-               *ptr++ = vpath_info->rx_stats.rx_ip_octets;
-               *ptr++ = vpath_info->rx_stats.rx_err_ip;
-               *ptr++ = vpath_info->rx_stats.rx_icmp;
-               *ptr++ = vpath_info->rx_stats.rx_tcp;
-               *ptr++ = vpath_info->rx_stats.rx_udp;
-               *ptr++ = vpath_info->rx_stats.rx_err_tcp;
-               *ptr++ = vpath_info->rx_stats.rx_lost_frms;
-               *ptr++ = vpath_info->rx_stats.rx_lost_ip;
-               *ptr++ = vpath_info->rx_stats.rx_lost_ip_offload;
-               *ptr++ = vpath_info->rx_stats.rx_various_discard;
-               *ptr++ = vpath_info->rx_stats.rx_sleep_discard;
-               *ptr++ = vpath_info->rx_stats.rx_red_discard;
-               *ptr++ = vpath_info->rx_stats.rx_queue_full_discard;
-               *ptr++ = vpath_info->rx_stats.rx_mpa_ok_frms;
-       }
-       *ptr++ = 0;
-       for (k = 0; k < vdev->max_config_port; k++) {
-               *ptr++ = xmac_stats->aggr_stats[k].tx_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].tx_data_octets;
-               *ptr++ = xmac_stats->aggr_stats[k].tx_mcast_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].tx_bcast_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].tx_discarded_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].tx_errored_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_data_octets;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_mcast_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_bcast_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_discarded_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_errored_frms;
-               *ptr++ = xmac_stats->aggr_stats[k].rx_unknown_slow_proto_frms;
-       }
-       *ptr++ = 0;
-       for (k = 0; k < vdev->max_config_port; k++) {
-               *ptr++ = xmac_stats->port_stats[k].tx_ttl_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_ttl_octets;
-               *ptr++ = xmac_stats->port_stats[k].tx_data_octets;
-               *ptr++ = xmac_stats->port_stats[k].tx_mcast_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_bcast_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_ucast_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_tagged_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_vld_ip;
-               *ptr++ = xmac_stats->port_stats[k].tx_vld_ip_octets;
-               *ptr++ = xmac_stats->port_stats[k].tx_icmp;
-               *ptr++ = xmac_stats->port_stats[k].tx_tcp;
-               *ptr++ = xmac_stats->port_stats[k].tx_rst_tcp;
-               *ptr++ = xmac_stats->port_stats[k].tx_udp;
-               *ptr++ = xmac_stats->port_stats[k].tx_parse_error;
-               *ptr++ = xmac_stats->port_stats[k].tx_unknown_protocol;
-               *ptr++ = xmac_stats->port_stats[k].tx_pause_ctrl_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_marker_pdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_lacpdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_drop_ip;
-               *ptr++ = xmac_stats->port_stats[k].tx_marker_resp_pdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_char2_match;
-               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_char1_match;
-               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_column2_match;
-               *ptr++ = xmac_stats->port_stats[k].tx_xgmii_column1_match;
-               *ptr++ = xmac_stats->port_stats[k].tx_any_err_frms;
-               *ptr++ = xmac_stats->port_stats[k].tx_drop_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_vld_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_offload_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_octets;
-               *ptr++ = xmac_stats->port_stats[k].rx_data_octets;
-               *ptr++ = xmac_stats->port_stats[k].rx_offload_octets;
-               *ptr++ = xmac_stats->port_stats[k].rx_vld_mcast_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_vld_bcast_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_accepted_ucast_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_accepted_nucast_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_tagged_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_long_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_usized_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_osized_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_frag_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_jabber_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_64_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_65_127_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_128_255_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_256_511_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_512_1023_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_1024_1518_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_1519_4095_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_4096_8191_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_8192_max_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ttl_gt_max_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_ip;
-               *ptr++ = xmac_stats->port_stats[k].rx_accepted_ip;
-               *ptr++ = xmac_stats->port_stats[k].rx_ip_octets;
-               *ptr++ = xmac_stats->port_stats[k].rx_err_ip;
-               *ptr++ = xmac_stats->port_stats[k].rx_icmp;
-               *ptr++ = xmac_stats->port_stats[k].rx_tcp;
-               *ptr++ = xmac_stats->port_stats[k].rx_udp;
-               *ptr++ = xmac_stats->port_stats[k].rx_err_tcp;
-               *ptr++ = xmac_stats->port_stats[k].rx_pause_count;
-               *ptr++ = xmac_stats->port_stats[k].rx_pause_ctrl_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_unsup_ctrl_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_fcs_err_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_in_rng_len_err_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_out_rng_len_err_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_drop_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_discarded_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_drop_ip;
-               *ptr++ = xmac_stats->port_stats[k].rx_drop_udp;
-               *ptr++ = xmac_stats->port_stats[k].rx_marker_pdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_lacpdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_unknown_pdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_marker_resp_pdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_fcs_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_illegal_pdu_frms;
-               *ptr++ = xmac_stats->port_stats[k].rx_switch_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_len_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_rpa_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_l2_mgmt_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_rts_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_trash_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_buff_full_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_red_discard;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_ctrl_err_cnt;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_data_err_cnt;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_char1_match;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_err_sym;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_column1_match;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_char2_match;
-               *ptr++ = xmac_stats->port_stats[k].rx_local_fault;
-               *ptr++ = xmac_stats->port_stats[k].rx_xgmii_column2_match;
-               *ptr++ = xmac_stats->port_stats[k].rx_jettison;
-               *ptr++ = xmac_stats->port_stats[k].rx_remote_fault;
-       }
-
-       *ptr++ = 0;
-       for (k = 0; k < vdev->no_of_vpath; k++) {
-               struct vxge_hw_vpath_stats_sw_info *vpath_info;
-
-               vpath = &vdev->vpaths[k];
-               j = vpath->device_id;
-               vpath_info = (struct vxge_hw_vpath_stats_sw_info *)
-                               &sw_stats->vpath_info[j];
-               *ptr++ = vpath_info->soft_reset_cnt;
-               *ptr++ = vpath_info->error_stats.unknown_alarms;
-               *ptr++ = vpath_info->error_stats.network_sustained_fault;
-               *ptr++ = vpath_info->error_stats.network_sustained_ok;
-               *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_overwrite;
-               *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_poison;
-               *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_dma_error;
-               *ptr++ = vpath_info->error_stats.dblgen_fifo0_overflow;
-               *ptr++ = vpath_info->error_stats.statsb_pif_chain_error;
-               *ptr++ = vpath_info->error_stats.statsb_drop_timeout;
-               *ptr++ = vpath_info->error_stats.target_illegal_access;
-               *ptr++ = vpath_info->error_stats.ini_serr_det;
-               *ptr++ = vpath_info->error_stats.prc_ring_bumps;
-               *ptr++ = vpath_info->error_stats.prc_rxdcm_sc_err;
-               *ptr++ = vpath_info->error_stats.prc_rxdcm_sc_abort;
-               *ptr++ = vpath_info->error_stats.prc_quanta_size_err;
-               *ptr++ = vpath_info->ring_stats.common_stats.full_cnt;
-               *ptr++ = vpath_info->ring_stats.common_stats.usage_cnt;
-               *ptr++ = vpath_info->ring_stats.common_stats.usage_max;
-               *ptr++ = vpath_info->ring_stats.common_stats.
-                                       reserve_free_swaps_cnt;
-               *ptr++ = vpath_info->ring_stats.common_stats.total_compl_cnt;
-               for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
-                       *ptr++ = vpath_info->ring_stats.rxd_t_code_err_cnt[j];
-               *ptr++ = vpath_info->fifo_stats.common_stats.full_cnt;
-               *ptr++ = vpath_info->fifo_stats.common_stats.usage_cnt;
-               *ptr++ = vpath_info->fifo_stats.common_stats.usage_max;
-               *ptr++ = vpath_info->fifo_stats.common_stats.
-                                               reserve_free_swaps_cnt;
-               *ptr++ = vpath_info->fifo_stats.common_stats.total_compl_cnt;
-               *ptr++ = vpath_info->fifo_stats.total_posts;
-               *ptr++ = vpath_info->fifo_stats.total_buffers;
-               for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
-                       *ptr++ = vpath_info->fifo_stats.txd_t_code_err_cnt[j];
-       }
-
-       *ptr++ = 0;
-       for (k = 0; k < vdev->no_of_vpath; k++) {
-               struct vxge_hw_vpath_stats_hw_info *vpath_info;
-               vpath = &vdev->vpaths[k];
-               j = vpath->device_id;
-               vpath_info = hw_stats->vpath_info[j];
-               if (!vpath_info) {
-                       memset(ptr, 0, VXGE_HW_VPATH_STATS_LEN * sizeof(u64));
-                       ptr += VXGE_HW_VPATH_STATS_LEN;
-                       continue;
-               }
-               *ptr++ = vpath_info->ini_num_mwr_sent;
-               *ptr++ = vpath_info->ini_num_mrd_sent;
-               *ptr++ = vpath_info->ini_num_cpl_rcvd;
-               *ptr++ = vpath_info->ini_num_mwr_byte_sent;
-               *ptr++ = vpath_info->ini_num_cpl_byte_rcvd;
-               *ptr++ = vpath_info->wrcrdtarb_xoff;
-               *ptr++ = vpath_info->rdcrdtarb_xoff;
-               *ptr++ = vpath_info->vpath_genstats_count0;
-               *ptr++ = vpath_info->vpath_genstats_count1;
-               *ptr++ = vpath_info->vpath_genstats_count2;
-               *ptr++ = vpath_info->vpath_genstats_count3;
-               *ptr++ = vpath_info->vpath_genstats_count4;
-               *ptr++ = vpath_info->vpath_genstats_count5;
-               *ptr++ = vpath_info->prog_event_vnum0;
-               *ptr++ = vpath_info->prog_event_vnum1;
-               *ptr++ = vpath_info->prog_event_vnum2;
-               *ptr++ = vpath_info->prog_event_vnum3;
-               *ptr++ = vpath_info->rx_multi_cast_frame_discard;
-               *ptr++ = vpath_info->rx_frm_transferred;
-               *ptr++ = vpath_info->rxd_returned;
-               *ptr++ = vpath_info->rx_mpa_len_fail_frms;
-               *ptr++ = vpath_info->rx_mpa_mrk_fail_frms;
-               *ptr++ = vpath_info->rx_mpa_crc_fail_frms;
-               *ptr++ = vpath_info->rx_permitted_frms;
-               *ptr++ = vpath_info->rx_vp_reset_discarded_frms;
-               *ptr++ = vpath_info->rx_wol_frms;
-               *ptr++ = vpath_info->tx_vp_reset_discarded_frms;
-       }
-
-       *ptr++ = 0;
-       *ptr++ = vdev->stats.vpaths_open;
-       *ptr++ = vdev->stats.vpath_open_fail;
-       *ptr++ = vdev->stats.link_up;
-       *ptr++ = vdev->stats.link_down;
-
-       for (k = 0; k < vdev->no_of_vpath; k++) {
-               *ptr += vdev->vpaths[k].fifo.stats.tx_frms;
-               *(ptr + 1) += vdev->vpaths[k].fifo.stats.tx_errors;
-               *(ptr + 2) += vdev->vpaths[k].fifo.stats.tx_bytes;
-               *(ptr + 3) += vdev->vpaths[k].fifo.stats.txd_not_free;
-               *(ptr + 4) += vdev->vpaths[k].fifo.stats.txd_out_of_desc;
-               *(ptr + 5) += vdev->vpaths[k].ring.stats.rx_frms;
-               *(ptr + 6) += vdev->vpaths[k].ring.stats.rx_errors;
-               *(ptr + 7) += vdev->vpaths[k].ring.stats.rx_bytes;
-               *(ptr + 8) += vdev->vpaths[k].ring.stats.rx_mcast;
-               *(ptr + 9) += vdev->vpaths[k].fifo.stats.pci_map_fail +
-                               vdev->vpaths[k].ring.stats.pci_map_fail;
-               *(ptr + 10) += vdev->vpaths[k].ring.stats.skb_alloc_fail;
-       }
-
-       ptr += 12;
-
-       kfree(xmac_stats);
-       kfree(sw_stats);
-       kfree(hw_stats);
-}
-
-static void vxge_ethtool_get_strings(struct net_device *dev, u32 stringset,
-                                    u8 *data)
-{
-       int stat_size = 0;
-       int i, j;
-       struct vxgedev *vdev = netdev_priv(dev);
-       switch (stringset) {
-       case ETH_SS_STATS:
-               vxge_add_string("VPATH STATISTICS%s\t\t\t",
-                       &stat_size, data, "");
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vxge_add_string("tx_ttl_eth_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_ttl_eth_octects_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_data_octects_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_mcast_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_bcast_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_ucast_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_tagged_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_vld_ip_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_vld_ip_octects_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_icmp_%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_tcp_%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_rst_tcp_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_udp_%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_unknown_proto_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_lost_ip_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_parse_error_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_tcp_offload_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_retx_tcp_offload_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_lost_ip_offload_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_eth_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_vld_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_offload_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_eth_octects_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_data_octects_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_offload_octects_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_vld_mcast_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_vld_bcast_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_accepted_ucast_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_accepted_nucast_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_tagged_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_long_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_usized_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_osized_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_frag_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_jabber_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_64_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_65_127_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_128_255_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_256_511_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_512_1023_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_1024_1518_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_1519_4095_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_4096_8191_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_8192_max_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ttl_gt_max_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ip%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_accepted_ip_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_ip_octects_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_err_ip_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_icmp_%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_tcp_%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_udp_%d\t\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_err_tcp_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_lost_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_lost_ip_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_lost_ip_offload_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_various_discard_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_sleep_discard_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_red_discard_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_queue_full_discard_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_mpa_ok_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-               }
-
-               vxge_add_string("\nAGGR STATISTICS%s\t\t\t\t",
-                       &stat_size, data, "");
-               for (i = 0; i < vdev->max_config_port; i++) {
-                       vxge_add_string("tx_frms_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_data_octects_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_mcast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_bcast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_discarded_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_errored_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_frms_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_data_octects_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_mcast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_bcast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_discarded_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_errored_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_unknown_slow_proto_frms_%d\t",
-                               &stat_size, data, i);
-               }
-
-               vxge_add_string("\nPORT STATISTICS%s\t\t\t\t",
-                       &stat_size, data, "");
-               for (i = 0; i < vdev->max_config_port; i++) {
-                       vxge_add_string("tx_ttl_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_ttl_octects_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_data_octects_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_mcast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_bcast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_ucast_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_tagged_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_vld_ip_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_vld_ip_octects_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_icmp_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_tcp_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_rst_tcp_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_udp_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_parse_error_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_unknown_protocol_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_pause_ctrl_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_marker_pdu_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_lacpdu_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_drop_ip_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_marker_resp_pdu_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_xgmii_char2_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_xgmii_char1_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_xgmii_column2_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_xgmii_column1_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_any_err_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("tx_drop_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_vld_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_offload_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_octects_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_data_octects_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_offload_octects_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_vld_mcast_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_vld_bcast_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_accepted_ucast_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_accepted_nucast_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_tagged_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_long_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_usized_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_osized_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_frag_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_jabber_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_64_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_65_127_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_128_255_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_256_511_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_512_1023_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_1024_1518_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_1519_4095_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_4096_8191_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_8192_max_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ttl_gt_max_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ip_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_accepted_ip_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_ip_octets_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_err_ip_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_icmp_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_tcp_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_udp_%d\t\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_err_tcp_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_pause_count_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_pause_ctrl_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_unsup_ctrl_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_fcs_err_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_in_rng_len_err_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_out_rng_len_err_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_drop_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_discard_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_drop_ip_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_drop_udp_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_marker_pdu_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_lacpdu_frms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_unknown_pdu_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_marker_resp_pdu_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_fcs_discard_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_illegal_pdu_frms_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_switch_discard_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_len_discard_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_rpa_discard_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_l2_mgmt_discard_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_rts_discard_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_trash_discard_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_buff_full_discard_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_red_discard_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_ctrl_err_cnt_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_data_err_cnt_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_char1_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_err_sym_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_column1_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_char2_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_local_fault_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_xgmii_column2_match_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_jettison_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("rx_remote_fault_%d\t\t\t",
-                               &stat_size, data, i);
-               }
-
-               vxge_add_string("\n SOFTWARE STATISTICS%s\t\t\t",
-                       &stat_size, data, "");
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vxge_add_string("soft_reset_cnt_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("unknown_alarms_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("network_sustained_fault_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("network_sustained_ok_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("kdfcctl_fifo0_overwrite_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("kdfcctl_fifo0_poison_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("kdfcctl_fifo0_dma_error_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("dblgen_fifo0_overflow_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("statsb_pif_chain_error_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("statsb_drop_timeout_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("target_illegal_access_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("ini_serr_det_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("prc_ring_bumps_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("prc_rxdcm_sc_err_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("prc_rxdcm_sc_abort_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("prc_quanta_size_err_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("ring_full_cnt_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("ring_usage_cnt_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("ring_usage_max_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("ring_reserve_free_swaps_cnt_%d\t",
-                               &stat_size, data, i);
-                       vxge_add_string("ring_total_compl_cnt_%d\t\t",
-                               &stat_size, data, i);
-                       for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
-                               vxge_add_string("rxd_t_code_err_cnt%d_%d\t\t",
-                                       &stat_size, data, j, i);
-                       vxge_add_string("fifo_full_cnt_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("fifo_usage_cnt_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("fifo_usage_max_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("fifo_reserve_free_swaps_cnt_%d\t",
-                               &stat_size, data, i);
-                       vxge_add_string("fifo_total_compl_cnt_%d\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("fifo_total_posts_%d\t\t\t",
-                               &stat_size, data, i);
-                       vxge_add_string("fifo_total_buffers_%d\t\t",
-                               &stat_size, data, i);
-                       for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++)
-                               vxge_add_string("txd_t_code_err_cnt%d_%d\t\t",
-                                       &stat_size, data, j, i);
-               }
-
-               vxge_add_string("\n HARDWARE STATISTICS%s\t\t\t",
-                               &stat_size, data, "");
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vxge_add_string("ini_num_mwr_sent_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("ini_num_mrd_sent_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("ini_num_cpl_rcvd_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("ini_num_mwr_byte_sent_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("ini_num_cpl_byte_rcvd_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("wrcrdtarb_xoff_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rdcrdtarb_xoff_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("vpath_genstats_count0_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("vpath_genstats_count1_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("vpath_genstats_count2_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("vpath_genstats_count3_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("vpath_genstats_count4_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("vpath_genstats_count5_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("prog_event_vnum0_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("prog_event_vnum1_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("prog_event_vnum2_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("prog_event_vnum3_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_multi_cast_frame_discard_%d\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_frm_transferred_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rxd_returned_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_mpa_len_fail_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_mpa_mrk_fail_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_mpa_crc_fail_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_permitted_frms_%d\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_vp_reset_discarded_frms_%d\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("rx_wol_frms_%d\t\t\t",
-                                       &stat_size, data, i);
-                       vxge_add_string("tx_vp_reset_discarded_frms_%d\t",
-                                       &stat_size, data, i);
-               }
-
-               memcpy(data + stat_size, &ethtool_driver_stats_keys,
-                       sizeof(ethtool_driver_stats_keys));
-       }
-}
-
-static int vxge_ethtool_get_regs_len(struct net_device *dev)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
-}
-
-static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       switch (sset) {
-       case ETH_SS_STATS:
-               return VXGE_TITLE_LEN +
-                       (vdev->no_of_vpath * VXGE_HW_VPATH_STATS_LEN) +
-                       (vdev->max_config_port * VXGE_HW_AGGR_STATS_LEN) +
-                       (vdev->max_config_port * VXGE_HW_PORT_STATS_LEN) +
-                       (vdev->no_of_vpath * VXGE_HW_VPATH_TX_STATS_LEN) +
-                       (vdev->no_of_vpath * VXGE_HW_VPATH_RX_STATS_LEN) +
-                       (vdev->no_of_vpath * VXGE_SW_STATS_LEN) +
-                       DRIVER_STAT_LEN;
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       if (vdev->max_vpath_supported != VXGE_HW_MAX_VIRTUAL_PATHS) {
-               printk(KERN_INFO "Single Function Mode is required to flash the"
-                      " firmware\n");
-               return -EINVAL;
-       }
-
-       if (netif_running(dev)) {
-               printk(KERN_INFO "Interface %s must be down to flash the "
-                      "firmware\n", dev->name);
-               return -EBUSY;
-       }
-
-       return vxge_fw_upgrade(vdev, parms->data, 1);
-}
-
-static const struct ethtool_ops vxge_ethtool_ops = {
-       .get_drvinfo            = vxge_ethtool_gdrvinfo,
-       .get_regs_len           = vxge_ethtool_get_regs_len,
-       .get_regs               = vxge_ethtool_gregs,
-       .get_link               = ethtool_op_get_link,
-       .get_pauseparam         = vxge_ethtool_getpause_data,
-       .set_pauseparam         = vxge_ethtool_setpause_data,
-       .get_strings            = vxge_ethtool_get_strings,
-       .set_phys_id            = vxge_ethtool_idnic,
-       .get_sset_count         = vxge_ethtool_get_sset_count,
-       .get_ethtool_stats      = vxge_get_ethtool_stats,
-       .flash_device           = vxge_fw_flash,
-       .get_link_ksettings     = vxge_ethtool_get_link_ksettings,
-       .set_link_ksettings     = vxge_ethtool_set_link_ksettings,
-};
-
-void vxge_initialize_ethtool_ops(struct net_device *ndev)
-{
-       ndev->ethtool_ops = &vxge_ethtool_ops;
-}
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h b/drivers/net/ethernet/neterion/vxge/vxge-ethtool.h
deleted file mode 100644 (file)
index 065a2c0..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-ethtool.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#ifndef _VXGE_ETHTOOL_H
-#define _VXGE_ETHTOOL_H
-
-#include "vxge-main.h"
-
-/* Ethtool related variables and Macros. */
-static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset);
-
-#define VXGE_TITLE_LEN                 5
-#define VXGE_HW_VPATH_STATS_LEN        27
-#define VXGE_HW_AGGR_STATS_LEN         13
-#define VXGE_HW_PORT_STATS_LEN         94
-#define VXGE_HW_VPATH_TX_STATS_LEN     19
-#define VXGE_HW_VPATH_RX_STATS_LEN     42
-#define VXGE_SW_STATS_LEN              60
-#define VXGE_HW_STATS_LEN      (VXGE_HW_VPATH_STATS_LEN +\
-                               VXGE_HW_AGGR_STATS_LEN +\
-                               VXGE_HW_PORT_STATS_LEN +\
-                               VXGE_HW_VPATH_TX_STATS_LEN +\
-                               VXGE_HW_VPATH_RX_STATS_LEN)
-
-#define DRIVER_STAT_LEN (sizeof(ethtool_driver_stats_keys)/ETH_GSTRING_LEN)
-#define STAT_LEN (VXGE_HW_STATS_LEN + DRIVER_STAT_LEN + VXGE_SW_STATS_LEN)
-
-/* Maximum flicker time of adapter LED */
-#define VXGE_MAX_FLICKER_TIME (60 * HZ) /* 60 seconds */
-#define VXGE_FLICKER_ON                1
-#define VXGE_FLICKER_OFF       0
-
-#define vxge_add_string(fmt, size, buf, ...) {\
-       snprintf(buf + *size, ETH_GSTRING_LEN, fmt, __VA_ARGS__); \
-       *size += ETH_GSTRING_LEN; \
-}
-
-#endif /*_VXGE_ETHTOOL_H*/
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
deleted file mode 100644 (file)
index fa5d4dd..0000000
+++ /dev/null
@@ -1,4808 +0,0 @@
-/******************************************************************************
-* 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 code fall under the GPL and must
-* retain the authorship, copyright and license notice.  This file is not
-* a complete program and may only be used when the entire operating
-* system is licensed under the GPL.
-* See the file COPYING in this distribution for more information.
-*
-* vxge-main.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
-*              Virtualized Server Adapter.
-* Copyright(c) 2002-2010 Exar Corp.
-*
-* The module loadable parameters that are supported by the driver and a brief
-* explanation of all the variables:
-* vlan_tag_strip:
-*      Strip VLAN Tag enable/disable. Instructs the device to remove
-*      the VLAN tag from all received tagged frames that are not
-*      replicated at the internal L2 switch.
-*              0 - Do not strip the VLAN tag.
-*              1 - Strip the VLAN tag.
-*
-* addr_learn_en:
-*      Enable learning the mac address of the guest OS interface in
-*      a virtualization environment.
-*              0 - DISABLE
-*              1 - ENABLE
-*
-* max_config_port:
-*      Maximum number of port to be supported.
-*              MIN -1 and MAX - 2
-*
-* max_config_vpath:
-*      This configures the maximum no of VPATH configures for each
-*      device function.
-*              MIN - 1 and MAX - 17
-*
-* max_config_dev:
-*      This configures maximum no of Device function to be enabled.
-*              MIN - 1 and MAX - 17
-*
-******************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/bitops.h>
-#include <linux/if_vlan.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <net/ip.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/firmware.h>
-#include <linux/net_tstamp.h>
-#include <linux/prefetch.h>
-#include <linux/module.h>
-#include "vxge-main.h"
-#include "vxge-reg.h"
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O"
-       "Virtualized Server Adapter");
-
-static const struct pci_device_id vxge_id_table[] = {
-       {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID,
-       PCI_ANY_ID},
-       {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID,
-       PCI_ANY_ID},
-       {0}
-};
-
-MODULE_DEVICE_TABLE(pci, vxge_id_table);
-
-VXGE_MODULE_PARAM_INT(vlan_tag_strip, VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE);
-VXGE_MODULE_PARAM_INT(addr_learn_en, VXGE_HW_MAC_ADDR_LEARN_DEFAULT);
-VXGE_MODULE_PARAM_INT(max_config_port, VXGE_MAX_CONFIG_PORT);
-VXGE_MODULE_PARAM_INT(max_config_vpath, VXGE_USE_DEFAULT);
-VXGE_MODULE_PARAM_INT(max_mac_vpath, VXGE_MAX_MAC_ADDR_COUNT);
-VXGE_MODULE_PARAM_INT(max_config_dev, VXGE_MAX_CONFIG_DEV);
-
-static u16 vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS] =
-               {0, 1, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, 31};
-static unsigned int bw_percentage[VXGE_HW_MAX_VIRTUAL_PATHS] =
-       {[0 ...(VXGE_HW_MAX_VIRTUAL_PATHS - 1)] = 0xFF};
-module_param_array(bw_percentage, uint, NULL, 0);
-
-static struct vxge_drv_config *driver_config;
-static void vxge_reset_all_vpaths(struct vxgedev *vdev);
-
-static inline int is_vxge_card_up(struct vxgedev *vdev)
-{
-       return test_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-}
-
-static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo)
-{
-       struct sk_buff **skb_ptr = NULL;
-       struct sk_buff **temp;
-#define NR_SKB_COMPLETED 16
-       struct sk_buff *completed[NR_SKB_COMPLETED];
-       int more;
-
-       do {
-               more = 0;
-               skb_ptr = completed;
-
-               if (__netif_tx_trylock(fifo->txq)) {
-                       vxge_hw_vpath_poll_tx(fifo->handle, &skb_ptr,
-                                               NR_SKB_COMPLETED, &more);
-                       __netif_tx_unlock(fifo->txq);
-               }
-
-               /* free SKBs */
-               for (temp = completed; temp != skb_ptr; temp++)
-                       dev_consume_skb_irq(*temp);
-       } while (more);
-}
-
-static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev)
-{
-       int i;
-
-       /* Complete all transmits */
-       for (i = 0; i < vdev->no_of_vpath; i++)
-               VXGE_COMPLETE_VPATH_TX(&vdev->vpaths[i].fifo);
-}
-
-static inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev)
-{
-       int i;
-       struct vxge_ring *ring;
-
-       /* Complete all receives*/
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               ring = &vdev->vpaths[i].ring;
-               vxge_hw_vpath_poll_rx(ring->handle);
-       }
-}
-
-/*
- * vxge_callback_link_up
- *
- * This function is called during interrupt context to notify link up state
- * change.
- */
-static void vxge_callback_link_up(struct __vxge_hw_device *hldev)
-{
-       struct net_device *dev = hldev->ndev;
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-               vdev->ndev->name, __func__, __LINE__);
-       netdev_notice(vdev->ndev, "Link Up\n");
-       vdev->stats.link_up++;
-
-       netif_carrier_on(vdev->ndev);
-       netif_tx_wake_all_queues(vdev->ndev);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
-}
-
-/*
- * vxge_callback_link_down
- *
- * This function is called during interrupt context to notify link down state
- * change.
- */
-static void vxge_callback_link_down(struct __vxge_hw_device *hldev)
-{
-       struct net_device *dev = hldev->ndev;
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
-       netdev_notice(vdev->ndev, "Link Down\n");
-
-       vdev->stats.link_down++;
-       netif_carrier_off(vdev->ndev);
-       netif_tx_stop_all_queues(vdev->ndev);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__);
-}
-
-/*
- * vxge_rx_alloc
- *
- * Allocate SKB.
- */
-static struct sk_buff *
-vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size)
-{
-       struct net_device    *dev;
-       struct sk_buff       *skb;
-       struct vxge_rx_priv *rx_priv;
-
-       dev = ring->ndev;
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-               ring->ndev->name, __func__, __LINE__);
-
-       rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
-
-       /* try to allocate skb first. this one may fail */
-       skb = netdev_alloc_skb(dev, skb_size +
-       VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
-       if (skb == NULL) {
-               vxge_debug_mem(VXGE_ERR,
-                       "%s: out of memory to allocate SKB", dev->name);
-               ring->stats.skb_alloc_fail++;
-               return NULL;
-       }
-
-       vxge_debug_mem(VXGE_TRACE,
-               "%s: %s:%d  Skb : 0x%p", ring->ndev->name,
-               __func__, __LINE__, skb);
-
-       skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
-
-       rx_priv->skb = skb;
-       rx_priv->skb_data = NULL;
-       rx_priv->data_size = skb_size;
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
-
-       return skb;
-}
-
-/*
- * vxge_rx_map
- */
-static int vxge_rx_map(void *dtrh, struct vxge_ring *ring)
-{
-       struct vxge_rx_priv *rx_priv;
-       dma_addr_t dma_addr;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-               ring->ndev->name, __func__, __LINE__);
-       rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
-
-       rx_priv->skb_data = rx_priv->skb->data;
-       dma_addr = dma_map_single(&ring->pdev->dev, rx_priv->skb_data,
-                                 rx_priv->data_size, DMA_FROM_DEVICE);
-
-       if (unlikely(dma_mapping_error(&ring->pdev->dev, dma_addr))) {
-               ring->stats.pci_map_fail++;
-               return -EIO;
-       }
-       vxge_debug_mem(VXGE_TRACE,
-               "%s: %s:%d  1 buffer mode dma_addr = 0x%llx",
-               ring->ndev->name, __func__, __LINE__,
-               (unsigned long long)dma_addr);
-       vxge_hw_ring_rxd_1b_set(dtrh, dma_addr, rx_priv->data_size);
-
-       rx_priv->data_dma = dma_addr;
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
-
-       return 0;
-}
-
-/*
- * vxge_rx_initial_replenish
- * Allocation of RxD as an initial replenish procedure.
- */
-static enum vxge_hw_status
-vxge_rx_initial_replenish(void *dtrh, void *userdata)
-{
-       struct vxge_ring *ring = (struct vxge_ring *)userdata;
-       struct vxge_rx_priv *rx_priv;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-               ring->ndev->name, __func__, __LINE__);
-       if (vxge_rx_alloc(dtrh, ring,
-                         VXGE_LL_MAX_FRAME_SIZE(ring->ndev)) == NULL)
-               return VXGE_HW_FAIL;
-
-       if (vxge_rx_map(dtrh, ring)) {
-               rx_priv = vxge_hw_ring_rxd_private_get(dtrh);
-               dev_kfree_skb(rx_priv->skb);
-
-               return VXGE_HW_FAIL;
-       }
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
-
-       return VXGE_HW_OK;
-}
-
-static inline void
-vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
-                int pkt_length, struct vxge_hw_ring_rxd_info *ext_info)
-{
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-                       ring->ndev->name, __func__, __LINE__);
-       skb_record_rx_queue(skb, ring->driver_id);
-       skb->protocol = eth_type_trans(skb, ring->ndev);
-
-       u64_stats_update_begin(&ring->stats.syncp);
-       ring->stats.rx_frms++;
-       ring->stats.rx_bytes += pkt_length;
-
-       if (skb->pkt_type == PACKET_MULTICAST)
-               ring->stats.rx_mcast++;
-       u64_stats_update_end(&ring->stats.syncp);
-
-       vxge_debug_rx(VXGE_TRACE,
-               "%s: %s:%d  skb protocol = %d",
-               ring->ndev->name, __func__, __LINE__, skb->protocol);
-
-       if (ext_info->vlan &&
-           ring->vlan_tag_strip == VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ext_info->vlan);
-       napi_gro_receive(ring->napi_p, skb);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
-}
-
-static inline void vxge_re_pre_post(void *dtr, struct vxge_ring *ring,
-                                   struct vxge_rx_priv *rx_priv)
-{
-       dma_sync_single_for_device(&ring->pdev->dev, rx_priv->data_dma,
-                                  rx_priv->data_size, DMA_FROM_DEVICE);
-
-       vxge_hw_ring_rxd_1b_set(dtr, rx_priv->data_dma, rx_priv->data_size);
-       vxge_hw_ring_rxd_pre_post(ring->handle, dtr);
-}
-
-static inline void vxge_post(int *dtr_cnt, void **first_dtr,
-                            void *post_dtr, struct __vxge_hw_ring *ringh)
-{
-       int dtr_count = *dtr_cnt;
-       if ((*dtr_cnt % VXGE_HW_RXSYNC_FREQ_CNT) == 0) {
-               if (*first_dtr)
-                       vxge_hw_ring_rxd_post_post_wmb(ringh, *first_dtr);
-               *first_dtr = post_dtr;
-       } else
-               vxge_hw_ring_rxd_post_post(ringh, post_dtr);
-       dtr_count++;
-       *dtr_cnt = dtr_count;
-}
-
-/*
- * vxge_rx_1b_compl
- *
- * If the interrupt is because of a received frame or if the receive ring
- * contains fresh as yet un-processed frames, this function is called.
- */
-static enum vxge_hw_status
-vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
-                u8 t_code, void *userdata)
-{
-       struct vxge_ring *ring = (struct vxge_ring *)userdata;
-       struct net_device *dev = ring->ndev;
-       unsigned int dma_sizes;
-       void *first_dtr = NULL;
-       int dtr_cnt = 0;
-       int data_size;
-       dma_addr_t data_dma;
-       int pkt_length;
-       struct sk_buff *skb;
-       struct vxge_rx_priv *rx_priv;
-       struct vxge_hw_ring_rxd_info ext_info;
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-               ring->ndev->name, __func__, __LINE__);
-
-       if (ring->budget <= 0)
-               goto out;
-
-       do {
-               prefetch((char *)dtr + L1_CACHE_BYTES);
-               rx_priv = vxge_hw_ring_rxd_private_get(dtr);
-               skb = rx_priv->skb;
-               data_size = rx_priv->data_size;
-               data_dma = rx_priv->data_dma;
-               prefetch(rx_priv->skb_data);
-
-               vxge_debug_rx(VXGE_TRACE,
-                       "%s: %s:%d  skb = 0x%p",
-                       ring->ndev->name, __func__, __LINE__, skb);
-
-               vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes);
-               pkt_length = dma_sizes;
-
-               pkt_length -= ETH_FCS_LEN;
-
-               vxge_debug_rx(VXGE_TRACE,
-                       "%s: %s:%d  Packet Length = %d",
-                       ring->ndev->name, __func__, __LINE__, pkt_length);
-
-               vxge_hw_ring_rxd_1b_info_get(ringh, dtr, &ext_info);
-
-               /* check skb validity */
-               vxge_assert(skb);
-
-               prefetch((char *)skb + L1_CACHE_BYTES);
-               if (unlikely(t_code)) {
-                       if (vxge_hw_ring_handle_tcode(ringh, dtr, t_code) !=
-                               VXGE_HW_OK) {
-
-                               ring->stats.rx_errors++;
-                               vxge_debug_rx(VXGE_TRACE,
-                                       "%s: %s :%d Rx T_code is %d",
-                                       ring->ndev->name, __func__,
-                                       __LINE__, t_code);
-
-                               /* If the t_code is not supported and if the
-                                * t_code is other than 0x5 (unparseable packet
-                                * such as unknown UPV6 header), Drop it !!!
-                                */
-                               vxge_re_pre_post(dtr, ring, rx_priv);
-
-                               vxge_post(&dtr_cnt, &first_dtr, dtr, ringh);
-                               ring->stats.rx_dropped++;
-                               continue;
-                       }
-               }
-
-               if (pkt_length > VXGE_LL_RX_COPY_THRESHOLD) {
-                       if (vxge_rx_alloc(dtr, ring, data_size) != NULL) {
-                               if (!vxge_rx_map(dtr, ring)) {
-                                       skb_put(skb, pkt_length);
-
-                                       dma_unmap_single(&ring->pdev->dev,
-                                                        data_dma, data_size,
-                                                        DMA_FROM_DEVICE);
-
-                                       vxge_hw_ring_rxd_pre_post(ringh, dtr);
-                                       vxge_post(&dtr_cnt, &first_dtr, dtr,
-                                               ringh);
-                               } else {
-                                       dev_kfree_skb(rx_priv->skb);
-                                       rx_priv->skb = skb;
-                                       rx_priv->data_size = data_size;
-                                       vxge_re_pre_post(dtr, ring, rx_priv);
-
-                                       vxge_post(&dtr_cnt, &first_dtr, dtr,
-                                               ringh);
-                                       ring->stats.rx_dropped++;
-                                       break;
-                               }
-                       } else {
-                               vxge_re_pre_post(dtr, ring, rx_priv);
-
-                               vxge_post(&dtr_cnt, &first_dtr, dtr, ringh);
-                               ring->stats.rx_dropped++;
-                               break;
-                       }
-               } else {
-                       struct sk_buff *skb_up;
-
-                       skb_up = netdev_alloc_skb(dev, pkt_length +
-                               VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
-                       if (skb_up != NULL) {
-                               skb_reserve(skb_up,
-                                   VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN);
-
-                               dma_sync_single_for_cpu(&ring->pdev->dev,
-                                                       data_dma, data_size,
-                                                       DMA_FROM_DEVICE);
-
-                               vxge_debug_mem(VXGE_TRACE,
-                                       "%s: %s:%d  skb_up = %p",
-                                       ring->ndev->name, __func__,
-                                       __LINE__, skb);
-                               memcpy(skb_up->data, skb->data, pkt_length);
-
-                               vxge_re_pre_post(dtr, ring, rx_priv);
-
-                               vxge_post(&dtr_cnt, &first_dtr, dtr,
-                                       ringh);
-                               /* will netif_rx small SKB instead */
-                               skb = skb_up;
-                               skb_put(skb, pkt_length);
-                       } else {
-                               vxge_re_pre_post(dtr, ring, rx_priv);
-
-                               vxge_post(&dtr_cnt, &first_dtr, dtr, ringh);
-                               vxge_debug_rx(VXGE_ERR,
-                                       "%s: vxge_rx_1b_compl: out of "
-                                       "memory", dev->name);
-                               ring->stats.skb_alloc_fail++;
-                               break;
-                       }
-               }
-
-               if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) &&
-                   !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) &&
-                   (dev->features & NETIF_F_RXCSUM) && /* Offload Rx side CSUM */
-                   ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK &&
-                   ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK)
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-               else
-                       skb_checksum_none_assert(skb);
-
-
-               if (ring->rx_hwts) {
-                       struct skb_shared_hwtstamps *skb_hwts;
-                       u32 ns = *(u32 *)(skb->head + pkt_length);
-
-                       skb_hwts = skb_hwtstamps(skb);
-                       skb_hwts->hwtstamp = ns_to_ktime(ns);
-               }
-
-               /* rth_hash_type and rth_it_hit are non-zero regardless of
-                * whether rss is enabled.  Only the rth_value is zero/non-zero
-                * if rss is disabled/enabled, so key off of that.
-                */
-               if (ext_info.rth_value)
-                       skb_set_hash(skb, ext_info.rth_value,
-                                    PKT_HASH_TYPE_L3);
-
-               vxge_rx_complete(ring, skb, ext_info.vlan,
-                       pkt_length, &ext_info);
-
-               ring->budget--;
-               ring->pkts_processed++;
-               if (!ring->budget)
-                       break;
-
-       } while (vxge_hw_ring_rxd_next_completed(ringh, &dtr,
-               &t_code) == VXGE_HW_OK);
-
-       if (first_dtr)
-               vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr);
-
-out:
-       vxge_debug_entryexit(VXGE_TRACE,
-                               "%s:%d  Exiting...",
-                               __func__, __LINE__);
-       return VXGE_HW_OK;
-}
-
-/*
- * vxge_xmit_compl
- *
- * If an interrupt was raised to indicate DMA complete of the Tx packet,
- * this function is called. It identifies the last TxD whose buffer was
- * freed and frees all skbs whose data have already DMA'ed into the NICs
- * internal memory.
- */
-static enum vxge_hw_status
-vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr,
-               enum vxge_hw_fifo_tcode t_code, void *userdata,
-               struct sk_buff ***skb_ptr, int nr_skb, int *more)
-{
-       struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
-       struct sk_buff *skb, **done_skb = *skb_ptr;
-       int pkt_cnt = 0;
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d Entered....", __func__, __LINE__);
-
-       do {
-               int frg_cnt;
-               skb_frag_t *frag;
-               int i = 0, j;
-               struct vxge_tx_priv *txd_priv =
-                       vxge_hw_fifo_txdl_private_get(dtr);
-
-               skb = txd_priv->skb;
-               frg_cnt = skb_shinfo(skb)->nr_frags;
-               frag = &skb_shinfo(skb)->frags[0];
-
-               vxge_debug_tx(VXGE_TRACE,
-                               "%s: %s:%d fifo_hw = %p dtr = %p "
-                               "tcode = 0x%x", fifo->ndev->name, __func__,
-                               __LINE__, fifo_hw, dtr, t_code);
-               /* check skb validity */
-               vxge_assert(skb);
-               vxge_debug_tx(VXGE_TRACE,
-                       "%s: %s:%d skb = %p itxd_priv = %p frg_cnt = %d",
-                       fifo->ndev->name, __func__, __LINE__,
-                       skb, txd_priv, frg_cnt);
-               if (unlikely(t_code)) {
-                       fifo->stats.tx_errors++;
-                       vxge_debug_tx(VXGE_ERR,
-                               "%s: tx: dtr %p completed due to "
-                               "error t_code %01x", fifo->ndev->name,
-                               dtr, t_code);
-                       vxge_hw_fifo_handle_tcode(fifo_hw, dtr, t_code);
-               }
-
-               /*  for unfragmented skb */
-               dma_unmap_single(&fifo->pdev->dev, txd_priv->dma_buffers[i++],
-                                skb_headlen(skb), DMA_TO_DEVICE);
-
-               for (j = 0; j < frg_cnt; j++) {
-                       dma_unmap_page(&fifo->pdev->dev,
-                                      txd_priv->dma_buffers[i++],
-                                      skb_frag_size(frag), DMA_TO_DEVICE);
-                       frag += 1;
-               }
-
-               vxge_hw_fifo_txdl_free(fifo_hw, dtr);
-
-               /* Updating the statistics block */
-               u64_stats_update_begin(&fifo->stats.syncp);
-               fifo->stats.tx_frms++;
-               fifo->stats.tx_bytes += skb->len;
-               u64_stats_update_end(&fifo->stats.syncp);
-
-               *done_skb++ = skb;
-
-               if (--nr_skb <= 0) {
-                       *more = 1;
-                       break;
-               }
-
-               pkt_cnt++;
-               if (pkt_cnt > fifo->indicate_max_pkts)
-                       break;
-
-       } while (vxge_hw_fifo_txdl_next_completed(fifo_hw,
-                               &dtr, &t_code) == VXGE_HW_OK);
-
-       *skb_ptr = done_skb;
-       if (netif_tx_queue_stopped(fifo->txq))
-               netif_tx_wake_queue(fifo->txq);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-                               "%s: %s:%d  Exiting...",
-                               fifo->ndev->name, __func__, __LINE__);
-       return VXGE_HW_OK;
-}
-
-/* select a vpath to transmit the packet */
-static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb)
-{
-       u16 queue_len, counter = 0;
-       if (skb->protocol == htons(ETH_P_IP)) {
-               struct iphdr *ip;
-               struct tcphdr *th;
-
-               ip = ip_hdr(skb);
-
-               if (!ip_is_fragment(ip)) {
-                       th = (struct tcphdr *)(((unsigned char *)ip) +
-                                       ip->ihl*4);
-
-                       queue_len = vdev->no_of_vpath;
-                       counter = (ntohs(th->source) +
-                               ntohs(th->dest)) &
-                               vdev->vpath_selector[queue_len - 1];
-                       if (counter >= queue_len)
-                               counter = queue_len - 1;
-               }
-       }
-       return counter;
-}
-
-static enum vxge_hw_status vxge_search_mac_addr_in_list(
-       struct vxge_vpath *vpath, u64 del_mac)
-{
-       struct list_head *entry, *next;
-       list_for_each_safe(entry, next, &vpath->mac_addr_list) {
-               if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac)
-                       return TRUE;
-       }
-       return FALSE;
-}
-
-static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac)
-{
-       struct vxge_mac_addrs *new_mac_entry;
-       u8 *mac_address = NULL;
-
-       if (vpath->mac_addr_cnt >= VXGE_MAX_LEARN_MAC_ADDR_CNT)
-               return TRUE;
-
-       new_mac_entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_ATOMIC);
-       if (!new_mac_entry) {
-               vxge_debug_mem(VXGE_ERR,
-                       "%s: memory allocation failed",
-                       VXGE_DRIVER_NAME);
-               return FALSE;
-       }
-
-       list_add(&new_mac_entry->item, &vpath->mac_addr_list);
-
-       /* Copy the new mac address to the list */
-       mac_address = (u8 *)&new_mac_entry->macaddr;
-       memcpy(mac_address, mac->macaddr, ETH_ALEN);
-
-       new_mac_entry->state = mac->state;
-       vpath->mac_addr_cnt++;
-
-       if (is_multicast_ether_addr(mac->macaddr))
-               vpath->mcast_addr_cnt++;
-
-       return TRUE;
-}
-
-/* Add a mac address to DA table */
-static enum vxge_hw_status
-vxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_vpath *vpath;
-       enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode;
-
-       if (is_multicast_ether_addr(mac->macaddr))
-               duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE;
-       else
-               duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE;
-
-       vpath = &vdev->vpaths[mac->vpath_no];
-       status = vxge_hw_vpath_mac_addr_add(vpath->handle, mac->macaddr,
-                                               mac->macmask, duplicate_mode);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "DA config add entry failed for vpath:%d",
-                       vpath->device_id);
-       } else
-               if (FALSE == vxge_mac_list_add(vpath, mac))
-                       status = -EPERM;
-
-       return status;
-}
-
-static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
-{
-       struct macInfo mac_info;
-       u8 *mac_address = NULL;
-       u64 mac_addr = 0, vpath_vector = 0;
-       int vpath_idx = 0;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_vpath *vpath = NULL;
-
-       mac_address = (u8 *)&mac_addr;
-       memcpy(mac_address, mac_header, ETH_ALEN);
-
-       /* Is this mac address already in the list? */
-       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
-               vpath = &vdev->vpaths[vpath_idx];
-               if (vxge_search_mac_addr_in_list(vpath, mac_addr))
-                       return vpath_idx;
-       }
-
-       memset(&mac_info, 0, sizeof(struct macInfo));
-       memcpy(mac_info.macaddr, mac_header, ETH_ALEN);
-
-       /* Any vpath has room to add mac address to its da table? */
-       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
-               vpath = &vdev->vpaths[vpath_idx];
-               if (vpath->mac_addr_cnt < vpath->max_mac_addr_cnt) {
-                       /* Add this mac address to this vpath */
-                       mac_info.vpath_no = vpath_idx;
-                       mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE;
-                       status = vxge_add_mac_addr(vdev, &mac_info);
-                       if (status != VXGE_HW_OK)
-                               return -EPERM;
-                       return vpath_idx;
-               }
-       }
-
-       mac_info.state = VXGE_LL_MAC_ADDR_IN_LIST;
-       vpath_idx = 0;
-       mac_info.vpath_no = vpath_idx;
-       /* Is the first vpath already selected as catch-basin ? */
-       vpath = &vdev->vpaths[vpath_idx];
-       if (vpath->mac_addr_cnt > vpath->max_mac_addr_cnt) {
-               /* Add this mac address to this vpath */
-               if (FALSE == vxge_mac_list_add(vpath, &mac_info))
-                       return -EPERM;
-               return vpath_idx;
-       }
-
-       /* Select first vpath as catch-basin */
-       vpath_vector = vxge_mBIT(vpath->device_id);
-       status = vxge_hw_mgmt_reg_write(vpath->vdev->devh,
-                               vxge_hw_mgmt_reg_type_mrpcim,
-                               0,
-                               (ulong)offsetof(
-                                       struct vxge_hw_mrpcim_reg,
-                                       rts_mgr_cbasin_cfg),
-                               vpath_vector);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_tx(VXGE_ERR,
-                       "%s: Unable to set the vpath-%d in catch-basin mode",
-                       VXGE_DRIVER_NAME, vpath->device_id);
-               return -EPERM;
-       }
-
-       if (FALSE == vxge_mac_list_add(vpath, &mac_info))
-               return -EPERM;
-
-       return vpath_idx;
-}
-
-/**
- * vxge_xmit
- * @skb : the socket buffer containing the Tx data.
- * @dev : device pointer.
- *
- * This function is the Tx entry point of the driver. Neterion NIC supports
- * certain protocol assist features on Tx side, namely  CSO, S/G, LSO.
-*/
-static netdev_tx_t
-vxge_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct vxge_fifo *fifo = NULL;
-       void *dtr_priv;
-       void *dtr = NULL;
-       struct vxgedev *vdev = NULL;
-       enum vxge_hw_status status;
-       int frg_cnt, first_frg_len;
-       skb_frag_t *frag;
-       int i = 0, j = 0, avail;
-       u64 dma_pointer;
-       struct vxge_tx_priv *txdl_priv = NULL;
-       struct __vxge_hw_fifo *fifo_hw;
-       int offload_type;
-       int vpath_no = 0;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-                       dev->name, __func__, __LINE__);
-
-       /* A buffer with no data will be dropped */
-       if (unlikely(skb->len <= 0)) {
-               vxge_debug_tx(VXGE_ERR,
-                       "%s: Buffer has no data..", dev->name);
-               dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
-       }
-
-       vdev = netdev_priv(dev);
-
-       if (unlikely(!is_vxge_card_up(vdev))) {
-               vxge_debug_tx(VXGE_ERR,
-                       "%s: vdev not initialized", dev->name);
-               dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
-       }
-
-       if (vdev->config.addr_learn_en) {
-               vpath_no = vxge_learn_mac(vdev, skb->data + ETH_ALEN);
-               if (vpath_no == -EPERM) {
-                       vxge_debug_tx(VXGE_ERR,
-                               "%s: Failed to store the mac address",
-                               dev->name);
-                       dev_kfree_skb_any(skb);
-                       return NETDEV_TX_OK;
-               }
-       }
-
-       if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING)
-               vpath_no = skb_get_queue_mapping(skb);
-       else if (vdev->config.tx_steering_type == TX_PORT_STEERING)
-               vpath_no = vxge_get_vpath_no(vdev, skb);
-
-       vxge_debug_tx(VXGE_TRACE, "%s: vpath_no= %d", dev->name, vpath_no);
-
-       if (vpath_no >= vdev->no_of_vpath)
-               vpath_no = 0;
-
-       fifo = &vdev->vpaths[vpath_no].fifo;
-       fifo_hw = fifo->handle;
-
-       if (netif_tx_queue_stopped(fifo->txq))
-               return NETDEV_TX_BUSY;
-
-       avail = vxge_hw_fifo_free_txdl_count_get(fifo_hw);
-       if (avail == 0) {
-               vxge_debug_tx(VXGE_ERR,
-                       "%s: No free TXDs available", dev->name);
-               fifo->stats.txd_not_free++;
-               goto _exit0;
-       }
-
-       /* Last TXD?  Stop tx queue to avoid dropping packets.  TX
-        * completion will resume the queue.
-        */
-       if (avail == 1)
-               netif_tx_stop_queue(fifo->txq);
-
-       status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv);
-       if (unlikely(status != VXGE_HW_OK)) {
-               vxge_debug_tx(VXGE_ERR,
-                  "%s: Out of descriptors .", dev->name);
-               fifo->stats.txd_out_of_desc++;
-               goto _exit0;
-       }
-
-       vxge_debug_tx(VXGE_TRACE,
-               "%s: %s:%d fifo_hw = %p dtr = %p dtr_priv = %p",
-               dev->name, __func__, __LINE__,
-               fifo_hw, dtr, dtr_priv);
-
-       if (skb_vlan_tag_present(skb)) {
-               u16 vlan_tag = skb_vlan_tag_get(skb);
-               vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag);
-       }
-
-       first_frg_len = skb_headlen(skb);
-
-       dma_pointer = dma_map_single(&fifo->pdev->dev, skb->data,
-                                    first_frg_len, DMA_TO_DEVICE);
-
-       if (unlikely(dma_mapping_error(&fifo->pdev->dev, dma_pointer))) {
-               vxge_hw_fifo_txdl_free(fifo_hw, dtr);
-               fifo->stats.pci_map_fail++;
-               goto _exit0;
-       }
-
-       txdl_priv = vxge_hw_fifo_txdl_private_get(dtr);
-       txdl_priv->skb = skb;
-       txdl_priv->dma_buffers[j] = dma_pointer;
-
-       frg_cnt = skb_shinfo(skb)->nr_frags;
-       vxge_debug_tx(VXGE_TRACE,
-                       "%s: %s:%d skb = %p txdl_priv = %p "
-                       "frag_cnt = %d dma_pointer = 0x%llx", dev->name,
-                       __func__, __LINE__, skb, txdl_priv,
-                       frg_cnt, (unsigned long long)dma_pointer);
-
-       vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer,
-               first_frg_len);
-
-       frag = &skb_shinfo(skb)->frags[0];
-       for (i = 0; i < frg_cnt; i++) {
-               /* ignore 0 length fragment */
-               if (!skb_frag_size(frag))
-                       continue;
-
-               dma_pointer = (u64)skb_frag_dma_map(&fifo->pdev->dev, frag,
-                                                   0, skb_frag_size(frag),
-                                                   DMA_TO_DEVICE);
-
-               if (unlikely(dma_mapping_error(&fifo->pdev->dev, dma_pointer)))
-                       goto _exit2;
-               vxge_debug_tx(VXGE_TRACE,
-                       "%s: %s:%d frag = %d dma_pointer = 0x%llx",
-                               dev->name, __func__, __LINE__, i,
-                               (unsigned long long)dma_pointer);
-
-               txdl_priv->dma_buffers[j] = dma_pointer;
-               vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer,
-                                       skb_frag_size(frag));
-               frag += 1;
-       }
-
-       offload_type = vxge_offload_type(skb);
-
-       if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
-               int mss = vxge_tcp_mss(skb);
-               if (mss) {
-                       vxge_debug_tx(VXGE_TRACE, "%s: %s:%d mss = %d",
-                               dev->name, __func__, __LINE__, mss);
-                       vxge_hw_fifo_txdl_mss_set(dtr, mss);
-               } else {
-                       vxge_assert(skb->len <=
-                               dev->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE);
-                       vxge_assert(0);
-                       goto _exit1;
-               }
-       }
-
-       if (skb->ip_summed == CHECKSUM_PARTIAL)
-               vxge_hw_fifo_txdl_cksum_set_bits(dtr,
-                                       VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN |
-                                       VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN |
-                                       VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN);
-
-       vxge_hw_fifo_txdl_post(fifo_hw, dtr);
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
-               dev->name, __func__, __LINE__);
-       return NETDEV_TX_OK;
-
-_exit2:
-       vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
-_exit1:
-       j = 0;
-       frag = &skb_shinfo(skb)->frags[0];
-
-       dma_unmap_single(&fifo->pdev->dev, txdl_priv->dma_buffers[j++],
-                        skb_headlen(skb), DMA_TO_DEVICE);
-
-       for (; j < i; j++) {
-               dma_unmap_page(&fifo->pdev->dev, txdl_priv->dma_buffers[j],
-                              skb_frag_size(frag), DMA_TO_DEVICE);
-               frag += 1;
-       }
-
-       vxge_hw_fifo_txdl_free(fifo_hw, dtr);
-_exit0:
-       netif_tx_stop_queue(fifo->txq);
-       dev_kfree_skb_any(skb);
-
-       return NETDEV_TX_OK;
-}
-
-/*
- * vxge_rx_term
- *
- * Function will be called by hw function to abort all outstanding receive
- * descriptors.
- */
-static void
-vxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata)
-{
-       struct vxge_ring *ring = (struct vxge_ring *)userdata;
-       struct vxge_rx_priv *rx_priv =
-               vxge_hw_ring_rxd_private_get(dtrh);
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-                       ring->ndev->name, __func__, __LINE__);
-       if (state != VXGE_HW_RXD_STATE_POSTED)
-               return;
-
-       dma_unmap_single(&ring->pdev->dev, rx_priv->data_dma,
-                        rx_priv->data_size, DMA_FROM_DEVICE);
-
-       dev_kfree_skb(rx_priv->skb);
-       rx_priv->skb_data = NULL;
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d  Exiting...",
-               ring->ndev->name, __func__, __LINE__);
-}
-
-/*
- * vxge_tx_term
- *
- * Function will be called to abort all outstanding tx descriptors
- */
-static void
-vxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata)
-{
-       struct vxge_fifo *fifo = (struct vxge_fifo *)userdata;
-       skb_frag_t *frag;
-       int i = 0, j, frg_cnt;
-       struct vxge_tx_priv *txd_priv = vxge_hw_fifo_txdl_private_get(dtrh);
-       struct sk_buff *skb = txd_priv->skb;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       if (state != VXGE_HW_TXDL_STATE_POSTED)
-               return;
-
-       /* check skb validity */
-       vxge_assert(skb);
-       frg_cnt = skb_shinfo(skb)->nr_frags;
-       frag = &skb_shinfo(skb)->frags[0];
-
-       /*  for unfragmented skb */
-       dma_unmap_single(&fifo->pdev->dev, txd_priv->dma_buffers[i++],
-                        skb_headlen(skb), DMA_TO_DEVICE);
-
-       for (j = 0; j < frg_cnt; j++) {
-               dma_unmap_page(&fifo->pdev->dev, txd_priv->dma_buffers[i++],
-                              skb_frag_size(frag), DMA_TO_DEVICE);
-               frag += 1;
-       }
-
-       dev_kfree_skb(skb);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d  Exiting...", __func__, __LINE__);
-}
-
-static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac)
-{
-       struct list_head *entry, *next;
-       u64 del_mac = 0;
-       u8 *mac_address = (u8 *) (&del_mac);
-
-       /* Copy the mac address to delete from the list */
-       memcpy(mac_address, mac->macaddr, ETH_ALEN);
-
-       list_for_each_safe(entry, next, &vpath->mac_addr_list) {
-               if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) {
-                       list_del(entry);
-                       kfree(entry);
-                       vpath->mac_addr_cnt--;
-
-                       if (is_multicast_ether_addr(mac->macaddr))
-                               vpath->mcast_addr_cnt--;
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-/* delete a mac address from DA table */
-static enum vxge_hw_status
-vxge_del_mac_addr(struct vxgedev *vdev, struct macInfo *mac)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_vpath *vpath;
-
-       vpath = &vdev->vpaths[mac->vpath_no];
-       status = vxge_hw_vpath_mac_addr_delete(vpath->handle, mac->macaddr,
-                                               mac->macmask);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "DA config delete entry failed for vpath:%d",
-                       vpath->device_id);
-       } else
-               vxge_mac_list_del(vpath, mac);
-       return status;
-}
-
-/**
- * vxge_set_multicast
- * @dev: pointer to the device structure
- *
- * Entry point for multicast address enable/disable
- * This function is a driver entry point which gets called by the kernel
- * whenever multicast addresses must be enabled/disabled. This also gets
- * called to set/reset promiscuous mode. Depending on the deivce flag, we
- * determine, if multicast address must be enabled or if promiscuous mode
- * is to be disabled etc.
- */
-static void vxge_set_multicast(struct net_device *dev)
-{
-       struct netdev_hw_addr *ha;
-       struct vxgedev *vdev;
-       int i, mcast_cnt = 0;
-       struct vxge_vpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct macInfo mac_info;
-       int vpath_idx = 0;
-       struct vxge_mac_addrs *mac_entry;
-       struct list_head *list_head;
-       struct list_head *entry, *next;
-       u8 *mac_address = NULL;
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d", __func__, __LINE__);
-
-       vdev = netdev_priv(dev);
-
-       if (unlikely(!is_vxge_card_up(vdev)))
-               return;
-
-       if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       vxge_assert(vpath->is_open);
-                       status = vxge_hw_vpath_mcast_enable(vpath->handle);
-                       if (status != VXGE_HW_OK)
-                               vxge_debug_init(VXGE_ERR, "failed to enable "
-                                               "multicast, status %d", status);
-                       vdev->all_multi_flg = 1;
-               }
-       } else if (!(dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       vxge_assert(vpath->is_open);
-                       status = vxge_hw_vpath_mcast_disable(vpath->handle);
-                       if (status != VXGE_HW_OK)
-                               vxge_debug_init(VXGE_ERR, "failed to disable "
-                                               "multicast, status %d", status);
-                       vdev->all_multi_flg = 0;
-               }
-       }
-
-
-       if (!vdev->config.addr_learn_en) {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       vxge_assert(vpath->is_open);
-
-                       if (dev->flags & IFF_PROMISC)
-                               status = vxge_hw_vpath_promisc_enable(
-                                       vpath->handle);
-                       else
-                               status = vxge_hw_vpath_promisc_disable(
-                                       vpath->handle);
-                       if (status != VXGE_HW_OK)
-                               vxge_debug_init(VXGE_ERR, "failed to %s promisc"
-                                       ", status %d", dev->flags&IFF_PROMISC ?
-                                       "enable" : "disable", status);
-               }
-       }
-
-       memset(&mac_info, 0, sizeof(struct macInfo));
-       /* Update individual M_CAST address list */
-       if ((!vdev->all_multi_flg) && netdev_mc_count(dev)) {
-               mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
-               list_head = &vdev->vpaths[0].mac_addr_list;
-               if ((netdev_mc_count(dev) +
-                       (vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) >
-                               vdev->vpaths[0].max_mac_addr_cnt)
-                       goto _set_all_mcast;
-
-               /* Delete previous MC's */
-               for (i = 0; i < mcast_cnt; i++) {
-                       list_for_each_safe(entry, next, list_head) {
-                               mac_entry = (struct vxge_mac_addrs *)entry;
-                               /* Copy the mac address to delete */
-                               mac_address = (u8 *)&mac_entry->macaddr;
-                               memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
-
-                               if (is_multicast_ether_addr(mac_info.macaddr)) {
-                                       for (vpath_idx = 0; vpath_idx <
-                                               vdev->no_of_vpath;
-                                               vpath_idx++) {
-                                               mac_info.vpath_no = vpath_idx;
-                                               status = vxge_del_mac_addr(
-                                                               vdev,
-                                                               &mac_info);
-                                       }
-                               }
-                       }
-               }
-
-               /* Add new ones */
-               netdev_for_each_mc_addr(ha, dev) {
-                       memcpy(mac_info.macaddr, ha->addr, ETH_ALEN);
-                       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
-                                       vpath_idx++) {
-                               mac_info.vpath_no = vpath_idx;
-                               mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE;
-                               status = vxge_add_mac_addr(vdev, &mac_info);
-                               if (status != VXGE_HW_OK) {
-                                       vxge_debug_init(VXGE_ERR,
-                                               "%s:%d Setting individual"
-                                               "multicast address failed",
-                                               __func__, __LINE__);
-                                       goto _set_all_mcast;
-                               }
-                       }
-               }
-
-               return;
-_set_all_mcast:
-               mcast_cnt = vdev->vpaths[0].mcast_addr_cnt;
-               /* Delete previous MC's */
-               for (i = 0; i < mcast_cnt; i++) {
-                       list_for_each_safe(entry, next, list_head) {
-                               mac_entry = (struct vxge_mac_addrs *)entry;
-                               /* Copy the mac address to delete */
-                               mac_address = (u8 *)&mac_entry->macaddr;
-                               memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
-
-                               if (is_multicast_ether_addr(mac_info.macaddr))
-                                       break;
-                       }
-
-                       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
-                                       vpath_idx++) {
-                               mac_info.vpath_no = vpath_idx;
-                               status = vxge_del_mac_addr(vdev, &mac_info);
-                       }
-               }
-
-               /* Enable all multicast */
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       vxge_assert(vpath->is_open);
-
-                       status = vxge_hw_vpath_mcast_enable(vpath->handle);
-                       if (status != VXGE_HW_OK) {
-                               vxge_debug_init(VXGE_ERR,
-                                       "%s:%d Enabling all multicasts failed",
-                                        __func__, __LINE__);
-                       }
-                       vdev->all_multi_flg = 1;
-               }
-               dev->flags |= IFF_ALLMULTI;
-       }
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d  Exiting...", __func__, __LINE__);
-}
-
-/**
- * vxge_set_mac_addr
- * @dev: pointer to the device structure
- * @p: socket info
- *
- * Update entry "0" (default MAC addr)
- */
-static int vxge_set_mac_addr(struct net_device *dev, void *p)
-{
-       struct sockaddr *addr = p;
-       struct vxgedev *vdev;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct macInfo mac_info_new, mac_info_old;
-       int vpath_idx = 0;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       vdev = netdev_priv(dev);
-
-       if (!is_valid_ether_addr(addr->sa_data))
-               return -EINVAL;
-
-       memset(&mac_info_new, 0, sizeof(struct macInfo));
-       memset(&mac_info_old, 0, sizeof(struct macInfo));
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d  Exiting...",
-               __func__, __LINE__);
-
-       /* Get the old address */
-       memcpy(mac_info_old.macaddr, dev->dev_addr, dev->addr_len);
-
-       /* Copy the new address */
-       memcpy(mac_info_new.macaddr, addr->sa_data, dev->addr_len);
-
-       /* First delete the old mac address from all the vpaths
-       as we can't specify the index while adding new mac address */
-       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
-               struct vxge_vpath *vpath = &vdev->vpaths[vpath_idx];
-               if (!vpath->is_open) {
-                       /* This can happen when this interface is added/removed
-                       to the bonding interface. Delete this station address
-                       from the linked list */
-                       vxge_mac_list_del(vpath, &mac_info_old);
-
-                       /* Add this new address to the linked list
-                       for later restoring */
-                       vxge_mac_list_add(vpath, &mac_info_new);
-
-                       continue;
-               }
-               /* Delete the station address */
-               mac_info_old.vpath_no = vpath_idx;
-               status = vxge_del_mac_addr(vdev, &mac_info_old);
-       }
-
-       if (unlikely(!is_vxge_card_up(vdev))) {
-               eth_hw_addr_set(dev, addr->sa_data);
-               return VXGE_HW_OK;
-       }
-
-       /* Set this mac address to all the vpaths */
-       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
-               mac_info_new.vpath_no = vpath_idx;
-               mac_info_new.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE;
-               status = vxge_add_mac_addr(vdev, &mac_info_new);
-               if (status != VXGE_HW_OK)
-                       return -EINVAL;
-       }
-
-       eth_hw_addr_set(dev, addr->sa_data);
-
-       return status;
-}
-
-/*
- * vxge_vpath_intr_enable
- * @vdev: pointer to vdev
- * @vp_id: vpath for which to enable the interrupts
- *
- * Enables the interrupts for the vpath
-*/
-static void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
-{
-       struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
-       int msix_id = 0;
-       int tim_msix_id[4] = {0, 1, 0, 0};
-       int alarm_msix_id = VXGE_ALARM_MSIX_ID;
-
-       vxge_hw_vpath_intr_enable(vpath->handle);
-
-       if (vdev->config.intr_type == INTA)
-               vxge_hw_vpath_inta_unmask_tx_rx(vpath->handle);
-       else {
-               vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id,
-                       alarm_msix_id);
-
-               msix_id = vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE;
-               vxge_hw_vpath_msix_unmask(vpath->handle, msix_id);
-               vxge_hw_vpath_msix_unmask(vpath->handle, msix_id + 1);
-
-               /* enable the alarm vector */
-               msix_id = (vpath->handle->vpath->hldev->first_vp_id *
-                       VXGE_HW_VPATH_MSIX_ACTIVE) + alarm_msix_id;
-               vxge_hw_vpath_msix_unmask(vpath->handle, msix_id);
-       }
-}
-
-/*
- * vxge_vpath_intr_disable
- * @vdev: pointer to vdev
- * @vp_id: vpath for which to disable the interrupts
- *
- * Disables the interrupts for the vpath
-*/
-static void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
-{
-       struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
-       struct __vxge_hw_device *hldev;
-       int msix_id;
-
-       hldev = pci_get_drvdata(vdev->pdev);
-
-       vxge_hw_vpath_wait_receive_idle(hldev, vpath->device_id);
-
-       vxge_hw_vpath_intr_disable(vpath->handle);
-
-       if (vdev->config.intr_type == INTA)
-               vxge_hw_vpath_inta_mask_tx_rx(vpath->handle);
-       else {
-               msix_id = vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE;
-               vxge_hw_vpath_msix_mask(vpath->handle, msix_id);
-               vxge_hw_vpath_msix_mask(vpath->handle, msix_id + 1);
-
-               /* disable the alarm vector */
-               msix_id = (vpath->handle->vpath->hldev->first_vp_id *
-                       VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID;
-               vxge_hw_vpath_msix_mask(vpath->handle, msix_id);
-       }
-}
-
-/* list all mac addresses from DA table */
-static enum vxge_hw_status
-vxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath, struct macInfo *mac)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       unsigned char macmask[ETH_ALEN];
-       unsigned char macaddr[ETH_ALEN];
-
-       status = vxge_hw_vpath_mac_addr_get(vpath->handle,
-                               macaddr, macmask);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "DA config list entry failed for vpath:%d",
-                       vpath->device_id);
-               return status;
-       }
-
-       while (!ether_addr_equal(mac->macaddr, macaddr)) {
-               status = vxge_hw_vpath_mac_addr_get_next(vpath->handle,
-                               macaddr, macmask);
-               if (status != VXGE_HW_OK)
-                       break;
-       }
-
-       return status;
-}
-
-/* Store all mac addresses from the list to the DA table */
-static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct macInfo mac_info;
-       u8 *mac_address = NULL;
-       struct list_head *entry, *next;
-
-       memset(&mac_info, 0, sizeof(struct macInfo));
-
-       if (vpath->is_open) {
-               list_for_each_safe(entry, next, &vpath->mac_addr_list) {
-                       mac_address =
-                               (u8 *)&
-                               ((struct vxge_mac_addrs *)entry)->macaddr;
-                       memcpy(mac_info.macaddr, mac_address, ETH_ALEN);
-                       ((struct vxge_mac_addrs *)entry)->state =
-                               VXGE_LL_MAC_ADDR_IN_DA_TABLE;
-                       /* does this mac address already exist in da table? */
-                       status = vxge_search_mac_addr_in_da_table(vpath,
-                               &mac_info);
-                       if (status != VXGE_HW_OK) {
-                               /* Add this mac address to the DA table */
-                               status = vxge_hw_vpath_mac_addr_add(
-                                       vpath->handle, mac_info.macaddr,
-                                       mac_info.macmask,
-                                   VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE);
-                               if (status != VXGE_HW_OK) {
-                                       vxge_debug_init(VXGE_ERR,
-                                           "DA add entry failed for vpath:%d",
-                                           vpath->device_id);
-                                       ((struct vxge_mac_addrs *)entry)->state
-                                               = VXGE_LL_MAC_ADDR_IN_LIST;
-                               }
-                       }
-               }
-       }
-
-       return status;
-}
-
-/* Store all vlan ids from the list to the vid table */
-static enum vxge_hw_status
-vxge_restore_vpath_vid_table(struct vxge_vpath *vpath)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxgedev *vdev = vpath->vdev;
-       u16 vid;
-
-       if (!vpath->is_open)
-               return status;
-
-       for_each_set_bit(vid, vdev->active_vlans, VLAN_N_VID)
-               status = vxge_hw_vpath_vid_add(vpath->handle, vid);
-
-       return status;
-}
-
-/*
- * vxge_reset_vpath
- * @vdev: pointer to vdev
- * @vp_id: vpath to reset
- *
- * Resets the vpath
-*/
-static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
-       int ret = 0;
-
-       /* check if device is down already */
-       if (unlikely(!is_vxge_card_up(vdev)))
-               return 0;
-
-       /* is device reset already scheduled */
-       if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
-               return 0;
-
-       if (vpath->handle) {
-               if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) {
-                       if (is_vxge_card_up(vdev) &&
-                               vxge_hw_vpath_recover_from_reset(vpath->handle)
-                                       != VXGE_HW_OK) {
-                               vxge_debug_init(VXGE_ERR,
-                                       "vxge_hw_vpath_recover_from_reset"
-                                       "failed for vpath:%d", vp_id);
-                               return status;
-                       }
-               } else {
-                       vxge_debug_init(VXGE_ERR,
-                               "vxge_hw_vpath_reset failed for"
-                               "vpath:%d", vp_id);
-                       return status;
-               }
-       } else
-               return VXGE_HW_FAIL;
-
-       vxge_restore_vpath_mac_addr(vpath);
-       vxge_restore_vpath_vid_table(vpath);
-
-       /* Enable all broadcast */
-       vxge_hw_vpath_bcast_enable(vpath->handle);
-
-       /* Enable all multicast */
-       if (vdev->all_multi_flg) {
-               status = vxge_hw_vpath_mcast_enable(vpath->handle);
-               if (status != VXGE_HW_OK)
-                       vxge_debug_init(VXGE_ERR,
-                               "%s:%d Enabling multicast failed",
-                               __func__, __LINE__);
-       }
-
-       /* Enable the interrupts */
-       vxge_vpath_intr_enable(vdev, vp_id);
-
-       smp_wmb();
-
-       /* Enable the flow of traffic through the vpath */
-       vxge_hw_vpath_enable(vpath->handle);
-
-       smp_wmb();
-       vxge_hw_vpath_rx_doorbell_init(vpath->handle);
-       vpath->ring.last_status = VXGE_HW_OK;
-
-       /* Vpath reset done */
-       clear_bit(vp_id, &vdev->vp_reset);
-
-       /* Start the vpath queue */
-       if (netif_tx_queue_stopped(vpath->fifo.txq))
-               netif_tx_wake_queue(vpath->fifo.txq);
-
-       return ret;
-}
-
-/* Configure CI */
-static void vxge_config_ci_for_tti_rti(struct vxgedev *vdev)
-{
-       int i = 0;
-
-       /* Enable CI for RTI */
-       if (vdev->config.intr_type == MSI_X) {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       struct __vxge_hw_ring *hw_ring;
-
-                       hw_ring = vdev->vpaths[i].ring.handle;
-                       vxge_hw_vpath_dynamic_rti_ci_set(hw_ring);
-               }
-       }
-
-       /* Enable CI for TTI */
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               struct __vxge_hw_fifo *hw_fifo = vdev->vpaths[i].fifo.handle;
-               vxge_hw_vpath_tti_ci_set(hw_fifo);
-               /*
-                * For Inta (with or without napi), Set CI ON for only one
-                * vpath. (Have only one free running timer).
-                */
-               if ((vdev->config.intr_type == INTA) && (i == 0))
-                       break;
-       }
-
-       return;
-}
-
-static int do_vxge_reset(struct vxgedev *vdev, int event)
-{
-       int ret = 0, vp_id, i;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET)) {
-               /* check if device is down already */
-               if (unlikely(!is_vxge_card_up(vdev)))
-                       return 0;
-
-               /* is reset already scheduled */
-               if (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
-                       return 0;
-       }
-
-       if (event == VXGE_LL_FULL_RESET) {
-               netif_carrier_off(vdev->ndev);
-
-               /* wait for all the vpath reset to complete */
-               for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
-                       while (test_bit(vp_id, &vdev->vp_reset))
-                               msleep(50);
-               }
-
-               netif_carrier_on(vdev->ndev);
-
-               /* if execution mode is set to debug, don't reset the adapter */
-               if (unlikely(vdev->exec_mode)) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: execution mode is debug, returning..",
-                               vdev->ndev->name);
-                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-                       netif_tx_stop_all_queues(vdev->ndev);
-                       return 0;
-               }
-       }
-
-       if (event == VXGE_LL_FULL_RESET) {
-               vxge_hw_device_wait_receive_idle(vdev->devh);
-               vxge_hw_device_intr_disable(vdev->devh);
-
-               switch (vdev->cric_err_event) {
-               case VXGE_HW_EVENT_UNKNOWN:
-                       netif_tx_stop_all_queues(vdev->ndev);
-                       vxge_debug_init(VXGE_ERR,
-                               "fatal: %s: Disabling device due to"
-                               "unknown error",
-                               vdev->ndev->name);
-                       ret = -EPERM;
-                       goto out;
-               case VXGE_HW_EVENT_RESET_START:
-                       break;
-               case VXGE_HW_EVENT_RESET_COMPLETE:
-               case VXGE_HW_EVENT_LINK_DOWN:
-               case VXGE_HW_EVENT_LINK_UP:
-               case VXGE_HW_EVENT_ALARM_CLEARED:
-               case VXGE_HW_EVENT_ECCERR:
-               case VXGE_HW_EVENT_MRPCIM_ECCERR:
-                       ret = -EPERM;
-                       goto out;
-               case VXGE_HW_EVENT_FIFO_ERR:
-               case VXGE_HW_EVENT_VPATH_ERR:
-                       break;
-               case VXGE_HW_EVENT_CRITICAL_ERR:
-                       netif_tx_stop_all_queues(vdev->ndev);
-                       vxge_debug_init(VXGE_ERR,
-                               "fatal: %s: Disabling device due to"
-                               "serious error",
-                               vdev->ndev->name);
-                       /* SOP or device reset required */
-                       /* This event is not currently used */
-                       ret = -EPERM;
-                       goto out;
-               case VXGE_HW_EVENT_SERR:
-                       netif_tx_stop_all_queues(vdev->ndev);
-                       vxge_debug_init(VXGE_ERR,
-                               "fatal: %s: Disabling device due to"
-                               "serious error",
-                               vdev->ndev->name);
-                       ret = -EPERM;
-                       goto out;
-               case VXGE_HW_EVENT_SRPCIM_SERR:
-               case VXGE_HW_EVENT_MRPCIM_SERR:
-                       ret = -EPERM;
-                       goto out;
-               case VXGE_HW_EVENT_SLOT_FREEZE:
-                       netif_tx_stop_all_queues(vdev->ndev);
-                       vxge_debug_init(VXGE_ERR,
-                               "fatal: %s: Disabling device due to"
-                               "slot freeze",
-                               vdev->ndev->name);
-                       ret = -EPERM;
-                       goto out;
-               default:
-                       break;
-
-               }
-       }
-
-       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET))
-               netif_tx_stop_all_queues(vdev->ndev);
-
-       if (event == VXGE_LL_FULL_RESET) {
-               vxge_reset_all_vpaths(vdev);
-       }
-
-       if (event == VXGE_LL_COMPL_RESET) {
-               for (i = 0; i < vdev->no_of_vpath; i++)
-                       if (vdev->vpaths[i].handle) {
-                               if (vxge_hw_vpath_recover_from_reset(
-                                       vdev->vpaths[i].handle)
-                                               != VXGE_HW_OK) {
-                                       vxge_debug_init(VXGE_ERR,
-                                               "vxge_hw_vpath_recover_"
-                                               "from_reset failed for vpath: "
-                                               "%d", i);
-                                       ret = -EPERM;
-                                       goto out;
-                               }
-                               } else {
-                                       vxge_debug_init(VXGE_ERR,
-                                       "vxge_hw_vpath_reset failed for "
-                                               "vpath:%d", i);
-                                       ret = -EPERM;
-                                       goto out;
-                               }
-       }
-
-       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET)) {
-               /* Reprogram the DA table with populated mac addresses */
-               for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
-                       vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]);
-                       vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]);
-               }
-
-               /* enable vpath interrupts */
-               for (i = 0; i < vdev->no_of_vpath; i++)
-                       vxge_vpath_intr_enable(vdev, i);
-
-               vxge_hw_device_intr_enable(vdev->devh);
-
-               smp_wmb();
-
-               /* Indicate card up */
-               set_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-
-               /* Get the traffic to flow through the vpaths */
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vxge_hw_vpath_enable(vdev->vpaths[i].handle);
-                       smp_wmb();
-                       vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle);
-               }
-
-               netif_tx_wake_all_queues(vdev->ndev);
-       }
-
-       /* configure CI */
-       vxge_config_ci_for_tti_rti(vdev);
-
-out:
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d  Exiting...", __func__, __LINE__);
-
-       /* Indicate reset done */
-       if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET))
-               clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state);
-       return ret;
-}
-
-/*
- * vxge_reset
- * @vdev: pointer to ll device
- *
- * driver may reset the chip on events of serr, eccerr, etc
- */
-static void vxge_reset(struct work_struct *work)
-{
-       struct vxgedev *vdev = container_of(work, struct vxgedev, reset_task);
-
-       if (!netif_running(vdev->ndev))
-               return;
-
-       do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
-}
-
-/**
- * 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.
- *
- * This function comes into picture only if Receive side is being handled
- * through polling (called NAPI in linux). It mostly does what the normal
- * Rx interrupt handler does in terms of descriptor and packet processing
- * but not in an interrupt context. Also it will process a specified number
- * of packets at most in one iteration. This value is passed down by the
- * kernel as the function argument 'budget'.
- */
-static int vxge_poll_msix(struct napi_struct *napi, int budget)
-{
-       struct vxge_ring *ring = container_of(napi, struct vxge_ring, napi);
-       int pkts_processed;
-       int budget_org = budget;
-
-       ring->budget = budget;
-       ring->pkts_processed = 0;
-       vxge_hw_vpath_poll_rx(ring->handle);
-       pkts_processed = ring->pkts_processed;
-
-       if (pkts_processed < budget_org) {
-               napi_complete_done(napi, pkts_processed);
-
-               /* Re enable the Rx interrupts for the vpath */
-               vxge_hw_channel_msix_unmask(
-                               (struct __vxge_hw_channel *)ring->handle,
-                               ring->rx_vector_no);
-       }
-
-       /* We are copying and returning the local variable, in case if after
-        * clearing the msix interrupt above, if the interrupt fires right
-        * away which can preempt this NAPI thread */
-       return pkts_processed;
-}
-
-static int vxge_poll_inta(struct napi_struct *napi, int budget)
-{
-       struct vxgedev *vdev = container_of(napi, struct vxgedev, napi);
-       int pkts_processed = 0;
-       int i;
-       int budget_org = budget;
-       struct vxge_ring *ring;
-
-       struct __vxge_hw_device *hldev = pci_get_drvdata(vdev->pdev);
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               ring = &vdev->vpaths[i].ring;
-               ring->budget = budget;
-               ring->pkts_processed = 0;
-               vxge_hw_vpath_poll_rx(ring->handle);
-               pkts_processed += ring->pkts_processed;
-               budget -= ring->pkts_processed;
-               if (budget <= 0)
-                       break;
-       }
-
-       VXGE_COMPLETE_ALL_TX(vdev);
-
-       if (pkts_processed < budget_org) {
-               napi_complete_done(napi, pkts_processed);
-               /* Re enable the Rx interrupts for the ring */
-               vxge_hw_device_unmask_all(hldev);
-               vxge_hw_device_flush_io(hldev);
-       }
-
-       return pkts_processed;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-/**
- * vxge_netpoll - netpoll event handler entry point
- * @dev : pointer to the device structure.
- * Description:
- *      This function will be called by upper layer to check for events on the
- * interface in situations where interrupts are disabled. It is used for
- * specific in-kernel networking tasks, such as remote consoles and kernel
- * debugging over the network (example netdump in RedHat).
- */
-static void vxge_netpoll(struct net_device *dev)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct pci_dev *pdev = vdev->pdev;
-       struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
-       const int irq = pdev->irq;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       if (pci_channel_offline(pdev))
-               return;
-
-       disable_irq(irq);
-       vxge_hw_device_clear_tx_rx(hldev);
-
-       vxge_hw_device_clear_tx_rx(hldev);
-       VXGE_COMPLETE_ALL_RX(vdev);
-       VXGE_COMPLETE_ALL_TX(vdev);
-
-       enable_irq(irq);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d  Exiting...", __func__, __LINE__);
-}
-#endif
-
-/* RTH configuration */
-static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_hw_rth_hash_types hash_types;
-       u8 itable[256] = {0}; /* indirection table */
-       u8 mtable[256] = {0}; /* CPU to vpath mapping  */
-       int index;
-
-       /*
-        * Filling
-        *      - itable with bucket numbers
-        *      - mtable with bucket-to-vpath mapping
-        */
-       for (index = 0; index < (1 << vdev->config.rth_bkt_sz); index++) {
-               itable[index] = index;
-               mtable[index] = index % vdev->no_of_vpath;
-       }
-
-       /* set indirection table, bucket-to-vpath mapping */
-       status = vxge_hw_vpath_rts_rth_itable_set(vdev->vp_handles,
-                                               vdev->no_of_vpath,
-                                               mtable, itable,
-                                               vdev->config.rth_bkt_sz);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "RTH indirection table configuration failed "
-                       "for vpath:%d", vdev->vpaths[0].device_id);
-               return status;
-       }
-
-       /* Fill RTH hash types */
-       hash_types.hash_type_tcpipv4_en   = vdev->config.rth_hash_type_tcpipv4;
-       hash_types.hash_type_ipv4_en      = vdev->config.rth_hash_type_ipv4;
-       hash_types.hash_type_tcpipv6_en   = vdev->config.rth_hash_type_tcpipv6;
-       hash_types.hash_type_ipv6_en      = vdev->config.rth_hash_type_ipv6;
-       hash_types.hash_type_tcpipv6ex_en =
-                                       vdev->config.rth_hash_type_tcpipv6ex;
-       hash_types.hash_type_ipv6ex_en    = vdev->config.rth_hash_type_ipv6ex;
-
-       /*
-        * Because the itable_set() method uses the active_table field
-        * for the target virtual path the RTH config should be updated
-        * for all VPATHs. The h/w only uses the lowest numbered VPATH
-        * when steering frames.
-        */
-       for (index = 0; index < vdev->no_of_vpath; index++) {
-               status = vxge_hw_vpath_rts_rth_set(
-                               vdev->vpaths[index].handle,
-                               vdev->config.rth_algorithm,
-                               &hash_types,
-                               vdev->config.rth_bkt_sz);
-               if (status != VXGE_HW_OK) {
-                       vxge_debug_init(VXGE_ERR,
-                               "RTH configuration failed for vpath:%d",
-                               vdev->vpaths[index].device_id);
-                       return status;
-               }
-       }
-
-       return status;
-}
-
-/* reset vpaths */
-static void vxge_reset_all_vpaths(struct vxgedev *vdev)
-{
-       struct vxge_vpath *vpath;
-       int i;
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               vpath = &vdev->vpaths[i];
-               if (vpath->handle) {
-                       if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) {
-                               if (is_vxge_card_up(vdev) &&
-                                       vxge_hw_vpath_recover_from_reset(
-                                               vpath->handle) != VXGE_HW_OK) {
-                                       vxge_debug_init(VXGE_ERR,
-                                               "vxge_hw_vpath_recover_"
-                                               "from_reset failed for vpath: "
-                                               "%d", i);
-                                       return;
-                               }
-                       } else {
-                               vxge_debug_init(VXGE_ERR,
-                                       "vxge_hw_vpath_reset failed for "
-                                       "vpath:%d", i);
-                               return;
-                       }
-               }
-       }
-}
-
-/* close vpaths */
-static void vxge_close_vpaths(struct vxgedev *vdev, int index)
-{
-       struct vxge_vpath *vpath;
-       int i;
-
-       for (i = index; i < vdev->no_of_vpath; i++) {
-               vpath = &vdev->vpaths[i];
-
-               if (vpath->handle && vpath->is_open) {
-                       vxge_hw_vpath_close(vpath->handle);
-                       vdev->stats.vpaths_open--;
-               }
-               vpath->is_open = 0;
-               vpath->handle = NULL;
-       }
-}
-
-/* open vpaths */
-static int vxge_open_vpaths(struct vxgedev *vdev)
-{
-       struct vxge_hw_vpath_attr attr;
-       enum vxge_hw_status status;
-       struct vxge_vpath *vpath;
-       u32 vp_id = 0;
-       int i;
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               vpath = &vdev->vpaths[i];
-               vxge_assert(vpath->is_configured);
-
-               if (!vdev->titan1) {
-                       struct vxge_hw_vp_config *vcfg;
-                       vcfg = &vdev->devh->config.vp_config[vpath->device_id];
-
-                       vcfg->rti.urange_a = RTI_T1A_RX_URANGE_A;
-                       vcfg->rti.urange_b = RTI_T1A_RX_URANGE_B;
-                       vcfg->rti.urange_c = RTI_T1A_RX_URANGE_C;
-                       vcfg->tti.uec_a = TTI_T1A_TX_UFC_A;
-                       vcfg->tti.uec_b = TTI_T1A_TX_UFC_B;
-                       vcfg->tti.uec_c = TTI_T1A_TX_UFC_C(vdev->mtu);
-                       vcfg->tti.uec_d = TTI_T1A_TX_UFC_D(vdev->mtu);
-                       vcfg->tti.ltimer_val = VXGE_T1A_TTI_LTIMER_VAL;
-                       vcfg->tti.rtimer_val = VXGE_T1A_TTI_RTIMER_VAL;
-               }
-
-               attr.vp_id = vpath->device_id;
-               attr.fifo_attr.callback = vxge_xmit_compl;
-               attr.fifo_attr.txdl_term = vxge_tx_term;
-               attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv);
-               attr.fifo_attr.userdata = &vpath->fifo;
-
-               attr.ring_attr.callback = vxge_rx_1b_compl;
-               attr.ring_attr.rxd_init = vxge_rx_initial_replenish;
-               attr.ring_attr.rxd_term = vxge_rx_term;
-               attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv);
-               attr.ring_attr.userdata = &vpath->ring;
-
-               vpath->ring.ndev = vdev->ndev;
-               vpath->ring.pdev = vdev->pdev;
-
-               status = vxge_hw_vpath_open(vdev->devh, &attr, &vpath->handle);
-               if (status == VXGE_HW_OK) {
-                       vpath->fifo.handle =
-                           (struct __vxge_hw_fifo *)attr.fifo_attr.userdata;
-                       vpath->ring.handle =
-                           (struct __vxge_hw_ring *)attr.ring_attr.userdata;
-                       vpath->fifo.tx_steering_type =
-                               vdev->config.tx_steering_type;
-                       vpath->fifo.ndev = vdev->ndev;
-                       vpath->fifo.pdev = vdev->pdev;
-
-                       u64_stats_init(&vpath->fifo.stats.syncp);
-                       u64_stats_init(&vpath->ring.stats.syncp);
-
-                       if (vdev->config.tx_steering_type)
-                               vpath->fifo.txq =
-                                       netdev_get_tx_queue(vdev->ndev, i);
-                       else
-                               vpath->fifo.txq =
-                                       netdev_get_tx_queue(vdev->ndev, 0);
-                       vpath->fifo.indicate_max_pkts =
-                               vdev->config.fifo_indicate_max_pkts;
-                       vpath->fifo.tx_vector_no = 0;
-                       vpath->ring.rx_vector_no = 0;
-                       vpath->ring.rx_hwts = vdev->rx_hwts;
-                       vpath->is_open = 1;
-                       vdev->vp_handles[i] = vpath->handle;
-                       vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip;
-                       vdev->stats.vpaths_open++;
-               } else {
-                       vdev->stats.vpath_open_fail++;
-                       vxge_debug_init(VXGE_ERR, "%s: vpath: %d failed to "
-                                       "open with status: %d",
-                                       vdev->ndev->name, vpath->device_id,
-                                       status);
-                       vxge_close_vpaths(vdev, 0);
-                       return -EPERM;
-               }
-
-               vp_id = vpath->handle->vpath->vp_id;
-               vdev->vpaths_deployed |= vxge_mBIT(vp_id);
-       }
-
-       return VXGE_HW_OK;
-}
-
-/**
- *  adaptive_coalesce_tx_interrupts - Changes the interrupt coalescing
- *  if the interrupts are not within a range
- *  @fifo: pointer to transmit fifo structure
- *  Description: The function changes boundary timer and restriction timer
- *  value depends on the traffic
- *  Return Value: None
- */
-static void adaptive_coalesce_tx_interrupts(struct vxge_fifo *fifo)
-{
-       fifo->interrupt_count++;
-       if (time_before(fifo->jiffies + HZ / 100, jiffies)) {
-               struct __vxge_hw_fifo *hw_fifo = fifo->handle;
-
-               fifo->jiffies = jiffies;
-               if (fifo->interrupt_count > VXGE_T1A_MAX_TX_INTERRUPT_COUNT &&
-                   hw_fifo->rtimer != VXGE_TTI_RTIMER_ADAPT_VAL) {
-                       hw_fifo->rtimer = VXGE_TTI_RTIMER_ADAPT_VAL;
-                       vxge_hw_vpath_dynamic_tti_rtimer_set(hw_fifo);
-               } else if (hw_fifo->rtimer != 0) {
-                       hw_fifo->rtimer = 0;
-                       vxge_hw_vpath_dynamic_tti_rtimer_set(hw_fifo);
-               }
-               fifo->interrupt_count = 0;
-       }
-}
-
-/**
- *  adaptive_coalesce_rx_interrupts - Changes the interrupt coalescing
- *  if the interrupts are not within a range
- *  @ring: pointer to receive ring structure
- *  Description: The function increases of decreases the packet counts within
- *  the ranges of traffic utilization, if the interrupts due to this ring are
- *  not within a fixed range.
- *  Return Value: Nothing
- */
-static void adaptive_coalesce_rx_interrupts(struct vxge_ring *ring)
-{
-       ring->interrupt_count++;
-       if (time_before(ring->jiffies + HZ / 100, jiffies)) {
-               struct __vxge_hw_ring *hw_ring = ring->handle;
-
-               ring->jiffies = jiffies;
-               if (ring->interrupt_count > VXGE_T1A_MAX_INTERRUPT_COUNT &&
-                   hw_ring->rtimer != VXGE_RTI_RTIMER_ADAPT_VAL) {
-                       hw_ring->rtimer = VXGE_RTI_RTIMER_ADAPT_VAL;
-                       vxge_hw_vpath_dynamic_rti_rtimer_set(hw_ring);
-               } else if (hw_ring->rtimer != 0) {
-                       hw_ring->rtimer = 0;
-                       vxge_hw_vpath_dynamic_rti_rtimer_set(hw_ring);
-               }
-               ring->interrupt_count = 0;
-       }
-}
-
-/*
- *  vxge_isr_napi
- *  @irq: the irq of the device.
- *  @dev_id: a void pointer to the hldev structure of the Titan device
- *  @ptregs: pointer to the registers pushed on the stack.
- *
- *  This function is the ISR handler of the device when napi is enabled. It
- *  identifies the reason for the interrupt and calls the relevant service
- *  routines.
- */
-static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
-{
-       struct __vxge_hw_device *hldev;
-       u64 reason;
-       enum vxge_hw_status status;
-       struct vxgedev *vdev = (struct vxgedev *)dev_id;
-
-       vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       hldev = pci_get_drvdata(vdev->pdev);
-
-       if (pci_channel_offline(vdev->pdev))
-               return IRQ_NONE;
-
-       if (unlikely(!is_vxge_card_up(vdev)))
-               return IRQ_HANDLED;
-
-       status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode, &reason);
-       if (status == VXGE_HW_OK) {
-               vxge_hw_device_mask_all(hldev);
-
-               if (reason &
-                       VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(
-                       vdev->vpaths_deployed >>
-                       (64 - VXGE_HW_MAX_VIRTUAL_PATHS))) {
-
-                       vxge_hw_device_clear_tx_rx(hldev);
-                       napi_schedule(&vdev->napi);
-                       vxge_debug_intr(VXGE_TRACE,
-                               "%s:%d  Exiting...", __func__, __LINE__);
-                       return IRQ_HANDLED;
-               } else
-                       vxge_hw_device_unmask_all(hldev);
-       } else if (unlikely((status == VXGE_HW_ERR_VPATH) ||
-               (status == VXGE_HW_ERR_CRITICAL) ||
-               (status == VXGE_HW_ERR_FIFO))) {
-               vxge_hw_device_mask_all(hldev);
-               vxge_hw_device_flush_io(hldev);
-               return IRQ_HANDLED;
-       } else if (unlikely(status == VXGE_HW_ERR_SLOT_FREEZE))
-               return IRQ_HANDLED;
-
-       vxge_debug_intr(VXGE_TRACE, "%s:%d  Exiting...", __func__, __LINE__);
-       return IRQ_NONE;
-}
-
-static irqreturn_t vxge_tx_msix_handle(int irq, void *dev_id)
-{
-       struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id;
-
-       adaptive_coalesce_tx_interrupts(fifo);
-
-       vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)fifo->handle,
-                                 fifo->tx_vector_no);
-
-       vxge_hw_channel_msix_clear((struct __vxge_hw_channel *)fifo->handle,
-                                  fifo->tx_vector_no);
-
-       VXGE_COMPLETE_VPATH_TX(fifo);
-
-       vxge_hw_channel_msix_unmask((struct __vxge_hw_channel *)fifo->handle,
-                                   fifo->tx_vector_no);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t vxge_rx_msix_napi_handle(int irq, void *dev_id)
-{
-       struct vxge_ring *ring = (struct vxge_ring *)dev_id;
-
-       adaptive_coalesce_rx_interrupts(ring);
-
-       vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)ring->handle,
-                                 ring->rx_vector_no);
-
-       vxge_hw_channel_msix_clear((struct __vxge_hw_channel *)ring->handle,
-                                  ring->rx_vector_no);
-
-       napi_schedule(&ring->napi);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t
-vxge_alarm_msix_handle(int irq, void *dev_id)
-{
-       int i;
-       enum vxge_hw_status status;
-       struct vxge_vpath *vpath = (struct vxge_vpath *)dev_id;
-       struct vxgedev *vdev = vpath->vdev;
-       int msix_id = (vpath->handle->vpath->vp_id *
-               VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID;
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               /* Reduce the chance of losing alarm interrupts by masking
-                * the vector. A pending bit will be set if an alarm is
-                * generated and on unmask the interrupt will be fired.
-                */
-               vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle, msix_id);
-               vxge_hw_vpath_msix_clear(vdev->vpaths[i].handle, msix_id);
-
-               status = vxge_hw_vpath_alarm_process(vdev->vpaths[i].handle,
-                       vdev->exec_mode);
-               if (status == VXGE_HW_OK) {
-                       vxge_hw_vpath_msix_unmask(vdev->vpaths[i].handle,
-                                                 msix_id);
-                       continue;
-               }
-               vxge_debug_intr(VXGE_ERR,
-                       "%s: vxge_hw_vpath_alarm_process failed %x ",
-                       VXGE_DRIVER_NAME, status);
-       }
-       return IRQ_HANDLED;
-}
-
-static int vxge_alloc_msix(struct vxgedev *vdev)
-{
-       int j, i, ret = 0;
-       int msix_intr_vect = 0, temp;
-       vdev->intr_cnt = 0;
-
-start:
-       /* Tx/Rx MSIX Vectors count */
-       vdev->intr_cnt = vdev->no_of_vpath * 2;
-
-       /* Alarm MSIX Vectors count */
-       vdev->intr_cnt++;
-
-       vdev->entries = kcalloc(vdev->intr_cnt, sizeof(struct msix_entry),
-                               GFP_KERNEL);
-       if (!vdev->entries) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: memory allocation failed",
-                       VXGE_DRIVER_NAME);
-               ret = -ENOMEM;
-               goto alloc_entries_failed;
-       }
-
-       vdev->vxge_entries = kcalloc(vdev->intr_cnt,
-                                    sizeof(struct vxge_msix_entry),
-                                    GFP_KERNEL);
-       if (!vdev->vxge_entries) {
-               vxge_debug_init(VXGE_ERR, "%s: memory allocation failed",
-                       VXGE_DRIVER_NAME);
-               ret = -ENOMEM;
-               goto alloc_vxge_entries_failed;
-       }
-
-       for (i = 0, j = 0; i < vdev->no_of_vpath; i++) {
-
-               msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE;
-
-               /* Initialize the fifo vector */
-               vdev->entries[j].entry = msix_intr_vect;
-               vdev->vxge_entries[j].entry = msix_intr_vect;
-               vdev->vxge_entries[j].in_use = 0;
-               j++;
-
-               /* Initialize the ring vector */
-               vdev->entries[j].entry = msix_intr_vect + 1;
-               vdev->vxge_entries[j].entry = msix_intr_vect + 1;
-               vdev->vxge_entries[j].in_use = 0;
-               j++;
-       }
-
-       /* Initialize the alarm vector */
-       vdev->entries[j].entry = VXGE_ALARM_MSIX_ID;
-       vdev->vxge_entries[j].entry = VXGE_ALARM_MSIX_ID;
-       vdev->vxge_entries[j].in_use = 0;
-
-       ret = pci_enable_msix_range(vdev->pdev,
-                                   vdev->entries, 3, vdev->intr_cnt);
-       if (ret < 0) {
-               ret = -ENODEV;
-               goto enable_msix_failed;
-       } else if (ret < vdev->intr_cnt) {
-               pci_disable_msix(vdev->pdev);
-
-               vxge_debug_init(VXGE_ERR,
-                       "%s: MSI-X enable failed for %d vectors, ret: %d",
-                       VXGE_DRIVER_NAME, vdev->intr_cnt, ret);
-               if (max_config_vpath != VXGE_USE_DEFAULT) {
-                       ret = -ENODEV;
-                       goto enable_msix_failed;
-               }
-
-               kfree(vdev->entries);
-               kfree(vdev->vxge_entries);
-               vdev->entries = NULL;
-               vdev->vxge_entries = NULL;
-               /* Try with less no of vector by reducing no of vpaths count */
-               temp = (ret - 1)/2;
-               vxge_close_vpaths(vdev, temp);
-               vdev->no_of_vpath = temp;
-               goto start;
-       }
-       return 0;
-
-enable_msix_failed:
-       kfree(vdev->vxge_entries);
-alloc_vxge_entries_failed:
-       kfree(vdev->entries);
-alloc_entries_failed:
-       return ret;
-}
-
-static int vxge_enable_msix(struct vxgedev *vdev)
-{
-
-       int i, ret = 0;
-       /* 0 - Tx, 1 - Rx  */
-       int tim_msix_id[4] = {0, 1, 0, 0};
-
-       vdev->intr_cnt = 0;
-
-       /* allocate msix vectors */
-       ret = vxge_alloc_msix(vdev);
-       if (!ret) {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       struct vxge_vpath *vpath = &vdev->vpaths[i];
-
-                       /* If fifo or ring are not enabled, the MSIX vector for
-                        * it should be set to 0.
-                        */
-                       vpath->ring.rx_vector_no = (vpath->device_id *
-                                               VXGE_HW_VPATH_MSIX_ACTIVE) + 1;
-
-                       vpath->fifo.tx_vector_no = (vpath->device_id *
-                                               VXGE_HW_VPATH_MSIX_ACTIVE);
-
-                       vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id,
-                                              VXGE_ALARM_MSIX_ID);
-               }
-       }
-
-       return ret;
-}
-
-static void vxge_rem_msix_isr(struct vxgedev *vdev)
-{
-       int intr_cnt;
-
-       for (intr_cnt = 0; intr_cnt < (vdev->no_of_vpath * 2 + 1);
-               intr_cnt++) {
-               if (vdev->vxge_entries[intr_cnt].in_use) {
-                       free_irq(vdev->entries[intr_cnt].vector,
-                               vdev->vxge_entries[intr_cnt].arg);
-                       vdev->vxge_entries[intr_cnt].in_use = 0;
-               }
-       }
-
-       kfree(vdev->entries);
-       kfree(vdev->vxge_entries);
-       vdev->entries = NULL;
-       vdev->vxge_entries = NULL;
-
-       if (vdev->config.intr_type == MSI_X)
-               pci_disable_msix(vdev->pdev);
-}
-
-static void vxge_rem_isr(struct vxgedev *vdev)
-{
-       if (IS_ENABLED(CONFIG_PCI_MSI) &&
-           vdev->config.intr_type == MSI_X) {
-               vxge_rem_msix_isr(vdev);
-       } else if (vdev->config.intr_type == INTA) {
-                       free_irq(vdev->pdev->irq, vdev);
-       }
-}
-
-static int vxge_add_isr(struct vxgedev *vdev)
-{
-       int ret = 0;
-       int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
-       int pci_fun = PCI_FUNC(vdev->pdev->devfn);
-
-       if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X)
-               ret = vxge_enable_msix(vdev);
-
-       if (ret) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: Enabling MSI-X Failed", VXGE_DRIVER_NAME);
-               vxge_debug_init(VXGE_ERR,
-                       "%s: Defaulting to INTA", VXGE_DRIVER_NAME);
-               vdev->config.intr_type = INTA;
-       }
-
-       if (IS_ENABLED(CONFIG_PCI_MSI) && vdev->config.intr_type == MSI_X) {
-               for (intr_idx = 0;
-                    intr_idx < (vdev->no_of_vpath *
-                       VXGE_HW_VPATH_MSIX_ACTIVE); intr_idx++) {
-
-                       msix_idx = intr_idx % VXGE_HW_VPATH_MSIX_ACTIVE;
-                       irq_req = 0;
-
-                       switch (msix_idx) {
-                       case 0:
-                               snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
-                                       "%s:vxge:MSI-X %d - Tx - fn:%d vpath:%d",
-                                       vdev->ndev->name,
-                                       vdev->entries[intr_cnt].entry,
-                                       pci_fun, vp_idx);
-                               ret = request_irq(
-                                       vdev->entries[intr_cnt].vector,
-                                       vxge_tx_msix_handle, 0,
-                                       vdev->desc[intr_cnt],
-                                       &vdev->vpaths[vp_idx].fifo);
-                               vdev->vxge_entries[intr_cnt].arg =
-                                               &vdev->vpaths[vp_idx].fifo;
-                               irq_req = 1;
-                               break;
-                       case 1:
-                               snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
-                                       "%s:vxge:MSI-X %d - Rx - fn:%d vpath:%d",
-                                       vdev->ndev->name,
-                                       vdev->entries[intr_cnt].entry,
-                                       pci_fun, vp_idx);
-                               ret = request_irq(
-                                       vdev->entries[intr_cnt].vector,
-                                       vxge_rx_msix_napi_handle, 0,
-                                       vdev->desc[intr_cnt],
-                                       &vdev->vpaths[vp_idx].ring);
-                               vdev->vxge_entries[intr_cnt].arg =
-                                               &vdev->vpaths[vp_idx].ring;
-                               irq_req = 1;
-                               break;
-                       }
-
-                       if (ret) {
-                               vxge_debug_init(VXGE_ERR,
-                                       "%s: MSIX - %d  Registration failed",
-                                       vdev->ndev->name, intr_cnt);
-                               vxge_rem_msix_isr(vdev);
-                               vdev->config.intr_type = INTA;
-                               vxge_debug_init(VXGE_ERR,
-                                       "%s: Defaulting to INTA",
-                                       vdev->ndev->name);
-                               goto INTA_MODE;
-                       }
-
-                       if (irq_req) {
-                               /* We requested for this msix interrupt */
-                               vdev->vxge_entries[intr_cnt].in_use = 1;
-                               msix_idx +=  vdev->vpaths[vp_idx].device_id *
-                                       VXGE_HW_VPATH_MSIX_ACTIVE;
-                               vxge_hw_vpath_msix_unmask(
-                                       vdev->vpaths[vp_idx].handle,
-                                       msix_idx);
-                               intr_cnt++;
-                       }
-
-                       /* Point to next vpath handler */
-                       if (((intr_idx + 1) % VXGE_HW_VPATH_MSIX_ACTIVE == 0) &&
-                           (vp_idx < (vdev->no_of_vpath - 1)))
-                               vp_idx++;
-               }
-
-               intr_cnt = vdev->no_of_vpath * 2;
-               snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
-                       "%s:vxge:MSI-X %d - Alarm - fn:%d",
-                       vdev->ndev->name,
-                       vdev->entries[intr_cnt].entry,
-                       pci_fun);
-               /* For Alarm interrupts */
-               ret = request_irq(vdev->entries[intr_cnt].vector,
-                                       vxge_alarm_msix_handle, 0,
-                                       vdev->desc[intr_cnt],
-                                       &vdev->vpaths[0]);
-               if (ret) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: MSIX - %d Registration failed",
-                               vdev->ndev->name, intr_cnt);
-                       vxge_rem_msix_isr(vdev);
-                       vdev->config.intr_type = INTA;
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: Defaulting to INTA",
-                               vdev->ndev->name);
-                       goto INTA_MODE;
-               }
-
-               msix_idx = (vdev->vpaths[0].handle->vpath->vp_id *
-                       VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID;
-               vxge_hw_vpath_msix_unmask(vdev->vpaths[vp_idx].handle,
-                                       msix_idx);
-               vdev->vxge_entries[intr_cnt].in_use = 1;
-               vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[0];
-       }
-
-INTA_MODE:
-       if (vdev->config.intr_type == INTA) {
-               snprintf(vdev->desc[0], VXGE_INTR_STRLEN,
-                       "%s:vxge:INTA", vdev->ndev->name);
-               vxge_hw_device_set_intr_type(vdev->devh,
-                       VXGE_HW_INTR_MODE_IRQLINE);
-
-               vxge_hw_vpath_tti_ci_set(vdev->vpaths[0].fifo.handle);
-
-               ret = request_irq((int) vdev->pdev->irq,
-                       vxge_isr_napi,
-                       IRQF_SHARED, vdev->desc[0], vdev);
-               if (ret) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s %s-%d: ISR registration failed",
-                               VXGE_DRIVER_NAME, "IRQ", vdev->pdev->irq);
-                       return -ENODEV;
-               }
-               vxge_debug_init(VXGE_TRACE,
-                       "new %s-%d line allocated",
-                       "IRQ", vdev->pdev->irq);
-       }
-
-       return VXGE_HW_OK;
-}
-
-static void vxge_poll_vp_reset(struct timer_list *t)
-{
-       struct vxgedev *vdev = from_timer(vdev, t, vp_reset_timer);
-       int i, j = 0;
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               if (test_bit(i, &vdev->vp_reset)) {
-                       vxge_reset_vpath(vdev, i);
-                       j++;
-               }
-       }
-       if (j && (vdev->config.intr_type != MSI_X)) {
-               vxge_hw_device_unmask_all(vdev->devh);
-               vxge_hw_device_flush_io(vdev->devh);
-       }
-
-       mod_timer(&vdev->vp_reset_timer, jiffies + HZ / 2);
-}
-
-static void vxge_poll_vp_lockup(struct timer_list *t)
-{
-       struct vxgedev *vdev = from_timer(vdev, t, vp_lockup_timer);
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_vpath *vpath;
-       struct vxge_ring *ring;
-       int i;
-       unsigned long rx_frms;
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               ring = &vdev->vpaths[i].ring;
-
-               /* Truncated to machine word size number of frames */
-               rx_frms = READ_ONCE(ring->stats.rx_frms);
-
-               /* Did this vpath received any packets */
-               if (ring->stats.prev_rx_frms == rx_frms) {
-                       status = vxge_hw_vpath_check_leak(ring->handle);
-
-                       /* Did it received any packets last time */
-                       if ((VXGE_HW_FAIL == status) &&
-                               (VXGE_HW_FAIL == ring->last_status)) {
-
-                               /* schedule vpath reset */
-                               if (!test_and_set_bit(i, &vdev->vp_reset)) {
-                                       vpath = &vdev->vpaths[i];
-
-                                       /* disable interrupts for this vpath */
-                                       vxge_vpath_intr_disable(vdev, i);
-
-                                       /* stop the queue for this vpath */
-                                       netif_tx_stop_queue(vpath->fifo.txq);
-                                       continue;
-                               }
-                       }
-               }
-               ring->stats.prev_rx_frms = rx_frms;
-               ring->last_status = status;
-       }
-
-       /* Check every 1 milli second */
-       mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000);
-}
-
-static netdev_features_t vxge_fix_features(struct net_device *dev,
-       netdev_features_t features)
-{
-       netdev_features_t changed = dev->features ^ features;
-
-       /* Enabling RTH requires some of the logic in vxge_device_register and a
-        * vpath reset.  Due to these restrictions, only allow modification
-        * while the interface is down.
-        */
-       if ((changed & NETIF_F_RXHASH) && netif_running(dev))
-               features ^= NETIF_F_RXHASH;
-
-       return features;
-}
-
-static int vxge_set_features(struct net_device *dev, netdev_features_t features)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       netdev_features_t changed = dev->features ^ features;
-
-       if (!(changed & NETIF_F_RXHASH))
-               return 0;
-
-       /* !netif_running() ensured by vxge_fix_features() */
-
-       vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH);
-       vxge_reset_all_vpaths(vdev);
-
-       return 0;
-}
-
-/**
- * vxge_open
- * @dev: pointer to the device structure.
- *
- * This function is the open entry point of the driver. It mainly calls a
- * function to allocate Rx buffers and inserts them into the buffer
- * descriptors and then enables the Rx part of the NIC.
- * Return value: '0' on success and an appropriate (-)ve integer as
- * defined in errno.h file on failure.
- */
-static int vxge_open(struct net_device *dev)
-{
-       enum vxge_hw_status status;
-       struct vxgedev *vdev;
-       struct __vxge_hw_device *hldev;
-       struct vxge_vpath *vpath;
-       int ret = 0;
-       int i;
-       u64 val64;
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d", dev->name, __func__, __LINE__);
-
-       vdev = netdev_priv(dev);
-       hldev = pci_get_drvdata(vdev->pdev);
-
-       /* make sure you have link off by default every time Nic is
-        * initialized */
-       netif_carrier_off(dev);
-
-       /* Open VPATHs */
-       status = vxge_open_vpaths(vdev);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: fatal: Vpath open failed", vdev->ndev->name);
-               ret = -EPERM;
-               goto out0;
-       }
-
-       vdev->mtu = dev->mtu;
-
-       status = vxge_add_isr(vdev);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: fatal: ISR add failed", dev->name);
-               ret = -EPERM;
-               goto out1;
-       }
-
-       if (vdev->config.intr_type != MSI_X) {
-               netif_napi_add_weight(dev, &vdev->napi, vxge_poll_inta,
-                                     vdev->config.napi_weight);
-               napi_enable(&vdev->napi);
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       vpath->ring.napi_p = &vdev->napi;
-               }
-       } else {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       netif_napi_add_weight(dev, &vpath->ring.napi,
-                                             vxge_poll_msix,
-                                             vdev->config.napi_weight);
-                       napi_enable(&vpath->ring.napi);
-                       vpath->ring.napi_p = &vpath->ring.napi;
-               }
-       }
-
-       /* configure RTH */
-       if (vdev->config.rth_steering) {
-               status = vxge_rth_configure(vdev);
-               if (status != VXGE_HW_OK) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: fatal: RTH configuration failed",
-                               dev->name);
-                       ret = -EPERM;
-                       goto out2;
-               }
-       }
-       printk(KERN_INFO "%s: Receive Hashing Offload %s\n", dev->name,
-              hldev->config.rth_en ? "enabled" : "disabled");
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               vpath = &vdev->vpaths[i];
-
-               /* set initial mtu before enabling the device */
-               status = vxge_hw_vpath_mtu_set(vpath->handle, vdev->mtu);
-               if (status != VXGE_HW_OK) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: fatal: can not set new MTU", dev->name);
-                       ret = -EPERM;
-                       goto out2;
-               }
-       }
-
-       VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_TRACE, VXGE_COMPONENT_LL, vdev);
-       vxge_debug_init(vdev->level_trace,
-               "%s: MTU is %d", vdev->ndev->name, vdev->mtu);
-       VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev);
-
-       /* Restore the DA, VID table and also multicast and promiscuous mode
-        * states
-        */
-       if (vdev->all_multi_flg) {
-               for (i = 0; i < vdev->no_of_vpath; i++) {
-                       vpath = &vdev->vpaths[i];
-                       vxge_restore_vpath_mac_addr(vpath);
-                       vxge_restore_vpath_vid_table(vpath);
-
-                       status = vxge_hw_vpath_mcast_enable(vpath->handle);
-                       if (status != VXGE_HW_OK)
-                               vxge_debug_init(VXGE_ERR,
-                                       "%s:%d Enabling multicast failed",
-                                       __func__, __LINE__);
-               }
-       }
-
-       /* Enable vpath to sniff all unicast/multicast traffic that not
-        * addressed to them. We allow promiscuous mode for PF only
-        */
-
-       val64 = 0;
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
-               val64 |= VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(i);
-
-       vxge_hw_mgmt_reg_write(vdev->devh,
-               vxge_hw_mgmt_reg_type_mrpcim,
-               0,
-               (ulong)offsetof(struct vxge_hw_mrpcim_reg,
-                       rxmac_authorize_all_addr),
-               val64);
-
-       vxge_hw_mgmt_reg_write(vdev->devh,
-               vxge_hw_mgmt_reg_type_mrpcim,
-               0,
-               (ulong)offsetof(struct vxge_hw_mrpcim_reg,
-                       rxmac_authorize_all_vid),
-               val64);
-
-       vxge_set_multicast(dev);
-
-       /* Enabling Bcast and mcast for all vpath */
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               vpath = &vdev->vpaths[i];
-               status = vxge_hw_vpath_bcast_enable(vpath->handle);
-               if (status != VXGE_HW_OK)
-                       vxge_debug_init(VXGE_ERR,
-                               "%s : Can not enable bcast for vpath "
-                               "id %d", dev->name, i);
-               if (vdev->config.addr_learn_en) {
-                       status = vxge_hw_vpath_mcast_enable(vpath->handle);
-                       if (status != VXGE_HW_OK)
-                               vxge_debug_init(VXGE_ERR,
-                                       "%s : Can not enable mcast for vpath "
-                                       "id %d", dev->name, i);
-               }
-       }
-
-       vxge_hw_device_setpause_data(vdev->devh, 0,
-               vdev->config.tx_pause_enable,
-               vdev->config.rx_pause_enable);
-
-       if (vdev->vp_reset_timer.function == NULL)
-               vxge_os_timer(&vdev->vp_reset_timer, vxge_poll_vp_reset,
-                             HZ / 2);
-
-       /* There is no need to check for RxD leak and RxD lookup on Titan1A */
-       if (vdev->titan1 && vdev->vp_lockup_timer.function == NULL)
-               vxge_os_timer(&vdev->vp_lockup_timer, vxge_poll_vp_lockup,
-                             HZ / 2);
-
-       set_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-
-       smp_wmb();
-
-       if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) {
-               netif_carrier_on(vdev->ndev);
-               netdev_notice(vdev->ndev, "Link Up\n");
-               vdev->stats.link_up++;
-       }
-
-       vxge_hw_device_intr_enable(vdev->devh);
-
-       smp_wmb();
-
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               vpath = &vdev->vpaths[i];
-
-               vxge_hw_vpath_enable(vpath->handle);
-               smp_wmb();
-               vxge_hw_vpath_rx_doorbell_init(vpath->handle);
-       }
-
-       netif_tx_start_all_queues(vdev->ndev);
-
-       /* configure CI */
-       vxge_config_ci_for_tti_rti(vdev);
-
-       goto out0;
-
-out2:
-       vxge_rem_isr(vdev);
-
-       /* Disable napi */
-       if (vdev->config.intr_type != MSI_X)
-               napi_disable(&vdev->napi);
-       else {
-               for (i = 0; i < vdev->no_of_vpath; i++)
-                       napi_disable(&vdev->vpaths[i].ring.napi);
-       }
-
-out1:
-       vxge_close_vpaths(vdev, 0);
-out0:
-       vxge_debug_entryexit(VXGE_TRACE,
-                               "%s: %s:%d  Exiting...",
-                               dev->name, __func__, __LINE__);
-       return ret;
-}
-
-/* Loop through the mac address list and delete all the entries */
-static void vxge_free_mac_add_list(struct vxge_vpath *vpath)
-{
-
-       struct list_head *entry, *next;
-       if (list_empty(&vpath->mac_addr_list))
-               return;
-
-       list_for_each_safe(entry, next, &vpath->mac_addr_list) {
-               list_del(entry);
-               kfree(entry);
-       }
-}
-
-static void vxge_napi_del_all(struct vxgedev *vdev)
-{
-       int i;
-       if (vdev->config.intr_type != MSI_X)
-               netif_napi_del(&vdev->napi);
-       else {
-               for (i = 0; i < vdev->no_of_vpath; i++)
-                       netif_napi_del(&vdev->vpaths[i].ring.napi);
-       }
-}
-
-static int do_vxge_close(struct net_device *dev, int do_io)
-{
-       enum vxge_hw_status status;
-       struct vxgedev *vdev;
-       struct __vxge_hw_device *hldev;
-       int i;
-       u64 val64, vpath_vector;
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
-               dev->name, __func__, __LINE__);
-
-       vdev = netdev_priv(dev);
-       hldev = pci_get_drvdata(vdev->pdev);
-
-       if (unlikely(!is_vxge_card_up(vdev)))
-               return 0;
-
-       /* If vxge_handle_crit_err task is executing,
-        * wait till it completes. */
-       while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
-               msleep(50);
-
-       if (do_io) {
-               /* Put the vpath back in normal mode */
-               vpath_vector = vxge_mBIT(vdev->vpaths[0].device_id);
-               status = vxge_hw_mgmt_reg_read(vdev->devh,
-                               vxge_hw_mgmt_reg_type_mrpcim,
-                               0,
-                               (ulong)offsetof(
-                                       struct vxge_hw_mrpcim_reg,
-                                       rts_mgr_cbasin_cfg),
-                               &val64);
-               if (status == VXGE_HW_OK) {
-                       val64 &= ~vpath_vector;
-                       status = vxge_hw_mgmt_reg_write(vdev->devh,
-                                       vxge_hw_mgmt_reg_type_mrpcim,
-                                       0,
-                                       (ulong)offsetof(
-                                               struct vxge_hw_mrpcim_reg,
-                                               rts_mgr_cbasin_cfg),
-                                       val64);
-               }
-
-               /* Remove the function 0 from promiscuous mode */
-               vxge_hw_mgmt_reg_write(vdev->devh,
-                       vxge_hw_mgmt_reg_type_mrpcim,
-                       0,
-                       (ulong)offsetof(struct vxge_hw_mrpcim_reg,
-                               rxmac_authorize_all_addr),
-                       0);
-
-               vxge_hw_mgmt_reg_write(vdev->devh,
-                       vxge_hw_mgmt_reg_type_mrpcim,
-                       0,
-                       (ulong)offsetof(struct vxge_hw_mrpcim_reg,
-                               rxmac_authorize_all_vid),
-                       0);
-
-               smp_wmb();
-       }
-
-       if (vdev->titan1)
-               del_timer_sync(&vdev->vp_lockup_timer);
-
-       del_timer_sync(&vdev->vp_reset_timer);
-
-       if (do_io)
-               vxge_hw_device_wait_receive_idle(hldev);
-
-       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-
-       /* Disable napi */
-       if (vdev->config.intr_type != MSI_X)
-               napi_disable(&vdev->napi);
-       else {
-               for (i = 0; i < vdev->no_of_vpath; i++)
-                       napi_disable(&vdev->vpaths[i].ring.napi);
-       }
-
-       netif_carrier_off(vdev->ndev);
-       netdev_notice(vdev->ndev, "Link Down\n");
-       netif_tx_stop_all_queues(vdev->ndev);
-
-       /* Note that at this point xmit() is stopped by upper layer */
-       if (do_io)
-               vxge_hw_device_intr_disable(vdev->devh);
-
-       vxge_rem_isr(vdev);
-
-       vxge_napi_del_all(vdev);
-
-       if (do_io)
-               vxge_reset_all_vpaths(vdev);
-
-       vxge_close_vpaths(vdev, 0);
-
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s: %s:%d  Exiting...", dev->name, __func__, __LINE__);
-
-       clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state);
-
-       return 0;
-}
-
-/**
- * vxge_close
- * @dev: device pointer.
- *
- * This is the stop entry point of the driver. It needs to undo exactly
- * whatever was done by the open entry point, thus it's usually referred to
- * as the close function.Among other things this function mainly stops the
- * Rx side of the NIC and frees all the Rx buffers in the Rx rings.
- * Return value: '0' on success and an appropriate (-)ve integer as
- * defined in errno.h file on failure.
- */
-static int vxge_close(struct net_device *dev)
-{
-       do_vxge_close(dev, 1);
-       return 0;
-}
-
-/**
- * vxge_change_mtu
- * @dev: net device pointer.
- * @new_mtu :the new MTU size for the device.
- *
- * A driver entry point to change MTU size for the device. Before changing
- * the MTU the device must be stopped.
- */
-static int vxge_change_mtu(struct net_device *dev, int new_mtu)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       vxge_debug_entryexit(vdev->level_trace,
-               "%s:%d", __func__, __LINE__);
-
-       /* check if device is down already */
-       if (unlikely(!is_vxge_card_up(vdev))) {
-               /* just store new value, will use later on open() */
-               dev->mtu = new_mtu;
-               vxge_debug_init(vdev->level_err,
-                       "%s", "device is down on MTU change");
-               return 0;
-       }
-
-       vxge_debug_init(vdev->level_trace,
-               "trying to apply new MTU %d", new_mtu);
-
-       if (vxge_close(dev))
-               return -EIO;
-
-       dev->mtu = new_mtu;
-       vdev->mtu = new_mtu;
-
-       if (vxge_open(dev))
-               return -EIO;
-
-       vxge_debug_init(vdev->level_trace,
-               "%s: MTU changed to %d", vdev->ndev->name, new_mtu);
-
-       vxge_debug_entryexit(vdev->level_trace,
-               "%s:%d  Exiting...", __func__, __LINE__);
-
-       return 0;
-}
-
-/**
- * vxge_get_stats64
- * @dev: pointer to the device structure
- * @net_stats: pointer to struct rtnl_link_stats64
- *
- */
-static void
-vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       int k;
-
-       /* net_stats already zeroed by caller */
-       for (k = 0; k < vdev->no_of_vpath; k++) {
-               struct vxge_ring_stats *rxstats = &vdev->vpaths[k].ring.stats;
-               struct vxge_fifo_stats *txstats = &vdev->vpaths[k].fifo.stats;
-               unsigned int start;
-               u64 packets, bytes, multicast;
-
-               do {
-                       start = u64_stats_fetch_begin_irq(&rxstats->syncp);
-
-                       packets   = rxstats->rx_frms;
-                       multicast = rxstats->rx_mcast;
-                       bytes     = rxstats->rx_bytes;
-               } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start));
-
-               net_stats->rx_packets += packets;
-               net_stats->rx_bytes += bytes;
-               net_stats->multicast += multicast;
-
-               net_stats->rx_errors += rxstats->rx_errors;
-               net_stats->rx_dropped += rxstats->rx_dropped;
-
-               do {
-                       start = u64_stats_fetch_begin_irq(&txstats->syncp);
-
-                       packets = txstats->tx_frms;
-                       bytes   = txstats->tx_bytes;
-               } while (u64_stats_fetch_retry_irq(&txstats->syncp, start));
-
-               net_stats->tx_packets += packets;
-               net_stats->tx_bytes += bytes;
-               net_stats->tx_errors += txstats->tx_errors;
-       }
-}
-
-static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh)
-{
-       enum vxge_hw_status status;
-       u64 val64;
-
-       /* Timestamp is passed to the driver via the FCS, therefore we
-        * must disable the FCS stripping by the adapter.  Since this is
-        * required for the driver to load (due to a hardware bug),
-        * there is no need to do anything special here.
-        */
-       val64 = VXGE_HW_XMAC_TIMESTAMP_EN |
-               VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) |
-               VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0);
-
-       status = vxge_hw_mgmt_reg_write(devh,
-                                       vxge_hw_mgmt_reg_type_mrpcim,
-                                       0,
-                                       offsetof(struct vxge_hw_mrpcim_reg,
-                                                xmac_timestamp),
-                                       val64);
-       vxge_hw_device_flush_io(devh);
-       devh->config.hwts_en = VXGE_HW_HWTS_ENABLE;
-       return status;
-}
-
-static int vxge_hwtstamp_set(struct vxgedev *vdev, void __user *data)
-{
-       struct hwtstamp_config config;
-       int i;
-
-       if (copy_from_user(&config, data, sizeof(config)))
-               return -EFAULT;
-
-       /* Transmit HW Timestamp not supported */
-       switch (config.tx_type) {
-       case HWTSTAMP_TX_OFF:
-               break;
-       case HWTSTAMP_TX_ON:
-       default:
-               return -ERANGE;
-       }
-
-       switch (config.rx_filter) {
-       case HWTSTAMP_FILTER_NONE:
-               vdev->rx_hwts = 0;
-               config.rx_filter = HWTSTAMP_FILTER_NONE;
-               break;
-
-       case HWTSTAMP_FILTER_ALL:
-       case HWTSTAMP_FILTER_SOME:
-       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
-       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
-       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
-       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
-       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
-       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
-       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
-       case HWTSTAMP_FILTER_PTP_V2_EVENT:
-       case HWTSTAMP_FILTER_PTP_V2_SYNC:
-       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
-       case HWTSTAMP_FILTER_NTP_ALL:
-               if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE)
-                       return -EFAULT;
-
-               vdev->rx_hwts = 1;
-               config.rx_filter = HWTSTAMP_FILTER_ALL;
-               break;
-
-       default:
-                return -ERANGE;
-       }
-
-       for (i = 0; i < vdev->no_of_vpath; i++)
-               vdev->vpaths[i].ring.rx_hwts = vdev->rx_hwts;
-
-       if (copy_to_user(data, &config, sizeof(config)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int vxge_hwtstamp_get(struct vxgedev *vdev, void __user *data)
-{
-       struct hwtstamp_config config;
-
-       config.flags = 0;
-       config.tx_type = HWTSTAMP_TX_OFF;
-       config.rx_filter = (vdev->rx_hwts ?
-                           HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
-
-       if (copy_to_user(data, &config, sizeof(config)))
-               return -EFAULT;
-
-       return 0;
-}
-
-/**
- * vxge_ioctl
- * @dev: Device pointer.
- * @rq: An IOCTL specific structure, that can contain a pointer to
- *       a proprietary structure used to pass information to the driver.
- * @cmd: This is used to distinguish between the different commands that
- *       can be passed to the IOCTL functions.
- *
- * Entry point for the Ioctl.
- */
-static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-
-       switch (cmd) {
-       case SIOCSHWTSTAMP:
-               return vxge_hwtstamp_set(vdev, rq->ifr_data);
-       case SIOCGHWTSTAMP:
-               return vxge_hwtstamp_get(vdev, rq->ifr_data);
-       default:
-               return -EOPNOTSUPP;
-       }
-}
-
-/**
- * vxge_tx_watchdog
- * @dev: pointer to net device structure
- * @txqueue: index of the hanging queue
- *
- * Watchdog for transmit side.
- * This function is triggered if the Tx Queue is stopped
- * for a pre-defined amount of time when the Interface is still up.
- */
-static void vxge_tx_watchdog(struct net_device *dev, unsigned int txqueue)
-{
-       struct vxgedev *vdev;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       vdev = netdev_priv(dev);
-
-       vdev->cric_err_event = VXGE_HW_EVENT_RESET_START;
-
-       schedule_work(&vdev->reset_task);
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d  Exiting...", __func__, __LINE__);
-}
-
-/**
- * vxge_vlan_rx_add_vid
- * @dev: net device pointer.
- * @proto: vlan protocol
- * @vid: vid
- *
- * Add the vlan id to the devices vlan id table
- */
-static int
-vxge_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct vxge_vpath *vpath;
-       int vp_id;
-
-       /* Add these vlan to the vid table */
-       for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
-               vpath = &vdev->vpaths[vp_id];
-               if (!vpath->is_open)
-                       continue;
-               vxge_hw_vpath_vid_add(vpath->handle, vid);
-       }
-       set_bit(vid, vdev->active_vlans);
-       return 0;
-}
-
-/**
- * vxge_vlan_rx_kill_vid
- * @dev: net device pointer.
- * @proto: vlan protocol
- * @vid: vid
- *
- * Remove the vlan id from the device's vlan id table
- */
-static int
-vxge_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
-{
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct vxge_vpath *vpath;
-       int vp_id;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-
-       /* Delete this vlan from the vid table */
-       for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) {
-               vpath = &vdev->vpaths[vp_id];
-               if (!vpath->is_open)
-                       continue;
-               vxge_hw_vpath_vid_delete(vpath->handle, vid);
-       }
-       vxge_debug_entryexit(VXGE_TRACE,
-               "%s:%d  Exiting...", __func__, __LINE__);
-       clear_bit(vid, vdev->active_vlans);
-       return 0;
-}
-
-static const struct net_device_ops vxge_netdev_ops = {
-       .ndo_open               = vxge_open,
-       .ndo_stop               = vxge_close,
-       .ndo_get_stats64        = vxge_get_stats64,
-       .ndo_start_xmit         = vxge_xmit,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_rx_mode        = vxge_set_multicast,
-       .ndo_eth_ioctl           = vxge_ioctl,
-       .ndo_set_mac_address    = vxge_set_mac_addr,
-       .ndo_change_mtu         = vxge_change_mtu,
-       .ndo_fix_features       = vxge_fix_features,
-       .ndo_set_features       = vxge_set_features,
-       .ndo_vlan_rx_kill_vid   = vxge_vlan_rx_kill_vid,
-       .ndo_vlan_rx_add_vid    = vxge_vlan_rx_add_vid,
-       .ndo_tx_timeout         = vxge_tx_watchdog,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = vxge_netpoll,
-#endif
-};
-
-static int vxge_device_register(struct __vxge_hw_device *hldev,
-                               struct vxge_config *config,
-                               int no_of_vpath, struct vxgedev **vdev_out)
-{
-       struct net_device *ndev;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxgedev *vdev;
-       int ret = 0, no_of_queue = 1;
-       u64 stat;
-
-       *vdev_out = NULL;
-       if (config->tx_steering_type)
-               no_of_queue = no_of_vpath;
-
-       ndev = alloc_etherdev_mq(sizeof(struct vxgedev),
-                       no_of_queue);
-       if (ndev == NULL) {
-               vxge_debug_init(
-                       vxge_hw_device_trace_level_get(hldev),
-               "%s : device allocation failed", __func__);
-               ret = -ENODEV;
-               goto _out0;
-       }
-
-       vxge_debug_entryexit(
-               vxge_hw_device_trace_level_get(hldev),
-               "%s: %s:%d  Entering...",
-               ndev->name, __func__, __LINE__);
-
-       vdev = netdev_priv(ndev);
-       memset(vdev, 0, sizeof(struct vxgedev));
-
-       vdev->ndev = ndev;
-       vdev->devh = hldev;
-       vdev->pdev = hldev->pdev;
-       memcpy(&vdev->config, config, sizeof(struct vxge_config));
-       vdev->rx_hwts = 0;
-       vdev->titan1 = (vdev->pdev->revision == VXGE_HW_TITAN1_PCI_REVISION);
-
-       SET_NETDEV_DEV(ndev, &vdev->pdev->dev);
-
-       ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG |
-               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_TSO | NETIF_F_TSO6 |
-               NETIF_F_HW_VLAN_CTAG_TX;
-       if (vdev->config.rth_steering != NO_STEERING)
-               ndev->hw_features |= NETIF_F_RXHASH;
-
-       ndev->features |= ndev->hw_features |
-               NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
-
-
-       ndev->netdev_ops = &vxge_netdev_ops;
-
-       ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT;
-       INIT_WORK(&vdev->reset_task, vxge_reset);
-
-       vxge_initialize_ethtool_ops(ndev);
-
-       /* Allocate memory for vpath */
-       vdev->vpaths = kcalloc(no_of_vpath, sizeof(struct vxge_vpath),
-                              GFP_KERNEL);
-       if (!vdev->vpaths) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: vpath memory allocation failed",
-                       vdev->ndev->name);
-               ret = -ENOMEM;
-               goto _out1;
-       }
-
-       vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
-               "%s : checksumming enabled", __func__);
-
-       ndev->features |= NETIF_F_HIGHDMA;
-
-       /* MTU range: 68 - 9600 */
-       ndev->min_mtu = VXGE_HW_MIN_MTU;
-       ndev->max_mtu = VXGE_HW_MAX_MTU;
-
-       ret = register_netdev(ndev);
-       if (ret) {
-               vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
-                       "%s: %s : device registration failed!",
-                       ndev->name, __func__);
-               goto _out2;
-       }
-
-       /*  Set the factory defined MAC address initially */
-       ndev->addr_len = ETH_ALEN;
-
-       /* Make Link state as off at this point, when the Link change
-        * interrupt comes the state will be automatically changed to
-        * the right state.
-        */
-       netif_carrier_off(ndev);
-
-       vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
-               "%s: Ethernet device registered",
-               ndev->name);
-
-       hldev->ndev = ndev;
-       *vdev_out = vdev;
-
-       /* Resetting the Device stats */
-       status = vxge_hw_mrpcim_stats_access(
-                               hldev,
-                               VXGE_HW_STATS_OP_CLEAR_ALL_STATS,
-                               0,
-                               0,
-                               &stat);
-
-       if (status == VXGE_HW_ERR_PRIVILEGED_OPERATION)
-               vxge_debug_init(
-                       vxge_hw_device_trace_level_get(hldev),
-                       "%s: device stats clear returns"
-                       "VXGE_HW_ERR_PRIVILEGED_OPERATION", ndev->name);
-
-       vxge_debug_entryexit(vxge_hw_device_trace_level_get(hldev),
-               "%s: %s:%d  Exiting...",
-               ndev->name, __func__, __LINE__);
-
-       return ret;
-_out2:
-       kfree(vdev->vpaths);
-_out1:
-       free_netdev(ndev);
-_out0:
-       return ret;
-}
-
-/*
- * vxge_device_unregister
- *
- * This function will unregister and free network device
- */
-static void vxge_device_unregister(struct __vxge_hw_device *hldev)
-{
-       struct vxgedev *vdev;
-       struct net_device *dev;
-       char buf[IFNAMSIZ];
-
-       dev = hldev->ndev;
-       vdev = netdev_priv(dev);
-
-       vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d", vdev->ndev->name,
-                            __func__, __LINE__);
-
-       strlcpy(buf, dev->name, IFNAMSIZ);
-
-       flush_work(&vdev->reset_task);
-
-       /* in 2.6 will call stop() if device is up */
-       unregister_netdev(dev);
-
-       kfree(vdev->vpaths);
-
-       vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered",
-                       buf);
-       vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d  Exiting...", buf,
-                            __func__, __LINE__);
-
-       /* we are safe to free it now */
-       free_netdev(dev);
-}
-
-/*
- * vxge_callback_crit_err
- *
- * This function is called by the alarm handler in interrupt context.
- * Driver must analyze it based on the event type.
- */
-static void
-vxge_callback_crit_err(struct __vxge_hw_device *hldev,
-                       enum vxge_hw_event type, u64 vp_id)
-{
-       struct net_device *dev = hldev->ndev;
-       struct vxgedev *vdev = netdev_priv(dev);
-       struct vxge_vpath *vpath = NULL;
-       int vpath_idx;
-
-       vxge_debug_entryexit(vdev->level_trace,
-               "%s: %s:%d", vdev->ndev->name, __func__, __LINE__);
-
-       /* Note: This event type should be used for device wide
-        * indications only - Serious errors, Slot freeze and critical errors
-        */
-       vdev->cric_err_event = type;
-
-       for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) {
-               vpath = &vdev->vpaths[vpath_idx];
-               if (vpath->device_id == vp_id)
-                       break;
-       }
-
-       if (!test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) {
-               if (type == VXGE_HW_EVENT_SLOT_FREEZE) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: Slot is frozen", vdev->ndev->name);
-               } else if (type == VXGE_HW_EVENT_SERR) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: Encountered Serious Error",
-                               vdev->ndev->name);
-               } else if (type == VXGE_HW_EVENT_CRITICAL_ERR)
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: Encountered Critical Error",
-                               vdev->ndev->name);
-       }
-
-       if ((type == VXGE_HW_EVENT_SERR) ||
-               (type == VXGE_HW_EVENT_SLOT_FREEZE)) {
-               if (unlikely(vdev->exec_mode))
-                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-       } else if (type == VXGE_HW_EVENT_CRITICAL_ERR) {
-               vxge_hw_device_mask_all(hldev);
-               if (unlikely(vdev->exec_mode))
-                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-       } else if ((type == VXGE_HW_EVENT_FIFO_ERR) ||
-                 (type == VXGE_HW_EVENT_VPATH_ERR)) {
-
-               if (unlikely(vdev->exec_mode))
-                       clear_bit(__VXGE_STATE_CARD_UP, &vdev->state);
-               else {
-                       /* check if this vpath is already set for reset */
-                       if (!test_and_set_bit(vpath_idx, &vdev->vp_reset)) {
-
-                               /* disable interrupts for this vpath */
-                               vxge_vpath_intr_disable(vdev, vpath_idx);
-
-                               /* stop the queue for this vpath */
-                               netif_tx_stop_queue(vpath->fifo.txq);
-                       }
-               }
-       }
-
-       vxge_debug_entryexit(vdev->level_trace,
-               "%s: %s:%d  Exiting...",
-               vdev->ndev->name, __func__, __LINE__);
-}
-
-static void verify_bandwidth(void)
-{
-       int i, band_width, total = 0, equal_priority = 0;
-
-       /* 1. If user enters 0 for some fifo, give equal priority to all */
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (bw_percentage[i] == 0) {
-                       equal_priority = 1;
-                       break;
-               }
-       }
-
-       if (!equal_priority) {
-               /* 2. If sum exceeds 100, give equal priority to all */
-               for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-                       if (bw_percentage[i] == 0xFF)
-                               break;
-
-                       total += bw_percentage[i];
-                       if (total > VXGE_HW_VPATH_BANDWIDTH_MAX) {
-                               equal_priority = 1;
-                               break;
-                       }
-               }
-       }
-
-       if (!equal_priority) {
-               /* Is all the bandwidth consumed? */
-               if (total < VXGE_HW_VPATH_BANDWIDTH_MAX) {
-                       if (i < VXGE_HW_MAX_VIRTUAL_PATHS) {
-                               /* Split rest of bw equally among next VPs*/
-                               band_width =
-                                 (VXGE_HW_VPATH_BANDWIDTH_MAX  - total) /
-                                       (VXGE_HW_MAX_VIRTUAL_PATHS - i);
-                               if (band_width < 2) /* min of 2% */
-                                       equal_priority = 1;
-                               else {
-                                       for (; i < VXGE_HW_MAX_VIRTUAL_PATHS;
-                                               i++)
-                                               bw_percentage[i] =
-                                                       band_width;
-                               }
-                       }
-               } else if (i < VXGE_HW_MAX_VIRTUAL_PATHS)
-                       equal_priority = 1;
-       }
-
-       if (equal_priority) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: Assigning equal bandwidth to all the vpaths",
-                       VXGE_DRIVER_NAME);
-               bw_percentage[0] = VXGE_HW_VPATH_BANDWIDTH_MAX /
-                                       VXGE_HW_MAX_VIRTUAL_PATHS;
-               for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
-                       bw_percentage[i] = bw_percentage[0];
-       }
-}
-
-/*
- * Vpath configuration
- */
-static int vxge_config_vpaths(struct vxge_hw_device_config *device_config,
-                             u64 vpath_mask, struct vxge_config *config_param)
-{
-       int i, no_of_vpaths = 0, default_no_vpath = 0, temp;
-       u32 txdl_size, txdl_per_memblock;
-
-       temp = driver_config->vpath_per_dev;
-       if ((driver_config->vpath_per_dev == VXGE_USE_DEFAULT) &&
-               (max_config_dev == VXGE_MAX_CONFIG_DEV)) {
-               /* No more CPU. Return vpath number as zero.*/
-               if (driver_config->g_no_cpus == -1)
-                       return 0;
-
-               if (!driver_config->g_no_cpus)
-                       driver_config->g_no_cpus =
-                               netif_get_num_default_rss_queues();
-
-               driver_config->vpath_per_dev = driver_config->g_no_cpus >> 1;
-               if (!driver_config->vpath_per_dev)
-                       driver_config->vpath_per_dev = 1;
-
-               for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
-                       if (vxge_bVALn(vpath_mask, i, 1))
-                               default_no_vpath++;
-
-               if (default_no_vpath < driver_config->vpath_per_dev)
-                       driver_config->vpath_per_dev = default_no_vpath;
-
-               driver_config->g_no_cpus = driver_config->g_no_cpus -
-                               (driver_config->vpath_per_dev * 2);
-               if (driver_config->g_no_cpus <= 0)
-                       driver_config->g_no_cpus = -1;
-       }
-
-       if (driver_config->vpath_per_dev == 1) {
-               vxge_debug_ll_config(VXGE_TRACE,
-                       "%s: Disable tx and rx steering, "
-                       "as single vpath is configured", VXGE_DRIVER_NAME);
-               config_param->rth_steering = NO_STEERING;
-               config_param->tx_steering_type = NO_STEERING;
-               device_config->rth_en = 0;
-       }
-
-       /* configure bandwidth */
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
-               device_config->vp_config[i].min_bandwidth = bw_percentage[i];
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               device_config->vp_config[i].vp_id = i;
-               device_config->vp_config[i].mtu = VXGE_HW_DEFAULT_MTU;
-               if (no_of_vpaths < driver_config->vpath_per_dev) {
-                       if (!vxge_bVALn(vpath_mask, i, 1)) {
-                               vxge_debug_ll_config(VXGE_TRACE,
-                                       "%s: vpath: %d is not available",
-                                       VXGE_DRIVER_NAME, i);
-                               continue;
-                       } else {
-                               vxge_debug_ll_config(VXGE_TRACE,
-                                       "%s: vpath: %d available",
-                                       VXGE_DRIVER_NAME, i);
-                               no_of_vpaths++;
-                       }
-               } else {
-                       vxge_debug_ll_config(VXGE_TRACE,
-                               "%s: vpath: %d is not configured, "
-                               "max_config_vpath exceeded",
-                               VXGE_DRIVER_NAME, i);
-                       break;
-               }
-
-               /* Configure Tx fifo's */
-               device_config->vp_config[i].fifo.enable =
-                                               VXGE_HW_FIFO_ENABLE;
-               device_config->vp_config[i].fifo.max_frags =
-                               MAX_SKB_FRAGS + 1;
-               device_config->vp_config[i].fifo.memblock_size =
-                       VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE;
-
-               txdl_size = device_config->vp_config[i].fifo.max_frags *
-                               sizeof(struct vxge_hw_fifo_txd);
-               txdl_per_memblock = VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE / txdl_size;
-
-               device_config->vp_config[i].fifo.fifo_blocks =
-                       ((VXGE_DEF_FIFO_LENGTH - 1) / txdl_per_memblock) + 1;
-
-               device_config->vp_config[i].fifo.intr =
-                               VXGE_HW_FIFO_QUEUE_INTR_DISABLE;
-
-               /* Configure tti properties */
-               device_config->vp_config[i].tti.intr_enable =
-                                       VXGE_HW_TIM_INTR_ENABLE;
-
-               device_config->vp_config[i].tti.btimer_val =
-                       (VXGE_TTI_BTIMER_VAL * 1000) / 272;
-
-               device_config->vp_config[i].tti.timer_ac_en =
-                               VXGE_HW_TIM_TIMER_AC_ENABLE;
-
-               /* For msi-x with napi (each vector has a handler of its own) -
-                * Set CI to OFF for all vpaths
-                */
-               device_config->vp_config[i].tti.timer_ci_en =
-                       VXGE_HW_TIM_TIMER_CI_DISABLE;
-
-               device_config->vp_config[i].tti.timer_ri_en =
-                               VXGE_HW_TIM_TIMER_RI_DISABLE;
-
-               device_config->vp_config[i].tti.util_sel =
-                       VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL;
-
-               device_config->vp_config[i].tti.ltimer_val =
-                       (VXGE_TTI_LTIMER_VAL * 1000) / 272;
-
-               device_config->vp_config[i].tti.rtimer_val =
-                       (VXGE_TTI_RTIMER_VAL * 1000) / 272;
-
-               device_config->vp_config[i].tti.urange_a = TTI_TX_URANGE_A;
-               device_config->vp_config[i].tti.urange_b = TTI_TX_URANGE_B;
-               device_config->vp_config[i].tti.urange_c = TTI_TX_URANGE_C;
-               device_config->vp_config[i].tti.uec_a = TTI_TX_UFC_A;
-               device_config->vp_config[i].tti.uec_b = TTI_TX_UFC_B;
-               device_config->vp_config[i].tti.uec_c = TTI_TX_UFC_C;
-               device_config->vp_config[i].tti.uec_d = TTI_TX_UFC_D;
-
-               /* Configure Rx rings */
-               device_config->vp_config[i].ring.enable  =
-                                               VXGE_HW_RING_ENABLE;
-
-               device_config->vp_config[i].ring.ring_blocks  =
-                                               VXGE_HW_DEF_RING_BLOCKS;
-
-               device_config->vp_config[i].ring.buffer_mode =
-                       VXGE_HW_RING_RXD_BUFFER_MODE_1;
-
-               device_config->vp_config[i].ring.rxds_limit  =
-                               VXGE_HW_DEF_RING_RXDS_LIMIT;
-
-               device_config->vp_config[i].ring.scatter_mode =
-                                       VXGE_HW_RING_SCATTER_MODE_A;
-
-               /* Configure rti properties */
-               device_config->vp_config[i].rti.intr_enable =
-                                       VXGE_HW_TIM_INTR_ENABLE;
-
-               device_config->vp_config[i].rti.btimer_val =
-                       (VXGE_RTI_BTIMER_VAL * 1000)/272;
-
-               device_config->vp_config[i].rti.timer_ac_en =
-                                               VXGE_HW_TIM_TIMER_AC_ENABLE;
-
-               device_config->vp_config[i].rti.timer_ci_en =
-                                               VXGE_HW_TIM_TIMER_CI_DISABLE;
-
-               device_config->vp_config[i].rti.timer_ri_en =
-                                               VXGE_HW_TIM_TIMER_RI_DISABLE;
-
-               device_config->vp_config[i].rti.util_sel =
-                               VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL;
-
-               device_config->vp_config[i].rti.urange_a =
-                                               RTI_RX_URANGE_A;
-               device_config->vp_config[i].rti.urange_b =
-                                               RTI_RX_URANGE_B;
-               device_config->vp_config[i].rti.urange_c =
-                                               RTI_RX_URANGE_C;
-               device_config->vp_config[i].rti.uec_a = RTI_RX_UFC_A;
-               device_config->vp_config[i].rti.uec_b = RTI_RX_UFC_B;
-               device_config->vp_config[i].rti.uec_c = RTI_RX_UFC_C;
-               device_config->vp_config[i].rti.uec_d = RTI_RX_UFC_D;
-
-               device_config->vp_config[i].rti.rtimer_val =
-                       (VXGE_RTI_RTIMER_VAL * 1000) / 272;
-
-               device_config->vp_config[i].rti.ltimer_val =
-                       (VXGE_RTI_LTIMER_VAL * 1000) / 272;
-
-               device_config->vp_config[i].rpa_strip_vlan_tag =
-                       vlan_tag_strip;
-       }
-
-       driver_config->vpath_per_dev = temp;
-       return no_of_vpaths;
-}
-
-/* initialize device configuratrions */
-static void vxge_device_config_init(struct vxge_hw_device_config *device_config,
-                                   int *intr_type)
-{
-       /* Used for CQRQ/SRQ. */
-       device_config->dma_blockpool_initial =
-                       VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE;
-
-       device_config->dma_blockpool_max =
-                       VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE;
-
-       if (max_mac_vpath > VXGE_MAX_MAC_ADDR_COUNT)
-               max_mac_vpath = VXGE_MAX_MAC_ADDR_COUNT;
-
-       if (!IS_ENABLED(CONFIG_PCI_MSI)) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: This Kernel does not support "
-                       "MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME);
-               *intr_type = INTA;
-       }
-
-       /* Configure whether MSI-X or IRQL. */
-       switch (*intr_type) {
-       case INTA:
-               device_config->intr_mode = VXGE_HW_INTR_MODE_IRQLINE;
-               break;
-
-       case MSI_X:
-               device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX_ONE_SHOT;
-               break;
-       }
-
-       /* Timer period between device poll */
-       device_config->device_poll_millis = VXGE_TIMER_DELAY;
-
-       /* Configure mac based steering. */
-       device_config->rts_mac_en = addr_learn_en;
-
-       /* Configure Vpaths */
-       device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_MULTI_IT;
-
-       vxge_debug_ll_config(VXGE_TRACE, "%s : Device Config Params ",
-                       __func__);
-       vxge_debug_ll_config(VXGE_TRACE, "intr_mode : %d",
-                       device_config->intr_mode);
-       vxge_debug_ll_config(VXGE_TRACE, "device_poll_millis : %d",
-                       device_config->device_poll_millis);
-       vxge_debug_ll_config(VXGE_TRACE, "rth_en : %d",
-                       device_config->rth_en);
-       vxge_debug_ll_config(VXGE_TRACE, "rth_it_type : %d",
-                       device_config->rth_it_type);
-}
-
-static void vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask)
-{
-       int i;
-
-       vxge_debug_init(VXGE_TRACE,
-               "%s: %d Vpath(s) opened",
-               vdev->ndev->name, vdev->no_of_vpath);
-
-       switch (vdev->config.intr_type) {
-       case INTA:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Interrupt type INTA", vdev->ndev->name);
-               break;
-
-       case MSI_X:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Interrupt type MSI-X", vdev->ndev->name);
-               break;
-       }
-
-       if (vdev->config.rth_steering) {
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: RTH steering enabled for TCP_IPV4",
-                       vdev->ndev->name);
-       } else {
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: RTH steering disabled", vdev->ndev->name);
-       }
-
-       switch (vdev->config.tx_steering_type) {
-       case NO_STEERING:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Tx steering disabled", vdev->ndev->name);
-               break;
-       case TX_PRIORITY_STEERING:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Unsupported tx steering option",
-                       vdev->ndev->name);
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Tx steering disabled", vdev->ndev->name);
-               vdev->config.tx_steering_type = 0;
-               break;
-       case TX_VLAN_STEERING:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Unsupported tx steering option",
-                       vdev->ndev->name);
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Tx steering disabled", vdev->ndev->name);
-               vdev->config.tx_steering_type = 0;
-               break;
-       case TX_MULTIQ_STEERING:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Tx multiqueue steering enabled",
-                       vdev->ndev->name);
-               break;
-       case TX_PORT_STEERING:
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Tx port steering enabled",
-                       vdev->ndev->name);
-               break;
-       default:
-               vxge_debug_init(VXGE_ERR,
-                       "%s: Unsupported tx steering type",
-                       vdev->ndev->name);
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: Tx steering disabled", vdev->ndev->name);
-               vdev->config.tx_steering_type = 0;
-       }
-
-       if (vdev->config.addr_learn_en)
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: MAC Address learning enabled", vdev->ndev->name);
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!vxge_bVALn(vpath_mask, i, 1))
-                       continue;
-               vxge_debug_ll_config(VXGE_TRACE,
-                       "%s: MTU size - %d", vdev->ndev->name,
-                       ((vdev->devh))->
-                               config.vp_config[i].mtu);
-               vxge_debug_init(VXGE_TRACE,
-                       "%s: VLAN tag stripping %s", vdev->ndev->name,
-                       ((vdev->devh))->
-                               config.vp_config[i].rpa_strip_vlan_tag
-                       ? "Enabled" : "Disabled");
-               vxge_debug_ll_config(VXGE_TRACE,
-                       "%s: Max frags : %d", vdev->ndev->name,
-                       ((vdev->devh))->
-                               config.vp_config[i].fifo.max_frags);
-               break;
-       }
-}
-
-/**
- * vxge_pm_suspend - vxge power management suspend entry point
- * @dev_d: device pointer
- *
- */
-static int __maybe_unused vxge_pm_suspend(struct device *dev_d)
-{
-       return -ENOSYS;
-}
-/**
- * vxge_pm_resume - vxge power management resume entry point
- * @dev_d: device pointer
- *
- */
-static int __maybe_unused vxge_pm_resume(struct device *dev_d)
-{
-       return -ENOSYS;
-}
-
-/**
- * vxge_io_error_detected - called when PCI error is detected
- * @pdev: Pointer to PCI device
- * @state: The current pci connection state
- *
- * This function is called after a PCI bus error affecting
- * this device has been detected.
- */
-static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev,
-                                               pci_channel_state_t state)
-{
-       struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
-       struct net_device *netdev = hldev->ndev;
-
-       netif_device_detach(netdev);
-
-       if (state == pci_channel_io_perm_failure)
-               return PCI_ERS_RESULT_DISCONNECT;
-
-       if (netif_running(netdev)) {
-               /* Bring down the card, while avoiding PCI I/O */
-               do_vxge_close(netdev, 0);
-       }
-
-       pci_disable_device(pdev);
-
-       return PCI_ERS_RESULT_NEED_RESET;
-}
-
-/**
- * vxge_io_slot_reset - called after the pci bus has been reset.
- * @pdev: Pointer to PCI device
- *
- * Restart the card from scratch, as if from a cold-boot.
- * At this point, the card has exprienced a hard reset,
- * followed by fixups by BIOS, and has its config space
- * set up identically to what it was at cold boot.
- */
-static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev)
-{
-       struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
-       struct net_device *netdev = hldev->ndev;
-
-       struct vxgedev *vdev = netdev_priv(netdev);
-
-       if (pci_enable_device(pdev)) {
-               netdev_err(netdev, "Cannot re-enable device after reset\n");
-               return PCI_ERS_RESULT_DISCONNECT;
-       }
-
-       pci_set_master(pdev);
-       do_vxge_reset(vdev, VXGE_LL_FULL_RESET);
-
-       return PCI_ERS_RESULT_RECOVERED;
-}
-
-/**
- * vxge_io_resume - called when traffic can start flowing again.
- * @pdev: Pointer to PCI device
- *
- * This callback is called when the error recovery driver tells
- * us that its OK to resume normal operation.
- */
-static void vxge_io_resume(struct pci_dev *pdev)
-{
-       struct __vxge_hw_device *hldev = pci_get_drvdata(pdev);
-       struct net_device *netdev = hldev->ndev;
-
-       if (netif_running(netdev)) {
-               if (vxge_open(netdev)) {
-                       netdev_err(netdev,
-                                  "Can't bring device back up after reset\n");
-                       return;
-               }
-       }
-
-       netif_device_attach(netdev);
-}
-
-static inline u32 vxge_get_num_vfs(u64 function_mode)
-{
-       u32 num_functions = 0;
-
-       switch (function_mode) {
-       case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
-       case VXGE_HW_FUNCTION_MODE_SRIOV_8:
-               num_functions = 8;
-               break;
-       case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
-               num_functions = 1;
-               break;
-       case VXGE_HW_FUNCTION_MODE_SRIOV:
-       case VXGE_HW_FUNCTION_MODE_MRIOV:
-       case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17:
-               num_functions = 17;
-               break;
-       case VXGE_HW_FUNCTION_MODE_SRIOV_4:
-               num_functions = 4;
-               break;
-       case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2:
-               num_functions = 2;
-               break;
-       case VXGE_HW_FUNCTION_MODE_MRIOV_8:
-               num_functions = 8; /* TODO */
-               break;
-       }
-       return num_functions;
-}
-
-int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override)
-{
-       struct __vxge_hw_device *hldev = vdev->devh;
-       u32 maj, min, bld, cmaj, cmin, cbld;
-       enum vxge_hw_status status;
-       const struct firmware *fw;
-       int ret;
-
-       ret = request_firmware(&fw, fw_name, &vdev->pdev->dev);
-       if (ret) {
-               vxge_debug_init(VXGE_ERR, "%s: Firmware file '%s' not found",
-                               VXGE_DRIVER_NAME, fw_name);
-               goto out;
-       }
-
-       /* Load the new firmware onto the adapter */
-       status = vxge_update_fw_image(hldev, fw->data, fw->size);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                               "%s: FW image download to adapter failed '%s'.",
-                               VXGE_DRIVER_NAME, fw_name);
-               ret = -EIO;
-               goto out;
-       }
-
-       /* Read the version of the new firmware */
-       status = vxge_hw_upgrade_read_version(hldev, &maj, &min, &bld);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                               "%s: Upgrade read version failed '%s'.",
-                               VXGE_DRIVER_NAME, fw_name);
-               ret = -EIO;
-               goto out;
-       }
-
-       cmaj = vdev->config.device_hw_info.fw_version.major;
-       cmin = vdev->config.device_hw_info.fw_version.minor;
-       cbld = vdev->config.device_hw_info.fw_version.build;
-       /* It's possible the version in /lib/firmware is not the latest version.
-        * If so, we could get into a loop of trying to upgrade to the latest
-        * and flashing the older version.
-        */
-       if (VXGE_FW_VER(maj, min, bld) == VXGE_FW_VER(cmaj, cmin, cbld) &&
-           !override) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       printk(KERN_NOTICE "Upgrade to firmware version %d.%d.%d commencing\n",
-              maj, min, bld);
-
-       /* Flash the adapter with the new firmware */
-       status = vxge_hw_flash_fw(hldev);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR, "%s: Upgrade commit failed '%s'.",
-                               VXGE_DRIVER_NAME, fw_name);
-               ret = -EIO;
-               goto out;
-       }
-
-       printk(KERN_NOTICE "Upgrade of firmware successful!  Adapter must be "
-              "hard reset before using, thus requiring a system reboot or a "
-              "hotplug event.\n");
-
-out:
-       release_firmware(fw);
-       return ret;
-}
-
-static int vxge_probe_fw_update(struct vxgedev *vdev)
-{
-       u32 maj, min, bld;
-       int ret, gpxe = 0;
-       char *fw_name;
-
-       maj = vdev->config.device_hw_info.fw_version.major;
-       min = vdev->config.device_hw_info.fw_version.minor;
-       bld = vdev->config.device_hw_info.fw_version.build;
-
-       if (VXGE_FW_VER(maj, min, bld) == VXGE_CERT_FW_VER)
-               return 0;
-
-       /* Ignore the build number when determining if the current firmware is
-        * "too new" to load the driver
-        */
-       if (VXGE_FW_VER(maj, min, 0) > VXGE_CERT_FW_VER) {
-               vxge_debug_init(VXGE_ERR, "%s: Firmware newer than last known "
-                               "version, unable to load driver\n",
-                               VXGE_DRIVER_NAME);
-               return -EINVAL;
-       }
-
-       /* Firmware 1.4.4 and older cannot be upgraded, and is too ancient to
-        * work with this driver.
-        */
-       if (VXGE_FW_VER(maj, min, bld) <= VXGE_FW_DEAD_VER) {
-               vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d cannot be "
-                               "upgraded\n", VXGE_DRIVER_NAME, maj, min, bld);
-               return -EINVAL;
-       }
-
-       /* If file not specified, determine gPXE or not */
-       if (VXGE_FW_VER(maj, min, bld) >= VXGE_EPROM_FW_VER) {
-               int i;
-               for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++)
-                       if (vdev->devh->eprom_versions[i]) {
-                               gpxe = 1;
-                               break;
-                       }
-       }
-       if (gpxe)
-               fw_name = "vxge/X3fw-pxe.ncf";
-       else
-               fw_name = "vxge/X3fw.ncf";
-
-       ret = vxge_fw_upgrade(vdev, fw_name, 0);
-       /* -EINVAL and -ENOENT are not fatal errors for flashing firmware on
-        * probe, so ignore them
-        */
-       if (ret != -EINVAL && ret != -ENOENT)
-               return -EIO;
-       else
-               ret = 0;
-
-       if (VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, VXGE_CERT_FW_VER_MINOR, 0) >
-           VXGE_FW_VER(maj, min, 0)) {
-               vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d is too old to"
-                               " be used with this driver.",
-                               VXGE_DRIVER_NAME, maj, min, bld);
-               return -EINVAL;
-       }
-
-       return ret;
-}
-
-static int is_sriov_initialized(struct pci_dev *pdev)
-{
-       int pos;
-       u16 ctrl;
-
-       pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
-       if (pos) {
-               pci_read_config_word(pdev, pos + PCI_SRIOV_CTRL, &ctrl);
-               if (ctrl & PCI_SRIOV_CTRL_VFE)
-                       return 1;
-       }
-       return 0;
-}
-
-static const struct vxge_hw_uld_cbs vxge_callbacks = {
-       .link_up = vxge_callback_link_up,
-       .link_down = vxge_callback_link_down,
-       .crit_err = vxge_callback_crit_err,
-};
-
-/**
- * vxge_probe
- * @pdev : structure containing the PCI related information of the device.
- * @pre: List of PCI devices supported by the driver listed in vxge_id_table.
- * Description:
- * This function is called when a new PCI device gets detected and initializes
- * it.
- * Return value:
- * returns 0 on success and negative on failure.
- *
- */
-static int
-vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
-{
-       struct __vxge_hw_device *hldev;
-       enum vxge_hw_status status;
-       int ret;
-       u64 vpath_mask = 0;
-       struct vxgedev *vdev;
-       struct vxge_config *ll_config = NULL;
-       struct vxge_hw_device_config *device_config = NULL;
-       struct vxge_hw_device_attr attr;
-       int i, j, no_of_vpath = 0, max_vpath_supported = 0;
-       u8 *macaddr;
-       struct vxge_mac_addrs *entry;
-       static int bus = -1, device = -1;
-       u32 host_type;
-       u8 new_device = 0;
-       enum vxge_hw_status is_privileged;
-       u32 function_mode;
-       u32 num_vfs = 0;
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
-       attr.pdev = pdev;
-
-       /* In SRIOV-17 mode, functions of the same adapter
-        * can be deployed on different buses
-        */
-       if (((bus != pdev->bus->number) || (device != PCI_SLOT(pdev->devfn))) &&
-           !pdev->is_virtfn)
-               new_device = 1;
-
-       bus = pdev->bus->number;
-       device = PCI_SLOT(pdev->devfn);
-
-       if (new_device) {
-               if (driver_config->config_dev_cnt &&
-                  (driver_config->config_dev_cnt !=
-                       driver_config->total_dev_cnt))
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: Configured %d of %d devices",
-                               VXGE_DRIVER_NAME,
-                               driver_config->config_dev_cnt,
-                               driver_config->total_dev_cnt);
-               driver_config->config_dev_cnt = 0;
-               driver_config->total_dev_cnt = 0;
-       }
-
-       /* Now making the CPU based no of vpath calculation
-        * applicable for individual functions as well.
-        */
-       driver_config->g_no_cpus = 0;
-       driver_config->vpath_per_dev = max_config_vpath;
-
-       driver_config->total_dev_cnt++;
-       if (++driver_config->config_dev_cnt > max_config_dev) {
-               ret = 0;
-               goto _exit0;
-       }
-
-       device_config = kzalloc(sizeof(struct vxge_hw_device_config),
-               GFP_KERNEL);
-       if (!device_config) {
-               ret = -ENOMEM;
-               vxge_debug_init(VXGE_ERR,
-                       "device_config : malloc failed %s %d",
-                       __FILE__, __LINE__);
-               goto _exit0;
-       }
-
-       ll_config = kzalloc(sizeof(struct vxge_config), GFP_KERNEL);
-       if (!ll_config) {
-               ret = -ENOMEM;
-               vxge_debug_init(VXGE_ERR,
-                       "device_config : malloc failed %s %d",
-                       __FILE__, __LINE__);
-               goto _exit0;
-       }
-       ll_config->tx_steering_type = TX_MULTIQ_STEERING;
-       ll_config->intr_type = MSI_X;
-       ll_config->napi_weight = NAPI_POLL_WEIGHT;
-       ll_config->rth_steering = RTH_STEERING;
-
-       /* get the default configuration parameters */
-       vxge_hw_device_config_default_get(device_config);
-
-       /* initialize configuration parameters */
-       vxge_device_config_init(device_config, &ll_config->intr_type);
-
-       ret = pci_enable_device(pdev);
-       if (ret) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : can not enable PCI device", __func__);
-               goto _exit0;
-       }
-
-       if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
-               vxge_debug_ll_config(VXGE_TRACE,
-                       "%s : using 64bit DMA", __func__);
-       } else {
-               ret = -ENOMEM;
-               goto _exit1;
-       }
-
-       ret = pci_request_region(pdev, 0, VXGE_DRIVER_NAME);
-       if (ret) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : request regions failed", __func__);
-               goto _exit1;
-       }
-
-       pci_set_master(pdev);
-
-       attr.bar0 = pci_ioremap_bar(pdev, 0);
-       if (!attr.bar0) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s : cannot remap io memory bar0", __func__);
-               ret = -ENODEV;
-               goto _exit2;
-       }
-       vxge_debug_ll_config(VXGE_TRACE,
-               "pci ioremap bar0: %p:0x%llx",
-               attr.bar0,
-               (unsigned long long)pci_resource_start(pdev, 0));
-
-       status = vxge_hw_device_hw_info_get(attr.bar0,
-                       &ll_config->device_hw_info);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: Reading of hardware info failed."
-                       "Please try upgrading the firmware.", VXGE_DRIVER_NAME);
-               ret = -EINVAL;
-               goto _exit3;
-       }
-
-       vpath_mask = ll_config->device_hw_info.vpath_mask;
-       if (vpath_mask == 0) {
-               vxge_debug_ll_config(VXGE_TRACE,
-                       "%s: No vpaths available in device", VXGE_DRIVER_NAME);
-               ret = -EINVAL;
-               goto _exit3;
-       }
-
-       vxge_debug_ll_config(VXGE_TRACE,
-               "%s:%d  Vpath mask = %llx", __func__, __LINE__,
-               (unsigned long long)vpath_mask);
-
-       function_mode = ll_config->device_hw_info.function_mode;
-       host_type = ll_config->device_hw_info.host_type;
-       is_privileged = __vxge_hw_device_is_privilaged(host_type,
-               ll_config->device_hw_info.func_id);
-
-       /* Check how many vpaths are available */
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!((vpath_mask) & vxge_mBIT(i)))
-                       continue;
-               max_vpath_supported++;
-       }
-
-       if (new_device)
-               num_vfs = vxge_get_num_vfs(function_mode) - 1;
-
-       /* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */
-       if (is_sriov(function_mode) && !is_sriov_initialized(pdev) &&
-          (ll_config->intr_type != INTA)) {
-               ret = pci_enable_sriov(pdev, num_vfs);
-               if (ret)
-                       vxge_debug_ll_config(VXGE_ERR,
-                               "Failed in enabling SRIOV mode: %d\n", ret);
-                       /* No need to fail out, as an error here is non-fatal */
-       }
-
-       /*
-        * Configure vpaths and get driver configured number of vpaths
-        * which is less than or equal to the maximum vpaths per function.
-        */
-       no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, ll_config);
-       if (!no_of_vpath) {
-               vxge_debug_ll_config(VXGE_ERR,
-                       "%s: No more vpaths to configure", VXGE_DRIVER_NAME);
-               ret = 0;
-               goto _exit3;
-       }
-
-       /* Setting driver callbacks */
-       attr.uld_callbacks = &vxge_callbacks;
-
-       status = vxge_hw_device_initialize(&hldev, &attr, device_config);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR,
-                       "Failed to initialize device (%d)", status);
-               ret = -EINVAL;
-               goto _exit3;
-       }
-
-       if (VXGE_FW_VER(ll_config->device_hw_info.fw_version.major,
-                       ll_config->device_hw_info.fw_version.minor,
-                       ll_config->device_hw_info.fw_version.build) >=
-           VXGE_EPROM_FW_VER) {
-               struct eprom_image img[VXGE_HW_MAX_ROM_IMAGES];
-
-               status = vxge_hw_vpath_eprom_img_ver_get(hldev, img);
-               if (status != VXGE_HW_OK) {
-                       vxge_debug_init(VXGE_ERR, "%s: Reading of EPROM failed",
-                                       VXGE_DRIVER_NAME);
-                       /* This is a non-fatal error, continue */
-               }
-
-               for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) {
-                       hldev->eprom_versions[i] = img[i].version;
-                       if (!img[i].is_valid)
-                               break;
-                       vxge_debug_init(VXGE_TRACE, "%s: EPROM %d, version "
-                                       "%d.%d.%d.%d", VXGE_DRIVER_NAME, i,
-                                       VXGE_EPROM_IMG_MAJOR(img[i].version),
-                                       VXGE_EPROM_IMG_MINOR(img[i].version),
-                                       VXGE_EPROM_IMG_FIX(img[i].version),
-                                       VXGE_EPROM_IMG_BUILD(img[i].version));
-               }
-       }
-
-       /* if FCS stripping is not disabled in MAC fail driver load */
-       status = vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask);
-       if (status != VXGE_HW_OK) {
-               vxge_debug_init(VXGE_ERR, "%s: FCS stripping is enabled in MAC"
-                               " failing driver load", VXGE_DRIVER_NAME);
-               ret = -EINVAL;
-               goto _exit4;
-       }
-
-       /* Always enable HWTS.  This will always cause the FCS to be invalid,
-        * due to the fact that HWTS is using the FCS as the location of the
-        * timestamp.  The HW FCS checking will still correctly determine if
-        * there is a valid checksum, and the FCS is being removed by the driver
-        * anyway.  So no functionality is being lost.  Since it is always
-        * enabled, we now simply use the ioctl call to set whether or not the
-        * driver should be paying attention to the HWTS.
-        */
-       if (is_privileged == VXGE_HW_OK) {
-               status = vxge_timestamp_config(hldev);
-               if (status != VXGE_HW_OK) {
-                       vxge_debug_init(VXGE_ERR, "%s: HWTS enable failed",
-                                       VXGE_DRIVER_NAME);
-                       ret = -EFAULT;
-                       goto _exit4;
-               }
-       }
-
-       vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
-
-       /* set private device info */
-       pci_set_drvdata(pdev, hldev);
-
-       ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
-       ll_config->addr_learn_en = addr_learn_en;
-       ll_config->rth_algorithm = RTH_ALG_JENKINS;
-       ll_config->rth_hash_type_tcpipv4 = 1;
-       ll_config->rth_hash_type_ipv4 = 0;
-       ll_config->rth_hash_type_tcpipv6 = 0;
-       ll_config->rth_hash_type_ipv6 = 0;
-       ll_config->rth_hash_type_tcpipv6ex = 0;
-       ll_config->rth_hash_type_ipv6ex = 0;
-       ll_config->rth_bkt_sz = RTH_BUCKET_SIZE;
-       ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
-       ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
-
-       ret = vxge_device_register(hldev, ll_config, no_of_vpath, &vdev);
-       if (ret) {
-               ret = -EINVAL;
-               goto _exit4;
-       }
-
-       ret = vxge_probe_fw_update(vdev);
-       if (ret)
-               goto _exit5;
-
-       vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
-       VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
-               vxge_hw_device_trace_level_get(hldev));
-
-       /* set private HW device info */
-       vdev->mtu = VXGE_HW_DEFAULT_MTU;
-       vdev->bar0 = attr.bar0;
-       vdev->max_vpath_supported = max_vpath_supported;
-       vdev->no_of_vpath = no_of_vpath;
-
-       /* Virtual Path count */
-       for (i = 0, j = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-               if (!vxge_bVALn(vpath_mask, i, 1))
-                       continue;
-               if (j >= vdev->no_of_vpath)
-                       break;
-
-               vdev->vpaths[j].is_configured = 1;
-               vdev->vpaths[j].device_id = i;
-               vdev->vpaths[j].ring.driver_id = j;
-               vdev->vpaths[j].vdev = vdev;
-               vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath;
-               memcpy((u8 *)vdev->vpaths[j].macaddr,
-                               ll_config->device_hw_info.mac_addrs[i],
-                               ETH_ALEN);
-
-               /* Initialize the mac address list header */
-               INIT_LIST_HEAD(&vdev->vpaths[j].mac_addr_list);
-
-               vdev->vpaths[j].mac_addr_cnt = 0;
-               vdev->vpaths[j].mcast_addr_cnt = 0;
-               j++;
-       }
-       vdev->exec_mode = VXGE_EXEC_MODE_DISABLE;
-       vdev->max_config_port = max_config_port;
-
-       vdev->vlan_tag_strip = vlan_tag_strip;
-
-       /* map the hashing selector table to the configured vpaths */
-       for (i = 0; i < vdev->no_of_vpath; i++)
-               vdev->vpath_selector[i] = vpath_selector[i];
-
-       macaddr = (u8 *)vdev->vpaths[0].macaddr;
-
-       ll_config->device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
-       ll_config->device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
-       ll_config->device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
-
-       vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s",
-               vdev->ndev->name, ll_config->device_hw_info.serial_number);
-
-       vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s",
-               vdev->ndev->name, ll_config->device_hw_info.part_number);
-
-       vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
-               vdev->ndev->name, ll_config->device_hw_info.product_desc);
-
-       vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM",
-               vdev->ndev->name, macaddr);
-
-       vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d",
-               vdev->ndev->name, vxge_hw_device_link_width_get(hldev));
-
-       vxge_debug_init(VXGE_TRACE,
-               "%s: Firmware version : %s Date : %s", vdev->ndev->name,
-               ll_config->device_hw_info.fw_version.version,
-               ll_config->device_hw_info.fw_date.date);
-
-       if (new_device) {
-               switch (ll_config->device_hw_info.function_mode) {
-               case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
-                       vxge_debug_init(VXGE_TRACE,
-                       "%s: Single Function Mode Enabled", vdev->ndev->name);
-               break;
-               case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
-                       vxge_debug_init(VXGE_TRACE,
-                       "%s: Multi Function Mode Enabled", vdev->ndev->name);
-               break;
-               case VXGE_HW_FUNCTION_MODE_SRIOV:
-                       vxge_debug_init(VXGE_TRACE,
-                       "%s: Single Root IOV Mode Enabled", vdev->ndev->name);
-               break;
-               case VXGE_HW_FUNCTION_MODE_MRIOV:
-                       vxge_debug_init(VXGE_TRACE,
-                       "%s: Multi Root IOV Mode Enabled", vdev->ndev->name);
-               break;
-               }
-       }
-
-       vxge_print_parm(vdev, vpath_mask);
-
-       /* Store the fw version for ethttool option */
-       strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
-       eth_hw_addr_set(vdev->ndev, (u8 *)vdev->vpaths[0].macaddr);
-
-       /* Copy the station mac address to the list */
-       for (i = 0; i < vdev->no_of_vpath; i++) {
-               entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_KERNEL);
-               if (NULL == entry) {
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: mac_addr_list : memory allocation failed",
-                               vdev->ndev->name);
-                       ret = -EPERM;
-                       goto _exit6;
-               }
-               macaddr = (u8 *)&entry->macaddr;
-               memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
-               list_add(&entry->item, &vdev->vpaths[i].mac_addr_list);
-               vdev->vpaths[i].mac_addr_cnt = 1;
-       }
-
-       kfree(device_config);
-
-       /*
-        * INTA is shared in multi-function mode. This is unlike the INTA
-        * implementation in MR mode, where each VH has its own INTA message.
-        * - INTA is masked (disabled) as long as at least one function sets
-        * its TITAN_MASK_ALL_INT.ALARM bit.
-        * - INTA is unmasked (enabled) when all enabled functions have cleared
-        * their own TITAN_MASK_ALL_INT.ALARM bit.
-        * The TITAN_MASK_ALL_INT ALARM & TRAFFIC bits are cleared on power up.
-        * Though this driver leaves the top level interrupts unmasked while
-        * leaving the required module interrupt bits masked on exit, there
-        * could be a rougue driver around that does not follow this procedure
-        * resulting in a failure to generate interrupts. The following code is
-        * present to prevent such a failure.
-        */
-
-       if (ll_config->device_hw_info.function_mode ==
-               VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION)
-               if (vdev->config.intr_type == INTA)
-                       vxge_hw_device_unmask_all(hldev);
-
-       vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d  Exiting...",
-               vdev->ndev->name, __func__, __LINE__);
-
-       vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
-       VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
-               vxge_hw_device_trace_level_get(hldev));
-
-       kfree(ll_config);
-       return 0;
-
-_exit6:
-       for (i = 0; i < vdev->no_of_vpath; i++)
-               vxge_free_mac_add_list(&vdev->vpaths[i]);
-_exit5:
-       vxge_device_unregister(hldev);
-_exit4:
-       vxge_hw_device_terminate(hldev);
-       pci_disable_sriov(pdev);
-_exit3:
-       iounmap(attr.bar0);
-_exit2:
-       pci_release_region(pdev, 0);
-_exit1:
-       pci_disable_device(pdev);
-_exit0:
-       kfree(ll_config);
-       kfree(device_config);
-       driver_config->config_dev_cnt--;
-       driver_config->total_dev_cnt--;
-       return ret;
-}
-
-/**
- * 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.
- */
-static void vxge_remove(struct pci_dev *pdev)
-{
-       struct __vxge_hw_device *hldev;
-       struct vxgedev *vdev;
-       int i;
-
-       hldev = pci_get_drvdata(pdev);
-       if (hldev == NULL)
-               return;
-
-       vdev = netdev_priv(hldev->ndev);
-
-       vxge_debug_entryexit(vdev->level_trace, "%s:%d", __func__, __LINE__);
-       vxge_debug_init(vdev->level_trace, "%s : removing PCI device...",
-                       __func__);
-
-       for (i = 0; i < vdev->no_of_vpath; i++)
-               vxge_free_mac_add_list(&vdev->vpaths[i]);
-
-       vxge_device_unregister(hldev);
-       /* Do not call pci_disable_sriov here, as it will break child devices */
-       vxge_hw_device_terminate(hldev);
-       iounmap(vdev->bar0);
-       pci_release_region(pdev, 0);
-       pci_disable_device(pdev);
-       driver_config->config_dev_cnt--;
-       driver_config->total_dev_cnt--;
-
-       vxge_debug_init(vdev->level_trace, "%s:%d Device unregistered",
-                       __func__, __LINE__);
-       vxge_debug_entryexit(vdev->level_trace, "%s:%d  Exiting...", __func__,
-                            __LINE__);
-}
-
-static const struct pci_error_handlers vxge_err_handler = {
-       .error_detected = vxge_io_error_detected,
-       .slot_reset = vxge_io_slot_reset,
-       .resume = vxge_io_resume,
-};
-
-static SIMPLE_DEV_PM_OPS(vxge_pm_ops, vxge_pm_suspend, vxge_pm_resume);
-
-static struct pci_driver vxge_driver = {
-       .name = VXGE_DRIVER_NAME,
-       .id_table = vxge_id_table,
-       .probe = vxge_probe,
-       .remove = vxge_remove,
-       .driver.pm = &vxge_pm_ops,
-       .err_handler = &vxge_err_handler,
-};
-
-static int __init
-vxge_starter(void)
-{
-       int ret = 0;
-
-       pr_info("Copyright(c) 2002-2010 Exar Corp.\n");
-       pr_info("Driver version: %s\n", DRV_VERSION);
-
-       verify_bandwidth();
-
-       driver_config = kzalloc(sizeof(struct vxge_drv_config), GFP_KERNEL);
-       if (!driver_config)
-               return -ENOMEM;
-
-       ret = pci_register_driver(&vxge_driver);
-       if (ret) {
-               kfree(driver_config);
-               goto err;
-       }
-
-       if (driver_config->config_dev_cnt &&
-          (driver_config->config_dev_cnt != driver_config->total_dev_cnt))
-               vxge_debug_init(VXGE_ERR,
-                       "%s: Configured %d of %d devices",
-                       VXGE_DRIVER_NAME, driver_config->config_dev_cnt,
-                       driver_config->total_dev_cnt);
-err:
-       return ret;
-}
-
-static void __exit
-vxge_closer(void)
-{
-       pci_unregister_driver(&vxge_driver);
-       kfree(driver_config);
-}
-module_init(vxge_starter);
-module_exit(vxge_closer);
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.h b/drivers/net/ethernet/neterion/vxge/vxge-main.h
deleted file mode 100644 (file)
index da9d2c1..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-main.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *              Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#ifndef VXGE_MAIN_H
-#define VXGE_MAIN_H
-
-#include "vxge-traffic.h"
-#include "vxge-config.h"
-#include "vxge-version.h"
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <linux/if_vlan.h>
-
-#define VXGE_DRIVER_NAME               "vxge"
-#define VXGE_DRIVER_VENDOR             "Neterion, Inc"
-#define VXGE_DRIVER_FW_VERSION_MAJOR   1
-
-#define DRV_VERSION    VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\
-       VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\
-       VXGE_VERSION_FOR
-
-#define PCI_DEVICE_ID_TITAN_WIN                0x5733
-#define PCI_DEVICE_ID_TITAN_UNI                0x5833
-#define VXGE_HW_TITAN1_PCI_REVISION    1
-#define VXGE_HW_TITAN1A_PCI_REVISION   2
-
-#define        VXGE_USE_DEFAULT                0xffffffff
-#define VXGE_HW_VPATH_MSIX_ACTIVE      4
-#define VXGE_ALARM_MSIX_ID             2
-#define VXGE_HW_RXSYNC_FREQ_CNT                4
-#define VXGE_LL_WATCH_DOG_TIMEOUT      (15 * HZ)
-#define VXGE_LL_RX_COPY_THRESHOLD      256
-#define VXGE_DEF_FIFO_LENGTH           84
-
-#define NO_STEERING            0
-#define PORT_STEERING          0x1
-#define RTH_STEERING           0x2
-#define RX_TOS_STEERING                0x3
-#define RX_VLAN_STEERING       0x4
-#define RTH_BUCKET_SIZE                4
-
-#define        TX_PRIORITY_STEERING    1
-#define        TX_VLAN_STEERING        2
-#define        TX_PORT_STEERING        3
-#define        TX_MULTIQ_STEERING      4
-
-#define VXGE_HW_MAC_ADDR_LEARN_DEFAULT VXGE_HW_RTS_MAC_DISABLE
-
-#define VXGE_TTI_BTIMER_VAL 250000
-
-#define VXGE_TTI_LTIMER_VAL    1000
-#define VXGE_T1A_TTI_LTIMER_VAL        80
-#define VXGE_TTI_RTIMER_VAL    0
-#define VXGE_TTI_RTIMER_ADAPT_VAL      10
-#define VXGE_T1A_TTI_RTIMER_VAL        400
-#define VXGE_RTI_BTIMER_VAL    250
-#define VXGE_RTI_LTIMER_VAL    100
-#define VXGE_RTI_RTIMER_VAL    0
-#define VXGE_RTI_RTIMER_ADAPT_VAL      15
-#define VXGE_FIFO_INDICATE_MAX_PKTS    VXGE_DEF_FIFO_LENGTH
-#define VXGE_ISR_POLLING_CNT   8
-#define VXGE_MAX_CONFIG_DEV    0xFF
-#define VXGE_EXEC_MODE_DISABLE 0
-#define VXGE_EXEC_MODE_ENABLE  1
-#define VXGE_MAX_CONFIG_PORT   1
-#define VXGE_ALL_VID_DISABLE   0
-#define VXGE_ALL_VID_ENABLE    1
-#define VXGE_PAUSE_CTRL_DISABLE        0
-#define VXGE_PAUSE_CTRL_ENABLE 1
-
-#define TTI_TX_URANGE_A        5
-#define TTI_TX_URANGE_B        15
-#define TTI_TX_URANGE_C        40
-#define TTI_TX_UFC_A   5
-#define TTI_TX_UFC_B   40
-#define TTI_TX_UFC_C   60
-#define TTI_TX_UFC_D   100
-#define TTI_T1A_TX_UFC_A       30
-#define TTI_T1A_TX_UFC_B       80
-/* Slope - (max_mtu - min_mtu)/(max_mtu_ufc - min_mtu_ufc) */
-/* Slope - 93 */
-/* 60 - 9k Mtu, 140 - 1.5k mtu */
-#define TTI_T1A_TX_UFC_C(mtu)  (60 + ((VXGE_HW_MAX_MTU - mtu) / 93))
-
-/* Slope - 37 */
-/* 100 - 9k Mtu, 300 - 1.5k mtu */
-#define TTI_T1A_TX_UFC_D(mtu)  (100 + ((VXGE_HW_MAX_MTU - mtu) / 37))
-
-
-#define RTI_RX_URANGE_A                5
-#define RTI_RX_URANGE_B                15
-#define RTI_RX_URANGE_C                40
-#define RTI_T1A_RX_URANGE_A    1
-#define RTI_T1A_RX_URANGE_B    20
-#define RTI_T1A_RX_URANGE_C    50
-#define RTI_RX_UFC_A           1
-#define RTI_RX_UFC_B           5
-#define RTI_RX_UFC_C           10
-#define RTI_RX_UFC_D           15
-#define RTI_T1A_RX_UFC_B       20
-#define RTI_T1A_RX_UFC_C       50
-#define RTI_T1A_RX_UFC_D       60
-
-/*
- * The interrupt rate is maintained at 3k per second with the moderation
- * parameters for most traffic but not all. This is the maximum interrupt
- * count allowed per function with INTA or per vector in the case of
- * MSI-X in a 10 millisecond time period. Enabled only for Titan 1A.
- */
-#define VXGE_T1A_MAX_INTERRUPT_COUNT   100
-#define VXGE_T1A_MAX_TX_INTERRUPT_COUNT        200
-
-/* Milli secs timer period */
-#define VXGE_TIMER_DELAY               10000
-
-#define VXGE_LL_MAX_FRAME_SIZE(dev) ((dev)->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE)
-
-#define is_sriov(function_mode) \
-       ((function_mode == VXGE_HW_FUNCTION_MODE_SRIOV) || \
-       (function_mode == VXGE_HW_FUNCTION_MODE_SRIOV_8) || \
-       (function_mode == VXGE_HW_FUNCTION_MODE_SRIOV_4))
-
-enum vxge_reset_event {
-       /* reset events */
-       VXGE_LL_VPATH_RESET     = 0,
-       VXGE_LL_DEVICE_RESET    = 1,
-       VXGE_LL_FULL_RESET      = 2,
-       VXGE_LL_START_RESET     = 3,
-       VXGE_LL_COMPL_RESET     = 4
-};
-/* These flags represent the devices temporary state */
-enum vxge_device_state_t {
-__VXGE_STATE_RESET_CARD = 0,
-__VXGE_STATE_CARD_UP
-};
-
-enum vxge_mac_addr_state {
-       /* mac address states */
-       VXGE_LL_MAC_ADDR_IN_LIST        = 0,
-       VXGE_LL_MAC_ADDR_IN_DA_TABLE    = 1
-};
-
-struct vxge_drv_config {
-       int config_dev_cnt;
-       int total_dev_cnt;
-       int g_no_cpus;
-       unsigned int vpath_per_dev;
-};
-
-struct macInfo {
-       unsigned char macaddr[ETH_ALEN];
-       unsigned char macmask[ETH_ALEN];
-       unsigned int vpath_no;
-       enum vxge_mac_addr_state state;
-};
-
-struct vxge_config {
-       int             tx_pause_enable;
-       int             rx_pause_enable;
-       int             napi_weight;
-       int             intr_type;
-#define INTA   0
-#define MSI    1
-#define MSI_X  2
-
-       int             addr_learn_en;
-
-       u32             rth_steering:2,
-                       rth_algorithm:2,
-                       rth_hash_type_tcpipv4:1,
-                       rth_hash_type_ipv4:1,
-                       rth_hash_type_tcpipv6:1,
-                       rth_hash_type_ipv6:1,
-                       rth_hash_type_tcpipv6ex:1,
-                       rth_hash_type_ipv6ex:1,
-                       rth_bkt_sz:8;
-       int             rth_jhash_golden_ratio;
-       int             tx_steering_type;
-       int     fifo_indicate_max_pkts;
-       struct vxge_hw_device_hw_info device_hw_info;
-};
-
-struct vxge_msix_entry {
-       /* Mimicing the msix_entry struct of Kernel. */
-       u16 vector;
-       u16 entry;
-       u16 in_use;
-       void *arg;
-};
-
-/* Software Statistics */
-
-struct vxge_sw_stats {
-
-       /* Virtual Path */
-       unsigned long vpaths_open;
-       unsigned long vpath_open_fail;
-
-       /* Misc. */
-       unsigned long link_up;
-       unsigned long link_down;
-};
-
-struct vxge_mac_addrs {
-       struct list_head item;
-       u64 macaddr;
-       u64 macmask;
-       enum vxge_mac_addr_state state;
-};
-
-struct vxgedev;
-
-struct vxge_fifo_stats {
-       struct u64_stats_sync   syncp;
-       u64 tx_frms;
-       u64 tx_bytes;
-
-       unsigned long tx_errors;
-       unsigned long txd_not_free;
-       unsigned long txd_out_of_desc;
-       unsigned long pci_map_fail;
-};
-
-struct vxge_fifo {
-       struct net_device *ndev;
-       struct pci_dev *pdev;
-       struct __vxge_hw_fifo *handle;
-       struct netdev_queue *txq;
-
-       int tx_steering_type;
-       int indicate_max_pkts;
-
-       /* Adaptive interrupt moderation parameters used in T1A */
-       unsigned long interrupt_count;
-       unsigned long jiffies;
-
-       u32 tx_vector_no;
-       /* Tx stats */
-       struct vxge_fifo_stats stats;
-} ____cacheline_aligned;
-
-struct vxge_ring_stats {
-       struct u64_stats_sync syncp;
-       u64 rx_frms;
-       u64 rx_mcast;
-       u64 rx_bytes;
-
-       unsigned long rx_errors;
-       unsigned long rx_dropped;
-       unsigned long prev_rx_frms;
-       unsigned long pci_map_fail;
-       unsigned long skb_alloc_fail;
-};
-
-struct vxge_ring {
-       struct net_device       *ndev;
-       struct pci_dev          *pdev;
-       struct __vxge_hw_ring   *handle;
-       /* The vpath id maintained in the driver -
-        * 0 to 'maximum_vpaths_in_function - 1'
-        */
-       int driver_id;
-
-       /* Adaptive interrupt moderation parameters used in T1A */
-       unsigned long interrupt_count;
-       unsigned long jiffies;
-
-       /* copy of the flag indicating whether rx_hwts is to be used */
-       u32 rx_hwts:1;
-
-       int pkts_processed;
-       int budget;
-
-       struct napi_struct napi;
-       struct napi_struct *napi_p;
-
-#define VXGE_MAX_MAC_ADDR_COUNT                30
-
-       int vlan_tag_strip;
-       u32 rx_vector_no;
-       enum vxge_hw_status last_status;
-
-       /* Rx stats */
-       struct vxge_ring_stats stats;
-} ____cacheline_aligned;
-
-struct vxge_vpath {
-       struct vxge_fifo fifo;
-       struct vxge_ring ring;
-
-       struct __vxge_hw_vpath_handle *handle;
-
-       /* Actual vpath id for this vpath in the device - 0 to 16 */
-       int device_id;
-       int max_mac_addr_cnt;
-       int is_configured;
-       int is_open;
-       struct vxgedev *vdev;
-       u8 macaddr[ETH_ALEN];
-       u8 macmask[ETH_ALEN];
-
-#define VXGE_MAX_LEARN_MAC_ADDR_CNT    2048
-       /* mac addresses currently programmed into NIC */
-       u16 mac_addr_cnt;
-       u16 mcast_addr_cnt;
-       struct list_head mac_addr_list;
-
-       u32 level_err;
-       u32 level_trace;
-};
-#define VXGE_COPY_DEBUG_INFO_TO_LL(vdev, err, trace) { \
-       for (i = 0; i < vdev->no_of_vpath; i++) {               \
-               vdev->vpaths[i].level_err = err;                \
-               vdev->vpaths[i].level_trace = trace;            \
-       }                                                       \
-       vdev->level_err = err;                                  \
-       vdev->level_trace = trace;                              \
-}
-
-struct vxgedev {
-       struct net_device       *ndev;
-       struct pci_dev          *pdev;
-       struct __vxge_hw_device *devh;
-       unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
-       int vlan_tag_strip;
-       struct vxge_config      config;
-       unsigned long   state;
-
-       /* Indicates which vpath to reset */
-       unsigned long  vp_reset;
-
-       /* Timer used for polling vpath resets */
-       struct timer_list vp_reset_timer;
-
-       /* Timer used for polling vpath lockup */
-       struct timer_list vp_lockup_timer;
-
-       /*
-        * Flags to track whether device is in All Multicast
-        * or in promiscuous mode.
-        */
-       u16             all_multi_flg;
-
-       /* A flag indicating whether rx_hwts is to be used or not. */
-       u32     rx_hwts:1,
-               titan1:1;
-
-       struct vxge_msix_entry *vxge_entries;
-       struct msix_entry *entries;
-       /*
-        * 4 for each vpath * 17;
-        * total is 68
-        */
-#define        VXGE_MAX_REQUESTED_MSIX 68
-#define VXGE_INTR_STRLEN 80
-       char desc[VXGE_MAX_REQUESTED_MSIX][VXGE_INTR_STRLEN];
-
-       enum vxge_hw_event cric_err_event;
-
-       int max_vpath_supported;
-       int no_of_vpath;
-
-       struct napi_struct napi;
-       /* A debug option, when enabled and if error condition occurs,
-        * the driver will do following steps:
-        * - mask all interrupts
-        * - Not clear the source of the alarm
-        * - gracefully stop all I/O
-        * A diagnostic dump of register and stats at this point
-        * reveals very useful information.
-        */
-       int exec_mode;
-       int max_config_port;
-       struct vxge_vpath       *vpaths;
-
-       struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS];
-       void __iomem *bar0;
-       struct vxge_sw_stats    stats;
-       int             mtu;
-       /* Below variables are used for vpath selection to transmit a packet */
-       u8              vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS];
-       u64             vpaths_deployed;
-
-       u32             intr_cnt;
-       u32             level_err;
-       u32             level_trace;
-       char            fw_version[VXGE_HW_FW_STRLEN];
-       struct work_struct reset_task;
-};
-
-struct vxge_rx_priv {
-       struct sk_buff          *skb;
-       unsigned char           *skb_data;
-       dma_addr_t              data_dma;
-       dma_addr_t              data_size;
-};
-
-struct vxge_tx_priv {
-       struct sk_buff          *skb;
-       dma_addr_t              dma_buffers[MAX_SKB_FRAGS+1];
-};
-
-#define VXGE_MODULE_PARAM_INT(p, val) \
-       static int p = val; \
-       module_param(p, int, 0)
-
-static inline
-void vxge_os_timer(struct timer_list *timer, void (*func)(struct timer_list *),
-                  unsigned long timeout)
-{
-       timer_setup(timer, func, 0);
-       mod_timer(timer, jiffies + timeout);
-}
-
-void vxge_initialize_ethtool_ops(struct net_device *ndev);
-int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override);
-
-/* #define VXGE_DEBUG_INIT: debug for initialization functions
- * #define VXGE_DEBUG_TX        : debug transmit related functions
- * #define VXGE_DEBUG_RX  : debug recevice related functions
- * #define VXGE_DEBUG_MEM : debug memory module
- * #define VXGE_DEBUG_LOCK: debug locks
- * #define VXGE_DEBUG_SEM : debug semaphore
- * #define VXGE_DEBUG_ENTRYEXIT: debug functions by adding entry exit statements
-*/
-#define VXGE_DEBUG_INIT                0x00000001
-#define VXGE_DEBUG_TX          0x00000002
-#define VXGE_DEBUG_RX          0x00000004
-#define VXGE_DEBUG_MEM         0x00000008
-#define VXGE_DEBUG_LOCK                0x00000010
-#define VXGE_DEBUG_SEM         0x00000020
-#define VXGE_DEBUG_ENTRYEXIT   0x00000040
-#define VXGE_DEBUG_INTR                0x00000080
-#define VXGE_DEBUG_LL_CONFIG   0x00000100
-
-/* Debug tracing for VXGE driver */
-#ifndef VXGE_DEBUG_MASK
-#define VXGE_DEBUG_MASK        0x0
-#endif
-
-#if (VXGE_DEBUG_LL_CONFIG & VXGE_DEBUG_MASK)
-#define vxge_debug_ll_config(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_ll_config(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#if (VXGE_DEBUG_INIT & VXGE_DEBUG_MASK)
-#define vxge_debug_init(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_init(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#if (VXGE_DEBUG_TX & VXGE_DEBUG_MASK)
-#define vxge_debug_tx(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_tx(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#if (VXGE_DEBUG_RX & VXGE_DEBUG_MASK)
-#define vxge_debug_rx(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_rx(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#if (VXGE_DEBUG_MEM & VXGE_DEBUG_MASK)
-#define vxge_debug_mem(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_mem(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#if (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)
-#define vxge_debug_entryexit(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_entryexit(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#if (VXGE_DEBUG_INTR & VXGE_DEBUG_MASK)
-#define vxge_debug_intr(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, ##__VA_ARGS__)
-#else
-#define vxge_debug_intr(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
-#endif
-
-#define VXGE_DEVICE_DEBUG_LEVEL_SET(level, mask, vdev) {\
-       vxge_hw_device_debug_set((struct __vxge_hw_device  *)vdev->devh, \
-               level, mask);\
-       VXGE_COPY_DEBUG_INFO_TO_LL(vdev, \
-               vxge_hw_device_error_level_get((struct __vxge_hw_device  *) \
-                       vdev->devh), \
-               vxge_hw_device_trace_level_get((struct __vxge_hw_device  *) \
-                       vdev->devh));\
-}
-
-#ifdef NETIF_F_GSO
-#define vxge_tcp_mss(skb) (skb_shinfo(skb)->gso_size)
-#define vxge_udp_mss(skb) (skb_shinfo(skb)->gso_size)
-#define vxge_offload_type(skb) (skb_shinfo(skb)->gso_type)
-#endif
-
-#endif
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-reg.h b/drivers/net/ethernet/neterion/vxge/vxge-reg.h
deleted file mode 100644 (file)
index 3e658b1..0000000
+++ /dev/null
@@ -1,4636 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-reg.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O Virtualized
- *             Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#ifndef VXGE_REG_H
-#define VXGE_REG_H
-
-/*
- * vxge_mBIT(loc) - set bit at offset
- */
-#define vxge_mBIT(loc)         (0x8000000000000000ULL >> (loc))
-
-/*
- * vxge_vBIT(val, loc, sz) - set bits at offset
- */
-#define vxge_vBIT(val, loc, sz)        (((u64)(val)) << (64-(loc)-(sz)))
-#define vxge_vBIT32(val, loc, sz)      (((u32)(val)) << (32-(loc)-(sz)))
-
-/*
- * vxge_bVALn(bits, loc, n) - Get the value of n bits at location
- */
-#define vxge_bVALn(bits, loc, n) \
-       ((((u64)bits) >> (64-(loc+n))) & ((0x1ULL << n) - 1))
-
-#define        VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(bits) \
-                                                       vxge_bVALn(bits, 0, 16)
-#define        VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(bits) \
-                                                       vxge_bVALn(bits, 48, 8)
-#define        VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(bits) \
-                                                       vxge_bVALn(bits, 56, 8)
-
-#define        VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(bits) \
-                                                       vxge_bVALn(bits, 3, 5)
-#define        VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(bits) \
-                                                       vxge_bVALn(bits, 5, 3)
-#define VXGE_HW_PF_SW_RESET_COMMAND                            0xA5
-
-#define VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES            17
-#define VXGE_HW_TITAN_SRPCIM_REG_SPACES                        17
-#define VXGE_HW_TITAN_VPMGMT_REG_SPACES                        17
-#define VXGE_HW_TITAN_VPATH_REG_SPACES                 17
-
-#define VXGE_HW_FW_API_GET_EPROM_REV                   31
-
-#define VXGE_EPROM_IMG_MAJOR(val)              (u32) vxge_bVALn(val, 48, 4)
-#define VXGE_EPROM_IMG_MINOR(val)              (u32) vxge_bVALn(val, 52, 4)
-#define VXGE_EPROM_IMG_FIX(val)                        (u32) vxge_bVALn(val, 56, 4)
-#define VXGE_EPROM_IMG_BUILD(val)              (u32) vxge_bVALn(val, 60, 4)
-
-#define VXGE_HW_GET_EPROM_IMAGE_INDEX(val)             vxge_bVALn(val, 16, 8)
-#define VXGE_HW_GET_EPROM_IMAGE_VALID(val)             vxge_bVALn(val, 31, 1)
-#define VXGE_HW_GET_EPROM_IMAGE_TYPE(val)              vxge_bVALn(val, 40, 8)
-#define VXGE_HW_GET_EPROM_IMAGE_REV(val)               vxge_bVALn(val, 48, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(val)  vxge_vBIT(val, 16, 8)
-
-#define VXGE_HW_FW_API_GET_FUNC_MODE                   29
-#define VXGE_HW_GET_FUNC_MODE_VAL(val)                 (val & 0xFF)
-
-#define VXGE_HW_FW_UPGRADE_MEMO                                13
-#define VXGE_HW_FW_UPGRADE_ACTION                      16
-#define VXGE_HW_FW_UPGRADE_OFFSET_START                        2
-#define VXGE_HW_FW_UPGRADE_OFFSET_SEND                 3
-#define VXGE_HW_FW_UPGRADE_OFFSET_COMMIT               4
-#define VXGE_HW_FW_UPGRADE_OFFSET_READ                 5
-
-#define VXGE_HW_FW_UPGRADE_BLK_SIZE                    16
-#define VXGE_HW_UPGRADE_GET_RET_ERR_CODE(val)          (val & 0xff)
-#define VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(val)          ((val >> 8) & 0xff)
-
-#define VXGE_HW_ASIC_MODE_RESERVED                             0
-#define VXGE_HW_ASIC_MODE_NO_IOV                               1
-#define VXGE_HW_ASIC_MODE_SR_IOV                               2
-#define VXGE_HW_ASIC_MODE_MR_IOV                               3
-
-#define        VXGE_HW_TXMAC_GEN_CFG1_TMAC_PERMA_STOP_EN               vxge_mBIT(3)
-#define        VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_WIRE              vxge_mBIT(19)
-#define        VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_SWITCH    vxge_mBIT(23)
-#define        VXGE_HW_TXMAC_GEN_CFG1_HOST_APPEND_FCS                  vxge_mBIT(31)
-
-#define        VXGE_HW_VPATH_IS_FIRST_GET_VPATH_IS_FIRST(bits) vxge_bVALn(bits, 3, 1)
-
-#define        VXGE_HW_TIM_VPATH_ASSIGNMENT_GET_BMAP_ROOT(bits) \
-                                               vxge_bVALn(bits, 0, 32)
-
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN(bits) \
-                                                       vxge_bVALn(bits, 50, 14)
-
-#define        VXGE_HW_XMAC_VSPORT_CHOICES_VP_GET_VSPORT_VECTOR(bits) \
-                                                       vxge_bVALn(bits, 0, 17)
-
-#define        VXGE_HW_XMAC_VPATH_TO_VSPORT_VPMGMT_CLONE_GET_VSPORT_NUMBER(bits) \
-                                                       vxge_bVALn(bits, 3, 5)
-
-#define        VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(bits) \
-                                                       vxge_bVALn(bits, 17, 15)
-
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_LEGACY_MODE                 0
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY            1
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_MULTI_OP_MODE               2
-
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MESSAGES_ONLY               0
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MULTI_OP_MODE               1
-
-#define        VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val) \
-                               (val&~VXGE_HW_TOC_KDFC_INITIAL_BIR(7))
-#define        VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val) \
-                               vxge_bVALn(val, 61, 3)
-#define        VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val) \
-                               (val&~VXGE_HW_TOC_USDC_INITIAL_BIR(7))
-#define        VXGE_HW_TOC_GET_USDC_INITIAL_BIR(val) \
-                               vxge_bVALn(val, 61, 3)
-
-#define        VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(bits)   bits
-#define        VXGE_HW_TOC_KDFC_FIFO_STRIDE_GET_TOC_KDFC_FIFO_STRIDE(bits)     bits
-
-#define        VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR0(bits) \
-                                               vxge_bVALn(bits, 1, 15)
-#define        VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR1(bits) \
-                                               vxge_bVALn(bits, 17, 15)
-#define        VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR2(bits) \
-                                               vxge_bVALn(bits, 33, 15)
-
-#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_VAPTH_NUM(val) vxge_vBIT(val, 42, 5)
-#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_NUM(val) vxge_vBIT(val, 47, 2)
-#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_OFFSET(val) \
-                                       vxge_vBIT(val, 49, 15)
-
-#define VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER                  0
-#define VXGE_HW_PRC_CFG4_RING_MODE_THREE_BUFFER                        1
-#define VXGE_HW_PRC_CFG4_RING_MODE_FIVE_BUFFER                 2
-
-#define VXGE_HW_PRC_CFG7_SCATTER_MODE_A                                0
-#define VXGE_HW_PRC_CFG7_SCATTER_MODE_B                                2
-#define VXGE_HW_PRC_CFG7_SCATTER_MODE_C                                1
-
-#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_READ                             0
-#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_WRITE                            1
-
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DA                  0
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_VID                 1
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_ETYPE               2
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_PN                  3
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RANGE_PN            4
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG         5
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT         6
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG       7
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK            8
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY             9
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_QOS                 10
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DS                  11
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT        12
-#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_FW_VERSION          13
-
-#define VXGE_HW_RTS_MGR_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
-                                                       vxge_bVALn(bits, 0, 48)
-#define VXGE_HW_RTS_MGR_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
-
-#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \
-                                                       vxge_bVALn(bits, 0, 48)
-#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MASK(val) vxge_vBIT(val, 0, 48)
-#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_PRIVILEGED_MODE \
-                                                               vxge_mBIT(54)
-#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_VPATH(bits) \
-                                                       vxge_bVALn(bits, 55, 5)
-#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_VPATH(val) \
-                                                       vxge_vBIT(val, 55, 5)
-#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_MODE(bits) \
-                                                       vxge_bVALn(bits, 62, 2)
-#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MODE(val) vxge_vBIT(val, 62, 2)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY                  0
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY               1
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY           2
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY            3
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY                 0
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY                1
-#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY           3
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL                4
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ALL_CLEAR                  172
-
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA                0
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID               1
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_ETYPE             2
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_PN                3
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG       5
-#define        VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT          6
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG     7
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK          8
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY           9
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_QOS               10
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DS                11
-#define        VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT         12
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO           13
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(bits) \
-                                                       vxge_bVALn(bits, 0, 48)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(bits) vxge_bVALn(bits, 0, 12)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(val) vxge_vBIT(val, 0, 12)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_ETYPE(bits)  vxge_bVALn(bits, 0, 11)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_ETYPE(val) vxge_vBIT(val, 0, 16)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_SRC_DEST_SEL(bits) \
-                                                       vxge_bVALn(bits, 3, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_SRC_DEST_SEL          vxge_mBIT(3)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_TCP_UDP_SEL(bits) \
-                                                       vxge_bVALn(bits, 7, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_TCP_UDP_SEL           vxge_mBIT(7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_PORT_NUM(bits) \
-                                                       vxge_bVALn(bits, 8, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_PORT_NUM(val) vxge_vBIT(val, 8, 16)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_EN(bits) \
-                                                       vxge_bVALn(bits, 3, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN           vxge_mBIT(3)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_BUCKET_SIZE(bits) \
-                                                       vxge_bVALn(bits, 4, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(val) \
-                                                       vxge_vBIT(val, 4, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ALG_SEL(bits) \
-                                                       vxge_bVALn(bits, 10, 2)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(val) \
-                                                       vxge_vBIT(val, 10, 2)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_JENKINS  0
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_MS_RSS   1
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_CRC32C   2
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV4_EN(bits) \
-                                                       vxge_bVALn(bits, 15, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN  vxge_mBIT(15)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV4_EN(bits) \
-                                                       vxge_bVALn(bits, 19, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN      vxge_mBIT(19)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EN(bits) \
-                                                       vxge_bVALn(bits, 23, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN  vxge_mBIT(23)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EN(bits) \
-                                                       vxge_bVALn(bits, 27, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN      vxge_mBIT(27)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EX_EN(bits) \
-                                                       vxge_bVALn(bits, 31, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN vxge_mBIT(31)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EX_EN(bits) \
-                                                       vxge_bVALn(bits, 35, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN   vxge_mBIT(35)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(bits) \
-                                                       vxge_bVALn(bits, 39, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE     vxge_mBIT(39)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_REPL_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 43, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_REPL_ENTRY_EN    vxge_mBIT(43)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 3, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN     vxge_mBIT(3)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 9, 7)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 0, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 0, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 8, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN       vxge_mBIT(8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 16, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 16, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 24, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN       vxge_mBIT(24)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 25, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 25, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 0, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 0, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 8, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN       vxge_mBIT(8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 16, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 16, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 24, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN       vxge_mBIT(24)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 25, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 25, 7)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_GOLDEN_RATIO(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_GOLDEN_RATIO(val) \
-                                                       vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_INIT_VALUE(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_INIT_VALUE(val) \
-                                                       vxge_vBIT(val, 32, 32)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_SA_MASK(bits) \
-                                                       vxge_bVALn(bits, 0, 16)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_SA_MASK(val) \
-                                                       vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_DA_MASK(bits) \
-                                                       vxge_bVALn(bits, 16, 16)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_DA_MASK(val) \
-                                                       vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_SA_MASK(bits) \
-                                                       vxge_bVALn(bits, 32, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_SA_MASK(val) \
-                                                       vxge_vBIT(val, 32, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_DA_MASK(bits) \
-                                                       vxge_bVALn(bits, 36, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_DA_MASK(val) \
-                                                       vxge_vBIT(val, 36, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4SP_MASK(bits) \
-                                                       vxge_bVALn(bits, 40, 2)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4SP_MASK(val) \
-                                                       vxge_vBIT(val, 40, 2)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4DP_MASK(bits) \
-                                                       vxge_bVALn(bits, 42, 2)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4DP_MASK(val) \
-                                                       vxge_vBIT(val, 42, 2)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_KEY_KEY(bits) \
-                                                       vxge_bVALn(bits, 0, 64)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_KEY_KEY vxge_vBIT(val, 0, 64)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_QOS_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 3, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_QOS_ENTRY_EN             vxge_mBIT(3)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DS_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 3, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_DS_ENTRY_EN              vxge_mBIT(3)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \
-                                                       vxge_bVALn(bits, 0, 48)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(val) \
-                                                       vxge_vBIT(val, 0, 48)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(val) \
-                                                       vxge_vBIT(val, 62, 2)
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 0, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 0, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 8, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_ENTRY_EN       vxge_mBIT(8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 9, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 16, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 16, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 24, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_ENTRY_EN       vxge_mBIT(24)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 25, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 25, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 32, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 32, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 40, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_ENTRY_EN       vxge_mBIT(40)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 41, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 41, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_NUM(bits) \
-                                                       vxge_bVALn(bits, 48, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_NUM(val) \
-                                                       vxge_vBIT(val, 48, 8)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_ENTRY_EN(bits) \
-                                                       vxge_bVALn(bits, 56, 1)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_ENTRY_EN       vxge_mBIT(56)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_DATA(bits) \
-                                                       vxge_bVALn(bits, 57, 7)
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_DATA(val) \
-                                                       vxge_vBIT(val, 57, 7)
-
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER           0
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER         1
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_VERSION               2
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE              3
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0                4
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_1                5
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_2                6
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3                7
-
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_ON                   1
-#define        VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_OFF                  0
-
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(bits) \
-                                                       vxge_bVALn(bits, 0, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_DAY(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(bits) \
-                                                       vxge_bVALn(bits, 8, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MONTH(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(bits) \
-                                               vxge_bVALn(bits, 16, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_YEAR(val) \
-                                                       vxge_vBIT(val, 16, 16)
-
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(bits) \
-                                               vxge_bVALn(bits, 32, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MAJOR vxge_vBIT(val, 32, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(bits) \
-                                               vxge_bVALn(bits, 40, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MINOR vxge_vBIT(val, 40, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(bits) \
-                                               vxge_bVALn(bits, 48, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_BUILD vxge_vBIT(val, 48, 16)
-
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(bits) \
-                                               vxge_bVALn(bits, 0, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_DAY(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(bits) \
-                                                       vxge_bVALn(bits, 8, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MONTH(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(bits) \
-                                                       vxge_bVALn(bits, 16, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_YEAR(val) \
-                                                       vxge_vBIT(val, 16, 16)
-
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(bits) \
-                                                       vxge_bVALn(bits, 32, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MAJOR vxge_vBIT(val, 32, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(bits) \
-                                                       vxge_bVALn(bits, 40, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MINOR vxge_vBIT(val, 40, 8)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(bits) \
-                                                       vxge_bVALn(bits, 48, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_BUILD vxge_vBIT(val, 48, 16)
-#define VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(bits) vxge_bVALn(bits, 0, 8)
-
-#define        VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_GET_PPIF_SRPCIM_TO_VPATH_ALARM(bits)\
-                                                       vxge_bVALn(bits, 0, 18)
-
-#define        VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(bits) \
-                                                       vxge_bVALn(bits, 48, 16)
-#define        VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(bits)     vxge_bVALn(bits, 48, 16)
-#define        VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(bits)      (bits)
-#define        VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(bits)      (bits)
-#define        VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(bits\
-) vxge_bVALn(bits, 48, 16)
-#define        VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(bits) vxge_bVALn(bits, 0, 16)
-#define        VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(bits) \
-                                                       vxge_bVALn(bits, 16, 16)
-#define        VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(bits) \
-                                                       vxge_bVALn(bits, 32, 16)
-#define        VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(bits)  vxge_bVALn(bits, 0, 16)
-#define        VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(bits) \
-                                                       vxge_bVALn(bits, 16, 16)
-#define        VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(bits) \
-                                                       vxge_bVALn(bits, 32, 16)
-
-#define        VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_WR_DROP(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_RD_DROP(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_MRPCIM_DEBUG_STATS1_GET_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(bits\
-) vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_MRPCIM_DEBUG_STATS2_GET_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(bits\
-) vxge_bVALn(bits, 32, 32)
-#define \
-VXGE_HW_MRPCIM_DEBUG_STATS3_GET_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(bits) \
-       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_WR_VPIN_DROP(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_RD_VPIN_DROP(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT1(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT0(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT3(bits) \
-                                                       vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT2(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_GENSTATS_COUNT4_GET_GENSTATS_COUNT4(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_GENSTATS_COUNT5_GET_GENSTATS_COUNT5(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-
-#define        VXGE_HW_DEBUG_STATS0_GET_RSTDROP_MSG(bits)      vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_DEBUG_STATS0_GET_RSTDROP_CPL(bits)      vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT0(bits)  vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT1(bits)  vxge_bVALn(bits, 32, 32)
-#define        VXGE_HW_DEBUG_STATS2_GET_RSTDROP_CLIENT2(bits)  vxge_bVALn(bits, 0, 32)
-#define        VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_PH(bits)   vxge_bVALn(bits, 0, 16)
-#define        VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_NPH(bits)  vxge_bVALn(bits, 16, 16)
-#define        VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_CPLH(bits) vxge_bVALn(bits, 32, 16)
-#define        VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_PD(bits)   vxge_bVALn(bits, 0, 16)
-#define        VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_NPD(bits)  bVAL(bits, 16, 16)
-#define        VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_CPLD(bits) vxge_bVALn(bits, 32, 16)
-
-#define        VXGE_HW_DBG_STATS_TPA_TX_PATH_GET_TX_PERMITTED_FRMS(bits) \
-                                                       vxge_bVALn(bits, 32, 32)
-
-#define        VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT0_TX_ANY_FRMS(bits) \
-                                                       vxge_bVALn(bits, 0, 8)
-#define        VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT1_TX_ANY_FRMS(bits) \
-                                                       vxge_bVALn(bits, 8, 8)
-#define        VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT2_TX_ANY_FRMS(bits) \
-                                                       vxge_bVALn(bits, 16, 8)
-
-#define        VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT0_RX_ANY_FRMS(bits) \
-                                                       vxge_bVALn(bits, 0, 8)
-#define        VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT1_RX_ANY_FRMS(bits) \
-                                                       vxge_bVALn(bits, 8, 8)
-#define        VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT2_RX_ANY_FRMS(bits) \
-                                                       vxge_bVALn(bits, 16, 8)
-
-#define VXGE_HW_CONFIG_PRIV_H
-
-#define VXGE_HW_SWAPPER_INITIAL_VALUE                  0x0123456789abcdefULL
-#define VXGE_HW_SWAPPER_BYTE_SWAPPED                   0xefcdab8967452301ULL
-#define VXGE_HW_SWAPPER_BIT_FLIPPED                    0x80c4a2e691d5b3f7ULL
-#define VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED       0xf7b3d591e6a2c480ULL
-
-#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE          0xFFFFFFFFFFFFFFFFULL
-#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_DISABLE         0x0000000000000000ULL
-
-#define VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE           0xFFFFFFFFFFFFFFFFULL
-#define VXGE_HW_SWAPPER_READ_BIT_FLAP_DISABLE          0x0000000000000000ULL
-
-#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE         0xFFFFFFFFFFFFFFFFULL
-#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_DISABLE                0x0000000000000000ULL
-
-#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE          0xFFFFFFFFFFFFFFFFULL
-#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_DISABLE         0x0000000000000000ULL
-
-/*
- * The registers are memory mapped and are native big-endian byte order. The
- * little-endian hosts are handled by enabling hardware byte-swapping for
- * register and dma operations.
- */
-struct vxge_hw_legacy_reg {
-
-       u8      unused00010[0x00010];
-
-/*0x00010*/    u64     toc_swapper_fb;
-#define VXGE_HW_TOC_SWAPPER_FB_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-/*0x00018*/    u64     pifm_rd_swap_en;
-#define VXGE_HW_PIFM_RD_SWAP_EN_PIFM_RD_SWAP_EN(val) vxge_vBIT(val, 0, 64)
-/*0x00020*/    u64     pifm_rd_flip_en;
-#define VXGE_HW_PIFM_RD_FLIP_EN_PIFM_RD_FLIP_EN(val) vxge_vBIT(val, 0, 64)
-/*0x00028*/    u64     pifm_wr_swap_en;
-#define VXGE_HW_PIFM_WR_SWAP_EN_PIFM_WR_SWAP_EN(val) vxge_vBIT(val, 0, 64)
-/*0x00030*/    u64     pifm_wr_flip_en;
-#define VXGE_HW_PIFM_WR_FLIP_EN_PIFM_WR_FLIP_EN(val) vxge_vBIT(val, 0, 64)
-/*0x00038*/    u64     toc_first_pointer;
-#define VXGE_HW_TOC_FIRST_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-/*0x00040*/    u64     host_access_en;
-#define VXGE_HW_HOST_ACCESS_EN_HOST_ACCESS_EN(val) vxge_vBIT(val, 0, 64)
-
-} __packed;
-
-struct vxge_hw_toc_reg {
-
-       u8      unused00050[0x00050];
-
-/*0x00050*/    u64     toc_common_pointer;
-#define VXGE_HW_TOC_COMMON_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-/*0x00058*/    u64     toc_memrepair_pointer;
-#define VXGE_HW_TOC_MEMREPAIR_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-/*0x00060*/    u64     toc_pcicfgmgmt_pointer[17];
-#define VXGE_HW_TOC_PCICFGMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-       u8      unused001e0[0x001e0-0x000e8];
-
-/*0x001e0*/    u64     toc_mrpcim_pointer;
-#define VXGE_HW_TOC_MRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-/*0x001e8*/    u64     toc_srpcim_pointer[17];
-#define VXGE_HW_TOC_SRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-       u8      unused00278[0x00278-0x00270];
-
-/*0x00278*/    u64     toc_vpmgmt_pointer[17];
-#define VXGE_HW_TOC_VPMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-       u8      unused00390[0x00390-0x00300];
-
-/*0x00390*/    u64     toc_vpath_pointer[17];
-#define VXGE_HW_TOC_VPATH_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64)
-       u8      unused004a0[0x004a0-0x00418];
-
-/*0x004a0*/    u64     toc_kdfc;
-#define VXGE_HW_TOC_KDFC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61)
-#define VXGE_HW_TOC_KDFC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3)
-/*0x004a8*/    u64     toc_usdc;
-#define VXGE_HW_TOC_USDC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61)
-#define VXGE_HW_TOC_USDC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3)
-/*0x004b0*/    u64     toc_kdfc_vpath_stride;
-#define        VXGE_HW_TOC_KDFC_VPATH_STRIDE_INITIAL_TOC_KDFC_VPATH_STRIDE(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x004b8*/    u64     toc_kdfc_fifo_stride;
-#define        VXGE_HW_TOC_KDFC_FIFO_STRIDE_INITIAL_TOC_KDFC_FIFO_STRIDE(val) \
-                                                       vxge_vBIT(val, 0, 64)
-
-} __packed;
-
-struct vxge_hw_common_reg {
-
-       u8      unused00a00[0x00a00];
-
-/*0x00a00*/    u64     prc_status1;
-#define VXGE_HW_PRC_STATUS1_PRC_VP_QUIESCENT(n)        vxge_mBIT(n)
-/*0x00a08*/    u64     rxdcm_reset_in_progress;
-#define VXGE_HW_RXDCM_RESET_IN_PROGRESS_PRC_VP(n)      vxge_mBIT(n)
-/*0x00a10*/    u64     replicq_flush_in_progress;
-#define VXGE_HW_REPLICQ_FLUSH_IN_PROGRESS_NOA_VP(n)    vxge_mBIT(n)
-/*0x00a18*/    u64     rxpe_cmds_reset_in_progress;
-#define VXGE_HW_RXPE_CMDS_RESET_IN_PROGRESS_NOA_VP(n)  vxge_mBIT(n)
-/*0x00a20*/    u64     mxp_cmds_reset_in_progress;
-#define VXGE_HW_MXP_CMDS_RESET_IN_PROGRESS_NOA_VP(n)   vxge_mBIT(n)
-/*0x00a28*/    u64     noffload_reset_in_progress;
-#define VXGE_HW_NOFFLOAD_RESET_IN_PROGRESS_PRC_VP(n)   vxge_mBIT(n)
-/*0x00a30*/    u64     rd_req_in_progress;
-#define VXGE_HW_RD_REQ_IN_PROGRESS_VP(n)       vxge_mBIT(n)
-/*0x00a38*/    u64     rd_req_outstanding;
-#define VXGE_HW_RD_REQ_OUTSTANDING_VP(n)       vxge_mBIT(n)
-/*0x00a40*/    u64     kdfc_reset_in_progress;
-#define VXGE_HW_KDFC_RESET_IN_PROGRESS_NOA_VP(n)       vxge_mBIT(n)
-       u8      unused00b00[0x00b00-0x00a48];
-
-/*0x00b00*/    u64     one_cfg_vp;
-#define VXGE_HW_ONE_CFG_VP_RDY(n)      vxge_mBIT(n)
-/*0x00b08*/    u64     one_common;
-#define VXGE_HW_ONE_COMMON_PET_VPATH_RESET_IN_PROGRESS(n)      vxge_mBIT(n)
-       u8      unused00b80[0x00b80-0x00b10];
-
-/*0x00b80*/    u64     tim_int_en;
-#define VXGE_HW_TIM_INT_EN_TIM_VP(n)   vxge_mBIT(n)
-/*0x00b88*/    u64     tim_set_int_en;
-#define VXGE_HW_TIM_SET_INT_EN_VP(n)   vxge_mBIT(n)
-/*0x00b90*/    u64     tim_clr_int_en;
-#define VXGE_HW_TIM_CLR_INT_EN_VP(n)   vxge_mBIT(n)
-/*0x00b98*/    u64     tim_mask_int_during_reset;
-#define VXGE_HW_TIM_MASK_INT_DURING_RESET_VPATH(n)     vxge_mBIT(n)
-/*0x00ba0*/    u64     tim_reset_in_progress;
-#define VXGE_HW_TIM_RESET_IN_PROGRESS_TIM_VPATH(n)     vxge_mBIT(n)
-/*0x00ba8*/    u64     tim_outstanding_bmap;
-#define VXGE_HW_TIM_OUTSTANDING_BMAP_TIM_VPATH(n)      vxge_mBIT(n)
-       u8      unused00c00[0x00c00-0x00bb0];
-
-/*0x00c00*/    u64     msg_reset_in_progress;
-#define VXGE_HW_MSG_RESET_IN_PROGRESS_MSG_COMPOSITE(val) vxge_vBIT(val, 0, 17)
-/*0x00c08*/    u64     msg_mxp_mr_ready;
-#define VXGE_HW_MSG_MXP_MR_READY_MP_BOOTED(n)  vxge_mBIT(n)
-/*0x00c10*/    u64     msg_uxp_mr_ready;
-#define VXGE_HW_MSG_UXP_MR_READY_UP_BOOTED(n)  vxge_mBIT(n)
-/*0x00c18*/    u64     msg_dmq_noni_rtl_prefetch;
-#define VXGE_HW_MSG_DMQ_NONI_RTL_PREFETCH_BYPASS_ENABLE(n)     vxge_mBIT(n)
-/*0x00c20*/    u64     msg_umq_rtl_bwr;
-#define VXGE_HW_MSG_UMQ_RTL_BWR_PREFETCH_DISABLE(n)    vxge_mBIT(n)
-       u8      unused00d00[0x00d00-0x00c28];
-
-/*0x00d00*/    u64     cmn_rsthdlr_cfg0;
-#define VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(val) vxge_vBIT(val, 0, 17)
-/*0x00d08*/    u64     cmn_rsthdlr_cfg1;
-#define VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(val) vxge_vBIT(val, 0, 17)
-/*0x00d10*/    u64     cmn_rsthdlr_cfg2;
-#define VXGE_HW_CMN_RSTHDLR_CFG2_SW_RESET_FIFO0(val) vxge_vBIT(val, 0, 17)
-/*0x00d18*/    u64     cmn_rsthdlr_cfg3;
-#define VXGE_HW_CMN_RSTHDLR_CFG3_SW_RESET_FIFO1(val) vxge_vBIT(val, 0, 17)
-/*0x00d20*/    u64     cmn_rsthdlr_cfg4;
-#define VXGE_HW_CMN_RSTHDLR_CFG4_SW_RESET_FIFO2(val) vxge_vBIT(val, 0, 17)
-       u8      unused00d40[0x00d40-0x00d28];
-
-/*0x00d40*/    u64     cmn_rsthdlr_cfg8;
-#define VXGE_HW_CMN_RSTHDLR_CFG8_INCR_VPATH_INST_NUM(val) vxge_vBIT(val, 0, 17)
-/*0x00d48*/    u64     stats_cfg0;
-#define VXGE_HW_STATS_CFG0_STATS_ENABLE(val) vxge_vBIT(val, 0, 17)
-       u8      unused00da8[0x00da8-0x00d50];
-
-/*0x00da8*/    u64     clear_msix_mask_vect[4];
-#define VXGE_HW_CLEAR_MSIX_MASK_VECT_CLEAR_MSIX_MASK_VECT(val) \
-                                               vxge_vBIT(val, 0, 17)
-/*0x00dc8*/    u64     set_msix_mask_vect[4];
-#define VXGE_HW_SET_MSIX_MASK_VECT_SET_MSIX_MASK_VECT(val) vxge_vBIT(val, 0, 17)
-/*0x00de8*/    u64     clear_msix_mask_all_vect;
-#define        VXGE_HW_CLEAR_MSIX_MASK_ALL_VECT_CLEAR_MSIX_MASK_ALL_VECT(val)  \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x00df0*/    u64     set_msix_mask_all_vect;
-#define        VXGE_HW_SET_MSIX_MASK_ALL_VECT_SET_MSIX_MASK_ALL_VECT(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x00df8*/    u64     mask_vector[4];
-#define VXGE_HW_MASK_VECTOR_MASK_VECTOR(val) vxge_vBIT(val, 0, 17)
-/*0x00e18*/    u64     msix_pending_vector[4];
-#define VXGE_HW_MSIX_PENDING_VECTOR_MSIX_PENDING_VECTOR(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x00e38*/    u64     clr_msix_one_shot_vec[4];
-#define        VXGE_HW_CLR_MSIX_ONE_SHOT_VEC_CLR_MSIX_ONE_SHOT_VEC(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x00e58*/    u64     titan_asic_id;
-#define VXGE_HW_TITAN_ASIC_ID_INITIAL_DEVICE_ID(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MAJOR_REVISION(val) vxge_vBIT(val, 48, 8)
-#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MINOR_REVISION(val) vxge_vBIT(val, 56, 8)
-/*0x00e60*/    u64     titan_general_int_status;
-#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_MRPCIM_ALARM_INT       vxge_mBIT(0)
-#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_SRPCIM_ALARM_INT       vxge_mBIT(1)
-#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT        vxge_mBIT(2)
-#define        VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(val) \
-                                                       vxge_vBIT(val, 3, 17)
-       u8      unused00e70[0x00e70-0x00e68];
-
-/*0x00e70*/    u64     titan_mask_all_int;
-#define        VXGE_HW_TITAN_MASK_ALL_INT_ALARM        vxge_mBIT(7)
-#define        VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC      vxge_mBIT(15)
-       u8      unused00e80[0x00e80-0x00e78];
-
-/*0x00e80*/    u64     tim_int_status0;
-#define VXGE_HW_TIM_INT_STATUS0_TIM_INT_STATUS0(val) vxge_vBIT(val, 0, 64)
-/*0x00e88*/    u64     tim_int_mask0;
-#define VXGE_HW_TIM_INT_MASK0_TIM_INT_MASK0(val) vxge_vBIT(val, 0, 64)
-/*0x00e90*/    u64     tim_int_status1;
-#define VXGE_HW_TIM_INT_STATUS1_TIM_INT_STATUS1(val) vxge_vBIT(val, 0, 4)
-/*0x00e98*/    u64     tim_int_mask1;
-#define VXGE_HW_TIM_INT_MASK1_TIM_INT_MASK1(val) vxge_vBIT(val, 0, 4)
-/*0x00ea0*/    u64     rti_int_status;
-#define VXGE_HW_RTI_INT_STATUS_RTI_INT_STATUS(val) vxge_vBIT(val, 0, 17)
-/*0x00ea8*/    u64     rti_int_mask;
-#define VXGE_HW_RTI_INT_MASK_RTI_INT_MASK(val) vxge_vBIT(val, 0, 17)
-/*0x00eb0*/    u64     adapter_status;
-#define        VXGE_HW_ADAPTER_STATUS_RTDMA_RTDMA_READY        vxge_mBIT(0)
-#define        VXGE_HW_ADAPTER_STATUS_WRDMA_WRDMA_READY        vxge_mBIT(1)
-#define        VXGE_HW_ADAPTER_STATUS_KDFC_KDFC_READY  vxge_mBIT(2)
-#define        VXGE_HW_ADAPTER_STATUS_TPA_TMAC_BUF_EMPTY       vxge_mBIT(3)
-#define        VXGE_HW_ADAPTER_STATUS_RDCTL_PIC_QUIESCENT      vxge_mBIT(4)
-#define        VXGE_HW_ADAPTER_STATUS_XGMAC_NETWORK_FAULT      vxge_mBIT(5)
-#define        VXGE_HW_ADAPTER_STATUS_ROCRC_OFFLOAD_QUIESCENT  vxge_mBIT(6)
-#define        VXGE_HW_ADAPTER_STATUS_G3IF_FB_G3IF_FB_GDDR3_READY      vxge_mBIT(7)
-#define        VXGE_HW_ADAPTER_STATUS_G3IF_CM_G3IF_CM_GDDR3_READY      vxge_mBIT(8)
-#define        VXGE_HW_ADAPTER_STATUS_RIC_RIC_RUNNING  vxge_mBIT(9)
-#define        VXGE_HW_ADAPTER_STATUS_CMG_C_PLL_IN_LOCK        vxge_mBIT(10)
-#define        VXGE_HW_ADAPTER_STATUS_XGMAC_X_PLL_IN_LOCK      vxge_mBIT(11)
-#define        VXGE_HW_ADAPTER_STATUS_FBIF_M_PLL_IN_LOCK       vxge_mBIT(12)
-#define VXGE_HW_ADAPTER_STATUS_PCC_PCC_IDLE(val) vxge_vBIT(val, 24, 8)
-#define VXGE_HW_ADAPTER_STATUS_ROCRC_RC_PRC_QUIESCENT(val) vxge_vBIT(val, 44, 8)
-/*0x00eb8*/    u64     gen_ctrl;
-#define        VXGE_HW_GEN_CTRL_SPI_MRPCIM_WR_DIS      vxge_mBIT(0)
-#define        VXGE_HW_GEN_CTRL_SPI_MRPCIM_RD_DIS      vxge_mBIT(1)
-#define        VXGE_HW_GEN_CTRL_SPI_SRPCIM_WR_DIS      vxge_mBIT(2)
-#define        VXGE_HW_GEN_CTRL_SPI_SRPCIM_RD_DIS      vxge_mBIT(3)
-#define        VXGE_HW_GEN_CTRL_SPI_DEBUG_DIS  vxge_mBIT(4)
-#define        VXGE_HW_GEN_CTRL_SPI_APP_LTSSM_TIMER_DIS        vxge_mBIT(5)
-#define VXGE_HW_GEN_CTRL_SPI_NOT_USED(val) vxge_vBIT(val, 6, 4)
-       u8      unused00ed0[0x00ed0-0x00ec0];
-
-/*0x00ed0*/    u64     adapter_ready;
-#define        VXGE_HW_ADAPTER_READY_ADAPTER_READY     vxge_mBIT(63)
-/*0x00ed8*/    u64     outstanding_read;
-#define VXGE_HW_OUTSTANDING_READ_OUTSTANDING_READ(val) vxge_vBIT(val, 0, 17)
-/*0x00ee0*/    u64     vpath_rst_in_prog;
-#define VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(val) vxge_vBIT(val, 0, 17)
-/*0x00ee8*/    u64     vpath_reg_modified;
-#define VXGE_HW_VPATH_REG_MODIFIED_VPATH_REG_MODIFIED(val) vxge_vBIT(val, 0, 17)
-       u8      unused00fc0[0x00fc0-0x00ef0];
-
-/*0x00fc0*/    u64     cp_reset_in_progress;
-#define VXGE_HW_CP_RESET_IN_PROGRESS_CP_VPATH(n)       vxge_mBIT(n)
-       u8      unused01080[0x01080-0x00fc8];
-
-/*0x01080*/    u64     xgmac_ready;
-#define VXGE_HW_XGMAC_READY_XMACJ_READY(val) vxge_vBIT(val, 0, 17)
-       u8      unused010c0[0x010c0-0x01088];
-
-/*0x010c0*/    u64     fbif_ready;
-#define VXGE_HW_FBIF_READY_FAU_READY(val) vxge_vBIT(val, 0, 17)
-       u8      unused01100[0x01100-0x010c8];
-
-/*0x01100*/    u64     vplane_assignments;
-#define VXGE_HW_VPLANE_ASSIGNMENTS_VPLANE_ASSIGNMENTS(val) vxge_vBIT(val, 3, 5)
-/*0x01108*/    u64     vpath_assignments;
-#define VXGE_HW_VPATH_ASSIGNMENTS_VPATH_ASSIGNMENTS(val) vxge_vBIT(val, 0, 17)
-/*0x01110*/    u64     resource_assignments;
-#define VXGE_HW_RESOURCE_ASSIGNMENTS_RESOURCE_ASSIGNMENTS(val) \
-                                               vxge_vBIT(val, 0, 17)
-/*0x01118*/    u64     host_type_assignments;
-#define        VXGE_HW_HOST_TYPE_ASSIGNMENTS_HOST_TYPE_ASSIGNMENTS(val) \
-                                                       vxge_vBIT(val, 5, 3)
-       u8      unused01128[0x01128-0x01120];
-
-/*0x01128*/    u64     max_resource_assignments;
-#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPLANE(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPATHS(val) \
-                                               vxge_vBIT(val, 11, 5)
-/*0x01130*/    u64     pf_vpath_assignments;
-#define VXGE_HW_PF_VPATH_ASSIGNMENTS_PF_VPATH_ASSIGNMENTS(val) \
-                                               vxge_vBIT(val, 0, 17)
-       u8      unused01200[0x01200-0x01138];
-
-/*0x01200*/    u64     rts_access_icmp;
-#define VXGE_HW_RTS_ACCESS_ICMP_EN(val) vxge_vBIT(val, 0, 17)
-/*0x01208*/    u64     rts_access_tcpsyn;
-#define VXGE_HW_RTS_ACCESS_TCPSYN_EN(val) vxge_vBIT(val, 0, 17)
-/*0x01210*/    u64     rts_access_zl4pyld;
-#define VXGE_HW_RTS_ACCESS_ZL4PYLD_EN(val) vxge_vBIT(val, 0, 17)
-/*0x01218*/    u64     rts_access_l4prtcl_tcp;
-#define VXGE_HW_RTS_ACCESS_L4PRTCL_TCP_EN(val) vxge_vBIT(val, 0, 17)
-/*0x01220*/    u64     rts_access_l4prtcl_udp;
-#define VXGE_HW_RTS_ACCESS_L4PRTCL_UDP_EN(val) vxge_vBIT(val, 0, 17)
-/*0x01228*/    u64     rts_access_l4prtcl_flex;
-#define VXGE_HW_RTS_ACCESS_L4PRTCL_FLEX_EN(val) vxge_vBIT(val, 0, 17)
-/*0x01230*/    u64     rts_access_ipfrag;
-#define VXGE_HW_RTS_ACCESS_IPFRAG_EN(val) vxge_vBIT(val, 0, 17)
-
-} __packed;
-
-struct vxge_hw_memrepair_reg {
-       u64     unused1;
-       u64     unused2;
-} __packed;
-
-struct vxge_hw_pcicfgmgmt_reg {
-
-/*0x00000*/    u64     resource_no;
-#define        VXGE_HW_RESOURCE_NO_PFN_OR_VF   BIT(3)
-/*0x00008*/    u64     bargrp_pf_or_vf_bar0_mask;
-#define        VXGE_HW_BARGRP_PF_OR_VF_BAR0_MASK_BARGRP_PF_OR_VF_BAR0_MASK(val) \
-                                                       vxge_vBIT(val, 2, 6)
-/*0x00010*/    u64     bargrp_pf_or_vf_bar1_mask;
-#define        VXGE_HW_BARGRP_PF_OR_VF_BAR1_MASK_BARGRP_PF_OR_VF_BAR1_MASK(val) \
-                                                       vxge_vBIT(val, 2, 6)
-/*0x00018*/    u64     bargrp_pf_or_vf_bar2_mask;
-#define        VXGE_HW_BARGRP_PF_OR_VF_BAR2_MASK_BARGRP_PF_OR_VF_BAR2_MASK(val) \
-                                                       vxge_vBIT(val, 2, 6)
-/*0x00020*/    u64     msixgrp_no;
-#define VXGE_HW_MSIXGRP_NO_TABLE_SIZE(val) vxge_vBIT(val, 5, 11)
-
-} __packed;
-
-struct vxge_hw_mrpcim_reg {
-/*0x00000*/    u64     g3fbct_int_status;
-#define        VXGE_HW_G3FBCT_INT_STATUS_ERR_G3IF_INT  vxge_mBIT(0)
-/*0x00008*/    u64     g3fbct_int_mask;
-/*0x00010*/    u64     g3fbct_err_reg;
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_SM_ERR      vxge_mBIT(4)
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_DECC  vxge_mBIT(5)
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_DECC        vxge_mBIT(6)
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_DECC      vxge_mBIT(7)
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_SECC  vxge_mBIT(29)
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_SECC        vxge_mBIT(30)
-#define        VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_SECC      vxge_mBIT(31)
-/*0x00018*/    u64     g3fbct_err_mask;
-/*0x00020*/    u64     g3fbct_err_alarm;
-
-       u8      unused00a00[0x00a00-0x00028];
-
-/*0x00a00*/    u64     wrdma_int_status;
-#define        VXGE_HW_WRDMA_INT_STATUS_RC_ALARM_RC_INT        vxge_mBIT(0)
-#define        VXGE_HW_WRDMA_INT_STATUS_RXDRM_SM_ERR_RXDRM_INT vxge_mBIT(1)
-#define        VXGE_HW_WRDMA_INT_STATUS_RXDCM_SM_ERR_RXDCM_SM_INT      vxge_mBIT(2)
-#define        VXGE_HW_WRDMA_INT_STATUS_RXDWM_SM_ERR_RXDWM_INT vxge_mBIT(3)
-#define        VXGE_HW_WRDMA_INT_STATUS_RDA_ERR_RDA_INT        vxge_mBIT(6)
-#define        VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_DB_RDA_ECC_DB_INT      vxge_mBIT(8)
-#define        VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_SG_RDA_ECC_SG_INT      vxge_mBIT(9)
-#define        VXGE_HW_WRDMA_INT_STATUS_FRF_ALARM_FRF_INT      vxge_mBIT(12)
-#define        VXGE_HW_WRDMA_INT_STATUS_ROCRC_ALARM_ROCRC_INT  vxge_mBIT(13)
-#define        VXGE_HW_WRDMA_INT_STATUS_WDE0_ALARM_WDE0_INT    vxge_mBIT(14)
-#define        VXGE_HW_WRDMA_INT_STATUS_WDE1_ALARM_WDE1_INT    vxge_mBIT(15)
-#define        VXGE_HW_WRDMA_INT_STATUS_WDE2_ALARM_WDE2_INT    vxge_mBIT(16)
-#define        VXGE_HW_WRDMA_INT_STATUS_WDE3_ALARM_WDE3_INT    vxge_mBIT(17)
-/*0x00a08*/    u64     wrdma_int_mask;
-/*0x00a10*/    u64     rc_alarm_reg;
-#define        VXGE_HW_RC_ALARM_REG_FTC_SM_ERR vxge_mBIT(0)
-#define        VXGE_HW_RC_ALARM_REG_FTC_SM_PHASE_ERR   vxge_mBIT(1)
-#define        VXGE_HW_RC_ALARM_REG_BTDWM_SM_ERR       vxge_mBIT(2)
-#define        VXGE_HW_RC_ALARM_REG_BTC_SM_ERR vxge_mBIT(3)
-#define        VXGE_HW_RC_ALARM_REG_BTDCM_SM_ERR       vxge_mBIT(4)
-#define        VXGE_HW_RC_ALARM_REG_BTDRM_SM_ERR       vxge_mBIT(5)
-#define        VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_DB_ERR      vxge_mBIT(6)
-#define        VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_SG_ERR      vxge_mBIT(7)
-#define        VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_DB_ERR     vxge_mBIT(8)
-#define        VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_SG_ERR     vxge_mBIT(9)
-#define        VXGE_HW_RC_ALARM_REG_RMM_SM_ERR vxge_mBIT(10)
-#define        VXGE_HW_RC_ALARM_REG_BTC_VPATH_MISMATCH_ERR     vxge_mBIT(12)
-/*0x00a18*/    u64     rc_alarm_mask;
-/*0x00a20*/    u64     rc_alarm_alarm;
-/*0x00a28*/    u64     rxdrm_sm_err_reg;
-#define VXGE_HW_RXDRM_SM_ERR_REG_PRC_VP(n)     vxge_mBIT(n)
-/*0x00a30*/    u64     rxdrm_sm_err_mask;
-/*0x00a38*/    u64     rxdrm_sm_err_alarm;
-/*0x00a40*/    u64     rxdcm_sm_err_reg;
-#define VXGE_HW_RXDCM_SM_ERR_REG_PRC_VP(n)     vxge_mBIT(n)
-/*0x00a48*/    u64     rxdcm_sm_err_mask;
-/*0x00a50*/    u64     rxdcm_sm_err_alarm;
-/*0x00a58*/    u64     rxdwm_sm_err_reg;
-#define VXGE_HW_RXDWM_SM_ERR_REG_PRC_VP(n)     vxge_mBIT(n)
-/*0x00a60*/    u64     rxdwm_sm_err_mask;
-/*0x00a68*/    u64     rxdwm_sm_err_alarm;
-/*0x00a70*/    u64     rda_err_reg;
-#define        VXGE_HW_RDA_ERR_REG_RDA_SM0_ERR_ALARM   vxge_mBIT(0)
-#define        VXGE_HW_RDA_ERR_REG_RDA_MISC_ERR        vxge_mBIT(1)
-#define        VXGE_HW_RDA_ERR_REG_RDA_PCIX_ERR        vxge_mBIT(2)
-#define        VXGE_HW_RDA_ERR_REG_RDA_RXD_ECC_DB_ERR  vxge_mBIT(3)
-#define        VXGE_HW_RDA_ERR_REG_RDA_FRM_ECC_DB_ERR  vxge_mBIT(4)
-#define        VXGE_HW_RDA_ERR_REG_RDA_UQM_ECC_DB_ERR  vxge_mBIT(5)
-#define        VXGE_HW_RDA_ERR_REG_RDA_IMM_ECC_DB_ERR  vxge_mBIT(6)
-#define        VXGE_HW_RDA_ERR_REG_RDA_TIM_ECC_DB_ERR  vxge_mBIT(7)
-/*0x00a78*/    u64     rda_err_mask;
-/*0x00a80*/    u64     rda_err_alarm;
-/*0x00a88*/    u64     rda_ecc_db_reg;
-#define VXGE_HW_RDA_ECC_DB_REG_RDA_RXD_ERR(n)  vxge_mBIT(n)
-/*0x00a90*/    u64     rda_ecc_db_mask;
-/*0x00a98*/    u64     rda_ecc_db_alarm;
-/*0x00aa0*/    u64     rda_ecc_sg_reg;
-#define VXGE_HW_RDA_ECC_SG_REG_RDA_RXD_ERR(n)  vxge_mBIT(n)
-/*0x00aa8*/    u64     rda_ecc_sg_mask;
-/*0x00ab0*/    u64     rda_ecc_sg_alarm;
-/*0x00ab8*/    u64     rqa_err_reg;
-#define        VXGE_HW_RQA_ERR_REG_RQA_SM_ERR_ALARM    vxge_mBIT(0)
-/*0x00ac0*/    u64     rqa_err_mask;
-/*0x00ac8*/    u64     rqa_err_alarm;
-/*0x00ad0*/    u64     frf_alarm_reg;
-#define VXGE_HW_FRF_ALARM_REG_PRC_VP_FRF_SM_ERR(n)     vxge_mBIT(n)
-/*0x00ad8*/    u64     frf_alarm_mask;
-/*0x00ae0*/    u64     frf_alarm_alarm;
-/*0x00ae8*/    u64     rocrc_alarm_reg;
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_DB      vxge_mBIT(0)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_SG      vxge_mBIT(1)
-#define        VXGE_HW_ROCRC_ALARM_REG_NOA_NMA_SM_ERR  vxge_mBIT(2)
-#define        VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_DB vxge_mBIT(3)
-#define        VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_SG vxge_mBIT(4)
-#define        VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_DB vxge_mBIT(5)
-#define        VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_SG vxge_mBIT(6)
-#define        VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_DB vxge_mBIT(11)
-#define        VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_SG vxge_mBIT(12)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_RSVD_ERR  vxge_mBIT(13)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_OWN_ERR   vxge_mBIT(14)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_BYP_OWN_ERR   vxge_mBIT(15)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_NOT_ASSIGNED_ERR        vxge_mBIT(16)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_RSVD_SYNC_ERR   vxge_mBIT(17)
-#define        VXGE_HW_ROCRC_ALARM_REG_QCQ_LOST_EGB_ERR        vxge_mBIT(18)
-#define        VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ0_OVERFLOW      vxge_mBIT(19)
-#define        VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ1_OVERFLOW      vxge_mBIT(20)
-#define        VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ2_OVERFLOW      vxge_mBIT(21)
-#define        VXGE_HW_ROCRC_ALARM_REG_NOA_WCT_CMD_FIFO_ERR    vxge_mBIT(22)
-/*0x00af0*/    u64     rocrc_alarm_mask;
-/*0x00af8*/    u64     rocrc_alarm_alarm;
-/*0x00b00*/    u64     wde0_alarm_reg;
-#define        VXGE_HW_WDE0_ALARM_REG_WDE0_DCC_SM_ERR  vxge_mBIT(0)
-#define        VXGE_HW_WDE0_ALARM_REG_WDE0_PRM_SM_ERR  vxge_mBIT(1)
-#define        VXGE_HW_WDE0_ALARM_REG_WDE0_CP_SM_ERR   vxge_mBIT(2)
-#define        VXGE_HW_WDE0_ALARM_REG_WDE0_CP_CMD_ERR  vxge_mBIT(3)
-#define        VXGE_HW_WDE0_ALARM_REG_WDE0_PCR_SM_ERR  vxge_mBIT(4)
-/*0x00b08*/    u64     wde0_alarm_mask;
-/*0x00b10*/    u64     wde0_alarm_alarm;
-/*0x00b18*/    u64     wde1_alarm_reg;
-#define        VXGE_HW_WDE1_ALARM_REG_WDE1_DCC_SM_ERR  vxge_mBIT(0)
-#define        VXGE_HW_WDE1_ALARM_REG_WDE1_PRM_SM_ERR  vxge_mBIT(1)
-#define        VXGE_HW_WDE1_ALARM_REG_WDE1_CP_SM_ERR   vxge_mBIT(2)
-#define        VXGE_HW_WDE1_ALARM_REG_WDE1_CP_CMD_ERR  vxge_mBIT(3)
-#define        VXGE_HW_WDE1_ALARM_REG_WDE1_PCR_SM_ERR  vxge_mBIT(4)
-/*0x00b20*/    u64     wde1_alarm_mask;
-/*0x00b28*/    u64     wde1_alarm_alarm;
-/*0x00b30*/    u64     wde2_alarm_reg;
-#define        VXGE_HW_WDE2_ALARM_REG_WDE2_DCC_SM_ERR  vxge_mBIT(0)
-#define        VXGE_HW_WDE2_ALARM_REG_WDE2_PRM_SM_ERR  vxge_mBIT(1)
-#define        VXGE_HW_WDE2_ALARM_REG_WDE2_CP_SM_ERR   vxge_mBIT(2)
-#define        VXGE_HW_WDE2_ALARM_REG_WDE2_CP_CMD_ERR  vxge_mBIT(3)
-#define        VXGE_HW_WDE2_ALARM_REG_WDE2_PCR_SM_ERR  vxge_mBIT(4)
-/*0x00b38*/    u64     wde2_alarm_mask;
-/*0x00b40*/    u64     wde2_alarm_alarm;
-/*0x00b48*/    u64     wde3_alarm_reg;
-#define        VXGE_HW_WDE3_ALARM_REG_WDE3_DCC_SM_ERR  vxge_mBIT(0)
-#define        VXGE_HW_WDE3_ALARM_REG_WDE3_PRM_SM_ERR  vxge_mBIT(1)
-#define        VXGE_HW_WDE3_ALARM_REG_WDE3_CP_SM_ERR   vxge_mBIT(2)
-#define        VXGE_HW_WDE3_ALARM_REG_WDE3_CP_CMD_ERR  vxge_mBIT(3)
-#define        VXGE_HW_WDE3_ALARM_REG_WDE3_PCR_SM_ERR  vxge_mBIT(4)
-/*0x00b50*/    u64     wde3_alarm_mask;
-/*0x00b58*/    u64     wde3_alarm_alarm;
-
-       u8      unused00be8[0x00be8-0x00b60];
-
-/*0x00be8*/    u64     rx_w_round_robin_0;
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(val) vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(val) vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(val) vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(val) vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(val) vxge_vBIT(val, 59, 5)
-/*0x00bf0*/    u64     rx_w_round_robin_1;
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_8(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_9(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_10(val) \
-                                               vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_11(val) \
-                                               vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_12(val) \
-                                               vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_13(val) \
-                                               vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_14(val) \
-                                               vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_15(val) \
-                                               vxge_vBIT(val, 59, 5)
-/*0x00bf8*/    u64     rx_w_round_robin_2;
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_16(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_17(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_18(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_19(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_20(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_21(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_22(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_23(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c00*/    u64     rx_w_round_robin_3;
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_24(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_25(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_26(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_27(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_28(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_29(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_30(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_31(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c08*/    u64     rx_w_round_robin_4;
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_32(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_33(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_34(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_35(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_36(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_37(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_38(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_39(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c10*/    u64     rx_w_round_robin_5;
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_40(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_41(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_42(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_43(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_44(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_45(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_46(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_47(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c18*/    u64     rx_w_round_robin_6;
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_48(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_49(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_50(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_51(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_52(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_53(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_54(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_55(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c20*/    u64     rx_w_round_robin_7;
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_56(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_57(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_58(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_59(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_60(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_61(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_62(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_63(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c28*/    u64     rx_w_round_robin_8;
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_64(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_65(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_66(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_67(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_68(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_69(val) \
-                                               vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_70(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_71(val) \
-                                               vxge_vBIT(val, 59, 5)
-/*0x00c30*/    u64     rx_w_round_robin_9;
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_72(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_73(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_74(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_75(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_76(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_77(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_78(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_79(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c38*/    u64     rx_w_round_robin_10;
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_80(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_81(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_82(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_83(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_84(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_85(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_86(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_87(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c40*/    u64     rx_w_round_robin_11;
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_88(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_89(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_90(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_91(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_92(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_93(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_94(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_95(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c48*/    u64     rx_w_round_robin_12;
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_96(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_97(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_98(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_99(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_100(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_101(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_102(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_103(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c50*/    u64     rx_w_round_robin_13;
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_104(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_105(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_106(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_107(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_108(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_109(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_110(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_111(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c58*/    u64     rx_w_round_robin_14;
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_112(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_113(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_114(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_115(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_116(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_117(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_118(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_119(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c60*/    u64     rx_w_round_robin_15;
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_120(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_121(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_122(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_123(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_124(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_125(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_126(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_127(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c68*/    u64     rx_w_round_robin_16;
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_128(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_129(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_130(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_131(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_132(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_133(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_134(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_135(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c70*/    u64     rx_w_round_robin_17;
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_136(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_137(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_138(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_139(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_140(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_141(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_142(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_143(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c78*/    u64     rx_w_round_robin_18;
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_144(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_145(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_146(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_147(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_148(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_149(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_150(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_151(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c80*/    u64     rx_w_round_robin_19;
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_152(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_153(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_154(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_155(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_156(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_157(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_158(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_159(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c88*/    u64     rx_w_round_robin_20;
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_160(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_161(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_162(val) \
-                                                       vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_163(val) \
-                                                       vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_164(val) \
-                                                       vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_165(val) \
-                                                       vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_166(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_167(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00c90*/    u64     rx_w_round_robin_21;
-#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_168(val) \
-                                                       vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_169(val) \
-                                                       vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_170(val) \
-                                                       vxge_vBIT(val, 19, 5)
-
-#define VXGE_HW_WRR_RING_SERVICE_STATES                        171
-#define VXGE_HW_WRR_RING_COUNT                         22
-
-/*0x00c98*/    u64     rx_queue_priority_0;
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(val) vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(val) vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(val) vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(val) vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(val) vxge_vBIT(val, 59, 5)
-/*0x00ca0*/    u64     rx_queue_priority_1;
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(val) vxge_vBIT(val, 19, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(val) vxge_vBIT(val, 35, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(val) vxge_vBIT(val, 43, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(val) vxge_vBIT(val, 51, 5)
-#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(val) vxge_vBIT(val, 59, 5)
-/*0x00ca8*/    u64     rx_queue_priority_2;
-#define VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(val) vxge_vBIT(val, 3, 5)
-       u8      unused00cc8[0x00cc8-0x00cb0];
-
-/*0x00cc8*/    u64     replication_queue_priority;
-#define        VXGE_HW_REPLICATION_QUEUE_PRIORITY_REPLICATION_QUEUE_PRIORITY(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00cd0*/    u64     rx_queue_select;
-#define VXGE_HW_RX_QUEUE_SELECT_NUMBER(n)      vxge_mBIT(n)
-#define        VXGE_HW_RX_QUEUE_SELECT_ENABLE_CODE     vxge_mBIT(15)
-#define        VXGE_HW_RX_QUEUE_SELECT_ENABLE_HIERARCHICAL_PRTY        vxge_mBIT(23)
-/*0x00cd8*/    u64     rqa_vpbp_ctrl;
-#define        VXGE_HW_RQA_VPBP_CTRL_WR_XON_DIS        vxge_mBIT(15)
-#define        VXGE_HW_RQA_VPBP_CTRL_ROCRC_DIS vxge_mBIT(23)
-#define        VXGE_HW_RQA_VPBP_CTRL_TXPE_DIS  vxge_mBIT(31)
-/*0x00ce0*/    u64     rx_multi_cast_ctrl;
-#define        VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_DIS vxge_mBIT(0)
-#define        VXGE_HW_RX_MULTI_CAST_CTRL_FRM_DROP_DIS vxge_mBIT(1)
-#define VXGE_HW_RX_MULTI_CAST_CTRL_NO_RXD_TIME_OUT_CNT(val) \
-                                                       vxge_vBIT(val, 2, 30)
-#define VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_CNT(val) vxge_vBIT(val, 32, 32)
-/*0x00ce8*/    u64     wde_prm_ctrl;
-#define VXGE_HW_WDE_PRM_CTRL_SPAV_THRESHOLD(val) vxge_vBIT(val, 2, 10)
-#define VXGE_HW_WDE_PRM_CTRL_SPLIT_THRESHOLD(val) vxge_vBIT(val, 18, 14)
-#define        VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_1ST_ROW   vxge_mBIT(32)
-#define        VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_ROW_BNDRY vxge_mBIT(33)
-#define VXGE_HW_WDE_PRM_CTRL_FB_ROW_SIZE(val) vxge_vBIT(val, 46, 2)
-/*0x00cf0*/    u64     noa_ctrl;
-#define VXGE_HW_NOA_CTRL_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_NOA_CTRL_NON_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 11, 5)
-#define        VXGE_HW_NOA_CTRL_IGNORE_KDFC_IF_STATUS  vxge_mBIT(16)
-#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE0(val) vxge_vBIT(val, 37, 4)
-#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE1(val) vxge_vBIT(val, 45, 4)
-#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE2(val) vxge_vBIT(val, 53, 4)
-#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE3(val) vxge_vBIT(val, 60, 4)
-/*0x00cf8*/    u64     phase_cfg;
-#define        VXGE_HW_PHASE_CFG_QCC_WR_PHASE_EN       vxge_mBIT(0)
-#define        VXGE_HW_PHASE_CFG_QCC_RD_PHASE_EN       vxge_mBIT(3)
-#define        VXGE_HW_PHASE_CFG_IMMM_WR_PHASE_EN      vxge_mBIT(7)
-#define        VXGE_HW_PHASE_CFG_IMMM_RD_PHASE_EN      vxge_mBIT(11)
-#define        VXGE_HW_PHASE_CFG_UMQM_WR_PHASE_EN      vxge_mBIT(15)
-#define        VXGE_HW_PHASE_CFG_UMQM_RD_PHASE_EN      vxge_mBIT(19)
-#define        VXGE_HW_PHASE_CFG_RCBM_WR_PHASE_EN      vxge_mBIT(23)
-#define        VXGE_HW_PHASE_CFG_RCBM_RD_PHASE_EN      vxge_mBIT(27)
-#define        VXGE_HW_PHASE_CFG_RXD_RC_WR_PHASE_EN    vxge_mBIT(31)
-#define        VXGE_HW_PHASE_CFG_RXD_RC_RD_PHASE_EN    vxge_mBIT(35)
-#define        VXGE_HW_PHASE_CFG_RXD_RHS_WR_PHASE_EN   vxge_mBIT(39)
-#define        VXGE_HW_PHASE_CFG_RXD_RHS_RD_PHASE_EN   vxge_mBIT(43)
-/*0x00d00*/    u64     rcq_bypq_cfg;
-#define VXGE_HW_RCQ_BYPQ_CFG_OVERFLOW_THRESHOLD(val) vxge_vBIT(val, 10, 22)
-#define VXGE_HW_RCQ_BYPQ_CFG_BYP_ON_THRESHOLD(val) vxge_vBIT(val, 39, 9)
-#define VXGE_HW_RCQ_BYPQ_CFG_BYP_OFF_THRESHOLD(val) vxge_vBIT(val, 55, 9)
-       u8      unused00e00[0x00e00-0x00d08];
-
-/*0x00e00*/    u64     doorbell_int_status;
-#define        VXGE_HW_DOORBELL_INT_STATUS_KDFC_ERR_REG_TXDMA_KDFC_INT vxge_mBIT(7)
-#define        VXGE_HW_DOORBELL_INT_STATUS_USDC_ERR_REG_TXDMA_USDC_INT vxge_mBIT(15)
-/*0x00e08*/    u64     doorbell_int_mask;
-/*0x00e10*/    u64     kdfc_err_reg;
-#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_SG_ERR       vxge_mBIT(7)
-#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_DB_ERR       vxge_mBIT(15)
-#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_SM_ERR_ALARM     vxge_mBIT(23)
-#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_MISC_ERR_1       vxge_mBIT(32)
-#define        VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_PCIX_ERR vxge_mBIT(39)
-/*0x00e18*/    u64     kdfc_err_mask;
-/*0x00e20*/    u64     kdfc_err_reg_alarm;
-#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_SG_ERR vxge_mBIT(7)
-#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_DB_ERR vxge_mBIT(15)
-#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_SM_ERR_ALARM       vxge_mBIT(23)
-#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_MISC_ERR_1 vxge_mBIT(32)
-#define        VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_PCIX_ERR   vxge_mBIT(39)
-       u8      unused00e40[0x00e40-0x00e28];
-/*0x00e40*/    u64     kdfc_vp_partition_0;
-#define        VXGE_HW_KDFC_VP_PARTITION_0_ENABLE      vxge_mBIT(0)
-#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_0(val) vxge_vBIT(val, 5, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_0(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_1(val) vxge_vBIT(val, 37, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_1(val) vxge_vBIT(val, 49, 15)
-/*0x00e48*/    u64     kdfc_vp_partition_1;
-#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_2(val) vxge_vBIT(val, 5, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_2(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_3(val) vxge_vBIT(val, 37, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_3(val) vxge_vBIT(val, 49, 15)
-/*0x00e50*/    u64     kdfc_vp_partition_2;
-#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_4(val) vxge_vBIT(val, 5, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_4(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_5(val) vxge_vBIT(val, 37, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_5(val) vxge_vBIT(val, 49, 15)
-/*0x00e58*/    u64     kdfc_vp_partition_3;
-#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_6(val) vxge_vBIT(val, 5, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_6(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_7(val) vxge_vBIT(val, 37, 3)
-#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_7(val) vxge_vBIT(val, 49, 15)
-/*0x00e60*/    u64     kdfc_vp_partition_4;
-#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_8(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_9(val) vxge_vBIT(val, 49, 15)
-/*0x00e68*/    u64     kdfc_vp_partition_5;
-#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_10(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_11(val) vxge_vBIT(val, 49, 15)
-/*0x00e70*/    u64     kdfc_vp_partition_6;
-#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_12(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_13(val) vxge_vBIT(val, 49, 15)
-/*0x00e78*/    u64     kdfc_vp_partition_7;
-#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_14(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_15(val) vxge_vBIT(val, 49, 15)
-/*0x00e80*/    u64     kdfc_vp_partition_8;
-#define VXGE_HW_KDFC_VP_PARTITION_8_LENGTH_16(val) vxge_vBIT(val, 17, 15)
-/*0x00e88*/    u64     kdfc_w_round_robin_0;
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(val) vxge_vBIT(val, 19, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(val) vxge_vBIT(val, 35, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(val) vxge_vBIT(val, 43, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(val) vxge_vBIT(val, 51, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(val) vxge_vBIT(val, 59, 5)
-
-       u8      unused0f28[0x0f28-0x0e90];
-
-/*0x00f28*/    u64     kdfc_w_round_robin_20;
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_0(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_1(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_2(val) vxge_vBIT(val, 19, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_3(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_4(val) vxge_vBIT(val, 35, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_5(val) vxge_vBIT(val, 43, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_6(val) vxge_vBIT(val, 51, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_7(val) vxge_vBIT(val, 59, 5)
-
-#define VXGE_HW_WRR_FIFO_COUNT                         20
-
-       u8      unused0fc8[0x0fc8-0x0f30];
-
-/*0x00fc8*/    u64     kdfc_w_round_robin_40;
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_0(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_1(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_2(val) vxge_vBIT(val, 19, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_3(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_4(val) vxge_vBIT(val, 35, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_5(val) vxge_vBIT(val, 43, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_6(val) vxge_vBIT(val, 51, 5)
-#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_7(val) vxge_vBIT(val, 59, 5)
-
-       u8      unused1068[0x01068-0x0fd0];
-
-/*0x01068*/    u64     kdfc_entry_type_sel_0;
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(val) vxge_vBIT(val, 6, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(val) vxge_vBIT(val, 14, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(val) vxge_vBIT(val, 22, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(val) vxge_vBIT(val, 30, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(val) vxge_vBIT(val, 38, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(val) vxge_vBIT(val, 46, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(val) vxge_vBIT(val, 54, 2)
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(val) vxge_vBIT(val, 62, 2)
-/*0x01070*/    u64     kdfc_entry_type_sel_1;
-#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(val) vxge_vBIT(val, 6, 2)
-/*0x01078*/    u64     kdfc_fifo_0_ctrl;
-#define VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_WEIGHTED_RR_SERVICE_STATES             176
-#define VXGE_HW_WRR_FIFO_SERVICE_STATES                        153
-
-       u8      unused1100[0x01100-0x1080];
-
-/*0x01100*/    u64     kdfc_fifo_17_ctrl;
-#define VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5)
-
-       u8      unused1600[0x01600-0x1108];
-
-/*0x01600*/    u64     rxmac_int_status;
-#define        VXGE_HW_RXMAC_INT_STATUS_RXMAC_GEN_ERR_RXMAC_GEN_INT    vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_INT_STATUS_RXMAC_ECC_ERR_RXMAC_ECC_INT    vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_INT_STATUS_RXMAC_VARIOUS_ERR_RXMAC_VARIOUS_INT \
-                                                               vxge_mBIT(11)
-/*0x01608*/    u64     rxmac_int_mask;
-       u8      unused01618[0x01618-0x01610];
-
-/*0x01618*/    u64     rxmac_gen_err_reg;
-/*0x01620*/    u64     rxmac_gen_err_mask;
-/*0x01628*/    u64     rxmac_gen_err_alarm;
-/*0x01630*/    u64     rxmac_ecc_err_reg;
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_SG_ERR(val) \
-                                                       vxge_vBIT(val, 0, 4)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_DB_ERR(val) \
-                                                       vxge_vBIT(val, 4, 4)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_SG_ERR(val) \
-                                                       vxge_vBIT(val, 8, 4)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_DB_ERR(val) \
-                                                       vxge_vBIT(val, 12, 4)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_SG_ERR(val) \
-                                                       vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_DB_ERR(val) \
-                                                       vxge_vBIT(val, 20, 4)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_SG_ERR(val) \
-                                                       vxge_vBIT(val, 24, 2)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_DB_ERR(val) \
-                                                       vxge_vBIT(val, 26, 2)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_SG_ERR(val) \
-                                                       vxge_vBIT(val, 28, 2)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_DB_ERR(val) \
-                                                       vxge_vBIT(val, 30, 2)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_SG_ERR      vxge_mBIT(32)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_DB_ERR      vxge_mBIT(33)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_SG_ERR  vxge_mBIT(34)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_DB_ERR  vxge_mBIT(35)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_SG_ERR  vxge_mBIT(36)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_DB_ERR  vxge_mBIT(37)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_SG_ERR  vxge_mBIT(38)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_DB_ERR  vxge_mBIT(39)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_SG_ERR(val) \
-                                                       vxge_vBIT(val, 40, 7)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_DB_ERR(val) \
-                                                       vxge_vBIT(val, 47, 7)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_SG_ERR(val) \
-                                                       vxge_vBIT(val, 54, 3)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_DB_ERR(val) \
-                                                       vxge_vBIT(val, 57, 3)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_SG_ERR \
-                                                       vxge_mBIT(60)
-#define        VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_DB_ERR \
-                                                       vxge_mBIT(61)
-/*0x01638*/    u64     rxmac_ecc_err_mask;
-/*0x01640*/    u64     rxmac_ecc_err_alarm;
-/*0x01648*/    u64     rxmac_various_err_reg;
-#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT0_FSM_ERR   vxge_mBIT(0)
-#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT1_FSM_ERR   vxge_mBIT(1)
-#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT2_FSM_ERR   vxge_mBIT(2)
-#define        VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMACJ_RMACJ_FSM_ERR       vxge_mBIT(3)
-/*0x01650*/    u64     rxmac_various_err_mask;
-/*0x01658*/    u64     rxmac_various_err_alarm;
-/*0x01660*/    u64     rxmac_gen_cfg;
-#define        VXGE_HW_RXMAC_GEN_CFG_SCALE_RMAC_UTIL   vxge_mBIT(11)
-/*0x01668*/    u64     rxmac_authorize_all_addr;
-#define VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(n) vxge_mBIT(n)
-/*0x01670*/    u64     rxmac_authorize_all_vid;
-#define VXGE_HW_RXMAC_AUTHORIZE_ALL_VID_VP(n)  vxge_mBIT(n)
-       u8      unused016c0[0x016c0-0x01678];
-
-/*0x016c0*/    u64     rxmac_red_rate_repl_queue;
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR0(val) vxge_vBIT(val, 0, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR1(val) vxge_vBIT(val, 4, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR2(val) vxge_vBIT(val, 8, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR3(val) vxge_vBIT(val, 12, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR0(val) vxge_vBIT(val, 16, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR1(val) vxge_vBIT(val, 20, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR2(val) vxge_vBIT(val, 24, 4)
-#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR3(val) vxge_vBIT(val, 28, 4)
-#define        VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_TRICKLE_EN    vxge_mBIT(35)
-       u8      unused016e0[0x016e0-0x016c8];
-
-/*0x016e0*/    u64     rxmac_cfg0_port[3];
-#define        VXGE_HW_RXMAC_CFG0_PORT_RMAC_EN vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_CFG0_PORT_STRIP_FCS       vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_CFG0_PORT_DISCARD_PFRM    vxge_mBIT(11)
-#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_FCS_ERR  vxge_mBIT(15)
-#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LONG_ERR vxge_mBIT(19)
-#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_USIZED_ERR       vxge_mBIT(23)
-#define        VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LEN_MISMATCH     vxge_mBIT(27)
-#define VXGE_HW_RXMAC_CFG0_PORT_MAX_PYLD_LEN(val) vxge_vBIT(val, 50, 14)
-       u8      unused01710[0x01710-0x016f8];
-
-/*0x01710*/    u64     rxmac_cfg2_port[3];
-#define        VXGE_HW_RXMAC_CFG2_PORT_PROM_EN vxge_mBIT(3)
-/*0x01728*/    u64     rxmac_pause_cfg_port[3];
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN     vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN     vxge_mBIT(7)
-#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_ACCEL_SEND(val) vxge_vBIT(val, 9, 3)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_DUAL_THR   vxge_mBIT(15)
-#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_HIGH_PTIME(val) vxge_vBIT(val, 20, 16)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_FCS_ERR  vxge_mBIT(39)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_LEN_ERR  vxge_mBIT(43)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_LIMITER_EN vxge_mBIT(47)
-#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_MAX_LIMIT(val) vxge_vBIT(val, 48, 8)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_PERMIT_RATEMGMT_CTRL       vxge_mBIT(59)
-       u8      unused01758[0x01758-0x01740];
-
-/*0x01758*/    u64     rxmac_red_cfg0_port[3];
-#define VXGE_HW_RXMAC_RED_CFG0_PORT_RED_EN_VP(n)       vxge_mBIT(n)
-/*0x01770*/    u64     rxmac_red_cfg1_port[3];
-#define        VXGE_HW_RXMAC_RED_CFG1_PORT_FINE_EN     vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_RED_CFG1_PORT_RED_EN_REPL_QUEUE   vxge_mBIT(11)
-/*0x01788*/    u64     rxmac_red_cfg2_port[3];
-#define VXGE_HW_RXMAC_RED_CFG2_PORT_TRICKLE_EN_VP(n)   vxge_mBIT(n)
-/*0x017a0*/    u64     rxmac_link_util_port[3];
-#define        VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_UTILIZATION(val) \
-                                                       vxge_vBIT(val, 1, 7)
-#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4)
-#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_FRAC_UTIL(val) \
-                                                       vxge_vBIT(val, 12, 4)
-#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_SCALE_FACTOR     vxge_mBIT(23)
-       u8      unused017d0[0x017d0-0x017b8];
-
-/*0x017d0*/    u64     rxmac_status_port[3];
-#define        VXGE_HW_RXMAC_STATUS_PORT_RMAC_RX_FRM_RCVD      vxge_mBIT(3)
-       u8      unused01800[0x01800-0x017e8];
-
-/*0x01800*/    u64     rxmac_rx_pa_cfg0;
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_IGNORE_FRAME_ERR       vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_SNAP_AB_N      vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_HAO vxge_mBIT(18)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_MOBILE_IPV6_HDRS       vxge_mBIT(19)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_IPV6_STOP_SEARCHING    vxge_mBIT(23)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_NO_PS_IF_UNKNOWN       vxge_mBIT(27)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_ETYPE       vxge_mBIT(35)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L3_CSUM_ERR    vxge_mBIT(39)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR  vxge_mBIT(43)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L4_CSUM_ERR    vxge_mBIT(47)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR  vxge_mBIT(51)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_RPA_ERR        vxge_mBIT(55)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_RPA_ERR      vxge_mBIT(59)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_JUMBO_SNAP_EN  vxge_mBIT(63)
-/*0x01808*/    u64     rxmac_rx_pa_cfg1;
-#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_TCP_INCL_PH  vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_TCP_INCL_PH  vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_UDP_INCL_PH  vxge_mBIT(11)
-#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_UDP_INCL_PH  vxge_mBIT(15)
-#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_L4_INCL_CF        vxge_mBIT(19)
-#define        VXGE_HW_RXMAC_RX_PA_CFG1_REPL_STRIP_VLAN_TAG    vxge_mBIT(23)
-       u8      unused01828[0x01828-0x01810];
-
-/*0x01828*/    u64     rts_mgr_cfg0;
-#define        VXGE_HW_RTS_MGR_CFG0_RTS_DP_SP_PRIORITY vxge_mBIT(3)
-#define VXGE_HW_RTS_MGR_CFG0_FLEX_L4PRTCL_VALUE(val) vxge_vBIT(val, 24, 8)
-#define        VXGE_HW_RTS_MGR_CFG0_ICMP_TRASH vxge_mBIT(35)
-#define        VXGE_HW_RTS_MGR_CFG0_TCPSYN_TRASH       vxge_mBIT(39)
-#define        VXGE_HW_RTS_MGR_CFG0_ZL4PYLD_TRASH      vxge_mBIT(43)
-#define        VXGE_HW_RTS_MGR_CFG0_L4PRTCL_TCP_TRASH  vxge_mBIT(47)
-#define        VXGE_HW_RTS_MGR_CFG0_L4PRTCL_UDP_TRASH  vxge_mBIT(51)
-#define        VXGE_HW_RTS_MGR_CFG0_L4PRTCL_FLEX_TRASH vxge_mBIT(55)
-#define        VXGE_HW_RTS_MGR_CFG0_IPFRAG_TRASH       vxge_mBIT(59)
-/*0x01830*/    u64     rts_mgr_cfg1;
-#define        VXGE_HW_RTS_MGR_CFG1_DA_ACTIVE_TABLE    vxge_mBIT(3)
-#define        VXGE_HW_RTS_MGR_CFG1_PN_ACTIVE_TABLE    vxge_mBIT(7)
-/*0x01838*/    u64     rts_mgr_criteria_priority;
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ETYPE(val) vxge_vBIT(val, 5, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ICMP_TCPSYN(val) vxge_vBIT(val, 9, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PN(val) vxge_vBIT(val, 13, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RANGE_L4PN(val) vxge_vBIT(val, 17, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RTH_IT(val) vxge_vBIT(val, 21, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_DS(val) vxge_vBIT(val, 25, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_QOS(val) vxge_vBIT(val, 29, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ZL4PYLD(val) vxge_vBIT(val, 33, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PRTCL(val) vxge_vBIT(val, 37, 3)
-/*0x01840*/    u64     rts_mgr_da_pause_cfg;
-#define VXGE_HW_RTS_MGR_DA_PAUSE_CFG_VPATH_VECTOR(val) vxge_vBIT(val, 0, 17)
-/*0x01848*/    u64     rts_mgr_da_slow_proto_cfg;
-#define VXGE_HW_RTS_MGR_DA_SLOW_PROTO_CFG_VPATH_VECTOR(val) \
-                                                       vxge_vBIT(val, 0, 17)
-       u8      unused01890[0x01890-0x01850];
-/*0x01890*/     u64     rts_mgr_cbasin_cfg;
-       u8      unused01968[0x01968-0x01898];
-
-/*0x01968*/    u64     dbg_stat_rx_any_frms;
-#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT0_RX_ANY_FRMS(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT1_RX_ANY_FRMS(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT2_RX_ANY_FRMS(val) \
-                                                       vxge_vBIT(val, 16, 8)
-       u8      unused01a00[0x01a00-0x01970];
-
-/*0x01a00*/    u64     rxmac_red_rate_vp[17];
-#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR0(val) vxge_vBIT(val, 0, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR1(val) vxge_vBIT(val, 4, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR2(val) vxge_vBIT(val, 8, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR3(val) vxge_vBIT(val, 12, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR0(val) vxge_vBIT(val, 16, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR1(val) vxge_vBIT(val, 20, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR2(val) vxge_vBIT(val, 24, 4)
-#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR3(val) vxge_vBIT(val, 28, 4)
-       u8      unused01e00[0x01e00-0x01a88];
-
-/*0x01e00*/    u64     xgmac_int_status;
-#define        VXGE_HW_XGMAC_INT_STATUS_XMAC_GEN_ERR_XMAC_GEN_INT      vxge_mBIT(3)
-#define        VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT0_XMAC_LINK_INT_PORT0 \
-                                                               vxge_mBIT(7)
-#define        VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT1_XMAC_LINK_INT_PORT1 \
-                                                               vxge_mBIT(11)
-#define        VXGE_HW_XGMAC_INT_STATUS_XGXS_GEN_ERR_XGXS_GEN_INT      vxge_mBIT(15)
-#define        VXGE_HW_XGMAC_INT_STATUS_ASIC_NTWK_ERR_ASIC_NTWK_INT    vxge_mBIT(19)
-#define        VXGE_HW_XGMAC_INT_STATUS_ASIC_GPIO_ERR_ASIC_GPIO_INT    vxge_mBIT(23)
-/*0x01e08*/    u64     xgmac_int_mask;
-/*0x01e10*/    u64     xmac_gen_err_reg;
-#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_ACTOR_CHURN_DETECTED \
-                                                               vxge_mBIT(7)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_PARTNER_CHURN_DETECTED \
-                                                               vxge_mBIT(11)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_RECEIVED_LACPDU vxge_mBIT(15)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_ACTOR_CHURN_DETECTED \
-                                                               vxge_mBIT(19)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_PARTNER_CHURN_DETECTED \
-                                                               vxge_mBIT(23)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_RECEIVED_LACPDU vxge_mBIT(27)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XLCM_LAG_FAILOVER_DETECTED     vxge_mBIT(31)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_SG_ERR(val) \
-                                                       vxge_vBIT(val, 40, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_DB_ERR(val) \
-                                                       vxge_vBIT(val, 42, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_SG_ERR(val) \
-                                                       vxge_vBIT(val, 44, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_DB_ERR(val) \
-                                                       vxge_vBIT(val, 46, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_SG_ERR(val) \
-                                                       vxge_vBIT(val, 48, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_DB_ERR(val) \
-                                                       vxge_vBIT(val, 50, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_SG_ERR(val) \
-                                                       vxge_vBIT(val, 52, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_DB_ERR(val) \
-                                                       vxge_vBIT(val, 54, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_SG_ERR(val) \
-                                                       vxge_vBIT(val, 56, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_DB_ERR(val) \
-                                                       vxge_vBIT(val, 58, 2)
-#define        VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR     vxge_mBIT(63)
-/*0x01e18*/    u64     xmac_gen_err_mask;
-/*0x01e20*/    u64     xmac_gen_err_alarm;
-/*0x01e28*/    u64     xmac_link_err_port0_reg;
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN  vxge_mBIT(3)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP    vxge_mBIT(7)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN     vxge_mBIT(11)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_UP       vxge_mBIT(15)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_FAULT \
-                                                               vxge_mBIT(19)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_OK vxge_mBIT(23)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_DOWN  vxge_mBIT(27)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_UP    vxge_mBIT(31)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_RATE_CHANGE     vxge_mBIT(35)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV        vxge_mBIT(39)
-#define        VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
-                                                               vxge_mBIT(47)
-/*0x01e30*/    u64     xmac_link_err_port0_mask;
-/*0x01e38*/    u64     xmac_link_err_port0_alarm;
-/*0x01e40*/    u64     xmac_link_err_port1_reg;
-/*0x01e48*/    u64     xmac_link_err_port1_mask;
-/*0x01e50*/    u64     xmac_link_err_port1_alarm;
-/*0x01e58*/    u64     xgxs_gen_err_reg;
-#define        VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR      vxge_mBIT(63)
-/*0x01e60*/    u64     xgxs_gen_err_mask;
-/*0x01e68*/    u64     xgxs_gen_err_alarm;
-/*0x01e70*/    u64     asic_ntwk_err_reg;
-#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_DOWN       vxge_mBIT(3)
-#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_UP vxge_mBIT(7)
-#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_DOWN  vxge_mBIT(11)
-#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_UP    vxge_mBIT(15)
-#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT   vxge_mBIT(19)
-#define        VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK      vxge_mBIT(23)
-/*0x01e78*/    u64     asic_ntwk_err_mask;
-/*0x01e80*/    u64     asic_ntwk_err_alarm;
-/*0x01e88*/    u64     asic_gpio_err_reg;
-#define VXGE_HW_ASIC_GPIO_ERR_REG_XMACJ_GPIO_INT(n)    vxge_mBIT(n)
-/*0x01e90*/    u64     asic_gpio_err_mask;
-/*0x01e98*/    u64     asic_gpio_err_alarm;
-/*0x01ea0*/    u64     xgmac_gen_status;
-#define        VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_OK  vxge_mBIT(3)
-#define        VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_DATA_RATE   vxge_mBIT(11)
-/*0x01ea8*/    u64     xgmac_gen_fw_memo_status;
-#define        VXGE_HW_XGMAC_GEN_FW_MEMO_STATUS_XMACJ_EVENTS_PENDING(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x01eb0*/    u64     xgmac_gen_fw_memo_mask;
-#define VXGE_HW_XGMAC_GEN_FW_MEMO_MASK_MASK(val) vxge_vBIT(val, 0, 64)
-/*0x01eb8*/    u64     xgmac_gen_fw_vpath_to_vsport_status;
-#define        VXGE_HW_XGMAC_GEN_FW_VPATH_TO_VSPORT_STATUS_XMACJ_EVENTS_PENDING(val) \
-                                               vxge_vBIT(val, 0, 17)
-/*0x01ec0*/    u64     xgmac_main_cfg_port[2];
-#define        VXGE_HW_XGMAC_MAIN_CFG_PORT_PORT_EN     vxge_mBIT(3)
-       u8      unused01f40[0x01f40-0x01ed0];
-
-/*0x01f40*/    u64     xmac_gen_cfg;
-#define VXGE_HW_XMAC_GEN_CFG_RATEMGMT_MAC_RATE_SEL(val) vxge_vBIT(val, 2, 2)
-#define        VXGE_HW_XMAC_GEN_CFG_TX_HEAD_DROP_WHEN_FAULT    vxge_mBIT(7)
-#define        VXGE_HW_XMAC_GEN_CFG_FAULT_BEHAVIOUR    vxge_mBIT(27)
-#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_UP(val) vxge_vBIT(val, 28, 4)
-#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_DOWN(val) vxge_vBIT(val, 32, 4)
-/*0x01f48*/    u64     xmac_timestamp;
-#define        VXGE_HW_XMAC_TIMESTAMP_EN       vxge_mBIT(3)
-#define VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(val) vxge_vBIT(val, 6, 2)
-#define VXGE_HW_XMAC_TIMESTAMP_INTERVAL(val) vxge_vBIT(val, 12, 4)
-#define        VXGE_HW_XMAC_TIMESTAMP_TIMER_RESTART    vxge_mBIT(19)
-#define VXGE_HW_XMAC_TIMESTAMP_XMACJ_ROLLOVER_CNT(val) vxge_vBIT(val, 32, 16)
-/*0x01f50*/    u64     xmac_stats_gen_cfg;
-#define VXGE_HW_XMAC_STATS_GEN_CFG_PRTAGGR_CUM_TIMER(val) vxge_vBIT(val, 4, 4)
-#define VXGE_HW_XMAC_STATS_GEN_CFG_VPATH_CUM_TIMER(val) vxge_vBIT(val, 8, 4)
-#define        VXGE_HW_XMAC_STATS_GEN_CFG_VLAN_HANDLING        vxge_mBIT(15)
-/*0x01f58*/    u64     xmac_stats_sys_cmd;
-#define VXGE_HW_XMAC_STATS_SYS_CMD_OP(val) vxge_vBIT(val, 5, 3)
-#define        VXGE_HW_XMAC_STATS_SYS_CMD_STROBE       vxge_mBIT(15)
-#define VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(val) vxge_vBIT(val, 27, 5)
-#define VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8)
-/*0x01f60*/    u64     xmac_stats_sys_data;
-#define VXGE_HW_XMAC_STATS_SYS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64)
-       u8      unused01f80[0x01f80-0x01f68];
-
-/*0x01f80*/    u64     asic_ntwk_ctrl;
-#define        VXGE_HW_ASIC_NTWK_CTRL_REQ_TEST_NTWK    vxge_mBIT(3)
-#define        VXGE_HW_ASIC_NTWK_CTRL_PORT0_REQ_TEST_PORT      vxge_mBIT(11)
-#define        VXGE_HW_ASIC_NTWK_CTRL_PORT1_REQ_TEST_PORT      vxge_mBIT(15)
-/*0x01f88*/    u64     asic_ntwk_cfg_show_port_info;
-#define VXGE_HW_ASIC_NTWK_CFG_SHOW_PORT_INFO_VP(n)     vxge_mBIT(n)
-/*0x01f90*/    u64     asic_ntwk_cfg_port_num;
-#define VXGE_HW_ASIC_NTWK_CFG_PORT_NUM_VP(n)   vxge_mBIT(n)
-/*0x01f98*/    u64     xmac_cfg_port[3];
-#define        VXGE_HW_XMAC_CFG_PORT_XGMII_LOOPBACK    vxge_mBIT(3)
-#define        VXGE_HW_XMAC_CFG_PORT_XGMII_REVERSE_LOOPBACK    vxge_mBIT(7)
-#define        VXGE_HW_XMAC_CFG_PORT_XGMII_TX_BEHAV    vxge_mBIT(11)
-#define        VXGE_HW_XMAC_CFG_PORT_XGMII_RX_BEHAV    vxge_mBIT(15)
-/*0x01fb0*/    u64     xmac_station_addr_port[2];
-#define VXGE_HW_XMAC_STATION_ADDR_PORT_MAC_ADDR(val) vxge_vBIT(val, 0, 48)
-       u8      unused02020[0x02020-0x01fc0];
-
-/*0x02020*/    u64     lag_cfg;
-#define        VXGE_HW_LAG_CFG_EN      vxge_mBIT(3)
-#define VXGE_HW_LAG_CFG_MODE(val) vxge_vBIT(val, 6, 2)
-#define        VXGE_HW_LAG_CFG_TX_DISCARD_BEHAV        vxge_mBIT(11)
-#define        VXGE_HW_LAG_CFG_RX_DISCARD_BEHAV        vxge_mBIT(15)
-#define        VXGE_HW_LAG_CFG_PREF_INDIV_PORT_NUM     vxge_mBIT(19)
-/*0x02028*/    u64     lag_status;
-#define        VXGE_HW_LAG_STATUS_XLCM_WAITING_TO_FAILBACK     vxge_mBIT(3)
-#define VXGE_HW_LAG_STATUS_XLCM_TIMER_VAL_COLD_FAILOVER(val) \
-                                                       vxge_vBIT(val, 8, 8)
-/*0x02030*/    u64     lag_active_passive_cfg;
-#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_HOT_STANDBY      vxge_mBIT(3)
-#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_LACP_DECIDES     vxge_mBIT(7)
-#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_PREF_ACTIVE_PORT_NUM     vxge_mBIT(11)
-#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_AUTO_FAILBACK    vxge_mBIT(15)
-#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_FAILBACK_EN      vxge_mBIT(19)
-#define        VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_COLD_FAILOVER_TIMEOUT(val) \
-                                                       vxge_vBIT(val, 32, 16)
-       u8      unused02040[0x02040-0x02038];
-
-/*0x02040*/    u64     lag_lacp_cfg;
-#define        VXGE_HW_LAG_LACP_CFG_EN vxge_mBIT(3)
-#define        VXGE_HW_LAG_LACP_CFG_LACP_BEGIN vxge_mBIT(7)
-#define        VXGE_HW_LAG_LACP_CFG_DISCARD_LACP       vxge_mBIT(11)
-#define        VXGE_HW_LAG_LACP_CFG_LIBERAL_LEN_CHK    vxge_mBIT(15)
-/*0x02048*/    u64     lag_timer_cfg_1;
-#define VXGE_HW_LAG_TIMER_CFG_1_FAST_PER(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_LAG_TIMER_CFG_1_SLOW_PER(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_LAG_TIMER_CFG_1_SHORT_TIMEOUT(val) vxge_vBIT(val, 32, 16)
-#define VXGE_HW_LAG_TIMER_CFG_1_LONG_TIMEOUT(val) vxge_vBIT(val, 48, 16)
-/*0x02050*/    u64     lag_timer_cfg_2;
-#define VXGE_HW_LAG_TIMER_CFG_2_CHURN_DET(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_LAG_TIMER_CFG_2_AGGR_WAIT(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_LAG_TIMER_CFG_2_SHORT_TIMER_SCALE(val) vxge_vBIT(val, 32, 16)
-#define VXGE_HW_LAG_TIMER_CFG_2_LONG_TIMER_SCALE(val)  vxge_vBIT(val, 48, 16)
-/*0x02058*/    u64     lag_sys_id;
-#define VXGE_HW_LAG_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48)
-#define        VXGE_HW_LAG_SYS_ID_USE_PORT_ADDR        vxge_mBIT(51)
-#define        VXGE_HW_LAG_SYS_ID_ADDR_SEL     vxge_mBIT(55)
-/*0x02060*/    u64     lag_sys_cfg;
-#define VXGE_HW_LAG_SYS_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16)
-       u8      unused02070[0x02070-0x02068];
-
-/*0x02070*/    u64     lag_aggr_addr_cfg[2];
-#define VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR(val) vxge_vBIT(val, 0, 48)
-#define        VXGE_HW_LAG_AGGR_ADDR_CFG_USE_PORT_ADDR vxge_mBIT(51)
-#define        VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR_SEL      vxge_mBIT(55)
-/*0x02080*/    u64     lag_aggr_id_cfg[2];
-#define VXGE_HW_LAG_AGGR_ID_CFG_ID(val) vxge_vBIT(val, 0, 16)
-/*0x02090*/    u64     lag_aggr_admin_key[2];
-#define VXGE_HW_LAG_AGGR_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16)
-/*0x020a0*/    u64     lag_aggr_alt_admin_key;
-#define VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_ALT_AGGR vxge_mBIT(19)
-/*0x020a8*/    u64     lag_aggr_oper_key[2];
-#define VXGE_HW_LAG_AGGR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16)
-/*0x020b8*/    u64     lag_aggr_partner_sys_id[2];
-#define VXGE_HW_LAG_AGGR_PARTNER_SYS_ID_LAGC_ADDR(val) vxge_vBIT(val, 0, 48)
-/*0x020c8*/    u64     lag_aggr_partner_info[2];
-#define VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_SYS_PRI(val) vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_OPER_KEY(val) \
-                                               vxge_vBIT(val, 16, 16)
-/*0x020d8*/    u64     lag_aggr_state[2];
-#define        VXGE_HW_LAG_AGGR_STATE_LAGC_TX  vxge_mBIT(3)
-#define        VXGE_HW_LAG_AGGR_STATE_LAGC_RX  vxge_mBIT(7)
-#define        VXGE_HW_LAG_AGGR_STATE_LAGC_READY       vxge_mBIT(11)
-#define        VXGE_HW_LAG_AGGR_STATE_LAGC_INDIVIDUAL  vxge_mBIT(15)
-       u8      unused020f0[0x020f0-0x020e8];
-
-/*0x020f0*/    u64     lag_port_cfg[2];
-#define        VXGE_HW_LAG_PORT_CFG_EN vxge_mBIT(3)
-#define        VXGE_HW_LAG_PORT_CFG_DISCARD_SLOW_PROTO vxge_mBIT(7)
-#define        VXGE_HW_LAG_PORT_CFG_HOST_CHOSEN_AGGR   vxge_mBIT(11)
-#define        VXGE_HW_LAG_PORT_CFG_DISCARD_UNKNOWN_SLOW_PROTO vxge_mBIT(15)
-/*0x02100*/    u64     lag_port_actor_admin_cfg[2];
-#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_NUM(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_PRI(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_10G(val) vxge_vBIT(val, 32, 16)
-#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_1G(val) vxge_vBIT(val, 48, 16)
-/*0x02110*/    u64     lag_port_actor_admin_state[2];
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_ACTIVITY        vxge_mBIT(3)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_TIMEOUT vxge_mBIT(7)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_AGGREGATION  vxge_mBIT(11)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_SYNCHRONIZATION      vxge_mBIT(15)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_COLLECTING   vxge_mBIT(19)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DISTRIBUTING vxge_mBIT(23)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DEFAULTED    vxge_mBIT(27)
-#define        VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_EXPIRED      vxge_mBIT(31)
-/*0x02120*/    u64     lag_port_partner_admin_sys_id[2];
-#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48)
-/*0x02130*/    u64     lag_port_partner_admin_cfg[2];
-#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_KEY(val) vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_NUM(val) \
-                                                       vxge_vBIT(val, 32, 16)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_PRI(val) \
-                                                       vxge_vBIT(val, 48, 16)
-/*0x02140*/    u64     lag_port_partner_admin_state[2];
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_ACTIVITY      vxge_mBIT(3)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_TIMEOUT       vxge_mBIT(7)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_AGGREGATION        vxge_mBIT(11)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_SYNCHRONIZATION    vxge_mBIT(15)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_COLLECTING vxge_mBIT(19)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DISTRIBUTING       vxge_mBIT(23)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DEFAULTED  vxge_mBIT(27)
-#define        VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_EXPIRED    vxge_mBIT(31)
-/*0x02150*/    u64     lag_port_to_aggr[2];
-#define VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_ID(val) vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_VLD_ID       vxge_mBIT(19)
-/*0x02160*/    u64     lag_port_actor_oper_key[2];
-#define VXGE_HW_LAG_PORT_ACTOR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16)
-/*0x02170*/    u64     lag_port_actor_oper_state[2];
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_ACTIVITY    vxge_mBIT(3)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_TIMEOUT     vxge_mBIT(7)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_AGGREGATION      vxge_mBIT(11)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_SYNCHRONIZATION  vxge_mBIT(15)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_COLLECTING       vxge_mBIT(19)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DISTRIBUTING     vxge_mBIT(23)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DEFAULTED        vxge_mBIT(27)
-#define        VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_EXPIRED  vxge_mBIT(31)
-/*0x02180*/    u64     lag_port_partner_oper_sys_id[2];
-#define VXGE_HW_LAG_PORT_PARTNER_OPER_SYS_ID_LAGC_ADDR(val) \
-                                               vxge_vBIT(val, 0, 48)
-/*0x02190*/    u64     lag_port_partner_oper_info[2];
-#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_SYS_PRI(val) \
-                                               vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_KEY(val) \
-                                               vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_NUM(val) \
-                                               vxge_vBIT(val, 32, 16)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_PRI(val) \
-                                               vxge_vBIT(val, 48, 16)
-/*0x021a0*/    u64     lag_port_partner_oper_state[2];
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_ACTIVITY  vxge_mBIT(3)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_TIMEOUT   vxge_mBIT(7)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_AGGREGATION    vxge_mBIT(11)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_SYNCHRONIZATION \
-                                                               vxge_mBIT(15)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_COLLECTING     vxge_mBIT(19)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DISTRIBUTING   vxge_mBIT(23)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DEFAULTED      vxge_mBIT(27)
-#define        VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_EXPIRED        vxge_mBIT(31)
-/*0x021b0*/    u64     lag_port_state_vars[2];
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_READY  vxge_mBIT(3)
-#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_SELECTED(val) vxge_vBIT(val, 6, 2)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_AGGR_NUM       vxge_mBIT(11)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_MOVED     vxge_mBIT(15)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_ENABLED   vxge_mBIT(18)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_DISABLED  vxge_mBIT(19)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_NTT    vxge_mBIT(23)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN    vxge_mBIT(27)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN  vxge_mBIT(31)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_INFO_LEN_MISMATCH \
-                                                               vxge_mBIT(32)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_INFO_LEN_MISMATCH \
-                                                               vxge_mBIT(33)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_COLL_INFO_LEN_MISMATCH vxge_mBIT(34)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_TERM_INFO_LEN_MISMATCH vxge_mBIT(35)
-#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_RX_FSM_STATE(val) vxge_vBIT(val, 37, 3)
-#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_FSM_STATE(val) \
-                                                       vxge_vBIT(val, 41, 3)
-#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_REASON(val) vxge_vBIT(val, 44, 4)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_STATE      vxge_mBIT(54)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_STATE    vxge_mBIT(55)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_COUNT(val) \
-                                                       vxge_vBIT(val, 56, 4)
-#define        VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_COUNT(val) \
-                                                       vxge_vBIT(val, 60, 4)
-/*0x021c0*/    u64     lag_port_timer_cntr[2];
-#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_CURRENT_WHILE(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PERIODIC_WHILE(val) \
-                                                       vxge_vBIT(val, 8, 8)
-#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_WAIT_WHILE(val) vxge_vBIT(val, 16, 8)
-#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_TX_LACP(val) vxge_vBIT(val, 24, 8)
-#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_SYNC_TRANSITION_COUNT(val) \
-                                                       vxge_vBIT(val, 32, 8)
-#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_SYNC_TRANSITION_COUNT(val) \
-                                                       vxge_vBIT(val, 40, 8)
-#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_CHANGE_COUNT(val) \
-                                                       vxge_vBIT(val, 48, 8)
-#define        VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_CHANGE_COUNT(val) \
-                                                       vxge_vBIT(val, 56, 8)
-       u8      unused02208[0x02700-0x021d0];
-
-/*0x02700*/    u64     rtdma_int_status;
-#define        VXGE_HW_RTDMA_INT_STATUS_PDA_ALARM_PDA_INT      vxge_mBIT(1)
-#define        VXGE_HW_RTDMA_INT_STATUS_PCC_ERROR_PCC_INT      vxge_mBIT(2)
-#define        VXGE_HW_RTDMA_INT_STATUS_LSO_ERROR_LSO_INT      vxge_mBIT(4)
-#define        VXGE_HW_RTDMA_INT_STATUS_SM_ERROR_SM_INT        vxge_mBIT(5)
-/*0x02708*/    u64     rtdma_int_mask;
-/*0x02710*/    u64     pda_alarm_reg;
-#define        VXGE_HW_PDA_ALARM_REG_PDA_HSC_FIFO_ERR  vxge_mBIT(0)
-#define        VXGE_HW_PDA_ALARM_REG_PDA_SM_ERR        vxge_mBIT(1)
-/*0x02718*/    u64     pda_alarm_mask;
-/*0x02720*/    u64     pda_alarm_alarm;
-/*0x02728*/    u64     pcc_error_reg;
-#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_SBE(n)   vxge_mBIT(n)
-#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_SBE(n)      vxge_mBIT(n)
-#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_DBE(n)   vxge_mBIT(n)
-#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_DBE(n)      vxge_mBIT(n)
-#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FSM_ERR_ALARM(n) vxge_mBIT(n)
-#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_SERR(n)  vxge_mBIT(n)
-/*0x02730*/    u64     pcc_error_mask;
-/*0x02738*/    u64     pcc_error_alarm;
-/*0x02740*/    u64     lso_error_reg;
-#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_ABORT(n) vxge_mBIT(n)
-#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_FSM_ERR_ALARM(n) vxge_mBIT(n)
-/*0x02748*/    u64     lso_error_mask;
-/*0x02750*/    u64     lso_error_alarm;
-/*0x02758*/    u64     sm_error_reg;
-#define        VXGE_HW_SM_ERROR_REG_SM_FSM_ERR_ALARM   vxge_mBIT(15)
-/*0x02760*/    u64     sm_error_mask;
-/*0x02768*/    u64     sm_error_alarm;
-
-       u8      unused027a8[0x027a8-0x02770];
-
-/*0x027a8*/    u64     txd_ownership_ctrl;
-#define        VXGE_HW_TXD_OWNERSHIP_CTRL_KEEP_OWNERSHIP       vxge_mBIT(7)
-/*0x027b0*/    u64     pcc_cfg;
-#define VXGE_HW_PCC_CFG_PCC_ENABLE(n)  vxge_mBIT(n)
-#define VXGE_HW_PCC_CFG_PCC_ECC_ENABLE_N(n)    vxge_mBIT(n)
-/*0x027b8*/    u64     pcc_control;
-#define VXGE_HW_PCC_CONTROL_FE_ENABLE(val) vxge_vBIT(val, 6, 2)
-#define        VXGE_HW_PCC_CONTROL_EARLY_ASSIGN_EN     vxge_mBIT(15)
-#define        VXGE_HW_PCC_CONTROL_UNBLOCK_DB_ERR      vxge_mBIT(31)
-/*0x027c0*/    u64     pda_status1;
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_0_CTR(val) vxge_vBIT(val, 4, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_1_CTR(val) vxge_vBIT(val, 12, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_2_CTR(val) vxge_vBIT(val, 20, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_3_CTR(val) vxge_vBIT(val, 28, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_4_CTR(val) vxge_vBIT(val, 36, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_5_CTR(val) vxge_vBIT(val, 44, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_6_CTR(val) vxge_vBIT(val, 52, 4)
-#define VXGE_HW_PDA_STATUS1_PDA_WRAP_7_CTR(val) vxge_vBIT(val, 60, 4)
-/*0x027c8*/    u64     rtdma_bw_timer;
-#define VXGE_HW_RTDMA_BW_TIMER_TIMER_CTRL(val) vxge_vBIT(val, 12, 4)
-
-       u8      unused02900[0x02900-0x027d0];
-/*0x02900*/    u64     g3cmct_int_status;
-#define        VXGE_HW_G3CMCT_INT_STATUS_ERR_G3IF_INT  vxge_mBIT(0)
-/*0x02908*/    u64     g3cmct_int_mask;
-/*0x02910*/    u64     g3cmct_err_reg;
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_SM_ERR      vxge_mBIT(4)
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_DECC  vxge_mBIT(5)
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_DECC        vxge_mBIT(6)
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_DECC      vxge_mBIT(7)
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_SECC  vxge_mBIT(29)
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_SECC        vxge_mBIT(30)
-#define        VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_SECC      vxge_mBIT(31)
-/*0x02918*/    u64     g3cmct_err_mask;
-/*0x02920*/    u64     g3cmct_err_alarm;
-       u8      unused03000[0x03000-0x02928];
-
-/*0x03000*/    u64     mc_int_status;
-#define        VXGE_HW_MC_INT_STATUS_MC_ERR_MC_INT     vxge_mBIT(3)
-#define        VXGE_HW_MC_INT_STATUS_GROCRC_ALARM_ROCRC_INT    vxge_mBIT(7)
-#define        VXGE_HW_MC_INT_STATUS_FAU_GEN_ERR_FAU_GEN_INT   vxge_mBIT(11)
-#define        VXGE_HW_MC_INT_STATUS_FAU_ECC_ERR_FAU_ECC_INT   vxge_mBIT(15)
-/*0x03008*/    u64     mc_int_mask;
-/*0x03010*/    u64     mc_err_reg;
-#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_A     vxge_mBIT(3)
-#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_B     vxge_mBIT(4)
-#define        VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_SG_ERR   vxge_mBIT(5)
-#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_0 vxge_mBIT(6)
-#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_1 vxge_mBIT(7)
-#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_A     vxge_mBIT(10)
-#define        VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_B     vxge_mBIT(11)
-#define        VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_DB_ERR   vxge_mBIT(12)
-#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_0 vxge_mBIT(13)
-#define        VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_1 vxge_mBIT(14)
-#define        VXGE_HW_MC_ERR_REG_MC_SM_ERR    vxge_mBIT(15)
-/*0x03018*/    u64     mc_err_mask;
-/*0x03020*/    u64     mc_err_alarm;
-/*0x03028*/    u64     grocrc_alarm_reg;
-#define        VXGE_HW_GROCRC_ALARM_REG_XFMD_WR_FIFO_ERR       vxge_mBIT(3)
-#define        VXGE_HW_GROCRC_ALARM_REG_WDE2MSR_RD_FIFO_ERR    vxge_mBIT(7)
-/*0x03030*/    u64     grocrc_alarm_mask;
-/*0x03038*/    u64     grocrc_alarm_alarm;
-       u8      unused03100[0x03100-0x03040];
-
-/*0x03100*/    u64     rx_thresh_cfg_repl;
-#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_0(val) vxge_vBIT(val, 16, 8)
-#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_1(val) vxge_vBIT(val, 24, 8)
-#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_2(val) vxge_vBIT(val, 32, 8)
-#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_3(val) vxge_vBIT(val, 40, 8)
-#define        VXGE_HW_RX_THRESH_CFG_REPL_GLOBAL_WOL_EN        vxge_mBIT(62)
-#define        VXGE_HW_RX_THRESH_CFG_REPL_EXACT_VP_MATCH_REQ   vxge_mBIT(63)
-       u8      unused033b8[0x033b8-0x03108];
-
-/*0x033b8*/    u64     fbmc_ecc_cfg;
-#define VXGE_HW_FBMC_ECC_CFG_ENABLE(val) vxge_vBIT(val, 3, 5)
-       u8      unused03400[0x03400-0x033c0];
-
-/*0x03400*/    u64     pcipif_int_status;
-#define        VXGE_HW_PCIPIF_INT_STATUS_DBECC_ERR_DBECC_ERR_INT       vxge_mBIT(3)
-#define        VXGE_HW_PCIPIF_INT_STATUS_SBECC_ERR_SBECC_ERR_INT       vxge_mBIT(7)
-#define        VXGE_HW_PCIPIF_INT_STATUS_GENERAL_ERR_GENERAL_ERR_INT   vxge_mBIT(11)
-#define        VXGE_HW_PCIPIF_INT_STATUS_SRPCIM_MSG_SRPCIM_MSG_INT     vxge_mBIT(15)
-#define        VXGE_HW_PCIPIF_INT_STATUS_MRPCIM_SPARE_R1_MRPCIM_SPARE_R1_INT \
-                                                               vxge_mBIT(19)
-/*0x03408*/    u64     pcipif_int_mask;
-/*0x03410*/    u64     dbecc_err_reg;
-#define        VXGE_HW_DBECC_ERR_REG_PCI_RETRY_BUF_DB_ERR      vxge_mBIT(3)
-#define        VXGE_HW_DBECC_ERR_REG_PCI_RETRY_SOT_DB_ERR      vxge_mBIT(7)
-#define        VXGE_HW_DBECC_ERR_REG_PCI_P_HDR_DB_ERR  vxge_mBIT(11)
-#define        VXGE_HW_DBECC_ERR_REG_PCI_P_DATA_DB_ERR vxge_mBIT(15)
-#define        VXGE_HW_DBECC_ERR_REG_PCI_NP_HDR_DB_ERR vxge_mBIT(19)
-#define        VXGE_HW_DBECC_ERR_REG_PCI_NP_DATA_DB_ERR        vxge_mBIT(23)
-/*0x03418*/    u64     dbecc_err_mask;
-/*0x03420*/    u64     dbecc_err_alarm;
-/*0x03428*/    u64     sbecc_err_reg;
-#define        VXGE_HW_SBECC_ERR_REG_PCI_RETRY_BUF_SG_ERR      vxge_mBIT(3)
-#define        VXGE_HW_SBECC_ERR_REG_PCI_RETRY_SOT_SG_ERR      vxge_mBIT(7)
-#define        VXGE_HW_SBECC_ERR_REG_PCI_P_HDR_SG_ERR  vxge_mBIT(11)
-#define        VXGE_HW_SBECC_ERR_REG_PCI_P_DATA_SG_ERR vxge_mBIT(15)
-#define        VXGE_HW_SBECC_ERR_REG_PCI_NP_HDR_SG_ERR vxge_mBIT(19)
-#define        VXGE_HW_SBECC_ERR_REG_PCI_NP_DATA_SG_ERR        vxge_mBIT(23)
-/*0x03430*/    u64     sbecc_err_mask;
-/*0x03438*/    u64     sbecc_err_alarm;
-/*0x03440*/    u64     general_err_reg;
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_DROPPED_ILLEGAL_CFG vxge_mBIT(3)
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_ILLEGAL_MEM_MAP_PROG        vxge_mBIT(7)
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_LINK_RST_FSM_ERR    vxge_mBIT(11)
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_RX_ILLEGAL_TLP_VPLANE       vxge_mBIT(15)
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_TRAINING_RESET_DET  vxge_mBIT(19)
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_PCI_LINK_DOWN_DET   vxge_mBIT(23)
-#define        VXGE_HW_GENERAL_ERR_REG_PCI_RESET_ACK_DLLP      vxge_mBIT(27)
-/*0x03448*/    u64     general_err_mask;
-/*0x03450*/    u64     general_err_alarm;
-/*0x03458*/    u64     srpcim_msg_reg;
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE0_RMSG_INT \
-                                                               vxge_mBIT(0)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE1_RMSG_INT \
-                                                               vxge_mBIT(1)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE2_RMSG_INT \
-                                                               vxge_mBIT(2)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE3_RMSG_INT \
-                                                               vxge_mBIT(3)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE4_RMSG_INT \
-                                                               vxge_mBIT(4)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE5_RMSG_INT \
-                                                               vxge_mBIT(5)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE6_RMSG_INT \
-                                                               vxge_mBIT(6)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE7_RMSG_INT \
-                                                               vxge_mBIT(7)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE8_RMSG_INT \
-                                                               vxge_mBIT(8)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE9_RMSG_INT \
-                                                               vxge_mBIT(9)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE10_RMSG_INT \
-                                                               vxge_mBIT(10)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE11_RMSG_INT \
-                                                               vxge_mBIT(11)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE12_RMSG_INT \
-                                                               vxge_mBIT(12)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE13_RMSG_INT \
-                                                               vxge_mBIT(13)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE14_RMSG_INT \
-                                                               vxge_mBIT(14)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE15_RMSG_INT \
-                                                               vxge_mBIT(15)
-#define        VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE16_RMSG_INT \
-                                                               vxge_mBIT(16)
-/*0x03460*/    u64     srpcim_msg_mask;
-/*0x03468*/    u64     srpcim_msg_alarm;
-       u8      unused03600[0x03600-0x03470];
-
-/*0x03600*/    u64     gcmg1_int_status;
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSCC_ERR_GSSCC_INT    vxge_mBIT(0)
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR0_GSSC0_0_INT vxge_mBIT(1)
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR1_GSSC0_1_INT vxge_mBIT(2)
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR0_GSSC1_0_INT vxge_mBIT(3)
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR1_GSSC1_1_INT vxge_mBIT(4)
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR0_GSSC2_0_INT vxge_mBIT(5)
-#define        VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR1_GSSC2_1_INT vxge_mBIT(6)
-#define        VXGE_HW_GCMG1_INT_STATUS_UQM_ERR_UQM_INT        vxge_mBIT(7)
-#define        VXGE_HW_GCMG1_INT_STATUS_GQCC_ERR_GQCC_INT      vxge_mBIT(8)
-/*0x03608*/    u64     gcmg1_int_mask;
-       u8      unused03a00[0x03a00-0x03610];
-
-/*0x03a00*/    u64     pcmg1_int_status;
-#define        VXGE_HW_PCMG1_INT_STATUS_PSSCC_ERR_PSSCC_INT    vxge_mBIT(0)
-#define        VXGE_HW_PCMG1_INT_STATUS_PQCC_ERR_PQCC_INT      vxge_mBIT(1)
-#define        VXGE_HW_PCMG1_INT_STATUS_PQCC_CQM_ERR_PQCC_CQM_INT      vxge_mBIT(2)
-#define        VXGE_HW_PCMG1_INT_STATUS_PQCC_SQM_ERR_PQCC_SQM_INT      vxge_mBIT(3)
-/*0x03a08*/    u64     pcmg1_int_mask;
-       u8      unused04000[0x04000-0x03a10];
-
-/*0x04000*/    u64     one_int_status;
-#define        VXGE_HW_ONE_INT_STATUS_RXPE_ERR_RXPE_INT        vxge_mBIT(7)
-#define        VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_SG_ECC_ERR_TXPE_BCC_MEM_SG_ECC_INT \
-                                                       vxge_mBIT(13)
-#define        VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_DB_ECC_ERR_TXPE_BCC_MEM_DB_ECC_INT \
-                                                       vxge_mBIT(14)
-#define        VXGE_HW_ONE_INT_STATUS_TXPE_ERR_TXPE_INT        vxge_mBIT(15)
-#define        VXGE_HW_ONE_INT_STATUS_DLM_ERR_DLM_INT  vxge_mBIT(23)
-#define        VXGE_HW_ONE_INT_STATUS_PE_ERR_PE_INT    vxge_mBIT(31)
-#define        VXGE_HW_ONE_INT_STATUS_RPE_ERR_RPE_INT  vxge_mBIT(39)
-#define        VXGE_HW_ONE_INT_STATUS_RPE_FSM_ERR_RPE_FSM_INT  vxge_mBIT(47)
-#define        VXGE_HW_ONE_INT_STATUS_OES_ERR_OES_INT  vxge_mBIT(55)
-/*0x04008*/    u64     one_int_mask;
-       u8      unused04818[0x04818-0x04010];
-
-/*0x04818*/    u64     noa_wct_ctrl;
-#define        VXGE_HW_NOA_WCT_CTRL_VP_INT_NUM vxge_mBIT(0)
-/*0x04820*/    u64     rc_cfg2;
-#define VXGE_HW_RC_CFG2_BUFF1_SIZE(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_RC_CFG2_BUFF2_SIZE(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_RC_CFG2_BUFF3_SIZE(val) vxge_vBIT(val, 32, 16)
-#define VXGE_HW_RC_CFG2_BUFF4_SIZE(val) vxge_vBIT(val, 48, 16)
-/*0x04828*/    u64     rc_cfg3;
-#define VXGE_HW_RC_CFG3_BUFF5_SIZE(val) vxge_vBIT(val, 0, 16)
-/*0x04830*/    u64     rx_multi_cast_ctrl1;
-#define        VXGE_HW_RX_MULTI_CAST_CTRL1_ENABLE      vxge_mBIT(7)
-#define VXGE_HW_RX_MULTI_CAST_CTRL1_DELAY_COUNT(val) vxge_vBIT(val, 11, 5)
-/*0x04838*/    u64     rxdm_dbg_rd;
-#define VXGE_HW_RXDM_DBG_RD_ADDR(val) vxge_vBIT(val, 0, 12)
-#define        VXGE_HW_RXDM_DBG_RD_ENABLE      vxge_mBIT(31)
-/*0x04840*/    u64     rxdm_dbg_rd_data;
-#define VXGE_HW_RXDM_DBG_RD_DATA_RMC_RXDM_DBG_RD_DATA(val) vxge_vBIT(val, 0, 64)
-/*0x04848*/    u64     rqa_top_prty_for_vh[17];
-#define VXGE_HW_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \
-                                                       vxge_vBIT(val, 59, 5)
-       u8      unused04900[0x04900-0x048d0];
-
-/*0x04900*/    u64     tim_status;
-#define        VXGE_HW_TIM_STATUS_TIM_RESET_IN_PROGRESS        vxge_mBIT(0)
-/*0x04908*/    u64     tim_ecc_enable;
-#define        VXGE_HW_TIM_ECC_ENABLE_VBLS_N   vxge_mBIT(7)
-#define        VXGE_HW_TIM_ECC_ENABLE_BMAP_N   vxge_mBIT(15)
-#define        VXGE_HW_TIM_ECC_ENABLE_BMAP_MSG_N       vxge_mBIT(23)
-/*0x04910*/    u64     tim_bp_ctrl;
-#define        VXGE_HW_TIM_BP_CTRL_RD_XON      vxge_mBIT(7)
-#define        VXGE_HW_TIM_BP_CTRL_WR_XON      vxge_mBIT(15)
-#define        VXGE_HW_TIM_BP_CTRL_ROCRC_BYP   vxge_mBIT(23)
-/*0x04918*/    u64     tim_resource_assignment_vh[17];
-#define VXGE_HW_TIM_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
-/*0x049a0*/    u64     tim_bmap_mapping_vp_err[17];
-#define VXGE_HW_TIM_BMAP_MAPPING_VP_ERR_TIM_DEST_VPATH(val) vxge_vBIT(val, 3, 5)
-       u8      unused04b00[0x04b00-0x04a28];
-
-/*0x04b00*/    u64     gcmg2_int_status;
-#define        VXGE_HW_GCMG2_INT_STATUS_GXTMC_ERR_GXTMC_INT    vxge_mBIT(7)
-#define        VXGE_HW_GCMG2_INT_STATUS_GCP_ERR_GCP_INT        vxge_mBIT(15)
-#define        VXGE_HW_GCMG2_INT_STATUS_CMC_ERR_CMC_INT        vxge_mBIT(23)
-/*0x04b08*/    u64     gcmg2_int_mask;
-/*0x04b10*/    u64     gxtmc_err_reg;
-#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_DB_ERR(val) vxge_vBIT(val, 0, 4)
-#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_SG_ERR(val) vxge_vBIT(val, 4, 4)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMC_RD_DATA_DB_ERR   vxge_mBIT(8)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_FIFO_ERR vxge_mBIT(9)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR    vxge_mBIT(10)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR      vxge_mBIT(11)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR      vxge_mBIT(12)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_FIFO_ERR     vxge_mBIT(13)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_ERR  vxge_mBIT(14)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_FIFO_ERR     vxge_mBIT(15)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_ERR  vxge_mBIT(16)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_DATA_SM_ERR      vxge_mBIT(17)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_CMC0_IF_ERR      vxge_mBIT(18)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_ARB_SM_ERR   vxge_mBIT(19)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_CFC_SM_ERR   vxge_mBIT(20)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_OVERFLOW \
-                                                       vxge_mBIT(21)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_UNDERFLOW \
-                                                       vxge_mBIT(22)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_SM_ERR        vxge_mBIT(23)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_OVERFLOW \
-                                                       vxge_mBIT(24)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_UNDERFLOW \
-                                                       vxge_mBIT(25)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_SM_ERR vxge_mBIT(26)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_SM_ERR        vxge_mBIT(27)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_TAG_ERR       vxge_mBIT(28)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_SM_ERR  vxge_mBIT(29)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_FIFO_ERR        vxge_mBIT(30)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_POP_ERR vxge_mBIT(31)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_CMI_OP_ERR  vxge_mBIT(32)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFETCH_OP_ERR       vxge_mBIT(33)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFIFO_ERR   vxge_mBIT(34)
-#define        VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_ARB_SM_ERR       vxge_mBIT(35)
-/*0x04b18*/    u64     gxtmc_err_mask;
-/*0x04b20*/    u64     gxtmc_err_alarm;
-/*0x04b28*/    u64     cmc_err_reg;
-#define        VXGE_HW_CMC_ERR_REG_CMC_CMC_SM_ERR      vxge_mBIT(0)
-/*0x04b30*/    u64     cmc_err_mask;
-/*0x04b38*/    u64     cmc_err_alarm;
-/*0x04b40*/    u64     gcp_err_reg;
-#define        VXGE_HW_GCP_ERR_REG_CP_H2L2CP_FIFO_ERR  vxge_mBIT(0)
-#define        VXGE_HW_GCP_ERR_REG_CP_STC2CP_FIFO_ERR  vxge_mBIT(1)
-#define        VXGE_HW_GCP_ERR_REG_CP_STE2CP_FIFO_ERR  vxge_mBIT(2)
-#define        VXGE_HW_GCP_ERR_REG_CP_TTE2CP_FIFO_ERR  vxge_mBIT(3)
-/*0x04b48*/    u64     gcp_err_mask;
-/*0x04b50*/    u64     gcp_err_alarm;
-       u8      unused04f00[0x04f00-0x04b58];
-
-/*0x04f00*/    u64     pcmg2_int_status;
-#define        VXGE_HW_PCMG2_INT_STATUS_PXTMC_ERR_PXTMC_INT    vxge_mBIT(7)
-#define        VXGE_HW_PCMG2_INT_STATUS_CP_EXC_CP_XT_EXC_INT   vxge_mBIT(15)
-#define        VXGE_HW_PCMG2_INT_STATUS_CP_ERR_CP_ERR_INT      vxge_mBIT(23)
-/*0x04f08*/    u64     pcmg2_int_mask;
-/*0x04f10*/    u64     pxtmc_err_reg;
-#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_DB_ERR(val) vxge_vBIT(val, 0, 2)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FIFO_ERR     vxge_mBIT(2)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_PRSP_FIFO_ERR    vxge_mBIT(3)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_WRSP_FIFO_ERR    vxge_mBIT(4)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FIFO_ERR     vxge_mBIT(5)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_PRSP_FIFO_ERR    vxge_mBIT(6)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_WRSP_FIFO_ERR    vxge_mBIT(7)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FIFO_ERR     vxge_mBIT(8)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_PRSP_FIFO_ERR    vxge_mBIT(9)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_WRSP_FIFO_ERR    vxge_mBIT(10)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_FIFO_ERR vxge_mBIT(11)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR    vxge_mBIT(12)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR      vxge_mBIT(13)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR      vxge_mBIT(14)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_SHADOW_ERR   vxge_mBIT(15)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_SHADOW_ERR   vxge_mBIT(16)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_SHADOW_ERR   vxge_mBIT(17)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_SHADOW_ERR   vxge_mBIT(18)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_SHADOW_ERR   vxge_mBIT(19)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_SHADOW_ERR   vxge_mBIT(20)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_SHADOW_ERR       vxge_mBIT(21)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_SHADOW_ERR       vxge_mBIT(22)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_RAM_SHADOW_ERR       vxge_mBIT(23)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_SHADOW_ERR       vxge_mBIT(24)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_SHADOW_ERR       vxge_mBIT(25)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FSM_ERR      vxge_mBIT(26)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_FSM_ERR      vxge_mBIT(27)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FSM_ERR      vxge_mBIT(28)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_FSM_ERR      vxge_mBIT(29)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FSM_ERR      vxge_mBIT(30)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_FSM_ERR      vxge_mBIT(31)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_FSM_ERR  vxge_mBIT(32)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_FSM_ERR  vxge_mBIT(33)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_FSM_ERR  vxge_mBIT(34)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_FSM_ERR  vxge_mBIT(35)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_ERR      vxge_mBIT(36)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_ERR      vxge_mBIT(37)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_ERR      vxge_mBIT(38)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_ERR      vxge_mBIT(39)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_ERR      vxge_mBIT(40)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_ERR      vxge_mBIT(41)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_ERR     vxge_mBIT(42)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_ERR     vxge_mBIT(43)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_ERR     vxge_mBIT(44)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_INFO_ERR vxge_mBIT(45)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_INFO_ERR vxge_mBIT(46)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_INFO_ERR vxge_mBIT(47)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_INFO_ERR vxge_mBIT(48)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_INFO_ERR vxge_mBIT(49)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_INFO_ERR vxge_mBIT(50)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_INFO_ERR        vxge_mBIT(51)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_INFO_ERR        vxge_mBIT(52)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_INFO_ERR        vxge_mBIT(53)
-#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_SG_ERR(val) vxge_vBIT(val, 54, 2)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_DFIFO_PUSH_ERR        vxge_mBIT(56)
-#define        VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_PUSH_ERR        vxge_mBIT(57)
-/*0x04f18*/    u64     pxtmc_err_mask;
-/*0x04f20*/    u64     pxtmc_err_alarm;
-/*0x04f28*/    u64     cp_err_reg;
-#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_SG_ERR(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_SG_ERR(val) vxge_vBIT(val, 8, 2)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_DTAG_SG_ERR    vxge_mBIT(10)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_ITAG_SG_ERR    vxge_mBIT(11)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_TRACE_SG_ERR   vxge_mBIT(12)
-#define        VXGE_HW_CP_ERR_REG_CP_DMA2CP_SG_ERR     vxge_mBIT(13)
-#define        VXGE_HW_CP_ERR_REG_CP_MP2CP_SG_ERR      vxge_mBIT(14)
-#define        VXGE_HW_CP_ERR_REG_CP_QCC2CP_SG_ERR     vxge_mBIT(15)
-#define VXGE_HW_CP_ERR_REG_CP_STC2CP_SG_ERR(val) vxge_vBIT(val, 16, 2)
-#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_DB_ERR(val) vxge_vBIT(val, 24, 8)
-#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_DB_ERR(val) vxge_vBIT(val, 32, 2)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_DTAG_DB_ERR    vxge_mBIT(34)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_ITAG_DB_ERR    vxge_mBIT(35)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_TRACE_DB_ERR   vxge_mBIT(36)
-#define        VXGE_HW_CP_ERR_REG_CP_DMA2CP_DB_ERR     vxge_mBIT(37)
-#define        VXGE_HW_CP_ERR_REG_CP_MP2CP_DB_ERR      vxge_mBIT(38)
-#define        VXGE_HW_CP_ERR_REG_CP_QCC2CP_DB_ERR     vxge_mBIT(39)
-#define VXGE_HW_CP_ERR_REG_CP_STC2CP_DB_ERR(val) vxge_vBIT(val, 40, 2)
-#define        VXGE_HW_CP_ERR_REG_CP_H2L2CP_FIFO_ERR   vxge_mBIT(48)
-#define        VXGE_HW_CP_ERR_REG_CP_STC2CP_FIFO_ERR   vxge_mBIT(49)
-#define        VXGE_HW_CP_ERR_REG_CP_STE2CP_FIFO_ERR   vxge_mBIT(50)
-#define        VXGE_HW_CP_ERR_REG_CP_TTE2CP_FIFO_ERR   vxge_mBIT(51)
-#define        VXGE_HW_CP_ERR_REG_CP_SWIF2CP_FIFO_ERR  vxge_mBIT(52)
-#define        VXGE_HW_CP_ERR_REG_CP_CP2DMA_FIFO_ERR   vxge_mBIT(53)
-#define        VXGE_HW_CP_ERR_REG_CP_DAM2CP_FIFO_ERR   vxge_mBIT(54)
-#define        VXGE_HW_CP_ERR_REG_CP_MP2CP_FIFO_ERR    vxge_mBIT(55)
-#define        VXGE_HW_CP_ERR_REG_CP_QCC2CP_FIFO_ERR   vxge_mBIT(56)
-#define        VXGE_HW_CP_ERR_REG_CP_DMA2CP_FIFO_ERR   vxge_mBIT(57)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_WAKE_FSM_INTEGRITY_ERR vxge_mBIT(60)
-#define        VXGE_HW_CP_ERR_REG_CP_CP_PMON_FSM_INTEGRITY_ERR vxge_mBIT(61)
-#define        VXGE_HW_CP_ERR_REG_CP_DMA_RD_SHADOW_ERR vxge_mBIT(62)
-#define        VXGE_HW_CP_ERR_REG_CP_PIFT_CREDIT_ERR   vxge_mBIT(63)
-/*0x04f30*/    u64     cp_err_mask;
-/*0x04f38*/    u64     cp_err_alarm;
-       u8      unused04fe8[0x04f50-0x04f40];
-
-/*0x04f50*/    u64     cp_exc_reg;
-#define        VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_INFO_INT vxge_mBIT(47)
-#define        VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_CRIT_INT vxge_mBIT(55)
-#define        VXGE_HW_CP_EXC_REG_CP_CP_SERR   vxge_mBIT(63)
-/*0x04f58*/    u64     cp_exc_mask;
-/*0x04f60*/    u64     cp_exc_alarm;
-/*0x04f68*/    u64     cp_exc_cause;
-#define VXGE_HW_CP_EXC_CAUSE_CP_CP_CAUSE(val) vxge_vBIT(val, 32, 32)
-       u8      unused05200[0x05200-0x04f70];
-
-/*0x05200*/    u64     msg_int_status;
-#define        VXGE_HW_MSG_INT_STATUS_TIM_ERR_TIM_INT  vxge_mBIT(7)
-#define        VXGE_HW_MSG_INT_STATUS_MSG_EXC_MSG_XT_EXC_INT   vxge_mBIT(60)
-#define        VXGE_HW_MSG_INT_STATUS_MSG_ERR3_MSG_ERR3_INT    vxge_mBIT(61)
-#define        VXGE_HW_MSG_INT_STATUS_MSG_ERR2_MSG_ERR2_INT    vxge_mBIT(62)
-#define        VXGE_HW_MSG_INT_STATUS_MSG_ERR_MSG_ERR_INT      vxge_mBIT(63)
-/*0x05208*/    u64     msg_int_mask;
-/*0x05210*/    u64     tim_err_reg;
-#define        VXGE_HW_TIM_ERR_REG_TIM_VBLS_SG_ERR     vxge_mBIT(4)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_SG_ERR  vxge_mBIT(5)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_SG_ERR  vxge_mBIT(6)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_SG_ERR vxge_mBIT(7)
-#define        VXGE_HW_TIM_ERR_REG_TIM_VBLS_DB_ERR     vxge_mBIT(12)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_DB_ERR  vxge_mBIT(13)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_DB_ERR  vxge_mBIT(14)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_DB_ERR vxge_mBIT(15)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MEM_CNTRL_SM_ERR   vxge_mBIT(18)
-#define        VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_MEM_CNTRL_SM_ERR       vxge_mBIT(19)
-#define        VXGE_HW_TIM_ERR_REG_TIM_MPIF_PCIWR_ERR  vxge_mBIT(20)
-#define        VXGE_HW_TIM_ERR_REG_TIM_ROCRC_BMAP_UPDT_FIFO_ERR        vxge_mBIT(22)
-#define        VXGE_HW_TIM_ERR_REG_TIM_CREATE_BMAPMSG_FIFO_ERR vxge_mBIT(23)
-#define        VXGE_HW_TIM_ERR_REG_TIM_ROCRCIF_MISMATCH        vxge_mBIT(46)
-#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MAPPING_VP_ERR(n) vxge_mBIT(n)
-/*0x05218*/    u64     tim_err_mask;
-/*0x05220*/    u64     tim_err_alarm;
-/*0x05228*/    u64     msg_err_reg;
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_WAKE_FSM_INTEGRITY_ERR       vxge_mBIT(0)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_WAKE_FSM_INTEGRITY_ERR       vxge_mBIT(1)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_READ_CMD_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(2)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_RESP_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(3)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_OWN_FSM_INTEGRITY_ERR   vxge_mBIT(4)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_PDA_ACC_FSM_INTEGRITY_ERR   vxge_mBIT(5)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_PMON_FSM_INTEGRITY_ERR       vxge_mBIT(6)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_PMON_FSM_INTEGRITY_ERR       vxge_mBIT(7)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_SG_ERR  vxge_mBIT(8)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_SG_ERR  vxge_mBIT(10)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_SG_ERR  vxge_mBIT(12)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_SG_ERR  vxge_mBIT(14)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_SG_ERR vxge_mBIT(16)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_SG_ERR vxge_mBIT(17)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_SG_ERR      vxge_mBIT(18)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_SG_ERR     vxge_mBIT(19)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_SG_ERR     vxge_mBIT(20)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_SG_ERR      vxge_mBIT(21)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_SG_ERR  vxge_mBIT(26)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_SG_ERR       vxge_mBIT(27)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_SG_ERR      vxge_mBIT(29)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_SG_ERR vxge_mBIT(31)
-#define        VXGE_HW_MSG_ERR_REG_MSG_XFMDQRY_FSM_INTEGRITY_ERR       vxge_mBIT(33)
-#define        VXGE_HW_MSG_ERR_REG_MSG_FRMQRY_FSM_INTEGRITY_ERR        vxge_mBIT(34)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_WRITE_FSM_INTEGRITY_ERR vxge_mBIT(35)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_BWR_PF_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(36)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_RESP_FIFO_ERR   vxge_mBIT(38)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_DB_ERR  vxge_mBIT(39)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_DB_ERR  vxge_mBIT(41)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_DB_ERR  vxge_mBIT(43)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_DB_ERR  vxge_mBIT(45)
-#define        VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_DB_ERR vxge_mBIT(47)
-#define        VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_DB_ERR vxge_mBIT(48)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_DB_ERR      vxge_mBIT(49)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_DB_ERR     vxge_mBIT(50)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_DB_ERR     vxge_mBIT(51)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_DB_ERR      vxge_mBIT(52)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_READ_FIFO_ERR   vxge_mBIT(53)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_MXP2UXP_FIFO_ERR    vxge_mBIT(54)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_KDFC_SIF_FIFO_ERR   vxge_mBIT(55)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_CXP2SWIF_FIFO_ERR   vxge_mBIT(56)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_DB_ERR  vxge_mBIT(57)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_DB_ERR       vxge_mBIT(58)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_SIF_FIFO_ERR    vxge_mBIT(59)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_DB_ERR      vxge_mBIT(60)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_READ_FIFO_ERR   vxge_mBIT(61)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_DB_ERR vxge_mBIT(62)
-#define        VXGE_HW_MSG_ERR_REG_MSG_QUE_UXP2MXP_FIFO_ERR    vxge_mBIT(63)
-/*0x05230*/    u64     msg_err_mask;
-/*0x05238*/    u64     msg_err_alarm;
-       u8      unused05340[0x05340-0x05240];
-
-/*0x05340*/    u64     msg_exc_reg;
-#define        VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_INFO_INT       vxge_mBIT(50)
-#define        VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_CRIT_INT       vxge_mBIT(51)
-#define        VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_INFO_INT       vxge_mBIT(54)
-#define        VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_CRIT_INT       vxge_mBIT(55)
-#define        VXGE_HW_MSG_EXC_REG_MP_MXP_SERR vxge_mBIT(62)
-#define        VXGE_HW_MSG_EXC_REG_UP_UXP_SERR vxge_mBIT(63)
-/*0x05348*/    u64     msg_exc_mask;
-/*0x05350*/    u64     msg_exc_alarm;
-/*0x05358*/    u64     msg_exc_cause;
-#define VXGE_HW_MSG_EXC_CAUSE_MP_MXP(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_MSG_EXC_CAUSE_UP_UXP(val) vxge_vBIT(val, 32, 32)
-       u8      unused05368[0x05380-0x05360];
-
-/*0x05380*/    u64     msg_err2_reg;
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_CMG2MSG_DISPATCH_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(0)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMQ_DISPATCH_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(1)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_DISPATCH_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(2)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_PIC_WRITE_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(3)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIFREG_FSM_INTEGRITY_ERR  vxge_mBIT(4)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_TIM_WRITE_FSM_INTEGRITY_ERR \
-                                                               vxge_mBIT(5)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ_TA_FSM_INTEGRITY_ERR   vxge_mBIT(6)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE_TA_FSM_INTEGRITY_ERR  vxge_mBIT(7)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE_TA_FSM_INTEGRITY_ERR  vxge_mBIT(8)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_TA_FSM_INTEGRITY_ERR  vxge_mBIT(9)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMA_TA_FSM_INTEGRITY_ERR   vxge_mBIT(10)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_CP_TA_FSM_INTEGRITY_ERR    vxge_mBIT(11)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA16_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(12)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA15_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(13)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA14_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(14)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA13_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(15)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA12_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(16)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA11_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(17)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA10_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(18)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA9_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(19)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA8_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(20)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA7_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(21)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA6_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(22)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA5_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(23)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA4_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(24)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA3_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(25)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA2_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(26)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA1_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(27)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA0_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(28)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_FBMC_OWN_FSM_INTEGRITY_ERR vxge_mBIT(29)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(30)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(31)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_RPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \
-                                                       vxge_mBIT(32)
-#define        VXGE_HW_MSG_ERR2_REG_MP_MP_PIFT_IF_CREDIT_CNT_ERR       vxge_mBIT(33)
-#define        VXGE_HW_MSG_ERR2_REG_UP_UP_PIFT_IF_CREDIT_CNT_ERR       vxge_mBIT(34)
-#define        VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ2PIC_CMD_FIFO_ERR       vxge_mBIT(62)
-#define        VXGE_HW_MSG_ERR2_REG_TIM_TIM2MSG_CMD_FIFO_ERR   vxge_mBIT(63)
-/*0x05388*/    u64     msg_err2_mask;
-/*0x05390*/    u64     msg_err2_alarm;
-/*0x05398*/    u64     msg_err3_reg;
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR0      vxge_mBIT(0)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR1      vxge_mBIT(1)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR2      vxge_mBIT(2)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR3      vxge_mBIT(3)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR4      vxge_mBIT(4)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR5      vxge_mBIT(5)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR6      vxge_mBIT(6)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR7      vxge_mBIT(7)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR0      vxge_mBIT(8)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR1      vxge_mBIT(9)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR0      vxge_mBIT(16)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR1      vxge_mBIT(17)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR2      vxge_mBIT(18)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR3      vxge_mBIT(19)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR4      vxge_mBIT(20)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR5      vxge_mBIT(21)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR6      vxge_mBIT(22)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR7      vxge_mBIT(23)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR0      vxge_mBIT(24)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR1      vxge_mBIT(25)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR0      vxge_mBIT(32)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR1      vxge_mBIT(33)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR2      vxge_mBIT(34)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR3      vxge_mBIT(35)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR4      vxge_mBIT(36)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR5      vxge_mBIT(37)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR6      vxge_mBIT(38)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR7      vxge_mBIT(39)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR0      vxge_mBIT(40)
-#define        VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR1      vxge_mBIT(41)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR0      vxge_mBIT(48)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR1      vxge_mBIT(49)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR2      vxge_mBIT(50)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR3      vxge_mBIT(51)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR4      vxge_mBIT(52)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR5      vxge_mBIT(53)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR6      vxge_mBIT(54)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR7      vxge_mBIT(55)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR0      vxge_mBIT(56)
-#define        VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR1      vxge_mBIT(57)
-/*0x053a0*/    u64     msg_err3_mask;
-/*0x053a8*/    u64     msg_err3_alarm;
-       u8      unused05600[0x05600-0x053b0];
-
-/*0x05600*/    u64     fau_gen_err_reg;
-#define        VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT0_PERMANENT_STOP       vxge_mBIT(3)
-#define        VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT1_PERMANENT_STOP       vxge_mBIT(7)
-#define        VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT2_PERMANENT_STOP       vxge_mBIT(11)
-#define        VXGE_HW_FAU_GEN_ERR_REG_FALR_AUTO_LRO_NOTIFICATION      vxge_mBIT(15)
-/*0x05608*/    u64     fau_gen_err_mask;
-/*0x05610*/    u64     fau_gen_err_alarm;
-/*0x05618*/    u64     fau_ecc_err_reg;
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_SG_ERR    vxge_mBIT(0)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_DB_ERR    vxge_mBIT(1)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_SG_ERR(val) \
-                                                       vxge_vBIT(val, 2, 2)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_DB_ERR(val) \
-                                                       vxge_vBIT(val, 4, 2)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_SG_ERR    vxge_mBIT(6)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_DB_ERR    vxge_mBIT(7)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_SG_ERR(val) \
-                                                       vxge_vBIT(val, 8, 2)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_DB_ERR(val) \
-                                                       vxge_vBIT(val, 10, 2)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_SG_ERR    vxge_mBIT(12)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_DB_ERR    vxge_mBIT(13)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_SG_ERR(val) \
-                                                       vxge_vBIT(val, 14, 2)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_DB_ERR(val) \
-                                                       vxge_vBIT(val, 16, 2)
-#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_SG_ERR(val) \
-                                                       vxge_vBIT(val, 18, 2)
-#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_DB_ERR(val) \
-                                                       vxge_vBIT(val, 20, 2)
-#define        VXGE_HW_FAU_ECC_ERR_REG_FAUJ_FAU_FSM_ERR        vxge_mBIT(31)
-/*0x05620*/    u64     fau_ecc_err_mask;
-/*0x05628*/    u64     fau_ecc_err_alarm;
-       u8      unused05658[0x05658-0x05630];
-/*0x05658*/    u64     fau_pa_cfg;
-#define        VXGE_HW_FAU_PA_CFG_REPL_L4_COMP_CSUM    vxge_mBIT(3)
-#define        VXGE_HW_FAU_PA_CFG_REPL_L3_INCL_CF      vxge_mBIT(7)
-#define        VXGE_HW_FAU_PA_CFG_REPL_L3_COMP_CSUM    vxge_mBIT(11)
-       u8      unused05668[0x05668-0x05660];
-
-/*0x05668*/    u64     dbg_stats_fau_rx_path;
-#define        VXGE_HW_DBG_STATS_FAU_RX_PATH_RX_PERMITTED_FRMS(val) \
-                                               vxge_vBIT(val, 32, 32)
-       u8      unused056c0[0x056c0-0x05670];
-
-/*0x056c0*/    u64     fau_lag_cfg;
-#define VXGE_HW_FAU_LAG_CFG_COLL_ALG(val) vxge_vBIT(val, 2, 2)
-#define        VXGE_HW_FAU_LAG_CFG_INCR_RX_AGGR_STATS  vxge_mBIT(7)
-       u8      unused05800[0x05800-0x056c8];
-
-/*0x05800*/    u64     tpa_int_status;
-#define        VXGE_HW_TPA_INT_STATUS_ORP_ERR_ORP_INT  vxge_mBIT(15)
-#define        VXGE_HW_TPA_INT_STATUS_PTM_ALARM_PTM_INT        vxge_mBIT(23)
-#define        VXGE_HW_TPA_INT_STATUS_TPA_ERROR_TPA_INT        vxge_mBIT(31)
-/*0x05808*/    u64     tpa_int_mask;
-/*0x05810*/    u64     orp_err_reg;
-#define        VXGE_HW_ORP_ERR_REG_ORP_FIFO_SG_ERR     vxge_mBIT(3)
-#define        VXGE_HW_ORP_ERR_REG_ORP_FIFO_DB_ERR     vxge_mBIT(7)
-#define        VXGE_HW_ORP_ERR_REG_ORP_XFMD_FIFO_UFLOW_ERR     vxge_mBIT(11)
-#define        VXGE_HW_ORP_ERR_REG_ORP_FRM_FIFO_UFLOW_ERR      vxge_mBIT(15)
-#define        VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_FSM_ERR        vxge_mBIT(19)
-#define        VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_FSM_ERR vxge_mBIT(23)
-#define        VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_FSM_ERR  vxge_mBIT(27)
-#define        VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_SHADOW_ERR     vxge_mBIT(31)
-#define        VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_SHADOW_ERR      vxge_mBIT(35)
-#define        VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_SHADOW_ERR       vxge_mBIT(39)
-#define        VXGE_HW_ORP_ERR_REG_ORP_OUTFRM_SHADOW_ERR       vxge_mBIT(43)
-#define        VXGE_HW_ORP_ERR_REG_ORP_OPTPRS_SHADOW_ERR       vxge_mBIT(47)
-/*0x05818*/    u64     orp_err_mask;
-/*0x05820*/    u64     orp_err_alarm;
-/*0x05828*/    u64     ptm_alarm_reg;
-#define        VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_SYNC_ERR       vxge_mBIT(3)
-#define        VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_FIFO_ERR       vxge_mBIT(7)
-#define        VXGE_HW_PTM_ALARM_REG_XFMD_RD_FIFO_ERR  vxge_mBIT(11)
-#define        VXGE_HW_PTM_ALARM_REG_WDE2MSR_WR_FIFO_ERR       vxge_mBIT(15)
-#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_DB_ERR(val) vxge_vBIT(val, 18, 2)
-#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_SG_ERR(val) vxge_vBIT(val, 22, 2)
-/*0x05830*/    u64     ptm_alarm_mask;
-/*0x05838*/    u64     ptm_alarm_alarm;
-/*0x05840*/    u64     tpa_error_reg;
-#define        VXGE_HW_TPA_ERROR_REG_TPA_FSM_ERR_ALARM vxge_mBIT(3)
-#define        VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_DB_ERR       vxge_mBIT(7)
-#define        VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_SG_ERR       vxge_mBIT(11)
-/*0x05848*/    u64     tpa_error_mask;
-/*0x05850*/    u64     tpa_error_alarm;
-/*0x05858*/    u64     tpa_global_cfg;
-#define        VXGE_HW_TPA_GLOBAL_CFG_SUPPORT_SNAP_AB_N        vxge_mBIT(7)
-#define        VXGE_HW_TPA_GLOBAL_CFG_ECC_ENABLE_N     vxge_mBIT(35)
-       u8      unused05868[0x05870-0x05860];
-
-/*0x05870*/    u64     ptm_ecc_cfg;
-#define        VXGE_HW_PTM_ECC_CFG_PTM_FRMM_ECC_EN_N   vxge_mBIT(3)
-/*0x05878*/    u64     ptm_phase_cfg;
-#define        VXGE_HW_PTM_PHASE_CFG_FRMM_WR_PHASE_EN  vxge_mBIT(3)
-#define        VXGE_HW_PTM_PHASE_CFG_FRMM_RD_PHASE_EN  vxge_mBIT(7)
-       u8      unused05898[0x05898-0x05880];
-
-/*0x05898*/    u64     dbg_stats_tpa_tx_path;
-#define        VXGE_HW_DBG_STATS_TPA_TX_PATH_TX_PERMITTED_FRMS(val) \
-                                                       vxge_vBIT(val, 32, 32)
-       u8      unused05900[0x05900-0x058a0];
-
-/*0x05900*/    u64     tmac_int_status;
-#define        VXGE_HW_TMAC_INT_STATUS_TXMAC_GEN_ERR_TXMAC_GEN_INT     vxge_mBIT(3)
-#define        VXGE_HW_TMAC_INT_STATUS_TXMAC_ECC_ERR_TXMAC_ECC_INT     vxge_mBIT(7)
-/*0x05908*/    u64     tmac_int_mask;
-/*0x05910*/    u64     txmac_gen_err_reg;
-#define        VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_PERMANENT_STOP  vxge_mBIT(3)
-#define        VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_NO_VALID_VSPORT vxge_mBIT(7)
-/*0x05918*/    u64     txmac_gen_err_mask;
-/*0x05920*/    u64     txmac_gen_err_alarm;
-/*0x05928*/    u64     txmac_ecc_err_reg;
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_SG_ERR     vxge_mBIT(3)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_DB_ERR     vxge_mBIT(7)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_SG_ERR    vxge_mBIT(11)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_DB_ERR    vxge_mBIT(15)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_SG_ERR    vxge_mBIT(19)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_DB_ERR    vxge_mBIT(23)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT0_FSM_ERR       vxge_mBIT(27)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT1_FSM_ERR       vxge_mBIT(31)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT2_FSM_ERR       vxge_mBIT(35)
-#define        VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMACJ_FSM_ERR   vxge_mBIT(39)
-/*0x05930*/    u64     txmac_ecc_err_mask;
-/*0x05938*/    u64     txmac_ecc_err_alarm;
-       u8      unused05978[0x05978-0x05940];
-
-/*0x05978*/    u64     dbg_stat_tx_any_frms;
-#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT0_TX_ANY_FRMS(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT1_TX_ANY_FRMS(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT2_TX_ANY_FRMS(val) \
-                                                       vxge_vBIT(val, 16, 8)
-       u8      unused059a0[0x059a0-0x05980];
-
-/*0x059a0*/    u64     txmac_link_util_port[3];
-#define        VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_UTILIZATION(val) \
-                                                       vxge_vBIT(val, 1, 7)
-#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4)
-#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_FRAC_UTIL(val) \
-                                                       vxge_vBIT(val, 12, 4)
-#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_SCALE_FACTOR     vxge_mBIT(23)
-/*0x059b8*/    u64     txmac_cfg0_port[3];
-#define        VXGE_HW_TXMAC_CFG0_PORT_TMAC_EN vxge_mBIT(3)
-#define        VXGE_HW_TXMAC_CFG0_PORT_APPEND_PAD      vxge_mBIT(7)
-#define VXGE_HW_TXMAC_CFG0_PORT_PAD_BYTE(val) vxge_vBIT(val, 8, 8)
-/*0x059d0*/    u64     txmac_cfg1_port[3];
-#define VXGE_HW_TXMAC_CFG1_PORT_AVG_IPG(val) vxge_vBIT(val, 40, 8)
-/*0x059e8*/    u64     txmac_status_port[3];
-#define        VXGE_HW_TXMAC_STATUS_PORT_TMAC_TX_FRM_SENT      vxge_mBIT(3)
-       u8      unused05a20[0x05a20-0x05a00];
-
-/*0x05a20*/    u64     lag_distrib_dest;
-#define VXGE_HW_LAG_DISTRIB_DEST_MAP_VPATH(n)  vxge_mBIT(n)
-/*0x05a28*/    u64     lag_marker_cfg;
-#define        VXGE_HW_LAG_MARKER_CFG_GEN_RCVR_EN      vxge_mBIT(3)
-#define        VXGE_HW_LAG_MARKER_CFG_RESP_EN  vxge_mBIT(7)
-#define VXGE_HW_LAG_MARKER_CFG_RESP_TIMEOUT(val) vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_LAG_MARKER_CFG_SLOW_PROTO_MRKR_MIN_INTERVAL(val) \
-                                                       vxge_vBIT(val, 32, 16)
-#define        VXGE_HW_LAG_MARKER_CFG_THROTTLE_MRKR_RESP       vxge_mBIT(51)
-/*0x05a30*/    u64     lag_tx_cfg;
-#define        VXGE_HW_LAG_TX_CFG_INCR_TX_AGGR_STATS   vxge_mBIT(3)
-#define VXGE_HW_LAG_TX_CFG_DISTRIB_ALG_SEL(val) vxge_vBIT(val, 6, 2)
-#define        VXGE_HW_LAG_TX_CFG_DISTRIB_REMAP_IF_FAIL        vxge_mBIT(11)
-#define VXGE_HW_LAG_TX_CFG_COLL_MAX_DELAY(val) vxge_vBIT(val, 16, 16)
-/*0x05a38*/    u64     lag_tx_status;
-#define VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_EMPTIED_LINK(val) \
-                                                       vxge_vBIT(val, 0, 8)
-#define        VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKR(val) \
-                                                       vxge_vBIT(val, 8, 8)
-#define        VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKRRESP(val) \
-                                                       vxge_vBIT(val, 16, 8)
-       u8      unused05d48[0x05d48-0x05a40];
-
-/*0x05d48*/    u64     srpcim_to_mrpcim_vplane_rmsg[17];
-#define        \
-VXGE_HAL_SRPCIM_TO_MRPCIM_VPLANE_RMSG_SWIF_SRPCIM_TO_MRPCIM_VPLANE_RMSG(val)\
- vxge_vBIT(val, 0, 64)
-               u8      unused06420[0x06420-0x05dd0];
-
-/*0x06420*/    u64     mrpcim_to_srpcim_vplane_wmsg[17];
-#define        VXGE_HW_MRPCIM_TO_SRPCIM_VPLANE_WMSG_MRPCIM_TO_SRPCIM_VPLANE_WMSG(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x064a8*/    u64     mrpcim_to_srpcim_vplane_wmsg_trig[17];
-
-/*0x06530*/    u64     debug_stats0;
-#define VXGE_HW_DEBUG_STATS0_RSTDROP_MSG(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_DEBUG_STATS0_RSTDROP_CPL(val) vxge_vBIT(val, 32, 32)
-/*0x06538*/    u64     debug_stats1;
-#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT0(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT1(val) vxge_vBIT(val, 32, 32)
-/*0x06540*/    u64     debug_stats2;
-#define VXGE_HW_DEBUG_STATS2_RSTDROP_CLIENT2(val) vxge_vBIT(val, 0, 32)
-/*0x06548*/    u64     debug_stats3_vplane[17];
-#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_PH(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_NPH(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_CPLH(val) vxge_vBIT(val, 32, 16)
-/*0x065d0*/    u64     debug_stats4_vplane[17];
-#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_PD(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_NPD(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_CPLD(val) vxge_vBIT(val, 32, 16)
-
-       u8      unused07000[0x07000-0x06658];
-
-/*0x07000*/    u64     mrpcim_general_int_status;
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PIC_INT       vxge_mBIT(0)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCI_INT       vxge_mBIT(1)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RTDMA_INT     vxge_mBIT(2)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_WRDMA_INT     vxge_mBIT(3)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMCT_INT    vxge_mBIT(4)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG1_INT     vxge_mBIT(5)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG2_INT     vxge_mBIT(6)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG3_INT     vxge_mBIT(7)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFL_INT   vxge_mBIT(8)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFU_INT   vxge_mBIT(9)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG1_INT     vxge_mBIT(10)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG2_INT     vxge_mBIT(11)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG3_INT     vxge_mBIT(12)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_XMAC_INT      vxge_mBIT(13)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RXMAC_INT     vxge_mBIT(14)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TMAC_INT      vxge_mBIT(15)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBIF_INT    vxge_mBIT(16)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_FBMC_INT      vxge_mBIT(17)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBCT_INT    vxge_mBIT(18)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TPA_INT       vxge_mBIT(19)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_DRBELL_INT    vxge_mBIT(20)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_ONE_INT       vxge_mBIT(21)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_STATUS_MSG_INT       vxge_mBIT(22)
-/*0x07008*/    u64     mrpcim_general_int_mask;
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PIC_INT vxge_mBIT(0)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCI_INT vxge_mBIT(1)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_RTDMA_INT       vxge_mBIT(2)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_WRDMA_INT       vxge_mBIT(3)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMCT_INT      vxge_mBIT(4)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG1_INT       vxge_mBIT(5)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG2_INT       vxge_mBIT(6)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG3_INT       vxge_mBIT(7)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFL_INT     vxge_mBIT(8)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFU_INT     vxge_mBIT(9)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG1_INT       vxge_mBIT(10)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG2_INT       vxge_mBIT(11)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG3_INT       vxge_mBIT(12)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_XMAC_INT        vxge_mBIT(13)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_RXMAC_INT       vxge_mBIT(14)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_TMAC_INT        vxge_mBIT(15)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBIF_INT      vxge_mBIT(16)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_FBMC_INT        vxge_mBIT(17)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBCT_INT      vxge_mBIT(18)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_TPA_INT vxge_mBIT(19)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_DRBELL_INT      vxge_mBIT(20)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_ONE_INT vxge_mBIT(21)
-#define        VXGE_HW_MRPCIM_GENERAL_INT_MASK_MSG_INT vxge_mBIT(22)
-/*0x07010*/    u64     mrpcim_ppif_int_status;
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_INI_ERRORS_INI_INT       vxge_mBIT(3)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_DMA_ERRORS_DMA_INT       vxge_mBIT(7)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_TGT_ERRORS_TGT_INT       vxge_mBIT(11)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CONFIG_ERRORS_CONFIG_INT vxge_mBIT(15)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_CRDT_INT     vxge_mBIT(19)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_PLL_ERRORS_PLL_INT       vxge_mBIT(27)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE0_CRD_INT_VPLANE0_INT\
-                                                       vxge_mBIT(31)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE1_CRD_INT_VPLANE1_INT\
-                                                       vxge_mBIT(32)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE2_CRD_INT_VPLANE2_INT\
-                                                       vxge_mBIT(33)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE3_CRD_INT_VPLANE3_INT\
-                                                       vxge_mBIT(34)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE4_CRD_INT_VPLANE4_INT\
-                                                       vxge_mBIT(35)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE5_CRD_INT_VPLANE5_INT\
-                                                       vxge_mBIT(36)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE6_CRD_INT_VPLANE6_INT\
-                                                       vxge_mBIT(37)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE7_CRD_INT_VPLANE7_INT\
-                                                       vxge_mBIT(38)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE8_CRD_INT_VPLANE8_INT\
-                                                       vxge_mBIT(39)
-#define        VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE9_CRD_INT_VPLANE9_INT\
-                                                       vxge_mBIT(40)
-#define \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE10_CRD_INT_VPLANE10_INT \
-                                                       vxge_mBIT(41)
-#define \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE11_CRD_INT_VPLANE11_INT \
-                                                       vxge_mBIT(42)
-#define        \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE12_CRD_INT_VPLANE12_INT \
-                                                       vxge_mBIT(43)
-#define        \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE13_CRD_INT_VPLANE13_INT \
-                                                       vxge_mBIT(44)
-#define        \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE14_CRD_INT_VPLANE14_INT \
-                                                       vxge_mBIT(45)
-#define        \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE15_CRD_INT_VPLANE15_INT \
-                                                       vxge_mBIT(46)
-#define        \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE16_CRD_INT_VPLANE16_INT \
-                                                       vxge_mBIT(47)
-#define        \
-VXGE_HW_MRPCIM_PPIF_INT_STATUS_VPATH_TO_MRPCIM_ALARM_VPATH_TO_MRPCIM_ALARM_INT \
-                                                       vxge_mBIT(55)
-/*0x07018*/    u64     mrpcim_ppif_int_mask;
-       u8      unused07028[0x07028-0x07020];
-
-/*0x07028*/    u64     ini_errors_reg;
-#define        VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT_UNUSED_TAG      vxge_mBIT(3)
-#define        VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT vxge_mBIT(7)
-#define        VXGE_HW_INI_ERRORS_REG_DCPL_FSM_ERR     vxge_mBIT(11)
-#define        VXGE_HW_INI_ERRORS_REG_DCPL_POISON      vxge_mBIT(12)
-#define        VXGE_HW_INI_ERRORS_REG_DCPL_UNSUPPORTED vxge_mBIT(15)
-#define        VXGE_HW_INI_ERRORS_REG_DCPL_ABORT       vxge_mBIT(19)
-#define        VXGE_HW_INI_ERRORS_REG_INI_TLP_ABORT    vxge_mBIT(23)
-#define        VXGE_HW_INI_ERRORS_REG_INI_DLLP_ABORT   vxge_mBIT(27)
-#define        VXGE_HW_INI_ERRORS_REG_INI_ECRC_ERR     vxge_mBIT(31)
-#define        VXGE_HW_INI_ERRORS_REG_INI_BUF_DB_ERR   vxge_mBIT(35)
-#define        VXGE_HW_INI_ERRORS_REG_INI_BUF_SG_ERR   vxge_mBIT(39)
-#define        VXGE_HW_INI_ERRORS_REG_INI_DATA_OVERFLOW        vxge_mBIT(43)
-#define        VXGE_HW_INI_ERRORS_REG_INI_HDR_OVERFLOW vxge_mBIT(47)
-#define        VXGE_HW_INI_ERRORS_REG_INI_MRD_SYS_DROP vxge_mBIT(51)
-#define        VXGE_HW_INI_ERRORS_REG_INI_MWR_SYS_DROP vxge_mBIT(55)
-#define        VXGE_HW_INI_ERRORS_REG_INI_MRD_CLIENT_DROP      vxge_mBIT(59)
-#define        VXGE_HW_INI_ERRORS_REG_INI_MWR_CLIENT_DROP      vxge_mBIT(63)
-/*0x07030*/    u64     ini_errors_mask;
-/*0x07038*/    u64     ini_errors_alarm;
-/*0x07040*/    u64     dma_errors_reg;
-#define        VXGE_HW_DMA_ERRORS_REG_RDARB_FSM_ERR    vxge_mBIT(3)
-#define        VXGE_HW_DMA_ERRORS_REG_WRARB_FSM_ERR    vxge_mBIT(7)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_OVERFLOW        vxge_mBIT(8)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_UNDERFLOW       vxge_mBIT(9)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_OVERFLOW       vxge_mBIT(10)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_UNDERFLOW      vxge_mBIT(11)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_OVERFLOW  vxge_mBIT(12)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_UNDERFLOW vxge_mBIT(13)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_OVERFLOW vxge_mBIT(14)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_UNDERFLOW        vxge_mBIT(15)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_OVERFLOW        vxge_mBIT(16)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_UNDERFLOW       vxge_mBIT(17)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_OVERFLOW       vxge_mBIT(18)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_UNDERFLOW      vxge_mBIT(19)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_OVERFLOW        vxge_mBIT(20)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_UNDERFLOW       vxge_mBIT(21)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_OVERFLOW       vxge_mBIT(22)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_UNDERFLOW      vxge_mBIT(23)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_OVERFLOW        vxge_mBIT(24)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_UNDERFLOW       vxge_mBIT(25)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_OVERFLOW        vxge_mBIT(28)
-#define        VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_UNDERFLOW       vxge_mBIT(29)
-#define        VXGE_HW_DMA_ERRORS_REG_DBLGEN_FSM_ERR   vxge_mBIT(32)
-#define        VXGE_HW_DMA_ERRORS_REG_DBLGEN_CREDIT_FSM_ERR    vxge_mBIT(33)
-#define        VXGE_HW_DMA_ERRORS_REG_DBLGEN_DMA_WRR_SM_ERR    vxge_mBIT(34)
-/*0x07048*/    u64     dma_errors_mask;
-/*0x07050*/    u64     dma_errors_alarm;
-/*0x07058*/    u64     tgt_errors_reg;
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_VENDOR_MSG   vxge_mBIT(0)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_MSG_UNLOCK   vxge_mBIT(1)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_ILLEGAL_TLP_BE       vxge_mBIT(2)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_BOOT_WRITE   vxge_mBIT(3)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_PIF_WR_CROSS_QWRANGE vxge_mBIT(4)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_PIF_READ_CROSS_QWRANGE       vxge_mBIT(5)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_READ    vxge_mBIT(6)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_USDC_READ    vxge_mBIT(7)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_USDC_WR_CROSS_QWRANGE        vxge_mBIT(8)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_MSIX_BEYOND_RANGE    vxge_mBIT(9)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_KDFC_POISON    vxge_mBIT(10)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_USDC_POISON    vxge_mBIT(11)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_PIF_POISON     vxge_mBIT(12)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MSIX_POISON    vxge_mBIT(13)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MRIOV_POISON   vxge_mBIT(14)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_NOT_MEM_TLP  vxge_mBIT(15)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_UNKNOWN_MEM_TLP      vxge_mBIT(16)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_REQ_FSM_ERR  vxge_mBIT(17)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_CPL_FSM_ERR  vxge_mBIT(18)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_PROT_ERR        vxge_mBIT(19)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_SWIF_PROT_ERR        vxge_mBIT(20)
-#define        VXGE_HW_TGT_ERRORS_REG_TGT_MRIOV_MEM_MAP_CFG_ERR        vxge_mBIT(21)
-/*0x07060*/    u64     tgt_errors_mask;
-/*0x07068*/    u64     tgt_errors_alarm;
-/*0x07070*/    u64     config_errors_reg;
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_STOP_COND vxge_mBIT(3)
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_START_COND        vxge_mBIT(7)
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_EXP_RD_CNT        vxge_mBIT(11)
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_EXTRA_CYCLE       vxge_mBIT(15)
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_MAIN_FSM_ERR      vxge_mBIT(19)
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_REQ_COLLISION     vxge_mBIT(23)
-#define        VXGE_HW_CONFIG_ERRORS_REG_I2C_REG_FSM_ERR       vxge_mBIT(27)
-#define        VXGE_HW_CONFIG_ERRORS_REG_CFGM_I2C_TIMEOUT      vxge_mBIT(31)
-#define        VXGE_HW_CONFIG_ERRORS_REG_RIC_I2C_TIMEOUT       vxge_mBIT(35)
-#define        VXGE_HW_CONFIG_ERRORS_REG_CFGM_FSM_ERR  vxge_mBIT(39)
-#define        VXGE_HW_CONFIG_ERRORS_REG_RIC_FSM_ERR   vxge_mBIT(43)
-#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_ILLEGAL_ACCESS   vxge_mBIT(47)
-#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_TIMEOUT  vxge_mBIT(51)
-#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_FSM_ERR  vxge_mBIT(55)
-#define        VXGE_HW_CONFIG_ERRORS_REG_PIFM_TO_FSM_ERR       vxge_mBIT(59)
-#define        VXGE_HW_CONFIG_ERRORS_REG_RIC_RIC_RD_TIMEOUT    vxge_mBIT(63)
-/*0x07078*/    u64     config_errors_mask;
-/*0x07080*/    u64     config_errors_alarm;
-       u8      unused07090[0x07090-0x07088];
-
-/*0x07090*/    u64     crdt_errors_reg;
-#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_FSM_ERR       vxge_mBIT(11)
-#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_INTCTL_ILLEGAL_CRD_DEAL \
-                                                       vxge_mBIT(15)
-#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PDA_ILLEGAL_CRD_DEAL  vxge_mBIT(19)
-#define        VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PCI_MSG_ILLEGAL_CRD_DEAL \
-                                                       vxge_mBIT(23)
-#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_FSM_ERR       vxge_mBIT(35)
-#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_RDA_ILLEGAL_CRD_DEAL  vxge_mBIT(39)
-#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_PDA_ILLEGAL_CRD_DEAL  vxge_mBIT(43)
-#define        VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_DBLGEN_ILLEGAL_CRD_DEAL \
-                                                       vxge_mBIT(47)
-/*0x07098*/    u64     crdt_errors_mask;
-/*0x070a0*/    u64     crdt_errors_alarm;
-       u8      unused070b0[0x070b0-0x070a8];
-
-/*0x070b0*/    u64     mrpcim_general_errors_reg;
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_STATSB_FSM_ERR        vxge_mBIT(3)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XGEN_FSM_ERR  vxge_mBIT(7)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XMEM_FSM_ERR  vxge_mBIT(11)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_KDFCCTL_FSM_ERR       vxge_mBIT(15)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_MRIOVCTL_FSM_ERR      vxge_mBIT(19)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_FLSH_ERR  vxge_mBIT(23)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_ACK_ERR       vxge_mBIT(27)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_CHKSUM_ERR    vxge_mBIT(31)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INI_SERR_DET  vxge_mBIT(35)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSIX_FSM_ERR   vxge_mBIT(39)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSI_OVERFLOW   vxge_mBIT(43)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_PCI_NOT_FLUSH_DURING_SW_RESET \
-                                                       vxge_mBIT(47)
-#define        VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_SW_RESET_FSM_ERR vxge_mBIT(51)
-/*0x070b8*/    u64     mrpcim_general_errors_mask;
-/*0x070c0*/    u64     mrpcim_general_errors_alarm;
-       u8      unused070d0[0x070d0-0x070c8];
-
-/*0x070d0*/    u64     pll_errors_reg;
-#define        VXGE_HW_PLL_ERRORS_REG_CORE_CMG_PLL_OOL vxge_mBIT(3)
-#define        VXGE_HW_PLL_ERRORS_REG_CORE_FB_PLL_OOL  vxge_mBIT(7)
-#define        VXGE_HW_PLL_ERRORS_REG_CORE_X_PLL_OOL   vxge_mBIT(11)
-/*0x070d8*/    u64     pll_errors_mask;
-/*0x070e0*/    u64     pll_errors_alarm;
-/*0x070e8*/    u64     srpcim_to_mrpcim_alarm_reg;
-#define        VXGE_HW_SRPCIM_TO_MRPCIM_ALARM_REG_PPIF_SRPCIM_TO_MRPCIM_ALARM(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x070f0*/    u64     srpcim_to_mrpcim_alarm_mask;
-/*0x070f8*/    u64     srpcim_to_mrpcim_alarm_alarm;
-/*0x07100*/    u64     vpath_to_mrpcim_alarm_reg;
-#define        VXGE_HW_VPATH_TO_MRPCIM_ALARM_REG_PPIF_VPATH_TO_MRPCIM_ALARM(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x07108*/    u64     vpath_to_mrpcim_alarm_mask;
-/*0x07110*/    u64     vpath_to_mrpcim_alarm_alarm;
-       u8      unused07128[0x07128-0x07118];
-
-/*0x07128*/    u64     crdt_errors_vplane_reg[17];
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_CONSUME_CRDT_ERR \
-                                                       vxge_mBIT(3)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_CONSUME_CRDT_ERR \
-                                                       vxge_mBIT(7)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_RETURN_CRDT_ERR \
-                                                       vxge_mBIT(11)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_RETURN_CRDT_ERR \
-                                                       vxge_mBIT(15)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_CONSUME_CRDT_ERR \
-                                                       vxge_mBIT(19)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_RETURN_CRDT_ERR \
-                                                       vxge_mBIT(23)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_CONSUME_TAG_ERR \
-                                                       vxge_mBIT(27)
-#define        VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_RETURN_TAG_ERR \
-                                                       vxge_mBIT(31)
-/*0x07130*/    u64     crdt_errors_vplane_mask[17];
-/*0x07138*/    u64     crdt_errors_vplane_alarm[17];
-       u8      unused072f0[0x072f0-0x072c0];
-
-/*0x072f0*/    u64     mrpcim_rst_in_prog;
-#define        VXGE_HW_MRPCIM_RST_IN_PROG_MRPCIM_RST_IN_PROG   vxge_mBIT(7)
-/*0x072f8*/    u64     mrpcim_reg_modified;
-#define        VXGE_HW_MRPCIM_REG_MODIFIED_MRPCIM_REG_MODIFIED vxge_mBIT(7)
-
-       u8      unused07378[0x07378-0x07300];
-
-/*0x07378*/    u64     write_arb_pending;
-#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_WRDMA   vxge_mBIT(3)
-#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_RTDMA   vxge_mBIT(7)
-#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_MSG     vxge_mBIT(11)
-#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_STATSB  vxge_mBIT(15)
-#define        VXGE_HW_WRITE_ARB_PENDING_WRARB_INTCTL  vxge_mBIT(19)
-/*0x07380*/    u64     read_arb_pending;
-#define        VXGE_HW_READ_ARB_PENDING_RDARB_WRDMA    vxge_mBIT(3)
-#define        VXGE_HW_READ_ARB_PENDING_RDARB_RTDMA    vxge_mBIT(7)
-#define        VXGE_HW_READ_ARB_PENDING_RDARB_DBLGEN   vxge_mBIT(11)
-/*0x07388*/    u64     dmaif_dmadbl_pending;
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_WR     vxge_mBIT(0)
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_RD     vxge_mBIT(1)
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_WR     vxge_mBIT(2)
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_RD     vxge_mBIT(3)
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_MSG_WR       vxge_mBIT(4)
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_STATS_WR     vxge_mBIT(5)
-#define        VXGE_HW_DMAIF_DMADBL_PENDING_DBLGEN_IN_PROG(val) \
-                                                       vxge_vBIT(val, 13, 51)
-/*0x07390*/    u64     wrcrdtarb_status0_vplane[17];
-#define        VXGE_HW_WRCRDTARB_STATUS0_VPLANE_WRCRDTARB_ABS_AVAIL_P_H(val) \
-                                                       vxge_vBIT(val, 0, 8)
-/*0x07418*/    u64     wrcrdtarb_status1_vplane[17];
-#define        VXGE_HW_WRCRDTARB_STATUS1_VPLANE_WRCRDTARB_ABS_AVAIL_P_D(val) \
-                                                       vxge_vBIT(val, 4, 12)
-       u8      unused07500[0x07500-0x074a0];
-
-/*0x07500*/    u64     mrpcim_general_cfg1;
-#define        VXGE_HW_MRPCIM_GENERAL_CFG1_CLEAR_SERR  vxge_mBIT(7)
-/*0x07508*/    u64     mrpcim_general_cfg2;
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_WR_TD        vxge_mBIT(3)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_RD_TD        vxge_mBIT(7)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_CPL_TD       vxge_mBIT(11)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MWR  vxge_mBIT(15)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MRD  vxge_mBIT(19)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_IGNORE_VPATH_RST_FOR_MSIX   vxge_mBIT(23)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_FLASH_READ_MSB      vxge_mBIT(27)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_HOST_PIPELINE_WR        vxge_mBIT(31)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_ENABLE vxge_mBIT(43)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_MAP_TO_VPATH(val) \
-                                                       vxge_vBIT(val, 47, 5)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_EN_BLOCK_MSIX_DUE_TO_SERR   vxge_mBIT(55)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_FORCE_SENDING_INTA  vxge_mBIT(59)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_SWIF_PROT_ON_RDS        vxge_mBIT(63)
-/*0x07510*/    u64     mrpcim_general_cfg3;
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_PROTECTION_CA_OR_UNSUPN     vxge_mBIT(0)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_ILLEGAL_RD_CA_OR_UNSUPN     vxge_mBIT(3)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BYTE_SWAPEN      vxge_mBIT(7)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BIT_FLIPEN       vxge_mBIT(11)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BYTE_SWAPEN      vxge_mBIT(15)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BIT_FLIPEN       vxge_mBIT(19)
-#define VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MAX_MVFS(val) vxge_vBIT(val, 20, 16)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MVF_TBL_SIZE(val) \
-                                                       vxge_vBIT(val, 36, 16)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_PF0_SW_RESET_EN     vxge_mBIT(55)
-#define VXGE_HW_MRPCIM_GENERAL_CFG3_REG_MODIFIED_CFG(val) vxge_vBIT(val, 56, 2)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_CPL_ECC_ENABLE_N    vxge_mBIT(59)
-#define        VXGE_HW_MRPCIM_GENERAL_CFG3_BYPASS_DAISY_CHAIN  vxge_mBIT(63)
-/*0x07518*/    u64     mrpcim_stats_start_host_addr;
-#define        VXGE_HW_MRPCIM_STATS_START_HOST_ADDR_MRPCIM_STATS_START_HOST_ADDR(val)\
-                                                       vxge_vBIT(val, 0, 57)
-
-       u8      unused07950[0x07950-0x07520];
-
-/*0x07950*/    u64     rdcrdtarb_cfg0;
-#define VXGE_HW_RDCRDTARB_CFG0_RDA_MAX_OUTSTANDING_RDS(val) \
-                                               vxge_vBIT(val, 18, 6)
-#define VXGE_HW_RDCRDTARB_CFG0_PDA_MAX_OUTSTANDING_RDS(val) \
-                                               vxge_vBIT(val, 26, 6)
-#define VXGE_HW_RDCRDTARB_CFG0_DBLGEN_MAX_OUTSTANDING_RDS(val) \
-                                               vxge_vBIT(val, 34, 6)
-#define VXGE_HW_RDCRDTARB_CFG0_WAIT_CNT(val) vxge_vBIT(val, 48, 4)
-#define VXGE_HW_RDCRDTARB_CFG0_MAX_OUTSTANDING_RDS(val) vxge_vBIT(val, 54, 6)
-#define        VXGE_HW_RDCRDTARB_CFG0_EN_XON   vxge_mBIT(63)
-       u8      unused07be8[0x07be8-0x07958];
-
-/*0x07be8*/    u64     bf_sw_reset;
-#define VXGE_HW_BF_SW_RESET_BF_SW_RESET(val) vxge_vBIT(val, 0, 8)
-/*0x07bf0*/    u64     sw_reset_status;
-#define        VXGE_HW_SW_RESET_STATUS_RESET_CMPLT     vxge_mBIT(7)
-#define        VXGE_HW_SW_RESET_STATUS_INIT_CMPLT      vxge_mBIT(15)
-       u8      unused07d30[0x07d30-0x07bf8];
-
-/*0x07d30*/    u64     mrpcim_debug_stats0;
-#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_WR_DROP(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_RD_DROP(val) vxge_vBIT(val, 32, 32)
-/*0x07d38*/    u64     mrpcim_debug_stats1_vplane[17];
-#define        VXGE_HW_MRPCIM_DEBUG_STATS1_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x07dc0*/    u64     mrpcim_debug_stats2_vplane[17];
-#define        VXGE_HW_MRPCIM_DEBUG_STATS2_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x07e48*/    u64     mrpcim_debug_stats3_vplane[17];
-#define        VXGE_HW_MRPCIM_DEBUG_STATS3_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x07ed0*/    u64     mrpcim_debug_stats4;
-#define VXGE_HW_MRPCIM_DEBUG_STATS4_INI_WR_VPIN_DROP(val) vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_MRPCIM_DEBUG_STATS4_INI_RD_VPIN_DROP(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x07ed8*/    u64     genstats_count01;
-#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT1(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT0(val) vxge_vBIT(val, 32, 32)
-/*0x07ee0*/    u64     genstats_count23;
-#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT3(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT2(val) vxge_vBIT(val, 32, 32)
-/*0x07ee8*/    u64     genstats_count4;
-#define VXGE_HW_GENSTATS_COUNT4_GENSTATS_COUNT4(val) vxge_vBIT(val, 32, 32)
-/*0x07ef0*/    u64     genstats_count5;
-#define VXGE_HW_GENSTATS_COUNT5_GENSTATS_COUNT5(val) vxge_vBIT(val, 32, 32)
-
-       u8      unused07f08[0x07f08-0x07ef8];
-
-/*0x07f08*/    u64     genstats_cfg[6];
-#define VXGE_HW_GENSTATS_CFG_DTYPE_SEL(val) vxge_vBIT(val, 3, 5)
-#define VXGE_HW_GENSTATS_CFG_CLIENT_NO_SEL(val) vxge_vBIT(val, 9, 3)
-#define VXGE_HW_GENSTATS_CFG_WR_RD_CPL_SEL(val) vxge_vBIT(val, 14, 2)
-#define VXGE_HW_GENSTATS_CFG_VPATH_SEL(val) vxge_vBIT(val, 31, 17)
-/*0x07f38*/    u64     genstat_64bit_cfg;
-#define        VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS0      vxge_mBIT(3)
-#define        VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS2      vxge_mBIT(7)
-       u8      unused08000[0x08000-0x07f40];
-/*0x08000*/    u64     gcmg3_int_status;
-#define        VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR0_GSTC0_INT    vxge_mBIT(0)
-#define        VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR1_GSTC1_INT    vxge_mBIT(1)
-#define        VXGE_HW_GCMG3_INT_STATUS_GH2L_ERR0_GH2L0_INT    vxge_mBIT(2)
-#define        VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR_GH2L1_INT     vxge_mBIT(3)
-#define        VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR2_GH2L2_INT    vxge_mBIT(4)
-#define        VXGE_HW_GCMG3_INT_STATUS_GH2L_SMERR0_GH2L3_INT  vxge_mBIT(5)
-#define        VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR3_GH2L4_INT    vxge_mBIT(6)
-/*0x08008*/    u64     gcmg3_int_mask;
-       u8      unused09000[0x09000-0x8010];
-
-/*0x09000*/    u64     g3ifcmd_fb_int_status;
-#define        VXGE_HW_G3IFCMD_FB_INT_STATUS_ERR_G3IF_INT      vxge_mBIT(0)
-/*0x09008*/    u64     g3ifcmd_fb_int_mask;
-/*0x09010*/    u64     g3ifcmd_fb_err_reg;
-#define        VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_CK_DLL_LOCK     vxge_mBIT(6)
-#define        VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_SM_ERR  vxge_mBIT(7)
-#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
-                                               vxge_vBIT(val, 24, 8)
-#define        VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_IOCAL_FAULT     vxge_mBIT(55)
-/*0x09018*/    u64     g3ifcmd_fb_err_mask;
-/*0x09020*/    u64     g3ifcmd_fb_err_alarm;
-
-       u8      unused09400[0x09400-0x09028];
-
-/*0x09400*/    u64     g3ifcmd_cmu_int_status;
-#define        VXGE_HW_G3IFCMD_CMU_INT_STATUS_ERR_G3IF_INT     vxge_mBIT(0)
-/*0x09408*/    u64     g3ifcmd_cmu_int_mask;
-/*0x09410*/    u64     g3ifcmd_cmu_err_reg;
-#define        VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_CK_DLL_LOCK    vxge_mBIT(6)
-#define        VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_SM_ERR vxge_mBIT(7)
-#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
-                                                       vxge_vBIT(val, 24, 8)
-#define        VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_IOCAL_FAULT    vxge_mBIT(55)
-/*0x09418*/    u64     g3ifcmd_cmu_err_mask;
-/*0x09420*/    u64     g3ifcmd_cmu_err_alarm;
-
-       u8      unused09800[0x09800-0x09428];
-
-/*0x09800*/    u64     g3ifcmd_cml_int_status;
-#define        VXGE_HW_G3IFCMD_CML_INT_STATUS_ERR_G3IF_INT     vxge_mBIT(0)
-/*0x09808*/    u64     g3ifcmd_cml_int_mask;
-/*0x09810*/    u64     g3ifcmd_cml_err_reg;
-#define        VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_CK_DLL_LOCK    vxge_mBIT(6)
-#define        VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_SM_ERR vxge_mBIT(7)
-#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \
-                                               vxge_vBIT(val, 24, 8)
-#define        VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_IOCAL_FAULT    vxge_mBIT(55)
-/*0x09818*/    u64     g3ifcmd_cml_err_mask;
-/*0x09820*/    u64     g3ifcmd_cml_err_alarm;
-       u8      unused09b00[0x09b00-0x09828];
-
-/*0x09b00*/    u64     vpath_to_vplane_map[17];
-#define VXGE_HW_VPATH_TO_VPLANE_MAP_VPATH_TO_VPLANE_MAP(val) \
-                                                       vxge_vBIT(val, 3, 5)
-       u8      unused09c30[0x09c30-0x09b88];
-
-/*0x09c30*/    u64     xgxs_cfg_port[2];
-#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_LOS(val) vxge_vBIT(val, 16, 4)
-#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_VALID(val) vxge_vBIT(val, 20, 4)
-#define        VXGE_HW_XGXS_CFG_PORT_SEL_INFO_0        vxge_mBIT(27)
-#define VXGE_HW_XGXS_CFG_PORT_SEL_INFO_1(val) vxge_vBIT(val, 29, 3)
-#define VXGE_HW_XGXS_CFG_PORT_TX_LANE0_SKEW(val) vxge_vBIT(val, 32, 4)
-#define VXGE_HW_XGXS_CFG_PORT_TX_LANE1_SKEW(val) vxge_vBIT(val, 36, 4)
-#define VXGE_HW_XGXS_CFG_PORT_TX_LANE2_SKEW(val) vxge_vBIT(val, 40, 4)
-#define VXGE_HW_XGXS_CFG_PORT_TX_LANE3_SKEW(val) vxge_vBIT(val, 44, 4)
-/*0x09c40*/    u64     xgxs_rxber_cfg_port[2];
-#define VXGE_HW_XGXS_RXBER_CFG_PORT_INTERVAL_DUR(val) vxge_vBIT(val, 0, 4)
-#define        VXGE_HW_XGXS_RXBER_CFG_PORT_RXGXS_INTERVAL_CNT(val) \
-                                                       vxge_vBIT(val, 16, 48)
-/*0x09c50*/    u64     xgxs_rxber_status_port[2];
-#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_A_ERR_CNT(val)  \
-                                                       vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_B_ERR_CNT(val)  \
-                                                       vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_C_ERR_CNT(val)  \
-                                                       vxge_vBIT(val, 32, 16)
-#define        VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_D_ERR_CNT(val)  \
-                                                       vxge_vBIT(val, 48, 16)
-/*0x09c60*/    u64     xgxs_status_port[2];
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_TX_ACTIVITY(val) vxge_vBIT(val, 0, 4)
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_RX_ACTIVITY(val) vxge_vBIT(val, 4, 4)
-#define        VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_FIFO_ERR BIT(11)
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_BYTE_SYNC_LOST(val) \
-                                                       vxge_vBIT(val, 12, 4)
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_ERR(val) vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_ALIGNMENT_ERR        vxge_mBIT(23)
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_DEC_ERR(val) vxge_vBIT(val, 24, 8)
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_INS_REQ(val) \
-                                                       vxge_vBIT(val, 32, 4)
-#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_DEL_REQ(val) \
-                                                       vxge_vBIT(val, 36, 4)
-/*0x09c70*/    u64     xgxs_pma_reset_port[2];
-#define VXGE_HW_XGXS_PMA_RESET_PORT_SERDES_RESET(val) vxge_vBIT(val, 0, 8)
-       u8      unused09c90[0x09c90-0x09c80];
-
-/*0x09c90*/    u64     xgxs_static_cfg_port[2];
-#define        VXGE_HW_XGXS_STATIC_CFG_PORT_FW_CTRL_SERDES     vxge_mBIT(3)
-       u8      unused09d40[0x09d40-0x09ca0];
-
-/*0x09d40*/    u64     xgxs_info_port[2];
-#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_0(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_1(val) vxge_vBIT(val, 32, 32)
-/*0x09d50*/    u64     ratemgmt_cfg_port[2];
-#define VXGE_HW_RATEMGMT_CFG_PORT_MODE(val) vxge_vBIT(val, 2, 2)
-#define        VXGE_HW_RATEMGMT_CFG_PORT_RATE  vxge_mBIT(7)
-#define        VXGE_HW_RATEMGMT_CFG_PORT_FIXED_USE_FSM vxge_mBIT(11)
-#define        VXGE_HW_RATEMGMT_CFG_PORT_ANTP_USE_FSM  vxge_mBIT(15)
-#define        VXGE_HW_RATEMGMT_CFG_PORT_ANBE_USE_FSM  vxge_mBIT(19)
-/*0x09d60*/    u64     ratemgmt_status_port[2];
-#define        VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_COMPLETE  vxge_mBIT(3)
-#define        VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_RATE      vxge_mBIT(7)
-#define        VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_MAC_MATCHES_PHY   vxge_mBIT(11)
-       u8      unused09d80[0x09d80-0x09d70];
-
-/*0x09d80*/    u64     ratemgmt_fixed_cfg_port[2];
-#define        VXGE_HW_RATEMGMT_FIXED_CFG_PORT_RESTART vxge_mBIT(7)
-/*0x09d90*/    u64     ratemgmt_antp_cfg_port[2];
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_RESTART  vxge_mBIT(7)
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_PREAMBLE_EXT_PHY     vxge_mBIT(11)
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_ACT_SEL      vxge_mBIT(15)
-#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_RETRY_PHY_QUERY(val) \
-                                                       vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_WAIT_MDIO_RESPONSE(val) \
-                                                       vxge_vBIT(val, 20, 4)
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_LDOWN_REAUTO_RESPONSE(val) \
-                                                       vxge_vBIT(val, 24, 4)
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_10G    vxge_mBIT(31)
-#define        VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_1G     vxge_mBIT(35)
-/*0x09da0*/    u64     ratemgmt_anbe_cfg_port[2];
-#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_RESTART  vxge_mBIT(7)
-#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_10G_KX4_ENABLE \
-                                                               vxge_mBIT(11)
-#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_1G_KX_ENABLE \
-                                                               vxge_mBIT(15)
-#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_10G_KX4(val) vxge_vBIT(val, 16, 4)
-#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_1G_KX(val) vxge_vBIT(val, 20, 4)
-#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_DME_EXCHANGE(val) vxge_vBIT(val, 24, 4)
-#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_10G_KX4        vxge_mBIT(31)
-#define        VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_1G_KX  vxge_mBIT(35)
-/*0x09db0*/    u64     anbe_cfg_port[2];
-#define VXGE_HW_ANBE_CFG_PORT_RESET_CFG_REGS(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_ANBE_CFG_PORT_ALIGN_10G_KX4_OVERRIDE(val) vxge_vBIT(val, 10, 2)
-#define VXGE_HW_ANBE_CFG_PORT_SYNC_1G_KX_OVERRIDE(val) vxge_vBIT(val, 14, 2)
-/*0x09dc0*/    u64     anbe_mgr_ctrl_port[2];
-#define        VXGE_HW_ANBE_MGR_CTRL_PORT_WE   vxge_mBIT(3)
-#define        VXGE_HW_ANBE_MGR_CTRL_PORT_STROBE       vxge_mBIT(7)
-#define VXGE_HW_ANBE_MGR_CTRL_PORT_ADDR(val) vxge_vBIT(val, 15, 9)
-#define VXGE_HW_ANBE_MGR_CTRL_PORT_DATA(val) vxge_vBIT(val, 32, 32)
-       u8      unused09de0[0x09de0-0x09dd0];
-
-/*0x09de0*/    u64     anbe_fw_mstr_port[2];
-#define        VXGE_HW_ANBE_FW_MSTR_PORT_CONNECT_BEAN_TO_SERDES        vxge_mBIT(3)
-#define        VXGE_HW_ANBE_FW_MSTR_PORT_TX_ZEROES_TO_SERDES   vxge_mBIT(7)
-/*0x09df0*/    u64     anbe_hwfsm_gen_status_port[2];
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_PD \
-                                                       vxge_mBIT(3)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_DME \
-                                                       vxge_mBIT(7)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_PD \
-                                                       vxge_mBIT(11)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_DME \
-                                                       vxge_mBIT(15)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANBEFSM_STATE(val)  \
-                                                       vxge_vBIT(val, 18, 6)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_NEXT_PAGE_RECEIVED \
-                                                       vxge_mBIT(27)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_BASE_PAGE_RECEIVED \
-                                                       vxge_mBIT(35)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_AUTONEG_COMPLETE \
-                                                       vxge_mBIT(39)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NP_BEFORE_BP \
-                                                       vxge_mBIT(43)
-#define        \
-VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_BP \
-                                                       vxge_mBIT(47)
-#define        \
-VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_NP \
-vxge_mBIT(51)
-#define        \
-VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MODE_WHEN_AN_COMPLETE \
-                                                       vxge_mBIT(55)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_BP(val) \
-                                                       vxge_vBIT(val, 56, 4)
-#define        VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_NP(val) \
-                                                       vxge_vBIT(val, 60, 4)
-/*0x09e00*/    u64     anbe_hwfsm_bp_status_port[2];
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ENABLE \
-                                                       vxge_mBIT(32)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ABILITY \
-                                                       vxge_mBIT(33)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KR_CAPABLE \
-                                                       vxge_mBIT(40)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KX4_CAPABLE \
-                                                       vxge_mBIT(41)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_1G_KX_CAPABLE \
-                                                       vxge_mBIT(42)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_TX_NONCE(val)     \
-                                                       vxge_vBIT(val, 43, 5)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP        vxge_mBIT(48)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK       vxge_mBIT(49)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_REMOTE_FAULT \
-                                                       vxge_mBIT(50)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ASM_DIR   vxge_mBIT(51)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_PAUSE     vxge_mBIT(53)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ECHOED_NONCE(val) \
-                                                       vxge_vBIT(val, 54, 5)
-#define        VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x09e10*/    u64     anbe_hwfsm_np_status_port[2];
-#define        VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_47_TO_32(val) \
-                                                       vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_31_TO_0(val) \
-                                                       vxge_vBIT(val, 32, 32)
-       u8      unused09e30[0x09e30-0x09e20];
-
-/*0x09e30*/    u64     antp_gen_cfg_port[2];
-/*0x09e40*/    u64     antp_hwfsm_gen_status_port[2];
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G   vxge_mBIT(3)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G    vxge_mBIT(7)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANTPFSM_STATE(val)  \
-                                                       vxge_vBIT(val, 10, 6)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_AUTONEG_COMPLETE \
-                                                               vxge_mBIT(23)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_LP_XNP \
-                                                       vxge_mBIT(27)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_GOT_LP_XNP  vxge_mBIT(31)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MESSAGE_CODE \
-                                                       vxge_mBIT(35)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_HCD \
-                                                       vxge_mBIT(43)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_FOUND_HCD   vxge_mBIT(47)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_INVALID_RATE \
-                                                       vxge_mBIT(51)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_VALID_RATE  vxge_mBIT(55)
-#define        VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_PERSISTENT_LDOWN \
-                                                       vxge_mBIT(59)
-/*0x09e50*/    u64     antp_hwfsm_bp_status_port[2];
-#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP        vxge_mBIT(0)
-#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK       vxge_mBIT(1)
-#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_RF        vxge_mBIT(2)
-#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_XNP       vxge_mBIT(3)
-#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ABILITY_FIELD(val) \
-                                                       vxge_vBIT(val, 4, 7)
-#define        VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \
-                                                       vxge_vBIT(val, 11, 5)
-/*0x09e60*/    u64     antp_hwfsm_xnp_status_port[2];
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_NP      vxge_mBIT(0)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK     vxge_mBIT(1)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MP      vxge_mBIT(2)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK2    vxge_mBIT(3)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_TOGGLE  vxge_mBIT(4)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MESSAGE_CODE(val) \
-                                                       vxge_vBIT(val, 5, 11)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD1(val) \
-                                                       vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD2(val) \
-                                                       vxge_vBIT(val, 32, 16)
-/*0x09e70*/    u64     mdio_mgr_access_port[2];
-#define        VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_ONE BIT(3)
-#define VXGE_HW_MDIO_MGR_ACCESS_PORT_OP_TYPE(val) vxge_vBIT(val, 5, 3)
-#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DEVAD(val) vxge_vBIT(val, 11, 5)
-#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ADDR(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DATA(val) vxge_vBIT(val, 32, 16)
-#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ST_PATTERN(val) vxge_vBIT(val, 49, 2)
-#define        VXGE_HW_MDIO_MGR_ACCESS_PORT_PREAMBLE   vxge_mBIT(51)
-#define VXGE_HW_MDIO_MGR_ACCESS_PORT_PRTAD(val) vxge_vBIT(val, 55, 5)
-#define        VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_TWO vxge_mBIT(63)
-       u8      unused0a200[0x0a200-0x09e80];
-/*0x0a200*/    u64     xmac_vsport_choices_vh[17];
-#define VXGE_HW_XMAC_VSPORT_CHOICES_VH_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17)
-       u8      unused0a400[0x0a400-0x0a288];
-
-/*0x0a400*/    u64     rx_thresh_cfg_vp[17];
-#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_0(val) vxge_vBIT(val, 16, 8)
-#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_1(val) vxge_vBIT(val, 24, 8)
-#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_2(val) vxge_vBIT(val, 32, 8)
-#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_3(val) vxge_vBIT(val, 40, 8)
-       u8      unused0ac90[0x0ac90-0x0a488];
-} __packed;
-
-/*VXGE_HW_SRPCIM_REGS_H*/
-struct vxge_hw_srpcim_reg {
-
-/*0x00000*/    u64     tim_mr2sr_resource_assignment_vh;
-#define        VXGE_HW_TIM_MR2SR_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) \
-                                                       vxge_vBIT(val, 0, 32)
-       u8      unused00100[0x00100-0x00008];
-
-/*0x00100*/    u64     srpcim_pcipif_int_status;
-#define        VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_MRPCIM_MSG_MRPCIM_MSG_INT      BIT(3)
-#define        VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_VPATH_MSG_VPATH_MSG_INT        BIT(7)
-#define        VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_SRPCIM_SPARE_R1_SRPCIM_SPARE_R1_INT \
-                                                                       BIT(11)
-/*0x00108*/    u64     srpcim_pcipif_int_mask;
-/*0x00110*/    u64     mrpcim_msg_reg;
-#define        VXGE_HW_MRPCIM_MSG_REG_SWIF_MRPCIM_TO_SRPCIM_RMSG_INT   BIT(3)
-/*0x00118*/    u64     mrpcim_msg_mask;
-/*0x00120*/    u64     mrpcim_msg_alarm;
-/*0x00128*/    u64     vpath_msg_reg;
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH0_TO_SRPCIM_RMSG_INT    BIT(0)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH1_TO_SRPCIM_RMSG_INT    BIT(1)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH2_TO_SRPCIM_RMSG_INT    BIT(2)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH3_TO_SRPCIM_RMSG_INT    BIT(3)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH4_TO_SRPCIM_RMSG_INT    BIT(4)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH5_TO_SRPCIM_RMSG_INT    BIT(5)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH6_TO_SRPCIM_RMSG_INT    BIT(6)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH7_TO_SRPCIM_RMSG_INT    BIT(7)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH8_TO_SRPCIM_RMSG_INT    BIT(8)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH9_TO_SRPCIM_RMSG_INT    BIT(9)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH10_TO_SRPCIM_RMSG_INT   BIT(10)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH11_TO_SRPCIM_RMSG_INT   BIT(11)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH12_TO_SRPCIM_RMSG_INT   BIT(12)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH13_TO_SRPCIM_RMSG_INT   BIT(13)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH14_TO_SRPCIM_RMSG_INT   BIT(14)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH15_TO_SRPCIM_RMSG_INT   BIT(15)
-#define        VXGE_HW_VPATH_MSG_REG_SWIF_VPATH16_TO_SRPCIM_RMSG_INT   BIT(16)
-/*0x00130*/    u64     vpath_msg_mask;
-/*0x00138*/    u64     vpath_msg_alarm;
-       u8      unused00160[0x00160-0x00140];
-
-/*0x00160*/    u64     srpcim_to_mrpcim_wmsg;
-#define        VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_SRPCIM_TO_MRPCIM_WMSG(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x00168*/    u64     srpcim_to_mrpcim_wmsg_trig;
-#define        VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_TRIG_SRPCIM_TO_MRPCIM_WMSG_TRIG   BIT(0)
-/*0x00170*/    u64     mrpcim_to_srpcim_rmsg;
-#define        VXGE_HW_MRPCIM_TO_SRPCIM_RMSG_SWIF_MRPCIM_TO_SRPCIM_RMSG(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x00178*/    u64     vpath_to_srpcim_rmsg_sel;
-#define        VXGE_HW_VPATH_TO_SRPCIM_RMSG_SEL_VPATH_TO_SRPCIM_RMSG_SEL(val) \
-                                                       vxge_vBIT(val, 0, 5)
-/*0x00180*/    u64     vpath_to_srpcim_rmsg;
-#define        VXGE_HW_VPATH_TO_SRPCIM_RMSG_SWIF_VPATH_TO_SRPCIM_RMSG(val) \
-                                                       vxge_vBIT(val, 0, 64)
-       u8      unused00200[0x00200-0x00188];
-
-/*0x00200*/    u64     srpcim_general_int_status;
-#define        VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PIC_INT       BIT(0)
-#define        VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PCI_INT       BIT(3)
-#define        VXGE_HW_SRPCIM_GENERAL_INT_STATUS_XMAC_INT      BIT(7)
-       u8      unused00210[0x00210-0x00208];
-
-/*0x00210*/    u64     srpcim_general_int_mask;
-#define        VXGE_HW_SRPCIM_GENERAL_INT_MASK_PIC_INT BIT(0)
-#define        VXGE_HW_SRPCIM_GENERAL_INT_MASK_PCI_INT BIT(3)
-#define        VXGE_HW_SRPCIM_GENERAL_INT_MASK_XMAC_INT        BIT(7)
-       u8      unused00220[0x00220-0x00218];
-
-/*0x00220*/    u64     srpcim_ppif_int_status;
-
-/*0x00228*/    u64     srpcim_ppif_int_mask;
-/*0x00230*/    u64     srpcim_gen_errors_reg;
-#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_STATUS_ERR   BIT(3)
-#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_UNCOR_ERR    BIT(7)
-#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_COR_ERR      BIT(11)
-#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_INTCTRL_SCHED_INT BIT(15)
-#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_INI_SERR_DET      BIT(19)
-#define        VXGE_HW_SRPCIM_GEN_ERRORS_REG_TGT_PF_ILLEGAL_ACCESS     BIT(23)
-/*0x00238*/    u64     srpcim_gen_errors_mask;
-/*0x00240*/    u64     srpcim_gen_errors_alarm;
-/*0x00248*/    u64     mrpcim_to_srpcim_alarm_reg;
-#define        VXGE_HW_MRPCIM_TO_SRPCIM_ALARM_REG_PPIF_MRPCIM_TO_SRPCIM_ALARM  BIT(3)
-/*0x00250*/    u64     mrpcim_to_srpcim_alarm_mask;
-/*0x00258*/    u64     mrpcim_to_srpcim_alarm_alarm;
-/*0x00260*/    u64     vpath_to_srpcim_alarm_reg;
-
-/*0x00268*/    u64     vpath_to_srpcim_alarm_mask;
-/*0x00270*/    u64     vpath_to_srpcim_alarm_alarm;
-       u8      unused00280[0x00280-0x00278];
-
-/*0x00280*/    u64     pf_sw_reset;
-#define VXGE_HW_PF_SW_RESET_PF_SW_RESET(val) vxge_vBIT(val, 0, 8)
-/*0x00288*/    u64     srpcim_general_cfg1;
-#define        VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BYTE_SWAPEN    BIT(19)
-#define        VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BIT_FLIPEN     BIT(23)
-#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_SWAPEN    BIT(27)
-#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_FLIPEN    BIT(31)
-#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_SWAPEN    BIT(35)
-#define        VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_FLIPEN    BIT(39)
-/*0x00290*/    u64     srpcim_interrupt_cfg1;
-#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7)
-#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_TRAFFIC_CLASS(val) vxge_vBIT(val, 9, 3)
-       u8      unused002a8[0x002a8-0x00298];
-
-/*0x002a8*/    u64     srpcim_clear_msix_mask;
-#define        VXGE_HW_SRPCIM_CLEAR_MSIX_MASK_SRPCIM_CLEAR_MSIX_MASK   BIT(0)
-/*0x002b0*/    u64     srpcim_set_msix_mask;
-#define        VXGE_HW_SRPCIM_SET_MSIX_MASK_SRPCIM_SET_MSIX_MASK       BIT(0)
-/*0x002b8*/    u64     srpcim_clr_msix_one_shot;
-#define        VXGE_HW_SRPCIM_CLR_MSIX_ONE_SHOT_SRPCIM_CLR_MSIX_ONE_SHOT       BIT(0)
-/*0x002c0*/    u64     srpcim_rst_in_prog;
-#define        VXGE_HW_SRPCIM_RST_IN_PROG_SRPCIM_RST_IN_PROG   BIT(7)
-/*0x002c8*/    u64     srpcim_reg_modified;
-#define        VXGE_HW_SRPCIM_REG_MODIFIED_SRPCIM_REG_MODIFIED BIT(7)
-/*0x002d0*/    u64     tgt_pf_illegal_access;
-#define VXGE_HW_TGT_PF_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7)
-/*0x002d8*/    u64     srpcim_msix_status;
-#define        VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_MASK      BIT(3)
-#define        VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_PENDING_VECTOR    BIT(7)
-       u8      unused00880[0x00880-0x002e0];
-
-/*0x00880*/    u64     xgmac_sr_int_status;
-#define        VXGE_HW_XGMAC_SR_INT_STATUS_ASIC_NTWK_SR_ERR_ASIC_NTWK_SR_INT   BIT(3)
-/*0x00888*/    u64     xgmac_sr_int_mask;
-/*0x00890*/    u64     asic_ntwk_sr_err_reg;
-#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT BIT(3)
-#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK    BIT(7)
-#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT_OCCURRED \
-                                                                       BIT(11)
-#define        VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK_OCCURRED   BIT(15)
-/*0x00898*/    u64     asic_ntwk_sr_err_mask;
-/*0x008a0*/    u64     asic_ntwk_sr_err_alarm;
-       u8      unused008c0[0x008c0-0x008a8];
-
-/*0x008c0*/    u64     xmac_vsport_choices_sr_clone;
-#define        VXGE_HW_XMAC_VSPORT_CHOICES_SR_CLONE_VSPORT_VECTOR(val) \
-                                                       vxge_vBIT(val, 0, 17)
-       u8      unused00900[0x00900-0x008c8];
-
-/*0x00900*/    u64     mr_rqa_top_prty_for_vh;
-#define        VXGE_HW_MR_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00908*/    u64     umq_vh_data_list_empty;
-#define        VXGE_HW_UMQ_VH_DATA_LIST_EMPTY_ROCRC_UMQ_VH_DATA_LIST_EMPTY \
-                                                       BIT(0)
-/*0x00910*/    u64     wde_cfg;
-#define        VXGE_HW_WDE_CFG_NS0_FORCE_MWB_START     BIT(0)
-#define        VXGE_HW_WDE_CFG_NS0_FORCE_MWB_END       BIT(1)
-#define        VXGE_HW_WDE_CFG_NS0_FORCE_QB_START      BIT(2)
-#define        VXGE_HW_WDE_CFG_NS0_FORCE_QB_END        BIT(3)
-#define        VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_START    BIT(4)
-#define        VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_END      BIT(5)
-#define        VXGE_HW_WDE_CFG_NS0_MWB_OPT_EN  BIT(6)
-#define        VXGE_HW_WDE_CFG_NS0_QB_OPT_EN   BIT(7)
-#define        VXGE_HW_WDE_CFG_NS0_MPSB_OPT_EN BIT(8)
-#define        VXGE_HW_WDE_CFG_NS1_FORCE_MWB_START     BIT(9)
-#define        VXGE_HW_WDE_CFG_NS1_FORCE_MWB_END       BIT(10)
-#define        VXGE_HW_WDE_CFG_NS1_FORCE_QB_START      BIT(11)
-#define        VXGE_HW_WDE_CFG_NS1_FORCE_QB_END        BIT(12)
-#define        VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_START    BIT(13)
-#define        VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_END      BIT(14)
-#define        VXGE_HW_WDE_CFG_NS1_MWB_OPT_EN  BIT(15)
-#define        VXGE_HW_WDE_CFG_NS1_QB_OPT_EN   BIT(16)
-#define        VXGE_HW_WDE_CFG_NS1_MPSB_OPT_EN BIT(17)
-#define        VXGE_HW_WDE_CFG_DISABLE_QPAD_FOR_UNALIGNED_ADDR BIT(19)
-#define VXGE_HW_WDE_CFG_ALIGNMENT_PREFERENCE(val) vxge_vBIT(val, 30, 2)
-#define VXGE_HW_WDE_CFG_MEM_WORD_SIZE(val) vxge_vBIT(val, 46, 2)
-
-} __packed;
-
-/*VXGE_HW_VPMGMT_REGS_H*/
-struct vxge_hw_vpmgmt_reg {
-
-       u8      unused00040[0x00040-0x00000];
-
-/*0x00040*/    u64     vpath_to_func_map_cfg1;
-#define        VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_VPATH_TO_FUNC_MAP_CFG1(val) \
-                                                       vxge_vBIT(val, 3, 5)
-/*0x00048*/    u64     vpath_is_first;
-#define        VXGE_HW_VPATH_IS_FIRST_VPATH_IS_FIRST   vxge_mBIT(3)
-/*0x00050*/    u64     srpcim_to_vpath_wmsg;
-#define        VXGE_HW_SRPCIM_TO_VPATH_WMSG_SRPCIM_TO_VPATH_WMSG(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x00058*/    u64     srpcim_to_vpath_wmsg_trig;
-#define        VXGE_HW_SRPCIM_TO_VPATH_WMSG_TRIG_SRPCIM_TO_VPATH_WMSG_TRIG \
-                                                               vxge_mBIT(0)
-       u8      unused00100[0x00100-0x00060];
-
-/*0x00100*/    u64     tim_vpath_assignment;
-#define VXGE_HW_TIM_VPATH_ASSIGNMENT_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
-       u8      unused00140[0x00140-0x00108];
-
-/*0x00140*/    u64     rqa_top_prty_for_vp;
-#define VXGE_HW_RQA_TOP_PRTY_FOR_VP_RQA_TOP_PRTY_FOR_VP(val) \
-                                                       vxge_vBIT(val, 59, 5)
-       u8      unused001c0[0x001c0-0x00148];
-
-/*0x001c0*/    u64     rxmac_rx_pa_cfg0_vpmgmt_clone;
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IGNORE_FRAME_ERR  vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_SNAP_AB_N vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_HAO    vxge_mBIT(18)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_MOBILE_IPV6_HDRS \
-                                                               vxge_mBIT(19)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IPV6_STOP_SEARCHING \
-                                                               vxge_mBIT(23)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_NO_PS_IF_UNKNOWN  vxge_mBIT(27)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_ETYPE  vxge_mBIT(35)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L3_CSUM_ERR \
-                                                               vxge_mBIT(39)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR \
-                                                               vxge_mBIT(43)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L4_CSUM_ERR \
-                                                               vxge_mBIT(47)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR \
-                                                               vxge_mBIT(51)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_RPA_ERR \
-                                                               vxge_mBIT(55)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_RPA_ERR \
-                                                               vxge_mBIT(59)
-#define        VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_JUMBO_SNAP_EN     vxge_mBIT(63)
-/*0x001c8*/    u64     rts_mgr_cfg0_vpmgmt_clone;
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_RTS_DP_SP_PRIORITY    vxge_mBIT(3)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_FLEX_L4PRTCL_VALUE(val) \
-                                                       vxge_vBIT(val, 24, 8)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ICMP_TRASH    vxge_mBIT(35)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_TCPSYN_TRASH  vxge_mBIT(39)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ZL4PYLD_TRASH vxge_mBIT(43)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_TCP_TRASH     vxge_mBIT(47)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_UDP_TRASH     vxge_mBIT(51)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_FLEX_TRASH    vxge_mBIT(55)
-#define        VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_IPFRAG_TRASH  vxge_mBIT(59)
-/*0x001d0*/    u64     rts_mgr_criteria_priority_vpmgmt_clone;
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ETYPE(val) \
-                                                       vxge_vBIT(val, 5, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ICMP_TCPSYN(val) \
-                                                       vxge_vBIT(val, 9, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PN(val) \
-                                                       vxge_vBIT(val, 13, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RANGE_L4PN(val) \
-                                                       vxge_vBIT(val, 17, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RTH_IT(val) \
-                                                       vxge_vBIT(val, 21, 3)
-#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_DS(val) \
-                                                       vxge_vBIT(val, 25, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_QOS(val) \
-                                                       vxge_vBIT(val, 29, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ZL4PYLD(val) \
-                                                       vxge_vBIT(val, 33, 3)
-#define        VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PRTCL(val) \
-                                                       vxge_vBIT(val, 37, 3)
-/*0x001d8*/    u64     rxmac_cfg0_port_vpmgmt_clone[3];
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_RMAC_EN    vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS  vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_DISCARD_PFRM       vxge_mBIT(11)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_FCS_ERR     vxge_mBIT(15)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LONG_ERR    vxge_mBIT(19)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_USIZED_ERR  vxge_mBIT(23)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LEN_MISMATCH \
-                                                               vxge_mBIT(27)
-#define        VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_MAX_PYLD_LEN(val) \
-                                                       vxge_vBIT(val, 50, 14)
-/*0x001f0*/    u64     rxmac_pause_cfg_port_vpmgmt_clone[3];
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_GEN_EN        vxge_mBIT(3)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_RCV_EN        vxge_mBIT(7)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_ACCEL_SEND(val) \
-                                                       vxge_vBIT(val, 9, 3)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_DUAL_THR      vxge_mBIT(15)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_HIGH_PTIME(val) \
-                                                       vxge_vBIT(val, 20, 16)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_FCS_ERR \
-                                                               vxge_mBIT(39)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_LEN_ERR \
-                                                               vxge_mBIT(43)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_LIMITER_EN    vxge_mBIT(47)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_MAX_LIMIT(val) \
-                                                       vxge_vBIT(val, 48, 8)
-#define        VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_PERMIT_RATEMGMT_CTRL \
-                                                       vxge_mBIT(59)
-       u8      unused00240[0x00240-0x00208];
-
-/*0x00240*/    u64     xmac_vsport_choices_vp;
-#define VXGE_HW_XMAC_VSPORT_CHOICES_VP_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17)
-       u8      unused00260[0x00260-0x00248];
-
-/*0x00260*/    u64     xgmac_gen_status_vpmgmt_clone;
-#define        VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK     vxge_mBIT(3)
-#define        VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_DATA_RATE \
-                                                               vxge_mBIT(11)
-/*0x00268*/    u64     xgmac_status_port_vpmgmt_clone[2];
-#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_REMOTE_FAULT \
-                                                               vxge_mBIT(3)
-#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_LOCAL_FAULT vxge_mBIT(7)
-#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_MAC_PHY_LAYER_AVAIL \
-                                                               vxge_mBIT(11)
-#define        VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_PORT_OK    vxge_mBIT(15)
-/*0x00278*/    u64     xmac_gen_cfg_vpmgmt_clone;
-#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_RATEMGMT_MAC_RATE_SEL(val) \
-                                                       vxge_vBIT(val, 2, 2)
-#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_TX_HEAD_DROP_WHEN_FAULT \
-                                                       vxge_mBIT(7)
-#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_FAULT_BEHAVIOUR       vxge_mBIT(27)
-#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_UP(val) \
-                                                       vxge_vBIT(val, 28, 4)
-#define        VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_DOWN(val) \
-                                                       vxge_vBIT(val, 32, 4)
-/*0x00280*/    u64     xmac_timestamp_vpmgmt_clone;
-#define        VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_EN  vxge_mBIT(3)
-#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_USE_LINK_ID(val) \
-                                                       vxge_vBIT(val, 6, 2)
-#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_INTERVAL(val) vxge_vBIT(val, 12, 4)
-#define        VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_TIMER_RESTART       vxge_mBIT(19)
-#define        VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_XMACJ_ROLLOVER_CNT(val) \
-                                                       vxge_vBIT(val, 32, 16)
-/*0x00288*/    u64     xmac_stats_gen_cfg_vpmgmt_clone;
-#define        VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_PRTAGGR_CUM_TIMER(val) \
-                                                       vxge_vBIT(val, 4, 4)
-#define        VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VPATH_CUM_TIMER(val) \
-                                                       vxge_vBIT(val, 8, 4)
-#define        VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VLAN_HANDLING   vxge_mBIT(15)
-/*0x00290*/    u64     xmac_cfg_port_vpmgmt_clone[3];
-#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_LOOPBACK       vxge_mBIT(3)
-#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_REVERSE_LOOPBACK \
-                                                               vxge_mBIT(7)
-#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_TX_BEHAV       vxge_mBIT(11)
-#define        VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_RX_BEHAV       vxge_mBIT(15)
-       u8      unused002c0[0x002c0-0x002a8];
-
-/*0x002c0*/    u64     txmac_gen_cfg0_vpmgmt_clone;
-#define        VXGE_HW_TXMAC_GEN_CFG0_VPMGMT_CLONE_CHOSEN_TX_PORT      vxge_mBIT(7)
-/*0x002c8*/    u64     txmac_cfg0_port_vpmgmt_clone[3];
-#define        VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_TMAC_EN    vxge_mBIT(3)
-#define        VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_APPEND_PAD vxge_mBIT(7)
-#define VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_PAD_BYTE(val) vxge_vBIT(val, 8, 8)
-       u8      unused00300[0x00300-0x002e0];
-
-/*0x00300*/    u64     wol_mp_crc;
-#define VXGE_HW_WOL_MP_CRC_CRC(val) vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_WOL_MP_CRC_RC_EN        vxge_mBIT(63)
-/*0x00308*/    u64     wol_mp_mask_a;
-#define VXGE_HW_WOL_MP_MASK_A_MASK(val) vxge_vBIT(val, 0, 64)
-/*0x00310*/    u64     wol_mp_mask_b;
-#define VXGE_HW_WOL_MP_MASK_B_MASK(val) vxge_vBIT(val, 0, 64)
-       u8      unused00360[0x00360-0x00318];
-
-/*0x00360*/    u64     fau_pa_cfg_vpmgmt_clone;
-#define        VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L4_COMP_CSUM       vxge_mBIT(3)
-#define        VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_INCL_CF vxge_mBIT(7)
-#define        VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_COMP_CSUM       vxge_mBIT(11)
-/*0x00368*/    u64     rx_datapath_util_vp_clone;
-#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_UTILIZATION(val) \
-                                                       vxge_vBIT(val, 7, 9)
-#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_UTIL_CFG(val) \
-                                                       vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_FRAC_UTIL(val) \
-                                                       vxge_vBIT(val, 20, 4)
-#define        VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_PKT_WEIGHT(val) \
-                                                       vxge_vBIT(val, 24, 4)
-       u8      unused00380[0x00380-0x00370];
-
-/*0x00380*/    u64     tx_datapath_util_vp_clone;
-#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_UTILIZATION(val) \
-                                                       vxge_vBIT(val, 7, 9)
-#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_UTIL_CFG(val) \
-                                                       vxge_vBIT(val, 16, 4)
-#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_FRAC_UTIL(val) \
-                                                       vxge_vBIT(val, 20, 4)
-#define        VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_PKT_WEIGHT(val) \
-                                                       vxge_vBIT(val, 24, 4)
-
-} __packed;
-
-struct vxge_hw_vpath_reg {
-
-       u8      unused00300[0x00300];
-
-/*0x00300*/    u64     usdc_vpath;
-#define VXGE_HW_USDC_VPATH_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 32)
-       u8      unused00a00[0x00a00-0x00308];
-
-/*0x00a00*/    u64     wrdma_alarm_status;
-#define        VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT    vxge_mBIT(1)
-/*0x00a08*/    u64     wrdma_alarm_mask;
-       u8      unused00a30[0x00a30-0x00a10];
-
-/*0x00a30*/    u64     prc_alarm_reg;
-#define        VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP     vxge_mBIT(0)
-#define        VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR  vxge_mBIT(1)
-#define        VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT        vxge_mBIT(2)
-#define        VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR       vxge_mBIT(3)
-/*0x00a38*/    u64     prc_alarm_mask;
-/*0x00a40*/    u64     prc_alarm_alarm;
-/*0x00a48*/    u64     prc_cfg1;
-#define VXGE_HW_PRC_CFG1_RX_TIMER_VAL(val) vxge_vBIT(val, 3, 29)
-#define        VXGE_HW_PRC_CFG1_TIM_RING_BUMP_INT_ENABLE       vxge_mBIT(34)
-#define        VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE       vxge_mBIT(35)
-#define        VXGE_HW_PRC_CFG1_GREEDY_RETURN  vxge_mBIT(36)
-#define        VXGE_HW_PRC_CFG1_QUICK_SHOT     vxge_mBIT(37)
-#define        VXGE_HW_PRC_CFG1_RX_TIMER_CI    vxge_mBIT(39)
-#define VXGE_HW_PRC_CFG1_RESET_TIMER_ON_RXD_RET(val) vxge_vBIT(val, 40, 2)
-       u8      unused00a60[0x00a60-0x00a50];
-
-/*0x00a60*/    u64     prc_cfg4;
-#define        VXGE_HW_PRC_CFG4_IN_SVC vxge_mBIT(7)
-#define VXGE_HW_PRC_CFG4_RING_MODE(val) vxge_vBIT(val, 14, 2)
-#define        VXGE_HW_PRC_CFG4_RXD_NO_SNOOP   vxge_mBIT(22)
-#define        VXGE_HW_PRC_CFG4_FRM_NO_SNOOP   vxge_mBIT(23)
-#define        VXGE_HW_PRC_CFG4_RTH_DISABLE    vxge_mBIT(31)
-#define        VXGE_HW_PRC_CFG4_IGNORE_OWNERSHIP       vxge_mBIT(32)
-#define        VXGE_HW_PRC_CFG4_SIGNAL_BENIGN_OVFLW    vxge_mBIT(36)
-#define        VXGE_HW_PRC_CFG4_BIMODAL_INTERRUPT      vxge_mBIT(37)
-#define VXGE_HW_PRC_CFG4_BACKOFF_INTERVAL(val) vxge_vBIT(val, 40, 24)
-/*0x00a68*/    u64     prc_cfg5;
-#define VXGE_HW_PRC_CFG5_RXD0_ADD(val) vxge_vBIT(val, 0, 61)
-/*0x00a70*/    u64     prc_cfg6;
-#define        VXGE_HW_PRC_CFG6_FRM_PAD_EN     vxge_mBIT(0)
-#define        VXGE_HW_PRC_CFG6_QSIZE_ALIGNED_RXD      vxge_mBIT(2)
-#define        VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN       vxge_mBIT(5)
-#define        VXGE_HW_PRC_CFG6_L3_CPC_TRSFR_CODE_EN   vxge_mBIT(8)
-#define        VXGE_HW_PRC_CFG6_L4_CPC_TRSFR_CODE_EN   vxge_mBIT(9)
-#define VXGE_HW_PRC_CFG6_RXD_CRXDT(val) vxge_vBIT(val, 23, 9)
-#define VXGE_HW_PRC_CFG6_RXD_SPAT(val) vxge_vBIT(val, 36, 9)
-#define VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val)     vxge_bVALn(val, 36, 9)
-/*0x00a78*/    u64     prc_cfg7;
-#define VXGE_HW_PRC_CFG7_SCATTER_MODE(val) vxge_vBIT(val, 6, 2)
-#define        VXGE_HW_PRC_CFG7_SMART_SCAT_EN  vxge_mBIT(11)
-#define        VXGE_HW_PRC_CFG7_RXD_NS_CHG_EN  vxge_mBIT(12)
-#define        VXGE_HW_PRC_CFG7_NO_HDR_SEPARATION      vxge_mBIT(14)
-#define VXGE_HW_PRC_CFG7_RXD_BUFF_SIZE_MASK(val) vxge_vBIT(val, 20, 4)
-#define VXGE_HW_PRC_CFG7_BUFF_SIZE0_MASK(val) vxge_vBIT(val, 27, 5)
-/*0x00a80*/    u64     tim_dest_addr;
-#define VXGE_HW_TIM_DEST_ADDR_TIM_DEST_ADDR(val) vxge_vBIT(val, 0, 64)
-/*0x00a88*/    u64     prc_rxd_doorbell;
-#define VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val) vxge_vBIT(val, 48, 16)
-/*0x00a90*/    u64     rqa_prty_for_vp;
-#define VXGE_HW_RQA_PRTY_FOR_VP_RQA_PRTY_FOR_VP(val) vxge_vBIT(val, 59, 5)
-/*0x00a98*/    u64     rxdmem_size;
-#define VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(val) vxge_vBIT(val, 51, 13)
-/*0x00aa0*/    u64     frm_in_progress_cnt;
-#define        VXGE_HW_FRM_IN_PROGRESS_CNT_PRC_FRM_IN_PROGRESS_CNT(val) \
-                                                       vxge_vBIT(val, 59, 5)
-/*0x00aa8*/    u64     rx_multi_cast_stats;
-#define VXGE_HW_RX_MULTI_CAST_STATS_FRAME_DISCARD(val) vxge_vBIT(val, 48, 16)
-/*0x00ab0*/    u64     rx_frm_transferred;
-#define        VXGE_HW_RX_FRM_TRANSFERRED_RX_FRM_TRANSFERRED(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x00ab8*/    u64     rxd_returned;
-#define VXGE_HW_RXD_RETURNED_RXD_RETURNED(val) vxge_vBIT(val, 48, 16)
-       u8      unused00c00[0x00c00-0x00ac0];
-
-/*0x00c00*/    u64     kdfc_fifo_trpl_partition;
-#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_1(val) vxge_vBIT(val, 33, 15)
-#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_2(val) vxge_vBIT(val, 49, 15)
-/*0x00c08*/    u64     kdfc_fifo_trpl_ctrl;
-#define        VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE      vxge_mBIT(7)
-/*0x00c10*/    u64     kdfc_trpl_fifo_0_ctrl;
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(val) vxge_vBIT(val, 14, 2)
-#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_FLIP_EN   vxge_mBIT(22)
-#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN   vxge_mBIT(23)
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
-#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_CTRL_STRUC        vxge_mBIT(28)
-#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_ADD_PAD   vxge_mBIT(29)
-#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_NO_SNOOP  vxge_mBIT(30)
-#define        VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_RLX_ORD   vxge_mBIT(31)
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
-#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
-/*0x00c18*/    u64     kdfc_trpl_fifo_1_ctrl;
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE(val) vxge_vBIT(val, 14, 2)
-#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_FLIP_EN   vxge_mBIT(22)
-#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SWAP_EN   vxge_mBIT(23)
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
-#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_CTRL_STRUC        vxge_mBIT(28)
-#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_ADD_PAD   vxge_mBIT(29)
-#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_NO_SNOOP  vxge_mBIT(30)
-#define        VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_RLX_ORD   vxge_mBIT(31)
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
-#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
-/*0x00c20*/    u64     kdfc_trpl_fifo_2_ctrl;
-#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_FLIP_EN   vxge_mBIT(22)
-#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SWAP_EN   vxge_mBIT(23)
-#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2)
-#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_CTRL_STRUC        vxge_mBIT(28)
-#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_ADD_PAD   vxge_mBIT(29)
-#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_NO_SNOOP  vxge_mBIT(30)
-#define        VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_RLX_ORD   vxge_mBIT(31)
-#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SELECT(val) vxge_vBIT(val, 32, 8)
-#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7)
-#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16)
-/*0x00c28*/    u64     kdfc_trpl_fifo_0_wb_address;
-#define VXGE_HW_KDFC_TRPL_FIFO_0_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
-/*0x00c30*/    u64     kdfc_trpl_fifo_1_wb_address;
-#define VXGE_HW_KDFC_TRPL_FIFO_1_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
-/*0x00c38*/    u64     kdfc_trpl_fifo_2_wb_address;
-#define VXGE_HW_KDFC_TRPL_FIFO_2_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64)
-/*0x00c40*/    u64     kdfc_trpl_fifo_offset;
-#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR0(val) vxge_vBIT(val, 1, 15)
-#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR1(val) vxge_vBIT(val, 17, 15)
-#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR2(val) vxge_vBIT(val, 33, 15)
-/*0x00c48*/    u64     kdfc_drbl_triplet_total;
-#define        VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_KDFC_MAX_SIZE(val) \
-                                                       vxge_vBIT(val, 17, 15)
-       u8      unused00c60[0x00c60-0x00c50];
-
-/*0x00c60*/    u64     usdc_drbl_ctrl;
-#define        VXGE_HW_USDC_DRBL_CTRL_FLIP_EN  vxge_mBIT(22)
-#define        VXGE_HW_USDC_DRBL_CTRL_SWAP_EN  vxge_mBIT(23)
-/*0x00c68*/    u64     usdc_vp_ready;
-#define        VXGE_HW_USDC_VP_READY_USDC_HTN_READY    vxge_mBIT(7)
-#define        VXGE_HW_USDC_VP_READY_USDC_SRQ_READY    vxge_mBIT(15)
-#define        VXGE_HW_USDC_VP_READY_USDC_CQRQ_READY   vxge_mBIT(23)
-/*0x00c70*/    u64     kdfc_status;
-#define        VXGE_HW_KDFC_STATUS_KDFC_WRR_0_READY    vxge_mBIT(0)
-#define        VXGE_HW_KDFC_STATUS_KDFC_WRR_1_READY    vxge_mBIT(1)
-#define        VXGE_HW_KDFC_STATUS_KDFC_WRR_2_READY    vxge_mBIT(2)
-       u8      unused00c80[0x00c80-0x00c78];
-
-/*0x00c80*/    u64     xmac_rpa_vcfg;
-#define        VXGE_HW_XMAC_RPA_VCFG_IPV4_TCP_INCL_PH  vxge_mBIT(3)
-#define        VXGE_HW_XMAC_RPA_VCFG_IPV6_TCP_INCL_PH  vxge_mBIT(7)
-#define        VXGE_HW_XMAC_RPA_VCFG_IPV4_UDP_INCL_PH  vxge_mBIT(11)
-#define        VXGE_HW_XMAC_RPA_VCFG_IPV6_UDP_INCL_PH  vxge_mBIT(15)
-#define        VXGE_HW_XMAC_RPA_VCFG_L4_INCL_CF        vxge_mBIT(19)
-#define        VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG    vxge_mBIT(23)
-/*0x00c88*/    u64     rxmac_vcfg0;
-#define VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(val) vxge_vBIT(val, 2, 14)
-#define        VXGE_HW_RXMAC_VCFG0_RTS_USE_MIN_LEN     vxge_mBIT(19)
-#define VXGE_HW_RXMAC_VCFG0_RTS_MIN_FRM_LEN(val) vxge_vBIT(val, 26, 14)
-#define        VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN   vxge_mBIT(43)
-#define        VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN   vxge_mBIT(47)
-#define        VXGE_HW_RXMAC_VCFG0_BCAST_EN    vxge_mBIT(51)
-#define        VXGE_HW_RXMAC_VCFG0_ALL_VID_EN  vxge_mBIT(55)
-/*0x00c90*/    u64     rxmac_vcfg1;
-#define VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(val) vxge_vBIT(val, 42, 2)
-#define        VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE    vxge_mBIT(47)
-#define        VXGE_HW_RXMAC_VCFG1_CONTRIB_L2_FLOW     vxge_mBIT(51)
-/*0x00c98*/    u64     rts_access_steer_ctrl;
-#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(val) vxge_vBIT(val, 1, 7)
-#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(val) vxge_vBIT(val, 8, 4)
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE    vxge_mBIT(15)
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_BEHAV_TBL_SEL     vxge_mBIT(23)
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL vxge_mBIT(27)
-#define        VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS      vxge_mBIT(0)
-#define VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(val) vxge_vBIT(val, 40, 8)
-/*0x00ca0*/    u64     rts_access_steer_data0;
-#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DATA(val) vxge_vBIT(val, 0, 64)
-/*0x00ca8*/    u64     rts_access_steer_data1;
-#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DATA(val) vxge_vBIT(val, 0, 64)
-       u8      unused00d00[0x00d00-0x00cb0];
-
-/*0x00d00*/    u64     xmac_vsport_choice;
-#define VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(val) vxge_vBIT(val, 3, 5)
-/*0x00d08*/    u64     xmac_stats_cfg;
-/*0x00d10*/    u64     xmac_stats_access_cmd;
-#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(val) vxge_vBIT(val, 6, 2)
-#define        VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE    vxge_mBIT(15)
-#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8)
-/*0x00d18*/    u64     xmac_stats_access_data;
-#define VXGE_HW_XMAC_STATS_ACCESS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64)
-/*0x00d20*/    u64     asic_ntwk_vp_ctrl;
-#define        VXGE_HW_ASIC_NTWK_VP_CTRL_REQ_TEST_NTWK vxge_mBIT(3)
-#define        VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_SHOW_PORT_INFO  vxge_mBIT(55)
-#define        VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_PORT_NUM        vxge_mBIT(63)
-       u8      unused00d30[0x00d30-0x00d28];
-
-/*0x00d30*/    u64     xgmac_vp_int_status;
-#define        VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT \
-                                                               vxge_mBIT(3)
-/*0x00d38*/    u64     xgmac_vp_int_mask;
-/*0x00d40*/    u64     asic_ntwk_vp_err_reg;
-#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT        vxge_mBIT(3)
-#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK vxge_mBIT(7)
-#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR \
-                                                               vxge_mBIT(11)
-#define        VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR \
-                                                       vxge_mBIT(15)
-#define        VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT \
-                                                       vxge_mBIT(19)
-#define        VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK   vxge_mBIT(23)
-/*0x00d48*/    u64     asic_ntwk_vp_err_mask;
-/*0x00d50*/    u64     asic_ntwk_vp_err_alarm;
-       u8      unused00d80[0x00d80-0x00d58];
-
-/*0x00d80*/    u64     rtdma_bw_ctrl;
-#define        VXGE_HW_RTDMA_BW_CTRL_BW_CTRL_EN        vxge_mBIT(39)
-#define VXGE_HW_RTDMA_BW_CTRL_DESIRED_BW(val) vxge_vBIT(val, 46, 18)
-/*0x00d88*/    u64     rtdma_rd_optimization_ctrl;
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_GEN_INT_AFTER_ABORT  vxge_mBIT(3)
-#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_MODE(val) vxge_vBIT(val, 6, 2)
-#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_PATTERN(val) vxge_vBIT(val, 8, 8)
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE    vxge_mBIT(19)
-#define VXGE_HW_PCI_EXP_DEVCTL_READRQ   0x7000  /* Max_Read_Request_Size */
-#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val) \
-                                                       vxge_vBIT(val, 21, 3)
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK_EN    vxge_mBIT(28)
-#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK(val) \
-                                                       vxge_vBIT(val, 29, 3)
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN      vxge_mBIT(35)
-#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(val) \
-                                                       vxge_vBIT(val, 37, 3)
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_WAIT_FOR_SPACE   vxge_mBIT(43)
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_FILL_THRESH(val) \
-                                                       vxge_vBIT(val, 51, 5)
-#define        VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY_EN     vxge_mBIT(59)
-#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY(val) \
-                                                       vxge_vBIT(val, 61, 3)
-/*0x00d90*/    u64     pda_pcc_job_monitor;
-#define        VXGE_HW_PDA_PCC_JOB_MONITOR_PDA_PCC_JOB_STATUS  vxge_mBIT(7)
-/*0x00d98*/    u64     tx_protocol_assist_cfg;
-#define        VXGE_HW_TX_PROTOCOL_ASSIST_CFG_LSOV2_EN vxge_mBIT(6)
-#define        VXGE_HW_TX_PROTOCOL_ASSIST_CFG_IPV6_KEEP_SEARCHING      vxge_mBIT(7)
-       u8      unused01000[0x01000-0x00da0];
-
-/*0x01000*/    u64     tim_cfg1_int_num[4];
-#define VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(val) vxge_vBIT(val, 6, 26)
-#define        VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN       vxge_mBIT(35)
-#define        VXGE_HW_TIM_CFG1_INT_NUM_TXFRM_CNT_EN   vxge_mBIT(36)
-#define        VXGE_HW_TIM_CFG1_INT_NUM_TXD_CNT_EN     vxge_mBIT(37)
-#define        VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC       vxge_mBIT(38)
-#define        VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI       vxge_mBIT(39)
-#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(val) vxge_vBIT(val, 41, 7)
-#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(val) vxge_vBIT(val, 49, 7)
-#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(val) vxge_vBIT(val, 57, 7)
-/*0x01020*/    u64     tim_cfg2_int_num[4];
-#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(val) vxge_vBIT(val, 32, 16)
-#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(val) vxge_vBIT(val, 48, 16)
-/*0x01040*/    u64     tim_cfg3_int_num[4];
-#define        VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI       vxge_mBIT(0)
-#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(val) vxge_vBIT(val, 1, 4)
-#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(val) vxge_vBIT(val, 6, 26)
-#define VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(val) vxge_vBIT(val, 32, 6)
-#define VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(val) vxge_vBIT(val, 38, 26)
-/*0x01060*/    u64     tim_wrkld_clc;
-#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_PRD(val) vxge_vBIT(val, 0, 32)
-#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_DIV(val) vxge_vBIT(val, 35, 5)
-#define        VXGE_HW_TIM_WRKLD_CLC_CNT_FRM_BYTE      vxge_mBIT(40)
-#define VXGE_HW_TIM_WRKLD_CLC_CNT_RX_TX(val) vxge_vBIT(val, 41, 2)
-#define        VXGE_HW_TIM_WRKLD_CLC_CNT_LNK_EN        vxge_mBIT(43)
-#define VXGE_HW_TIM_WRKLD_CLC_HOST_UTIL(val) vxge_vBIT(val, 57, 7)
-/*0x01068*/    u64     tim_bitmap;
-#define VXGE_HW_TIM_BITMAP_MASK(val) vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_TIM_BITMAP_LLROOT_RXD_EN        vxge_mBIT(32)
-#define        VXGE_HW_TIM_BITMAP_LLROOT_TXD_EN        vxge_mBIT(33)
-/*0x01070*/    u64     tim_ring_assn;
-#define VXGE_HW_TIM_RING_ASSN_INT_NUM(val) vxge_vBIT(val, 6, 2)
-/*0x01078*/    u64     tim_remap;
-#define        VXGE_HW_TIM_REMAP_TX_EN vxge_mBIT(5)
-#define        VXGE_HW_TIM_REMAP_RX_EN vxge_mBIT(6)
-#define        VXGE_HW_TIM_REMAP_OFFLOAD_EN    vxge_mBIT(7)
-#define VXGE_HW_TIM_REMAP_TO_VPATH_NUM(val) vxge_vBIT(val, 11, 5)
-/*0x01080*/    u64     tim_vpath_map;
-#define VXGE_HW_TIM_VPATH_MAP_BMAP_ROOT(val) vxge_vBIT(val, 0, 32)
-/*0x01088*/    u64     tim_pci_cfg;
-#define        VXGE_HW_TIM_PCI_CFG_ADD_PAD     vxge_mBIT(7)
-#define        VXGE_HW_TIM_PCI_CFG_NO_SNOOP    vxge_mBIT(15)
-#define        VXGE_HW_TIM_PCI_CFG_RELAXED     vxge_mBIT(23)
-#define        VXGE_HW_TIM_PCI_CFG_CTL_STR     vxge_mBIT(31)
-       u8      unused01100[0x01100-0x01090];
-
-/*0x01100*/    u64     sgrp_assign;
-#define VXGE_HW_SGRP_ASSIGN_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 64)
-/*0x01108*/    u64     sgrp_aoa_and_result;
-#define        VXGE_HW_SGRP_AOA_AND_RESULT_PET_SGRP_AOA_AND_RESULT(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x01110*/    u64     rpe_pci_cfg;
-#define        VXGE_HW_RPE_PCI_CFG_PAD_LRO_DATA_ENABLE vxge_mBIT(7)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_LRO_HDR_ENABLE  vxge_mBIT(8)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_LRO_CQE_ENABLE  vxge_mBIT(9)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_NONLL_CQE_ENABLE        vxge_mBIT(10)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_BASE_LL_CQE_ENABLE      vxge_mBIT(11)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_LL_CQE_IDATA_ENABLE     vxge_mBIT(12)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_CQRQ_IR_ENABLE  vxge_mBIT(13)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_CQSQ_IR_ENABLE  vxge_mBIT(14)
-#define        VXGE_HW_RPE_PCI_CFG_PAD_CQRR_IR_ENABLE  vxge_mBIT(15)
-#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_DATA        vxge_mBIT(18)
-#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_NONLL_CQE   vxge_mBIT(19)
-#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_LL_CQE      vxge_mBIT(20)
-#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRQ_IR     vxge_mBIT(21)
-#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQSQ_IR     vxge_mBIT(22)
-#define        VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRR_IR     vxge_mBIT(23)
-#define        VXGE_HW_RPE_PCI_CFG_RELAXED_DATA        vxge_mBIT(26)
-#define        VXGE_HW_RPE_PCI_CFG_RELAXED_NONLL_CQE   vxge_mBIT(27)
-#define        VXGE_HW_RPE_PCI_CFG_RELAXED_LL_CQE      vxge_mBIT(28)
-#define        VXGE_HW_RPE_PCI_CFG_RELAXED_CQRQ_IR     vxge_mBIT(29)
-#define        VXGE_HW_RPE_PCI_CFG_RELAXED_CQSQ_IR     vxge_mBIT(30)
-#define        VXGE_HW_RPE_PCI_CFG_RELAXED_CQRR_IR     vxge_mBIT(31)
-/*0x01118*/    u64     rpe_lro_cfg;
-#define        VXGE_HW_RPE_LRO_CFG_SUPPRESS_LRO_ETH_TRLR       vxge_mBIT(7)
-#define        VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_SNAP_SNAPJUMBO_MRG        vxge_mBIT(11)
-#define        VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_LLC_LLCJUMBO_MRG  vxge_mBIT(15)
-#define        VXGE_HW_RPE_LRO_CFG_INCL_ACK_CNT_IN_CQE vxge_mBIT(23)
-/*0x01120*/    u64     pe_mr2vp_ack_blk_limit;
-#define VXGE_HW_PE_MR2VP_ACK_BLK_LIMIT_BLK_LIMIT(val) vxge_vBIT(val, 32, 32)
-/*0x01128*/    u64     pe_mr2vp_rirr_lirr_blk_limit;
-#define        VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_RIRR_BLK_LIMIT(val) \
-                                                       vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_LIRR_BLK_LIMIT(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x01130*/    u64     txpe_pci_nce_cfg;
-#define VXGE_HW_TXPE_PCI_NCE_CFG_NCE_THRESH(val) vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_TXPE_PCI_NCE_CFG_PAD_TOWI_ENABLE        vxge_mBIT(55)
-#define        VXGE_HW_TXPE_PCI_NCE_CFG_NOSNOOP_TOWI   vxge_mBIT(63)
-       u8      unused01180[0x01180-0x01138];
-
-/*0x01180*/    u64     msg_qpad_en_cfg;
-#define        VXGE_HW_MSG_QPAD_EN_CFG_UMQ_BWR_READ    vxge_mBIT(3)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_DMQ_BWR_READ    vxge_mBIT(7)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_READ vxge_mBIT(11)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_READ vxge_mBIT(15)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_UMQ_MSG_WRITE   vxge_mBIT(19)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_UMQDMQ_IR_WRITE vxge_mBIT(23)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_WRITE        vxge_mBIT(27)
-#define        VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_WRITE        vxge_mBIT(31)
-/*0x01188*/    u64     msg_pci_cfg;
-#define        VXGE_HW_MSG_PCI_CFG_GENDMA_NO_SNOOP     vxge_mBIT(3)
-#define        VXGE_HW_MSG_PCI_CFG_UMQDMQ_IR_NO_SNOOP  vxge_mBIT(7)
-#define        VXGE_HW_MSG_PCI_CFG_UMQ_NO_SNOOP        vxge_mBIT(11)
-#define        VXGE_HW_MSG_PCI_CFG_DMQ_NO_SNOOP        vxge_mBIT(15)
-/*0x01190*/    u64     umqdmq_ir_init;
-#define VXGE_HW_UMQDMQ_IR_INIT_HOST_WRITE_ADD(val) vxge_vBIT(val, 0, 64)
-/*0x01198*/    u64     dmq_ir_int;
-#define        VXGE_HW_DMQ_IR_INT_IMMED_ENABLE vxge_mBIT(6)
-#define        VXGE_HW_DMQ_IR_INT_EVENT_ENABLE vxge_mBIT(7)
-#define VXGE_HW_DMQ_IR_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
-#define VXGE_HW_DMQ_IR_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
-/*0x011a0*/    u64     dmq_bwr_init_add;
-#define VXGE_HW_DMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64)
-/*0x011a8*/    u64     dmq_bwr_init_byte;
-#define VXGE_HW_DMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
-/*0x011b0*/    u64     dmq_ir;
-#define VXGE_HW_DMQ_IR_POLICY(val) vxge_vBIT(val, 0, 8)
-/*0x011b8*/    u64     umq_int;
-#define        VXGE_HW_UMQ_INT_IMMED_ENABLE    vxge_mBIT(6)
-#define        VXGE_HW_UMQ_INT_EVENT_ENABLE    vxge_mBIT(7)
-#define VXGE_HW_UMQ_INT_NUMBER(val) vxge_vBIT(val, 9, 7)
-#define VXGE_HW_UMQ_INT_BITMAP(val) vxge_vBIT(val, 16, 16)
-/*0x011c0*/    u64     umq_mr2vp_bwr_pfch_init;
-#define VXGE_HW_UMQ_MR2VP_BWR_PFCH_INIT_NUMBER(val) vxge_vBIT(val, 0, 8)
-/*0x011c8*/    u64     umq_bwr_pfch_ctrl;
-#define        VXGE_HW_UMQ_BWR_PFCH_CTRL_POLL_EN       vxge_mBIT(3)
-/*0x011d0*/    u64     umq_mr2vp_bwr_eol;
-#define VXGE_HW_UMQ_MR2VP_BWR_EOL_POLL_LATENCY(val) vxge_vBIT(val, 32, 32)
-/*0x011d8*/    u64     umq_bwr_init_add;
-#define VXGE_HW_UMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64)
-/*0x011e0*/    u64     umq_bwr_init_byte;
-#define VXGE_HW_UMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32)
-/*0x011e8*/    u64     gendma_int;
-/*0x011f0*/    u64     umqdmq_ir_init_notify;
-#define        VXGE_HW_UMQDMQ_IR_INIT_NOTIFY_PULSE     vxge_mBIT(3)
-/*0x011f8*/    u64     dmq_init_notify;
-#define        VXGE_HW_DMQ_INIT_NOTIFY_PULSE   vxge_mBIT(3)
-/*0x01200*/    u64     umq_init_notify;
-#define        VXGE_HW_UMQ_INIT_NOTIFY_PULSE   vxge_mBIT(3)
-       u8      unused01380[0x01380-0x01208];
-
-/*0x01380*/    u64     tpa_cfg;
-#define        VXGE_HW_TPA_CFG_IGNORE_FRAME_ERR        vxge_mBIT(3)
-#define        VXGE_HW_TPA_CFG_IPV6_STOP_SEARCHING     vxge_mBIT(7)
-#define        VXGE_HW_TPA_CFG_L4_PSHDR_PRESENT        vxge_mBIT(11)
-#define        VXGE_HW_TPA_CFG_SUPPORT_MOBILE_IPV6_HDRS        vxge_mBIT(15)
-       u8      unused01400[0x01400-0x01388];
-
-/*0x01400*/    u64     tx_vp_reset_discarded_frms;
-#define        VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_TX_VP_RESET_DISCARDED_FRMS(val) \
-                                                       vxge_vBIT(val, 48, 16)
-       u8      unused01480[0x01480-0x01408];
-
-/*0x01480*/    u64     fau_rpa_vcfg;
-#define        VXGE_HW_FAU_RPA_VCFG_L4_COMP_CSUM       vxge_mBIT(7)
-#define        VXGE_HW_FAU_RPA_VCFG_L3_INCL_CF vxge_mBIT(11)
-#define        VXGE_HW_FAU_RPA_VCFG_L3_COMP_CSUM       vxge_mBIT(15)
-       u8      unused014d0[0x014d0-0x01488];
-
-/*0x014d0*/    u64     dbg_stats_rx_mpa;
-#define VXGE_HW_DBG_STATS_RX_MPA_CRC_FAIL_FRMS(val) vxge_vBIT(val, 0, 16)
-#define VXGE_HW_DBG_STATS_RX_MPA_MRK_FAIL_FRMS(val) vxge_vBIT(val, 16, 16)
-#define VXGE_HW_DBG_STATS_RX_MPA_LEN_FAIL_FRMS(val) vxge_vBIT(val, 32, 16)
-/*0x014d8*/    u64     dbg_stats_rx_fau;
-#define VXGE_HW_DBG_STATS_RX_FAU_RX_WOL_FRMS(val) vxge_vBIT(val, 0, 16)
-#define        VXGE_HW_DBG_STATS_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val) \
-                                                       vxge_vBIT(val, 16, 16)
-#define        VXGE_HW_DBG_STATS_RX_FAU_RX_PERMITTED_FRMS(val) \
-                                                       vxge_vBIT(val, 32, 32)
-       u8      unused014f0[0x014f0-0x014e0];
-
-/*0x014f0*/    u64     fbmc_vp_rdy;
-#define        VXGE_HW_FBMC_VP_RDY_QUEUE_SPAV_FM       vxge_mBIT(0)
-       u8      unused01e00[0x01e00-0x014f8];
-
-/*0x01e00*/    u64     vpath_pcipif_int_status;
-#define \
-VXGE_HW_VPATH_PCIPIF_INT_STATUS_SRPCIM_MSG_TO_VPATH_SRPCIM_MSG_TO_VPATH_INT \
-                                                               vxge_mBIT(3)
-#define        VXGE_HW_VPATH_PCIPIF_INT_STATUS_VPATH_SPARE_R1_VPATH_SPARE_R1_INT \
-                                                               vxge_mBIT(7)
-/*0x01e08*/    u64     vpath_pcipif_int_mask;
-       u8      unused01e20[0x01e20-0x01e10];
-
-/*0x01e20*/    u64     srpcim_msg_to_vpath_reg;
-#define        VXGE_HW_SRPCIM_MSG_TO_VPATH_REG_SWIF_SRPCIM_TO_VPATH_RMSG_INT \
-                                                               vxge_mBIT(3)
-/*0x01e28*/    u64     srpcim_msg_to_vpath_mask;
-/*0x01e30*/    u64     srpcim_msg_to_vpath_alarm;
-       u8      unused01ea0[0x01ea0-0x01e38];
-
-/*0x01ea0*/    u64     vpath_to_srpcim_wmsg;
-#define VXGE_HW_VPATH_TO_SRPCIM_WMSG_VPATH_TO_SRPCIM_WMSG(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x01ea8*/    u64     vpath_to_srpcim_wmsg_trig;
-#define        VXGE_HW_VPATH_TO_SRPCIM_WMSG_TRIG_VPATH_TO_SRPCIM_WMSG_TRIG \
-                                                       vxge_mBIT(0)
-       u8      unused02000[0x02000-0x01eb0];
-
-/*0x02000*/    u64     vpath_general_int_status;
-#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT        vxge_mBIT(3)
-#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT        vxge_mBIT(7)
-#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT      vxge_mBIT(15)
-#define        VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT       vxge_mBIT(19)
-/*0x02008*/    u64     vpath_general_int_mask;
-#define        VXGE_HW_VPATH_GENERAL_INT_MASK_PIC_INT  vxge_mBIT(3)
-#define        VXGE_HW_VPATH_GENERAL_INT_MASK_PCI_INT  vxge_mBIT(7)
-#define        VXGE_HW_VPATH_GENERAL_INT_MASK_WRDMA_INT        vxge_mBIT(15)
-#define        VXGE_HW_VPATH_GENERAL_INT_MASK_XMAC_INT vxge_mBIT(19)
-/*0x02010*/    u64     vpath_ppif_int_status;
-#define        VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT \
-                                                       vxge_mBIT(3)
-#define        VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT \
-                                                       vxge_mBIT(7)
-#define        VXGE_HW_VPATH_PPIF_INT_STATUS_PCI_CONFIG_ERRORS_PCI_CONFIG_INT \
-                                                       vxge_mBIT(11)
-#define \
-VXGE_HW_VPATH_PPIF_INT_STATUS_MRPCIM_TO_VPATH_ALARM_MRPCIM_TO_VPATH_ALARM_INT \
-                                                       vxge_mBIT(15)
-#define \
-VXGE_HW_VPATH_PPIF_INT_STATUS_SRPCIM_TO_VPATH_ALARM_SRPCIM_TO_VPATH_ALARM_INT \
-                                                       vxge_mBIT(19)
-/*0x02018*/    u64     vpath_ppif_int_mask;
-/*0x02020*/    u64     kdfcctl_errors_reg;
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR  vxge_mBIT(3)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR  vxge_mBIT(7)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR  vxge_mBIT(11)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON vxge_mBIT(15)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON vxge_mBIT(19)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON vxge_mBIT(23)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR        vxge_mBIT(31)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR        vxge_mBIT(35)
-#define        VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_DMA_ERR        vxge_mBIT(39)
-/*0x02028*/    u64     kdfcctl_errors_mask;
-/*0x02030*/    u64     kdfcctl_errors_alarm;
-       u8      unused02040[0x02040-0x02038];
-
-/*0x02040*/    u64     general_errors_reg;
-#define        VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW vxge_mBIT(3)
-#define        VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW vxge_mBIT(7)
-#define        VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW vxge_mBIT(11)
-#define        VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR vxge_mBIT(15)
-#define        VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ      vxge_mBIT(19)
-#define        VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS   vxge_mBIT(27)
-#define        VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET vxge_mBIT(31)
-/*0x02048*/    u64     general_errors_mask;
-/*0x02050*/    u64     general_errors_alarm;
-/*0x02058*/    u64     pci_config_errors_reg;
-#define        VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_STATUS_ERR      vxge_mBIT(3)
-#define        VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_UNCOR_ERR       vxge_mBIT(7)
-#define        VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_COR_ERR vxge_mBIT(11)
-/*0x02060*/    u64     pci_config_errors_mask;
-/*0x02068*/    u64     pci_config_errors_alarm;
-/*0x02070*/    u64     mrpcim_to_vpath_alarm_reg;
-#define        VXGE_HW_MRPCIM_TO_VPATH_ALARM_REG_PPIF_MRPCIM_TO_VPATH_ALARM \
-                                                               vxge_mBIT(3)
-/*0x02078*/    u64     mrpcim_to_vpath_alarm_mask;
-/*0x02080*/    u64     mrpcim_to_vpath_alarm_alarm;
-/*0x02088*/    u64     srpcim_to_vpath_alarm_reg;
-#define        VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_PPIF_SRPCIM_TO_VPATH_ALARM(val) \
-                                                       vxge_vBIT(val, 0, 17)
-/*0x02090*/    u64     srpcim_to_vpath_alarm_mask;
-/*0x02098*/    u64     srpcim_to_vpath_alarm_alarm;
-       u8      unused02108[0x02108-0x020a0];
-
-/*0x02108*/    u64     kdfcctl_status;
-#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_PRES(val) vxge_vBIT(val, 0, 8)
-#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_PRES(val) vxge_vBIT(val, 8, 8)
-#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_PRES(val) vxge_vBIT(val, 16, 8)
-#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_OVRWR(val) vxge_vBIT(val, 24, 8)
-#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_OVRWR(val) vxge_vBIT(val, 32, 8)
-#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_OVRWR(val) vxge_vBIT(val, 40, 8)
-/*0x02110*/    u64     rsthdlr_status;
-#define        VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_RESET    vxge_mBIT(3)
-#define VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_VPIN(val) vxge_vBIT(val, 6, 2)
-/*0x02118*/    u64     fifo0_status;
-#define VXGE_HW_FIFO0_STATUS_DBLGEN_FIFO0_RDIDX(val) vxge_vBIT(val, 0, 12)
-/*0x02120*/    u64     fifo1_status;
-#define VXGE_HW_FIFO1_STATUS_DBLGEN_FIFO1_RDIDX(val) vxge_vBIT(val, 0, 12)
-/*0x02128*/    u64     fifo2_status;
-#define VXGE_HW_FIFO2_STATUS_DBLGEN_FIFO2_RDIDX(val) vxge_vBIT(val, 0, 12)
-       u8      unused02158[0x02158-0x02130];
-
-/*0x02158*/    u64     tgt_illegal_access;
-#define VXGE_HW_TGT_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7)
-       u8      unused02200[0x02200-0x02160];
-
-/*0x02200*/    u64     vpath_general_cfg1;
-#define VXGE_HW_VPATH_GENERAL_CFG1_TC_VALUE(val) vxge_vBIT(val, 1, 3)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_DATA_BYTE_SWAPEN     vxge_mBIT(7)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_DATA_FLIPEN  vxge_mBIT(11)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN      vxge_mBIT(15)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_CTL_FLIPEN   vxge_mBIT(23)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_SWAPEN     vxge_mBIT(51)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_FLIPEN     vxge_mBIT(55)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_SWAPEN     vxge_mBIT(59)
-#define        VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_FLIPEN     vxge_mBIT(63)
-/*0x02208*/    u64     vpath_general_cfg2;
-#define VXGE_HW_VPATH_GENERAL_CFG2_SIZE_QUANTUM(val) vxge_vBIT(val, 1, 3)
-/*0x02210*/    u64     vpath_general_cfg3;
-#define        VXGE_HW_VPATH_GENERAL_CFG3_IGNORE_VPATH_RST_FOR_INTA    vxge_mBIT(3)
-       u8      unused02220[0x02220-0x02218];
-
-/*0x02220*/    u64     kdfcctl_cfg0;
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0  vxge_mBIT(1)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1  vxge_mBIT(2)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2  vxge_mBIT(3)
-#define        VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO0   vxge_mBIT(5)
-#define        VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO1   vxge_mBIT(6)
-#define        VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO2   vxge_mBIT(7)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO0      vxge_mBIT(9)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO1      vxge_mBIT(10)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO2      vxge_mBIT(11)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO0      vxge_mBIT(13)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO1      vxge_mBIT(14)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO2      vxge_mBIT(15)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO0      vxge_mBIT(17)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO1      vxge_mBIT(18)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO2      vxge_mBIT(19)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO0      vxge_mBIT(21)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO1      vxge_mBIT(22)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO2      vxge_mBIT(23)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO0      vxge_mBIT(25)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO1      vxge_mBIT(26)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO2      vxge_mBIT(27)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO0      vxge_mBIT(29)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO1      vxge_mBIT(30)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO2      vxge_mBIT(31)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO0      vxge_mBIT(33)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO1      vxge_mBIT(34)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO2      vxge_mBIT(35)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO0      vxge_mBIT(37)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO1      vxge_mBIT(38)
-#define        VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO2      vxge_mBIT(39)
-
-       u8      unused02268[0x02268-0x02228];
-
-/*0x02268*/    u64     stats_cfg;
-#define VXGE_HW_STATS_CFG_START_HOST_ADDR(val) vxge_vBIT(val, 0, 57)
-/*0x02270*/    u64     interrupt_cfg0;
-#define VXGE_HW_INTERRUPT_CFG0_MSIX_FOR_RXTI(val) vxge_vBIT(val, 1, 7)
-#define VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(val) vxge_vBIT(val, 9, 7)
-#define VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(val) vxge_vBIT(val, 17, 7)
-#define VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI(val) vxge_vBIT(val, 25, 7)
-#define VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI(val) vxge_vBIT(val, 33, 7)
-       u8      unused02280[0x02280-0x02278];
-
-/*0x02280*/    u64     interrupt_cfg2;
-#define VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7)
-/*0x02288*/    u64     one_shot_vect0_en;
-#define        VXGE_HW_ONE_SHOT_VECT0_EN_ONE_SHOT_VECT0_EN     vxge_mBIT(3)
-/*0x02290*/    u64     one_shot_vect1_en;
-#define        VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN     vxge_mBIT(3)
-/*0x02298*/    u64     one_shot_vect2_en;
-#define        VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN     vxge_mBIT(3)
-/*0x022a0*/    u64     one_shot_vect3_en;
-#define        VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN     vxge_mBIT(3)
-       u8      unused022b0[0x022b0-0x022a8];
-
-/*0x022b0*/    u64     pci_config_access_cfg1;
-#define VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(val) vxge_vBIT(val, 0, 12)
-#define        VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0        vxge_mBIT(15)
-/*0x022b8*/    u64     pci_config_access_cfg2;
-#define        VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ      vxge_mBIT(0)
-/*0x022c0*/    u64     pci_config_access_status;
-#define        VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR     vxge_mBIT(0)
-#define VXGE_HW_PCI_CONFIG_ACCESS_STATUS_DATA(val) vxge_vBIT(val, 32, 32)
-       u8      unused02300[0x02300-0x022c8];
-
-/*0x02300*/    u64     vpath_debug_stats0;
-#define VXGE_HW_VPATH_DEBUG_STATS0_INI_NUM_MWR_SENT(val) vxge_vBIT(val, 0, 32)
-/*0x02308*/    u64     vpath_debug_stats1;
-#define VXGE_HW_VPATH_DEBUG_STATS1_INI_NUM_MRD_SENT(val) vxge_vBIT(val, 0, 32)
-/*0x02310*/    u64     vpath_debug_stats2;
-#define VXGE_HW_VPATH_DEBUG_STATS2_INI_NUM_CPL_RCVD(val) vxge_vBIT(val, 0, 32)
-/*0x02318*/    u64     vpath_debug_stats3;
-#define VXGE_HW_VPATH_DEBUG_STATS3_INI_NUM_MWR_BYTE_SENT(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x02320*/    u64     vpath_debug_stats4;
-#define VXGE_HW_VPATH_DEBUG_STATS4_INI_NUM_CPL_BYTE_RCVD(val) \
-                                                       vxge_vBIT(val, 0, 64)
-/*0x02328*/    u64     vpath_debug_stats5;
-#define VXGE_HW_VPATH_DEBUG_STATS5_WRCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32)
-/*0x02330*/    u64     vpath_debug_stats6;
-#define VXGE_HW_VPATH_DEBUG_STATS6_RDCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32)
-/*0x02338*/    u64     vpath_genstats_count01;
-#define        VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT1(val) \
-                                                       vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT0(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x02340*/    u64     vpath_genstats_count23;
-#define        VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT3(val) \
-                                                       vxge_vBIT(val, 0, 32)
-#define        VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT2(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x02348*/    u64     vpath_genstats_count4;
-#define        VXGE_HW_VPATH_GENSTATS_COUNT4_PPIF_VPATH_GENSTATS_COUNT4(val) \
-                                                       vxge_vBIT(val, 32, 32)
-/*0x02350*/    u64     vpath_genstats_count5;
-#define        VXGE_HW_VPATH_GENSTATS_COUNT5_PPIF_VPATH_GENSTATS_COUNT5(val) \
-                                                       vxge_vBIT(val, 32, 32)
-       u8      unused02648[0x02648-0x02358];
-} __packed;
-
-#define VXGE_HW_EEPROM_SIZE    (0x01 << 11)
-
-/* Capability lists */
-#define  VXGE_HW_PCI_EXP_LNKCAP_LNK_SPEED    0xf  /* Supported Link speeds */
-#define  VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH    0x3f0 /* Supported Link speeds. */
-#define  VXGE_HW_PCI_EXP_LNKCAP_LW_RES       0x0  /* Reserved. */
-
-#endif
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.c b/drivers/net/ethernet/neterion/vxge/vxge-traffic.c
deleted file mode 100644 (file)
index ee16497..0000000
+++ /dev/null
@@ -1,2428 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-traffic.c: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#include <linux/etherdevice.h>
-#include <linux/io-64-nonatomic-lo-hi.h>
-#include <linux/prefetch.h>
-
-#include "vxge-traffic.h"
-#include "vxge-config.h"
-#include "vxge-main.h"
-
-/*
- * vxge_hw_vpath_intr_enable - Enable vpath interrupts.
- * @vp: Virtual Path handle.
- *
- * Enable vpath interrupts. The function is to be executed the last in
- * vpath initialization sequence.
- *
- * See also: vxge_hw_vpath_intr_disable()
- */
-enum vxge_hw_status vxge_hw_vpath_intr_enable(struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_virtualpath *vpath;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-
-       vp_reg = vpath->vp_reg;
-
-       writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->general_errors_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->pci_config_errors_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->mrpcim_to_vpath_alarm_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->srpcim_to_vpath_alarm_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->vpath_ppif_int_status);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->srpcim_msg_to_vpath_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->vpath_pcipif_int_status);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->prc_alarm_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->wrdma_alarm_status);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->asic_ntwk_vp_err_reg);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->xgmac_vp_int_status);
-
-       readq(&vp_reg->vpath_general_int_status);
-
-       /* Mask unwanted interrupts */
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->vpath_pcipif_int_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->srpcim_msg_to_vpath_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->srpcim_to_vpath_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->mrpcim_to_vpath_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->pci_config_errors_mask);
-
-       /* Unmask the individual interrupts */
-
-       writeq((u32)vxge_bVALn((VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW|
-               VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW|
-               VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ|
-               VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR), 0, 32),
-               &vp_reg->general_errors_mask);
-
-       __vxge_hw_pio_mem_write32_upper(
-               (u32)vxge_bVALn((VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR|
-               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR|
-               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON|
-               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON|
-               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR|
-               VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_DMA_ERR), 0, 32),
-               &vp_reg->kdfcctl_errors_mask);
-
-       __vxge_hw_pio_mem_write32_upper(0, &vp_reg->vpath_ppif_int_mask);
-
-       __vxge_hw_pio_mem_write32_upper(
-               (u32)vxge_bVALn(VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP, 0, 32),
-               &vp_reg->prc_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper(0, &vp_reg->wrdma_alarm_mask);
-       __vxge_hw_pio_mem_write32_upper(0, &vp_reg->xgmac_vp_int_mask);
-
-       if (vpath->hldev->first_vp_id != vpath->vp_id)
-               __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->asic_ntwk_vp_err_mask);
-       else
-               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn((
-               VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT |
-               VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK), 0, 32),
-               &vp_reg->asic_ntwk_vp_err_mask);
-
-       __vxge_hw_pio_mem_write32_upper(0,
-               &vp_reg->vpath_general_int_mask);
-exit:
-       return status;
-
-}
-
-/*
- * vxge_hw_vpath_intr_disable - Disable vpath interrupts.
- * @vp: Virtual Path handle.
- *
- * Disable vpath interrupts. The function is to be executed the last in
- * vpath initialization sequence.
- *
- * See also: vxge_hw_vpath_intr_enable()
- */
-enum vxge_hw_status vxge_hw_vpath_intr_disable(
-                       struct __vxge_hw_vpath_handle *vp)
-{
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) {
-               status = VXGE_HW_ERR_VPATH_NOT_OPEN;
-               goto exit;
-       }
-       vp_reg = vpath->vp_reg;
-
-       __vxge_hw_pio_mem_write32_upper(
-               (u32)VXGE_HW_INTR_MASK_ALL,
-               &vp_reg->vpath_general_int_mask);
-
-       writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->general_errors_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->pci_config_errors_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->mrpcim_to_vpath_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->srpcim_to_vpath_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->vpath_ppif_int_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->srpcim_msg_to_vpath_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->vpath_pcipif_int_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->wrdma_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->prc_alarm_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->xgmac_vp_int_mask);
-
-       __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL,
-                       &vp_reg->asic_ntwk_vp_err_mask);
-
-exit:
-       return status;
-}
-
-void vxge_hw_vpath_tti_ci_set(struct __vxge_hw_fifo *fifo)
-{
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-       struct vxge_hw_vp_config *config;
-       u64 val64;
-
-       if (fifo->config->enable != VXGE_HW_FIFO_ENABLE)
-               return;
-
-       vp_reg = fifo->vp_reg;
-       config = container_of(fifo->config, struct vxge_hw_vp_config, fifo);
-
-       if (config->tti.timer_ci_en != VXGE_HW_TIM_TIMER_CI_ENABLE) {
-               config->tti.timer_ci_en = VXGE_HW_TIM_TIMER_CI_ENABLE;
-               val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
-               val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
-               fifo->tim_tti_cfg1_saved = val64;
-               writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
-       }
-}
-
-void vxge_hw_vpath_dynamic_rti_ci_set(struct __vxge_hw_ring *ring)
-{
-       u64 val64 = ring->tim_rti_cfg1_saved;
-
-       val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI;
-       ring->tim_rti_cfg1_saved = val64;
-       writeq(val64, &ring->vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]);
-}
-
-void vxge_hw_vpath_dynamic_tti_rtimer_set(struct __vxge_hw_fifo *fifo)
-{
-       u64 val64 = fifo->tim_tti_cfg3_saved;
-       u64 timer = (fifo->rtimer * 1000) / 272;
-
-       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(0x3ffffff);
-       if (timer)
-               val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(timer) |
-                       VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(5);
-
-       writeq(val64, &fifo->vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]);
-       /* tti_cfg3_saved is not updated again because it is
-        * initialized at one place only - init time.
-        */
-}
-
-void vxge_hw_vpath_dynamic_rti_rtimer_set(struct __vxge_hw_ring *ring)
-{
-       u64 val64 = ring->tim_rti_cfg3_saved;
-       u64 timer = (ring->rtimer * 1000) / 272;
-
-       val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(0x3ffffff);
-       if (timer)
-               val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(timer) |
-                       VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(4);
-
-       writeq(val64, &ring->vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]);
-       /* rti_cfg3_saved is not updated again because it is
-        * initialized at one place only - init time.
-        */
-}
-
-/**
- * vxge_hw_channel_msix_mask - Mask MSIX Vector.
- * @channel: Channel for rx or tx handle
- * @msix_id:  MSIX ID
- *
- * The function masks the msix interrupt for the given msix_id
- *
- * Returns: 0
- */
-void vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channel, int msix_id)
-{
-
-       __vxge_hw_pio_mem_write32_upper(
-               (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
-               &channel->common_reg->set_msix_mask_vect[msix_id%4]);
-}
-
-/**
- * vxge_hw_channel_msix_unmask - Unmask the MSIX Vector.
- * @channel: Channel for rx or tx handle
- * @msix_id:  MSI ID
- *
- * The function unmasks the msix interrupt for the given msix_id
- *
- * Returns: 0
- */
-void
-vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channel, int msix_id)
-{
-
-       __vxge_hw_pio_mem_write32_upper(
-               (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
-               &channel->common_reg->clear_msix_mask_vect[msix_id%4]);
-}
-
-/**
- * vxge_hw_channel_msix_clear - Unmask the MSIX Vector.
- * @channel: Channel for rx or tx handle
- * @msix_id:  MSI ID
- *
- * The function unmasks the msix interrupt for the given msix_id
- * if configured in MSIX oneshot mode
- *
- * Returns: 0
- */
-void vxge_hw_channel_msix_clear(struct __vxge_hw_channel *channel, int msix_id)
-{
-       __vxge_hw_pio_mem_write32_upper(
-               (u32) vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
-               &channel->common_reg->clr_msix_one_shot_vec[msix_id % 4]);
-}
-
-/**
- * vxge_hw_device_set_intr_type - Updates the configuration
- *             with new interrupt type.
- * @hldev: HW device handle.
- * @intr_mode: New interrupt type
- */
-u32 vxge_hw_device_set_intr_type(struct __vxge_hw_device *hldev, u32 intr_mode)
-{
-
-       if ((intr_mode != VXGE_HW_INTR_MODE_IRQLINE) &&
-          (intr_mode != VXGE_HW_INTR_MODE_MSIX) &&
-          (intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) &&
-          (intr_mode != VXGE_HW_INTR_MODE_DEF))
-               intr_mode = VXGE_HW_INTR_MODE_IRQLINE;
-
-       hldev->config.intr_mode = intr_mode;
-       return intr_mode;
-}
-
-/**
- * vxge_hw_device_intr_enable - Enable interrupts.
- * @hldev: HW device handle.
- *
- * Enable Titan interrupts. The function is to be executed the last in
- * Titan initialization sequence.
- *
- * See also: vxge_hw_device_intr_disable()
- */
-void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev)
-{
-       u32 i;
-       u64 val64;
-       u32 val32;
-
-       vxge_hw_device_mask_all(hldev);
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
-               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
-                       continue;
-
-               vxge_hw_vpath_intr_enable(
-                       VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i]));
-       }
-
-       if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_IRQLINE) {
-               val64 = hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
-                       hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX];
-
-               if (val64 != 0) {
-                       writeq(val64, &hldev->common_reg->tim_int_status0);
-
-                       writeq(~val64, &hldev->common_reg->tim_int_mask0);
-               }
-
-               val32 = hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
-                       hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX];
-
-               if (val32 != 0) {
-                       __vxge_hw_pio_mem_write32_upper(val32,
-                                       &hldev->common_reg->tim_int_status1);
-
-                       __vxge_hw_pio_mem_write32_upper(~val32,
-                                       &hldev->common_reg->tim_int_mask1);
-               }
-       }
-
-       val64 = readq(&hldev->common_reg->titan_general_int_status);
-
-       vxge_hw_device_unmask_all(hldev);
-}
-
-/**
- * vxge_hw_device_intr_disable - Disable Titan interrupts.
- * @hldev: HW device handle.
- *
- * Disable Titan interrupts.
- *
- * See also: vxge_hw_device_intr_enable()
- */
-void vxge_hw_device_intr_disable(struct __vxge_hw_device *hldev)
-{
-       u32 i;
-
-       vxge_hw_device_mask_all(hldev);
-
-       /* mask all the tim interrupts */
-       writeq(VXGE_HW_INTR_MASK_ALL, &hldev->common_reg->tim_int_mask0);
-       __vxge_hw_pio_mem_write32_upper(VXGE_HW_DEFAULT_32,
-               &hldev->common_reg->tim_int_mask1);
-
-       for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
-               if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
-                       continue;
-
-               vxge_hw_vpath_intr_disable(
-                       VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i]));
-       }
-}
-
-/**
- * vxge_hw_device_mask_all - Mask all device interrupts.
- * @hldev: HW device handle.
- *
- * Mask        all device interrupts.
- *
- * See also: vxge_hw_device_unmask_all()
- */
-void vxge_hw_device_mask_all(struct __vxge_hw_device *hldev)
-{
-       u64 val64;
-
-       val64 = VXGE_HW_TITAN_MASK_ALL_INT_ALARM |
-               VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC;
-
-       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
-                               &hldev->common_reg->titan_mask_all_int);
-}
-
-/**
- * vxge_hw_device_unmask_all - Unmask all device interrupts.
- * @hldev: HW device handle.
- *
- * Unmask all device interrupts.
- *
- * See also: vxge_hw_device_mask_all()
- */
-void vxge_hw_device_unmask_all(struct __vxge_hw_device *hldev)
-{
-       u64 val64 = 0;
-
-       if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_IRQLINE)
-               val64 =  VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC;
-
-       __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
-                       &hldev->common_reg->titan_mask_all_int);
-}
-
-/**
- * vxge_hw_device_flush_io - Flush io writes.
- * @hldev: HW device handle.
- *
- * The function        performs a read operation to flush io writes.
- *
- * Returns: void
- */
-void vxge_hw_device_flush_io(struct __vxge_hw_device *hldev)
-{
-       readl(&hldev->common_reg->titan_general_int_status);
-}
-
-/**
- * __vxge_hw_device_handle_error - Handle error
- * @hldev: HW device
- * @vp_id: Vpath Id
- * @type: Error type. Please see enum vxge_hw_event{}
- *
- * Handle error.
- */
-static enum vxge_hw_status
-__vxge_hw_device_handle_error(struct __vxge_hw_device *hldev, u32 vp_id,
-                             enum vxge_hw_event type)
-{
-       switch (type) {
-       case VXGE_HW_EVENT_UNKNOWN:
-               break;
-       case VXGE_HW_EVENT_RESET_START:
-       case VXGE_HW_EVENT_RESET_COMPLETE:
-       case VXGE_HW_EVENT_LINK_DOWN:
-       case VXGE_HW_EVENT_LINK_UP:
-               goto out;
-       case VXGE_HW_EVENT_ALARM_CLEARED:
-               goto out;
-       case VXGE_HW_EVENT_ECCERR:
-       case VXGE_HW_EVENT_MRPCIM_ECCERR:
-               goto out;
-       case VXGE_HW_EVENT_FIFO_ERR:
-       case VXGE_HW_EVENT_VPATH_ERR:
-       case VXGE_HW_EVENT_CRITICAL_ERR:
-       case VXGE_HW_EVENT_SERR:
-               break;
-       case VXGE_HW_EVENT_SRPCIM_SERR:
-       case VXGE_HW_EVENT_MRPCIM_SERR:
-               goto out;
-       case VXGE_HW_EVENT_SLOT_FREEZE:
-               break;
-       default:
-               vxge_assert(0);
-               goto out;
-       }
-
-       /* notify driver */
-       if (hldev->uld_callbacks->crit_err)
-               hldev->uld_callbacks->crit_err(hldev,
-                       type, vp_id);
-out:
-
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_handle_link_down_ind
- * @hldev: HW device handle.
- *
- * Link down indication handler. The function is invoked by HW when
- * Titan indicates that the link is down.
- */
-static enum vxge_hw_status
-__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev)
-{
-       /*
-        * If the previous link state is not down, return.
-        */
-       if (hldev->link_state == VXGE_HW_LINK_DOWN)
-               goto exit;
-
-       hldev->link_state = VXGE_HW_LINK_DOWN;
-
-       /* notify driver */
-       if (hldev->uld_callbacks->link_down)
-               hldev->uld_callbacks->link_down(hldev);
-exit:
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_device_handle_link_up_ind
- * @hldev: HW device handle.
- *
- * Link up indication handler. The function is invoked by HW when
- * Titan indicates that the link is up for programmable amount of time.
- */
-static enum vxge_hw_status
-__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev)
-{
-       /*
-        * If the previous link state is not down, return.
-        */
-       if (hldev->link_state == VXGE_HW_LINK_UP)
-               goto exit;
-
-       hldev->link_state = VXGE_HW_LINK_UP;
-
-       /* notify driver */
-       if (hldev->uld_callbacks->link_up)
-               hldev->uld_callbacks->link_up(hldev);
-exit:
-       return VXGE_HW_OK;
-}
-
-/*
- * __vxge_hw_vpath_alarm_process - Process Alarms.
- * @vpath: Virtual Path.
- * @skip_alarms: Do not clear the alarms
- *
- * Process vpath alarms.
- *
- */
-static enum vxge_hw_status
-__vxge_hw_vpath_alarm_process(struct __vxge_hw_virtualpath *vpath,
-                             u32 skip_alarms)
-{
-       u64 val64;
-       u64 alarm_status;
-       u64 pic_status;
-       struct __vxge_hw_device *hldev = NULL;
-       enum vxge_hw_event alarm_event = VXGE_HW_EVENT_UNKNOWN;
-       u64 mask64;
-       struct vxge_hw_vpath_stats_sw_info *sw_stats;
-       struct vxge_hw_vpath_reg __iomem *vp_reg;
-
-       if (vpath == NULL) {
-               alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
-                       alarm_event);
-               goto out2;
-       }
-
-       hldev = vpath->hldev;
-       vp_reg = vpath->vp_reg;
-       alarm_status = readq(&vp_reg->vpath_general_int_status);
-
-       if (alarm_status == VXGE_HW_ALL_FOXES) {
-               alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE,
-                       alarm_event);
-               goto out;
-       }
-
-       sw_stats = vpath->sw_stats;
-
-       if (alarm_status & ~(
-               VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT |
-               VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT |
-               VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT |
-               VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) {
-               sw_stats->error_stats.unknown_alarms++;
-
-               alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN,
-                       alarm_event);
-               goto out;
-       }
-
-       if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT) {
-
-               val64 = readq(&vp_reg->xgmac_vp_int_status);
-
-               if (val64 &
-               VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT) {
-
-                       val64 = readq(&vp_reg->asic_ntwk_vp_err_reg);
-
-                       if (((val64 &
-                             VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) &&
-                            (!(val64 &
-                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) ||
-                           ((val64 &
-                            VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) &&
-                            (!(val64 &
-                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR)
-                                    ))) {
-                               sw_stats->error_stats.network_sustained_fault++;
-
-                               writeq(
-                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT,
-                                       &vp_reg->asic_ntwk_vp_err_mask);
-
-                               __vxge_hw_device_handle_link_down_ind(hldev);
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_LINK_DOWN, alarm_event);
-                       }
-
-                       if (((val64 &
-                             VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) &&
-                            (!(val64 &
-                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) ||
-                           ((val64 &
-                             VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) &&
-                            (!(val64 &
-                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR)
-                                    ))) {
-
-                               sw_stats->error_stats.network_sustained_ok++;
-
-                               writeq(
-                               VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK,
-                                       &vp_reg->asic_ntwk_vp_err_mask);
-
-                               __vxge_hw_device_handle_link_up_ind(hldev);
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_LINK_UP, alarm_event);
-                       }
-
-                       writeq(VXGE_HW_INTR_MASK_ALL,
-                               &vp_reg->asic_ntwk_vp_err_reg);
-
-                       alarm_event = VXGE_HW_SET_LEVEL(
-                               VXGE_HW_EVENT_ALARM_CLEARED, alarm_event);
-
-                       if (skip_alarms)
-                               return VXGE_HW_OK;
-               }
-       }
-
-       if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT) {
-
-               pic_status = readq(&vp_reg->vpath_ppif_int_status);
-
-               if (pic_status &
-                   VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT) {
-
-                       val64 = readq(&vp_reg->general_errors_reg);
-                       mask64 = readq(&vp_reg->general_errors_mask);
-
-                       if ((val64 &
-                               VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET) &
-                               ~mask64) {
-                               sw_stats->error_stats.ini_serr_det++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_SERR, alarm_event);
-                       }
-
-                       if ((val64 &
-                           VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW) &
-                               ~mask64) {
-                               sw_stats->error_stats.dblgen_fifo0_overflow++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_FIFO_ERR, alarm_event);
-                       }
-
-                       if ((val64 &
-                           VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR) &
-                               ~mask64)
-                               sw_stats->error_stats.statsb_pif_chain_error++;
-
-                       if ((val64 &
-                          VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ) &
-                               ~mask64)
-                               sw_stats->error_stats.statsb_drop_timeout++;
-
-                       if ((val64 &
-                               VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS) &
-                               ~mask64)
-                               sw_stats->error_stats.target_illegal_access++;
-
-                       if (!skip_alarms) {
-                               writeq(VXGE_HW_INTR_MASK_ALL,
-                                       &vp_reg->general_errors_reg);
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_ALARM_CLEARED,
-                                       alarm_event);
-                       }
-               }
-
-               if (pic_status &
-                   VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT) {
-
-                       val64 = readq(&vp_reg->kdfcctl_errors_reg);
-                       mask64 = readq(&vp_reg->kdfcctl_errors_mask);
-
-                       if ((val64 &
-                           VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR) &
-                               ~mask64) {
-                               sw_stats->error_stats.kdfcctl_fifo0_overwrite++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_FIFO_ERR,
-                                       alarm_event);
-                       }
-
-                       if ((val64 &
-                           VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON) &
-                               ~mask64) {
-                               sw_stats->error_stats.kdfcctl_fifo0_poison++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_FIFO_ERR,
-                                       alarm_event);
-                       }
-
-                       if ((val64 &
-                           VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR) &
-                               ~mask64) {
-                               sw_stats->error_stats.kdfcctl_fifo0_dma_error++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_FIFO_ERR,
-                                       alarm_event);
-                       }
-
-                       if (!skip_alarms) {
-                               writeq(VXGE_HW_INTR_MASK_ALL,
-                                       &vp_reg->kdfcctl_errors_reg);
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_ALARM_CLEARED,
-                                       alarm_event);
-                       }
-               }
-
-       }
-
-       if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT) {
-
-               val64 = readq(&vp_reg->wrdma_alarm_status);
-
-               if (val64 & VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT) {
-
-                       val64 = readq(&vp_reg->prc_alarm_reg);
-                       mask64 = readq(&vp_reg->prc_alarm_mask);
-
-                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP)&
-                               ~mask64)
-                               sw_stats->error_stats.prc_ring_bumps++;
-
-                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR) &
-                               ~mask64) {
-                               sw_stats->error_stats.prc_rxdcm_sc_err++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_VPATH_ERR,
-                                       alarm_event);
-                       }
-
-                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT)
-                               & ~mask64) {
-                               sw_stats->error_stats.prc_rxdcm_sc_abort++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                               VXGE_HW_EVENT_VPATH_ERR,
-                                               alarm_event);
-                       }
-
-                       if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR)
-                                & ~mask64) {
-                               sw_stats->error_stats.prc_quanta_size_err++;
-
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                       VXGE_HW_EVENT_VPATH_ERR,
-                                       alarm_event);
-                       }
-
-                       if (!skip_alarms) {
-                               writeq(VXGE_HW_INTR_MASK_ALL,
-                                       &vp_reg->prc_alarm_reg);
-                               alarm_event = VXGE_HW_SET_LEVEL(
-                                               VXGE_HW_EVENT_ALARM_CLEARED,
-                                               alarm_event);
-                       }
-               }
-       }
-out:
-       hldev->stats.sw_dev_err_stats.vpath_alarms++;
-out2:
-       if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) ||
-               (alarm_event == VXGE_HW_EVENT_UNKNOWN))
-               return VXGE_HW_OK;
-
-       __vxge_hw_device_handle_error(hldev, vpath->vp_id, alarm_event);
-
-       if (alarm_event == VXGE_HW_EVENT_SERR)
-               return VXGE_HW_ERR_CRITICAL;
-
-       return (alarm_event == VXGE_HW_EVENT_SLOT_FREEZE) ?
-               VXGE_HW_ERR_SLOT_FREEZE :
-               (alarm_event == VXGE_HW_EVENT_FIFO_ERR) ? VXGE_HW_ERR_FIFO :
-               VXGE_HW_ERR_VPATH;
-}
-
-/**
- * vxge_hw_device_begin_irq - Begin IRQ processing.
- * @hldev: HW device handle.
- * @skip_alarms: Do not clear the alarms
- * @reason: "Reason" for the interrupt, the value of Titan's
- *     general_int_status register.
- *
- * The function        performs two actions, It first checks whether (shared IRQ) the
- * interrupt was raised        by the device. Next, it masks the device interrupts.
- *
- * Note:
- * vxge_hw_device_begin_irq() does not flush MMIO writes through the
- * bridge. Therefore, two back-to-back interrupts are potentially possible.
- *
- * Returns: 0, if the interrupt        is not "ours" (note that in this case the
- * device remain enabled).
- * Otherwise, vxge_hw_device_begin_irq() returns 64bit general adapter
- * status.
- */
-enum vxge_hw_status vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev,
-                                            u32 skip_alarms, u64 *reason)
-{
-       u32 i;
-       u64 val64;
-       u64 adapter_status;
-       u64 vpath_mask;
-       enum vxge_hw_status ret = VXGE_HW_OK;
-
-       val64 = readq(&hldev->common_reg->titan_general_int_status);
-
-       if (unlikely(!val64)) {
-               /* not Titan interrupt  */
-               *reason = 0;
-               ret = VXGE_HW_ERR_WRONG_IRQ;
-               goto exit;
-       }
-
-       if (unlikely(val64 == VXGE_HW_ALL_FOXES)) {
-
-               adapter_status = readq(&hldev->common_reg->adapter_status);
-
-               if (adapter_status == VXGE_HW_ALL_FOXES) {
-
-                       __vxge_hw_device_handle_error(hldev,
-                               NULL_VPID, VXGE_HW_EVENT_SLOT_FREEZE);
-                       *reason = 0;
-                       ret = VXGE_HW_ERR_SLOT_FREEZE;
-                       goto exit;
-               }
-       }
-
-       hldev->stats.sw_dev_info_stats.total_intr_cnt++;
-
-       *reason = val64;
-
-       vpath_mask = hldev->vpaths_deployed >>
-                               (64 - VXGE_HW_MAX_VIRTUAL_PATHS);
-
-       if (val64 &
-           VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(vpath_mask)) {
-               hldev->stats.sw_dev_info_stats.traffic_intr_cnt++;
-
-               return VXGE_HW_OK;
-       }
-
-       hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++;
-
-       if (unlikely(val64 &
-                       VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT)) {
-
-               enum vxge_hw_status error_level = VXGE_HW_OK;
-
-               hldev->stats.sw_dev_err_stats.vpath_alarms++;
-
-               for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
-
-                       if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
-                               continue;
-
-                       ret = __vxge_hw_vpath_alarm_process(
-                               &hldev->virtual_paths[i], skip_alarms);
-
-                       error_level = VXGE_HW_SET_LEVEL(ret, error_level);
-
-                       if (unlikely((ret == VXGE_HW_ERR_CRITICAL) ||
-                               (ret == VXGE_HW_ERR_SLOT_FREEZE)))
-                               break;
-               }
-
-               ret = error_level;
-       }
-exit:
-       return ret;
-}
-
-/**
- * vxge_hw_device_clear_tx_rx - Acknowledge (that is, clear) the
- * condition that has caused the Tx and RX interrupt.
- * @hldev: HW device.
- *
- * Acknowledge (that is, clear) the condition that has caused
- * the Tx and Rx interrupt.
- * See also: vxge_hw_device_begin_irq(),
- * vxge_hw_device_mask_tx_rx(), vxge_hw_device_unmask_tx_rx().
- */
-void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev)
-{
-
-       if ((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
-          (hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
-               writeq((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
-                                hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX]),
-                               &hldev->common_reg->tim_int_status0);
-       }
-
-       if ((hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
-          (hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
-               __vxge_hw_pio_mem_write32_upper(
-                               (hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
-                                hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX]),
-                               &hldev->common_reg->tim_int_status1);
-       }
-}
-
-/*
- * vxge_hw_channel_dtr_alloc - Allocate a dtr from the channel
- * @channel: Channel
- * @dtrh: Buffer to return the DTR pointer
- *
- * Allocates a dtr from the reserve array. If the reserve array is empty,
- * it swaps the reserve and free arrays.
- *
- */
-static enum vxge_hw_status
-vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh)
-{
-       if (channel->reserve_ptr - channel->reserve_top > 0) {
-_alloc_after_swap:
-               *dtrh = channel->reserve_arr[--channel->reserve_ptr];
-
-               return VXGE_HW_OK;
-       }
-
-       /* switch between empty and full arrays */
-
-       /* the idea behind such a design is that by having free and reserved
-        * arrays separated we basically separated irq and non-irq parts.
-        * i.e. no additional lock need to be done when we free a resource */
-
-       if (channel->length - channel->free_ptr > 0) {
-               swap(channel->reserve_arr, channel->free_arr);
-               channel->reserve_ptr = channel->length;
-               channel->reserve_top = channel->free_ptr;
-               channel->free_ptr = channel->length;
-
-               channel->stats->reserve_free_swaps_cnt++;
-
-               goto _alloc_after_swap;
-       }
-
-       channel->stats->full_cnt++;
-
-       *dtrh = NULL;
-       return VXGE_HW_INF_OUT_OF_DESCRIPTORS;
-}
-
-/*
- * vxge_hw_channel_dtr_post - Post a dtr to the channel
- * @channelh: Channel
- * @dtrh: DTR pointer
- *
- * Posts a dtr to work array.
- *
- */
-static void
-vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh)
-{
-       vxge_assert(channel->work_arr[channel->post_index] == NULL);
-
-       channel->work_arr[channel->post_index++] = dtrh;
-
-       /* wrap-around */
-       if (channel->post_index == channel->length)
-               channel->post_index = 0;
-}
-
-/*
- * vxge_hw_channel_dtr_try_complete - Returns next completed dtr
- * @channel: Channel
- * @dtr: Buffer to return the next completed DTR pointer
- *
- * Returns the next completed dtr with out removing it from work array
- *
- */
-void
-vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, void **dtrh)
-{
-       vxge_assert(channel->compl_index < channel->length);
-
-       *dtrh = channel->work_arr[channel->compl_index];
-       prefetch(*dtrh);
-}
-
-/*
- * vxge_hw_channel_dtr_complete - Removes next completed dtr from the work array
- * @channel: Channel handle
- *
- * Removes the next completed dtr from work array
- *
- */
-void vxge_hw_channel_dtr_complete(struct __vxge_hw_channel *channel)
-{
-       channel->work_arr[channel->compl_index] = NULL;
-
-       /* wrap-around */
-       if (++channel->compl_index == channel->length)
-               channel->compl_index = 0;
-
-       channel->stats->total_compl_cnt++;
-}
-
-/*
- * vxge_hw_channel_dtr_free - Frees a dtr
- * @channel: Channel handle
- * @dtr:  DTR pointer
- *
- * Returns the dtr to free array
- *
- */
-void vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh)
-{
-       channel->free_arr[--channel->free_ptr] = dtrh;
-}
-
-/*
- * vxge_hw_channel_dtr_count
- * @channel: Channel handle. Obtained via vxge_hw_channel_open().
- *
- * Retrieve number of DTRs available. This function can not be called
- * from data path. ring_initial_replenishi() is the only user.
- */
-int vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel)
-{
-       return (channel->reserve_ptr - channel->reserve_top) +
-               (channel->length - channel->free_ptr);
-}
-
-/**
- * vxge_hw_ring_rxd_reserve    - Reserve ring descriptor.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Reserved descriptor. On success HW fills this "out" parameter
- * with a valid handle.
- *
- * Reserve Rx descriptor for the subsequent filling-in driver
- * and posting on the corresponding channel (@channelh)
- * via vxge_hw_ring_rxd_post().
- *
- * Returns: VXGE_HW_OK - success.
- * VXGE_HW_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available.
- *
- */
-enum vxge_hw_status vxge_hw_ring_rxd_reserve(struct __vxge_hw_ring *ring,
-       void **rxdh)
-{
-       enum vxge_hw_status status;
-       struct __vxge_hw_channel *channel;
-
-       channel = &ring->channel;
-
-       status = vxge_hw_channel_dtr_alloc(channel, rxdh);
-
-       if (status == VXGE_HW_OK) {
-               struct vxge_hw_ring_rxd_1 *rxdp =
-                       (struct vxge_hw_ring_rxd_1 *)*rxdh;
-
-               rxdp->control_0 = rxdp->control_1 = 0;
-       }
-
-       return status;
-}
-
-/**
- * vxge_hw_ring_rxd_free - Free descriptor.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor handle.
- *
- * Free        the reserved descriptor. This operation is "symmetrical" to
- * vxge_hw_ring_rxd_reserve. The "free-ing" completes the descriptor's
- * lifecycle.
- *
- * After free-ing (see vxge_hw_ring_rxd_free()) the descriptor again can
- * be:
- *
- * - reserved (vxge_hw_ring_rxd_reserve);
- *
- * - posted    (vxge_hw_ring_rxd_post);
- *
- * - completed (vxge_hw_ring_rxd_next_completed);
- *
- * - and recycled again        (vxge_hw_ring_rxd_free).
- *
- * For alternative state transitions and more details please refer to
- * the design doc.
- *
- */
-void vxge_hw_ring_rxd_free(struct __vxge_hw_ring *ring, void *rxdh)
-{
-       struct __vxge_hw_channel *channel;
-
-       channel = &ring->channel;
-
-       vxge_hw_channel_dtr_free(channel, rxdh);
-
-}
-
-/**
- * vxge_hw_ring_rxd_pre_post - Prepare rxd and post
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor handle.
- *
- * This routine prepares a rxd and posts
- */
-void vxge_hw_ring_rxd_pre_post(struct __vxge_hw_ring *ring, void *rxdh)
-{
-       struct __vxge_hw_channel *channel;
-
-       channel = &ring->channel;
-
-       vxge_hw_channel_dtr_post(channel, rxdh);
-}
-
-/**
- * vxge_hw_ring_rxd_post_post - Process rxd after post.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor handle.
- *
- * Processes rxd after post
- */
-void vxge_hw_ring_rxd_post_post(struct __vxge_hw_ring *ring, void *rxdh)
-{
-       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
-
-       rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
-
-       if (ring->stats->common_stats.usage_cnt > 0)
-               ring->stats->common_stats.usage_cnt--;
-}
-
-/**
- * vxge_hw_ring_rxd_post - Post descriptor on the ring.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor obtained via vxge_hw_ring_rxd_reserve().
- *
- * Post        descriptor on the ring.
- * Prior to posting the        descriptor should be filled in accordance with
- * Host/Titan interface specification for a given service (LL, etc.).
- *
- */
-void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring, void *rxdh)
-{
-       struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh;
-       struct __vxge_hw_channel *channel;
-
-       channel = &ring->channel;
-
-       wmb();
-       rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
-
-       vxge_hw_channel_dtr_post(channel, rxdh);
-
-       if (ring->stats->common_stats.usage_cnt > 0)
-               ring->stats->common_stats.usage_cnt--;
-}
-
-/**
- * vxge_hw_ring_rxd_post_post_wmb - Process rxd after post with memory barrier.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor handle.
- *
- * Processes rxd after post with memory barrier.
- */
-void vxge_hw_ring_rxd_post_post_wmb(struct __vxge_hw_ring *ring, void *rxdh)
-{
-       wmb();
-       vxge_hw_ring_rxd_post_post(ring, rxdh);
-}
-
-/**
- * vxge_hw_ring_rxd_next_completed - Get the _next_ completed descriptor.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor handle. Returned by HW.
- * @t_code:    Transfer code, as per Titan User Guide,
- *      Receive Descriptor Format. Returned by HW.
- *
- * Retrieve the        _next_ completed descriptor.
- * HW uses ring callback (*vxge_hw_ring_callback_f) to notifiy
- * driver of new completed descriptors. After that
- * the driver can use vxge_hw_ring_rxd_next_completed to retrieve the rest
- * completions (the very first completion is passed by HW via
- * vxge_hw_ring_callback_f).
- *
- * Implementation-wise, the driver is free to call
- * vxge_hw_ring_rxd_next_completed either immediately from inside the
- * ring callback, or in a deferred fashion and separate (from HW)
- * context.
- *
- * Non-zero @t_code means failure to fill-in receive buffer(s)
- * of the descriptor.
- * For instance, parity        error detected during the data transfer.
- * In this case        Titan will complete the descriptor and indicate
- * for the host        that the received data is not to be used.
- * For details please refer to Titan User Guide.
- *
- * Returns: VXGE_HW_OK - success.
- * VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors
- * are currently available for processing.
- *
- * See also: vxge_hw_ring_callback_f{},
- * vxge_hw_fifo_rxd_next_completed(), enum vxge_hw_status{}.
- */
-enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
-       struct __vxge_hw_ring *ring, void **rxdh, u8 *t_code)
-{
-       struct __vxge_hw_channel *channel;
-       struct vxge_hw_ring_rxd_1 *rxdp;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       u64 control_0, own;
-
-       channel = &ring->channel;
-
-       vxge_hw_channel_dtr_try_complete(channel, rxdh);
-
-       rxdp = *rxdh;
-       if (rxdp == NULL) {
-               status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
-               goto exit;
-       }
-
-       control_0 = rxdp->control_0;
-       own = control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
-       *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(control_0);
-
-       /* check whether it is not the end */
-       if (!own || *t_code == VXGE_HW_RING_T_CODE_FRM_DROP) {
-
-               vxge_assert((rxdp)->host_control !=
-                               0);
-
-               ++ring->cmpl_cnt;
-               vxge_hw_channel_dtr_complete(channel);
-
-               vxge_assert(*t_code != VXGE_HW_RING_RXD_T_CODE_UNUSED);
-
-               ring->stats->common_stats.usage_cnt++;
-               if (ring->stats->common_stats.usage_max <
-                               ring->stats->common_stats.usage_cnt)
-                       ring->stats->common_stats.usage_max =
-                               ring->stats->common_stats.usage_cnt;
-
-               status = VXGE_HW_OK;
-               goto exit;
-       }
-
-       /* reset it. since we don't want to return
-        * garbage to the driver */
-       *rxdh = NULL;
-       status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_ring_handle_tcode - Handle transfer code.
- * @ring: Handle to the ring object used for receive
- * @rxdh: Descriptor handle.
- * @t_code: One of the enumerated (and documented in the Titan user guide)
- * "transfer codes".
- *
- * Handle descriptor's transfer code. The latter comes with each completed
- * descriptor.
- *
- * Returns: one of the enum vxge_hw_status{} enumerated types.
- * VXGE_HW_OK                  - for success.
- * VXGE_HW_ERR_CRITICAL         - when encounters critical error.
- */
-enum vxge_hw_status vxge_hw_ring_handle_tcode(
-       struct __vxge_hw_ring *ring, void *rxdh, u8 t_code)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       /* If the t_code is not supported and if the
-        * t_code is other than 0x5 (unparseable packet
-        * such as unknown UPV6 header), Drop it !!!
-        */
-
-       if (t_code ==  VXGE_HW_RING_T_CODE_OK ||
-               t_code == VXGE_HW_RING_T_CODE_L3_PKT_ERR) {
-               status = VXGE_HW_OK;
-               goto exit;
-       }
-
-       if (t_code > VXGE_HW_RING_T_CODE_MULTI_ERR) {
-               status = VXGE_HW_ERR_INVALID_TCODE;
-               goto exit;
-       }
-
-       ring->stats->rxd_t_code_err_cnt[t_code]++;
-exit:
-       return status;
-}
-
-/**
- * __vxge_hw_non_offload_db_post - Post non offload doorbell
- *
- * @fifo: fifohandle
- * @txdl_ptr: The starting location of the TxDL in host memory
- * @num_txds: The highest TxD in this TxDL (0 to 255 means 1 to 256)
- * @no_snoop: No snoop flags
- *
- * This function posts a non-offload doorbell to doorbell FIFO
- *
- */
-static void __vxge_hw_non_offload_db_post(struct __vxge_hw_fifo *fifo,
-       u64 txdl_ptr, u32 num_txds, u32 no_snoop)
-{
-       writeq(VXGE_HW_NODBW_TYPE(VXGE_HW_NODBW_TYPE_NODBW) |
-               VXGE_HW_NODBW_LAST_TXD_NUMBER(num_txds) |
-               VXGE_HW_NODBW_GET_NO_SNOOP(no_snoop),
-               &fifo->nofl_db->control_0);
-
-       writeq(txdl_ptr, &fifo->nofl_db->txdl_ptr);
-}
-
-/**
- * vxge_hw_fifo_free_txdl_count_get - returns the number of txdls available in
- * the fifo
- * @fifoh: Handle to the fifo object used for non offload send
- */
-u32 vxge_hw_fifo_free_txdl_count_get(struct __vxge_hw_fifo *fifoh)
-{
-       return vxge_hw_channel_dtr_count(&fifoh->channel);
-}
-
-/**
- * vxge_hw_fifo_txdl_reserve - Reserve fifo descriptor.
- * @fifo: Handle to the fifo object used for non offload send
- * @txdlh: Reserved descriptor. On success HW fills this "out" parameter
- *        with a valid handle.
- * @txdl_priv: Buffer to return the pointer to per txdl space
- *
- * Reserve a single TxDL (that is, fifo descriptor)
- * for the subsequent filling-in by driver)
- * and posting on the corresponding channel (@channelh)
- * via vxge_hw_fifo_txdl_post().
- *
- * Note: it is the responsibility of driver to reserve multiple descriptors
- * for lengthy (e.g., LSO) transmit operation. A single fifo descriptor
- * carries up to configured number (fifo.max_frags) of contiguous buffers.
- *
- * Returns: VXGE_HW_OK - success;
- * VXGE_HW_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available
- *
- */
-enum vxge_hw_status vxge_hw_fifo_txdl_reserve(
-       struct __vxge_hw_fifo *fifo,
-       void **txdlh, void **txdl_priv)
-{
-       struct __vxge_hw_channel *channel;
-       enum vxge_hw_status status;
-       int i;
-
-       channel = &fifo->channel;
-
-       status = vxge_hw_channel_dtr_alloc(channel, txdlh);
-
-       if (status == VXGE_HW_OK) {
-               struct vxge_hw_fifo_txd *txdp =
-                       (struct vxge_hw_fifo_txd *)*txdlh;
-               struct __vxge_hw_fifo_txdl_priv *priv;
-
-               priv = __vxge_hw_fifo_txdl_priv(fifo, txdp);
-
-               /* reset the TxDL's private */
-               priv->align_dma_offset = 0;
-               priv->align_vaddr_start = priv->align_vaddr;
-               priv->align_used_frags = 0;
-               priv->frags = 0;
-               priv->alloc_frags = fifo->config->max_frags;
-               priv->next_txdl_priv = NULL;
-
-               *txdl_priv = (void *)(size_t)txdp->host_control;
-
-               for (i = 0; i < fifo->config->max_frags; i++) {
-                       txdp = ((struct vxge_hw_fifo_txd *)*txdlh) + i;
-                       txdp->control_0 = txdp->control_1 = 0;
-               }
-       }
-
-       return status;
-}
-
-/**
- * vxge_hw_fifo_txdl_buffer_set - Set transmit buffer pointer in the
- * descriptor.
- * @fifo: Handle to the fifo object used for non offload send
- * @txdlh: Descriptor handle.
- * @frag_idx: Index of the data buffer in the caller's scatter-gather list
- *            (of buffers).
- * @dma_pointer: DMA address of the data buffer referenced by @frag_idx.
- * @size: Size of the data buffer (in bytes).
- *
- * This API is part of the preparation of the transmit descriptor for posting
- * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include
- * vxge_hw_fifo_txdl_mss_set() and vxge_hw_fifo_txdl_cksum_set_bits().
- * All three APIs fill in the fields of the fifo descriptor,
- * in accordance with the Titan specification.
- *
- */
-void vxge_hw_fifo_txdl_buffer_set(struct __vxge_hw_fifo *fifo,
-                                 void *txdlh, u32 frag_idx,
-                                 dma_addr_t dma_pointer, u32 size)
-{
-       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
-       struct vxge_hw_fifo_txd *txdp, *txdp_last;
-
-       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdlh);
-       txdp = (struct vxge_hw_fifo_txd *)txdlh  +  txdl_priv->frags;
-
-       if (frag_idx != 0)
-               txdp->control_0 = txdp->control_1 = 0;
-       else {
-               txdp->control_0 |= VXGE_HW_FIFO_TXD_GATHER_CODE(
-                       VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST);
-               txdp->control_1 |= fifo->interrupt_type;
-               txdp->control_1 |= VXGE_HW_FIFO_TXD_INT_NUMBER(
-                       fifo->tx_intr_num);
-               if (txdl_priv->frags) {
-                       txdp_last = (struct vxge_hw_fifo_txd *)txdlh  +
-                       (txdl_priv->frags - 1);
-                       txdp_last->control_0 |= VXGE_HW_FIFO_TXD_GATHER_CODE(
-                               VXGE_HW_FIFO_TXD_GATHER_CODE_LAST);
-               }
-       }
-
-       vxge_assert(frag_idx < txdl_priv->alloc_frags);
-
-       txdp->buffer_pointer = (u64)dma_pointer;
-       txdp->control_0 |= VXGE_HW_FIFO_TXD_BUFFER_SIZE(size);
-       fifo->stats->total_buffers++;
-       txdl_priv->frags++;
-}
-
-/**
- * vxge_hw_fifo_txdl_post - Post descriptor on the fifo channel.
- * @fifo: Handle to the fifo object used for non offload send
- * @txdlh: Descriptor obtained via vxge_hw_fifo_txdl_reserve()
- *
- * Post descriptor on the 'fifo' type channel for transmission.
- * Prior to posting the descriptor should be filled in accordance with
- * Host/Titan interface specification for a given service (LL, etc.).
- *
- */
-void vxge_hw_fifo_txdl_post(struct __vxge_hw_fifo *fifo, void *txdlh)
-{
-       struct __vxge_hw_fifo_txdl_priv *txdl_priv;
-       struct vxge_hw_fifo_txd *txdp_last;
-       struct vxge_hw_fifo_txd *txdp_first;
-
-       txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdlh);
-       txdp_first = txdlh;
-
-       txdp_last = (struct vxge_hw_fifo_txd *)txdlh  +  (txdl_priv->frags - 1);
-       txdp_last->control_0 |=
-             VXGE_HW_FIFO_TXD_GATHER_CODE(VXGE_HW_FIFO_TXD_GATHER_CODE_LAST);
-       txdp_first->control_0 |= VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER;
-
-       vxge_hw_channel_dtr_post(&fifo->channel, txdlh);
-
-       __vxge_hw_non_offload_db_post(fifo,
-               (u64)txdl_priv->dma_addr,
-               txdl_priv->frags - 1,
-               fifo->no_snoop_bits);
-
-       fifo->stats->total_posts++;
-       fifo->stats->common_stats.usage_cnt++;
-       if (fifo->stats->common_stats.usage_max <
-               fifo->stats->common_stats.usage_cnt)
-               fifo->stats->common_stats.usage_max =
-                       fifo->stats->common_stats.usage_cnt;
-}
-
-/**
- * vxge_hw_fifo_txdl_next_completed - Retrieve next completed descriptor.
- * @fifo: Handle to the fifo object used for non offload send
- * @txdlh: Descriptor handle. Returned by HW.
- * @t_code: Transfer code, as per Titan User Guide,
- *          Transmit Descriptor Format.
- *          Returned by HW.
- *
- * Retrieve the _next_ completed descriptor.
- * HW uses channel callback (*vxge_hw_channel_callback_f) to notifiy
- * driver of new completed descriptors. After that
- * the driver can use vxge_hw_fifo_txdl_next_completed to retrieve the rest
- * completions (the very first completion is passed by HW via
- * vxge_hw_channel_callback_f).
- *
- * Implementation-wise, the driver is free to call
- * vxge_hw_fifo_txdl_next_completed either immediately from inside the
- * channel callback, or in a deferred fashion and separate (from HW)
- * context.
- *
- * Non-zero @t_code means failure to process the descriptor.
- * The failure could happen, for instance, when the link is
- * down, in which case Titan completes the descriptor because it
- * is not able to send the data out.
- *
- * For details please refer to Titan User Guide.
- *
- * Returns: VXGE_HW_OK - success.
- * VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors
- * are currently available for processing.
- *
- */
-enum vxge_hw_status vxge_hw_fifo_txdl_next_completed(
-       struct __vxge_hw_fifo *fifo, void **txdlh,
-       enum vxge_hw_fifo_tcode *t_code)
-{
-       struct __vxge_hw_channel *channel;
-       struct vxge_hw_fifo_txd *txdp;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       channel = &fifo->channel;
-
-       vxge_hw_channel_dtr_try_complete(channel, txdlh);
-
-       txdp = *txdlh;
-       if (txdp == NULL) {
-               status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
-               goto exit;
-       }
-
-       /* check whether host owns it */
-       if (!(txdp->control_0 & VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER)) {
-
-               vxge_assert(txdp->host_control != 0);
-
-               vxge_hw_channel_dtr_complete(channel);
-
-               *t_code = (u8)VXGE_HW_FIFO_TXD_T_CODE_GET(txdp->control_0);
-
-               if (fifo->stats->common_stats.usage_cnt > 0)
-                       fifo->stats->common_stats.usage_cnt--;
-
-               status = VXGE_HW_OK;
-               goto exit;
-       }
-
-       /* no more completions */
-       *txdlh = NULL;
-       status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS;
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_fifo_handle_tcode - Handle transfer code.
- * @fifo: Handle to the fifo object used for non offload send
- * @txdlh: Descriptor handle.
- * @t_code: One of the enumerated (and documented in the Titan user guide)
- *          "transfer codes".
- *
- * Handle descriptor's transfer code. The latter comes with each completed
- * descriptor.
- *
- * Returns: one of the enum vxge_hw_status{} enumerated types.
- * VXGE_HW_OK - for success.
- * VXGE_HW_ERR_CRITICAL - when encounters critical error.
- */
-enum vxge_hw_status vxge_hw_fifo_handle_tcode(struct __vxge_hw_fifo *fifo,
-                                             void *txdlh,
-                                             enum vxge_hw_fifo_tcode t_code)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (((t_code & 0x7) < 0) || ((t_code & 0x7) > 0x4)) {
-               status = VXGE_HW_ERR_INVALID_TCODE;
-               goto exit;
-       }
-
-       fifo->stats->txd_t_code_err_cnt[t_code]++;
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_fifo_txdl_free - Free descriptor.
- * @fifo: Handle to the fifo object used for non offload send
- * @txdlh: Descriptor handle.
- *
- * Free the reserved descriptor. This operation is "symmetrical" to
- * vxge_hw_fifo_txdl_reserve. The "free-ing" completes the descriptor's
- * lifecycle.
- *
- * After free-ing (see vxge_hw_fifo_txdl_free()) the descriptor again can
- * be:
- *
- * - reserved (vxge_hw_fifo_txdl_reserve);
- *
- * - posted (vxge_hw_fifo_txdl_post);
- *
- * - completed (vxge_hw_fifo_txdl_next_completed);
- *
- * - and recycled again (vxge_hw_fifo_txdl_free).
- *
- * For alternative state transitions and more details please refer to
- * the design doc.
- *
- */
-void vxge_hw_fifo_txdl_free(struct __vxge_hw_fifo *fifo, void *txdlh)
-{
-       struct __vxge_hw_channel *channel;
-
-       channel = &fifo->channel;
-
-       vxge_hw_channel_dtr_free(channel, txdlh);
-}
-
-/**
- * vxge_hw_vpath_mac_addr_add - Add the mac address entry for this vpath to MAC address table.
- * @vp: Vpath handle.
- * @macaddr: MAC address to be added for this vpath into the list
- * @macaddr_mask: MAC address mask for macaddr
- * @duplicate_mode: Duplicate MAC address add mode. Please see
- *             enum vxge_hw_vpath_mac_addr_add_mode{}
- *
- * Adds the given mac address and mac address mask into the list for this
- * vpath.
- * see also: vxge_hw_vpath_mac_addr_delete, vxge_hw_vpath_mac_addr_get and
- * vxge_hw_vpath_mac_addr_get_next
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_add(
-       struct __vxge_hw_vpath_handle *vp,
-       u8 *macaddr,
-       u8 *macaddr_mask,
-       enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode)
-{
-       u32 i;
-       u64 data1 = 0ULL;
-       u64 data2 = 0ULL;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       for (i = 0; i < ETH_ALEN; i++) {
-               data1 <<= 8;
-               data1 |= (u8)macaddr[i];
-
-               data2 <<= 8;
-               data2 |= (u8)macaddr_mask[i];
-       }
-
-       switch (duplicate_mode) {
-       case VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE:
-               i = 0;
-               break;
-       case VXGE_HW_VPATH_MAC_ADDR_DISCARD_DUPLICATE:
-               i = 1;
-               break;
-       case VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE:
-               i = 2;
-               break;
-       default:
-               i = 0;
-               break;
-       }
-
-       status = __vxge_hw_vpath_rts_table_set(vp,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
-                       0,
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(data1),
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(data2)|
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(i));
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_mac_addr_get - Get the first mac address entry
- * @vp: Vpath handle.
- * @macaddr: First MAC address entry for this vpath in the list
- * @macaddr_mask: MAC address mask for macaddr
- *
- * Get the first mac address entry for this vpath from MAC address table.
- * Return: the first mac address and mac address mask in the list for this
- * vpath.
- * see also: vxge_hw_vpath_mac_addr_get_next
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_get(
-       struct __vxge_hw_vpath_handle *vp,
-       u8 *macaddr,
-       u8 *macaddr_mask)
-{
-       u32 i;
-       u64 data1 = 0ULL;
-       u64 data2 = 0ULL;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_rts_table_get(vp,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
-                       0, &data1, &data2);
-
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
-
-       data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(data2);
-
-       for (i = ETH_ALEN; i > 0; i--) {
-               macaddr[i-1] = (u8)(data1 & 0xFF);
-               data1 >>= 8;
-
-               macaddr_mask[i-1] = (u8)(data2 & 0xFF);
-               data2 >>= 8;
-       }
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_mac_addr_get_next - Get the next mac address entry
- * @vp: Vpath handle.
- * @macaddr: Next MAC address entry for this vpath in the list
- * @macaddr_mask: MAC address mask for macaddr
- *
- * Get the next mac address entry for this vpath from MAC address table.
- * Return: the next mac address and mac address mask in the list for this
- * vpath.
- * see also: vxge_hw_vpath_mac_addr_get
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_get_next(
-       struct __vxge_hw_vpath_handle *vp,
-       u8 *macaddr,
-       u8 *macaddr_mask)
-{
-       u32 i;
-       u64 data1 = 0ULL;
-       u64 data2 = 0ULL;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_rts_table_get(vp,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
-                       0, &data1, &data2);
-
-       if (status != VXGE_HW_OK)
-               goto exit;
-
-       data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1);
-
-       data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(data2);
-
-       for (i = ETH_ALEN; i > 0; i--) {
-               macaddr[i-1] = (u8)(data1 & 0xFF);
-               data1 >>= 8;
-
-               macaddr_mask[i-1] = (u8)(data2 & 0xFF);
-               data2 >>= 8;
-       }
-
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_mac_addr_delete - Delete the mac address entry for this vpath to MAC address table.
- * @vp: Vpath handle.
- * @macaddr: MAC address to be added for this vpath into the list
- * @macaddr_mask: MAC address mask for macaddr
- *
- * Delete the given mac address and mac address mask into the list for this
- * vpath.
- * see also: vxge_hw_vpath_mac_addr_add, vxge_hw_vpath_mac_addr_get and
- * vxge_hw_vpath_mac_addr_get_next
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_delete(
-       struct __vxge_hw_vpath_handle *vp,
-       u8 *macaddr,
-       u8 *macaddr_mask)
-{
-       u32 i;
-       u64 data1 = 0ULL;
-       u64 data2 = 0ULL;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       for (i = 0; i < ETH_ALEN; i++) {
-               data1 <<= 8;
-               data1 |= (u8)macaddr[i];
-
-               data2 <<= 8;
-               data2 |= (u8)macaddr_mask[i];
-       }
-
-       status = __vxge_hw_vpath_rts_table_set(vp,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA,
-                       0,
-                       VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(data1),
-                       VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(data2));
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_vid_add - Add the vlan id entry for this vpath to vlan id table.
- * @vp: Vpath handle.
- * @vid: vlan id to be added for this vpath into the list
- *
- * Adds the given vlan id into the list for this  vpath.
- * see also: vxge_hw_vpath_vid_delete
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_vid_add(struct __vxge_hw_vpath_handle *vp, u64 vid)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_rts_table_set(vp,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
-                       0, VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(vid), 0);
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_vid_delete - Delete the vlan id entry for this vpath
- *               to vlan id table.
- * @vp: Vpath handle.
- * @vid: vlan id to be added for this vpath into the list
- *
- * Adds the given vlan id into the list for this  vpath.
- * see also: vxge_hw_vpath_vid_add
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_vid_delete(struct __vxge_hw_vpath_handle *vp, u64 vid)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_rts_table_set(vp,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY,
-                       VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID,
-                       0, VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(vid), 0);
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_promisc_enable - Enable promiscuous mode.
- * @vp: Vpath handle.
- *
- * Enable promiscuous mode of Titan-e operation.
- *
- * See also: vxge_hw_vpath_promisc_disable().
- */
-enum vxge_hw_status vxge_hw_vpath_promisc_enable(
-                       struct __vxge_hw_vpath_handle *vp)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       /* Enable promiscuous mode for function 0 only */
-       if (!(vpath->hldev->access_rights &
-               VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM))
-               return VXGE_HW_OK;
-
-       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
-
-       if (!(val64 & VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN)) {
-
-               val64 |= VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN |
-                        VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN |
-                        VXGE_HW_RXMAC_VCFG0_BCAST_EN |
-                        VXGE_HW_RXMAC_VCFG0_ALL_VID_EN;
-
-               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
-       }
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_promisc_disable - Disable promiscuous mode.
- * @vp: Vpath handle.
- *
- * Disable promiscuous mode of Titan-e operation.
- *
- * See also: vxge_hw_vpath_promisc_enable().
- */
-enum vxge_hw_status vxge_hw_vpath_promisc_disable(
-                       struct __vxge_hw_vpath_handle *vp)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
-
-       if (val64 & VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN) {
-
-               val64 &= ~(VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN |
-                          VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN |
-                          VXGE_HW_RXMAC_VCFG0_ALL_VID_EN);
-
-               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
-       }
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_bcast_enable - Enable broadcast
- * @vp: Vpath handle.
- *
- * Enable receiving broadcasts.
- */
-enum vxge_hw_status vxge_hw_vpath_bcast_enable(
-                       struct __vxge_hw_vpath_handle *vp)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
-
-       if (!(val64 & VXGE_HW_RXMAC_VCFG0_BCAST_EN)) {
-               val64 |= VXGE_HW_RXMAC_VCFG0_BCAST_EN;
-               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
-       }
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_mcast_enable - Enable multicast addresses.
- * @vp: Vpath handle.
- *
- * Enable Titan-e multicast addresses.
- * Returns: VXGE_HW_OK on success.
- *
- */
-enum vxge_hw_status vxge_hw_vpath_mcast_enable(
-                       struct __vxge_hw_vpath_handle *vp)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
-
-       if (!(val64 & VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN)) {
-               val64 |= VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN;
-               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
-       }
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_mcast_disable - Disable  multicast addresses.
- * @vp: Vpath handle.
- *
- * Disable Titan-e multicast addresses.
- * Returns: VXGE_HW_OK - success.
- * VXGE_HW_ERR_INVALID_HANDLE - Invalid handle
- *
- */
-enum vxge_hw_status
-vxge_hw_vpath_mcast_disable(struct __vxge_hw_vpath_handle *vp)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath;
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if ((vp == NULL) || (vp->vpath->ringh == NULL)) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       vpath = vp->vpath;
-
-       val64 = readq(&vpath->vp_reg->rxmac_vcfg0);
-
-       if (val64 & VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN) {
-               val64 &= ~VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN;
-               writeq(val64, &vpath->vp_reg->rxmac_vcfg0);
-       }
-exit:
-       return status;
-}
-
-/*
- * vxge_hw_vpath_alarm_process - Process Alarms.
- * @vpath: Virtual Path.
- * @skip_alarms: Do not clear the alarms
- *
- * Process vpath alarms.
- *
- */
-enum vxge_hw_status vxge_hw_vpath_alarm_process(
-                       struct __vxge_hw_vpath_handle *vp,
-                       u32 skip_alarms)
-{
-       enum vxge_hw_status status = VXGE_HW_OK;
-
-       if (vp == NULL) {
-               status = VXGE_HW_ERR_INVALID_HANDLE;
-               goto exit;
-       }
-
-       status = __vxge_hw_vpath_alarm_process(vp->vpath, skip_alarms);
-exit:
-       return status;
-}
-
-/**
- * vxge_hw_vpath_msix_set - Associate MSIX vectors with TIM interrupts and
- *                            alrms
- * @vp: Virtual Path handle.
- * @tim_msix_id: MSIX vectors associated with VXGE_HW_MAX_INTR_PER_VP number of
- *             interrupts(Can be repeated). If fifo or ring are not enabled
- *             the MSIX vector for that should be set to 0
- * @alarm_msix_id: MSIX vector for alarm.
- *
- * This API will associate a given MSIX vector numbers with the four TIM
- * interrupts and alarm interrupt.
- */
-void
-vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vp, int *tim_msix_id,
-                      int alarm_msix_id)
-{
-       u64 val64;
-       struct __vxge_hw_virtualpath *vpath = vp->vpath;
-       struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
-       u32 vp_id = vp->vpath->vp_id;
-
-       val64 =  VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(
-                 (vp_id * 4) + tim_msix_id[0]) |
-                VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(
-                 (vp_id * 4) + tim_msix_id[1]);
-
-       writeq(val64, &vp_reg->interrupt_cfg0);
-
-       writeq(VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(
-                       (vpath->hldev->first_vp_id * 4) + alarm_msix_id),
-                       &vp_reg->interrupt_cfg2);
-
-       if (vpath->hldev->config.intr_mode ==
-                                       VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) {
-               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(
-                               VXGE_HW_ONE_SHOT_VECT0_EN_ONE_SHOT_VECT0_EN,
-                               0, 32), &vp_reg->one_shot_vect0_en);
-               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(
-                               VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN,
-                               0, 32), &vp_reg->one_shot_vect1_en);
-               __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(
-                               VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN,
-                               0, 32), &vp_reg->one_shot_vect2_en);
-       }
-}
-
-/**
- * vxge_hw_vpath_msix_mask - Mask MSIX Vector.
- * @vp: Virtual Path handle.
- * @msix_id:  MSIX ID
- *
- * The function masks the msix interrupt for the given msix_id
- *
- * Returns: 0,
- * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
- * status.
- * See also:
- */
-void
-vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vp, int msix_id)
-{
-       struct __vxge_hw_device *hldev = vp->vpath->hldev;
-       __vxge_hw_pio_mem_write32_upper(
-               (u32) vxge_bVALn(vxge_mBIT(msix_id  >> 2), 0, 32),
-               &hldev->common_reg->set_msix_mask_vect[msix_id % 4]);
-}
-
-/**
- * vxge_hw_vpath_msix_clear - Clear MSIX Vector.
- * @vp: Virtual Path handle.
- * @msix_id:  MSI ID
- *
- * The function clears the msix interrupt for the given msix_id
- *
- * Returns: 0,
- * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
- * status.
- * See also:
- */
-void vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id)
-{
-       struct __vxge_hw_device *hldev = vp->vpath->hldev;
-
-       if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_MSIX_ONE_SHOT)
-               __vxge_hw_pio_mem_write32_upper(
-                       (u32) vxge_bVALn(vxge_mBIT((msix_id >> 2)), 0, 32),
-                       &hldev->common_reg->clr_msix_one_shot_vec[msix_id % 4]);
-       else
-               __vxge_hw_pio_mem_write32_upper(
-                       (u32) vxge_bVALn(vxge_mBIT((msix_id >> 2)), 0, 32),
-                       &hldev->common_reg->clear_msix_mask_vect[msix_id % 4]);
-}
-
-/**
- * vxge_hw_vpath_msix_unmask - Unmask the MSIX Vector.
- * @vp: Virtual Path handle.
- * @msix_id:  MSI ID
- *
- * The function unmasks the msix interrupt for the given msix_id
- *
- * Returns: 0,
- * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range
- * status.
- * See also:
- */
-void
-vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vp, int msix_id)
-{
-       struct __vxge_hw_device *hldev = vp->vpath->hldev;
-       __vxge_hw_pio_mem_write32_upper(
-                       (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
-                       &hldev->common_reg->clear_msix_mask_vect[msix_id%4]);
-}
-
-/**
- * vxge_hw_vpath_inta_mask_tx_rx - Mask Tx and Rx interrupts.
- * @vp: Virtual Path handle.
- *
- * Mask Tx and Rx vpath interrupts.
- *
- * See also: vxge_hw_vpath_inta_mask_tx_rx()
- */
-void vxge_hw_vpath_inta_mask_tx_rx(struct __vxge_hw_vpath_handle *vp)
-{
-       u64     tim_int_mask0[4] = {[0 ...3] = 0};
-       u32     tim_int_mask1[4] = {[0 ...3] = 0};
-       u64     val64;
-       struct __vxge_hw_device *hldev = vp->vpath->hldev;
-
-       VXGE_HW_DEVICE_TIM_INT_MASK_SET(tim_int_mask0,
-               tim_int_mask1, vp->vpath->vp_id);
-
-       val64 = readq(&hldev->common_reg->tim_int_mask0);
-
-       if ((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
-               (tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
-               writeq((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
-                       tim_int_mask0[VXGE_HW_VPATH_INTR_RX] | val64),
-                       &hldev->common_reg->tim_int_mask0);
-       }
-
-       val64 = readl(&hldev->common_reg->tim_int_mask1);
-
-       if ((tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
-               (tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
-               __vxge_hw_pio_mem_write32_upper(
-                       (tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
-                       tim_int_mask1[VXGE_HW_VPATH_INTR_RX] | val64),
-                       &hldev->common_reg->tim_int_mask1);
-       }
-}
-
-/**
- * vxge_hw_vpath_inta_unmask_tx_rx - Unmask Tx and Rx interrupts.
- * @vp: Virtual Path handle.
- *
- * Unmask Tx and Rx vpath interrupts.
- *
- * See also: vxge_hw_vpath_inta_mask_tx_rx()
- */
-void vxge_hw_vpath_inta_unmask_tx_rx(struct __vxge_hw_vpath_handle *vp)
-{
-       u64     tim_int_mask0[4] = {[0 ...3] = 0};
-       u32     tim_int_mask1[4] = {[0 ...3] = 0};
-       u64     val64;
-       struct __vxge_hw_device *hldev = vp->vpath->hldev;
-
-       VXGE_HW_DEVICE_TIM_INT_MASK_SET(tim_int_mask0,
-               tim_int_mask1, vp->vpath->vp_id);
-
-       val64 = readq(&hldev->common_reg->tim_int_mask0);
-
-       if ((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) ||
-          (tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) {
-               writeq((~(tim_int_mask0[VXGE_HW_VPATH_INTR_TX] |
-                       tim_int_mask0[VXGE_HW_VPATH_INTR_RX])) & val64,
-                       &hldev->common_reg->tim_int_mask0);
-       }
-
-       if ((tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) ||
-          (tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) {
-               __vxge_hw_pio_mem_write32_upper(
-                       (~(tim_int_mask1[VXGE_HW_VPATH_INTR_TX] |
-                         tim_int_mask1[VXGE_HW_VPATH_INTR_RX])) & val64,
-                       &hldev->common_reg->tim_int_mask1);
-       }
-}
-
-/**
- * vxge_hw_vpath_poll_rx - Poll Rx Virtual Path for completed
- * descriptors and process the same.
- * @ring: Handle to the ring object used for receive
- *
- * The function        polls the Rx for the completed  descriptors and calls
- * the driver via supplied completion  callback.
- *
- * Returns: VXGE_HW_OK, if the polling is completed successful.
- * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed
- * descriptors available which are yet to be processed.
- *
- * See also: vxge_hw_vpath_poll_rx()
- */
-enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring)
-{
-       u8 t_code;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       void *first_rxdh;
-       int new_count = 0;
-
-       ring->cmpl_cnt = 0;
-
-       status = vxge_hw_ring_rxd_next_completed(ring, &first_rxdh, &t_code);
-       if (status == VXGE_HW_OK)
-               ring->callback(ring, first_rxdh,
-                       t_code, ring->channel.userdata);
-
-       if (ring->cmpl_cnt != 0) {
-               ring->doorbell_cnt += ring->cmpl_cnt;
-               if (ring->doorbell_cnt >= ring->rxds_limit) {
-                       /*
-                        * Each RxD is of 4 qwords, update the number of
-                        * qwords replenished
-                        */
-                       new_count = (ring->doorbell_cnt * 4);
-
-                       /* For each block add 4 more qwords */
-                       ring->total_db_cnt += ring->doorbell_cnt;
-                       if (ring->total_db_cnt >= ring->rxds_per_block) {
-                               new_count += 4;
-                               /* Reset total count */
-                               ring->total_db_cnt %= ring->rxds_per_block;
-                       }
-                       writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(new_count),
-                               &ring->vp_reg->prc_rxd_doorbell);
-                       readl(&ring->common_reg->titan_general_int_status);
-                       ring->doorbell_cnt = 0;
-               }
-       }
-
-       return status;
-}
-
-/**
- * vxge_hw_vpath_poll_tx - Poll Tx for completed descriptors and process the same.
- * @fifo: Handle to the fifo object used for non offload send
- * @skb_ptr: pointer to skb
- * @nr_skb: number of skbs
- * @more: more is coming
- *
- * The function polls the Tx for the completed descriptors and calls
- * the driver via supplied completion callback.
- *
- * Returns: VXGE_HW_OK, if the polling is completed successful.
- * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed
- * descriptors available which are yet to be processed.
- */
-enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo,
-                                       struct sk_buff ***skb_ptr, int nr_skb,
-                                       int *more)
-{
-       enum vxge_hw_fifo_tcode t_code;
-       void *first_txdlh;
-       enum vxge_hw_status status = VXGE_HW_OK;
-       struct __vxge_hw_channel *channel;
-
-       channel = &fifo->channel;
-
-       status = vxge_hw_fifo_txdl_next_completed(fifo,
-                               &first_txdlh, &t_code);
-       if (status == VXGE_HW_OK)
-               if (fifo->callback(fifo, first_txdlh, t_code,
-                       channel->userdata, skb_ptr, nr_skb, more) != VXGE_HW_OK)
-                       status = VXGE_HW_COMPLETIONS_REMAIN;
-
-       return status;
-}
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-traffic.h b/drivers/net/ethernet/neterion/vxge/vxge-traffic.h
deleted file mode 100644 (file)
index ba6f833..0000000
+++ /dev/null
@@ -1,2290 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-traffic.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#ifndef VXGE_TRAFFIC_H
-#define VXGE_TRAFFIC_H
-
-#include "vxge-reg.h"
-#include "vxge-version.h"
-
-#define VXGE_HW_DTR_MAX_T_CODE         16
-#define VXGE_HW_ALL_FOXES              0xFFFFFFFFFFFFFFFFULL
-#define VXGE_HW_INTR_MASK_ALL          0xFFFFFFFFFFFFFFFFULL
-#define        VXGE_HW_MAX_VIRTUAL_PATHS       17
-
-#define VXGE_HW_MAC_MAX_MAC_PORT_ID    2
-
-#define VXGE_HW_DEFAULT_32             0xffffffff
-/* frames sizes */
-#define VXGE_HW_HEADER_802_2_SIZE      3
-#define VXGE_HW_HEADER_SNAP_SIZE       5
-#define VXGE_HW_HEADER_VLAN_SIZE       4
-#define VXGE_HW_MAC_HEADER_MAX_SIZE \
-                       (ETH_HLEN + \
-                       VXGE_HW_HEADER_802_2_SIZE + \
-                       VXGE_HW_HEADER_VLAN_SIZE + \
-                       VXGE_HW_HEADER_SNAP_SIZE)
-
-/* 32bit alignments */
-#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN         2
-#define VXGE_HW_HEADER_802_2_SNAP_ALIGN                        2
-#define VXGE_HW_HEADER_802_2_ALIGN                     3
-#define VXGE_HW_HEADER_SNAP_ALIGN                      1
-
-#define VXGE_HW_L3_CKSUM_OK                            0xFFFF
-#define VXGE_HW_L4_CKSUM_OK                            0xFFFF
-
-/* Forward declarations */
-struct __vxge_hw_device;
-struct __vxge_hw_vpath_handle;
-struct vxge_hw_vp_config;
-struct __vxge_hw_virtualpath;
-struct __vxge_hw_channel;
-struct __vxge_hw_fifo;
-struct __vxge_hw_ring;
-struct vxge_hw_ring_attr;
-struct vxge_hw_mempool;
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-/*VXGE_HW_STATUS_H*/
-
-#define VXGE_HW_EVENT_BASE                     0
-#define VXGE_LL_EVENT_BASE                     100
-
-/**
- * enum vxge_hw_event- Enumerates slow-path HW events.
- * @VXGE_HW_EVENT_UNKNOWN: Unknown (and invalid) event.
- * @VXGE_HW_EVENT_SERR: Serious vpath hardware error event.
- * @VXGE_HW_EVENT_ECCERR: vpath ECC error event.
- * @VXGE_HW_EVENT_VPATH_ERR: Error local to the respective vpath
- * @VXGE_HW_EVENT_FIFO_ERR: FIFO Doorbell fifo error.
- * @VXGE_HW_EVENT_SRPCIM_SERR: srpcim hardware error event.
- * @VXGE_HW_EVENT_MRPCIM_SERR: mrpcim hardware error event.
- * @VXGE_HW_EVENT_MRPCIM_ECCERR: mrpcim ecc error event.
- * @VXGE_HW_EVENT_RESET_START: Privileged entity is starting device reset
- * @VXGE_HW_EVENT_RESET_COMPLETE: Device reset has been completed
- * @VXGE_HW_EVENT_SLOT_FREEZE: Slot-freeze event. Driver tries to distinguish
- * slot-freeze from the rest critical events (e.g. ECC) when it is
- * impossible to PIO read "through" the bus, i.e. when getting all-foxes.
- *
- * enum vxge_hw_event enumerates slow-path HW eventis.
- *
- * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{},
- * vxge_uld_link_down_f{}.
- */
-enum vxge_hw_event {
-       VXGE_HW_EVENT_UNKNOWN           = 0,
-       /* HW events */
-       VXGE_HW_EVENT_RESET_START       = VXGE_HW_EVENT_BASE + 1,
-       VXGE_HW_EVENT_RESET_COMPLETE    = VXGE_HW_EVENT_BASE + 2,
-       VXGE_HW_EVENT_LINK_DOWN         = VXGE_HW_EVENT_BASE + 3,
-       VXGE_HW_EVENT_LINK_UP           = VXGE_HW_EVENT_BASE + 4,
-       VXGE_HW_EVENT_ALARM_CLEARED     = VXGE_HW_EVENT_BASE + 5,
-       VXGE_HW_EVENT_ECCERR            = VXGE_HW_EVENT_BASE + 6,
-       VXGE_HW_EVENT_MRPCIM_ECCERR     = VXGE_HW_EVENT_BASE + 7,
-       VXGE_HW_EVENT_FIFO_ERR          = VXGE_HW_EVENT_BASE + 8,
-       VXGE_HW_EVENT_VPATH_ERR         = VXGE_HW_EVENT_BASE + 9,
-       VXGE_HW_EVENT_CRITICAL_ERR      = VXGE_HW_EVENT_BASE + 10,
-       VXGE_HW_EVENT_SERR              = VXGE_HW_EVENT_BASE + 11,
-       VXGE_HW_EVENT_SRPCIM_SERR       = VXGE_HW_EVENT_BASE + 12,
-       VXGE_HW_EVENT_MRPCIM_SERR       = VXGE_HW_EVENT_BASE + 13,
-       VXGE_HW_EVENT_SLOT_FREEZE       = VXGE_HW_EVENT_BASE + 14,
-};
-
-#define VXGE_HW_SET_LEVEL(a, b) (((a) > (b)) ? (a) : (b))
-
-/*
- * struct vxge_hw_mempool_dma - Represents DMA objects passed to the
-       caller.
- */
-struct vxge_hw_mempool_dma {
-       dma_addr_t                      addr;
-       struct pci_dev *handle;
-       struct pci_dev *acc_handle;
-};
-
-/*
- * vxge_hw_mempool_item_f  - Mempool item alloc/free callback
- * @mempoolh: Memory pool handle.
- * @memblock: Address of memory block
- * @memblock_index: Index of memory block
- * @item: Item that gets allocated or freed.
- * @index: Item's index in the memory pool.
- * @is_last: True, if this item is the last one in the pool; false - otherwise.
- * userdata: Per-pool user context.
- *
- * Memory pool allocation/deallocation callback.
- */
-
-/*
- * struct vxge_hw_mempool - Memory pool.
- */
-struct vxge_hw_mempool {
-
-       void (*item_func_alloc)(
-       struct vxge_hw_mempool *mempoolh,
-       u32                     memblock_index,
-       struct vxge_hw_mempool_dma      *dma_object,
-       u32                     index,
-       u32                     is_last);
-
-       void            *userdata;
-       void            **memblocks_arr;
-       void            **memblocks_priv_arr;
-       struct vxge_hw_mempool_dma      *memblocks_dma_arr;
-       struct __vxge_hw_device *devh;
-       u32                     memblock_size;
-       u32                     memblocks_max;
-       u32                     memblocks_allocated;
-       u32                     item_size;
-       u32                     items_max;
-       u32                     items_initial;
-       u32                     items_current;
-       u32                     items_per_memblock;
-       void            **items_arr;
-       u32                     items_priv_size;
-};
-
-#define        VXGE_HW_MAX_INTR_PER_VP                         4
-#define        VXGE_HW_VPATH_INTR_TX                           0
-#define        VXGE_HW_VPATH_INTR_RX                           1
-#define        VXGE_HW_VPATH_INTR_EINTA                        2
-#define        VXGE_HW_VPATH_INTR_BMAP                         3
-
-#define VXGE_HW_BLOCK_SIZE                             4096
-
-/**
- * struct vxge_hw_tim_intr_config - Titan Tim interrupt configuration.
- * @intr_enable: Set to 1, if interrupt is enabled.
- * @btimer_val: Boundary Timer Initialization value in units of 272 ns.
- * @timer_ac_en: Timer Automatic Cancel. 1 : Automatic Canceling Enable: when
- *             asserted, other interrupt-generating entities will cancel the
- *             scheduled timer interrupt.
- * @timer_ci_en: Timer Continuous Interrupt. 1 : Continuous Interrupting Enable:
- *             When asserted, an interrupt will be generated every time the
- *             boundary timer expires, even if no traffic has been transmitted
- *             on this interrupt.
- * @timer_ri_en: Timer Consecutive (Re-) Interrupt 1 : Consecutive
- *             (Re-) Interrupt Enable: When asserted, an interrupt will be
- *             generated the next time the timer expires, even if no traffic has
- *             been transmitted on this interrupt. (This will only happen once
- *             each time that this value is written to the TIM.) This bit is
- *             cleared by H/W at the end of the current-timer-interval when
- *             the interrupt is triggered.
- * @rtimer_val: Restriction Timer Initialization value in units of 272 ns.
- * @util_sel: Utilization Selector. Selects which of the workload approximations
- *             to use (e.g. legacy Tx utilization, Tx/Rx utilization, host
- *             specified utilization etc.), selects one of
- *             the 17 host configured values.
- *             0-Virtual Path 0
- *             1-Virtual Path 1
- *             ...
- *             16-Virtual Path 17
- *             17-Legacy Tx network utilization, provided by TPA
- *             18-Legacy Rx network utilization, provided by FAU
- *             19-Average of legacy Rx and Tx utilization calculated from link
- *                utilization values.
- *             20-31-Invalid configurations
- *             32-Host utilization for Virtual Path 0
- *             33-Host utilization for Virtual Path 1
- *             ...
- *             48-Host utilization for Virtual Path 17
- *             49-Legacy Tx network utilization, provided by TPA
- *             50-Legacy Rx network utilization, provided by FAU
- *             51-Average of legacy Rx and Tx utilization calculated from
- *                link utilization values.
- *             52-63-Invalid configurations
- * @ltimer_val: Latency Timer Initialization Value in units of 272 ns.
- * @txd_cnt_en: TxD Return Event Count Enable. This configuration bit when set
- *             to 1 enables counting of TxD0 returns (signalled by PCC's),
- *             towards utilization event count values.
- * @urange_a: Defines the upper limit (in percent) for this utilization range
- *             to be active. This range is considered active
- *             if 0 = UTIL = URNG_A
- *             and the UEC_A field (below) is non-zero.
- * @uec_a: Utilization Event Count A. If this range is active, the adapter will
- *             wait until UEC_A events have occurred on the interrupt before
- *             generating an interrupt.
- * @urange_b: Link utilization range B.
- * @uec_b: Utilization Event Count B.
- * @urange_c: Link utilization range C.
- * @uec_c: Utilization Event Count C.
- * @urange_d: Link utilization range D.
- * @uec_d: Utilization Event Count D.
- * Traffic Interrupt Controller Module interrupt configuration.
- */
-struct vxge_hw_tim_intr_config {
-
-       u32                             intr_enable;
-#define VXGE_HW_TIM_INTR_ENABLE                                1
-#define VXGE_HW_TIM_INTR_DISABLE                               0
-#define VXGE_HW_TIM_INTR_DEFAULT                               0
-
-       u32                             btimer_val;
-#define VXGE_HW_MIN_TIM_BTIMER_VAL                             0
-#define VXGE_HW_MAX_TIM_BTIMER_VAL                             67108864
-#define VXGE_HW_USE_FLASH_DEFAULT                              (~0)
-
-       u32                             timer_ac_en;
-#define VXGE_HW_TIM_TIMER_AC_ENABLE                            1
-#define VXGE_HW_TIM_TIMER_AC_DISABLE                           0
-
-       u32                             timer_ci_en;
-#define VXGE_HW_TIM_TIMER_CI_ENABLE                            1
-#define VXGE_HW_TIM_TIMER_CI_DISABLE                           0
-
-       u32                             timer_ri_en;
-#define VXGE_HW_TIM_TIMER_RI_ENABLE                            1
-#define VXGE_HW_TIM_TIMER_RI_DISABLE                           0
-
-       u32                             rtimer_val;
-#define VXGE_HW_MIN_TIM_RTIMER_VAL                             0
-#define VXGE_HW_MAX_TIM_RTIMER_VAL                             67108864
-
-       u32                             util_sel;
-#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL                17
-#define VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL                18
-#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_RX_AVE_NET_UTIL         19
-#define VXGE_HW_TIM_UTIL_SEL_PER_VPATH                         63
-
-       u32                             ltimer_val;
-#define VXGE_HW_MIN_TIM_LTIMER_VAL                             0
-#define VXGE_HW_MAX_TIM_LTIMER_VAL                             67108864
-
-       /* Line utilization interrupts */
-       u32                             urange_a;
-#define VXGE_HW_MIN_TIM_URANGE_A                               0
-#define VXGE_HW_MAX_TIM_URANGE_A                               100
-
-       u32                             uec_a;
-#define VXGE_HW_MIN_TIM_UEC_A                                  0
-#define VXGE_HW_MAX_TIM_UEC_A                                  65535
-
-       u32                             urange_b;
-#define VXGE_HW_MIN_TIM_URANGE_B                               0
-#define VXGE_HW_MAX_TIM_URANGE_B                               100
-
-       u32                             uec_b;
-#define VXGE_HW_MIN_TIM_UEC_B                                  0
-#define VXGE_HW_MAX_TIM_UEC_B                                  65535
-
-       u32                             urange_c;
-#define VXGE_HW_MIN_TIM_URANGE_C                               0
-#define VXGE_HW_MAX_TIM_URANGE_C                               100
-
-       u32                             uec_c;
-#define VXGE_HW_MIN_TIM_UEC_C                                  0
-#define VXGE_HW_MAX_TIM_UEC_C                                  65535
-
-       u32                             uec_d;
-#define VXGE_HW_MIN_TIM_UEC_D                                  0
-#define VXGE_HW_MAX_TIM_UEC_D                                  65535
-};
-
-#define        VXGE_HW_STATS_OP_READ                                   0
-#define        VXGE_HW_STATS_OP_CLEAR_STAT                             1
-#define        VXGE_HW_STATS_OP_CLEAR_ALL_VPATH_STATS                  2
-#define        VXGE_HW_STATS_OP_CLEAR_ALL_STATS_OF_LOC                 2
-#define        VXGE_HW_STATS_OP_CLEAR_ALL_STATS                        3
-
-#define        VXGE_HW_STATS_LOC_AGGR                                  17
-#define VXGE_HW_STATS_AGGRn_OFFSET                             0x00720
-
-#define VXGE_HW_STATS_VPATH_TX_OFFSET                          0x0
-#define VXGE_HW_STATS_VPATH_RX_OFFSET                          0x00090
-
-#define        VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET        (0x001d0 >> 3)
-#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(bits) \
-                                               vxge_bVALn(bits, 0, 32)
-
-#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(bits) \
-                                               vxge_bVALn(bits, 32, 32)
-
-#define        VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET        (0x001d8 >> 3)
-#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(bits) \
-                                               vxge_bVALn(bits, 0, 32)
-
-#define        VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(bits) \
-                                               vxge_bVALn(bits, 32, 32)
-
-/**
- * struct vxge_hw_xmac_aggr_stats - Per-Aggregator XMAC Statistics
- *
- * @tx_frms: Count of data frames transmitted on this Aggregator on all
- *             its Aggregation ports. Does not include LACPDUs or Marker PDUs.
- *             However, does include frames discarded by the Distribution
- *             function.
- * @tx_data_octets: Count of data and padding octets of frames transmitted
- *             on this Aggregator on all its Aggregation ports. Does not include
- *             octets of LACPDUs or Marker PDUs. However, does include octets of
- *             frames discarded by the Distribution function.
- * @tx_mcast_frms: Count of data frames transmitted (to a group destination
- *             address other than the broadcast address) on this Aggregator on
- *             all its Aggregation ports. Does not include LACPDUs or Marker
- *             PDUs. However, does include frames discarded by the Distribution
- *             function.
- * @tx_bcast_frms: Count of broadcast data frames transmitted on this Aggregator
- *             on all its Aggregation ports. Does not include LACPDUs or Marker
- *             PDUs. However, does include frames discarded by the Distribution
- *             function.
- * @tx_discarded_frms: Count of data frames to be transmitted on this Aggregator
- *             that are discarded by the Distribution function. This occurs when
- *             conversation are allocated to different ports and have to be
- *             flushed on old ports
- * @tx_errored_frms: Count of data frames transmitted on this Aggregator that
- *             experience transmission errors on its Aggregation ports.
- * @rx_frms: Count of data frames received on this Aggregator on all its
- *             Aggregation ports. Does not include LACPDUs or Marker PDUs.
- *             Also, does not include frames discarded by the Collection
- *             function.
- * @rx_data_octets: Count of data and padding octets of frames received on this
- *             Aggregator on all its Aggregation ports. Does not include octets
- *             of LACPDUs or Marker PDUs. Also, does not include
- *             octets of frames
- *             discarded by the Collection function.
- * @rx_mcast_frms: Count of data frames received (from a group destination
- *             address other than the broadcast address) on this Aggregator on
- *             all its Aggregation ports. Does not include LACPDUs or Marker
- *             PDUs. Also, does not include frames discarded by the Collection
- *             function.
- * @rx_bcast_frms: Count of broadcast data frames received on this Aggregator on
- *             all its Aggregation ports. Does not include LACPDUs or Marker
- *             PDUs. Also, does not include frames discarded by the Collection
- *             function.
- * @rx_discarded_frms: Count of data frames received on this Aggregator that are
- *             discarded by the Collection function because the Collection
- *             function was disabled on the port which the frames are received.
- * @rx_errored_frms: Count of data frames received on this Aggregator that are
- *             discarded by its Aggregation ports, or are discarded by the
- *             Collection function of the Aggregator, or that are discarded by
- *             the Aggregator due to detection of an illegal Slow Protocols PDU.
- * @rx_unknown_slow_proto_frms: Count of data frames received on this Aggregator
- *             that are discarded by its Aggregation ports due to detection of
- *             an unknown Slow Protocols PDU.
- *
- * Per aggregator XMAC RX statistics.
- */
-struct vxge_hw_xmac_aggr_stats {
-/*0x000*/              u64     tx_frms;
-/*0x008*/              u64     tx_data_octets;
-/*0x010*/              u64     tx_mcast_frms;
-/*0x018*/              u64     tx_bcast_frms;
-/*0x020*/              u64     tx_discarded_frms;
-/*0x028*/              u64     tx_errored_frms;
-/*0x030*/              u64     rx_frms;
-/*0x038*/              u64     rx_data_octets;
-/*0x040*/              u64     rx_mcast_frms;
-/*0x048*/              u64     rx_bcast_frms;
-/*0x050*/              u64     rx_discarded_frms;
-/*0x058*/              u64     rx_errored_frms;
-/*0x060*/              u64     rx_unknown_slow_proto_frms;
-} __packed;
-
-/**
- * struct vxge_hw_xmac_port_stats - XMAC Port Statistics
- *
- * @tx_ttl_frms: Count of successfully transmitted MAC frames
- * @tx_ttl_octets: Count of total octets of transmitted frames, not including
- *            framing characters (i.e. less framing bits). To determine the
- *            total octets of transmitted frames, including framing characters,
- *            multiply PORTn_TX_TTL_FRMS by 8 and add it to this stat (unless
- *            otherwise configured, this stat only counts frames that have
- *            8 bytes of preamble for each frame). This stat can be configured
- *            (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count everything
- *            including the preamble octets.
- * @tx_data_octets: Count of data and padding octets of successfully transmitted
- *            frames.
- * @tx_mcast_frms: Count of successfully transmitted frames to a group address
- *            other than the broadcast address.
- * @tx_bcast_frms: Count of successfully transmitted frames to the broadcast
- *            group address.
- * @tx_ucast_frms: Count of transmitted frames containing a unicast address.
- *            Includes discarded frames that are not sent to the network.
- * @tx_tagged_frms: Count of transmitted frames containing a VLAN tag.
- * @tx_vld_ip: Count of transmitted IP datagrams that are passed to the network.
- * @tx_vld_ip_octets: Count of total octets of transmitted IP datagrams that
- *            are passed to the network.
- * @tx_icmp: Count of transmitted ICMP messages. Includes messages not sent
- *            due to problems within ICMP.
- * @tx_tcp: Count of transmitted TCP segments. Does not include segments
- *            containing retransmitted octets.
- * @tx_rst_tcp: Count of transmitted TCP segments containing the RST flag.
- * @tx_udp: Count of transmitted UDP datagrams.
- * @tx_parse_error: Increments when the TPA is unable to parse a packet. This
- *            generally occurs when a packet is corrupt somehow, including
- *            packets that have IP version mismatches, invalid Layer 2 control
- *            fields, etc. L3/L4 checksums are not offloaded, but the packet
- *            is still be transmitted.
- * @tx_unknown_protocol: Increments when the TPA encounters an unknown
- *            protocol, such as a new IPv6 extension header, or an unsupported
- *            Routing Type. The packet still has a checksum calculated but it
- *            may be incorrect.
- * @tx_pause_ctrl_frms: Count of MAC PAUSE control frames that are transmitted.
- *            Since, the only control frames supported by this device are
- *            PAUSE frames, this register is a count of all transmitted MAC
- *            control frames.
- * @tx_marker_pdu_frms: Count of Marker PDUs transmitted
- * on this Aggregation port.
- * @tx_lacpdu_frms: Count of LACPDUs transmitted on this Aggregation port.
- * @tx_drop_ip: Count of transmitted IP datagrams that could not be passed to
- *            the network. Increments because of:
- *            1) An internal processing error
- *            (such as an uncorrectable ECC error). 2) A frame parsing error
- *            during IP checksum calculation.
- * @tx_marker_resp_pdu_frms: Count of Marker Response PDUs transmitted on this
- *            Aggregation port.
- * @tx_xgmii_char2_match: Maintains a count of the number of transmitted XGMII
- *            characters that match a pattern that is programmable through
- *            register XMAC_STATS_TX_XGMII_CHAR_PORTn. By default, the pattern
- *            is set to /T/ (i.e. the terminate character), thus the statistic
- *            tracks the number of transmitted Terminate characters.
- * @tx_xgmii_char1_match: Maintains a count of the number of transmitted XGMII
- *            characters that match a pattern that is programmable through
- *            register XMAC_STATS_TX_XGMII_CHAR_PORTn. By default, the pattern
- *            is set to /S/ (i.e. the start character),
- *            thus the statistic tracks
- *            the number of transmitted Start characters.
- * @tx_xgmii_column2_match: Maintains a count of the number of transmitted XGMII
- *            columns that match a pattern that is programmable through register
- *            XMAC_STATS_TX_XGMII_COLUMN2_PORTn. By default, the pattern is set
- *            to 4 x /E/ (i.e. a column containing all error characters), thus
- *            the statistic tracks the number of Error columns transmitted at
- *            any time. If XMAC_STATS_TX_XGMII_BEHAV_COLUMN2_PORTn.NEAR_COL1 is
- *            set to 1, then this stat increments when COLUMN2 is found within
- *            'n' clocks after COLUMN1. Here, 'n' is defined by
- *            XMAC_STATS_TX_XGMII_BEHAV_COLUMN2_PORTn.NUM_COL (if 'n' is set
- *            to 0, then it means to search anywhere for COLUMN2).
- * @tx_xgmii_column1_match: Maintains a count of the number of transmitted XGMII
- *            columns that match a pattern that is programmable through register
- *            XMAC_STATS_TX_XGMII_COLUMN1_PORTn. By default, the pattern is set
- *            to 4 x /I/ (i.e. a column containing all idle characters),
- *            thus the statistic tracks the number of transmitted Idle columns.
- * @tx_any_err_frms: Count of transmitted frames containing any error that
- *            prevents them from being passed to the network. Increments if
- *            there is an ECC while reading the frame out of the transmit
- *            buffer. Also increments if the transmit protocol assist (TPA)
- *            block determines that the frame should not be sent.
- * @tx_drop_frms: Count of frames that could not be sent for no other reason
- *            than internal MAC processing. Increments once whenever the
- *            transmit buffer is flushed (due to an ECC error on a memory
- *            descriptor).
- * @rx_ttl_frms: Count of total received MAC frames, including frames received
- *            with frame-too-long, FCS, or length errors. This stat can be
- *            configured (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count
- *            everything, even "frames" as small one byte of preamble.
- * @rx_vld_frms: Count of successfully received MAC frames. Does not include
- *            frames received with frame-too-long, FCS, or length errors.
- * @rx_offload_frms: Count of offloaded received frames that are passed to
- *            the host.
- * @rx_ttl_octets: Count of total octets of received frames, not including
- *            framing characters (i.e. less framing bits). To determine the
- *            total octets of received frames, including framing characters,
- *            multiply PORTn_RX_TTL_FRMS by 8 and add it to this stat (unless
- *            otherwise configured, this stat only counts frames that have 8
- *            bytes of preamble for each frame). This stat can be configured
- *            (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count everything,
- *            even the preamble octets of "frames" as small one byte of preamble
- * @rx_data_octets: Count of data and padding octets of successfully received
- *            frames. Does not include frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_offload_octets: Count of total octets, not including framing
- *            characters, of offloaded received frames that are passed
- *            to the host.
- * @rx_vld_mcast_frms: Count of successfully received MAC frames containing a
- *           nonbroadcast group address. Does not include frames received
- *            with frame-too-long, FCS, or length errors.
- * @rx_vld_bcast_frms: Count of successfully received MAC frames containing
- *            the broadcast group address. Does not include frames received
- *            with frame-too-long, FCS, or length errors.
- * @rx_accepted_ucast_frms: Count of successfully received frames containing
- *            a unicast address. Only includes frames that are passed to
- *            the system.
- * @rx_accepted_nucast_frms: Count of successfully received frames containing
- *            a non-unicast (broadcast or multicast) address. Only includes
- *            frames that are passed to the system. Could include, for instance,
- *            non-unicast frames that contain FCS errors if the MAC_ERROR_CFG
- *            register is set to pass FCS-errored frames to the host.
- * @rx_tagged_frms: Count of received frames containing a VLAN tag.
- * @rx_long_frms: Count of received frames that are longer than RX_MAX_PYLD_LEN
- *            + 18 bytes (+ 22 bytes if VLAN-tagged).
- * @rx_usized_frms: Count of received frames of length (including FCS, but not
- *            framing bits) less than 64 octets, that are otherwise well-formed.
- *            In other words, counts runts.
- * @rx_osized_frms: Count of received frames of length (including FCS, but not
- *            framing bits) more than 1518 octets, that are otherwise
- *            well-formed. Note: If register XMAC_STATS_GLOBAL_CFG.VLAN_HANDLING
- *            is set to 1, then "more than 1518 octets" becomes "more than 1518
- *            (1522 if VLAN-tagged) octets".
- * @rx_frag_frms: Count of received frames of length (including FCS, but not
- *            framing bits) less than 64 octets that had bad FCS. In other
- *            words, counts fragments.
- * @rx_jabber_frms: Count of received frames of length (including FCS, but not
- *            framing bits) more than 1518 octets that had bad FCS. In other
- *            words, counts jabbers. Note: If register
- *            XMAC_STATS_GLOBAL_CFG.VLAN_HANDLING is set to 1, then "more than
- *            1518 octets" becomes "more than 1518 (1522 if VLAN-tagged)
- *            octets".
- * @rx_ttl_64_frms: Count of total received MAC frames with length (including
- *            FCS, but not framing bits) of exactly 64 octets. Includes frames
- *            received with frame-too-long, FCS, or length errors.
- * @rx_ttl_65_127_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 65 and 127
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_128_255_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 128 and 255
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_256_511_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 256 and 511
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_512_1023_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 512 and 1023
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_1024_1518_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 1024 and 1518
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_1519_4095_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 1519 and 4095
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_4096_8191_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 4096 and 8191
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_8192_max_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 8192 and
- *            RX_MAX_PYLD_LEN+18 octets inclusive. Includes frames received
- *            with frame-too-long, FCS, or length errors.
- * @rx_ttl_gt_max_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) exceeding
- *            RX_MAX_PYLD_LEN+18 (+22 bytes if VLAN-tagged) octets inclusive.
- *            Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ip: Count of received IP datagrams. Includes errored IP datagrams.
- * @rx_accepted_ip: Count of received IP datagrams that
- *             are passed to the system.
- * @rx_ip_octets: Count of number of octets in received IP datagrams. Includes
- *            errored IP datagrams.
- * @rx_err_ip:         Count of received IP datagrams containing errors. For example,
- *            bad IP checksum.
- * @rx_icmp: Count of received ICMP messages. Includes errored ICMP messages.
- * @rx_tcp: Count of received TCP segments. Includes errored TCP segments.
- *            Note: This stat contains a count of all received TCP segments,
- *            regardless of whether or not they pertain to an established
- *            connection.
- * @rx_udp: Count of received UDP datagrams.
- * @rx_err_tcp: Count of received TCP segments containing errors. For example,
- *            bad TCP checksum.
- * @rx_pause_count: Count of number of pause quanta that the MAC has been in
- *            the paused state. Recall, one pause quantum equates to 512
- *            bit times.
- * @rx_pause_ctrl_frms: Count of received MAC PAUSE control frames.
- * @rx_unsup_ctrl_frms: Count of received MAC control frames that do not
- *            contain the PAUSE opcode. The sum of RX_PAUSE_CTRL_FRMS and
- *            this register is a count of all received MAC control frames.
- *            Note: This stat may be configured to count all layer 2 errors
- *            (i.e. length errors and FCS errors).
- * @rx_fcs_err_frms: Count of received MAC frames that do not pass FCS. Does
- *            not include frames received with frame-too-long or
- *            frame-too-short error.
- * @rx_in_rng_len_err_frms: Count of received frames with a length/type field
- *            value between 46 (42 for VLAN-tagged frames) and 1500 (also 1500
- *            for VLAN-tagged frames), inclusive, that does not match the
- *            number of data octets (including pad) received. Also contains
- *            a count of received frames with a length/type field less than
- *            46 (42 for VLAN-tagged frames) and the number of data octets
- *            (including pad) received is greater than 46 (42 for VLAN-tagged
- *            frames).
- * @rx_out_rng_len_err_frms:  Count of received frames with length/type field
- *            between 1501 and 1535 decimal, inclusive.
- * @rx_drop_frms: Count of received frames that could not be passed to the host.
- *            See PORTn_RX_L2_MGMT_DISCARD, PORTn_RX_RPA_DISCARD,
- *            PORTn_RX_TRASH_DISCARD, PORTn_RX_RTS_DISCARD, PORTn_RX_RED_DISCARD
- *            for a list of reasons. Because the RMAC drops one frame at a time,
- *            this stat also indicates the number of drop events.
- * @rx_discarded_frms: Count of received frames containing
- *             any error that prevents
- *            them from being passed to the system. See PORTn_RX_FCS_DISCARD,
- *            PORTn_RX_LEN_DISCARD, and PORTn_RX_SWITCH_DISCARD for a list of
- *            reasons.
- * @rx_drop_ip: Count of received IP datagrams that could not be passed to the
- *            host. See PORTn_RX_DROP_FRMS for a list of reasons.
- * @rx_drop_udp: Count of received UDP datagrams that are not delivered to the
- *            host. See PORTn_RX_DROP_FRMS for a list of reasons.
- * @rx_marker_pdu_frms: Count of valid Marker PDUs received on this Aggregation
- *            port.
- * @rx_lacpdu_frms: Count of valid LACPDUs received on this Aggregation port.
- * @rx_unknown_pdu_frms: Count of received frames (on this Aggregation port)
- *            that carry the Slow Protocols EtherType, but contain an unknown
- *            PDU. Or frames that contain the Slow Protocols group MAC address,
- *            but do not carry the Slow Protocols EtherType.
- * @rx_marker_resp_pdu_frms: Count of valid Marker Response PDUs received on
- *            this Aggregation port.
- * @rx_fcs_discard: Count of received frames that are discarded because the
- *            FCS check failed.
- * @rx_illegal_pdu_frms: Count of received frames (on this Aggregation port)
- *            that carry the Slow Protocols EtherType, but contain a badly
- *            formed PDU. Or frames that carry the Slow Protocols EtherType,
- *            but contain an illegal value of Protocol Subtype.
- * @rx_switch_discard: Count of received frames that are discarded by the
- *            internal switch because they did not have an entry in the
- *            Filtering Database. This includes frames that had an invalid
- *            destination MAC address or VLAN ID. It also includes frames are
- *            discarded because they did not satisfy the length requirements
- *            of the target VPATH.
- * @rx_len_discard: Count of received frames that are discarded because of an
- *            invalid frame length (includes fragments, oversized frames and
- *            mismatch between frame length and length/type field). This stat
- *            can be configured
- *            (see XMAC_STATS_GLOBAL_CFG.LEN_DISCARD_HANDLING).
- * @rx_rpa_discard: Count of received frames that were discarded because the
- *            receive protocol assist (RPA) discovered and error in the frame
- *            or was unable to parse the frame.
- * @rx_l2_mgmt_discard: Count of Layer 2 management frames (eg. pause frames,
- *            Link Aggregation Control Protocol (LACP) frames, etc.) that are
- *            discarded.
- * @rx_rts_discard: Count of received frames that are discarded by the receive
- *            traffic steering (RTS) logic. Includes those frame discarded
- *            because the SSC response contradicted the switch table, because
- *            the SSC timed out, or because the target queue could not fit the
- *            frame.
- * @rx_trash_discard: Count of received frames that are discarded because
- *            receive traffic steering (RTS) steered the frame to the trash
- *            queue.
- * @rx_buff_full_discard: Count of received frames that are discarded because
- *            internal buffers are full. Includes frames discarded because the
- *            RTS logic is waiting for an SSC lookup that has no timeout bound.
- *            Also, includes frames that are dropped because the MAC2FAU buffer
- *            is nearly full -- this can happen if the external receive buffer
- *            is full and the receive path is backing up.
- * @rx_red_discard: Count of received frames that are discarded because of RED
- *            (Random Early Discard).
- * @rx_xgmii_ctrl_err_cnt: Maintains a count of unexpected or misplaced control
- *            characters occurring between times of normal data transmission
- *            (i.e. not included in RX_XGMII_DATA_ERR_CNT). This counter is
- *            incremented when either -
- *            1) The Reconciliation Sublayer (RS) is expecting one control
- *               character and gets another (i.e. is expecting a Start
- *               character, but gets another control character).
- *            2) Start control character is not in lane 0
- *            Only increments the count by one for each XGMII column.
- * @rx_xgmii_data_err_cnt: Maintains a count of unexpected control characters
- *            during normal data transmission. If the Reconciliation Sublayer
- *            (RS) receives a control character, other than a terminate control
- *            character, during receipt of data octets then this register is
- *            incremented. Also increments if the start frame delimiter is not
- *            found in the correct location. Only increments the count by one
- *            for each XGMII column.
- * @rx_xgmii_char1_match: Maintains a count of the number of XGMII characters
- *            that match a pattern that is programmable through register
- *            XMAC_STATS_RX_XGMII_CHAR_PORTn. By default, the pattern is set
- *            to /E/ (i.e. the error character), thus the statistic tracks the
- *            number of Error characters received at any time.
- * @rx_xgmii_err_sym: Count of the number of symbol errors in the received
- *            XGMII data (i.e. PHY indicates "Receive Error" on the XGMII).
- *            Only includes symbol errors that are observed between the XGMII
- *            Start Frame Delimiter and End Frame Delimiter, inclusive. And
- *            only increments the count by one for each frame.
- * @rx_xgmii_column1_match: Maintains a count of the number of XGMII columns
- *            that match a pattern that is programmable through register
- *            XMAC_STATS_RX_XGMII_COLUMN1_PORTn. By default, the pattern is set
- *            to 4 x /E/ (i.e. a column containing all error characters), thus
- *            the statistic tracks the number of Error columns received at any
- *            time.
- * @rx_xgmii_char2_match: Maintains a count of the number of XGMII characters
- *            that match a pattern that is programmable through register
- *            XMAC_STATS_RX_XGMII_CHAR_PORTn. By default, the pattern is set
- *            to /E/ (i.e. the error character), thus the statistic tracks the
- *            number of Error characters received at any time.
- * @rx_local_fault: Maintains a count of the number of times that link
- *            transitioned from "up" to "down" due to a local fault.
- * @rx_xgmii_column2_match: Maintains a count of the number of XGMII columns
- *            that match a pattern that is programmable through register
- *            XMAC_STATS_RX_XGMII_COLUMN2_PORTn. By default, the pattern is set
- *            to 4 x /E/ (i.e. a column containing all error characters), thus
- *            the statistic tracks the number of Error columns received at any
- *            time. If XMAC_STATS_RX_XGMII_BEHAV_COLUMN2_PORTn.NEAR_COL1 is set
- *            to 1, then this stat increments when COLUMN2 is found within 'n'
- *            clocks after COLUMN1. Here, 'n' is defined by
- *            XMAC_STATS_RX_XGMII_BEHAV_COLUMN2_PORTn.NUM_COL (if 'n' is set to
- *            0, then it means to search anywhere for COLUMN2).
- * @rx_jettison: Count of received frames that are jettisoned because internal
- *            buffers are full.
- * @rx_remote_fault: Maintains a count of the number of times that link
- *            transitioned from "up" to "down" due to a remote fault.
- *
- * XMAC Port Statistics.
- */
-struct vxge_hw_xmac_port_stats {
-/*0x000*/              u64     tx_ttl_frms;
-/*0x008*/              u64     tx_ttl_octets;
-/*0x010*/              u64     tx_data_octets;
-/*0x018*/              u64     tx_mcast_frms;
-/*0x020*/              u64     tx_bcast_frms;
-/*0x028*/              u64     tx_ucast_frms;
-/*0x030*/              u64     tx_tagged_frms;
-/*0x038*/              u64     tx_vld_ip;
-/*0x040*/              u64     tx_vld_ip_octets;
-/*0x048*/              u64     tx_icmp;
-/*0x050*/              u64     tx_tcp;
-/*0x058*/              u64     tx_rst_tcp;
-/*0x060*/              u64     tx_udp;
-/*0x068*/              u32     tx_parse_error;
-/*0x06c*/              u32     tx_unknown_protocol;
-/*0x070*/              u64     tx_pause_ctrl_frms;
-/*0x078*/              u32     tx_marker_pdu_frms;
-/*0x07c*/              u32     tx_lacpdu_frms;
-/*0x080*/              u32     tx_drop_ip;
-/*0x084*/              u32     tx_marker_resp_pdu_frms;
-/*0x088*/              u32     tx_xgmii_char2_match;
-/*0x08c*/              u32     tx_xgmii_char1_match;
-/*0x090*/              u32     tx_xgmii_column2_match;
-/*0x094*/              u32     tx_xgmii_column1_match;
-/*0x098*/              u32     unused1;
-/*0x09c*/              u16     tx_any_err_frms;
-/*0x09e*/              u16     tx_drop_frms;
-/*0x0a0*/              u64     rx_ttl_frms;
-/*0x0a8*/              u64     rx_vld_frms;
-/*0x0b0*/              u64     rx_offload_frms;
-/*0x0b8*/              u64     rx_ttl_octets;
-/*0x0c0*/              u64     rx_data_octets;
-/*0x0c8*/              u64     rx_offload_octets;
-/*0x0d0*/              u64     rx_vld_mcast_frms;
-/*0x0d8*/              u64     rx_vld_bcast_frms;
-/*0x0e0*/              u64     rx_accepted_ucast_frms;
-/*0x0e8*/              u64     rx_accepted_nucast_frms;
-/*0x0f0*/              u64     rx_tagged_frms;
-/*0x0f8*/              u64     rx_long_frms;
-/*0x100*/              u64     rx_usized_frms;
-/*0x108*/              u64     rx_osized_frms;
-/*0x110*/              u64     rx_frag_frms;
-/*0x118*/              u64     rx_jabber_frms;
-/*0x120*/              u64     rx_ttl_64_frms;
-/*0x128*/              u64     rx_ttl_65_127_frms;
-/*0x130*/              u64     rx_ttl_128_255_frms;
-/*0x138*/              u64     rx_ttl_256_511_frms;
-/*0x140*/              u64     rx_ttl_512_1023_frms;
-/*0x148*/              u64     rx_ttl_1024_1518_frms;
-/*0x150*/              u64     rx_ttl_1519_4095_frms;
-/*0x158*/              u64     rx_ttl_4096_8191_frms;
-/*0x160*/              u64     rx_ttl_8192_max_frms;
-/*0x168*/              u64     rx_ttl_gt_max_frms;
-/*0x170*/              u64     rx_ip;
-/*0x178*/              u64     rx_accepted_ip;
-/*0x180*/              u64     rx_ip_octets;
-/*0x188*/              u64     rx_err_ip;
-/*0x190*/              u64     rx_icmp;
-/*0x198*/              u64     rx_tcp;
-/*0x1a0*/              u64     rx_udp;
-/*0x1a8*/              u64     rx_err_tcp;
-/*0x1b0*/              u64     rx_pause_count;
-/*0x1b8*/              u64     rx_pause_ctrl_frms;
-/*0x1c0*/              u64     rx_unsup_ctrl_frms;
-/*0x1c8*/              u64     rx_fcs_err_frms;
-/*0x1d0*/              u64     rx_in_rng_len_err_frms;
-/*0x1d8*/              u64     rx_out_rng_len_err_frms;
-/*0x1e0*/              u64     rx_drop_frms;
-/*0x1e8*/              u64     rx_discarded_frms;
-/*0x1f0*/              u64     rx_drop_ip;
-/*0x1f8*/              u64     rx_drop_udp;
-/*0x200*/              u32     rx_marker_pdu_frms;
-/*0x204*/              u32     rx_lacpdu_frms;
-/*0x208*/              u32     rx_unknown_pdu_frms;
-/*0x20c*/              u32     rx_marker_resp_pdu_frms;
-/*0x210*/              u32     rx_fcs_discard;
-/*0x214*/              u32     rx_illegal_pdu_frms;
-/*0x218*/              u32     rx_switch_discard;
-/*0x21c*/              u32     rx_len_discard;
-/*0x220*/              u32     rx_rpa_discard;
-/*0x224*/              u32     rx_l2_mgmt_discard;
-/*0x228*/              u32     rx_rts_discard;
-/*0x22c*/              u32     rx_trash_discard;
-/*0x230*/              u32     rx_buff_full_discard;
-/*0x234*/              u32     rx_red_discard;
-/*0x238*/              u32     rx_xgmii_ctrl_err_cnt;
-/*0x23c*/              u32     rx_xgmii_data_err_cnt;
-/*0x240*/              u32     rx_xgmii_char1_match;
-/*0x244*/              u32     rx_xgmii_err_sym;
-/*0x248*/              u32     rx_xgmii_column1_match;
-/*0x24c*/              u32     rx_xgmii_char2_match;
-/*0x250*/              u32     rx_local_fault;
-/*0x254*/              u32     rx_xgmii_column2_match;
-/*0x258*/              u32     rx_jettison;
-/*0x25c*/              u32     rx_remote_fault;
-} __packed;
-
-/**
- * struct vxge_hw_xmac_vpath_tx_stats - XMAC Vpath Tx Statistics
- *
- * @tx_ttl_eth_frms: Count of successfully transmitted MAC frames.
- * @tx_ttl_eth_octets: Count of total octets of transmitted frames,
- *             not including framing characters (i.e. less framing bits).
- *             To determine the total octets of transmitted frames, including
- *             framing characters, multiply TX_TTL_ETH_FRMS by 8 and add it to
- *             this stat (the device always prepends 8 bytes of preamble for
- *             each frame)
- * @tx_data_octets: Count of data and padding octets of successfully transmitted
- *             frames.
- * @tx_mcast_frms: Count of successfully transmitted frames to a group address
- *             other than the broadcast address.
- * @tx_bcast_frms: Count of successfully transmitted frames to the broadcast
- *             group address.
- * @tx_ucast_frms: Count of transmitted frames containing a unicast address.
- *             Includes discarded frames that are not sent to the network.
- * @tx_tagged_frms: Count of transmitted frames containing a VLAN tag.
- * @tx_vld_ip: Count of transmitted IP datagrams that are passed to the network.
- * @tx_vld_ip_octets: Count of total octets of transmitted IP datagrams that
- *            are passed to the network.
- * @tx_icmp: Count of transmitted ICMP messages. Includes messages not sent due
- *            to problems within ICMP.
- * @tx_tcp: Count of transmitted TCP segments. Does not include segments
- *            containing retransmitted octets.
- * @tx_rst_tcp: Count of transmitted TCP segments containing the RST flag.
- * @tx_udp: Count of transmitted UDP datagrams.
- * @tx_unknown_protocol: Increments when the TPA encounters an unknown protocol,
- *            such as a new IPv6 extension header, or an unsupported Routing
- *            Type. The packet still has a checksum calculated but it may be
- *            incorrect.
- * @tx_lost_ip: Count of transmitted IP datagrams that could not be passed
- *            to the network. Increments because of: 1) An internal processing
- *            error (such as an uncorrectable ECC error). 2) A frame parsing
- *            error during IP checksum calculation.
- * @tx_parse_error: Increments when the TPA is unable to parse a packet. This
- *            generally occurs when a packet is corrupt somehow, including
- *            packets that have IP version mismatches, invalid Layer 2 control
- *            fields, etc. L3/L4 checksums are not offloaded, but the packet
- *            is still be transmitted.
- * @tx_tcp_offload: For frames belonging to offloaded sessions only, a count
- *            of transmitted TCP segments. Does not include segments containing
- *            retransmitted octets.
- * @tx_retx_tcp_offload: For frames belonging to offloaded sessions only, the
- *            total number of segments retransmitted. Retransmitted segments
- *            that are sourced by the host are counted by the host.
- * @tx_lost_ip_offload: For frames belonging to offloaded sessions only, a count
- *            of transmitted IP datagrams that could not be passed to the
- *            network.
- *
- * XMAC Vpath TX Statistics.
- */
-struct vxge_hw_xmac_vpath_tx_stats {
-       u64     tx_ttl_eth_frms;
-       u64     tx_ttl_eth_octets;
-       u64     tx_data_octets;
-       u64     tx_mcast_frms;
-       u64     tx_bcast_frms;
-       u64     tx_ucast_frms;
-       u64     tx_tagged_frms;
-       u64     tx_vld_ip;
-       u64     tx_vld_ip_octets;
-       u64     tx_icmp;
-       u64     tx_tcp;
-       u64     tx_rst_tcp;
-       u64     tx_udp;
-       u32     tx_unknown_protocol;
-       u32     tx_lost_ip;
-       u32     unused1;
-       u32     tx_parse_error;
-       u64     tx_tcp_offload;
-       u64     tx_retx_tcp_offload;
-       u64     tx_lost_ip_offload;
-} __packed;
-
-/**
- * struct vxge_hw_xmac_vpath_rx_stats - XMAC Vpath RX Statistics
- *
- * @rx_ttl_eth_frms: Count of successfully received MAC frames.
- * @rx_vld_frms: Count of successfully received MAC frames. Does not include
- *            frames received with frame-too-long, FCS, or length errors.
- * @rx_offload_frms: Count of offloaded received frames that are passed to
- *            the host.
- * @rx_ttl_eth_octets: Count of total octets of received frames, not including
- *            framing characters (i.e. less framing bits). Only counts octets
- *            of frames that are at least 14 bytes (18 bytes for VLAN-tagged)
- *            before FCS. To determine the total octets of received frames,
- *            including framing characters, multiply RX_TTL_ETH_FRMS by 8 and
- *            add it to this stat (the stat RX_TTL_ETH_FRMS only counts frames
- *            that have the required 8 bytes of preamble).
- * @rx_data_octets: Count of data and padding octets of successfully received
- *            frames. Does not include frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_offload_octets: Count of total octets, not including framing characters,
- *            of offloaded received frames that are passed to the host.
- * @rx_vld_mcast_frms: Count of successfully received MAC frames containing a
- *            nonbroadcast group address. Does not include frames received with
- *            frame-too-long, FCS, or length errors.
- * @rx_vld_bcast_frms: Count of successfully received MAC frames containing the
- *            broadcast group address. Does not include frames received with
- *            frame-too-long, FCS, or length errors.
- * @rx_accepted_ucast_frms: Count of successfully received frames containing
- *            a unicast address. Only includes frames that are passed to the
- *            system.
- * @rx_accepted_nucast_frms: Count of successfully received frames containing
- *            a non-unicast (broadcast or multicast) address. Only includes
- *            frames that are passed to the system. Could include, for instance,
- *            non-unicast frames that contain FCS errors if the MAC_ERROR_CFG
- *            register is set to pass FCS-errored frames to the host.
- * @rx_tagged_frms: Count of received frames containing a VLAN tag.
- * @rx_long_frms: Count of received frames that are longer than RX_MAX_PYLD_LEN
- *            + 18 bytes (+ 22 bytes if VLAN-tagged).
- * @rx_usized_frms: Count of received frames of length (including FCS, but not
- *            framing bits) less than 64 octets, that are otherwise well-formed.
- *            In other words, counts runts.
- * @rx_osized_frms: Count of received frames of length (including FCS, but not
- *            framing bits) more than 1518 octets, that are otherwise
- *            well-formed.
- * @rx_frag_frms: Count of received frames of length (including FCS, but not
- *            framing bits) less than 64 octets that had bad FCS.
- *            In other words, counts fragments.
- * @rx_jabber_frms: Count of received frames of length (including FCS, but not
- *            framing bits) more than 1518 octets that had bad FCS. In other
- *            words, counts jabbers.
- * @rx_ttl_64_frms: Count of total received MAC frames with length (including
- *            FCS, but not framing bits) of exactly 64 octets. Includes frames
- *            received with frame-too-long, FCS, or length errors.
- * @rx_ttl_65_127_frms: Count of total received MAC frames
- *             with length (including
- *            FCS, but not framing bits) of between 65 and 127 octets inclusive.
- *            Includes frames received with frame-too-long, FCS,
- *            or length errors.
- * @rx_ttl_128_255_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits)
- *            of between 128 and 255 octets
- *            inclusive. Includes frames received with frame-too-long, FCS,
- *            or length errors.
- * @rx_ttl_256_511_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits)
- *            of between 256 and 511 octets
- *            inclusive. Includes frames received with frame-too-long, FCS, or
- *            length errors.
- * @rx_ttl_512_1023_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 512 and 1023
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_1024_1518_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 1024 and 1518
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_1519_4095_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 1519 and 4095
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_4096_8191_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 4096 and 8191
- *            octets inclusive. Includes frames received with frame-too-long,
- *            FCS, or length errors.
- * @rx_ttl_8192_max_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) of between 8192 and
- *            RX_MAX_PYLD_LEN+18 octets inclusive. Includes frames received
- *            with frame-too-long, FCS, or length errors.
- * @rx_ttl_gt_max_frms: Count of total received MAC frames with length
- *            (including FCS, but not framing bits) exceeding RX_MAX_PYLD_LEN+18
- *            (+22 bytes if VLAN-tagged) octets inclusive. Includes frames
- *            received with frame-too-long, FCS, or length errors.
- * @rx_ip: Count of received IP datagrams. Includes errored IP datagrams.
- * @rx_accepted_ip: Count of received IP datagrams that
- *             are passed to the system.
- * @rx_ip_octets: Count of number of octets in received IP datagrams.
- *            Includes errored IP datagrams.
- * @rx_err_ip: Count of received IP datagrams containing errors. For example,
- *            bad IP checksum.
- * @rx_icmp: Count of received ICMP messages. Includes errored ICMP messages.
- * @rx_tcp: Count of received TCP segments. Includes errored TCP segments.
- *             Note: This stat contains a count of all received TCP segments,
- *             regardless of whether or not they pertain to an established
- *             connection.
- * @rx_udp: Count of received UDP datagrams.
- * @rx_err_tcp: Count of received TCP segments containing errors. For example,
- *             bad TCP checksum.
- * @rx_lost_frms: Count of received frames that could not be passed to the host.
- *             See RX_QUEUE_FULL_DISCARD and RX_RED_DISCARD
- *             for a list of reasons.
- * @rx_lost_ip: Count of received IP datagrams that could not be passed to
- *             the host. See RX_LOST_FRMS for a list of reasons.
- * @rx_lost_ip_offload: For frames belonging to offloaded sessions only, a count
- *             of received IP datagrams that could not be passed to the host.
- *             See RX_LOST_FRMS for a list of reasons.
- * @rx_various_discard: Count of received frames that are discarded because
- *             the target receive queue is full.
- * @rx_sleep_discard: Count of received frames that are discarded because the
- *            target VPATH is asleep (a Wake-on-LAN magic packet can be used
- *            to awaken the VPATH).
- * @rx_red_discard: Count of received frames that are discarded because of RED
- *            (Random Early Discard).
- * @rx_queue_full_discard: Count of received frames that are discarded because
- *             the target receive queue is full.
- * @rx_mpa_ok_frms: Count of received frames that pass the MPA checks.
- *
- * XMAC Vpath RX Statistics.
- */
-struct vxge_hw_xmac_vpath_rx_stats {
-       u64     rx_ttl_eth_frms;
-       u64     rx_vld_frms;
-       u64     rx_offload_frms;
-       u64     rx_ttl_eth_octets;
-       u64     rx_data_octets;
-       u64     rx_offload_octets;
-       u64     rx_vld_mcast_frms;
-       u64     rx_vld_bcast_frms;
-       u64     rx_accepted_ucast_frms;
-       u64     rx_accepted_nucast_frms;
-       u64     rx_tagged_frms;
-       u64     rx_long_frms;
-       u64     rx_usized_frms;
-       u64     rx_osized_frms;
-       u64     rx_frag_frms;
-       u64     rx_jabber_frms;
-       u64     rx_ttl_64_frms;
-       u64     rx_ttl_65_127_frms;
-       u64     rx_ttl_128_255_frms;
-       u64     rx_ttl_256_511_frms;
-       u64     rx_ttl_512_1023_frms;
-       u64     rx_ttl_1024_1518_frms;
-       u64     rx_ttl_1519_4095_frms;
-       u64     rx_ttl_4096_8191_frms;
-       u64     rx_ttl_8192_max_frms;
-       u64     rx_ttl_gt_max_frms;
-       u64     rx_ip;
-       u64     rx_accepted_ip;
-       u64     rx_ip_octets;
-       u64     rx_err_ip;
-       u64     rx_icmp;
-       u64     rx_tcp;
-       u64     rx_udp;
-       u64     rx_err_tcp;
-       u64     rx_lost_frms;
-       u64     rx_lost_ip;
-       u64     rx_lost_ip_offload;
-       u16     rx_various_discard;
-       u16     rx_sleep_discard;
-       u16     rx_red_discard;
-       u16     rx_queue_full_discard;
-       u64     rx_mpa_ok_frms;
-} __packed;
-
-/**
- * struct vxge_hw_xmac_stats - XMAC Statistics
- *
- * @aggr_stats: Statistics on aggregate port(port 0, port 1)
- * @port_stats: Staticstics on ports(wire 0, wire 1, lag)
- * @vpath_tx_stats: Per vpath XMAC TX stats
- * @vpath_rx_stats: Per vpath XMAC RX stats
- *
- * XMAC Statistics.
- */
-struct vxge_hw_xmac_stats {
-       struct vxge_hw_xmac_aggr_stats
-                               aggr_stats[VXGE_HW_MAC_MAX_MAC_PORT_ID];
-       struct vxge_hw_xmac_port_stats
-                               port_stats[VXGE_HW_MAC_MAX_MAC_PORT_ID+1];
-       struct vxge_hw_xmac_vpath_tx_stats
-                               vpath_tx_stats[VXGE_HW_MAX_VIRTUAL_PATHS];
-       struct vxge_hw_xmac_vpath_rx_stats
-                               vpath_rx_stats[VXGE_HW_MAX_VIRTUAL_PATHS];
-};
-
-/**
- * struct vxge_hw_vpath_stats_hw_info - Titan vpath hardware statistics.
- * @ini_num_mwr_sent: The number of PCI memory writes initiated by the PIC block
- *             for the given VPATH
- * @ini_num_mrd_sent: The number of PCI memory reads initiated by the PIC block
- * @ini_num_cpl_rcvd: The number of PCI read completions received by the
- *             PIC block
- * @ini_num_mwr_byte_sent: The number of PCI memory write bytes sent by the PIC
- *             block to the host
- * @ini_num_cpl_byte_rcvd: The number of PCI read completion bytes received by
- *             the PIC block
- * @wrcrdtarb_xoff: TBD
- * @rdcrdtarb_xoff: TBD
- * @vpath_genstats_count0: TBD
- * @vpath_genstats_count1: TBD
- * @vpath_genstats_count2: TBD
- * @vpath_genstats_count3: TBD
- * @vpath_genstats_count4: TBD
- * @vpath_gennstats_count5: TBD
- * @tx_stats: Transmit stats
- * @rx_stats: Receive stats
- * @prog_event_vnum1: Programmable statistic. Increments when internal logic
- *             detects a certain event. See register
- *             XMAC_STATS_CFG.EVENT_VNUM1_CFG for more information.
- * @prog_event_vnum0: Programmable statistic. Increments when internal logic
- *             detects a certain event. See register
- *             XMAC_STATS_CFG.EVENT_VNUM0_CFG for more information.
- * @prog_event_vnum3: Programmable statistic. Increments when internal logic
- *             detects a certain event. See register
- *             XMAC_STATS_CFG.EVENT_VNUM3_CFG for more information.
- * @prog_event_vnum2: Programmable statistic. Increments when internal logic
- *             detects a certain event. See register
- *             XMAC_STATS_CFG.EVENT_VNUM2_CFG for more information.
- * @rx_multi_cast_frame_discard: TBD
- * @rx_frm_transferred: TBD
- * @rxd_returned: TBD
- * @rx_mpa_len_fail_frms: Count of received frames
- *             that fail the MPA length check
- * @rx_mpa_mrk_fail_frms: Count of received frames
- *             that fail the MPA marker check
- * @rx_mpa_crc_fail_frms: Count of received frames that fail the MPA CRC check
- * @rx_permitted_frms: Count of frames that pass through the FAU and on to the
- *             frame buffer (and subsequently to the host).
- * @rx_vp_reset_discarded_frms: Count of receive frames that are discarded
- *             because the VPATH is in reset
- * @rx_wol_frms: Count of received "magic packet" frames. Stat increments
- *             whenever the received frame matches the VPATH's Wake-on-LAN
- *             signature(s) CRC.
- * @tx_vp_reset_discarded_frms: Count of transmit frames that are discarded
- *             because the VPATH is in reset. Includes frames that are discarded
- *             because the current VPIN does not match that VPIN of the frame
- *
- * Titan vpath hardware statistics.
- */
-struct vxge_hw_vpath_stats_hw_info {
-/*0x000*/      u32 ini_num_mwr_sent;
-/*0x004*/      u32 unused1;
-/*0x008*/      u32 ini_num_mrd_sent;
-/*0x00c*/      u32 unused2;
-/*0x010*/      u32 ini_num_cpl_rcvd;
-/*0x014*/      u32 unused3;
-/*0x018*/      u64 ini_num_mwr_byte_sent;
-/*0x020*/      u64 ini_num_cpl_byte_rcvd;
-/*0x028*/      u32 wrcrdtarb_xoff;
-/*0x02c*/      u32 unused4;
-/*0x030*/      u32 rdcrdtarb_xoff;
-/*0x034*/      u32 unused5;
-/*0x038*/      u32 vpath_genstats_count0;
-/*0x03c*/      u32 vpath_genstats_count1;
-/*0x040*/      u32 vpath_genstats_count2;
-/*0x044*/      u32 vpath_genstats_count3;
-/*0x048*/      u32 vpath_genstats_count4;
-/*0x04c*/      u32 unused6;
-/*0x050*/      u32 vpath_genstats_count5;
-/*0x054*/      u32 unused7;
-/*0x058*/      struct vxge_hw_xmac_vpath_tx_stats tx_stats;
-/*0x0e8*/      struct vxge_hw_xmac_vpath_rx_stats rx_stats;
-/*0x220*/      u64 unused9;
-/*0x228*/      u32 prog_event_vnum1;
-/*0x22c*/      u32 prog_event_vnum0;
-/*0x230*/      u32 prog_event_vnum3;
-/*0x234*/      u32 prog_event_vnum2;
-/*0x238*/      u16 rx_multi_cast_frame_discard;
-/*0x23a*/      u8 unused10[6];
-/*0x240*/      u32 rx_frm_transferred;
-/*0x244*/      u32 unused11;
-/*0x248*/      u16 rxd_returned;
-/*0x24a*/      u8 unused12[6];
-/*0x252*/      u16 rx_mpa_len_fail_frms;
-/*0x254*/      u16 rx_mpa_mrk_fail_frms;
-/*0x256*/      u16 rx_mpa_crc_fail_frms;
-/*0x258*/      u16 rx_permitted_frms;
-/*0x25c*/      u64 rx_vp_reset_discarded_frms;
-/*0x25e*/      u64 rx_wol_frms;
-/*0x260*/      u64 tx_vp_reset_discarded_frms;
-} __packed;
-
-
-/**
- * struct vxge_hw_device_stats_mrpcim_info - Titan mrpcim hardware statistics.
- * @pic.ini_rd_drop     0x0000          4       Number of DMA reads initiated
- *  by the adapter that were discarded because the VPATH is out of service
- * @pic.ini_wr_drop    0x0004  4       Number of DMA writes initiated by the
- *  adapter that were discared because the VPATH is out of service
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane0]    0x0008  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane1]    0x0010  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane2]    0x0018  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane3]    0x0020  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane4]    0x0028  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane5]    0x0030  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane6]    0x0038  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane7]    0x0040  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane8]    0x0048  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane9]    0x0050  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane10]   0x0058  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane11]   0x0060  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane12]   0x0068  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane13]   0x0070  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane14]   0x0078  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane15]   0x0080  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_ph_crdt_depleted[vplane16]   0x0088  4       Number of times
- *  the posted header credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane0]    0x0090  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane1]    0x0098  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane2]    0x00a0  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane3]    0x00a8  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane4]    0x00b0  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane5]    0x00b8  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane6]    0x00c0  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane7]    0x00c8  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane8]    0x00d0  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane9]    0x00d8  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane10]   0x00e0  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane11]   0x00e8  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane12]   0x00f0  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane13]   0x00f8  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane14]   0x0100  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane15]   0x0108  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.wrcrdtarb_pd_crdt_depleted[vplane16]   0x0110  4       Number of times
- *  the posted data credits for upstream PCI writes were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane0]   0x0118  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane1]   0x0120  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane2]   0x0128  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane3]   0x0130  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane4]   0x0138  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane5]   0x0140  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane6]   0x0148  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane7]   0x0150  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane8]   0x0158  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane9]   0x0160  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane10]  0x0168  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane11]  0x0170  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane12]  0x0178  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane13]  0x0180  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane14]  0x0188  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane15]  0x0190  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.rdcrdtarb_nph_crdt_depleted[vplane16]  0x0198  4       Number of times
- *  the non-posted header credits for upstream PCI reads were depleted
- * @pic.ini_rd_vpin_drop       0x01a0  4       Number of DMA reads initiated by
- *  the adapter that were discarded because the VPATH instance number does
- *  not match
- * @pic.ini_wr_vpin_drop       0x01a4  4       Number of DMA writes initiated
- *  by the adapter that were discarded because the VPATH instance number
- *  does not match
- * @pic.genstats_count0        0x01a8  4       Configurable statistic #1. Refer
- *  to the GENSTATS0_CFG for information on configuring this statistic
- * @pic.genstats_count1        0x01ac  4       Configurable statistic #2. Refer
- *  to the GENSTATS1_CFG for information on configuring this statistic
- * @pic.genstats_count2        0x01b0  4       Configurable statistic #3. Refer
- *  to the GENSTATS2_CFG for information on configuring this statistic
- * @pic.genstats_count3        0x01b4  4       Configurable statistic #4. Refer
- *  to the GENSTATS3_CFG for information on configuring this statistic
- * @pic.genstats_count4        0x01b8  4       Configurable statistic #5. Refer
- *  to the GENSTATS4_CFG for information on configuring this statistic
- * @pic.genstats_count5        0x01c0  4       Configurable statistic #6. Refer
- *  to the GENSTATS5_CFG for information on configuring this statistic
- * @pci.rstdrop_cpl    0x01c8  4
- * @pci.rstdrop_msg    0x01cc  4
- * @pci.rstdrop_client1        0x01d0  4
- * @pci.rstdrop_client0        0x01d4  4
- * @pci.rstdrop_client2        0x01d8  4
- * @pci.depl_cplh[vplane0]     0x01e2  2       Number of times completion
- *  header credits were depleted
- * @pci.depl_nph[vplane0]      0x01e4  2       Number of times non posted
- *  header credits were depleted
- * @pci.depl_ph[vplane0]       0x01e6  2       Number of times the posted
- *  header credits were depleted
- * @pci.depl_cplh[vplane1]     0x01ea  2
- * @pci.depl_nph[vplane1]      0x01ec  2
- * @pci.depl_ph[vplane1]       0x01ee  2
- * @pci.depl_cplh[vplane2]     0x01f2  2
- * @pci.depl_nph[vplane2]      0x01f4  2
- * @pci.depl_ph[vplane2]       0x01f6  2
- * @pci.depl_cplh[vplane3]     0x01fa  2
- * @pci.depl_nph[vplane3]      0x01fc  2
- * @pci.depl_ph[vplane3]       0x01fe  2
- * @pci.depl_cplh[vplane4]     0x0202  2
- * @pci.depl_nph[vplane4]      0x0204  2
- * @pci.depl_ph[vplane4]       0x0206  2
- * @pci.depl_cplh[vplane5]     0x020a  2
- * @pci.depl_nph[vplane5]      0x020c  2
- * @pci.depl_ph[vplane5]       0x020e  2
- * @pci.depl_cplh[vplane6]     0x0212  2
- * @pci.depl_nph[vplane6]      0x0214  2
- * @pci.depl_ph[vplane6]       0x0216  2
- * @pci.depl_cplh[vplane7]     0x021a  2
- * @pci.depl_nph[vplane7]      0x021c  2
- * @pci.depl_ph[vplane7]       0x021e  2
- * @pci.depl_cplh[vplane8]     0x0222  2
- * @pci.depl_nph[vplane8]      0x0224  2
- * @pci.depl_ph[vplane8]       0x0226  2
- * @pci.depl_cplh[vplane9]     0x022a  2
- * @pci.depl_nph[vplane9]      0x022c  2
- * @pci.depl_ph[vplane9]       0x022e  2
- * @pci.depl_cplh[vplane10]    0x0232  2
- * @pci.depl_nph[vplane10]     0x0234  2
- * @pci.depl_ph[vplane10]      0x0236  2
- * @pci.depl_cplh[vplane11]    0x023a  2
- * @pci.depl_nph[vplane11]     0x023c  2
- * @pci.depl_ph[vplane11]      0x023e  2
- * @pci.depl_cplh[vplane12]    0x0242  2
- * @pci.depl_nph[vplane12]     0x0244  2
- * @pci.depl_ph[vplane12]      0x0246  2
- * @pci.depl_cplh[vplane13]    0x024a  2
- * @pci.depl_nph[vplane13]     0x024c  2
- * @pci.depl_ph[vplane13]      0x024e  2
- * @pci.depl_cplh[vplane14]    0x0252  2
- * @pci.depl_nph[vplane14]     0x0254  2
- * @pci.depl_ph[vplane14]      0x0256  2
- * @pci.depl_cplh[vplane15]    0x025a  2
- * @pci.depl_nph[vplane15]     0x025c  2
- * @pci.depl_ph[vplane15]      0x025e  2
- * @pci.depl_cplh[vplane16]    0x0262  2
- * @pci.depl_nph[vplane16]     0x0264  2
- * @pci.depl_ph[vplane16]      0x0266  2
- * @pci.depl_cpld[vplane0]     0x026a  2       Number of times completion data
- *  credits were depleted
- * @pci.depl_npd[vplane0]      0x026c  2       Number of times non posted data
- *  credits were depleted
- * @pci.depl_pd[vplane0]       0x026e  2       Number of times the posted data
- *  credits were depleted
- * @pci.depl_cpld[vplane1]     0x0272  2
- * @pci.depl_npd[vplane1]      0x0274  2
- * @pci.depl_pd[vplane1]       0x0276  2
- * @pci.depl_cpld[vplane2]     0x027a  2
- * @pci.depl_npd[vplane2]      0x027c  2
- * @pci.depl_pd[vplane2]       0x027e  2
- * @pci.depl_cpld[vplane3]     0x0282  2
- * @pci.depl_npd[vplane3]      0x0284  2
- * @pci.depl_pd[vplane3]       0x0286  2
- * @pci.depl_cpld[vplane4]     0x028a  2
- * @pci.depl_npd[vplane4]      0x028c  2
- * @pci.depl_pd[vplane4]       0x028e  2
- * @pci.depl_cpld[vplane5]     0x0292  2
- * @pci.depl_npd[vplane5]      0x0294  2
- * @pci.depl_pd[vplane5]       0x0296  2
- * @pci.depl_cpld[vplane6]     0x029a  2
- * @pci.depl_npd[vplane6]      0x029c  2
- * @pci.depl_pd[vplane6]       0x029e  2
- * @pci.depl_cpld[vplane7]     0x02a2  2
- * @pci.depl_npd[vplane7]      0x02a4  2
- * @pci.depl_pd[vplane7]       0x02a6  2
- * @pci.depl_cpld[vplane8]     0x02aa  2
- * @pci.depl_npd[vplane8]      0x02ac  2
- * @pci.depl_pd[vplane8]       0x02ae  2
- * @pci.depl_cpld[vplane9]     0x02b2  2
- * @pci.depl_npd[vplane9]      0x02b4  2
- * @pci.depl_pd[vplane9]       0x02b6  2
- * @pci.depl_cpld[vplane10]    0x02ba  2
- * @pci.depl_npd[vplane10]     0x02bc  2
- * @pci.depl_pd[vplane10]      0x02be  2
- * @pci.depl_cpld[vplane11]    0x02c2  2
- * @pci.depl_npd[vplane11]     0x02c4  2
- * @pci.depl_pd[vplane11]      0x02c6  2
- * @pci.depl_cpld[vplane12]    0x02ca  2
- * @pci.depl_npd[vplane12]     0x02cc  2
- * @pci.depl_pd[vplane12]      0x02ce  2
- * @pci.depl_cpld[vplane13]    0x02d2  2
- * @pci.depl_npd[vplane13]     0x02d4  2
- * @pci.depl_pd[vplane13]      0x02d6  2
- * @pci.depl_cpld[vplane14]    0x02da  2
- * @pci.depl_npd[vplane14]     0x02dc  2
- * @pci.depl_pd[vplane14]      0x02de  2
- * @pci.depl_cpld[vplane15]    0x02e2  2
- * @pci.depl_npd[vplane15]     0x02e4  2
- * @pci.depl_pd[vplane15]      0x02e6  2
- * @pci.depl_cpld[vplane16]    0x02ea  2
- * @pci.depl_npd[vplane16]     0x02ec  2
- * @pci.depl_pd[vplane16]      0x02ee  2
- * @xgmac_port[3];
- * @xgmac_aggr[2];
- * @xgmac.global_prog_event_gnum0      0x0ae0  8       Programmable statistic.
- *  Increments when internal logic detects a certain event. See register
- *  XMAC_STATS_GLOBAL_CFG.EVENT_GNUM0_CFG for more information.
- * @xgmac.global_prog_event_gnum1      0x0ae8  8       Programmable statistic.
- *  Increments when internal logic detects a certain event. See register
- *  XMAC_STATS_GLOBAL_CFG.EVENT_GNUM1_CFG for more information.
- * @xgmac.orp_lro_events       0x0af8  8
- * @xgmac.orp_bs_events        0x0b00  8
- * @xgmac.orp_iwarp_events     0x0b08  8
- * @xgmac.tx_permitted_frms    0x0b14  4
- * @xgmac.port2_tx_any_frms    0x0b1d  1
- * @xgmac.port1_tx_any_frms    0x0b1e  1
- * @xgmac.port0_tx_any_frms    0x0b1f  1
- * @xgmac.port2_rx_any_frms    0x0b25  1
- * @xgmac.port1_rx_any_frms    0x0b26  1
- * @xgmac.port0_rx_any_frms    0x0b27  1
- *
- * Titan mrpcim hardware statistics.
- */
-struct vxge_hw_device_stats_mrpcim_info {
-/*0x0000*/     u32     pic_ini_rd_drop;
-/*0x0004*/     u32     pic_ini_wr_drop;
-/*0x0008*/     struct {
-       /*0x0000*/      u32     pic_wrcrdtarb_ph_crdt_depleted;
-       /*0x0004*/      u32     unused1;
-               } pic_wrcrdtarb_ph_crdt_depleted_vplane[17];
-/*0x0090*/     struct {
-       /*0x0000*/      u32     pic_wrcrdtarb_pd_crdt_depleted;
-       /*0x0004*/      u32     unused2;
-               } pic_wrcrdtarb_pd_crdt_depleted_vplane[17];
-/*0x0118*/     struct {
-       /*0x0000*/      u32     pic_rdcrdtarb_nph_crdt_depleted;
-       /*0x0004*/      u32     unused3;
-               } pic_rdcrdtarb_nph_crdt_depleted_vplane[17];
-/*0x01a0*/     u32     pic_ini_rd_vpin_drop;
-/*0x01a4*/     u32     pic_ini_wr_vpin_drop;
-/*0x01a8*/     u32     pic_genstats_count0;
-/*0x01ac*/     u32     pic_genstats_count1;
-/*0x01b0*/     u32     pic_genstats_count2;
-/*0x01b4*/     u32     pic_genstats_count3;
-/*0x01b8*/     u32     pic_genstats_count4;
-/*0x01bc*/     u32     unused4;
-/*0x01c0*/     u32     pic_genstats_count5;
-/*0x01c4*/     u32     unused5;
-/*0x01c8*/     u32     pci_rstdrop_cpl;
-/*0x01cc*/     u32     pci_rstdrop_msg;
-/*0x01d0*/     u32     pci_rstdrop_client1;
-/*0x01d4*/     u32     pci_rstdrop_client0;
-/*0x01d8*/     u32     pci_rstdrop_client2;
-/*0x01dc*/     u32     unused6;
-/*0x01e0*/     struct {
-       /*0x0000*/      u16     unused7;
-       /*0x0002*/      u16     pci_depl_cplh;
-       /*0x0004*/      u16     pci_depl_nph;
-       /*0x0006*/      u16     pci_depl_ph;
-               } pci_depl_h_vplane[17];
-/*0x0268*/     struct {
-       /*0x0000*/      u16     unused8;
-       /*0x0002*/      u16     pci_depl_cpld;
-       /*0x0004*/      u16     pci_depl_npd;
-       /*0x0006*/      u16     pci_depl_pd;
-               } pci_depl_d_vplane[17];
-/*0x02f0*/     struct vxge_hw_xmac_port_stats xgmac_port[3];
-/*0x0a10*/     struct vxge_hw_xmac_aggr_stats xgmac_aggr[2];
-/*0x0ae0*/     u64     xgmac_global_prog_event_gnum0;
-/*0x0ae8*/     u64     xgmac_global_prog_event_gnum1;
-/*0x0af0*/     u64     unused7;
-/*0x0af8*/     u64     unused8;
-/*0x0b00*/     u64     unused9;
-/*0x0b08*/     u64     unused10;
-/*0x0b10*/     u32     unused11;
-/*0x0b14*/     u32     xgmac_tx_permitted_frms;
-/*0x0b18*/     u32     unused12;
-/*0x0b1c*/     u8      unused13;
-/*0x0b1d*/     u8      xgmac_port2_tx_any_frms;
-/*0x0b1e*/     u8      xgmac_port1_tx_any_frms;
-/*0x0b1f*/     u8      xgmac_port0_tx_any_frms;
-/*0x0b20*/     u32     unused14;
-/*0x0b24*/     u8      unused15;
-/*0x0b25*/     u8      xgmac_port2_rx_any_frms;
-/*0x0b26*/     u8      xgmac_port1_rx_any_frms;
-/*0x0b27*/     u8      xgmac_port0_rx_any_frms;
-} __packed;
-
-/**
- * struct vxge_hw_device_stats_hw_info - Titan hardware statistics.
- * @vpath_info: VPath statistics
- * @vpath_info_sav: Vpath statistics saved
- *
- * Titan hardware statistics.
- */
-struct vxge_hw_device_stats_hw_info {
-       struct vxge_hw_vpath_stats_hw_info
-               *vpath_info[VXGE_HW_MAX_VIRTUAL_PATHS];
-       struct vxge_hw_vpath_stats_hw_info
-               vpath_info_sav[VXGE_HW_MAX_VIRTUAL_PATHS];
-};
-
-/**
- * struct vxge_hw_vpath_stats_sw_common_info - HW common
- * statistics for queues.
- * @full_cnt: Number of times the queue was full
- * @usage_cnt: usage count.
- * @usage_max: Maximum usage
- * @reserve_free_swaps_cnt: Reserve/free swap counter. Internal usage.
- * @total_compl_cnt: Total descriptor completion count.
- *
- * Hw queue counters
- * See also: struct vxge_hw_vpath_stats_sw_fifo_info{},
- * struct vxge_hw_vpath_stats_sw_ring_info{},
- */
-struct vxge_hw_vpath_stats_sw_common_info {
-       u32     full_cnt;
-       u32     usage_cnt;
-       u32     usage_max;
-       u32     reserve_free_swaps_cnt;
-       u32 total_compl_cnt;
-};
-
-/**
- * struct vxge_hw_vpath_stats_sw_fifo_info - HW fifo statistics
- * @common_stats: Common counters for all queues
- * @total_posts: Total number of postings on the queue.
- * @total_buffers: Total number of buffers posted.
- * @txd_t_code_err_cnt: Array of transmit transfer codes. The position
- * (index) in this array reflects the transfer code type, for instance
- * 0xA - "loss of link".
- * Value txd_t_code_err_cnt[i] reflects the
- * number of times the corresponding transfer code was encountered.
- *
- * HW fifo counters
- * See also: struct vxge_hw_vpath_stats_sw_common_info{},
- * struct vxge_hw_vpath_stats_sw_ring_info{},
- */
-struct vxge_hw_vpath_stats_sw_fifo_info {
-       struct vxge_hw_vpath_stats_sw_common_info common_stats;
-       u32 total_posts;
-       u32 total_buffers;
-       u32 txd_t_code_err_cnt[VXGE_HW_DTR_MAX_T_CODE];
-};
-
-/**
- * struct vxge_hw_vpath_stats_sw_ring_info - HW ring statistics
- * @common_stats: Common counters for all queues
- * @rxd_t_code_err_cnt: Array of receive transfer codes. The position
- *             (index) in this array reflects the transfer code type,
- *             for instance
- *             0x7 - for "invalid receive buffer size", or 0x8 - for ECC.
- *             Value rxd_t_code_err_cnt[i] reflects the
- *             number of times the corresponding transfer code was encountered.
- *
- * HW ring counters
- * See also: struct vxge_hw_vpath_stats_sw_common_info{},
- * struct vxge_hw_vpath_stats_sw_fifo_info{},
- */
-struct vxge_hw_vpath_stats_sw_ring_info {
-       struct vxge_hw_vpath_stats_sw_common_info common_stats;
-       u32 rxd_t_code_err_cnt[VXGE_HW_DTR_MAX_T_CODE];
-
-};
-
-/**
- * struct vxge_hw_vpath_stats_sw_err - HW vpath error statistics
- * @unknown_alarms:
- * @network_sustained_fault:
- * @network_sustained_ok:
- * @kdfcctl_fifo0_overwrite:
- * @kdfcctl_fifo0_poison:
- * @kdfcctl_fifo0_dma_error:
- * @dblgen_fifo0_overflow:
- * @statsb_pif_chain_error:
- * @statsb_drop_timeout:
- * @target_illegal_access:
- * @ini_serr_det:
- * @prc_ring_bumps:
- * @prc_rxdcm_sc_err:
- * @prc_rxdcm_sc_abort:
- * @prc_quanta_size_err:
- *
- * HW vpath error statistics
- */
-struct vxge_hw_vpath_stats_sw_err {
-       u32     unknown_alarms;
-       u32     network_sustained_fault;
-       u32     network_sustained_ok;
-       u32     kdfcctl_fifo0_overwrite;
-       u32     kdfcctl_fifo0_poison;
-       u32     kdfcctl_fifo0_dma_error;
-       u32     dblgen_fifo0_overflow;
-       u32     statsb_pif_chain_error;
-       u32     statsb_drop_timeout;
-       u32     target_illegal_access;
-       u32     ini_serr_det;
-       u32     prc_ring_bumps;
-       u32     prc_rxdcm_sc_err;
-       u32     prc_rxdcm_sc_abort;
-       u32     prc_quanta_size_err;
-};
-
-/**
- * struct vxge_hw_vpath_stats_sw_info - HW vpath sw statistics
- * @soft_reset_cnt: Number of times soft reset is done on this vpath.
- * @error_stats: error counters for the vpath
- * @ring_stats: counters for ring belonging to the vpath
- * @fifo_stats: counters for fifo belonging to the vpath
- *
- * HW vpath sw statistics
- * See also: struct vxge_hw_device_info{} }.
- */
-struct vxge_hw_vpath_stats_sw_info {
-       u32    soft_reset_cnt;
-       struct vxge_hw_vpath_stats_sw_err       error_stats;
-       struct vxge_hw_vpath_stats_sw_ring_info ring_stats;
-       struct vxge_hw_vpath_stats_sw_fifo_info fifo_stats;
-};
-
-/**
- * struct vxge_hw_device_stats_sw_info - HW own per-device statistics.
- *
- * @not_traffic_intr_cnt: Number of times the host was interrupted
- *                        without new completions.
- *                        "Non-traffic interrupt counter".
- * @traffic_intr_cnt: Number of traffic interrupts for the device.
- * @total_intr_cnt: Total number of traffic interrupts for the device.
- *                  @total_intr_cnt == @traffic_intr_cnt +
- *                              @not_traffic_intr_cnt
- * @soft_reset_cnt: Number of times soft reset is done on this device.
- * @vpath_info: please see struct vxge_hw_vpath_stats_sw_info{}
- * HW per-device statistics.
- */
-struct vxge_hw_device_stats_sw_info {
-       u32     not_traffic_intr_cnt;
-       u32     traffic_intr_cnt;
-       u32     total_intr_cnt;
-       u32     soft_reset_cnt;
-       struct vxge_hw_vpath_stats_sw_info
-               vpath_info[VXGE_HW_MAX_VIRTUAL_PATHS];
-};
-
-/**
- * struct vxge_hw_device_stats_sw_err - HW device error statistics.
- * @vpath_alarms: Number of vpath alarms
- *
- * HW Device error stats
- */
-struct vxge_hw_device_stats_sw_err {
-       u32     vpath_alarms;
-};
-
-/**
- * struct vxge_hw_device_stats - Contains HW per-device statistics,
- * including hw.
- * @devh: HW device handle.
- * @dma_addr: DMA address of the %hw_info. Given to device to fill-in the stats.
- * @hw_info_dmah: DMA handle used to map hw statistics onto the device memory
- *                space.
- * @hw_info_dma_acch: One more DMA handle used subsequently to free the
- *                    DMA object. Note that this and the previous handle have
- *                    physical meaning for Solaris; on Windows and Linux the
- *                    corresponding value will be simply pointer to PCI device.
- *
- * @hw_dev_info_stats: Titan statistics maintained by the hardware.
- * @sw_dev_info_stats: HW's "soft" device informational statistics, e.g. number
- *                     of completions per interrupt.
- * @sw_dev_err_stats: HW's "soft" device error statistics.
- *
- * Structure-container of HW per-device statistics. Note that per-channel
- * statistics are kept in separate structures under HW's fifo and ring
- * channels.
- */
-struct vxge_hw_device_stats {
-       /* handles */
-       struct __vxge_hw_device *devh;
-
-       /* HW device hardware statistics */
-       struct vxge_hw_device_stats_hw_info     hw_dev_info_stats;
-
-       /* HW device "soft" stats */
-       struct vxge_hw_device_stats_sw_err   sw_dev_err_stats;
-       struct vxge_hw_device_stats_sw_info  sw_dev_info_stats;
-
-};
-
-enum vxge_hw_status vxge_hw_device_hw_stats_enable(
-                       struct __vxge_hw_device *devh);
-
-enum vxge_hw_status vxge_hw_device_stats_get(
-                       struct __vxge_hw_device *devh,
-                       struct vxge_hw_device_stats_hw_info *hw_stats);
-
-enum vxge_hw_status vxge_hw_driver_stats_get(
-                       struct __vxge_hw_device *devh,
-                       struct vxge_hw_device_stats_sw_info *sw_stats);
-
-enum vxge_hw_status vxge_hw_mrpcim_stats_enable(struct __vxge_hw_device *devh);
-
-enum vxge_hw_status vxge_hw_mrpcim_stats_disable(struct __vxge_hw_device *devh);
-
-enum vxge_hw_status
-vxge_hw_mrpcim_stats_access(
-       struct __vxge_hw_device *devh,
-       u32 operation,
-       u32 location,
-       u32 offset,
-       u64 *stat);
-
-enum vxge_hw_status
-vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *devh,
-                             struct vxge_hw_xmac_stats *xmac_stats);
-
-/**
- * enum enum vxge_hw_mgmt_reg_type - Register types.
- *
- * @vxge_hw_mgmt_reg_type_legacy: Legacy registers
- * @vxge_hw_mgmt_reg_type_toc: TOC Registers
- * @vxge_hw_mgmt_reg_type_common: Common Registers
- * @vxge_hw_mgmt_reg_type_mrpcim: mrpcim registers
- * @vxge_hw_mgmt_reg_type_srpcim: srpcim registers
- * @vxge_hw_mgmt_reg_type_vpmgmt: vpath management registers
- * @vxge_hw_mgmt_reg_type_vpath: vpath registers
- *
- * Register type enumaration
- */
-enum vxge_hw_mgmt_reg_type {
-       vxge_hw_mgmt_reg_type_legacy = 0,
-       vxge_hw_mgmt_reg_type_toc = 1,
-       vxge_hw_mgmt_reg_type_common = 2,
-       vxge_hw_mgmt_reg_type_mrpcim = 3,
-       vxge_hw_mgmt_reg_type_srpcim = 4,
-       vxge_hw_mgmt_reg_type_vpmgmt = 5,
-       vxge_hw_mgmt_reg_type_vpath = 6
-};
-
-enum vxge_hw_status
-vxge_hw_mgmt_reg_read(struct __vxge_hw_device *devh,
-                     enum vxge_hw_mgmt_reg_type type,
-                     u32 index,
-                     u32 offset,
-                     u64 *value);
-
-enum vxge_hw_status
-vxge_hw_mgmt_reg_write(struct __vxge_hw_device *devh,
-                     enum vxge_hw_mgmt_reg_type type,
-                     u32 index,
-                     u32 offset,
-                     u64 value);
-
-/**
- * enum enum vxge_hw_rxd_state - Descriptor (RXD) state.
- * @VXGE_HW_RXD_STATE_NONE: Invalid state.
- * @VXGE_HW_RXD_STATE_AVAIL: Descriptor is available for reservation.
- * @VXGE_HW_RXD_STATE_POSTED: Descriptor is posted for processing by the
- * device.
- * @VXGE_HW_RXD_STATE_FREED: Descriptor is free and can be reused for
- * filling-in and posting later.
- *
- * Titan/HW descriptor states.
- *
- */
-enum vxge_hw_rxd_state {
-       VXGE_HW_RXD_STATE_NONE          = 0,
-       VXGE_HW_RXD_STATE_AVAIL         = 1,
-       VXGE_HW_RXD_STATE_POSTED        = 2,
-       VXGE_HW_RXD_STATE_FREED         = 3
-};
-
-/**
- * struct vxge_hw_ring_rxd_info - Extended information associated with a
- * completed ring descriptor.
- * @syn_flag: SYN flag
- * @is_icmp: Is ICMP
- * @fast_path_eligible: Fast Path Eligible flag
- * @l3_cksum: in L3 checksum is valid
- * @l3_cksum: Result of IP checksum check (by Titan hardware).
- *            This field containing VXGE_HW_L3_CKSUM_OK would mean that
- *            the checksum is correct, otherwise - the datagram is
- *            corrupted.
- * @l4_cksum: in L4 checksum is valid
- * @l4_cksum: Result of TCP/UDP checksum check (by Titan hardware).
- *            This field containing VXGE_HW_L4_CKSUM_OK would mean that
- *            the checksum is correct. Otherwise - the packet is
- *            corrupted.
- * @frame: Zero or more of enum vxge_hw_frame_type flags.
- *             See enum vxge_hw_frame_type{}.
- * @proto: zero or more of enum vxge_hw_frame_proto flags.  Reporting bits for
- *            various higher-layer protocols, including (but note restricted to)
- *            TCP and UDP. See enum vxge_hw_frame_proto{}.
- * @is_vlan: If vlan tag is valid
- * @vlan: VLAN tag extracted from the received frame.
- * @rth_bucket: RTH bucket
- * @rth_it_hit: Set, If RTH hash value calculated by the Titan hardware
- *             has a matching entry in the Indirection table.
- * @rth_spdm_hit: Set, If RTH hash value calculated by the Titan hardware
- *             has a matching entry in the Socket Pair Direct Match table.
- * @rth_hash_type: RTH hash code of the function used to calculate the hash.
- * @rth_value: Receive Traffic Hashing(RTH) hash value. Produced by Titan
- *             hardware if RTH is enabled.
- */
-struct vxge_hw_ring_rxd_info {
-       u32     syn_flag;
-       u32     is_icmp;
-       u32     fast_path_eligible;
-       u32     l3_cksum_valid;
-       u32     l3_cksum;
-       u32     l4_cksum_valid;
-       u32     l4_cksum;
-       u32     frame;
-       u32     proto;
-       u32     is_vlan;
-       u32     vlan;
-       u32     rth_bucket;
-       u32     rth_it_hit;
-       u32     rth_spdm_hit;
-       u32     rth_hash_type;
-       u32     rth_value;
-};
-/**
- * enum vxge_hw_ring_tcode - Transfer codes returned by adapter
- * @VXGE_HW_RING_T_CODE_OK: Transfer ok.
- * @VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH: Layer 3 checksum presentation
- *             configuration mismatch.
- * @VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH: Layer 4 checksum presentation
- *             configuration mismatch.
- * @VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH: Layer 3 and Layer 4 checksum
- *             presentation configuration mismatch.
- * @VXGE_HW_RING_T_CODE_L3_PKT_ERR: Layer 3 error unparseable packet,
- *             such as unknown IPv6 header.
- * @VXGE_HW_RING_T_CODE_L2_FRM_ERR: Layer 2 error frame integrity
- *             error, such as FCS or ECC).
- * @VXGE_HW_RING_T_CODE_BUF_SIZE_ERR: Buffer size error the RxD buffer(
- *             s) were not appropriately sized and data loss occurred.
- * @VXGE_HW_RING_T_CODE_INT_ECC_ERR: Internal ECC error RxD corrupted.
- * @VXGE_HW_RING_T_CODE_BENIGN_OVFLOW: Benign overflow the contents of
- *             Segment1 exceeded the capacity of Buffer1 and the remainder
- *             was placed in Buffer2. Segment2 now starts in Buffer3.
- *             No data loss or errors occurred.
- * @VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF: Buffer size 0 one of the RxDs
- *             assigned buffers has a size of 0 bytes.
- * @VXGE_HW_RING_T_CODE_FRM_DROP: Frame dropped either due to
- *             VPath Reset or because of a VPIN mismatch.
- * @VXGE_HW_RING_T_CODE_UNUSED: Unused
- * @VXGE_HW_RING_T_CODE_MULTI_ERR: Multiple errors more than one
- *             transfer code condition occurred.
- *
- * Transfer codes returned by adapter.
- */
-enum vxge_hw_ring_tcode {
-       VXGE_HW_RING_T_CODE_OK                          = 0x0,
-       VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH           = 0x1,
-       VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH           = 0x2,
-       VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH        = 0x3,
-       VXGE_HW_RING_T_CODE_L3_PKT_ERR                  = 0x5,
-       VXGE_HW_RING_T_CODE_L2_FRM_ERR                  = 0x6,
-       VXGE_HW_RING_T_CODE_BUF_SIZE_ERR                = 0x7,
-       VXGE_HW_RING_T_CODE_INT_ECC_ERR                 = 0x8,
-       VXGE_HW_RING_T_CODE_BENIGN_OVFLOW               = 0x9,
-       VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF               = 0xA,
-       VXGE_HW_RING_T_CODE_FRM_DROP                    = 0xC,
-       VXGE_HW_RING_T_CODE_UNUSED                      = 0xE,
-       VXGE_HW_RING_T_CODE_MULTI_ERR                   = 0xF
-};
-
-enum vxge_hw_status vxge_hw_ring_rxd_reserve(
-       struct __vxge_hw_ring *ring_handle,
-       void **rxdh);
-
-void
-vxge_hw_ring_rxd_pre_post(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh);
-
-void
-vxge_hw_ring_rxd_post_post(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh);
-
-void
-vxge_hw_ring_rxd_post_post_wmb(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh);
-
-void vxge_hw_ring_rxd_post(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh);
-
-enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
-       struct __vxge_hw_ring *ring_handle,
-       void **rxdh,
-       u8 *t_code);
-
-enum vxge_hw_status vxge_hw_ring_handle_tcode(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh,
-       u8 t_code);
-
-void vxge_hw_ring_rxd_free(
-       struct __vxge_hw_ring *ring_handle,
-       void *rxdh);
-
-/**
- * enum enum vxge_hw_frame_proto - Higher-layer ethernet protocols.
- * @VXGE_HW_FRAME_PROTO_VLAN_TAGGED: VLAN.
- * @VXGE_HW_FRAME_PROTO_IPV4: IPv4.
- * @VXGE_HW_FRAME_PROTO_IPV6: IPv6.
- * @VXGE_HW_FRAME_PROTO_IP_FRAG: IP fragmented.
- * @VXGE_HW_FRAME_PROTO_TCP: TCP.
- * @VXGE_HW_FRAME_PROTO_UDP: UDP.
- * @VXGE_HW_FRAME_PROTO_TCP_OR_UDP: TCP or UDP.
- *
- * Higher layer ethernet protocols and options.
- */
-enum vxge_hw_frame_proto {
-       VXGE_HW_FRAME_PROTO_VLAN_TAGGED = 0x80,
-       VXGE_HW_FRAME_PROTO_IPV4                = 0x10,
-       VXGE_HW_FRAME_PROTO_IPV6                = 0x08,
-       VXGE_HW_FRAME_PROTO_IP_FRAG             = 0x04,
-       VXGE_HW_FRAME_PROTO_TCP                 = 0x02,
-       VXGE_HW_FRAME_PROTO_UDP                 = 0x01,
-       VXGE_HW_FRAME_PROTO_TCP_OR_UDP  = (VXGE_HW_FRAME_PROTO_TCP | \
-                                                  VXGE_HW_FRAME_PROTO_UDP)
-};
-
-/**
- * enum enum vxge_hw_fifo_gather_code - Gather codes used in fifo TxD
- * @VXGE_HW_FIFO_GATHER_CODE_FIRST: First TxDL
- * @VXGE_HW_FIFO_GATHER_CODE_MIDDLE: Middle TxDL
- * @VXGE_HW_FIFO_GATHER_CODE_LAST: Last TxDL
- * @VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST: First and Last TxDL.
- *
- * These gather codes are used to indicate the position of a TxD in a TxD list
- */
-enum vxge_hw_fifo_gather_code {
-       VXGE_HW_FIFO_GATHER_CODE_FIRST          = 0x2,
-       VXGE_HW_FIFO_GATHER_CODE_MIDDLE         = 0x0,
-       VXGE_HW_FIFO_GATHER_CODE_LAST           = 0x1,
-       VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST     = 0x3
-};
-
-/**
- * enum enum vxge_hw_fifo_tcode - tcodes used in fifo
- * @VXGE_HW_FIFO_T_CODE_OK: Transfer OK
- * @VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT: PCI read transaction (either TxD or
- *             frame data) returned with corrupt data.
- * @VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL:PCI read transaction was returned
- *             with no data.
- * @VXGE_HW_FIFO_T_CODE_INVALID_MSS: The host attempted to send either a
- *             frame or LSO MSS that was too long (>9800B).
- * @VXGE_HW_FIFO_T_CODE_LSO_ERROR: Error detected during TCP/UDP Large Send
-       *              Offload operation, due to improper header template,
-       *              unsupported protocol, etc.
- * @VXGE_HW_FIFO_T_CODE_UNUSED: Unused
- * @VXGE_HW_FIFO_T_CODE_MULTI_ERROR: Set to 1 by the adapter if multiple
- *             data buffer transfer errors are encountered (see below).
- *             Otherwise it is set to 0.
- *
- * These tcodes are returned in various API for TxD status
- */
-enum vxge_hw_fifo_tcode {
-       VXGE_HW_FIFO_T_CODE_OK                  = 0x0,
-       VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT    = 0x1,
-       VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL       = 0x2,
-       VXGE_HW_FIFO_T_CODE_INVALID_MSS         = 0x3,
-       VXGE_HW_FIFO_T_CODE_LSO_ERROR           = 0x4,
-       VXGE_HW_FIFO_T_CODE_UNUSED              = 0x7,
-       VXGE_HW_FIFO_T_CODE_MULTI_ERROR         = 0x8
-};
-
-enum vxge_hw_status vxge_hw_fifo_txdl_reserve(
-       struct __vxge_hw_fifo *fifoh,
-       void **txdlh,
-       void **txdl_priv);
-
-void vxge_hw_fifo_txdl_buffer_set(
-                       struct __vxge_hw_fifo *fifo_handle,
-                       void *txdlh,
-                       u32 frag_idx,
-                       dma_addr_t dma_pointer,
-                       u32 size);
-
-void vxge_hw_fifo_txdl_post(
-                       struct __vxge_hw_fifo *fifo_handle,
-                       void *txdlh);
-
-u32 vxge_hw_fifo_free_txdl_count_get(
-                       struct __vxge_hw_fifo *fifo_handle);
-
-enum vxge_hw_status vxge_hw_fifo_txdl_next_completed(
-       struct __vxge_hw_fifo *fifoh,
-       void **txdlh,
-       enum vxge_hw_fifo_tcode *t_code);
-
-enum vxge_hw_status vxge_hw_fifo_handle_tcode(
-       struct __vxge_hw_fifo *fifoh,
-       void *txdlh,
-       enum vxge_hw_fifo_tcode t_code);
-
-void vxge_hw_fifo_txdl_free(
-       struct __vxge_hw_fifo *fifoh,
-       void *txdlh);
-
-/*
- * Device
- */
-
-#define VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET (VXGE_HW_BLOCK_SIZE-8)
-#define VXGE_HW_RING_MEMBLOCK_IDX_OFFSET               (VXGE_HW_BLOCK_SIZE-16)
-
-/*
- * struct __vxge_hw_ring_rxd_priv - Receive descriptor HW-private data.
- * @dma_addr: DMA (mapped) address of _this_ descriptor.
- * @dma_handle: DMA handle used to map the descriptor onto device.
- * @dma_offset: Descriptor's offset in the memory block. HW allocates
- *              descriptors in memory blocks of %VXGE_HW_BLOCK_SIZE
- *              bytes. Each memblock is contiguous DMA-able memory. Each
- *              memblock contains 1 or more 4KB RxD blocks visible to the
- *              Titan hardware.
- * @dma_object: DMA address and handle of the memory block that contains
- *              the descriptor. This member is used only in the "checked"
- *              version of the HW (to enforce certain assertions);
- *              otherwise it gets compiled out.
- * @allocated: True if the descriptor is reserved, 0 otherwise. Internal usage.
- *
- * Per-receive decsriptor HW-private data. HW uses the space to keep DMA
- * information associated with the descriptor. Note that driver can ask HW
- * to allocate additional per-descriptor space for its own (driver-specific)
- * purposes.
- */
-struct __vxge_hw_ring_rxd_priv {
-       dma_addr_t      dma_addr;
-       struct pci_dev *dma_handle;
-       ptrdiff_t       dma_offset;
-#ifdef VXGE_DEBUG_ASSERT
-       struct vxge_hw_mempool_dma      *dma_object;
-#endif
-};
-
-struct vxge_hw_mempool_cbs {
-       void (*item_func_alloc)(
-                       struct vxge_hw_mempool *mempoolh,
-                       u32                     memblock_index,
-                       struct vxge_hw_mempool_dma      *dma_object,
-                       u32                     index,
-                       u32                     is_last);
-};
-
-#define VXGE_HW_VIRTUAL_PATH_HANDLE(vpath)                             \
-               ((struct __vxge_hw_vpath_handle *)(vpath)->vpath_handles.next)
-
-enum vxge_hw_status
-__vxge_hw_vpath_rts_table_get(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u32                     action,
-       u32                     rts_table,
-       u32                     offset,
-       u64                     *data1,
-       u64                     *data2);
-
-enum vxge_hw_status
-__vxge_hw_vpath_rts_table_set(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u32                     action,
-       u32                     rts_table,
-       u32                     offset,
-       u64                     data1,
-       u64                     data2);
-
-enum vxge_hw_status
-__vxge_hw_vpath_enable(
-       struct __vxge_hw_device *devh,
-       u32                     vp_id);
-
-void vxge_hw_device_intr_enable(
-       struct __vxge_hw_device *devh);
-
-u32 vxge_hw_device_set_intr_type(struct __vxge_hw_device *devh, u32 intr_mode);
-
-void vxge_hw_device_intr_disable(
-       struct __vxge_hw_device *devh);
-
-void vxge_hw_device_mask_all(
-       struct __vxge_hw_device *devh);
-
-void vxge_hw_device_unmask_all(
-       struct __vxge_hw_device *devh);
-
-enum vxge_hw_status vxge_hw_device_begin_irq(
-       struct __vxge_hw_device *devh,
-       u32 skip_alarms,
-       u64 *reason);
-
-void vxge_hw_device_clear_tx_rx(
-       struct __vxge_hw_device *devh);
-
-/*
- *  Virtual Paths
- */
-
-void vxge_hw_vpath_dynamic_rti_rtimer_set(struct __vxge_hw_ring *ring);
-
-void vxge_hw_vpath_dynamic_tti_rtimer_set(struct __vxge_hw_fifo *fifo);
-
-u32 vxge_hw_vpath_id(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_vpath_mac_addr_add_mode {
-       VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE = 0,
-       VXGE_HW_VPATH_MAC_ADDR_DISCARD_DUPLICATE = 1,
-       VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE = 2
-};
-
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_add(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u8 *macaddr,
-       u8 *macaddr_mask,
-       enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode);
-
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_get(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u8 *macaddr,
-       u8 *macaddr_mask);
-
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_get_next(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u8 *macaddr,
-       u8 *macaddr_mask);
-
-enum vxge_hw_status
-vxge_hw_vpath_mac_addr_delete(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u8 *macaddr,
-       u8 *macaddr_mask);
-
-enum vxge_hw_status
-vxge_hw_vpath_vid_add(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u64                     vid);
-
-enum vxge_hw_status
-vxge_hw_vpath_vid_delete(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u64                     vid);
-
-enum vxge_hw_status
-vxge_hw_vpath_etype_add(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u64                     etype);
-
-enum vxge_hw_status
-vxge_hw_vpath_etype_get(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u64                     *etype);
-
-enum vxge_hw_status
-vxge_hw_vpath_etype_get_next(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u64                     *etype);
-
-enum vxge_hw_status
-vxge_hw_vpath_etype_delete(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u64                     etype);
-
-enum vxge_hw_status vxge_hw_vpath_promisc_enable(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_promisc_disable(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_bcast_enable(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_mcast_enable(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_mcast_disable(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_poll_rx(
-       struct __vxge_hw_ring *ringh);
-
-enum vxge_hw_status vxge_hw_vpath_poll_tx(
-       struct __vxge_hw_fifo *fifoh,
-       struct sk_buff ***skb_ptr, int nr_skb, int *more);
-
-enum vxge_hw_status vxge_hw_vpath_alarm_process(
-       struct __vxge_hw_vpath_handle *vpath_handle,
-       u32 skip_alarms);
-
-void
-vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vpath_handle,
-                      int *tim_msix_id, int alarm_msix_id);
-
-void
-vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vpath_handle,
-                       int msix_id);
-
-void vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id);
-
-void vxge_hw_device_flush_io(struct __vxge_hw_device *devh);
-
-void
-vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vpath_handle,
-                         int msix_id);
-
-enum vxge_hw_status vxge_hw_vpath_intr_enable(
-                               struct __vxge_hw_vpath_handle *vpath_handle);
-
-enum vxge_hw_status vxge_hw_vpath_intr_disable(
-                               struct __vxge_hw_vpath_handle *vpath_handle);
-
-void vxge_hw_vpath_inta_mask_tx_rx(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-void vxge_hw_vpath_inta_unmask_tx_rx(
-       struct __vxge_hw_vpath_handle *vpath_handle);
-
-void
-vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channelh, int msix_id);
-
-void
-vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channelh, int msix_id);
-
-void
-vxge_hw_channel_msix_clear(struct __vxge_hw_channel *channelh, int msix_id);
-
-void
-vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel,
-                                void **dtrh);
-
-void
-vxge_hw_channel_dtr_complete(struct __vxge_hw_channel *channel);
-
-void
-vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh);
-
-int
-vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel);
-
-void vxge_hw_vpath_tti_ci_set(struct __vxge_hw_fifo *fifo);
-
-void vxge_hw_vpath_dynamic_rti_ci_set(struct __vxge_hw_ring *ring);
-
-#endif
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-version.h b/drivers/net/ethernet/neterion/vxge/vxge-version.h
deleted file mode 100644 (file)
index b9efa28..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/******************************************************************************
- * 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 code fall under the GPL and must
- * retain the authorship, copyright and license notice.  This file is not
- * a complete program and may only be used when the entire operating
- * system is licensed under the GPL.
- * See the file COPYING in this distribution for more information.
- *
- * vxge-version.h: Driver for Exar Corp's X3100 Series 10GbE PCIe I/O
- *                 Virtualized Server Adapter.
- * Copyright(c) 2002-2010 Exar Corp.
- ******************************************************************************/
-#ifndef VXGE_VERSION_H
-#define VXGE_VERSION_H
-
-#define VXGE_VERSION_MAJOR     "2"
-#define VXGE_VERSION_MINOR     "5"
-#define VXGE_VERSION_FIX       "3"
-#define VXGE_VERSION_BUILD     "22640"
-#define VXGE_VERSION_FOR       "k"
-
-#define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld))
-
-#define VXGE_DEAD_FW_VER_MAJOR 1
-#define VXGE_DEAD_FW_VER_MINOR 4
-#define VXGE_DEAD_FW_VER_BUILD 4
-
-#define VXGE_FW_DEAD_VER VXGE_FW_VER(VXGE_DEAD_FW_VER_MAJOR, \
-                                    VXGE_DEAD_FW_VER_MINOR, \
-                                    VXGE_DEAD_FW_VER_BUILD)
-
-#define VXGE_EPROM_FW_VER_MAJOR        1
-#define VXGE_EPROM_FW_VER_MINOR        6
-#define VXGE_EPROM_FW_VER_BUILD        1
-
-#define VXGE_EPROM_FW_VER VXGE_FW_VER(VXGE_EPROM_FW_VER_MAJOR, \
-                                     VXGE_EPROM_FW_VER_MINOR, \
-                                     VXGE_EPROM_FW_VER_BUILD)
-
-#define VXGE_CERT_FW_VER_MAJOR 1
-#define VXGE_CERT_FW_VER_MINOR 8
-#define VXGE_CERT_FW_VER_BUILD 1
-
-#define VXGE_CERT_FW_VER VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, \
-                                    VXGE_CERT_FW_VER_MINOR, \
-                                    VXGE_CERT_FW_VER_BUILD)
-
-#endif
index 0147de4..7453cc5 100644 (file)
@@ -149,7 +149,7 @@ nfp_fl_pre_lag(struct nfp_app *app, const struct flow_action_entry *act,
        }
 
        /* Pre_lag action must be first on action list.
-        * If other actions already exist they need pushed forward.
+        * If other actions already exist they need to be pushed forward.
         */
        if (act_len)
                memmove(nfp_flow->action_data + act_size,
@@ -674,9 +674,9 @@ nfp_fl_set_ip6_hop_limit_flow_label(u32 off, __be32 exact, __be32 mask,
                                            fl_hl_mask->hop_limit;
                break;
        case round_down(offsetof(struct ipv6hdr, flow_lbl), 4):
-               if (mask & ~IPV6_FLOW_LABEL_MASK ||
-                   exact & ~IPV6_FLOW_LABEL_MASK) {
-                       NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 flow label action");
+               if (mask & ~IPV6_FLOWINFO_MASK ||
+                   exact & ~IPV6_FLOWINFO_MASK) {
+                       NL_SET_ERR_MSG_MOD(extack, "unsupported offload: invalid pedit IPv6 flow info action");
                        return -EOPNOTSUPP;
                }
 
index 68e8a2f..2df2af1 100644 (file)
@@ -96,8 +96,6 @@
 #define NFP_FL_PUSH_VLAN_PRIO          GENMASK(15, 13)
 #define NFP_FL_PUSH_VLAN_VID           GENMASK(11, 0)
 
-#define IPV6_FLOW_LABEL_MASK           cpu_to_be32(0x000fffff)
-
 /* LAG ports */
 #define NFP_FL_LAG_OUT                 0xC0DE0000
 
index 7c31a46..b3b2a23 100644 (file)
@@ -182,7 +182,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
        u8 ip_proto = 0;
        /* Temporary buffer for mangling keys, 64 is enough to cover max
         * struct size of key in various fields that may be mangled.
-        * Supported fileds to mangle:
+        * Supported fields to mangle:
         * mac_src/mac_dst(struct flow_match_eth_addrs, 12B)
         * nw_tos/nw_ttl(struct flow_match_ip, 2B)
         * nw_src/nw_dst(struct flow_match_ipv4/6_addrs, 32B)
@@ -194,7 +194,7 @@ static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
            entry1->netdev != entry2->netdev)
                return -EINVAL;
 
-       /* check the overlapped fields one by one, the unmasked part
+       /* Check the overlapped fields one by one, the unmasked part
         * should not conflict with each other.
         */
        if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) {
@@ -563,7 +563,7 @@ static int nfp_fl_merge_actions_offload(struct flow_rule **rules,
                if (flow_rule_match_key(rules[j], FLOW_DISSECTOR_KEY_BASIC)) {
                        struct flow_match_basic match;
 
-                       /* ip_proto is the only field that needed in later compile_action,
+                       /* ip_proto is the only field that is needed in later compile_action,
                         * needed to set the correct checksum flags. It doesn't really matter
                         * which input rule's ip_proto field we take as the earlier merge checks
                         * would have made sure that they don't conflict. We do not know which
@@ -1013,7 +1013,7 @@ static int nfp_ct_do_nft_merge(struct nfp_fl_ct_zone_entry *zt,
        nft_m_entry->tc_m_parent = tc_m_entry;
        nft_m_entry->nft_parent = nft_entry;
        nft_m_entry->tc_flower_cookie = 0;
-       /* Copy the netdev from one the pre_ct entry. When the tc_m_entry was created
+       /* Copy the netdev from the pre_ct entry. When the tc_m_entry was created
         * it only combined them if the netdevs were the same, so can use any of them.
         */
        nft_m_entry->netdev = pre_ct_entry->netdev;
@@ -1143,7 +1143,7 @@ nfp_fl_ct_zone_entry *get_nfp_zone_entry(struct nfp_flower_priv *priv,
        zt->priv = priv;
        zt->nft = NULL;
 
-       /* init the various hash tables and lists*/
+       /* init the various hash tables and lists */
        INIT_LIST_HEAD(&zt->pre_ct_list);
        INIT_LIST_HEAD(&zt->post_ct_list);
        INIT_LIST_HEAD(&zt->nft_flows_list);
@@ -1346,7 +1346,7 @@ static void nfp_free_nft_merge_children(void *entry, bool is_nft_flow)
         */
 
        if (is_nft_flow) {
-               /* Need to iterate through list of nft_flow entries*/
+               /* Need to iterate through list of nft_flow entries */
                struct nfp_fl_ct_flow_entry *ct_entry = entry;
 
                list_for_each_entry_safe(m_entry, tmp, &ct_entry->children,
@@ -1354,7 +1354,7 @@ static void nfp_free_nft_merge_children(void *entry, bool is_nft_flow)
                        cleanup_nft_merge_entry(m_entry);
                }
        } else {
-               /* Need to iterate through list of tc_merged_flow entries*/
+               /* Need to iterate through list of tc_merged_flow entries */
                struct nfp_fl_ct_tc_merge *ct_entry = entry;
 
                list_for_each_entry_safe(m_entry, tmp, &ct_entry->children,
index ede90e0..e92860e 100644 (file)
@@ -234,7 +234,7 @@ nfp_fl_lag_config_group(struct nfp_fl_lag *lag, struct nfp_fl_lag_group *group,
        }
 
        /* To signal the end of a batch, both the switch and last flags are set
-        * and the the reserved SYNC group ID is used.
+        * and the reserved SYNC group ID is used.
         */
        if (*batch == NFP_FL_LAG_BATCH_FINISHED) {
                flags |= NFP_FL_LAG_SWITCH | NFP_FL_LAG_LAST;
@@ -576,7 +576,7 @@ nfp_fl_lag_changeupper_event(struct nfp_fl_lag *lag,
        group->dirty = true;
        group->slave_cnt = slave_count;
 
-       /* Group may have been on queue for removal but is now offloable. */
+       /* Group may have been on queue for removal but is now offloadable. */
        group->to_remove = false;
        mutex_unlock(&lag->lock);
 
index 74e1b27..0f06ef6 100644 (file)
@@ -339,7 +339,7 @@ int nfp_compile_flow_metadata(struct nfp_app *app, u32 cookie,
                goto err_free_ctx_entry;
        }
 
-       /* Do net allocate a mask-id for pre_tun_rules. These flows are used to
+       /* Do not allocate a mask-id for pre_tun_rules. These flows are used to
         * configure the pre_tun table and are never actually send to the
         * firmware as an add-flow message. This causes the mask-id allocation
         * on the firmware to get out of sync if allocated here.
index 9d65459..83c9715 100644 (file)
@@ -359,7 +359,7 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
                        flow_rule_match_enc_opts(rule, &enc_op);
 
                if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
-                       /* check if GRE, which has no enc_ports */
+                       /* Check if GRE, which has no enc_ports */
                        if (!netif_is_gretap(netdev) && !netif_is_ip6gretap(netdev)) {
                                NL_SET_ERR_MSG_MOD(extack, "unsupported offload: an exact match on L4 destination port is required for non-GRE tunnels");
                                return -EOPNOTSUPP;
@@ -1016,7 +1016,7 @@ int nfp_flower_merge_offloaded_flows(struct nfp_app *app,
            nfp_flower_is_merge_flow(sub_flow2))
                return -EINVAL;
 
-       /* check if the two flows are already merged */
+       /* Check if the two flows are already merged */
        parent_ctx = (u64)(be32_to_cpu(sub_flow1->meta.host_ctx_id)) << 32;
        parent_ctx |= (u64)(be32_to_cpu(sub_flow2->meta.host_ctx_id));
        if (rhashtable_lookup_fast(&priv->merge_table,
index 3206ba8..4e5df9f 100644 (file)
@@ -534,7 +534,7 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
        }
 }
 
-/* offload tc action, currently only for tc police */
+/* Offload tc action, currently only for tc police */
 
 static const struct rhashtable_params stats_meter_table_params = {
        .key_offset     = offsetof(struct nfp_meter_entry, meter_id),
@@ -690,7 +690,7 @@ nfp_act_install_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
        pps_support = !!(fl_priv->flower_ext_feats & NFP_FL_FEATS_QOS_PPS);
 
        for (i = 0 ; i < action_num; i++) {
-               /*set qos associate data for this interface */
+               /* Set qos associate data for this interface */
                action = paction + i;
                if (action->id != FLOW_ACTION_POLICE) {
                        NL_SET_ERR_MSG_MOD(extack,
@@ -736,7 +736,7 @@ nfp_act_remove_actions(struct nfp_app *app, struct flow_offload_action *fl_act,
        u32 meter_id;
        bool pps;
 
-       /*delete qos associate data for this interface */
+       /* Delete qos associate data for this interface */
        if (fl_act->id != FLOW_ACTION_POLICE) {
                NL_SET_ERR_MSG_MOD(extack,
                                   "unsupported offload: qos rate limit offload requires police action");
index 6bf3ec4..0af5541 100644 (file)
@@ -1064,7 +1064,7 @@ nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
                return 0;
 
        entry->ref_count--;
-       /* If del is part of a mod then mac_list is still in use elsewheree. */
+       /* If del is part of a mod then mac_list is still in use elsewhere. */
        if (nfp_netdev_is_nfp_repr(netdev) && !mod) {
                repr = netdev_priv(netdev);
                repr_priv = repr->app_priv;
index 7db56ab..448c1c1 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/bpf_trace.h>
 #include <linux/netdevice.h>
+#include <linux/bitfield.h>
 
 #include "../nfp_app.h"
 #include "../nfp_net.h"
@@ -81,12 +82,11 @@ nfp_nfd3_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfd3_tx_buf *txbuf,
        if (!skb->encapsulation) {
                l3_offset = skb_network_offset(skb);
                l4_offset = skb_transport_offset(skb);
-               hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdrlen = skb_tcp_all_headers(skb);
        } else {
                l3_offset = skb_inner_network_offset(skb);
                l4_offset = skb_inner_transport_offset(skb);
-               hdrlen = skb_inner_transport_header(skb) - skb->data +
-                       inner_tcp_hdrlen(skb);
+               hdrlen = skb_inner_tcp_all_headers(skb);
        }
 
        txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs;
@@ -167,30 +167,35 @@ nfp_nfd3_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
        u64_stats_update_end(&r_vec->tx_sync);
 }
 
-static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
+static int nfp_nfd3_prep_tx_meta(struct nfp_net_dp *dp, struct sk_buff *skb, u64 tls_handle)
 {
        struct metadata_dst *md_dst = skb_metadata_dst(skb);
        unsigned char *data;
+       bool vlan_insert;
        u32 meta_id = 0;
        int md_bytes;
 
-       if (likely(!md_dst && !tls_handle))
-               return 0;
-       if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX)) {
-               if (!tls_handle)
-                       return 0;
-               md_dst = NULL;
+       if (unlikely(md_dst || tls_handle)) {
+               if (unlikely(md_dst && md_dst->type != METADATA_HW_PORT_MUX))
+                       md_dst = NULL;
        }
 
-       md_bytes = 4 + !!md_dst * 4 + !!tls_handle * 8;
+       vlan_insert = skb_vlan_tag_present(skb) && (dp->ctrl & NFP_NET_CFG_CTRL_TXVLAN_V2);
+
+       if (!(md_dst || tls_handle || vlan_insert))
+               return 0;
+
+       md_bytes = sizeof(meta_id) +
+                  !!md_dst * NFP_NET_META_PORTID_SIZE +
+                  !!tls_handle * NFP_NET_META_CONN_HANDLE_SIZE +
+                  vlan_insert * NFP_NET_META_VLAN_SIZE;
 
        if (unlikely(skb_cow_head(skb, md_bytes)))
                return -ENOMEM;
 
-       meta_id = 0;
        data = skb_push(skb, md_bytes) + md_bytes;
        if (md_dst) {
-               data -= 4;
+               data -= NFP_NET_META_PORTID_SIZE;
                put_unaligned_be32(md_dst->u.port_info.port_id, data);
                meta_id = NFP_NET_META_PORTID;
        }
@@ -198,13 +203,23 @@ static int nfp_nfd3_prep_tx_meta(struct sk_buff *skb, u64 tls_handle)
                /* conn handle is opaque, we just use u64 to be able to quickly
                 * compare it to zero
                 */
-               data -= 8;
+               data -= NFP_NET_META_CONN_HANDLE_SIZE;
                memcpy(data, &tls_handle, sizeof(tls_handle));
                meta_id <<= NFP_NET_META_FIELD_SIZE;
                meta_id |= NFP_NET_META_CONN_HANDLE;
        }
+       if (vlan_insert) {
+               data -= NFP_NET_META_VLAN_SIZE;
+               /* data type of skb->vlan_proto is __be16
+                * so it fills metadata without calling put_unaligned_be16
+                */
+               memcpy(data, &skb->vlan_proto, sizeof(skb->vlan_proto));
+               put_unaligned_be16(skb_vlan_tag_get(skb), data + sizeof(skb->vlan_proto));
+               meta_id <<= NFP_NET_META_FIELD_SIZE;
+               meta_id |= NFP_NET_META_VLAN;
+       }
 
-       data -= 4;
+       data -= sizeof(meta_id);
        put_unaligned_be32(meta_id, data);
 
        return md_bytes;
@@ -258,7 +273,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_OK;
        }
 
-       md_bytes = nfp_nfd3_prep_tx_meta(skb, tls_handle);
+       md_bytes = nfp_nfd3_prep_tx_meta(dp, skb, tls_handle);
        if (unlikely(md_bytes < 0))
                goto err_flush;
 
@@ -282,7 +297,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
        txd = &tx_ring->txds[wr_idx];
        txd->offset_eop = (nr_frags ? 0 : NFD3_DESC_TX_EOP) | md_bytes;
        txd->dma_len = cpu_to_le16(skb_headlen(skb));
-       nfp_desc_set_dma_addr(txd, dma_addr);
+       nfp_desc_set_dma_addr_40b(txd, dma_addr);
        txd->data_len = cpu_to_le16(skb->len);
 
        txd->flags = 0;
@@ -320,7 +335,7 @@ netdev_tx_t nfp_nfd3_tx(struct sk_buff *skb, struct net_device *netdev)
 
                        txd = &tx_ring->txds[wr_idx];
                        txd->dma_len = cpu_to_le16(fsize);
-                       nfp_desc_set_dma_addr(txd, dma_addr);
+                       nfp_desc_set_dma_addr_40b(txd, dma_addr);
                        txd->offset_eop = md_bytes |
                                ((f == nr_frags - 1) ? NFD3_DESC_TX_EOP : 0);
                        txd->vals8[1] = second_half;
@@ -562,8 +577,12 @@ nfp_nfd3_rx_give_one(const struct nfp_net_dp *dp,
        /* Fill freelist descriptor */
        rx_ring->rxds[wr_idx].fld.reserved = 0;
        rx_ring->rxds[wr_idx].fld.meta_len_dd = 0;
-       nfp_desc_set_dma_addr(&rx_ring->rxds[wr_idx].fld,
-                             dma_addr + dp->rx_dma_off);
+       /* DMA address is expanded to 48-bit width in freelist for NFP3800,
+        * so the *_48b macro is used accordingly, it's also OK to fill
+        * a 40-bit address since the top 8 bits are get set to 0.
+        */
+       nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld,
+                                 dma_addr + dp->rx_dma_off);
 
        rx_ring->wr_p++;
        if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) {
@@ -700,7 +719,7 @@ bool
 nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
                    void *data, void *pkt, unsigned int pkt_len, int meta_len)
 {
-       u32 meta_info;
+       u32 meta_info, vlan_info;
 
        meta_info = get_unaligned_be32(data);
        data += 4;
@@ -718,6 +737,17 @@ nfp_nfd3_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
                        meta->mark = get_unaligned_be32(data);
                        data += 4;
                        break;
+               case NFP_NET_META_VLAN:
+                       vlan_info = get_unaligned_be32(data);
+                       if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
+                               meta->vlan.stripped = true;
+                               meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
+                                                           vlan_info);
+                               meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
+                                                          vlan_info);
+                       }
+                       data += 4;
+                       break;
                case NFP_NET_META_PORTID:
                        meta->portid = get_unaligned_be32(data);
                        data += 4;
@@ -817,7 +847,7 @@ nfp_nfd3_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
        txd = &tx_ring->txds[wr_idx];
        txd->offset_eop = NFD3_DESC_TX_EOP;
        txd->dma_len = cpu_to_le16(pkt_len);
-       nfp_desc_set_dma_addr(txd, rxbuf->dma_addr + dma_off);
+       nfp_desc_set_dma_addr_40b(txd, rxbuf->dma_addr + dma_off);
        txd->data_len = cpu_to_le16(pkt_len);
 
        txd->flags = 0;
@@ -1046,9 +1076,11 @@ static int nfp_nfd3_rx(struct nfp_net_rx_ring *rx_ring, int budget)
                }
 #endif
 
-               if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
-                       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
-                                              le16_to_cpu(rxd->rxd.vlan));
+               if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
+                       nfp_nfd3_rx_drop(dp, r_vec, rx_ring, NULL, skb);
+                       continue;
+               }
+
                if (meta_len_xdp)
                        skb_metadata_set(skb, meta_len_xdp);
 
@@ -1193,7 +1225,7 @@ nfp_nfd3_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
        txd = &tx_ring->txds[wr_idx];
        txd->offset_eop = meta_len | NFD3_DESC_TX_EOP;
        txd->dma_len = cpu_to_le16(skb_headlen(skb));
-       nfp_desc_set_dma_addr(txd, dma_addr);
+       nfp_desc_set_dma_addr_40b(txd, dma_addr);
        txd->data_len = cpu_to_le16(skb->len);
 
        txd->flags = 0;
index 47604d5..a03190c 100644 (file)
@@ -247,10 +247,13 @@ nfp_nfd3_print_tx_descs(struct seq_file *file,
         NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC |                \
         NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM |            \
         NFP_NET_CFG_CTRL_RXVLAN | NFP_NET_CFG_CTRL_TXVLAN |            \
+        NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ |         \
+        NFP_NET_CFG_CTRL_TXVLAN_V2 |                                   \
         NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO |               \
         NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA |    \
         NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_RSS |              \
         NFP_NET_CFG_CTRL_IRQMOD | NFP_NET_CFG_CTRL_TXRWB |             \
+        NFP_NET_CFG_CTRL_VEPA |                                        \
         NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE |              \
         NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 |                 \
         NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE |       \
@@ -260,6 +263,7 @@ const struct nfp_dp_ops nfp_nfd3_ops = {
        .version                = NFP_NFD_VER_NFD3,
        .tx_min_desc_per_pkt    = 1,
        .cap_mask               = NFP_NFD3_CFG_CTRL_SUPPORTED,
+       .dma_mask               = DMA_BIT_MASK(40),
        .poll                   = nfp_nfd3_poll,
        .xsk_poll               = nfp_nfd3_xsk_poll,
        .ctrl_poll              = nfp_nfd3_ctrl_poll,
index c16c4b4..65e2431 100644 (file)
@@ -40,7 +40,7 @@ nfp_nfd3_xsk_tx_xdp(const struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
        txd = &tx_ring->txds[wr_idx];
        txd->offset_eop = NFD3_DESC_TX_EOP;
        txd->dma_len = cpu_to_le16(pkt_len);
-       nfp_desc_set_dma_addr(txd, xrxbuf->dma_addr + pkt_off);
+       nfp_desc_set_dma_addr_40b(txd, xrxbuf->dma_addr + pkt_off);
        txd->data_len = cpu_to_le16(pkt_len);
 
        txd->flags = 0;
@@ -94,9 +94,12 @@ static void nfp_nfd3_xsk_rx_skb(struct nfp_net_rx_ring *rx_ring,
 
        nfp_nfd3_rx_csum(dp, r_vec, rxd, meta, skb);
 
-       if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
-               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
-                                      le16_to_cpu(rxd->rxd.vlan));
+       if (unlikely(!nfp_net_vlan_strip(skb, rxd, meta))) {
+               dev_kfree_skb_any(skb);
+               nfp_net_xsk_rx_drop(r_vec, xrxbuf);
+               return;
+       }
+
        if (meta_xdp)
                skb_metadata_set(skb,
                                 xrxbuf->xdp->data - xrxbuf->xdp->data_meta);
@@ -361,10 +364,8 @@ static void nfp_nfd3_xsk_tx(struct nfp_net_tx_ring *tx_ring)
 
                        /* Build TX descriptor. */
                        txd = &tx_ring->txds[wr_idx];
-                       nfp_desc_set_dma_addr(txd,
-                                             xsk_buff_raw_get_dma(xsk_pool,
-                                                                  desc[i].addr
-                                                                  ));
+                       nfp_desc_set_dma_addr_40b(txd,
+                                                 xsk_buff_raw_get_dma(xsk_pool, desc[i].addr));
                        txd->offset_eop = NFD3_DESC_TX_EOP;
                        txd->dma_len = cpu_to_le16(desc[i].len);
                        txd->data_len = cpu_to_le16(desc[i].len);
index e509d6d..0b4f550 100644 (file)
@@ -46,28 +46,16 @@ nfp_nfdk_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfdk_tx_buf *txbuf,
        if (!skb->encapsulation) {
                l3_offset = skb_network_offset(skb);
                l4_offset = skb_transport_offset(skb);
-               hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdrlen = skb_tcp_all_headers(skb);
        } else {
                l3_offset = skb_inner_network_offset(skb);
                l4_offset = skb_inner_transport_offset(skb);
-               hdrlen = skb_inner_transport_header(skb) - skb->data +
-                       inner_tcp_hdrlen(skb);
+               hdrlen = skb_inner_tcp_all_headers(skb);
        }
 
        segs = skb_shinfo(skb)->gso_segs;
        mss = skb_shinfo(skb)->gso_size & NFDK_DESC_TX_MSS_MASK;
 
-       /* Note: TSO of the packet with metadata prepended to skb is not
-        * supported yet, in which case l3/l4_offset and lso_hdrlen need
-        * be correctly handled here.
-        * Concern:
-        * The driver doesn't have md_bytes easily available at this point.
-        * The PCI.IN PD ME won't have md_bytes bytes to add to lso_hdrlen,
-        * so it needs the full length there.  The app MEs might prefer
-        * l3_offset and l4_offset relative to the start of packet data,
-        * but could probably cope with it being relative to the CTM buf
-        * data offset.
-        */
        txd.l3_offset = l3_offset;
        txd.l4_offset = l4_offset;
        txd.lso_meta_res = 0;
@@ -191,12 +179,6 @@ static int nfp_nfdk_prep_port_id(struct sk_buff *skb)
        if (unlikely(md_dst->type != METADATA_HW_PORT_MUX))
                return 0;
 
-       /* Note: Unsupported case when TSO a skb with metedata prepended.
-        * See the comments in `nfp_nfdk_tx_tso` for details.
-        */
-       if (unlikely(md_dst && skb_is_gso(skb)))
-               return -EOPNOTSUPP;
-
        if (unlikely(skb_cow_head(skb, sizeof(md_dst->u.port_info.port_id))))
                return -ENOMEM;
 
@@ -314,7 +296,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
-       nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr);
+       nfp_desc_set_dma_addr_48b(txd, dma_addr);
 
        /* starts at bit 0 */
        BUILD_BUG_ON(!(NFDK_DESC_TX_DMA_LEN_HEAD & 1));
@@ -339,7 +321,7 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
                        dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len);
 
                        txd->dma_len_type = cpu_to_le16(dlen_type);
-                       nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr);
+                       nfp_desc_set_dma_addr_48b(txd, dma_addr);
 
                        dma_len -= dlen_type;
                        dma_addr += dlen_type + 1;
@@ -595,8 +577,8 @@ nfp_nfdk_rx_give_one(const struct nfp_net_dp *dp,
        /* Fill freelist descriptor */
        rx_ring->rxds[wr_idx].fld.reserved = 0;
        rx_ring->rxds[wr_idx].fld.meta_len_dd = 0;
-       nfp_desc_set_dma_addr(&rx_ring->rxds[wr_idx].fld,
-                             dma_addr + dp->rx_dma_off);
+       nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld,
+                                 dma_addr + dp->rx_dma_off);
 
        rx_ring->wr_p++;
        if (!(rx_ring->wr_p % NFP_NET_FL_BATCH)) {
@@ -717,7 +699,7 @@ static bool
 nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
                    void *data, void *pkt, unsigned int pkt_len, int meta_len)
 {
-       u32 meta_info;
+       u32 meta_info, vlan_info;
 
        meta_info = get_unaligned_be32(data);
        data += 4;
@@ -735,6 +717,17 @@ nfp_nfdk_parse_meta(struct net_device *netdev, struct nfp_meta_parsed *meta,
                        meta->mark = get_unaligned_be32(data);
                        data += 4;
                        break;
+               case NFP_NET_META_VLAN:
+                       vlan_info = get_unaligned_be32(data);
+                       if (FIELD_GET(NFP_NET_META_VLAN_STRIP, vlan_info)) {
+                               meta->vlan.stripped = true;
+                               meta->vlan.tpid = FIELD_GET(NFP_NET_META_VLAN_TPID_MASK,
+                                                           vlan_info);
+                               meta->vlan.tci = FIELD_GET(NFP_NET_META_VLAN_TCI_MASK,
+                                                          vlan_info);
+                       }
+                       data += 4;
+                       break;
                case NFP_NET_META_PORTID:
                        meta->portid = get_unaligned_be32(data);
                        data += 4;
@@ -929,7 +922,7 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
-       nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr);
+       nfp_desc_set_dma_addr_48b(txd, dma_addr);
 
        tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD;
        dma_len -= tmp_dlen;
@@ -940,7 +933,7 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
                dma_len -= 1;
                dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len);
                txd->dma_len_type = cpu_to_le16(dlen_type);
-               nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr);
+               nfp_desc_set_dma_addr_48b(txd, dma_addr);
 
                dlen_type &= NFDK_DESC_TX_DMA_LEN;
                dma_len -= dlen_type;
@@ -1170,9 +1163,11 @@ static int nfp_nfdk_rx(struct nfp_net_rx_ring *rx_ring, int budget)
 
                nfp_nfdk_rx_csum(dp, r_vec, rxd, &meta, skb);
 
-               if (rxd->rxd.flags & PCIE_DESC_RX_VLAN)
-                       __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
-                                              le16_to_cpu(rxd->rxd.vlan));
+               if (unlikely(!nfp_net_vlan_strip(skb, rxd, &meta))) {
+                       nfp_nfdk_rx_drop(dp, r_vec, rx_ring, NULL, skb);
+                       continue;
+               }
+
                if (meta_len_xdp)
                        skb_metadata_set(skb, meta_len_xdp);
 
@@ -1332,7 +1327,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
-       nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr);
+       nfp_desc_set_dma_addr_48b(txd, dma_addr);
 
        tmp_dlen = dlen_type & NFDK_DESC_TX_DMA_LEN_HEAD;
        dma_len -= tmp_dlen;
@@ -1343,7 +1338,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
                dma_len -= 1;
                dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN, dma_len);
                txd->dma_len_type = cpu_to_le16(dlen_type);
-               nfp_nfdk_tx_desc_set_dma_addr(txd, dma_addr);
+               nfp_desc_set_dma_addr_48b(txd, dma_addr);
 
                dlen_type &= NFDK_DESC_TX_DMA_LEN;
                dma_len -= dlen_type;
index 301f111..6cd895d 100644 (file)
@@ -168,10 +168,11 @@ nfp_nfdk_print_tx_descs(struct seq_file *file,
         NFP_NET_CFG_CTRL_L2BC | NFP_NET_CFG_CTRL_L2MC |                \
         NFP_NET_CFG_CTRL_RXCSUM | NFP_NET_CFG_CTRL_TXCSUM |            \
         NFP_NET_CFG_CTRL_RXVLAN |                                      \
+        NFP_NET_CFG_CTRL_RXVLAN_V2 | NFP_NET_CFG_CTRL_RXQINQ |         \
         NFP_NET_CFG_CTRL_GATHER | NFP_NET_CFG_CTRL_LSO |               \
         NFP_NET_CFG_CTRL_CTAG_FILTER | NFP_NET_CFG_CTRL_CMSG_DATA |    \
         NFP_NET_CFG_CTRL_RINGCFG | NFP_NET_CFG_CTRL_IRQMOD |           \
-        NFP_NET_CFG_CTRL_TXRWB |                                       \
+        NFP_NET_CFG_CTRL_TXRWB | NFP_NET_CFG_CTRL_VEPA |               \
         NFP_NET_CFG_CTRL_VXLAN | NFP_NET_CFG_CTRL_NVGRE |              \
         NFP_NET_CFG_CTRL_BPF | NFP_NET_CFG_CTRL_LSO2 |                 \
         NFP_NET_CFG_CTRL_RSS2 | NFP_NET_CFG_CTRL_CSUM_COMPLETE |       \
@@ -181,6 +182,7 @@ const struct nfp_dp_ops nfp_nfdk_ops = {
        .version                = NFP_NFD_VER_NFDK,
        .tx_min_desc_per_pkt    = NFDK_TX_DESC_PER_SIMPLE_PKT,
        .cap_mask               = NFP_NFDK_CFG_CTRL_SUPPORTED,
+       .dma_mask               = DMA_BIT_MASK(48),
        .poll                   = nfp_nfdk_poll,
        .ctrl_poll              = nfp_nfdk_ctrl_poll,
        .xmit                   = nfp_nfdk_tx,
index 4f88d17..36b1730 100644 (file)
@@ -410,7 +410,9 @@ nfp_net_fw_find(struct pci_dev *pdev, struct nfp_pf *pf)
                return NULL;
        }
 
-       fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
+       fw_model = nfp_hwinfo_lookup(pf->hwinfo, "nffw.partno");
+       if (!fw_model)
+               fw_model = nfp_hwinfo_lookup(pf->hwinfo, "assembly.partno");
        if (!fw_model) {
                dev_err(&pdev->dev, "Error: can't read part number\n");
                return NULL;
index 3dd3a92..a101ff3 100644 (file)
@@ -115,7 +115,7 @@ struct nfp_nfdk_tx_buf;
 #define D_IDX(ring, idx)       ((idx) & ((ring)->cnt - 1))
 
 /* Convenience macro for writing dma address into RX/TX descriptors */
-#define nfp_desc_set_dma_addr(desc, dma_addr)                          \
+#define nfp_desc_set_dma_addr_40b(desc, dma_addr)                      \
        do {                                                            \
                __typeof__(desc) __d = (desc);                          \
                dma_addr_t __addr = (dma_addr);                         \
@@ -124,13 +124,13 @@ struct nfp_nfdk_tx_buf;
                __d->dma_addr_hi = upper_32_bits(__addr) & 0xff;        \
        } while (0)
 
-#define nfp_nfdk_tx_desc_set_dma_addr(desc, dma_addr)                         \
-       do {                                                                   \
-               __typeof__(desc) __d = (desc);                                 \
-               dma_addr_t __addr = (dma_addr);                                \
-                                                                              \
-               __d->dma_addr_hi = cpu_to_le16(upper_32_bits(__addr) & 0xff);  \
-               __d->dma_addr_lo = cpu_to_le32(lower_32_bits(__addr));         \
+#define nfp_desc_set_dma_addr_48b(desc, dma_addr)                      \
+       do {                                                            \
+               __typeof__(desc) __d = (desc);                          \
+               dma_addr_t __addr = (dma_addr);                         \
+                                                                       \
+               __d->dma_addr_hi = cpu_to_le16(upper_32_bits(__addr));  \
+               __d->dma_addr_lo = cpu_to_le32(lower_32_bits(__addr));  \
        } while (0)
 
 /**
@@ -225,8 +225,8 @@ struct nfp_net_tx_ring {
 struct nfp_net_rx_desc {
        union {
                struct {
-                       u8 dma_addr_hi; /* High bits of the buf address */
-                       __le16 reserved; /* Must be zero */
+                       __le16 dma_addr_hi; /* High bits of the buf address */
+                       u8 reserved; /* Must be zero */
                        u8 meta_len_dd; /* Must be zero */
 
                        __le32 dma_addr_lo; /* Low bits of the buffer address */
@@ -248,6 +248,8 @@ struct nfp_net_rx_desc {
 };
 
 #define NFP_NET_META_FIELD_MASK GENMASK(NFP_NET_META_FIELD_SIZE - 1, 0)
+#define NFP_NET_VLAN_CTAG      0
+#define NFP_NET_VLAN_STAG      1
 
 struct nfp_meta_parsed {
        u8 hash_type;
@@ -256,6 +258,11 @@ struct nfp_meta_parsed {
        u32 mark;
        u32 portid;
        __wsum csum;
+       struct {
+               bool stripped;
+               u8 tpid;
+               u16 tci;
+       } vlan;
 };
 
 struct nfp_net_rx_hash {
index 4e56a99..c5c3a4a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/ethtool.h>
 #include <linux/log2.h>
 #include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
 #include <linux/random.h>
 #include <linux/vmalloc.h>
 #include <linux/ktime.h>
@@ -597,7 +598,7 @@ nfp_net_tls_tx(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
        if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))
                return skb;
 
-       datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+       datalen = skb->len - skb_tcp_all_headers(skb);
        seq = ntohl(tcp_hdr(skb)->seq);
        ntls = tls_driver_ctx(skb->sk, TLS_OFFLOAD_CTX_DIR_TX);
        resync_pending = tls_offload_tx_resync_pending(skb->sk);
@@ -665,7 +666,7 @@ void nfp_net_tls_tx_undo(struct sk_buff *skb, u64 tls_handle)
        if (WARN_ON_ONCE(!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk)))
                return;
 
-       datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
+       datalen = skb->len - skb_tcp_all_headers(skb);
        seq = ntohl(tcp_hdr(skb)->seq);
 
        ntls = tls_driver_ctx(skb->sk, TLS_OFFLOAD_CTX_DIR_TX);
@@ -1694,16 +1695,18 @@ static int nfp_net_set_features(struct net_device *netdev,
 
        if (changed & NETIF_F_HW_VLAN_CTAG_RX) {
                if (features & NETIF_F_HW_VLAN_CTAG_RX)
-                       new_ctrl |= NFP_NET_CFG_CTRL_RXVLAN;
+                       new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ?:
+                                   NFP_NET_CFG_CTRL_RXVLAN;
                else
-                       new_ctrl &= ~NFP_NET_CFG_CTRL_RXVLAN;
+                       new_ctrl &= ~NFP_NET_CFG_CTRL_RXVLAN_ANY;
        }
 
        if (changed & NETIF_F_HW_VLAN_CTAG_TX) {
                if (features & NETIF_F_HW_VLAN_CTAG_TX)
-                       new_ctrl |= NFP_NET_CFG_CTRL_TXVLAN;
+                       new_ctrl |= nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ?:
+                                   NFP_NET_CFG_CTRL_TXVLAN;
                else
-                       new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN;
+                       new_ctrl &= ~NFP_NET_CFG_CTRL_TXVLAN_ANY;
        }
 
        if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
@@ -1713,6 +1716,13 @@ static int nfp_net_set_features(struct net_device *netdev,
                        new_ctrl &= ~NFP_NET_CFG_CTRL_CTAG_FILTER;
        }
 
+       if (changed & NETIF_F_HW_VLAN_STAG_RX) {
+               if (features & NETIF_F_HW_VLAN_STAG_RX)
+                       new_ctrl |= NFP_NET_CFG_CTRL_RXQINQ;
+               else
+                       new_ctrl &= ~NFP_NET_CFG_CTRL_RXQINQ;
+       }
+
        if (changed & NETIF_F_SG) {
                if (features & NETIF_F_SG)
                        new_ctrl |= NFP_NET_CFG_CTRL_GATHER;
@@ -1742,6 +1752,27 @@ static int nfp_net_set_features(struct net_device *netdev,
 }
 
 static netdev_features_t
+nfp_net_fix_features(struct net_device *netdev,
+                    netdev_features_t features)
+{
+       if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
+           (features & NETIF_F_HW_VLAN_STAG_RX)) {
+               if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+                       features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+                       netdev->wanted_features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+                       netdev_warn(netdev,
+                                   "S-tag and C-tag stripping can't be enabled at the same time. Enabling S-tag stripping and disabling C-tag stripping\n");
+               } else if (netdev->features & NETIF_F_HW_VLAN_STAG_RX) {
+                       features &= ~NETIF_F_HW_VLAN_STAG_RX;
+                       netdev->wanted_features &= ~NETIF_F_HW_VLAN_STAG_RX;
+                       netdev_warn(netdev,
+                                   "S-tag and C-tag stripping can't be enabled at the same time. Enabling C-tag stripping and disabling S-tag stripping\n");
+               }
+       }
+       return features;
+}
+
+static netdev_features_t
 nfp_net_features_check(struct sk_buff *skb, struct net_device *dev,
                       netdev_features_t features)
 {
@@ -1757,8 +1788,7 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev,
        if (skb_is_gso(skb)) {
                u32 hdrlen;
 
-               hdrlen = skb_inner_transport_header(skb) - skb->data +
-                       inner_tcp_hdrlen(skb);
+               hdrlen = skb_inner_tcp_all_headers(skb);
 
                /* Assume worst case scenario of having longest possible
                 * metadata prepend - 8B
@@ -1892,6 +1922,69 @@ static int nfp_net_set_mac_address(struct net_device *netdev, void *addr)
        return 0;
 }
 
+static int nfp_net_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+                                 struct net_device *dev, u32 filter_mask,
+                                 int nlflags)
+{
+       struct nfp_net *nn = netdev_priv(dev);
+       u16 mode;
+
+       if (!(nn->cap & NFP_NET_CFG_CTRL_VEPA))
+               return -EOPNOTSUPP;
+
+       mode = (nn->dp.ctrl & NFP_NET_CFG_CTRL_VEPA) ?
+              BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB;
+
+       return ndo_dflt_bridge_getlink(skb, pid, seq, dev, mode, 0, 0,
+                                      nlflags, filter_mask, NULL);
+}
+
+static int nfp_net_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
+                                 u16 flags, struct netlink_ext_ack *extack)
+{
+       struct nfp_net *nn = netdev_priv(dev);
+       struct nlattr *attr, *br_spec;
+       int rem, err;
+       u32 new_ctrl;
+       u16 mode;
+
+       if (!(nn->cap & NFP_NET_CFG_CTRL_VEPA))
+               return -EOPNOTSUPP;
+
+       br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (!br_spec)
+               return -EINVAL;
+
+       nla_for_each_nested(attr, br_spec, rem) {
+               if (nla_type(attr) != IFLA_BRIDGE_MODE)
+                       continue;
+
+               if (nla_len(attr) < sizeof(mode))
+                       return -EINVAL;
+
+               new_ctrl = nn->dp.ctrl;
+               mode = nla_get_u16(attr);
+               if (mode == BRIDGE_MODE_VEPA)
+                       new_ctrl |= NFP_NET_CFG_CTRL_VEPA;
+               else if (mode == BRIDGE_MODE_VEB)
+                       new_ctrl &= ~NFP_NET_CFG_CTRL_VEPA;
+               else
+                       return -EOPNOTSUPP;
+
+               if (new_ctrl == nn->dp.ctrl)
+                       return 0;
+
+               nn_writel(nn, NFP_NET_CFG_CTRL, new_ctrl);
+               err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN);
+               if (!err)
+                       nn->dp.ctrl = new_ctrl;
+
+               return err;
+       }
+
+       return -EINVAL;
+}
+
 const struct net_device_ops nfp_nfd3_netdev_ops = {
        .ndo_init               = nfp_app_ndo_init,
        .ndo_uninit             = nfp_app_ndo_uninit,
@@ -1914,11 +2007,14 @@ const struct net_device_ops nfp_nfd3_netdev_ops = {
        .ndo_change_mtu         = nfp_net_change_mtu,
        .ndo_set_mac_address    = nfp_net_set_mac_address,
        .ndo_set_features       = nfp_net_set_features,
+       .ndo_fix_features       = nfp_net_fix_features,
        .ndo_features_check     = nfp_net_features_check,
        .ndo_get_phys_port_name = nfp_net_get_phys_port_name,
        .ndo_bpf                = nfp_net_xdp,
        .ndo_xsk_wakeup         = nfp_net_xsk_wakeup,
        .ndo_get_devlink_port   = nfp_devlink_get_devlink_port,
+       .ndo_bridge_getlink     = nfp_net_bridge_getlink,
+       .ndo_bridge_setlink     = nfp_net_bridge_setlink,
 };
 
 const struct net_device_ops nfp_nfdk_netdev_ops = {
@@ -1932,6 +2028,7 @@ const struct net_device_ops nfp_nfdk_netdev_ops = {
        .ndo_vlan_rx_kill_vid   = nfp_net_vlan_rx_kill_vid,
        .ndo_set_vf_mac         = nfp_app_set_vf_mac,
        .ndo_set_vf_vlan        = nfp_app_set_vf_vlan,
+       .ndo_set_vf_rate        = nfp_app_set_vf_rate,
        .ndo_set_vf_spoofchk    = nfp_app_set_vf_spoofchk,
        .ndo_set_vf_trust       = nfp_app_set_vf_trust,
        .ndo_get_vf_config      = nfp_app_get_vf_config,
@@ -1942,10 +2039,13 @@ const struct net_device_ops nfp_nfdk_netdev_ops = {
        .ndo_change_mtu         = nfp_net_change_mtu,
        .ndo_set_mac_address    = nfp_net_set_mac_address,
        .ndo_set_features       = nfp_net_set_features,
+       .ndo_fix_features       = nfp_net_fix_features,
        .ndo_features_check     = nfp_net_features_check,
        .ndo_get_phys_port_name = nfp_net_get_phys_port_name,
        .ndo_bpf                = nfp_net_xdp,
        .ndo_get_devlink_port   = nfp_devlink_get_devlink_port,
+       .ndo_bridge_getlink     = nfp_net_bridge_getlink,
+       .ndo_bridge_setlink     = nfp_net_bridge_setlink,
 };
 
 static int nfp_udp_tunnel_sync(struct net_device *netdev, unsigned int table)
@@ -1993,7 +2093,7 @@ void nfp_net_info(struct nfp_net *nn)
                nn->fw_ver.extend, nn->fw_ver.class,
                nn->fw_ver.major, nn->fw_ver.minor,
                nn->max_mtu);
-       nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+       nn_info(nn, "CAP: %#x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
                nn->cap,
                nn->cap & NFP_NET_CFG_CTRL_PROMISC  ? "PROMISC "  : "",
                nn->cap & NFP_NET_CFG_CTRL_L2BC     ? "L2BCFILT " : "",
@@ -2002,6 +2102,9 @@ void nfp_net_info(struct nfp_net *nn)
                nn->cap & NFP_NET_CFG_CTRL_TXCSUM   ? "TXCSUM "   : "",
                nn->cap & NFP_NET_CFG_CTRL_RXVLAN   ? "RXVLAN "   : "",
                nn->cap & NFP_NET_CFG_CTRL_TXVLAN   ? "TXVLAN "   : "",
+               nn->cap & NFP_NET_CFG_CTRL_RXQINQ   ? "RXQINQ "   : "",
+               nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ? "RXVLANv2 "   : "",
+               nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2   ? "TXVLAN2 "   : "",
                nn->cap & NFP_NET_CFG_CTRL_SCATTER  ? "SCATTER "  : "",
                nn->cap & NFP_NET_CFG_CTRL_GATHER   ? "GATHER "   : "",
                nn->cap & NFP_NET_CFG_CTRL_LSO      ? "TSO1 "     : "",
@@ -2012,6 +2115,7 @@ void nfp_net_info(struct nfp_net *nn)
                nn->cap & NFP_NET_CFG_CTRL_MSIXAUTO ? "AUTOMASK " : "",
                nn->cap & NFP_NET_CFG_CTRL_IRQMOD   ? "IRQMOD "   : "",
                nn->cap & NFP_NET_CFG_CTRL_TXRWB    ? "TXRWB "    : "",
+               nn->cap & NFP_NET_CFG_CTRL_VEPA     ? "VEPA "     : "",
                nn->cap & NFP_NET_CFG_CTRL_VXLAN    ? "VXLAN "    : "",
                nn->cap & NFP_NET_CFG_CTRL_NVGRE    ? "NVGRE "    : "",
                nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ?
@@ -2040,6 +2144,7 @@ nfp_net_alloc(struct pci_dev *pdev, const struct nfp_dev_info *dev_info,
              void __iomem *ctrl_bar, bool needs_netdev,
              unsigned int max_tx_rings, unsigned int max_rx_rings)
 {
+       u64 dma_mask = dma_get_mask(&pdev->dev);
        struct nfp_net *nn;
        int err;
 
@@ -2085,6 +2190,14 @@ nfp_net_alloc(struct pci_dev *pdev, const struct nfp_dev_info *dev_info,
                goto err_free_nn;
        }
 
+       if ((dma_mask & nn->dp.ops->dma_mask) != dma_mask) {
+               dev_err(&pdev->dev,
+                       "DMA mask of loaded firmware: %llx, required DMA mask: %llx\n",
+                       nn->dp.ops->dma_mask, dma_mask);
+               err = -EINVAL;
+               goto err_free_nn;
+       }
+
        nn->max_tx_rings = max_tx_rings;
        nn->max_rx_rings = max_rx_rings;
 
@@ -2279,31 +2392,39 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
 
        netdev->vlan_features = netdev->hw_features;
 
-       if (nn->cap & NFP_NET_CFG_CTRL_RXVLAN) {
+       if (nn->cap & NFP_NET_CFG_CTRL_RXVLAN_ANY) {
                netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
-               nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXVLAN;
+               nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_RXVLAN_V2 ?:
+                              NFP_NET_CFG_CTRL_RXVLAN;
        }
-       if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN) {
+       if (nn->cap & NFP_NET_CFG_CTRL_TXVLAN_ANY) {
                if (nn->cap & NFP_NET_CFG_CTRL_LSO2) {
                        nn_warn(nn, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n");
                } else {
                        netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX;
-                       nn->dp.ctrl |= NFP_NET_CFG_CTRL_TXVLAN;
+                       nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_TXVLAN_V2 ?:
+                                      NFP_NET_CFG_CTRL_TXVLAN;
                }
        }
        if (nn->cap & NFP_NET_CFG_CTRL_CTAG_FILTER) {
                netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
                nn->dp.ctrl |= NFP_NET_CFG_CTRL_CTAG_FILTER;
        }
+       if (nn->cap & NFP_NET_CFG_CTRL_RXQINQ) {
+               netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX;
+               nn->dp.ctrl |= NFP_NET_CFG_CTRL_RXQINQ;
+       }
 
        netdev->features = netdev->hw_features;
 
        if (nfp_app_has_tc(nn->app) && nn->port)
                netdev->hw_features |= NETIF_F_HW_TC;
 
-       /* Advertise but disable TSO by default. */
-       netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-       nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_LSO_ANY;
+       /* C-Tag strip and S-Tag strip can't be supported simultaneously,
+        * so enable C-Tag strip and disable S-Tag strip by default.
+        */
+       netdev->features &= ~NETIF_F_HW_VLAN_STAG_RX;
+       nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_RXQINQ;
 
        /* Finalise the netdev setup */
        switch (nn->dp.ops->version) {
index 8892a94..ac05ec3 100644 (file)
 #define NFP_NET_LSO_MAX_HDR_SZ         255
 #define NFP_NET_LSO_MAX_SEGS           64
 
+/* working with metadata vlan api (NFD version >= 2.0) */
+#define NFP_NET_META_VLAN_STRIP                        BIT(31)
+#define NFP_NET_META_VLAN_TPID_MASK            GENMASK(19, 16)
+#define NFP_NET_META_VLAN_TCI_MASK             GENMASK(15, 0)
+
 /* Prepend field types */
 #define NFP_NET_META_FIELD_SIZE                4
 #define NFP_NET_META_HASH              1 /* next field carries hash type */
 #define NFP_NET_META_MARK              2
+#define NFP_NET_META_VLAN              4 /* ctag or stag type */
 #define NFP_NET_META_PORTID            5
 #define NFP_NET_META_CSUM              6 /* checksum complete type */
 #define NFP_NET_META_CONN_HANDLE       7
 
 #define NFP_META_PORT_ID_CTRL          ~0U
 
+/* Prepend field sizes */
+#define NFP_NET_META_VLAN_SIZE                 4
+#define NFP_NET_META_PORTID_SIZE               4
+#define NFP_NET_META_CONN_HANDLE_SIZE          8
 /* Hash type pre-pended when a RSS hash was computed */
 #define NFP_NET_RSS_NONE               0
 #define NFP_NET_RSS_IPV4               1
 #define   NFP_NET_CFG_CTRL_LSO           (0x1 << 10) /* LSO/TSO (version 1) */
 #define   NFP_NET_CFG_CTRL_CTAG_FILTER   (0x1 << 11) /* VLAN CTAG filtering */
 #define   NFP_NET_CFG_CTRL_CMSG_DATA     (0x1 << 12) /* RX cmsgs on data Qs */
+#define   NFP_NET_CFG_CTRL_RXQINQ        (0x1 << 13) /* Enable S-tag strip */
+#define   NFP_NET_CFG_CTRL_RXVLAN_V2     (0x1 << 15) /* Enable C-tag strip */
 #define   NFP_NET_CFG_CTRL_RINGCFG       (0x1 << 16) /* Ring runtime changes */
 #define   NFP_NET_CFG_CTRL_RSS           (0x1 << 17) /* RSS (version 1) */
 #define   NFP_NET_CFG_CTRL_IRQMOD        (0x1 << 18) /* Interrupt moderation */
 #define   NFP_NET_CFG_CTRL_MSIXAUTO      (0x1 << 20) /* MSI-X auto-masking */
 #define   NFP_NET_CFG_CTRL_TXRWB         (0x1 << 21) /* Write-back of TX ring*/
+#define   NFP_NET_CFG_CTRL_VEPA                  (0x1 << 22) /* Enable VEPA mode */
+#define   NFP_NET_CFG_CTRL_TXVLAN_V2     (0x1 << 23) /* Enable VLAN C-tag insert*/
 #define   NFP_NET_CFG_CTRL_VXLAN         (0x1 << 24) /* VXLAN tunnel support */
 #define   NFP_NET_CFG_CTRL_NVGRE         (0x1 << 25) /* NVGRE tunnel support */
 #define   NFP_NET_CFG_CTRL_BPF           (0x1 << 27) /* BPF offload capable */
                                         NFP_NET_CFG_CTRL_CSUM_COMPLETE)
 #define NFP_NET_CFG_CTRL_CHAIN_META    (NFP_NET_CFG_CTRL_RSS2 | \
                                         NFP_NET_CFG_CTRL_CSUM_COMPLETE)
+#define NFP_NET_CFG_CTRL_RXVLAN_ANY    (NFP_NET_CFG_CTRL_RXVLAN | \
+                                        NFP_NET_CFG_CTRL_RXVLAN_V2)
+#define NFP_NET_CFG_CTRL_TXVLAN_ANY    (NFP_NET_CFG_CTRL_TXVLAN | \
+                                        NFP_NET_CFG_CTRL_TXVLAN_V2)
 
 #define NFP_NET_CFG_UPDATE             0x0004
 #define   NFP_NET_CFG_UPDATE_GEN         (0x1 <<  0) /* General update */
index 34dd948..550df83 100644 (file)
@@ -440,3 +440,27 @@ bool nfp_ctrl_tx(struct nfp_net *nn, struct sk_buff *skb)
 
        return ret;
 }
+
+bool nfp_net_vlan_strip(struct sk_buff *skb, const struct nfp_net_rx_desc *rxd,
+                       const struct nfp_meta_parsed *meta)
+{
+       u16 tpid = 0, tci = 0;
+
+       if (rxd->rxd.flags & PCIE_DESC_RX_VLAN) {
+               tpid = ETH_P_8021Q;
+               tci = le16_to_cpu(rxd->rxd.vlan);
+       } else if (meta->vlan.stripped) {
+               if (meta->vlan.tpid == NFP_NET_VLAN_CTAG)
+                       tpid = ETH_P_8021Q;
+               else if (meta->vlan.tpid == NFP_NET_VLAN_STAG)
+                       tpid = ETH_P_8021AD;
+               else
+                       return false;
+
+               tci = meta->vlan.tci;
+       }
+       if (tpid)
+               __vlan_hwaccel_put_tag(skb, htons(tpid), tci);
+
+       return true;
+}
index c934cc2..831c83c 100644 (file)
@@ -106,6 +106,8 @@ int nfp_net_tx_rings_prepare(struct nfp_net *nn, struct nfp_net_dp *dp);
 void nfp_net_rx_rings_free(struct nfp_net_dp *dp);
 void nfp_net_tx_rings_free(struct nfp_net_dp *dp);
 void nfp_net_rx_ring_reset(struct nfp_net_rx_ring *rx_ring);
+bool nfp_net_vlan_strip(struct sk_buff *skb, const struct nfp_net_rx_desc *rxd,
+                       const struct nfp_meta_parsed *meta);
 
 enum nfp_nfd_version {
        NFP_NFD_VER_NFD3,
@@ -117,6 +119,7 @@ enum nfp_nfd_version {
  * @version:                   Indicate dp type
  * @tx_min_desc_per_pkt:       Minimal TX descs needed for each packet
  * @cap_mask:                  Mask of supported features
+ * @dma_mask:                  DMA addressing capability
  * @poll:                      Napi poll for normal rx/tx
  * @xsk_poll:                  Napi poll when xsk is enabled
  * @ctrl_poll:                 Tasklet poll for ctrl rx/tx
@@ -134,6 +137,7 @@ struct nfp_dp_ops {
        enum nfp_nfd_version version;
        unsigned int tx_min_desc_per_pkt;
        u32 cap_mask;
+       u64 dma_mask;
 
        int (*poll)(struct napi_struct *napi, int budget);
        int (*xsk_poll)(struct napi_struct *napi, int budget);
index df0afd2..c922dfa 100644 (file)
@@ -29,6 +29,7 @@
 #include "nfp_net_dp.h"
 #include "nfp_net.h"
 #include "nfp_port.h"
+#include "nfpcore/nfp_cpp.h"
 
 struct nfp_et_stat {
        char name[ETH_GSTRING_LEN];
@@ -442,6 +443,160 @@ static int nfp_net_set_ringparam(struct net_device *netdev,
        return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt);
 }
 
+static int nfp_test_link(struct net_device *netdev)
+{
+       if (!netif_carrier_ok(netdev) || !(netdev->flags & IFF_UP))
+               return 1;
+
+       return 0;
+}
+
+static int nfp_test_nsp(struct net_device *netdev)
+{
+       struct nfp_app *app = nfp_app_from_netdev(netdev);
+       struct nfp_nsp_identify *nspi;
+       struct nfp_nsp *nsp;
+       int err;
+
+       nsp = nfp_nsp_open(app->cpp);
+       if (IS_ERR(nsp)) {
+               err = PTR_ERR(nsp);
+               netdev_info(netdev, "NSP Test: failed to access the NSP: %d\n", err);
+               goto exit;
+       }
+
+       if (nfp_nsp_get_abi_ver_minor(nsp) < 15) {
+               err = -EOPNOTSUPP;
+               goto exit_close_nsp;
+       }
+
+       nspi = kzalloc(sizeof(*nspi), GFP_KERNEL);
+       if (!nspi) {
+               err = -ENOMEM;
+               goto exit_close_nsp;
+       }
+
+       err = nfp_nsp_read_identify(nsp, nspi, sizeof(*nspi));
+       if (err < 0)
+               netdev_info(netdev, "NSP Test: reading bsp version failed %d\n", err);
+
+       kfree(nspi);
+exit_close_nsp:
+       nfp_nsp_close(nsp);
+exit:
+       return err;
+}
+
+static int nfp_test_fw(struct net_device *netdev)
+{
+       struct nfp_net *nn = netdev_priv(netdev);
+       int err;
+
+       err = nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN);
+       if (err)
+               netdev_info(netdev, "FW Test: update failed %d\n", err);
+
+       return err;
+}
+
+static int nfp_test_reg(struct net_device *netdev)
+{
+       struct nfp_app *app = nfp_app_from_netdev(netdev);
+       struct nfp_cpp *cpp = app->cpp;
+       u32 model = nfp_cpp_model(cpp);
+       u32 value;
+       int err;
+
+       err = nfp_cpp_model_autodetect(cpp, &value);
+       if (err < 0) {
+               netdev_info(netdev, "REG Test: NFP model detection failed %d\n", err);
+               return err;
+       }
+
+       return (value == model) ? 0 : 1;
+}
+
+static bool link_test_supported(struct net_device *netdev)
+{
+       return true;
+}
+
+static bool nsp_test_supported(struct net_device *netdev)
+{
+       if (nfp_app_from_netdev(netdev))
+               return true;
+
+       return false;
+}
+
+static bool fw_test_supported(struct net_device *netdev)
+{
+       if (nfp_netdev_is_nfp_net(netdev))
+               return true;
+
+       return false;
+}
+
+static bool reg_test_supported(struct net_device *netdev)
+{
+       if (nfp_app_from_netdev(netdev))
+               return true;
+
+       return false;
+}
+
+static struct nfp_self_test_item {
+       char name[ETH_GSTRING_LEN];
+       bool (*is_supported)(struct net_device *dev);
+       int (*func)(struct net_device *dev);
+} nfp_self_test[] = {
+       {"Link Test", link_test_supported, nfp_test_link},
+       {"NSP Test", nsp_test_supported, nfp_test_nsp},
+       {"Firmware Test", fw_test_supported, nfp_test_fw},
+       {"Register Test", reg_test_supported, nfp_test_reg}
+};
+
+#define NFP_TEST_TOTAL_NUM ARRAY_SIZE(nfp_self_test)
+
+static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data)
+{
+       int i;
+
+       for (i = 0; i < NFP_TEST_TOTAL_NUM; i++)
+               if (nfp_self_test[i].is_supported(netdev))
+                       ethtool_sprintf(&data, nfp_self_test[i].name);
+}
+
+static int nfp_get_self_test_count(struct net_device *netdev)
+{
+       int i, count = 0;
+
+       for (i = 0; i < NFP_TEST_TOTAL_NUM; i++)
+               if (nfp_self_test[i].is_supported(netdev))
+                       count++;
+
+       return count;
+}
+
+static void nfp_net_self_test(struct net_device *netdev, struct ethtool_test *eth_test,
+                             u64 *data)
+{
+       int i, ret, count = 0;
+
+       netdev_info(netdev, "Start self test\n");
+
+       for (i = 0; i < NFP_TEST_TOTAL_NUM; i++) {
+               if (nfp_self_test[i].is_supported(netdev)) {
+                       ret = nfp_self_test[i].func(netdev);
+                       if (ret)
+                               eth_test->flags |= ETH_TEST_FL_FAILED;
+                       data[count++] = ret;
+               }
+       }
+
+       netdev_info(netdev, "Test end\n");
+}
+
 static unsigned int nfp_vnic_get_sw_stats_count(struct net_device *netdev)
 {
        struct nfp_net *nn = netdev_priv(netdev);
@@ -705,6 +860,9 @@ static void nfp_net_get_strings(struct net_device *netdev,
                data = nfp_mac_get_stats_strings(netdev, data);
                data = nfp_app_port_get_stats_strings(nn->port, data);
                break;
+       case ETH_SS_TEST:
+               nfp_get_self_test_strings(netdev, data);
+               break;
        }
 }
 
@@ -739,6 +897,8 @@ static int nfp_net_get_sset_count(struct net_device *netdev, int sset)
                cnt += nfp_mac_get_stats_count(netdev);
                cnt += nfp_app_port_get_stats_count(nn->port);
                return cnt;
+       case ETH_SS_TEST:
+               return nfp_get_self_test_count(netdev);
        default:
                return -EOPNOTSUPP;
        }
@@ -757,6 +917,9 @@ static void nfp_port_get_strings(struct net_device *netdev,
                        data = nfp_mac_get_stats_strings(netdev, data);
                data = nfp_app_port_get_stats_strings(port, data);
                break;
+       case ETH_SS_TEST:
+               nfp_get_self_test_strings(netdev, data);
+               break;
        }
 }
 
@@ -786,6 +949,8 @@ static int nfp_port_get_sset_count(struct net_device *netdev, int sset)
                        count = nfp_mac_get_stats_count(netdev);
                count += nfp_app_port_get_stats_count(port);
                return count;
+       case ETH_SS_TEST:
+               return nfp_get_self_test_count(netdev);
        default:
                return -EOPNOTSUPP;
        }
@@ -1460,6 +1625,55 @@ static int nfp_net_set_channels(struct net_device *netdev,
        return nfp_net_set_num_rings(nn, total_rx, total_tx);
 }
 
+static void nfp_port_get_pauseparam(struct net_device *netdev,
+                                   struct ethtool_pauseparam *pause)
+{
+       struct nfp_eth_table_port *eth_port;
+       struct nfp_port *port;
+
+       port = nfp_port_from_netdev(netdev);
+       eth_port = nfp_port_get_eth_port(port);
+       if (!eth_port)
+               return;
+
+       /* Currently pause frame support is fixed */
+       pause->autoneg = AUTONEG_DISABLE;
+       pause->rx_pause = 1;
+       pause->tx_pause = 1;
+}
+
+static int nfp_net_set_phys_id(struct net_device *netdev,
+                              enum ethtool_phys_id_state state)
+{
+       struct nfp_eth_table_port *eth_port;
+       struct nfp_port *port;
+       int err;
+
+       port = nfp_port_from_netdev(netdev);
+       eth_port = __nfp_port_get_eth_port(port);
+       if (!eth_port)
+               return -EOPNOTSUPP;
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               /* Control LED to blink */
+               err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 1);
+               break;
+
+       case ETHTOOL_ID_INACTIVE:
+               /* Control LED to normal mode */
+               err = nfp_eth_set_idmode(port->app->cpp, eth_port->index, 0);
+               break;
+
+       case ETHTOOL_ID_ON:
+       case ETHTOOL_ID_OFF:
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return err;
+}
+
 static const struct ethtool_ops nfp_net_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES |
@@ -1468,6 +1682,7 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_ringparam          = nfp_net_get_ringparam,
        .set_ringparam          = nfp_net_set_ringparam,
+       .self_test              = nfp_net_self_test,
        .get_strings            = nfp_net_get_strings,
        .get_ethtool_stats      = nfp_net_get_stats,
        .get_sset_count         = nfp_net_get_sset_count,
@@ -1492,6 +1707,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = {
        .set_link_ksettings     = nfp_net_set_link_ksettings,
        .get_fecparam           = nfp_port_get_fecparam,
        .set_fecparam           = nfp_port_set_fecparam,
+       .get_pauseparam         = nfp_port_get_pauseparam,
+       .set_phys_id            = nfp_net_set_phys_id,
 };
 
 const struct ethtool_ops nfp_port_ethtool_ops = {
@@ -1499,6 +1716,7 @@ const struct ethtool_ops nfp_port_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_strings            = nfp_port_get_strings,
        .get_ethtool_stats      = nfp_port_get_stats,
+       .self_test              = nfp_net_self_test,
        .get_sset_count         = nfp_port_get_sset_count,
        .set_dump               = nfp_app_set_dump,
        .get_dump_flag          = nfp_app_get_dump_flag,
@@ -1509,6 +1727,8 @@ const struct ethtool_ops nfp_port_ethtool_ops = {
        .set_link_ksettings     = nfp_net_set_link_ksettings,
        .get_fecparam           = nfp_port_get_fecparam,
        .set_fecparam           = nfp_port_set_fecparam,
+       .get_pauseparam         = nfp_port_get_pauseparam,
+       .set_phys_id            = nfp_net_set_phys_id,
 };
 
 void nfp_net_set_ethtool_ops(struct net_device *netdev)
index 75b5018..8b77582 100644 (file)
@@ -365,9 +365,9 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
 
        netdev->vlan_features = netdev->hw_features;
 
-       if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN)
+       if (repr_cap & NFP_NET_CFG_CTRL_RXVLAN_ANY)
                netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
-       if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN) {
+       if (repr_cap & NFP_NET_CFG_CTRL_TXVLAN_ANY) {
                if (repr_cap & NFP_NET_CFG_CTRL_LSO2)
                        netdev_warn(netdev, "Device advertises both TSO2 and TXVLAN. Refusing to enable TXVLAN.\n");
                else
@@ -375,11 +375,15 @@ int nfp_repr_init(struct nfp_app *app, struct net_device *netdev,
        }
        if (repr_cap & NFP_NET_CFG_CTRL_CTAG_FILTER)
                netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+       if (repr_cap & NFP_NET_CFG_CTRL_RXQINQ)
+               netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX;
 
        netdev->features = netdev->hw_features;
 
-       /* Advertise but disable TSO by default. */
-       netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+       /* C-Tag strip and S-Tag strip can't be supported simultaneously,
+        * so enable C-Tag strip and disable S-Tag strip by default.
+        */
+       netdev->features &= ~NETIF_F_HW_VLAN_STAG_RX;
        netif_set_tso_max_segs(netdev, NFP_NET_LSO_MAX_SEGS);
 
        netdev->priv_flags |= IFF_NO_QUEUE | IFF_DISABLE_NETPOLL;
index 8682944..aea507a 100644 (file)
@@ -70,8 +70,12 @@ void nfp_net_xsk_rx_ring_fill_freelist(struct nfp_net_rx_ring *rx_ring)
 
                nfp_net_xsk_rx_bufs_stash(rx_ring, wr_idx, xdp);
 
-               nfp_desc_set_dma_addr(&rx_ring->rxds[wr_idx].fld,
-                                     rx_ring->xsk_rxbufs[wr_idx].dma_addr);
+               /* DMA address is expanded to 48-bit width in freelist for NFP3800,
+                * so the *_48b macro is used accordingly, it's also OK to fill
+                * a 40-bit address since the top 8 bits are get set to 0.
+                */
+               nfp_desc_set_dma_addr_48b(&rx_ring->rxds[wr_idx].fld,
+                                         rx_ring->xsk_rxbufs[wr_idx].dma_addr);
 
                rx_ring->wr_p++;
                wr_ptr_add++;
index afab6f0..6ad43c7 100644 (file)
@@ -4,7 +4,6 @@
 #ifndef NFP_CRC32_H
 #define NFP_CRC32_H
 
-#include <linux/kernel.h>
 #include <linux/crc32.h>
 
 /**
index ddb34bf..3d379e9 100644 (file)
 #include <linux/ctype.h>
 #include <linux/types.h>
 #include <linux/sizes.h>
-#include <linux/stringify.h>
 
 #ifndef NFP_SUBSYS
 #define NFP_SUBSYS "nfp"
 #endif
 
-#define string_format(x) __FILE__ ":" __stringify(__LINE__) ": " x
-
-#define __nfp_err(cpp, fmt, args...) \
-       dev_err(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
-#define __nfp_warn(cpp, fmt, args...) \
-       dev_warn(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
-#define __nfp_info(cpp, fmt, args...) \
-       dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
-#define __nfp_dbg(cpp, fmt, args...) \
-       dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
-#define __nfp_printk(level, cpp, fmt, args...) \
-       dev_printk(level, nfp_cpp_device(cpp)->parent,  \
-                  NFP_SUBSYS ": " fmt, ## args)
-
 #define nfp_err(cpp, fmt, args...) \
-       __nfp_err(cpp, string_format(fmt), ## args)
+       dev_err(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
 #define nfp_warn(cpp, fmt, args...) \
-       __nfp_warn(cpp, string_format(fmt), ## args)
+       dev_warn(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
 #define nfp_info(cpp, fmt, args...) \
-       __nfp_info(cpp, string_format(fmt), ## args)
+       dev_info(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
 #define nfp_dbg(cpp, fmt, args...) \
-       __nfp_dbg(cpp, string_format(fmt), ## args)
+       dev_dbg(nfp_cpp_device(cpp)->parent, NFP_SUBSYS ": " fmt, ## args)
 #define nfp_printk(level, cpp, fmt, args...) \
-       __nfp_printk(level, cpp, string_format(fmt), ## args)
+       dev_printk(level, nfp_cpp_device(cpp)->parent,  \
+                  NFP_SUBSYS ": " fmt, ## args)
 
 #define PCI_64BIT_BAR_COUNT             3
 
index 28384d6..0725b51 100644 (file)
@@ -9,7 +9,7 @@
 
 const struct nfp_dev_info nfp_dev_info[NFP_DEV_CNT] = {
        [NFP_DEV_NFP3800] = {
-               .dma_mask               = DMA_BIT_MASK(40),
+               .dma_mask               = DMA_BIT_MASK(48),
                .qc_idx_mask            = GENMASK(8, 0),
                .qc_addr_offset         = 0x400000,
                .min_qc_size            = 512,
@@ -21,7 +21,7 @@ const struct nfp_dev_info nfp_dev_info[NFP_DEV_CNT] = {
                .qc_area_sz             = 0x100000,
        },
        [NFP_DEV_NFP3800_VF] = {
-               .dma_mask               = DMA_BIT_MASK(40),
+               .dma_mask               = DMA_BIT_MASK(48),
                .qc_idx_mask            = GENMASK(8, 0),
                .qc_addr_offset         = 0,
                .min_qc_size            = 512,
index f5360ba..77d6685 100644 (file)
@@ -196,6 +196,8 @@ int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx,
 int
 nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode);
 
+int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state);
+
 static inline bool nfp_eth_can_support_fec(struct nfp_eth_table_port *eth_port)
 {
        return !!eth_port->fec_modes_supported;
index 311a5be..edd3000 100644 (file)
@@ -49,6 +49,7 @@
 #define NSP_ETH_CTRL_SET_LANES         BIT_ULL(5)
 #define NSP_ETH_CTRL_SET_ANEG          BIT_ULL(6)
 #define NSP_ETH_CTRL_SET_FEC           BIT_ULL(7)
+#define NSP_ETH_CTRL_SET_IDMODE                BIT_ULL(8)
 
 enum nfp_eth_raw {
        NSP_ETH_RAW_PORT = 0,
@@ -492,6 +493,35 @@ nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
        return 0;
 }
 
+int nfp_eth_set_idmode(struct nfp_cpp *cpp, unsigned int idx, bool state)
+{
+       union eth_table_entry *entries;
+       struct nfp_nsp *nsp;
+       u64 reg;
+
+       nsp = nfp_eth_config_start(cpp, idx);
+       if (IS_ERR(nsp))
+               return PTR_ERR(nsp);
+
+       /* Set this features were added in ABI 0.32 */
+       if (nfp_nsp_get_abi_ver_minor(nsp) < 32) {
+               nfp_err(nfp_nsp_cpp(nsp),
+                       "set id mode operation not supported, please update flash\n");
+               return -EOPNOTSUPP;
+       }
+
+       entries = nfp_nsp_config_entries(nsp);
+
+       reg = le64_to_cpu(entries[idx].control);
+       reg &= ~NSP_ETH_CTRL_SET_IDMODE;
+       reg |= FIELD_PREP(NSP_ETH_CTRL_SET_IDMODE, state);
+       entries[idx].control = cpu_to_le64(reg);
+
+       nfp_nsp_config_set_modified(nsp, true);
+
+       return nfp_eth_config_commit_end(nsp);
+}
+
 #define NFP_ETH_SET_BIT_CONFIG(nsp, raw_idx, mask, val, ctrl_bit)      \
        ({                                                              \
                __BF_FIELD_CHECK(mask, 0ULL, val, "NFP_ETH_SET_BIT_CONFIG: "); \
index f540354..c03986b 100644 (file)
@@ -947,10 +947,9 @@ static int ionic_tx_tso(struct ionic_queue *q, struct sk_buff *skb)
        }
 
        if (encap)
-               hdrlen = skb_inner_transport_header(skb) - skb->data +
-                        inner_tcp_hdrlen(skb);
+               hdrlen = skb_inner_tcp_all_headers(skb);
        else
-               hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdrlen = skb_tcp_all_headers(skb);
 
        tso_rem = len;
        seg_rem = min(tso_rem, hdrlen + mss);
index 07dd3c3..4e6f00a 100644 (file)
@@ -1877,7 +1877,7 @@ netxen_tso_check(struct net_device *netdev,
        if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
                        skb_shinfo(skb)->gso_size > 0) {
 
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
 
                first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
                first_desc->total_hdr_length = hdr_len;
index 82e74f6..d701ecd 100644 (file)
@@ -1110,7 +1110,7 @@ static int qed_int_deassertion(struct qed_hwfn  *p_hwfn,
                                                                 bit_len);
 
                                        /* Some bits represent more than a
-                                        * single interrupt. Correctly print
+                                        * single interrupt. Correctly print
                                         * their name.
                                         */
                                        if (ATTENTION_LENGTH(flags) > 2 ||
index 69b0ede..5a5dbbb 100644 (file)
@@ -42,8 +42,7 @@ int qed_rdma_bmap_alloc(struct qed_hwfn *p_hwfn,
 
        bmap->max_count = max_count;
 
-       bmap->bitmap = kcalloc(BITS_TO_LONGS(max_count), sizeof(long),
-                              GFP_KERNEL);
+       bmap->bitmap = bitmap_zalloc(max_count, GFP_KERNEL);
        if (!bmap->bitmap)
                return -ENOMEM;
 
@@ -107,7 +106,7 @@ int qed_bmap_test_id(struct qed_hwfn *p_hwfn,
 
 static bool qed_bmap_is_empty(struct qed_bmap *bmap)
 {
-       return bmap->max_count == find_first_bit(bmap->bitmap, bmap->max_count);
+       return bitmap_empty(bmap->bitmap, bmap->max_count);
 }
 
 static u32 qed_rdma_get_sb_id(void *p_hwfn, u32 rel_sb_id)
@@ -343,7 +342,7 @@ void qed_rdma_bmap_free(struct qed_hwfn *p_hwfn,
        }
 
 end:
-       kfree(bmap->bitmap);
+       bitmap_free(bmap->bitmap);
        bmap->bitmap = NULL;
 }
 
index b7cc365..7c2af48 100644 (file)
@@ -260,11 +260,9 @@ static int map_frag_to_bd(struct qede_tx_queue *txq,
 static u16 qede_get_skb_hlen(struct sk_buff *skb, bool is_encap_pkt)
 {
        if (is_encap_pkt)
-               return (skb_inner_transport_header(skb) +
-                       inner_tcp_hdrlen(skb) - skb->data);
-       else
-               return (skb_transport_header(skb) +
-                       tcp_hdrlen(skb) - skb->data);
+               return skb_inner_tcp_all_headers(skb);
+
+       return skb_tcp_all_headers(skb);
 }
 
 /* +2 for 1st BD for headers and 2nd BD for headlen (if required) */
index 8d43ca2..9da5e97 100644 (file)
@@ -497,7 +497,7 @@ set_flags:
        }
        opcode = QLCNIC_TX_ETHER_PKT;
        if (skb_is_gso(skb)) {
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
                first_desc->hdr_length = hdr_len;
                opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 :
index e90fa97..8dd7aa0 100644 (file)
@@ -1869,8 +1869,7 @@ int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf,
        if (!min_tx_rate)
                min_tx_rate = QLC_VF_MIN_TX_RATE;
 
-       if (max_tx_rate &&
-           (max_tx_rate >= 10000 || max_tx_rate < min_tx_rate)) {
+       if (max_tx_rate && max_tx_rate >= 10000) {
                netdev_err(netdev,
                           "Invalid max Tx rate, allowed range is [%d - %d]",
                           min_tx_rate, QLC_VF_MAX_TX_RATE);
@@ -1880,8 +1879,7 @@ int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf,
        if (!max_tx_rate)
                max_tx_rate = 10000;
 
-       if (min_tx_rate &&
-           (min_tx_rate > max_tx_rate || min_tx_rate < QLC_VF_MIN_TX_RATE)) {
+       if (min_tx_rate && min_tx_rate < QLC_VF_MIN_TX_RATE) {
                netdev_err(netdev,
                           "Invalid min Tx rate, allowed range is [%d - %d]",
                           QLC_VF_MIN_TX_RATE, max_tx_rate);
index 06104d2..0d80447 100644 (file)
@@ -1264,7 +1264,7 @@ static int emac_tso_csum(struct emac_adapter *adpt,
                                pskb_trim(skb, pkt_len);
                }
 
-               hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               hdr_len = skb_tcp_all_headers(skb);
                if (unlikely(skb->len == hdr_len)) {
                        /* we only need to do csum */
                        netif_warn(adpt, tx_err, adpt->netdev,
@@ -1339,7 +1339,7 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt,
 
        /* if Large Segment Offload is (in TCP Segmentation Offload struct) */
        if (TPD_LSO(tpd)) {
-               mapped_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               mapped_len = skb_tcp_all_headers(skb);
 
                tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx);
                tpbuf->length = mapped_len;
@@ -1465,7 +1465,7 @@ netdev_tx_t emac_mac_tx_buf_send(struct emac_adapter *adpt,
        /* Make sure the are enough free descriptors to hold one
         * maximum-sized SKB.  We need one desc for each fragment,
         * one for the checksum (emac_tso_csum), one for TSO, and
-        * and one for the SKB header.
+        * one for the SKB header.
         */
        if (emac_tpd_num_free_descs(tx_q) < (MAX_SKB_FRAGS + 3))
                netif_stop_queue(adpt->netdev);
index 407a1f8..a1c10b6 100644 (file)
@@ -89,7 +89,7 @@ static void sxgbe_enable_eee_mode(const struct sxgbe_priv_data *priv)
 
 void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv)
 {
-       /* Exit and disable EEE in case of we are are in LPI state. */
+       /* Exit and disable EEE in case of we are in LPI state. */
        priv->hw->mac->reset_eee_mode(priv->ioaddr);
        del_timer_sync(&priv->eee_ctrl_timer);
        priv->tx_path_in_lpi_mode = false;
index 186cb28..a99c3a6 100644 (file)
@@ -3874,7 +3874,7 @@ static int efx_ef10_udp_tnl_set_port(struct net_device *dev,
                                     unsigned int table, unsigned int entry,
                                     struct udp_tunnel_info *ti)
 {
-       struct efx_nic *efx = netdev_priv(dev);
+       struct efx_nic *efx = efx_netdev_priv(dev);
        struct efx_ef10_nic_data *nic_data;
        int efx_tunnel_type, rc;
 
@@ -3934,7 +3934,7 @@ static int efx_ef10_udp_tnl_unset_port(struct net_device *dev,
                                       unsigned int table, unsigned int entry,
                                       struct udp_tunnel_info *ti)
 {
-       struct efx_nic *efx = netdev_priv(dev);
+       struct efx_nic *efx = efx_netdev_priv(dev);
        struct efx_ef10_nic_data *nic_data;
        int rc;
 
index 173f0ec..425017f 100644 (file)
@@ -423,65 +423,58 @@ static int ef100_pci_find_func_ctrl_window(struct efx_nic *efx,
  */
 static void ef100_pci_remove(struct pci_dev *pci_dev)
 {
-       struct efx_nic *efx;
+       struct efx_nic *efx = pci_get_drvdata(pci_dev);
+       struct efx_probe_data *probe_data;
 
-       efx = pci_get_drvdata(pci_dev);
        if (!efx)
                return;
 
-       rtnl_lock();
-       dev_close(efx->net_dev);
-       rtnl_unlock();
-
-       /* Unregistering our netdev notifier triggers unbinding of TC indirect
-        * blocks, so we have to do it before PCI removal.
-        */
-       unregister_netdevice_notifier(&efx->netdev_notifier);
-#if defined(CONFIG_SFC_SRIOV)
-       if (!efx->type->is_vf)
-               efx_ef100_pci_sriov_disable(efx);
-#endif
+       probe_data = container_of(efx, struct efx_probe_data, efx);
+       ef100_remove_netdev(probe_data);
+
        ef100_remove(efx);
        efx_fini_io(efx);
-       netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n");
 
-       pci_set_drvdata(pci_dev, NULL);
-       efx_fini_struct(efx);
-       free_netdev(efx->net_dev);
+       pci_dbg(pci_dev, "shutdown successful\n");
 
        pci_disable_pcie_error_reporting(pci_dev);
+
+       pci_set_drvdata(pci_dev, NULL);
+       efx_fini_struct(efx);
+       kfree(probe_data);
 };
 
 static int ef100_pci_probe(struct pci_dev *pci_dev,
                           const struct pci_device_id *entry)
 {
        struct ef100_func_ctl_window fcw = { 0 };
-       struct net_device *net_dev;
+       struct efx_probe_data *probe_data;
        struct efx_nic *efx;
        int rc;
 
-       /* Allocate and initialise a struct net_device and struct efx_nic */
-       net_dev = alloc_etherdev_mq(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES);
-       if (!net_dev)
+       /* Allocate probe data and struct efx_nic */
+       probe_data = kzalloc(sizeof(*probe_data), GFP_KERNEL);
+       if (!probe_data)
                return -ENOMEM;
-       efx = netdev_priv(net_dev);
+       probe_data->pci_dev = pci_dev;
+       efx = &probe_data->efx;
+
        efx->type = (const struct efx_nic_type *)entry->driver_data;
 
+       efx->pci_dev = pci_dev;
        pci_set_drvdata(pci_dev, efx);
-       SET_NETDEV_DEV(net_dev, &pci_dev->dev);
-       rc = efx_init_struct(efx, pci_dev, net_dev);
+       rc = efx_init_struct(efx, pci_dev);
        if (rc)
                goto fail;
 
        efx->vi_stride = EF100_DEFAULT_VI_STRIDE;
-       netif_info(efx, probe, efx->net_dev,
-                  "Solarflare EF100 NIC detected\n");
+       pci_info(pci_dev, "Solarflare EF100 NIC detected\n");
 
        rc = ef100_pci_find_func_ctrl_window(efx, &fcw);
        if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "Error looking for ef100 function control window, rc=%d\n",
-                         rc);
+               pci_err(pci_dev,
+                       "Error looking for ef100 function control window, rc=%d\n",
+                       rc);
                goto fail;
        }
 
@@ -493,8 +486,7 @@ static int ef100_pci_probe(struct pci_dev *pci_dev,
        }
 
        if (fcw.offset > pci_resource_len(efx->pci_dev, fcw.bar) - ESE_GZ_FCW_LEN) {
-               netif_err(efx, probe, efx->net_dev,
-                         "Func control window overruns BAR\n");
+               pci_err(pci_dev, "Func control window overruns BAR\n");
                rc = -EIO;
                goto fail;
        }
@@ -508,19 +500,16 @@ static int ef100_pci_probe(struct pci_dev *pci_dev,
 
        efx->reg_base = fcw.offset;
 
-       efx->netdev_notifier.notifier_call = ef100_netdev_event;
-       rc = register_netdevice_notifier(&efx->netdev_notifier);
-       if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "Failed to register netdevice notifier, rc=%d\n", rc);
+       rc = efx->type->probe(efx);
+       if (rc)
                goto fail;
-       }
 
-       rc = efx->type->probe(efx);
+       efx->state = STATE_PROBED;
+       rc = ef100_probe_netdev(probe_data);
        if (rc)
                goto fail;
 
-       netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
+       pci_dbg(pci_dev, "initialisation successful\n");
 
        return 0;
 
index 5dba412..702abbe 100644 (file)
@@ -26,7 +26,7 @@ ef100_ethtool_get_ringparam(struct net_device *net_dev,
                            struct kernel_ethtool_ringparam *kernel_ring,
                            struct netlink_ext_ack *extack)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        ring->rx_max_pending = EFX_EF100_MAX_DMAQ_SIZE;
        ring->tx_max_pending = EFX_EF100_MAX_DMAQ_SIZE;
index 67fe44d..060392d 100644 (file)
@@ -22,6 +22,7 @@
 #include "ef100_regs.h"
 #include "mcdi_filters.h"
 #include "rx_common.h"
+#include "ef100_sriov.h"
 
 static void ef100_update_name(struct efx_nic *efx)
 {
@@ -79,7 +80,7 @@ static int ef100_remap_bar(struct efx_nic *efx, int max_vis)
  */
 static int ef100_net_stop(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
                  raw_smp_processor_id());
@@ -96,13 +97,15 @@ static int ef100_net_stop(struct net_device *net_dev)
        efx_mcdi_free_vis(efx);
        efx_remove_interrupts(efx);
 
+       efx->state = STATE_NET_DOWN;
+
        return 0;
 }
 
 /* Context: process, rtnl_lock() held. */
 static int ef100_net_open(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        unsigned int allocated_vis;
        int rc;
 
@@ -172,6 +175,8 @@ static int ef100_net_open(struct net_device *net_dev)
                efx_link_status_changed(efx);
        mutex_unlock(&efx->mac_lock);
 
+       efx->state = STATE_NET_UP;
+
        return 0;
 
 fail:
@@ -189,7 +194,7 @@ fail:
 static netdev_tx_t ef100_hard_start_xmit(struct sk_buff *skb,
                                         struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_tx_queue *tx_queue;
        struct efx_channel *channel;
        int rc;
@@ -239,13 +244,14 @@ int ef100_netdev_event(struct notifier_block *this,
        struct efx_nic *efx = container_of(this, struct efx_nic, netdev_notifier);
        struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
 
-       if (netdev_priv(net_dev) == efx && event == NETDEV_CHANGENAME)
+       if (efx->net_dev == net_dev &&
+           (event == NETDEV_CHANGENAME || event == NETDEV_REGISTER))
                ef100_update_name(efx);
 
        return NOTIFY_DONE;
 }
 
-int ef100_register_netdev(struct efx_nic *efx)
+static int ef100_register_netdev(struct efx_nic *efx)
 {
        struct net_device *net_dev = efx->net_dev;
        int rc;
@@ -271,7 +277,7 @@ int ef100_register_netdev(struct efx_nic *efx)
        /* Always start with carrier off; PHY events will detect the link */
        netif_carrier_off(net_dev);
 
-       efx->state = STATE_READY;
+       efx->state = STATE_NET_DOWN;
        rtnl_unlock();
        efx_init_mcdi_logging(efx);
 
@@ -283,11 +289,119 @@ fail_locked:
        return rc;
 }
 
-void ef100_unregister_netdev(struct efx_nic *efx)
+static void ef100_unregister_netdev(struct efx_nic *efx)
 {
        if (efx_dev_registered(efx)) {
                efx_fini_mcdi_logging(efx);
-               efx->state = STATE_UNINIT;
+               efx->state = STATE_PROBED;
                unregister_netdev(efx->net_dev);
        }
 }
+
+void ef100_remove_netdev(struct efx_probe_data *probe_data)
+{
+       struct efx_nic *efx = &probe_data->efx;
+
+       if (!efx->net_dev)
+               return;
+
+       rtnl_lock();
+       dev_close(efx->net_dev);
+       rtnl_unlock();
+
+       unregister_netdevice_notifier(&efx->netdev_notifier);
+#if defined(CONFIG_SFC_SRIOV)
+       if (!efx->type->is_vf)
+               efx_ef100_pci_sriov_disable(efx);
+#endif
+
+       ef100_unregister_netdev(efx);
+
+       down_write(&efx->filter_sem);
+       efx_mcdi_filter_table_remove(efx);
+       up_write(&efx->filter_sem);
+       efx_fini_channels(efx);
+       kfree(efx->phy_data);
+       efx->phy_data = NULL;
+
+       free_netdev(efx->net_dev);
+       efx->net_dev = NULL;
+       efx->state = STATE_PROBED;
+}
+
+int ef100_probe_netdev(struct efx_probe_data *probe_data)
+{
+       struct efx_nic *efx = &probe_data->efx;
+       struct efx_probe_data **probe_ptr;
+       struct net_device *net_dev;
+       int rc;
+
+       if (efx->mcdi->fn_flags &
+                       (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_NO_ACTIVE_PORT)) {
+               pci_info(efx->pci_dev, "No network port on this PCI function");
+               return 0;
+       }
+
+       /* Allocate and initialise a struct net_device */
+       net_dev = alloc_etherdev_mq(sizeof(probe_data), EFX_MAX_CORE_TX_QUEUES);
+       if (!net_dev)
+               return -ENOMEM;
+       probe_ptr = netdev_priv(net_dev);
+       *probe_ptr = probe_data;
+       efx->net_dev = net_dev;
+       SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
+
+       net_dev->features |= efx->type->offload_features;
+       net_dev->hw_features |= efx->type->offload_features;
+       net_dev->hw_enc_features |= efx->type->offload_features;
+       net_dev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_SG |
+                                 NETIF_F_HIGHDMA | NETIF_F_ALL_TSO;
+       netif_set_tso_max_segs(net_dev,
+                              ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS_DEFAULT);
+       efx->mdio.dev = net_dev;
+
+       rc = efx_ef100_init_datapath_caps(efx);
+       if (rc < 0)
+               goto fail;
+
+       rc = ef100_phy_probe(efx);
+       if (rc)
+               goto fail;
+
+       rc = efx_init_channels(efx);
+       if (rc)
+               goto fail;
+
+       down_write(&efx->filter_sem);
+       rc = ef100_filter_table_probe(efx);
+       up_write(&efx->filter_sem);
+       if (rc)
+               goto fail;
+
+       netdev_rss_key_fill(efx->rss_context.rx_hash_key,
+                           sizeof(efx->rss_context.rx_hash_key));
+
+       /* Don't fail init if RSS setup doesn't work. */
+       efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
+
+       rc = ef100_register_netdev(efx);
+       if (rc)
+               goto fail;
+
+       if (!efx->type->is_vf) {
+               rc = ef100_probe_netdev_pf(efx);
+               if (rc)
+                       goto fail;
+       }
+
+       efx->netdev_notifier.notifier_call = ef100_netdev_event;
+       rc = register_netdevice_notifier(&efx->netdev_notifier);
+       if (rc) {
+               netif_err(efx, probe, efx->net_dev,
+                         "Failed to register netdevice notifier, rc=%d\n", rc);
+               goto fail;
+       }
+
+fail:
+       return rc;
+}
index d40abb7..38b032b 100644 (file)
@@ -13,5 +13,5 @@
 
 int ef100_netdev_event(struct notifier_block *this,
                       unsigned long event, void *ptr);
-int ef100_register_netdev(struct efx_nic *efx);
-void ef100_unregister_netdev(struct efx_nic *efx);
+int ef100_probe_netdev(struct efx_probe_data *probe_data);
+void ef100_remove_netdev(struct efx_probe_data *probe_data);
index b2536d2..f89e695 100644 (file)
@@ -148,7 +148,7 @@ static int ef100_get_mac_address(struct efx_nic *efx, u8 *mac_address)
        return 0;
 }
 
-static int efx_ef100_init_datapath_caps(struct efx_nic *efx)
+int efx_ef100_init_datapath_caps(struct efx_nic *efx)
 {
        MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_V7_OUT_LEN);
        struct ef100_nic_data *nic_data = efx->nic_data;
@@ -327,7 +327,7 @@ static irqreturn_t ef100_msi_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int ef100_phy_probe(struct efx_nic *efx)
+int ef100_phy_probe(struct efx_nic *efx)
 {
        struct efx_mcdi_phy_data *phy_data;
        int rc;
@@ -365,7 +365,7 @@ static int ef100_phy_probe(struct efx_nic *efx)
        return 0;
 }
 
-static int ef100_filter_table_probe(struct efx_nic *efx)
+int ef100_filter_table_probe(struct efx_nic *efx)
 {
        return efx_mcdi_filter_table_probe(efx, true);
 }
@@ -704,178 +704,6 @@ static unsigned int efx_ef100_recycle_ring_size(const struct efx_nic *efx)
        return 10 * EFX_RECYCLE_RING_SIZE_10G;
 }
 
-/*     NIC level access functions
- */
-#define EF100_OFFLOAD_FEATURES (NETIF_F_HW_CSUM | NETIF_F_RXCSUM |     \
-       NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_NTUPLE | \
-       NETIF_F_RXHASH | NETIF_F_RXFCS | NETIF_F_TSO_ECN | NETIF_F_RXALL | \
-       NETIF_F_HW_VLAN_CTAG_TX)
-
-const struct efx_nic_type ef100_pf_nic_type = {
-       .revision = EFX_REV_EF100,
-       .is_vf = false,
-       .probe = ef100_probe_pf,
-       .offload_features = EF100_OFFLOAD_FEATURES,
-       .mcdi_max_ver = 2,
-       .mcdi_request = ef100_mcdi_request,
-       .mcdi_poll_response = ef100_mcdi_poll_response,
-       .mcdi_read_response = ef100_mcdi_read_response,
-       .mcdi_poll_reboot = ef100_mcdi_poll_reboot,
-       .mcdi_reboot_detected = ef100_mcdi_reboot_detected,
-       .irq_enable_master = efx_port_dummy_op_void,
-       .irq_test_generate = efx_ef100_irq_test_generate,
-       .irq_disable_non_ev = efx_port_dummy_op_void,
-       .push_irq_moderation = efx_channel_dummy_op_void,
-       .min_interrupt_mode = EFX_INT_MODE_MSIX,
-       .map_reset_reason = ef100_map_reset_reason,
-       .map_reset_flags = ef100_map_reset_flags,
-       .reset = ef100_reset,
-
-       .check_caps = ef100_check_caps,
-
-       .ev_probe = ef100_ev_probe,
-       .ev_init = ef100_ev_init,
-       .ev_fini = efx_mcdi_ev_fini,
-       .ev_remove = efx_mcdi_ev_remove,
-       .irq_handle_msi = ef100_msi_interrupt,
-       .ev_process = ef100_ev_process,
-       .ev_read_ack = ef100_ev_read_ack,
-       .ev_test_generate = efx_ef100_ev_test_generate,
-       .tx_probe = ef100_tx_probe,
-       .tx_init = ef100_tx_init,
-       .tx_write = ef100_tx_write,
-       .tx_enqueue = ef100_enqueue_skb,
-       .rx_probe = efx_mcdi_rx_probe,
-       .rx_init = efx_mcdi_rx_init,
-       .rx_remove = efx_mcdi_rx_remove,
-       .rx_write = ef100_rx_write,
-       .rx_packet = __ef100_rx_packet,
-       .rx_buf_hash_valid = ef100_rx_buf_hash_valid,
-       .fini_dmaq = efx_fini_dmaq,
-       .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS,
-       .filter_table_probe = ef100_filter_table_up,
-       .filter_table_restore = efx_mcdi_filter_table_restore,
-       .filter_table_remove = ef100_filter_table_down,
-       .filter_insert = efx_mcdi_filter_insert,
-       .filter_remove_safe = efx_mcdi_filter_remove_safe,
-       .filter_get_safe = efx_mcdi_filter_get_safe,
-       .filter_clear_rx = efx_mcdi_filter_clear_rx,
-       .filter_count_rx_used = efx_mcdi_filter_count_rx_used,
-       .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit,
-       .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids,
-#ifdef CONFIG_RFS_ACCEL
-       .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one,
-#endif
-
-       .get_phys_port_id = efx_ef100_get_phys_port_id,
-
-       .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN,
-       .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8,
-       .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8,
-       .rx_hash_key_size = 40,
-       .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
-       .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config,
-       .rx_push_rss_context_config = efx_mcdi_rx_push_rss_context_config,
-       .rx_pull_rss_context_config = efx_mcdi_rx_pull_rss_context_config,
-       .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts,
-       .rx_recycle_ring_size = efx_ef100_recycle_ring_size,
-
-       .reconfigure_mac = ef100_reconfigure_mac,
-       .reconfigure_port = efx_mcdi_port_reconfigure,
-       .test_nvram = efx_new_mcdi_nvram_test_all,
-       .describe_stats = ef100_describe_stats,
-       .start_stats = efx_mcdi_mac_start_stats,
-       .update_stats = ef100_update_stats,
-       .pull_stats = efx_mcdi_mac_pull_stats,
-       .stop_stats = efx_mcdi_mac_stop_stats,
-#ifdef CONFIG_SFC_SRIOV
-       .sriov_configure = efx_ef100_sriov_configure,
-#endif
-
-       /* Per-type bar/size configuration not used on ef100. Location of
-        * registers is defined by extended capabilities.
-        */
-       .mem_bar = NULL,
-       .mem_map_size = NULL,
-
-};
-
-const struct efx_nic_type ef100_vf_nic_type = {
-       .revision = EFX_REV_EF100,
-       .is_vf = true,
-       .probe = ef100_probe_vf,
-       .offload_features = EF100_OFFLOAD_FEATURES,
-       .mcdi_max_ver = 2,
-       .mcdi_request = ef100_mcdi_request,
-       .mcdi_poll_response = ef100_mcdi_poll_response,
-       .mcdi_read_response = ef100_mcdi_read_response,
-       .mcdi_poll_reboot = ef100_mcdi_poll_reboot,
-       .mcdi_reboot_detected = ef100_mcdi_reboot_detected,
-       .irq_enable_master = efx_port_dummy_op_void,
-       .irq_test_generate = efx_ef100_irq_test_generate,
-       .irq_disable_non_ev = efx_port_dummy_op_void,
-       .push_irq_moderation = efx_channel_dummy_op_void,
-       .min_interrupt_mode = EFX_INT_MODE_MSIX,
-       .map_reset_reason = ef100_map_reset_reason,
-       .map_reset_flags = ef100_map_reset_flags,
-       .reset = ef100_reset,
-       .check_caps = ef100_check_caps,
-       .ev_probe = ef100_ev_probe,
-       .ev_init = ef100_ev_init,
-       .ev_fini = efx_mcdi_ev_fini,
-       .ev_remove = efx_mcdi_ev_remove,
-       .irq_handle_msi = ef100_msi_interrupt,
-       .ev_process = ef100_ev_process,
-       .ev_read_ack = ef100_ev_read_ack,
-       .ev_test_generate = efx_ef100_ev_test_generate,
-       .tx_probe = ef100_tx_probe,
-       .tx_init = ef100_tx_init,
-       .tx_write = ef100_tx_write,
-       .tx_enqueue = ef100_enqueue_skb,
-       .rx_probe = efx_mcdi_rx_probe,
-       .rx_init = efx_mcdi_rx_init,
-       .rx_remove = efx_mcdi_rx_remove,
-       .rx_write = ef100_rx_write,
-       .rx_packet = __ef100_rx_packet,
-       .rx_buf_hash_valid = ef100_rx_buf_hash_valid,
-       .fini_dmaq = efx_fini_dmaq,
-       .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS,
-       .filter_table_probe = ef100_filter_table_up,
-       .filter_table_restore = efx_mcdi_filter_table_restore,
-       .filter_table_remove = ef100_filter_table_down,
-       .filter_insert = efx_mcdi_filter_insert,
-       .filter_remove_safe = efx_mcdi_filter_remove_safe,
-       .filter_get_safe = efx_mcdi_filter_get_safe,
-       .filter_clear_rx = efx_mcdi_filter_clear_rx,
-       .filter_count_rx_used = efx_mcdi_filter_count_rx_used,
-       .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit,
-       .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids,
-#ifdef CONFIG_RFS_ACCEL
-       .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one,
-#endif
-
-       .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN,
-       .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8,
-       .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8,
-       .rx_hash_key_size = 40,
-       .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
-       .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config,
-       .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts,
-       .rx_recycle_ring_size = efx_ef100_recycle_ring_size,
-
-       .reconfigure_mac = ef100_reconfigure_mac,
-       .test_nvram = efx_new_mcdi_nvram_test_all,
-       .describe_stats = ef100_describe_stats,
-       .start_stats = efx_mcdi_mac_start_stats,
-       .update_stats = ef100_update_stats,
-       .pull_stats = efx_mcdi_mac_pull_stats,
-       .stop_stats = efx_mcdi_mac_stop_stats,
-
-       .mem_bar = NULL,
-       .mem_map_size = NULL,
-
-};
-
 static int compare_versions(const char *a, const char *b)
 {
        int a_major, a_minor, a_point, a_patch;
@@ -1077,8 +905,7 @@ static int ef100_check_design_params(struct efx_nic *efx)
 
        efx_readd(efx, &reg, ER_GZ_PARAMS_TLV_LEN);
        total_len = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
-       netif_dbg(efx, probe, efx->net_dev, "%u bytes of design parameters\n",
-                 total_len);
+       pci_dbg(efx->pci_dev, "%u bytes of design parameters\n", total_len);
        while (offset < total_len) {
                efx_readd(efx, &reg, ER_GZ_PARAMS_TLV + offset);
                data = EFX_DWORD_FIELD(reg, EFX_DWORD_0);
@@ -1117,7 +944,6 @@ out:
 static int ef100_probe_main(struct efx_nic *efx)
 {
        unsigned int bar_size = resource_size(&efx->pci_dev->resource[efx->mem_bar]);
-       struct net_device *net_dev = efx->net_dev;
        struct ef100_nic_data *nic_data;
        char fw_version[32];
        int i, rc;
@@ -1130,24 +956,18 @@ static int ef100_probe_main(struct efx_nic *efx)
                return -ENOMEM;
        efx->nic_data = nic_data;
        nic_data->efx = efx;
-       net_dev->features |= efx->type->offload_features;
-       net_dev->hw_features |= efx->type->offload_features;
-       net_dev->hw_enc_features |= efx->type->offload_features;
-       net_dev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_SG |
-                                 NETIF_F_HIGHDMA | NETIF_F_ALL_TSO;
+       efx->max_vis = EF100_MAX_VIS;
 
        /* Populate design-parameter defaults */
        nic_data->tso_max_hdr_len = ESE_EF100_DP_GZ_TSO_MAX_HDR_LEN_DEFAULT;
        nic_data->tso_max_frames = ESE_EF100_DP_GZ_TSO_MAX_NUM_FRAMES_DEFAULT;
        nic_data->tso_max_payload_num_segs = ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_NUM_SEGS_DEFAULT;
        nic_data->tso_max_payload_len = ESE_EF100_DP_GZ_TSO_MAX_PAYLOAD_LEN_DEFAULT;
-       netif_set_tso_max_segs(net_dev,
-                              ESE_EF100_DP_GZ_TSO_MAX_HDR_NUM_SEGS_DEFAULT);
+
        /* Read design parameters */
        rc = ef100_check_design_params(efx);
        if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "Unsupported design parameters\n");
+               pci_err(efx->pci_dev, "Unsupported design parameters\n");
                goto fail;
        }
 
@@ -1184,12 +1004,6 @@ static int ef100_probe_main(struct efx_nic *efx)
        /* Post-IO section. */
 
        rc = efx_mcdi_init(efx);
-       if (!rc && efx->mcdi->fn_flags &
-                  (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_NO_ACTIVE_PORT)) {
-               netif_info(efx, probe, efx->net_dev,
-                          "No network port on this PCI function");
-               rc = -ENODEV;
-       }
        if (rc)
                goto fail;
        /* Reset (most) configuration for this function */
@@ -1205,67 +1019,37 @@ static int ef100_probe_main(struct efx_nic *efx)
        if (rc)
                goto fail;
 
-       rc = efx_ef100_init_datapath_caps(efx);
-       if (rc < 0)
-               goto fail;
-
-       efx->max_vis = EF100_MAX_VIS;
-
        rc = efx_mcdi_port_get_number(efx);
        if (rc < 0)
                goto fail;
        efx->port_num = rc;
 
        efx_mcdi_print_fwver(efx, fw_version, sizeof(fw_version));
-       netif_dbg(efx, drv, efx->net_dev, "Firmware version %s\n", fw_version);
+       pci_dbg(efx->pci_dev, "Firmware version %s\n", fw_version);
 
        if (compare_versions(fw_version, "1.1.0.1000") < 0) {
-               netif_info(efx, drv, efx->net_dev, "Firmware uses old event descriptors\n");
+               pci_info(efx->pci_dev, "Firmware uses old event descriptors\n");
                rc = -EINVAL;
                goto fail;
        }
 
        if (efx_has_cap(efx, UNSOL_EV_CREDIT_SUPPORTED)) {
-               netif_info(efx, drv, efx->net_dev, "Firmware uses unsolicited-event credits\n");
+               pci_info(efx->pci_dev, "Firmware uses unsolicited-event credits\n");
                rc = -EINVAL;
                goto fail;
        }
 
-       rc = ef100_phy_probe(efx);
-       if (rc)
-               goto fail;
-
-       down_write(&efx->filter_sem);
-       rc = ef100_filter_table_probe(efx);
-       up_write(&efx->filter_sem);
-       if (rc)
-               goto fail;
-
-       netdev_rss_key_fill(efx->rss_context.rx_hash_key,
-                           sizeof(efx->rss_context.rx_hash_key));
-
-       /* Don't fail init if RSS setup doesn't work. */
-       efx_mcdi_push_default_indir_table(efx, efx->n_rx_channels);
-
-       rc = ef100_register_netdev(efx);
-       if (rc)
-               goto fail;
-
        return 0;
 fail:
        return rc;
 }
 
-int ef100_probe_pf(struct efx_nic *efx)
+int ef100_probe_netdev_pf(struct efx_nic *efx)
 {
+       struct ef100_nic_data *nic_data = efx->nic_data;
        struct net_device *net_dev = efx->net_dev;
-       struct ef100_nic_data *nic_data;
-       int rc = ef100_probe_main(efx);
-
-       if (rc)
-               goto fail;
+       int rc;
 
-       nic_data = efx->nic_data;
        rc = ef100_get_mac_address(efx, net_dev->perm_addr);
        if (rc)
                goto fail;
@@ -1288,14 +1072,6 @@ void ef100_remove(struct efx_nic *efx)
 {
        struct ef100_nic_data *nic_data = efx->nic_data;
 
-       ef100_unregister_netdev(efx);
-
-       down_write(&efx->filter_sem);
-       efx_mcdi_filter_table_remove(efx);
-       up_write(&efx->filter_sem);
-       efx_fini_channels(efx);
-       kfree(efx->phy_data);
-       efx->phy_data = NULL;
        efx_mcdi_detach(efx);
        efx_mcdi_fini(efx);
        if (nic_data)
@@ -1303,3 +1079,175 @@ void ef100_remove(struct efx_nic *efx)
        kfree(nic_data);
        efx->nic_data = NULL;
 }
+
+/*     NIC level access functions
+ */
+#define EF100_OFFLOAD_FEATURES (NETIF_F_HW_CSUM | NETIF_F_RXCSUM |     \
+       NETIF_F_HIGHDMA | NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_NTUPLE | \
+       NETIF_F_RXHASH | NETIF_F_RXFCS | NETIF_F_TSO_ECN | NETIF_F_RXALL | \
+       NETIF_F_HW_VLAN_CTAG_TX)
+
+const struct efx_nic_type ef100_pf_nic_type = {
+       .revision = EFX_REV_EF100,
+       .is_vf = false,
+       .probe = ef100_probe_main,
+       .offload_features = EF100_OFFLOAD_FEATURES,
+       .mcdi_max_ver = 2,
+       .mcdi_request = ef100_mcdi_request,
+       .mcdi_poll_response = ef100_mcdi_poll_response,
+       .mcdi_read_response = ef100_mcdi_read_response,
+       .mcdi_poll_reboot = ef100_mcdi_poll_reboot,
+       .mcdi_reboot_detected = ef100_mcdi_reboot_detected,
+       .irq_enable_master = efx_port_dummy_op_void,
+       .irq_test_generate = efx_ef100_irq_test_generate,
+       .irq_disable_non_ev = efx_port_dummy_op_void,
+       .push_irq_moderation = efx_channel_dummy_op_void,
+       .min_interrupt_mode = EFX_INT_MODE_MSIX,
+       .map_reset_reason = ef100_map_reset_reason,
+       .map_reset_flags = ef100_map_reset_flags,
+       .reset = ef100_reset,
+
+       .check_caps = ef100_check_caps,
+
+       .ev_probe = ef100_ev_probe,
+       .ev_init = ef100_ev_init,
+       .ev_fini = efx_mcdi_ev_fini,
+       .ev_remove = efx_mcdi_ev_remove,
+       .irq_handle_msi = ef100_msi_interrupt,
+       .ev_process = ef100_ev_process,
+       .ev_read_ack = ef100_ev_read_ack,
+       .ev_test_generate = efx_ef100_ev_test_generate,
+       .tx_probe = ef100_tx_probe,
+       .tx_init = ef100_tx_init,
+       .tx_write = ef100_tx_write,
+       .tx_enqueue = ef100_enqueue_skb,
+       .rx_probe = efx_mcdi_rx_probe,
+       .rx_init = efx_mcdi_rx_init,
+       .rx_remove = efx_mcdi_rx_remove,
+       .rx_write = ef100_rx_write,
+       .rx_packet = __ef100_rx_packet,
+       .rx_buf_hash_valid = ef100_rx_buf_hash_valid,
+       .fini_dmaq = efx_fini_dmaq,
+       .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS,
+       .filter_table_probe = ef100_filter_table_up,
+       .filter_table_restore = efx_mcdi_filter_table_restore,
+       .filter_table_remove = ef100_filter_table_down,
+       .filter_insert = efx_mcdi_filter_insert,
+       .filter_remove_safe = efx_mcdi_filter_remove_safe,
+       .filter_get_safe = efx_mcdi_filter_get_safe,
+       .filter_clear_rx = efx_mcdi_filter_clear_rx,
+       .filter_count_rx_used = efx_mcdi_filter_count_rx_used,
+       .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit,
+       .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids,
+#ifdef CONFIG_RFS_ACCEL
+       .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one,
+#endif
+
+       .get_phys_port_id = efx_ef100_get_phys_port_id,
+
+       .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN,
+       .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8,
+       .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8,
+       .rx_hash_key_size = 40,
+       .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
+       .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config,
+       .rx_push_rss_context_config = efx_mcdi_rx_push_rss_context_config,
+       .rx_pull_rss_context_config = efx_mcdi_rx_pull_rss_context_config,
+       .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts,
+       .rx_recycle_ring_size = efx_ef100_recycle_ring_size,
+
+       .reconfigure_mac = ef100_reconfigure_mac,
+       .reconfigure_port = efx_mcdi_port_reconfigure,
+       .test_nvram = efx_new_mcdi_nvram_test_all,
+       .describe_stats = ef100_describe_stats,
+       .start_stats = efx_mcdi_mac_start_stats,
+       .update_stats = ef100_update_stats,
+       .pull_stats = efx_mcdi_mac_pull_stats,
+       .stop_stats = efx_mcdi_mac_stop_stats,
+#ifdef CONFIG_SFC_SRIOV
+       .sriov_configure = efx_ef100_sriov_configure,
+#endif
+
+       /* Per-type bar/size configuration not used on ef100. Location of
+        * registers is defined by extended capabilities.
+        */
+       .mem_bar = NULL,
+       .mem_map_size = NULL,
+
+};
+
+const struct efx_nic_type ef100_vf_nic_type = {
+       .revision = EFX_REV_EF100,
+       .is_vf = true,
+       .probe = ef100_probe_vf,
+       .offload_features = EF100_OFFLOAD_FEATURES,
+       .mcdi_max_ver = 2,
+       .mcdi_request = ef100_mcdi_request,
+       .mcdi_poll_response = ef100_mcdi_poll_response,
+       .mcdi_read_response = ef100_mcdi_read_response,
+       .mcdi_poll_reboot = ef100_mcdi_poll_reboot,
+       .mcdi_reboot_detected = ef100_mcdi_reboot_detected,
+       .irq_enable_master = efx_port_dummy_op_void,
+       .irq_test_generate = efx_ef100_irq_test_generate,
+       .irq_disable_non_ev = efx_port_dummy_op_void,
+       .push_irq_moderation = efx_channel_dummy_op_void,
+       .min_interrupt_mode = EFX_INT_MODE_MSIX,
+       .map_reset_reason = ef100_map_reset_reason,
+       .map_reset_flags = ef100_map_reset_flags,
+       .reset = ef100_reset,
+       .check_caps = ef100_check_caps,
+       .ev_probe = ef100_ev_probe,
+       .ev_init = ef100_ev_init,
+       .ev_fini = efx_mcdi_ev_fini,
+       .ev_remove = efx_mcdi_ev_remove,
+       .irq_handle_msi = ef100_msi_interrupt,
+       .ev_process = ef100_ev_process,
+       .ev_read_ack = ef100_ev_read_ack,
+       .ev_test_generate = efx_ef100_ev_test_generate,
+       .tx_probe = ef100_tx_probe,
+       .tx_init = ef100_tx_init,
+       .tx_write = ef100_tx_write,
+       .tx_enqueue = ef100_enqueue_skb,
+       .rx_probe = efx_mcdi_rx_probe,
+       .rx_init = efx_mcdi_rx_init,
+       .rx_remove = efx_mcdi_rx_remove,
+       .rx_write = ef100_rx_write,
+       .rx_packet = __ef100_rx_packet,
+       .rx_buf_hash_valid = ef100_rx_buf_hash_valid,
+       .fini_dmaq = efx_fini_dmaq,
+       .max_rx_ip_filters = EFX_MCDI_FILTER_TBL_ROWS,
+       .filter_table_probe = ef100_filter_table_up,
+       .filter_table_restore = efx_mcdi_filter_table_restore,
+       .filter_table_remove = ef100_filter_table_down,
+       .filter_insert = efx_mcdi_filter_insert,
+       .filter_remove_safe = efx_mcdi_filter_remove_safe,
+       .filter_get_safe = efx_mcdi_filter_get_safe,
+       .filter_clear_rx = efx_mcdi_filter_clear_rx,
+       .filter_count_rx_used = efx_mcdi_filter_count_rx_used,
+       .filter_get_rx_id_limit = efx_mcdi_filter_get_rx_id_limit,
+       .filter_get_rx_ids = efx_mcdi_filter_get_rx_ids,
+#ifdef CONFIG_RFS_ACCEL
+       .filter_rfs_expire_one = efx_mcdi_filter_rfs_expire_one,
+#endif
+
+       .rx_prefix_size = ESE_GZ_RX_PKT_PREFIX_LEN,
+       .rx_hash_offset = ESF_GZ_RX_PREFIX_RSS_HASH_LBN / 8,
+       .rx_ts_offset = ESF_GZ_RX_PREFIX_PARTIAL_TSTAMP_LBN / 8,
+       .rx_hash_key_size = 40,
+       .rx_pull_rss_config = efx_mcdi_rx_pull_rss_config,
+       .rx_push_rss_config = efx_mcdi_pf_rx_push_rss_config,
+       .rx_restore_rss_contexts = efx_mcdi_rx_restore_rss_contexts,
+       .rx_recycle_ring_size = efx_ef100_recycle_ring_size,
+
+       .reconfigure_mac = ef100_reconfigure_mac,
+       .test_nvram = efx_new_mcdi_nvram_test_all,
+       .describe_stats = ef100_describe_stats,
+       .start_stats = efx_mcdi_mac_start_stats,
+       .update_stats = ef100_update_stats,
+       .pull_stats = efx_mcdi_mac_pull_stats,
+       .stop_stats = efx_mcdi_mac_stop_stats,
+
+       .mem_bar = NULL,
+       .mem_map_size = NULL,
+
+};
index e799688..744dbbd 100644 (file)
@@ -8,6 +8,8 @@
  * under the terms of the GNU General Public License version 2 as published
  * by the Free Software Foundation, incorporated herein by reference.
  */
+#ifndef EFX_EF100_NIC_H
+#define EFX_EF100_NIC_H
 
 #include "net_driver.h"
 #include "nic_common.h"
@@ -15,7 +17,7 @@
 extern const struct efx_nic_type ef100_pf_nic_type;
 extern const struct efx_nic_type ef100_vf_nic_type;
 
-int ef100_probe_pf(struct efx_nic *efx);
+int ef100_probe_netdev_pf(struct efx_nic *efx);
 int ef100_probe_vf(struct efx_nic *efx);
 void ef100_remove(struct efx_nic *efx);
 
@@ -78,3 +80,9 @@ struct ef100_nic_data {
 
 #define efx_ef100_has_cap(caps, flag) \
        (!!((caps) & BIT_ULL(MC_CMD_GET_CAPABILITIES_V4_OUT_ ## flag ## _LBN)))
+
+int efx_ef100_init_datapath_caps(struct efx_nic *efx);
+int ef100_phy_probe(struct efx_nic *efx);
+int ef100_filter_table_probe(struct efx_nic *efx);
+
+#endif /* EFX_EF100_NIC_H */
index 5a77235..153d68e 100644 (file)
@@ -106,14 +106,6 @@ static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp);
 static int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs,
                        u32 flags);
 
-#define EFX_ASSERT_RESET_SERIALISED(efx)               \
-       do {                                            \
-               if ((efx->state == STATE_READY) ||      \
-                   (efx->state == STATE_RECOVERY) ||   \
-                   (efx->state == STATE_DISABLED))     \
-                       ASSERT_RTNL();                  \
-       } while (0)
-
 /**************************************************************************
  *
  * Port handling
@@ -378,6 +370,8 @@ static int efx_probe_all(struct efx_nic *efx)
        if (rc)
                goto fail5;
 
+       efx->state = STATE_NET_DOWN;
+
        return 0;
 
  fail5:
@@ -498,7 +492,7 @@ void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
  */
 static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct mii_ioctl_data *data = if_mii(ifr);
 
        if (cmd == SIOCSHWTSTAMP)
@@ -523,7 +517,7 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
 /* Context: process, rtnl_lock() held. */
 int efx_net_open(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        netif_dbg(efx, ifup, efx->net_dev, "opening device on CPU %d\n",
@@ -544,6 +538,9 @@ int efx_net_open(struct net_device *net_dev)
        efx_start_all(efx);
        if (efx->state == STATE_DISABLED || efx->reset_pending)
                netif_device_detach(efx->net_dev);
+       else
+               efx->state = STATE_NET_UP;
+
        efx_selftest_async_start(efx);
        return 0;
 }
@@ -554,7 +551,7 @@ int efx_net_open(struct net_device *net_dev)
  */
 int efx_net_stop(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        netif_dbg(efx, ifdown, efx->net_dev, "closing on CPU %d\n",
                  raw_smp_processor_id());
@@ -567,7 +564,7 @@ int efx_net_stop(struct net_device *net_dev)
 
 static int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->vlan_rx_add_vid)
                return efx->type->vlan_rx_add_vid(efx, proto, vid);
@@ -577,7 +574,7 @@ static int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid
 
 static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vid)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->vlan_rx_kill_vid)
                return efx->type->vlan_rx_kill_vid(efx, proto, vid);
@@ -646,7 +643,7 @@ static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog)
 /* Context: process, rtnl_lock() held. */
 static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp)
 {
-       struct efx_nic *efx = netdev_priv(dev);
+       struct efx_nic *efx = efx_netdev_priv(dev);
 
        switch (xdp->command) {
        case XDP_SETUP_PROG:
@@ -659,7 +656,7 @@ static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp)
 static int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs,
                        u32 flags)
 {
-       struct efx_nic *efx = netdev_priv(dev);
+       struct efx_nic *efx = efx_netdev_priv(dev);
 
        if (!netif_running(dev))
                return -EINVAL;
@@ -681,7 +678,7 @@ static int efx_netdev_event(struct notifier_block *this,
 
        if ((net_dev->netdev_ops == &efx_netdev_ops) &&
            event == NETDEV_CHANGENAME)
-               efx_update_name(netdev_priv(net_dev));
+               efx_update_name(efx_netdev_priv(net_dev));
 
        return NOTIFY_DONE;
 }
@@ -720,8 +717,6 @@ static int efx_register_netdev(struct efx_nic *efx)
         * already requested.  If so, the NIC is probably hosed so we
         * abort.
         */
-       efx->state = STATE_READY;
-       smp_mb(); /* ensure we change state before checking reset_pending */
        if (efx->reset_pending) {
                pci_err(efx->pci_dev, "aborting probe due to scheduled reset\n");
                rc = -EIO;
@@ -748,6 +743,8 @@ static int efx_register_netdev(struct efx_nic *efx)
 
        efx_associate(efx);
 
+       efx->state = STATE_NET_DOWN;
+
        rtnl_unlock();
 
        rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type);
@@ -777,7 +774,8 @@ static void efx_unregister_netdev(struct efx_nic *efx)
        if (!efx->net_dev)
                return;
 
-       BUG_ON(netdev_priv(efx->net_dev) != efx);
+       if (WARN_ON(efx_netdev_priv(efx->net_dev) != efx))
+               return;
 
        if (efx_dev_registered(efx)) {
                strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
@@ -845,7 +843,7 @@ static void efx_pci_remove_main(struct efx_nic *efx)
        /* Flush reset_work. It can no longer be scheduled since we
         * are not READY.
         */
-       BUG_ON(efx->state == STATE_READY);
+       WARN_ON(efx_net_active(efx->state));
        efx_flush_reset_workqueue(efx);
 
        efx_disable_interrupts(efx);
@@ -863,6 +861,7 @@ static void efx_pci_remove_main(struct efx_nic *efx)
  */
 static void efx_pci_remove(struct pci_dev *pci_dev)
 {
+       struct efx_probe_data *probe_data;
        struct efx_nic *efx;
 
        efx = pci_get_drvdata(pci_dev);
@@ -887,10 +886,12 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
        efx_pci_remove_main(efx);
 
        efx_fini_io(efx);
-       netif_dbg(efx, drv, efx->net_dev, "shutdown successful\n");
+       pci_dbg(efx->pci_dev, "shutdown successful\n");
 
        efx_fini_struct(efx);
        free_netdev(efx->net_dev);
+       probe_data = container_of(efx, struct efx_probe_data, efx);
+       kfree(probe_data);
 
        pci_disable_pcie_error_reporting(pci_dev);
 };
@@ -1044,24 +1045,34 @@ static int efx_pci_probe_post_io(struct efx_nic *efx)
 static int efx_pci_probe(struct pci_dev *pci_dev,
                         const struct pci_device_id *entry)
 {
+       struct efx_probe_data *probe_data, **probe_ptr;
        struct net_device *net_dev;
        struct efx_nic *efx;
        int rc;
 
-       /* Allocate and initialise a struct net_device and struct efx_nic */
-       net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES,
-                                    EFX_MAX_RX_QUEUES);
+       /* Allocate probe data and struct efx_nic */
+       probe_data = kzalloc(sizeof(*probe_data), GFP_KERNEL);
+       if (!probe_data)
+               return -ENOMEM;
+       probe_data->pci_dev = pci_dev;
+       efx = &probe_data->efx;
+
+       /* Allocate and initialise a struct net_device */
+       net_dev = alloc_etherdev_mq(sizeof(probe_data), EFX_MAX_CORE_TX_QUEUES);
        if (!net_dev)
                return -ENOMEM;
-       efx = netdev_priv(net_dev);
+       probe_ptr = netdev_priv(net_dev);
+       *probe_ptr = probe_data;
+       efx->net_dev = net_dev;
        efx->type = (const struct efx_nic_type *) entry->driver_data;
        efx->fixed_features |= NETIF_F_HIGHDMA;
 
        pci_set_drvdata(pci_dev, efx);
        SET_NETDEV_DEV(net_dev, &pci_dev->dev);
-       rc = efx_init_struct(efx, pci_dev, net_dev);
+       rc = efx_init_struct(efx, pci_dev);
        if (rc)
                goto fail1;
+       efx->mdio.dev = net_dev;
 
        pci_info(pci_dev, "Solarflare NIC detected\n");
 
@@ -1150,13 +1161,13 @@ static int efx_pm_freeze(struct device *dev)
 
        rtnl_lock();
 
-       if (efx->state != STATE_DISABLED) {
-               efx->state = STATE_UNINIT;
-
+       if (efx_net_active(efx->state)) {
                efx_device_detach_sync(efx);
 
                efx_stop_all(efx);
                efx_disable_interrupts(efx);
+
+               efx->state = efx_freeze(efx->state);
        }
 
        rtnl_unlock();
@@ -1171,7 +1182,7 @@ static int efx_pm_thaw(struct device *dev)
 
        rtnl_lock();
 
-       if (efx->state != STATE_DISABLED) {
+       if (efx_frozen(efx->state)) {
                rc = efx_enable_interrupts(efx);
                if (rc)
                        goto fail;
@@ -1184,7 +1195,7 @@ static int efx_pm_thaw(struct device *dev)
 
                efx_device_attach_if_not_resetting(efx);
 
-               efx->state = STATE_READY;
+               efx->state = efx_thaw(efx->state);
 
                efx->type->resume_wol(efx);
        }
index f6577e7..56eb717 100644 (file)
@@ -167,7 +167,7 @@ static void efx_mac_work(struct work_struct *data)
 
 int efx_set_mac_address(struct net_device *net_dev, void *data)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct sockaddr *addr = data;
        u8 *new_addr = addr->sa_data;
        u8 old_addr[6];
@@ -202,7 +202,7 @@ int efx_set_mac_address(struct net_device *net_dev, void *data)
 /* Context: netif_addr_lock held, BHs disabled. */
 void efx_set_rx_mode(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->port_enabled)
                queue_work(efx->workqueue, &efx->mac_work);
@@ -211,7 +211,7 @@ void efx_set_rx_mode(struct net_device *net_dev)
 
 int efx_set_features(struct net_device *net_dev, netdev_features_t data)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        /* If disabling RX n-tuple filtering, clear existing filters */
@@ -285,7 +285,7 @@ unsigned int efx_xdp_max_mtu(struct efx_nic *efx)
 /* Context: process, rtnl_lock() held. */
 int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        rc = efx_check_disabled(efx);
@@ -600,7 +600,7 @@ void efx_stop_all(struct efx_nic *efx)
 /* Context: process, dev_base_lock or RTNL held, non-blocking. */
 void efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        spin_lock_bh(&efx->stats_lock);
        efx_nic_update_stats_atomic(efx, NULL, stats);
@@ -723,7 +723,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
 /* Context: netif_tx_lock held, BHs disabled. */
 void efx_watchdog(struct net_device *net_dev, unsigned int txqueue)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        netif_err(efx, tx_err, efx->net_dev,
                  "TX stuck with port_enabled=%d: resetting channels\n",
@@ -898,7 +898,7 @@ static void efx_reset_work(struct work_struct *data)
         * have changed by now.  Now that we have the RTNL lock,
         * it cannot change again.
         */
-       if (efx->state == STATE_READY)
+       if (efx_net_active(efx->state))
                (void)efx_reset(efx, method);
 
        rtnl_unlock();
@@ -908,7 +908,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
 {
        enum reset_type method;
 
-       if (efx->state == STATE_RECOVERY) {
+       if (efx_recovering(efx->state)) {
                netif_dbg(efx, drv, efx->net_dev,
                          "recovering: skip scheduling %s reset\n",
                          RESET_TYPE(type));
@@ -943,7 +943,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
        /* If we're not READY then just leave the flags set as the cue
         * to abort probing or reschedule the reset later.
         */
-       if (READ_ONCE(efx->state) != STATE_READY)
+       if (!efx_net_active(READ_ONCE(efx->state)))
                return;
 
        /* efx_process_channel() will no longer read events once a
@@ -978,8 +978,7 @@ void efx_port_dummy_op_void(struct efx_nic *efx) {}
 /* This zeroes out and then fills in the invariants in a struct
  * efx_nic (including all sub-structures).
  */
-int efx_init_struct(struct efx_nic *efx,
-                   struct pci_dev *pci_dev, struct net_device *net_dev)
+int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev)
 {
        int rc = -ENOMEM;
 
@@ -998,7 +997,6 @@ int efx_init_struct(struct efx_nic *efx,
        efx->state = STATE_UNINIT;
        strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
 
-       efx->net_dev = net_dev;
        efx->rx_prefix_size = efx->type->rx_prefix_size;
        efx->rx_ip_align =
                NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0;
@@ -1023,7 +1021,6 @@ int efx_init_struct(struct efx_nic *efx,
        efx->rps_hash_table = kcalloc(EFX_ARFS_HASH_TABLE_SIZE,
                                      sizeof(*efx->rps_hash_table), GFP_KERNEL);
 #endif
-       efx->mdio.dev = net_dev;
        INIT_WORK(&efx->mac_work, efx_mac_work);
        init_waitqueue_head(&efx->flush_wq);
 
@@ -1077,13 +1074,11 @@ int efx_init_io(struct efx_nic *efx, int bar, dma_addr_t dma_mask,
        int rc;
 
        efx->mem_bar = UINT_MAX;
-
-       netif_dbg(efx, probe, efx->net_dev, "initialising I/O bar=%d\n", bar);
+       pci_dbg(pci_dev, "initialising I/O bar=%d\n", bar);
 
        rc = pci_enable_device(pci_dev);
        if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "failed to enable PCI device\n");
+               pci_err(pci_dev, "failed to enable PCI device\n");
                goto fail1;
        }
 
@@ -1091,42 +1086,40 @@ int efx_init_io(struct efx_nic *efx, int bar, dma_addr_t dma_mask,
 
        rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask);
        if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "could not find a suitable DMA mask\n");
+               pci_err(efx->pci_dev, "could not find a suitable DMA mask\n");
                goto fail2;
        }
-       netif_dbg(efx, probe, efx->net_dev,
-                 "using DMA mask %llx\n", (unsigned long long)dma_mask);
+       pci_dbg(efx->pci_dev, "using DMA mask %llx\n", (unsigned long long)dma_mask);
 
        efx->membase_phys = pci_resource_start(efx->pci_dev, bar);
        if (!efx->membase_phys) {
-               netif_err(efx, probe, efx->net_dev,
-                         "ERROR: No BAR%d mapping from the BIOS. "
-                         "Try pci=realloc on the kernel command line\n", bar);
+               pci_err(efx->pci_dev,
+                       "ERROR: No BAR%d mapping from the BIOS. Try pci=realloc on the kernel command line\n",
+                       bar);
                rc = -ENODEV;
                goto fail3;
        }
 
        rc = pci_request_region(pci_dev, bar, "sfc");
        if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "request for memory BAR[%d] failed\n", bar);
+               pci_err(efx->pci_dev,
+                       "request for memory BAR[%d] failed\n", bar);
                rc = -EIO;
                goto fail3;
        }
        efx->mem_bar = bar;
        efx->membase = ioremap(efx->membase_phys, mem_map_size);
        if (!efx->membase) {
-               netif_err(efx, probe, efx->net_dev,
-                         "could not map memory BAR[%d] at %llx+%x\n", bar,
-                         (unsigned long long)efx->membase_phys, mem_map_size);
+               pci_err(efx->pci_dev,
+                       "could not map memory BAR[%d] at %llx+%x\n", bar,
+                       (unsigned long long)efx->membase_phys, mem_map_size);
                rc = -ENOMEM;
                goto fail4;
        }
-       netif_dbg(efx, probe, efx->net_dev,
-                 "memory BAR[%d] at %llx+%x (virtual %p)\n", bar,
-                 (unsigned long long)efx->membase_phys, mem_map_size,
-                 efx->membase);
+       pci_dbg(efx->pci_dev,
+               "memory BAR[%d] at %llx+%x (virtual %p)\n", bar,
+               (unsigned long long)efx->membase_phys, mem_map_size,
+               efx->membase);
 
        return 0;
 
@@ -1142,7 +1135,7 @@ fail1:
 
 void efx_fini_io(struct efx_nic *efx)
 {
-       netif_dbg(efx, drv, efx->net_dev, "shutting down I/O\n");
+       pci_dbg(efx->pci_dev, "shutting down I/O\n");
 
        if (efx->membase) {
                iounmap(efx->membase);
@@ -1217,13 +1210,15 @@ static pci_ers_result_t efx_io_error_detected(struct pci_dev *pdev,
        rtnl_lock();
 
        if (efx->state != STATE_DISABLED) {
-               efx->state = STATE_RECOVERY;
+               efx->state = efx_recover(efx->state);
                efx->reset_pending = 0;
 
                efx_device_detach_sync(efx);
 
-               efx_stop_all(efx);
-               efx_disable_interrupts(efx);
+               if (efx_net_active(efx->state)) {
+                       efx_stop_all(efx);
+                       efx_disable_interrupts(efx);
+               }
 
                status = PCI_ERS_RESULT_NEED_RESET;
        } else {
@@ -1271,7 +1266,7 @@ static void efx_io_resume(struct pci_dev *pdev)
                netif_err(efx, hw, efx->net_dev,
                          "efx_reset failed after PCI error (%d)\n", rc);
        } else {
-               efx->state = STATE_READY;
+               efx->state = efx_recovered(efx->state);
                netif_dbg(efx, hw, efx->net_dev,
                          "Done resetting and resuming IO after PCI error.\n");
        }
@@ -1357,7 +1352,7 @@ static bool efx_can_encap_offloads(struct efx_nic *efx, struct sk_buff *skb)
 netdev_features_t efx_features_check(struct sk_buff *skb, struct net_device *dev,
                                     netdev_features_t features)
 {
-       struct efx_nic *efx = netdev_priv(dev);
+       struct efx_nic *efx = efx_netdev_priv(dev);
 
        if (skb->encapsulation) {
                if (features & NETIF_F_GSO_MASK)
@@ -1378,7 +1373,7 @@ netdev_features_t efx_features_check(struct sk_buff *skb, struct net_device *dev
 int efx_get_phys_port_id(struct net_device *net_dev,
                         struct netdev_phys_item_id *ppid)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->get_phys_port_id)
                return efx->type->get_phys_port_id(efx, ppid);
@@ -1388,7 +1383,7 @@ int efx_get_phys_port_id(struct net_device *net_dev,
 
 int efx_get_phys_port_name(struct net_device *net_dev, char *name, size_t len)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (snprintf(name, len, "p%u", efx->port_num) >= len)
                return -EINVAL;
index 65513fd..93babc1 100644 (file)
@@ -14,8 +14,7 @@
 int efx_init_io(struct efx_nic *efx, int bar, dma_addr_t dma_mask,
                unsigned int mem_map_size);
 void efx_fini_io(struct efx_nic *efx);
-int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev,
-                   struct net_device *net_dev);
+int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev);
 void efx_fini_struct(struct efx_nic *efx);
 
 #define EFX_MAX_DMAQ_SIZE 4096UL
@@ -43,12 +42,11 @@ void efx_start_monitor(struct efx_nic *efx);
 int __efx_reconfigure_port(struct efx_nic *efx);
 int efx_reconfigure_port(struct efx_nic *efx);
 
-#define EFX_ASSERT_RESET_SERIALISED(efx)               \
-       do {                                            \
-               if ((efx->state == STATE_READY) ||      \
-                   (efx->state == STATE_RECOVERY) ||   \
-                   (efx->state == STATE_DISABLED))     \
-                       ASSERT_RTNL();                  \
+#define EFX_ASSERT_RESET_SERIALISED(efx)                               \
+       do {                                                            \
+               if ((efx)->state != STATE_UNINIT &&                     \
+                   (efx)->state != STATE_PROBED)                       \
+                       ASSERT_RTNL();                                  \
        } while (0)
 
 int efx_try_recovery(struct efx_nic *efx);
@@ -64,7 +62,7 @@ void efx_port_dummy_op_void(struct efx_nic *efx);
 
 static inline int efx_check_disabled(struct efx_nic *efx)
 {
-       if (efx->state == STATE_DISABLED || efx->state == STATE_RECOVERY) {
+       if (efx->state == STATE_DISABLED || efx_recovering(efx->state)) {
                netif_err(efx, drv, efx->net_dev,
                          "device is disabled due to earlier errors\n");
                return -EIO;
index 4850637..3643235 100644 (file)
@@ -33,7 +33,7 @@
 static int efx_ethtool_phys_id(struct net_device *net_dev,
                               enum ethtool_phys_id_state state)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        enum efx_led_mode mode = EFX_LED_DEFAULT;
 
        switch (state) {
@@ -55,13 +55,13 @@ static int efx_ethtool_phys_id(struct net_device *net_dev,
 
 static int efx_ethtool_get_regs_len(struct net_device *net_dev)
 {
-       return efx_nic_get_regs_len(netdev_priv(net_dev));
+       return efx_nic_get_regs_len(efx_netdev_priv(net_dev));
 }
 
 static void efx_ethtool_get_regs(struct net_device *net_dev,
                                 struct ethtool_regs *regs, void *buf)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        regs->version = efx->type->revision;
        efx_nic_get_regs(efx, buf);
@@ -101,7 +101,7 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
                                    struct kernel_ethtool_coalesce *kernel_coal,
                                    struct netlink_ext_ack *extack)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        unsigned int tx_usecs, rx_usecs;
        bool rx_adaptive;
 
@@ -121,7 +121,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
                                    struct kernel_ethtool_coalesce *kernel_coal,
                                    struct netlink_ext_ack *extack)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_channel *channel;
        unsigned int tx_usecs, rx_usecs;
        bool adaptive, rx_may_override_tx;
@@ -163,7 +163,7 @@ efx_ethtool_get_ringparam(struct net_device *net_dev,
                          struct kernel_ethtool_ringparam *kernel_ring,
                          struct netlink_ext_ack *extack)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        ring->rx_max_pending = EFX_MAX_DMAQ_SIZE;
        ring->tx_max_pending = EFX_TXQ_MAX_ENT(efx);
@@ -177,7 +177,7 @@ efx_ethtool_set_ringparam(struct net_device *net_dev,
                          struct kernel_ethtool_ringparam *kernel_ring,
                          struct netlink_ext_ack *extack)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        u32 txq_entries;
 
        if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
@@ -204,7 +204,7 @@ efx_ethtool_set_ringparam(struct net_device *net_dev,
 static void efx_ethtool_get_wol(struct net_device *net_dev,
                                struct ethtool_wolinfo *wol)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        return efx->type->get_wol(efx, wol);
 }
 
@@ -212,14 +212,14 @@ static void efx_ethtool_get_wol(struct net_device *net_dev,
 static int efx_ethtool_set_wol(struct net_device *net_dev,
                               struct ethtool_wolinfo *wol)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        return efx->type->set_wol(efx, wol->wolopts);
 }
 
 static void efx_ethtool_get_fec_stats(struct net_device *net_dev,
                                      struct ethtool_fec_stats *fec_stats)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->get_fec_stats)
                efx->type->get_fec_stats(efx, fec_stats);
@@ -228,7 +228,7 @@ static void efx_ethtool_get_fec_stats(struct net_device *net_dev,
 static int efx_ethtool_get_ts_info(struct net_device *net_dev,
                                   struct ethtool_ts_info *ts_info)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        /* Software capabilities */
        ts_info->so_timestamping = (SOF_TIMESTAMPING_RX_SOFTWARE |
index bd552c7..58ad9d6 100644 (file)
@@ -103,7 +103,7 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {
 void efx_ethtool_get_drvinfo(struct net_device *net_dev,
                             struct ethtool_drvinfo *info)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
        efx_mcdi_print_fwver(efx, info->fw_version,
@@ -113,14 +113,14 @@ void efx_ethtool_get_drvinfo(struct net_device *net_dev,
 
 u32 efx_ethtool_get_msglevel(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        return efx->msg_enable;
 }
 
 void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        efx->msg_enable = msg_enable;
 }
@@ -128,7 +128,7 @@ void efx_ethtool_set_msglevel(struct net_device *net_dev, u32 msg_enable)
 void efx_ethtool_self_test(struct net_device *net_dev,
                           struct ethtool_test *test, u64 *data)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_self_tests *efx_tests;
        bool already_up;
        int rc = -ENOMEM;
@@ -137,7 +137,7 @@ void efx_ethtool_self_test(struct net_device *net_dev,
        if (!efx_tests)
                goto fail;
 
-       if (efx->state != STATE_READY) {
+       if (!efx_net_active(efx->state)) {
                rc = -EBUSY;
                goto out;
        }
@@ -176,7 +176,7 @@ fail:
 void efx_ethtool_get_pauseparam(struct net_device *net_dev,
                                struct ethtool_pauseparam *pause)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX);
        pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX);
@@ -186,7 +186,7 @@ void efx_ethtool_get_pauseparam(struct net_device *net_dev,
 int efx_ethtool_set_pauseparam(struct net_device *net_dev,
                               struct ethtool_pauseparam *pause)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        u8 wanted_fc, old_fc;
        u32 old_adv;
        int rc = 0;
@@ -441,7 +441,7 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings)
 
 int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        switch (string_set) {
        case ETH_SS_STATS:
@@ -459,7 +459,7 @@ int efx_ethtool_get_sset_count(struct net_device *net_dev, int string_set)
 void efx_ethtool_get_strings(struct net_device *net_dev,
                             u32 string_set, u8 *strings)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int i;
 
        switch (string_set) {
@@ -487,7 +487,7 @@ void efx_ethtool_get_stats(struct net_device *net_dev,
                           struct ethtool_stats *stats,
                           u64 *data)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        const struct efx_sw_stat_desc *stat;
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
@@ -561,7 +561,7 @@ void efx_ethtool_get_stats(struct net_device *net_dev,
 int efx_ethtool_get_link_ksettings(struct net_device *net_dev,
                                   struct ethtool_link_ksettings *cmd)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_link_state *link_state = &efx->link_state;
 
        mutex_lock(&efx->mac_lock);
@@ -584,7 +584,7 @@ int efx_ethtool_get_link_ksettings(struct net_device *net_dev,
 int efx_ethtool_set_link_ksettings(struct net_device *net_dev,
                                   const struct ethtool_link_ksettings *cmd)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        /* GMAC does not support 1000Mbps HD */
@@ -604,7 +604,7 @@ int efx_ethtool_set_link_ksettings(struct net_device *net_dev,
 int efx_ethtool_get_fecparam(struct net_device *net_dev,
                             struct ethtool_fecparam *fecparam)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        mutex_lock(&efx->mac_lock);
@@ -617,7 +617,7 @@ int efx_ethtool_get_fecparam(struct net_device *net_dev,
 int efx_ethtool_set_fecparam(struct net_device *net_dev,
                             struct ethtool_fecparam *fecparam)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        mutex_lock(&efx->mac_lock);
@@ -809,7 +809,7 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
 int efx_ethtool_get_rxnfc(struct net_device *net_dev,
                          struct ethtool_rxnfc *info, u32 *rule_locs)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        u32 rss_context = 0;
        s32 rc = 0;
 
@@ -1127,7 +1127,7 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
 int efx_ethtool_set_rxnfc(struct net_device *net_dev,
                          struct ethtool_rxnfc *info)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx_filter_get_rx_id_limit(efx) == 0)
                return -EOPNOTSUPP;
@@ -1148,7 +1148,7 @@ int efx_ethtool_set_rxnfc(struct net_device *net_dev,
 
 u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->n_rx_channels == 1)
                return 0;
@@ -1157,7 +1157,7 @@ u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
 
 u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        return efx->type->rx_hash_key_size;
 }
@@ -1165,7 +1165,7 @@ u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)
 int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
                         u8 *hfunc)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        rc = efx->type->rx_pull_rss_config(efx);
@@ -1186,7 +1186,7 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
 int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
                         const u8 *key, const u8 hfunc)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        /* Hash function is Toeplitz, cannot be changed */
        if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
@@ -1205,7 +1205,7 @@ int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
 int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
                                 u8 *key, u8 *hfunc, u32 rss_context)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_rss_context *ctx;
        int rc = 0;
 
@@ -1238,7 +1238,7 @@ int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
                                 const u8 hfunc, u32 *rss_context,
                                 bool delete)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_rss_context *ctx;
        bool allocated = false;
        int rc;
@@ -1300,7 +1300,7 @@ out_unlock:
 
 int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int rc;
 
        rc = efx->type->map_reset_flags(flags);
@@ -1314,7 +1314,7 @@ int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
                                  struct ethtool_eeprom *ee,
                                  u8 *data)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int ret;
 
        mutex_lock(&efx->mac_lock);
@@ -1327,7 +1327,7 @@ int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
 int efx_ethtool_get_module_info(struct net_device *net_dev,
                                struct ethtool_modinfo *modinfo)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        int ret;
 
        mutex_lock(&efx->mac_lock);
index 5eb178d..78537a5 100644 (file)
@@ -117,7 +117,7 @@ typedef union ef4_oword {
  *
  *   ( element ) << 4
  *
- * The result will contain the relevant bits filled in in the range
+ * The result will contain the relevant bits filled in the range
  * [0,high-low), with garbage in bits [high-low+1,...).
  */
 #define EF4_EXTRACT_NATIVE(native_element, min, max, low, high)                \
index 2c91792..c64623c 100644 (file)
@@ -2711,7 +2711,7 @@ void ef4_farch_filter_table_remove(struct ef4_nic *efx)
        enum ef4_farch_filter_table_id table_id;
 
        for (table_id = 0; table_id < EF4_FARCH_FILTER_TABLE_COUNT; table_id++) {
-               kfree(state->table[table_id].used_bitmap);
+               bitmap_free(state->table[table_id].used_bitmap);
                vfree(state->table[table_id].spec);
        }
        kfree(state);
@@ -2740,9 +2740,7 @@ int ef4_farch_filter_table_probe(struct ef4_nic *efx)
                table = &state->table[table_id];
                if (table->size == 0)
                        continue;
-               table->used_bitmap = kcalloc(BITS_TO_LONGS(table->size),
-                                            sizeof(unsigned long),
-                                            GFP_KERNEL);
+               table->used_bitmap = bitmap_zalloc(table->size, GFP_KERNEL);
                if (!table->used_bitmap)
                        goto fail;
                table->spec = vzalloc(array_size(sizeof(*table->spec),
index 50baf62..3225fe6 100644 (file)
@@ -99,14 +99,12 @@ int efx_mcdi_init(struct efx_nic *efx)
         */
        rc = efx_mcdi_drv_attach(efx, true, &already_attached);
        if (rc) {
-               netif_err(efx, probe, efx->net_dev,
-                         "Unable to register driver with MCPU\n");
+               pci_err(efx->pci_dev, "Unable to register driver with MCPU\n");
                goto fail2;
        }
        if (already_attached)
                /* Not a fatal error */
-               netif_err(efx, probe, efx->net_dev,
-                         "Host already registered with MCPU\n");
+               pci_err(efx->pci_dev, "Host already registered with MCPU\n");
 
        if (efx->mcdi->fn_flags &
            (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY))
@@ -1261,7 +1259,7 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
 }
 
 /* The MC is going down in to BIST mode. set the BIST flag to block
- * new MCDI, cancel any outstanding MCDI and and schedule a BIST-type reset
+ * new MCDI, cancel any outstanding MCDI and schedule a BIST-type reset
  * (which doesn't actually execute a reset, it waits for the controlling
  * function to reset it).
  */
@@ -1447,7 +1445,7 @@ void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
        return;
 
 fail:
-       netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
+       pci_err(efx->pci_dev, "%s: failed rc=%d\n", __func__, rc);
        buf[0] = 0;
 }
 
@@ -1471,8 +1469,9 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
         * care what firmware we get.
         */
        if (rc == -EPERM) {
-               netif_dbg(efx, probe, efx->net_dev,
-                         "efx_mcdi_drv_attach with fw-variant setting failed EPERM, trying without it\n");
+               pci_dbg(efx->pci_dev,
+                       "%s with fw-variant setting failed EPERM, trying without it\n",
+                       __func__);
                MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_FIRMWARE_ID,
                               MC_CMD_FW_DONT_CARE);
                rc = efx_mcdi_rpc_quiet(efx, MC_CMD_DRV_ATTACH, inbuf,
@@ -1514,7 +1513,7 @@ static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
        return 0;
 
 fail:
-       netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
+       pci_err(efx->pci_dev, "%s: failed rc=%d\n", __func__, rc);
        return rc;
 }
 
index ff617b1..7984f6f 100644 (file)
  * MC_CMD_WORKAROUND_BUG26807.
  * May also returned for other operations such as sub-variant switching. */
 #define MC_CMD_ERR_FILTERS_PRESENT 0x1014
-/* The clock whose frequency you've attempted to set set
+/* The clock whose frequency you've attempted to set
  * doesn't exist on this NIC */
 #define MC_CMD_ERR_NO_CLOCK 0x1015
 /* Returned by MC_CMD_TESTASSERT if the action that should
  * large number (253) it is not anticipated that this will be needed in the
  * near future, so can currently be ignored.
  *
- * On Riverhead this command is implemented as a wrapper for `list` in the
+ * On Riverhead this command is implemented as a wrapper for `list` in the
  * sensor_query SPHINX service.
  */
 #define MC_CMD_DYNAMIC_SENSORS_LIST 0x66
  * update is in progress, and effectively means the set of usable sensors is
  * the intersection between the sets of sensors known to the driver and the MC.
  *
- * On Riverhead this command is implemented as a wrapper for
+ * On Riverhead this command is implemented as a wrapper for
  * `get_descriptions` in the sensor_query SPHINX service.
  */
 #define MC_CMD_DYNAMIC_SENSORS_GET_DESCRIPTIONS 0x67
  * update is in progress, and effectively means the set of usable sensors is
  * the intersection between the sets of sensors known to the driver and the MC.
  *
- * On Riverhead this command is implemented as a wrapper for `get_readings`
+ * On Riverhead this command is implemented as a wrapper for `get_readings`
  * in the sensor_query SPHINX service.
  */
 #define MC_CMD_DYNAMIC_SENSORS_GET_READINGS 0x68
  * TLV_PORT_MODE_*). A superset of MC_CMD_GET_PORT_MODES_OUT/MODES that
  * contains all modes implemented in firmware for a particular board. Modes
  * listed in MODES are considered production modes and should be exposed in
- * userland tools. Modes listed in in ENGINEERING_MODES, but not in MODES
+ * userland tools. Modes listed in ENGINEERING_MODES, but not in MODES
  * should be considered hidden (not to be exposed in userland tools) and for
  * engineering use only. There are no other semantic differences and any mode
  * listed in either MODES or ENGINEERING_MODES can be set on the board.
index 94c6a34..ad4694f 100644 (file)
@@ -20,7 +20,7 @@
 static int efx_mcdi_mdio_read(struct net_device *net_dev,
                              int prtad, int devad, u16 addr)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_READ_IN_LEN);
        MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_READ_OUT_LEN);
        size_t outlen;
@@ -46,7 +46,7 @@ static int efx_mcdi_mdio_read(struct net_device *net_dev,
 static int efx_mcdi_mdio_write(struct net_device *net_dev,
                               int prtad, int devad, u16 addr, u16 value)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_WRITE_IN_LEN);
        MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_WRITE_OUT_LEN);
        size_t outlen;
index 723bbee..2228c88 100644 (file)
@@ -622,12 +622,55 @@ enum efx_int_mode {
 #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
 
 enum nic_state {
-       STATE_UNINIT = 0,       /* device being probed/removed or is frozen */
-       STATE_READY = 1,        /* hardware ready and netdev registered */
-       STATE_DISABLED = 2,     /* device disabled due to hardware errors */
-       STATE_RECOVERY = 3,     /* device recovering from PCI error */
+       STATE_UNINIT = 0,       /* device being probed/removed */
+       STATE_PROBED,           /* hardware probed */
+       STATE_NET_DOWN,         /* netdev registered */
+       STATE_NET_UP,           /* ready for traffic */
+       STATE_DISABLED,         /* device disabled due to hardware errors */
+
+       STATE_RECOVERY = 0x100,/* recovering from PCI error */
+       STATE_FROZEN = 0x200,   /* frozen by power management */
 };
 
+static inline bool efx_net_active(enum nic_state state)
+{
+       return state == STATE_NET_DOWN || state == STATE_NET_UP;
+}
+
+static inline bool efx_frozen(enum nic_state state)
+{
+       return state & STATE_FROZEN;
+}
+
+static inline bool efx_recovering(enum nic_state state)
+{
+       return state & STATE_RECOVERY;
+}
+
+static inline enum nic_state efx_freeze(enum nic_state state)
+{
+       WARN_ON(!efx_net_active(state));
+       return state | STATE_FROZEN;
+}
+
+static inline enum nic_state efx_thaw(enum nic_state state)
+{
+       WARN_ON(!efx_frozen(state));
+       return state & ~STATE_FROZEN;
+}
+
+static inline enum nic_state efx_recover(enum nic_state state)
+{
+       WARN_ON(!efx_net_active(state));
+       return state | STATE_RECOVERY;
+}
+
+static inline enum nic_state efx_recovered(enum nic_state state)
+{
+       WARN_ON(!efx_recovering(state));
+       return state & ~STATE_RECOVERY;
+}
+
 /* Forward declaration */
 struct efx_nic;
 
@@ -1123,6 +1166,24 @@ struct efx_nic {
        atomic_t n_rx_noskb_drops;
 };
 
+/**
+ * struct efx_probe_data - State after hardware probe
+ * @pci_dev: The PCI device
+ * @efx: Efx NIC details
+ */
+struct efx_probe_data {
+       struct pci_dev *pci_dev;
+       struct efx_nic efx;
+};
+
+static inline struct efx_nic *efx_netdev_priv(struct net_device *dev)
+{
+       struct efx_probe_data **probe_ptr = netdev_priv(dev);
+       struct efx_probe_data *probe_data = *probe_ptr;
+
+       return &probe_data->efx;
+}
+
 static inline int efx_dev_registered(struct efx_nic *efx)
 {
        return efx->net_dev->reg_state == NETREG_REGISTERED;
index fa8b9aa..bd21d6a 100644 (file)
@@ -857,7 +857,7 @@ static void efx_filter_rfs_work(struct work_struct *data)
 {
        struct efx_async_filter_insertion *req = container_of(data, struct efx_async_filter_insertion,
                                                              work);
-       struct efx_nic *efx = netdev_priv(req->net_dev);
+       struct efx_nic *efx = efx_netdev_priv(req->net_dev);
        struct efx_channel *channel = efx_get_channel(efx, req->rxq_index);
        int slot_idx = req - efx->rps_slot;
        struct efx_arfs_rule *rule;
@@ -942,7 +942,7 @@ static void efx_filter_rfs_work(struct work_struct *data)
 int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
                   u16 rxq_index, u32 flow_id)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_async_filter_insertion *req;
        struct efx_arfs_rule *rule;
        struct flow_keys fk;
index cce2380..89ccd65 100644 (file)
@@ -2778,7 +2778,7 @@ void efx_farch_filter_table_remove(struct efx_nic *efx)
        enum efx_farch_filter_table_id table_id;
 
        for (table_id = 0; table_id < EFX_FARCH_FILTER_TABLE_COUNT; table_id++) {
-               kfree(state->table[table_id].used_bitmap);
+               bitmap_free(state->table[table_id].used_bitmap);
                vfree(state->table[table_id].spec);
        }
        kfree(state);
@@ -2822,9 +2822,7 @@ int efx_farch_filter_table_probe(struct efx_nic *efx)
                table = &state->table[table_id];
                if (table->size == 0)
                        continue;
-               table->used_bitmap = kcalloc(BITS_TO_LONGS(table->size),
-                                            sizeof(unsigned long),
-                                            GFP_KERNEL);
+               table->used_bitmap = bitmap_zalloc(table->size, GFP_KERNEL);
                if (!table->used_bitmap)
                        goto fail;
                table->spec = vzalloc(array_size(sizeof(*table->spec),
index 3df0f0e..3f7899d 100644 (file)
@@ -1264,7 +1264,7 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
 }
 
 /* The MC is going down in to BIST mode. set the BIST flag to block
- * new MCDI, cancel any outstanding MCDI and and schedule a BIST-type reset
+ * new MCDI, cancel any outstanding MCDI and schedule a BIST-type reset
  * (which doesn't actually execute a reset, it waits for the controlling
  * function to reset it).
  */
index 89a7fd4..a3cc8b7 100644 (file)
  * MC_CMD_WORKAROUND_BUG26807.
  * May also returned for other operations such as sub-variant switching. */
 #define MC_CMD_ERR_FILTERS_PRESENT 0x1014
-/* The clock whose frequency you've attempted to set set
+/* The clock whose frequency you've attempted to set
  * doesn't exist on this NIC */
 #define MC_CMD_ERR_NO_CLOCK 0x1015
 /* Returned by MC_CMD_TESTASSERT if the action that should
  * large number (253) it is not anticipated that this will be needed in the
  * near future, so can currently be ignored.
  *
- * On Riverhead this command is implemented as a wrapper for `list` in the
+ * On Riverhead this command is implemented as a wrapper for `list` in the
  * sensor_query SPHINX service.
  */
 #define MC_CMD_DYNAMIC_SENSORS_LIST 0x66
  * update is in progress, and effectively means the set of usable sensors is
  * the intersection between the sets of sensors known to the driver and the MC.
  *
- * On Riverhead this command is implemented as a wrapper for
+ * On Riverhead this command is implemented as a wrapper for
  * `get_descriptions` in the sensor_query SPHINX service.
  */
 #define MC_CMD_DYNAMIC_SENSORS_GET_DESCRIPTIONS 0x67
  * update is in progress, and effectively means the set of usable sensors is
  * the intersection between the sets of sensors known to the driver and the MC.
  *
- * On Riverhead this command is implemented as a wrapper for `get_readings`
+ * On Riverhead this command is implemented as a wrapper for `get_readings`
  * in the sensor_query SPHINX service.
  */
 #define MC_CMD_DYNAMIC_SENSORS_GET_READINGS 0x68
  * TLV_PORT_MODE_*). A superset of MC_CMD_GET_PORT_MODES_OUT/MODES that
  * contains all modes implemented in firmware for a particular board. Modes
  * listed in MODES are considered production modes and should be exposed in
- * userland tools. Modes listed in in ENGINEERING_MODES, but not in MODES
+ * userland tools. Modes listed in ENGINEERING_MODES, but not in MODES
  * should be considered hidden (not to be exposed in userland tools) and for
  * engineering use only. There are no other semantic differences and any mode
  * listed in either MODES or ENGINEERING_MODES can be set on the board.
index 3f241e6..fc9f018 100644 (file)
@@ -10,7 +10,7 @@
 
 int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->sriov_set_vf_mac)
                return efx->type->sriov_set_vf_mac(efx, vf_i, mac);
@@ -21,7 +21,7 @@ int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
 int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, u16 vlan,
                          u8 qos, __be16 vlan_proto)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->sriov_set_vf_vlan) {
                if ((vlan & ~VLAN_VID_MASK) ||
@@ -40,7 +40,7 @@ int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i, u16 vlan,
 int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
                              bool spoofchk)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->sriov_set_vf_spoofchk)
                return efx->type->sriov_set_vf_spoofchk(efx, vf_i, spoofchk);
@@ -51,7 +51,7 @@ int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
 int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
                            struct ifla_vf_info *ivi)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->sriov_get_vf_config)
                return efx->type->sriov_get_vf_config(efx, vf_i, ivi);
@@ -62,7 +62,7 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
 int efx_sriov_set_vf_link_state(struct net_device *net_dev, int vf_i,
                                int link_state)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
 
        if (efx->type->sriov_set_vf_link_state)
                return efx->type->sriov_set_vf_link_state(efx, vf_i,
index 138bca6..79cc0bb 100644 (file)
@@ -512,7 +512,7 @@ unlock:
 netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
                                struct net_device *net_dev)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct efx_tx_queue *tx_queue;
        unsigned index, type;
 
@@ -609,7 +609,7 @@ void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue)
 int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
                 void *type_data)
 {
-       struct efx_nic *efx = netdev_priv(net_dev);
+       struct efx_nic *efx = efx_netdev_priv(net_dev);
        struct tc_mqprio_qopt *mqprio = type_data;
        unsigned tc, num_tc;
 
index 929cfc2..31ff351 100644 (file)
@@ -91,6 +91,9 @@ config DWMAC_IPQ806X
          acceleration features available on this SoC. Network devices
          will behave like standard non-accelerated ethernet interfaces.
 
+         Select the QCOM_SOCINFO config flag to enable specific dwmac
+         fixup based on the ipq806x SoC revision.
+
 config DWMAC_LPC18XX
        tristate "NXP LPC18xx/43xx DWMAC support"
        default ARCH_LPC18XX
index 38fe77d..d0e82cb 100644 (file)
@@ -251,7 +251,6 @@ static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data)
                priv->plat->mdio_bus_data->xpcs_an_inband = false;
        } else {
                priv->plat->max_speed = 1000;
-               priv->plat->phy_interface = PHY_INTERFACE_MODE_SGMII;
                priv->plat->mdio_bus_data->xpcs_an_inband = true;
        }
 }
@@ -443,6 +442,7 @@ static void common_default_data(struct plat_stmmacenet_data *plat)
 static int intel_mgbe_common_data(struct pci_dev *pdev,
                                  struct plat_stmmacenet_data *plat)
 {
+       struct fwnode_handle *fwnode;
        char clk_name[20];
        int ret;
        int i;
@@ -561,12 +561,42 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
        /* Use the last Rx queue */
        plat->vlan_fail_q = plat->rx_queues_to_use - 1;
 
+       /* For fixed-link setup, we allow phy-mode setting */
+       fwnode = dev_fwnode(&pdev->dev);
+       if (fwnode) {
+               int phy_mode;
+
+               /* "phy-mode" setting is optional. If it is set,
+                *  we allow either sgmii or 1000base-x for now.
+                */
+               phy_mode = fwnode_get_phy_mode(fwnode);
+               if (phy_mode >= 0) {
+                       if (phy_mode == PHY_INTERFACE_MODE_SGMII ||
+                           phy_mode == PHY_INTERFACE_MODE_1000BASEX)
+                               plat->phy_interface = phy_mode;
+                       else
+                               dev_warn(&pdev->dev, "Invalid phy-mode\n");
+               }
+       }
+
        /* Intel mgbe SGMII interface uses pcs-xcps */
-       if (plat->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+       if (plat->phy_interface == PHY_INTERFACE_MODE_SGMII ||
+           plat->phy_interface == PHY_INTERFACE_MODE_1000BASEX) {
                plat->mdio_bus_data->has_xpcs = true;
                plat->mdio_bus_data->xpcs_an_inband = true;
        }
 
+       /* For fixed-link setup, we clear xpcs_an_inband */
+       if (fwnode) {
+               struct fwnode_handle *fixed_node;
+
+               fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
+               if (fixed_node)
+                       plat->mdio_bus_data->xpcs_an_inband = false;
+
+               fwnode_handle_put(fixed_node);
+       }
+
        /* Ensure mdio bus scan skips intel serdes and pcs-xpcs */
        plat->mdio_bus_data->phy_mask = 1 << INTEL_MGBE_ADHOC_ADDR;
        plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_ADDR;
index f7dc845..e888c8a 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/stmmac.h>
 #include <linux/of_mdio.h>
 #include <linux/module.h>
+#include <linux/sys_soc.h>
+#include <linux/bitfield.h>
 
 #include "stmmac_platform.h"
 
 #define NSS_COMMON_CLK_DIV_SGMII_100           4
 #define NSS_COMMON_CLK_DIV_SGMII_10            49
 
+#define QSGMII_PCS_ALL_CH_CTL                  0x80
+#define QSGMII_PCS_CH_SPEED_FORCE              BIT(1)
+#define QSGMII_PCS_CH_SPEED_10                 0x0
+#define QSGMII_PCS_CH_SPEED_100                        BIT(2)
+#define QSGMII_PCS_CH_SPEED_1000               BIT(3)
+#define QSGMII_PCS_CH_SPEED_MASK               (QSGMII_PCS_CH_SPEED_FORCE | \
+                                                QSGMII_PCS_CH_SPEED_10 | \
+                                                QSGMII_PCS_CH_SPEED_100 | \
+                                                QSGMII_PCS_CH_SPEED_1000)
+#define QSGMII_PCS_CH_SPEED_SHIFT(x)           ((x) * 4)
+
 #define QSGMII_PCS_CAL_LCKDT_CTL               0x120
 #define QSGMII_PCS_CAL_LCKDT_CTL_RST           BIT(19)
 
 #define QSGMII_PHY_RX_SIGNAL_DETECT_EN         BIT(2)
 #define QSGMII_PHY_TX_DRIVER_EN                        BIT(3)
 #define QSGMII_PHY_QSGMII_EN                   BIT(7)
-#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET      12
-#define QSGMII_PHY_RX_DC_BIAS_OFFSET           18
-#define QSGMII_PHY_RX_INPUT_EQU_OFFSET         20
-#define QSGMII_PHY_CDR_PI_SLEW_OFFSET          22
-#define QSGMII_PHY_TX_DRV_AMP_OFFSET           28
+#define QSGMII_PHY_DEEMPHASIS_LVL_MASK         GENMASK(11, 10)
+#define QSGMII_PHY_DEEMPHASIS_LVL(x)           FIELD_PREP(QSGMII_PHY_DEEMPHASIS_LVL_MASK, (x))
+#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK                GENMASK(14, 12)
+#define QSGMII_PHY_PHASE_LOOP_GAIN(x)          FIELD_PREP(QSGMII_PHY_PHASE_LOOP_GAIN_MASK, (x))
+#define QSGMII_PHY_RX_DC_BIAS_MASK             GENMASK(19, 18)
+#define QSGMII_PHY_RX_DC_BIAS(x)               FIELD_PREP(QSGMII_PHY_RX_DC_BIAS_MASK, (x))
+#define QSGMII_PHY_RX_INPUT_EQU_MASK           GENMASK(21, 20)
+#define QSGMII_PHY_RX_INPUT_EQU(x)             FIELD_PREP(QSGMII_PHY_RX_INPUT_EQU_MASK, (x))
+#define QSGMII_PHY_CDR_PI_SLEW_MASK            GENMASK(23, 22)
+#define QSGMII_PHY_CDR_PI_SLEW(x)              FIELD_PREP(QSGMII_PHY_CDR_PI_SLEW_MASK, (x))
+#define QSGMII_PHY_TX_SLEW_MASK                        GENMASK(27, 26)
+#define QSGMII_PHY_TX_SLEW(x)                  FIELD_PREP(QSGMII_PHY_TX_SLEW_MASK, (x))
+#define QSGMII_PHY_TX_DRV_AMP_MASK             GENMASK(31, 28)
+#define QSGMII_PHY_TX_DRV_AMP(x)               FIELD_PREP(QSGMII_PHY_TX_DRV_AMP_MASK, (x))
 
 struct ipq806x_gmac {
        struct platform_device *pdev;
@@ -242,6 +264,113 @@ static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
        ipq806x_gmac_set_speed(gmac, speed);
 }
 
+static int
+ipq806x_gmac_configure_qsgmii_pcs_speed(struct ipq806x_gmac *gmac)
+{
+       struct platform_device *pdev = gmac->pdev;
+       struct device *dev = &pdev->dev;
+       struct device_node *dn;
+       int link_speed;
+       int val = 0;
+       int ret;
+
+       /* Some bootloader may apply wrong configuration and cause
+        * not functioning port. If fixed link is not set,
+        * reset the force speed bit.
+        */
+       if (!of_phy_is_fixed_link(pdev->dev.of_node))
+               goto write;
+
+       dn = of_get_child_by_name(pdev->dev.of_node, "fixed-link");
+       ret = of_property_read_u32(dn, "speed", &link_speed);
+       of_node_put(dn);
+       if (ret) {
+               dev_err(dev, "found fixed-link node with no speed");
+               return ret;
+       }
+
+       val = QSGMII_PCS_CH_SPEED_FORCE;
+
+       switch (link_speed) {
+       case SPEED_1000:
+               val |= QSGMII_PCS_CH_SPEED_1000;
+               break;
+       case SPEED_100:
+               val |= QSGMII_PCS_CH_SPEED_100;
+               break;
+       case SPEED_10:
+               val |= QSGMII_PCS_CH_SPEED_10;
+               break;
+       }
+
+write:
+       regmap_update_bits(gmac->qsgmii_csr, QSGMII_PCS_ALL_CH_CTL,
+                          QSGMII_PCS_CH_SPEED_MASK <<
+                          QSGMII_PCS_CH_SPEED_SHIFT(gmac->id),
+                          val <<
+                          QSGMII_PCS_CH_SPEED_SHIFT(gmac->id));
+
+       return 0;
+}
+
+static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = {
+       {
+               .revision = "1.*",
+       },
+       {
+               /* sentinel */
+       }
+};
+
+static int
+ipq806x_gmac_configure_qsgmii_params(struct ipq806x_gmac *gmac)
+{
+       struct platform_device *pdev = gmac->pdev;
+       const struct soc_device_attribute *soc;
+       struct device *dev = &pdev->dev;
+       u32 qsgmii_param;
+
+       switch (gmac->id) {
+       case 1:
+               soc = soc_device_match(ipq806x_gmac_soc_v1);
+
+               if (soc)
+                       qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xc) |
+                                      QSGMII_PHY_TX_SLEW(0x2) |
+                                      QSGMII_PHY_DEEMPHASIS_LVL(0x2);
+               else
+                       qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xd) |
+                                      QSGMII_PHY_TX_SLEW(0x0) |
+                                      QSGMII_PHY_DEEMPHASIS_LVL(0x0);
+
+               qsgmii_param |= QSGMII_PHY_RX_DC_BIAS(0x2);
+               break;
+       case 2:
+       case 3:
+               qsgmii_param = QSGMII_PHY_RX_DC_BIAS(0x3) |
+                              QSGMII_PHY_TX_DRV_AMP(0xc);
+               break;
+       default: /* gmac 0 can't be set in SGMII mode */
+               dev_err(dev, "gmac id %d can't be in SGMII mode", gmac->id);
+               return -EINVAL;
+       }
+
+       /* Common params across all gmac id */
+       qsgmii_param |= QSGMII_PHY_CDR_EN |
+                       QSGMII_PHY_RX_FRONT_EN |
+                       QSGMII_PHY_RX_SIGNAL_DETECT_EN |
+                       QSGMII_PHY_TX_DRIVER_EN |
+                       QSGMII_PHY_QSGMII_EN |
+                       QSGMII_PHY_PHASE_LOOP_GAIN(0x4) |
+                       QSGMII_PHY_RX_INPUT_EQU(0x1) |
+                       QSGMII_PHY_CDR_PI_SLEW(0x2);
+
+       regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
+                    qsgmii_param);
+
+       return 0;
+}
+
 static int ipq806x_gmac_probe(struct platform_device *pdev)
 {
        struct plat_stmmacenet_data *plat_dat;
@@ -328,17 +457,13 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
        regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
 
        if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
-               regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
-                            QSGMII_PHY_CDR_EN |
-                            QSGMII_PHY_RX_FRONT_EN |
-                            QSGMII_PHY_RX_SIGNAL_DETECT_EN |
-                            QSGMII_PHY_TX_DRIVER_EN |
-                            QSGMII_PHY_QSGMII_EN |
-                            0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
-                            0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET |
-                            0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
-                            0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
-                            0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET);
+               err = ipq806x_gmac_configure_qsgmii_params(gmac);
+               if (err)
+                       goto err_remove_config_dt;
+
+               err = ipq806x_gmac_configure_qsgmii_pcs_speed(gmac);
+               if (err)
+                       goto err_remove_config_dt;
        }
 
        plat_dat->has_gmac = true;
index a57b0fa..ea4910a 100644 (file)
@@ -197,7 +197,7 @@ static void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
                 MMC_CNTRL, value);
 }
 
-/* To mask all all interrupts.*/
+/* To mask all interrupts.*/
 static void dwmac_mmc_intr_all_mask(void __iomem *mmcaddr)
 {
        writel(MMC_DEFAULT_MASK, mmcaddr + MMC_RX_INTR_MASK);
index d1a7cf4..6f14b00 100644 (file)
@@ -1128,18 +1128,20 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
 static int stmmac_init_phy(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
-       struct device_node *node;
+       struct fwnode_handle *fwnode;
        int ret;
 
-       node = priv->plat->phylink_node;
+       fwnode = of_fwnode_handle(priv->plat->phylink_node);
+       if (!fwnode)
+               fwnode = dev_fwnode(priv->device);
 
-       if (node)
-               ret = phylink_of_phy_connect(priv->phylink, node, 0);
+       if (fwnode)
+               ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0);
 
        /* Some DT bindings do not set-up the PHY handle. Let's try to
         * manually parse it
         */
-       if (!node || ret) {
+       if (!fwnode || ret) {
                int addr = priv->plat->phy_addr;
                struct phy_device *phydev;
 
@@ -3959,7 +3961,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
                proto_hdr_len = skb_transport_offset(skb) + sizeof(struct udphdr);
                hdr = sizeof(struct udphdr);
        } else {
-               proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               proto_hdr_len = skb_tcp_all_headers(skb);
                hdr = tcp_hdrlen(skb);
        }
 
index 03d3d1f..5f177ea 100644 (file)
@@ -434,9 +434,11 @@ int stmmac_mdio_register(struct net_device *ndev)
        int err = 0;
        struct mii_bus *new_bus;
        struct stmmac_priv *priv = netdev_priv(ndev);
+       struct fwnode_handle *fwnode = of_fwnode_handle(priv->plat->phylink_node);
        struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
        struct device_node *mdio_node = priv->plat->mdio_node;
        struct device *dev = ndev->dev.parent;
+       struct fwnode_handle *fixed_node;
        int addr, found, max_addr;
 
        if (!mdio_bus_data)
@@ -490,6 +492,18 @@ int stmmac_mdio_register(struct net_device *ndev)
        if (priv->plat->has_xgmac)
                stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45);
 
+       /* If fixed-link is set, skip PHY scanning */
+       if (!fwnode)
+               fwnode = dev_fwnode(priv->device);
+
+       if (fwnode) {
+               fixed_node = fwnode_get_named_child_node(fwnode, "fixed-link");
+               if (fixed_node) {
+                       fwnode_handle_put(fixed_node);
+                       goto bus_register_done;
+               }
+       }
+
        if (priv->plat->phy_node || mdio_node)
                goto bus_register_done;
 
index 435dc00..0b08b0e 100644 (file)
@@ -29,7 +29,7 @@
  *  -- on page reclamation, the driver swaps the page with a spare page.
  *     if that page is still in use, it frees its reference to that page,
  *     and allocates a new page for use. otherwise, it just recycles the
- *     the page.
+ *     page.
  *
  * NOTE: cassini can parse the header. however, it's not worth it
  *       as long as the network stack requires a header copy.
index ae5f05f..2d91f49 100644 (file)
  * PAUSE thresholds defined in terms of FIFO occupancy and may be translated
  * into FIFO vacancy using RX_FIFO_SIZE. setting ON will trigger XON frames
  * when FIFO reaches 0. OFF threshold should not be > size of RX FIFO. max
- * value is is 0x6F.
+ * value is 0x6F.
  * DEFAULT: 0x00078
  */
 #define  REG_RX_PAUSE_THRESH               0x4020  /* RX pause thresholds */
index 6b59b14..0cd8493 100644 (file)
@@ -335,7 +335,7 @@ static int vsw_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        port->tsolen = 0;
 
        /* Mark the port as belonging to ldmvsw which directs the
-        * the common code to use the net_device in the vnet_port
+        * common code to use the net_device in the vnet_port
         * rather than the net_device in the vnet (which is used
         * by sunvnet). This bit is used by the VNET_PORT_TO_NET_DEVICE
         * macro.
index 45bd891..a14591b 100644 (file)
@@ -1088,7 +1088,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
                netif_stop_queue(dev);
 
                /* netif_stop_queue() must be done before checking
-                * checking tx index in TX_BUFFS_AVAIL() below, because
+                * tx index in TX_BUFFS_AVAIL() below, because
                 * in gem_tx(), we update tx_old before checking for
                 * netif_queue_stopped().
                 */
index d435519..e54ce73 100644 (file)
@@ -81,7 +81,7 @@ static int xlgmac_prep_tso(struct sk_buff *skb,
        if (ret)
                return ret;
 
-       pkt_info->header_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       pkt_info->header_len = skb_tcp_all_headers(skb);
        pkt_info->tcp_header_len = tcp_hdrlen(skb);
        pkt_info->tcp_payload_len = skb->len - pkt_info->header_len;
        pkt_info->mss = skb_shinfo(skb)->gso_size;
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
new file mode 100644 (file)
index 0000000..baa1f0a
--- /dev/null
@@ -0,0 +1,32 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Wangxun network device configuration
+#
+
+config NET_VENDOR_WANGXUN
+       bool "Wangxun devices"
+       default y
+       help
+         If you have a network (Ethernet) card belonging to this class, say Y.
+
+         Note that the answer to this question doesn't directly affect the
+         kernel: saying N will just cause the configurator to skip all
+         the questions about Intel cards. If you say Y, you will be asked for
+         your specific card in the following questions.
+
+if NET_VENDOR_WANGXUN
+
+config TXGBE
+       tristate "Wangxun(R) 10GbE PCI Express adapters support"
+       depends on PCI
+       help
+         This driver supports Wangxun(R) 10GbE PCI Express family of
+         adapters.
+
+         More specific information on configuring the driver is in
+         <file:Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst>.
+
+         To compile this driver as a module, choose M here. The module
+         will be called txgbe.
+
+endif # NET_VENDOR_WANGXUN
diff --git a/drivers/net/ethernet/wangxun/Makefile b/drivers/net/ethernet/wangxun/Makefile
new file mode 100644 (file)
index 0000000..c34db1b
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the Wangxun network device drivers.
+#
+
+obj-$(CONFIG_TXGBE) += txgbe/
diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile
new file mode 100644 (file)
index 0000000..431303c
--- /dev/null
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd.
+#
+# Makefile for the Wangxun(R) 10GbE PCI Express ethernet driver
+#
+
+obj-$(CONFIG_TXGBE) += txgbe.o
+
+txgbe-objs := txgbe_main.o
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe.h b/drivers/net/ethernet/wangxun/txgbe/txgbe.h
new file mode 100644 (file)
index 0000000..38ddbde
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _TXGBE_H_
+#define _TXGBE_H_
+
+#include "txgbe_type.h"
+
+#define TXGBE_MAX_FDIR_INDICES          63
+
+#define TXGBE_MAX_RX_QUEUES   (TXGBE_MAX_FDIR_INDICES + 1)
+#define TXGBE_MAX_TX_QUEUES   (TXGBE_MAX_FDIR_INDICES + 1)
+
+/* board specific private data structure */
+struct txgbe_adapter {
+       u8 __iomem *io_addr;    /* Mainly for iounmap use */
+       /* OS defined structs */
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+};
+
+extern char txgbe_driver_name[];
+
+#endif /* _TXGBE_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
new file mode 100644 (file)
index 0000000..55c3c72
--- /dev/null
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/aer.h>
+#include <linux/etherdevice.h>
+
+#include "txgbe.h"
+
+char txgbe_driver_name[] = "txgbe";
+
+/* txgbe_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static const struct pci_device_id txgbe_pci_tbl[] = {
+       { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_SP1000), 0},
+       { PCI_VDEVICE(WANGXUN, TXGBE_DEV_ID_WX1820), 0},
+       /* required last entry */
+       { .device = 0 }
+};
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+static void txgbe_dev_shutdown(struct pci_dev *pdev, bool *enable_wake)
+{
+       struct txgbe_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev = adapter->netdev;
+
+       netif_device_detach(netdev);
+
+       pci_disable_device(pdev);
+}
+
+static void txgbe_shutdown(struct pci_dev *pdev)
+{
+       bool wake;
+
+       txgbe_dev_shutdown(pdev, &wake);
+
+       if (system_state == SYSTEM_POWER_OFF) {
+               pci_wake_from_d3(pdev, wake);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
+}
+
+/**
+ * txgbe_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in txgbe_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * txgbe_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int txgbe_probe(struct pci_dev *pdev,
+                      const struct pci_device_id __always_unused *ent)
+{
+       struct txgbe_adapter *adapter = NULL;
+       struct net_device *netdev;
+       int err;
+
+       err = pci_enable_device_mem(pdev);
+       if (err)
+               return err;
+
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+       if (err) {
+               dev_err(&pdev->dev,
+                       "No usable DMA configuration, aborting\n");
+               goto err_pci_disable_dev;
+       }
+
+       err = pci_request_selected_regions(pdev,
+                                          pci_select_bars(pdev, IORESOURCE_MEM),
+                                          txgbe_driver_name);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "pci_request_selected_regions failed 0x%x\n", err);
+               goto err_pci_disable_dev;
+       }
+
+       pci_enable_pcie_error_reporting(pdev);
+       pci_set_master(pdev);
+
+       netdev = devm_alloc_etherdev_mqs(&pdev->dev,
+                                        sizeof(struct txgbe_adapter),
+                                        TXGBE_MAX_TX_QUEUES,
+                                        TXGBE_MAX_RX_QUEUES);
+       if (!netdev) {
+               err = -ENOMEM;
+               goto err_pci_release_regions;
+       }
+
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+
+       adapter = netdev_priv(netdev);
+       adapter->netdev = netdev;
+       adapter->pdev = pdev;
+
+       adapter->io_addr = devm_ioremap(&pdev->dev,
+                                       pci_resource_start(pdev, 0),
+                                       pci_resource_len(pdev, 0));
+       if (!adapter->io_addr) {
+               err = -EIO;
+               goto err_pci_release_regions;
+       }
+
+       netdev->features |= NETIF_F_HIGHDMA;
+
+       pci_set_drvdata(pdev, adapter);
+
+       return 0;
+
+err_pci_release_regions:
+       pci_release_selected_regions(pdev,
+                                    pci_select_bars(pdev, IORESOURCE_MEM));
+err_pci_disable_dev:
+       pci_disable_device(pdev);
+       return err;
+}
+
+/**
+ * txgbe_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * txgbe_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void txgbe_remove(struct pci_dev *pdev)
+{
+       pci_release_selected_regions(pdev,
+                                    pci_select_bars(pdev, IORESOURCE_MEM));
+
+       pci_disable_pcie_error_reporting(pdev);
+
+       pci_disable_device(pdev);
+}
+
+static struct pci_driver txgbe_driver = {
+       .name     = txgbe_driver_name,
+       .id_table = txgbe_pci_tbl,
+       .probe    = txgbe_probe,
+       .remove   = txgbe_remove,
+       .shutdown = txgbe_shutdown,
+};
+
+module_pci_driver(txgbe_driver);
+
+MODULE_DEVICE_TABLE(pci, txgbe_pci_tbl);
+MODULE_AUTHOR("Beijing WangXun Technology Co., Ltd, <software@trustnetic.com>");
+MODULE_DESCRIPTION("WangXun(R) 10 Gigabit PCI Express Network Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
new file mode 100644 (file)
index 0000000..b2e329f
--- /dev/null
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _TXGBE_TYPE_H_
+#define _TXGBE_TYPE_H_
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+/************ txgbe_register.h ************/
+/* Vendor ID */
+#ifndef PCI_VENDOR_ID_WANGXUN
+#define PCI_VENDOR_ID_WANGXUN                   0x8088
+#endif
+
+/* Device IDs */
+#define TXGBE_DEV_ID_SP1000                     0x1001
+#define TXGBE_DEV_ID_WX1820                     0x2001
+
+/* Subsystem IDs */
+/* SFP */
+#define TXGBE_ID_SP1000_SFP                     0x0000
+#define TXGBE_ID_WX1820_SFP                     0x2000
+#define TXGBE_ID_SFP                            0x00
+
+/* copper */
+#define TXGBE_ID_SP1000_XAUI                    0x1010
+#define TXGBE_ID_WX1820_XAUI                    0x2010
+#define TXGBE_ID_XAUI                           0x10
+#define TXGBE_ID_SP1000_SGMII                   0x1020
+#define TXGBE_ID_WX1820_SGMII                   0x2020
+#define TXGBE_ID_SGMII                          0x20
+/* backplane */
+#define TXGBE_ID_SP1000_KR_KX_KX4               0x1030
+#define TXGBE_ID_WX1820_KR_KX_KX4               0x2030
+#define TXGBE_ID_KR_KX_KX4                      0x30
+/* MAC Interface */
+#define TXGBE_ID_SP1000_MAC_XAUI                0x1040
+#define TXGBE_ID_WX1820_MAC_XAUI                0x2040
+#define TXGBE_ID_MAC_XAUI                       0x40
+#define TXGBE_ID_SP1000_MAC_SGMII               0x1060
+#define TXGBE_ID_WX1820_MAC_SGMII               0x2060
+#define TXGBE_ID_MAC_SGMII                      0x60
+
+#define TXGBE_NCSI_SUP                          0x8000
+#define TXGBE_NCSI_MASK                         0x8000
+#define TXGBE_WOL_SUP                           0x4000
+#define TXGBE_WOL_MASK                          0x4000
+#define TXGBE_DEV_MASK                          0xf0
+
+/* Combined interface*/
+#define TXGBE_ID_SFI_XAUI                      0x50
+
+/* Revision ID */
+#define TXGBE_SP_MPW  1
+
+#endif /* _TXGBE_TYPE_H_ */
index 48f544f..2772a79 100644 (file)
@@ -106,7 +106,7 @@ static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg)
  * Return:     0 on success, -ETIMEDOUT on a timeout
  *
  * Writes the value to the requested register by first writing the value
- * into MWD register. The the MCR register is then appropriately setup
+ * into MWD register. The MCR register is then appropriately setup
  * to finish the write operation.
  */
 static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg,
index 9cfe843..4e46974 100644 (file)
@@ -823,7 +823,7 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell)
 
        /* Now update the scratch registers for GPI protocol */
        gpi = &scr.gpi;
-       gpi->max_outstanding_tre = gsi_channel_trans_tre_max(gsi, channel_id) *
+       gpi->max_outstanding_tre = channel->trans_tre_max *
                                        GSI_RING_ELEMENT_SIZE;
        gpi->outstanding_threshold = 2 * GSI_RING_ELEMENT_SIZE;
 
@@ -991,75 +991,66 @@ void gsi_resume(struct gsi *gsi)
        enable_irq(gsi->irq);
 }
 
-/**
- * gsi_channel_tx_queued() - Report queued TX transfers for a channel
- * @channel:   Channel for which to report
- *
- * Report to the network stack the number of bytes and transactions that
- * have been queued to hardware since last call.  This and the next function
- * supply information used by the network stack for throttling.
- *
- * For each channel we track the number of transactions used and bytes of
- * data those transactions represent.  We also track what those values are
- * each time this function is called.  Subtracting the two tells us
- * the number of bytes and transactions that have been added between
- * successive calls.
- *
- * Calling this each time we ring the channel doorbell allows us to
- * provide accurate information to the network stack about how much
- * work we've given the hardware at any point in time.
- */
-void gsi_channel_tx_queued(struct gsi_channel *channel)
+void gsi_trans_tx_committed(struct gsi_trans *trans)
 {
+       struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id];
+
+       channel->trans_count++;
+       channel->byte_count += trans->len;
+
+       trans->trans_count = channel->trans_count;
+       trans->byte_count = channel->byte_count;
+}
+
+void gsi_trans_tx_queued(struct gsi_trans *trans)
+{
+       u32 channel_id = trans->channel_id;
+       struct gsi *gsi = trans->gsi;
+       struct gsi_channel *channel;
        u32 trans_count;
        u32 byte_count;
 
+       channel = &gsi->channel[channel_id];
+
        byte_count = channel->byte_count - channel->queued_byte_count;
        trans_count = channel->trans_count - channel->queued_trans_count;
        channel->queued_byte_count = channel->byte_count;
        channel->queued_trans_count = channel->trans_count;
 
-       ipa_gsi_channel_tx_queued(channel->gsi, gsi_channel_id(channel),
-                                 trans_count, byte_count);
+       ipa_gsi_channel_tx_queued(gsi, channel_id, trans_count, byte_count);
 }
 
 /**
- * gsi_channel_tx_update() - Report completed TX transfers
- * @channel:   Channel that has completed transmitting packets
- * @trans:     Last transation known to be complete
+ * gsi_trans_tx_completed() - Report completed TX transactions
+ * @trans:     TX channel transaction that has completed
  *
- * Compute the number of transactions and bytes that have been transferred
- * over a TX channel since the given transaction was committed.  Report this
- * information to the network stack.
+ * Report that a transaction on a TX channel has completed.  At the time a
+ * transaction is committed, we record *in the transaction* its channel's
+ * committed transaction and byte counts.  Transactions are completed in
+ * order, and the difference between the channel's byte/transaction count
+ * when the transaction was committed and when it completes tells us
+ * exactly how much data has been transferred while the transaction was
+ * pending.
  *
- * At the time a transaction is committed, we record its channel's
- * committed transaction and byte counts *in the transaction*.
- * Completions are signaled by the hardware with an interrupt, and
- * we can determine the latest completed transaction at that time.
- *
- * The difference between the byte/transaction count recorded in
- * the transaction and the count last time we recorded a completion
- * tells us exactly how much data has been transferred between
- * completions.
- *
- * Calling this each time we learn of a newly-completed transaction
- * allows us to provide accurate information to the network stack
- * about how much work has been completed by the hardware at a given
- * point in time.
+ * We report this information to the network stack, which uses it to manage
+ * the rate at which data is sent to hardware.
  */
-static void
-gsi_channel_tx_update(struct gsi_channel *channel, struct gsi_trans *trans)
+static void gsi_trans_tx_completed(struct gsi_trans *trans)
 {
-       u64 byte_count = trans->byte_count + trans->len;
-       u64 trans_count = trans->trans_count + 1;
+       u32 channel_id = trans->channel_id;
+       struct gsi *gsi = trans->gsi;
+       struct gsi_channel *channel;
+       u32 trans_count;
+       u32 byte_count;
+
+       channel = &gsi->channel[channel_id];
+       trans_count = trans->trans_count - channel->compl_trans_count;
+       byte_count = trans->byte_count - channel->compl_byte_count;
 
-       byte_count -= channel->compl_byte_count;
-       channel->compl_byte_count += byte_count;
-       trans_count -= channel->compl_trans_count;
        channel->compl_trans_count += trans_count;
+       channel->compl_byte_count += byte_count;
 
-       ipa_gsi_channel_tx_completed(channel->gsi, gsi_channel_id(channel),
-                                    trans_count, byte_count);
+       ipa_gsi_channel_tx_completed(gsi, channel_id, trans_count, byte_count);
 }
 
 /* Channel control interrupt handler */
@@ -1327,28 +1318,45 @@ static int gsi_irq_init(struct gsi *gsi, struct platform_device *pdev)
 }
 
 /* Return the transaction associated with a transfer completion event */
-static struct gsi_trans *gsi_event_trans(struct gsi_channel *channel,
-                                        struct gsi_event *event)
+static struct gsi_trans *
+gsi_event_trans(struct gsi *gsi, struct gsi_event *event)
 {
+       u32 channel_id = event->chid;
+       struct gsi_channel *channel;
+       struct gsi_trans *trans;
        u32 tre_offset;
        u32 tre_index;
 
+       channel = &gsi->channel[channel_id];
+       if (WARN(!channel->gsi, "event has bad channel %u\n", channel_id))
+               return NULL;
+
        /* Event xfer_ptr records the TRE it's associated with */
        tre_offset = lower_32_bits(le64_to_cpu(event->xfer_ptr));
        tre_index = gsi_ring_index(&channel->tre_ring, tre_offset);
 
-       return gsi_channel_trans_mapped(channel, tre_index);
+       trans = gsi_channel_trans_mapped(channel, tre_index);
+
+       if (WARN(!trans, "channel %u event with no transaction\n", channel_id))
+               return NULL;
+
+       return trans;
 }
 
 /**
- * gsi_evt_ring_rx_update() - Record lengths of received data
- * @evt_ring:  Event ring associated with channel that received packets
- * @index:     Event index in ring reported by hardware
+ * gsi_evt_ring_update() - Update transaction state from hardware
+ * @gsi:               GSI pointer
+ * @evt_ring_id:       Event ring ID
+ * @index:             Event index in ring reported by hardware
  *
  * Events for RX channels contain the actual number of bytes received into
  * the buffer.  Every event has a transaction associated with it, and here
  * we update transactions to record their actual received lengths.
  *
+ * When an event for a TX channel arrives we use information in the
+ * transaction to report the number of requests and bytes have been
+ * transferred.
+ *
  * This function is called whenever we learn that the GSI hardware has filled
  * new events since the last time we checked.  The ring's index field tells
  * the first entry in need of processing.  The index provided is the
@@ -1359,29 +1367,24 @@ static struct gsi_trans *gsi_event_trans(struct gsi_channel *channel,
  *
  * Note that @index always refers to an element *within* the event ring.
  */
-static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)
+static void gsi_evt_ring_update(struct gsi *gsi, u32 evt_ring_id, u32 index)
 {
-       struct gsi_channel *channel = evt_ring->channel;
+       struct gsi_evt_ring *evt_ring = &gsi->evt_ring[evt_ring_id];
        struct gsi_ring *ring = &evt_ring->ring;
-       struct gsi_trans_info *trans_info;
        struct gsi_event *event_done;
        struct gsi_event *event;
-       struct gsi_trans *trans;
-       u32 trans_count = 0;
-       u32 byte_count = 0;
        u32 event_avail;
        u32 old_index;
 
-       trans_info = &channel->trans_info;
-
-       /* We'll start with the oldest un-processed event.  RX channels
-        * replenish receive buffers in single-TRE transactions, so we
-        * can just map that event to its transaction.  Transactions
-        * associated with completion events are consecutive.
+       /* Starting with the oldest un-processed event, determine which
+        * transaction (and which channel) is associated with the event.
+        * For RX channels, update each completed transaction with the
+        * number of bytes that were actually received.  For TX channels
+        * associated with a network device, report to the network stack
+        * the number of transfers and bytes this completion represents.
         */
        old_index = ring->index;
        event = gsi_ring_virt(ring, old_index);
-       trans = gsi_event_trans(channel, event);
 
        /* Compute the number of events to process before we wrap,
         * and determine when we'll be done processing events.
@@ -1389,21 +1392,28 @@ static void gsi_evt_ring_rx_update(struct gsi_evt_ring *evt_ring, u32 index)
        event_avail = ring->count - old_index % ring->count;
        event_done = gsi_ring_virt(ring, index);
        do {
-               trans->len = __le16_to_cpu(event->len);
-               byte_count += trans->len;
-               trans_count++;
+               struct gsi_trans *trans;
+
+               trans = gsi_event_trans(gsi, event);
+               if (!trans)
+                       return;
+
+               if (trans->direction == DMA_FROM_DEVICE)
+                       trans->len = __le16_to_cpu(event->len);
+               else
+                       gsi_trans_tx_completed(trans);
+
+               gsi_trans_move_complete(trans);
 
                /* Move on to the next event and transaction */
                if (--event_avail)
                        event++;
                else
                        event = gsi_ring_virt(ring, 0);
-               trans = gsi_trans_pool_next(&trans_info->pool, trans);
        } while (event != event_done);
 
-       /* We record RX bytes when they are received */
-       channel->byte_count += byte_count;
-       channel->trans_count += trans_count;
+       /* Tell the hardware we've handled these events */
+       gsi_evt_ring_doorbell(gsi, evt_ring_id, index);
 }
 
 /* Initialize a ring, including allocating DMA memory for its entries */
@@ -1493,22 +1503,16 @@ static struct gsi_trans *gsi_channel_update(struct gsi_channel *channel)
                return NULL;
 
        /* Get the transaction for the latest completed event. */
-       trans = gsi_event_trans(channel, gsi_ring_virt(ring, index - 1));
+       trans = gsi_event_trans(gsi, gsi_ring_virt(ring, index - 1));
+       if (!trans)
+               return NULL;
 
        /* For RX channels, update each completed transaction with the number
         * of bytes that were actually received.  For TX channels, report
         * the number of transactions and bytes this completion represents
         * up the network stack.
         */
-       if (channel->toward_ipa)
-               gsi_channel_tx_update(channel, trans);
-       else
-               gsi_evt_ring_rx_update(evt_ring, index);
-
-       gsi_trans_move_complete(trans);
-
-       /* Tell the hardware we've handled these events */
-       gsi_evt_ring_doorbell(gsi, evt_ring_id, index);
+       gsi_evt_ring_update(gsi, evt_ring_id, index);
 
        return gsi_channel_trans_complete(channel);
 }
@@ -2001,9 +2005,10 @@ static void gsi_channel_evt_ring_exit(struct gsi_channel *channel)
        gsi_evt_ring_id_free(gsi, evt_ring_id);
 }
 
-static bool gsi_channel_data_valid(struct gsi *gsi,
+static bool gsi_channel_data_valid(struct gsi *gsi, bool command,
                                   const struct ipa_gsi_endpoint_data *data)
 {
+       const struct gsi_channel_data *channel_data;
        u32 channel_id = data->channel_id;
        struct device *dev = gsi->dev;
 
@@ -2019,10 +2024,24 @@ static bool gsi_channel_data_valid(struct gsi *gsi,
                return false;
        }
 
-       if (!data->channel.tlv_count ||
-           data->channel.tlv_count > GSI_TLV_MAX) {
+       if (command && !data->toward_ipa) {
+               dev_err(dev, "command channel %u is not TX\n", channel_id);
+               return false;
+       }
+
+       channel_data = &data->channel;
+
+       if (!channel_data->tlv_count ||
+           channel_data->tlv_count > GSI_TLV_MAX) {
                dev_err(dev, "channel %u bad tlv_count %u; must be 1..%u\n",
-                       channel_id, data->channel.tlv_count, GSI_TLV_MAX);
+                       channel_id, channel_data->tlv_count, GSI_TLV_MAX);
+               return false;
+       }
+
+       if (command && IPA_COMMAND_TRANS_TRE_MAX > channel_data->tlv_count) {
+               dev_err(dev, "command TRE max too big for channel %u (%u > %u)\n",
+                       channel_id, IPA_COMMAND_TRANS_TRE_MAX,
+                       channel_data->tlv_count);
                return false;
        }
 
@@ -2031,22 +2050,22 @@ static bool gsi_channel_data_valid(struct gsi *gsi,
         * gsi_channel_tre_max() is computed, tre_count has to be almost
         * twice the TLV FIFO size to satisfy this requirement.
         */
-       if (data->channel.tre_count < 2 * data->channel.tlv_count - 1) {
+       if (channel_data->tre_count < 2 * channel_data->tlv_count - 1) {
                dev_err(dev, "channel %u TLV count %u exceeds TRE count %u\n",
-                       channel_id, data->channel.tlv_count,
-                       data->channel.tre_count);
+                       channel_id, channel_data->tlv_count,
+                       channel_data->tre_count);
                return false;
        }
 
-       if (!is_power_of_2(data->channel.tre_count)) {
+       if (!is_power_of_2(channel_data->tre_count)) {
                dev_err(dev, "channel %u bad tre_count %u; not power of 2\n",
-                       channel_id, data->channel.tre_count);
+                       channel_id, channel_data->tre_count);
                return false;
        }
 
-       if (!is_power_of_2(data->channel.event_count)) {
+       if (!is_power_of_2(channel_data->event_count)) {
                dev_err(dev, "channel %u bad event_count %u; not power of 2\n",
-                       channel_id, data->channel.event_count);
+                       channel_id, channel_data->event_count);
                return false;
        }
 
@@ -2062,7 +2081,7 @@ static int gsi_channel_init_one(struct gsi *gsi,
        u32 tre_count;
        int ret;
 
-       if (!gsi_channel_data_valid(gsi, data))
+       if (!gsi_channel_data_valid(gsi, command, data))
                return -EINVAL;
 
        /* Worst case we need an event for every outstanding TRE */
@@ -2080,7 +2099,7 @@ static int gsi_channel_init_one(struct gsi *gsi,
        channel->gsi = gsi;
        channel->toward_ipa = data->toward_ipa;
        channel->command = command;
-       channel->tlv_count = data->channel.tlv_count;
+       channel->trans_tre_max = data->channel.tlv_count;
        channel->tre_count = tre_count;
        channel->event_count = data->channel.event_count;
 
@@ -2295,13 +2314,5 @@ u32 gsi_channel_tre_max(struct gsi *gsi, u32 channel_id)
        struct gsi_channel *channel = &gsi->channel[channel_id];
 
        /* Hardware limit is channel->tre_count - 1 */
-       return channel->tre_count - (channel->tlv_count - 1);
-}
-
-/* Returns the maximum number of TREs in a single transaction for a channel */
-u32 gsi_channel_trans_tre_max(struct gsi *gsi, u32 channel_id)
-{
-       struct gsi_channel *channel = &gsi->channel[channel_id];
-
-       return channel->tlv_count;
+       return channel->tre_count - (channel->trans_tre_max - 1);
 }
index 5d66116..bad1a78 100644 (file)
@@ -110,16 +110,16 @@ struct gsi_channel {
        bool toward_ipa;
        bool command;                   /* AP command TX channel or not */
 
-       u8 tlv_count;                   /* # entries in TLV FIFO */
+       u8 trans_tre_max;               /* max TREs in a transaction */
        u16 tre_count;
        u16 event_count;
 
        struct gsi_ring tre_ring;
        u32 evt_ring_id;
 
+       /* The following counts are used only for TX endpoints */
        u64 byte_count;                 /* total # bytes transferred */
        u64 trans_count;                /* total # transactions */
-       /* The following counts are used only for TX endpoints */
        u64 queued_byte_count;          /* last reported queued byte count */
        u64 queued_trans_count;         /* ...and queued trans count */
        u64 compl_byte_count;           /* last reported completed byte count */
@@ -189,15 +189,6 @@ void gsi_teardown(struct gsi *gsi);
 u32 gsi_channel_tre_max(struct gsi *gsi, u32 channel_id);
 
 /**
- * gsi_channel_trans_tre_max() - Maximum TREs in a single transaction
- * @gsi:       GSI pointer
- * @channel_id:        Channel whose limit is to be returned
- *
- * Return:      The maximum TRE count per transaction on the channel
- */
-u32 gsi_channel_trans_tre_max(struct gsi *gsi, u32 channel_id);
-
-/**
  * gsi_channel_start() - Start an allocated GSI channel
  * @gsi:       GSI pointer
  * @channel_id:        Channel to start
index ea333a2..0b2516f 100644 (file)
@@ -16,9 +16,6 @@ struct gsi_channel;
 
 #define GSI_RING_ELEMENT_SIZE  16      /* bytes; must be a power of 2 */
 
-/* Return the entry that follows one provided in a transaction pool */
-void *gsi_trans_pool_next(struct gsi_trans_pool *pool, void *element);
-
 /**
  * gsi_trans_move_complete() - Mark a GSI transaction completed
  * @trans:     Transaction to commit
@@ -105,14 +102,21 @@ void gsi_channel_doorbell(struct gsi_channel *channel);
 void *gsi_ring_virt(struct gsi_ring *ring, u32 index);
 
 /**
- * gsi_channel_tx_queued() - Report the number of bytes queued to hardware
- * @channel:   Channel whose bytes have been queued
+ * gsi_trans_tx_committed() - Record bytes committed for transmit
+ * @trans:     TX endpoint transaction being committed
+ *
+ * Report that a TX transaction has been committed.  It updates some
+ * statistics used to manage transmit rates.
+ */
+void gsi_trans_tx_committed(struct gsi_trans *trans);
+
+/**
+ * gsi_trans_tx_queued() - Report a queued TX channel transaction
+ * @trans:     Transaction being passed to hardware
  *
- * This arranges for the the number of transactions and bytes for
- * transfer that have been queued to hardware to be reported.  It
- * passes this information up the network stack so it can be used to
- * throttle transmissions.
+ * Report to the network stack that a TX transaction is being supplied
+ * to the hardware.
  */
-void gsi_channel_tx_queued(struct gsi_channel *channel);
+void gsi_trans_tx_queued(struct gsi_trans *trans);
 
 #endif /* _GSI_PRIVATE_H_ */
index 55f8fe7..29496ca 100644 (file)
@@ -214,26 +214,14 @@ void *gsi_trans_pool_alloc_dma(struct gsi_trans_pool *pool, dma_addr_t *addr)
        return pool->base + offset;
 }
 
-/* Return the pool element that immediately follows the one given.
- * This only works done if elements are allocated one at a time.
- */
-void *gsi_trans_pool_next(struct gsi_trans_pool *pool, void *element)
+/* Map a TRE ring entry index to the transaction it is associated with */
+static void gsi_trans_map(struct gsi_trans *trans, u32 index)
 {
-       void *end = pool->base + pool->count * pool->size;
-
-       WARN_ON(element < pool->base);
-       WARN_ON(element >= end);
-       WARN_ON(pool->max_alloc != 1);
-
-       element += pool->size;
+       struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id];
 
-       return element < end ? element : pool->base;
-}
+       /* The completion event will indicate the last TRE used */
+       index += trans->used_count - 1;
 
-/* Map a given ring entry index to the transaction associated with it */
-static void gsi_channel_trans_map(struct gsi_channel *channel, u32 index,
-                                 struct gsi_trans *trans)
-{
        /* Note: index *must* be used modulo the ring count here */
        channel->trans_info.map[index % channel->tre_ring.count] = trans;
 }
@@ -340,7 +328,7 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id,
        struct gsi_trans_info *trans_info;
        struct gsi_trans *trans;
 
-       if (WARN_ON(tre_count > gsi_channel_trans_tre_max(gsi, channel_id)))
+       if (WARN_ON(tre_count > channel->trans_tre_max))
                return NULL;
 
        trans_info = &channel->trans_info;
@@ -351,11 +339,11 @@ struct gsi_trans *gsi_channel_trans_alloc(struct gsi *gsi, u32 channel_id,
        if (!gsi_trans_tre_reserve(trans_info, tre_count))
                return NULL;
 
-       /* Allocate and initialize non-zero fields in the the transaction */
+       /* Allocate and initialize non-zero fields in the transaction */
        trans = gsi_trans_pool_alloc(&trans_info->pool, 1);
        trans->gsi = gsi;
        trans->channel_id = channel_id;
-       trans->tre_count = tre_count;
+       trans->rsvd_count = tre_count;
        init_completion(&trans->completion);
 
        /* Allocate the scatterlist and (if requested) info entries. */
@@ -405,17 +393,17 @@ void gsi_trans_free(struct gsi_trans *trans)
        /* Releasing the reserved TREs implicitly frees the sgl[] and
         * (if present) info[] arrays, plus the transaction itself.
         */
-       gsi_trans_tre_release(trans_info, trans->tre_count);
+       gsi_trans_tre_release(trans_info, trans->rsvd_count);
 }
 
 /* Add an immediate command to a transaction */
 void gsi_trans_cmd_add(struct gsi_trans *trans, void *buf, u32 size,
                       dma_addr_t addr, enum ipa_cmd_opcode opcode)
 {
-       u32 which = trans->used++;
+       u32 which = trans->used_count++;
        struct scatterlist *sg;
 
-       WARN_ON(which >= trans->tre_count);
+       WARN_ON(which >= trans->rsvd_count);
 
        /* Commands are quite different from data transfer requests.
         * Their payloads come from a pool whose memory is allocated
@@ -446,9 +434,9 @@ int gsi_trans_page_add(struct gsi_trans *trans, struct page *page, u32 size,
        struct scatterlist *sg = &trans->sgl[0];
        int ret;
 
-       if (WARN_ON(trans->tre_count != 1))
+       if (WARN_ON(trans->rsvd_count != 1))
                return -EINVAL;
-       if (WARN_ON(trans->used))
+       if (WARN_ON(trans->used_count))
                return -EINVAL;
 
        sg_set_page(sg, page, size, offset);
@@ -456,7 +444,7 @@ int gsi_trans_page_add(struct gsi_trans *trans, struct page *page, u32 size,
        if (!ret)
                return -ENOMEM;
 
-       trans->used++;  /* Transaction now owns the (DMA mapped) page */
+       trans->used_count++;    /* Transaction now owns the (DMA mapped) page */
 
        return 0;
 }
@@ -465,25 +453,26 @@ int gsi_trans_page_add(struct gsi_trans *trans, struct page *page, u32 size,
 int gsi_trans_skb_add(struct gsi_trans *trans, struct sk_buff *skb)
 {
        struct scatterlist *sg = &trans->sgl[0];
-       u32 used;
+       u32 used_count;
        int ret;
 
-       if (WARN_ON(trans->tre_count != 1))
+       if (WARN_ON(trans->rsvd_count != 1))
                return -EINVAL;
-       if (WARN_ON(trans->used))
+       if (WARN_ON(trans->used_count))
                return -EINVAL;
 
        /* skb->len will not be 0 (checked early) */
        ret = skb_to_sgvec(skb, sg, 0, skb->len);
        if (ret < 0)
                return ret;
-       used = ret;
+       used_count = ret;
 
-       ret = dma_map_sg(trans->gsi->dev, sg, used, trans->direction);
+       ret = dma_map_sg(trans->gsi->dev, sg, used_count, trans->direction);
        if (!ret)
                return -ENOMEM;
 
-       trans->used += used;    /* Transaction now owns the (DMA mapped) skb */
+       /* Transaction now owns the (DMA mapped) skb */
+       trans->used_count += used_count;
 
        return 0;
 }
@@ -549,7 +538,7 @@ static void gsi_trans_tre_fill(struct gsi_tre *dest_tre, dma_addr_t addr,
 static void __gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
 {
        struct gsi_channel *channel = &trans->gsi->channel[trans->channel_id];
-       struct gsi_ring *ring = &channel->tre_ring;
+       struct gsi_ring *tre_ring = &channel->tre_ring;
        enum ipa_cmd_opcode opcode = IPA_CMD_NONE;
        bool bei = channel->toward_ipa;
        struct gsi_tre *dest_tre;
@@ -559,7 +548,7 @@ static void __gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
        u32 avail;
        u32 i;
 
-       WARN_ON(!trans->used);
+       WARN_ON(!trans->used_count);
 
        /* Consume the entries.  If we cross the end of the ring while
         * filling them we'll switch to the beginning to finish.
@@ -567,35 +556,30 @@ static void __gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
         * transfer request, whose opcode is IPA_CMD_NONE.
         */
        cmd_opcode = channel->command ? &trans->cmd_opcode[0] : NULL;
-       avail = ring->count - ring->index % ring->count;
-       dest_tre = gsi_ring_virt(ring, ring->index);
-       for_each_sg(trans->sgl, sg, trans->used, i) {
-               bool last_tre = i == trans->used - 1;
+       avail = tre_ring->count - tre_ring->index % tre_ring->count;
+       dest_tre = gsi_ring_virt(tre_ring, tre_ring->index);
+       for_each_sg(trans->sgl, sg, trans->used_count, i) {
+               bool last_tre = i == trans->used_count - 1;
                dma_addr_t addr = sg_dma_address(sg);
                u32 len = sg_dma_len(sg);
 
                byte_count += len;
                if (!avail--)
-                       dest_tre = gsi_ring_virt(ring, 0);
+                       dest_tre = gsi_ring_virt(tre_ring, 0);
                if (cmd_opcode)
                        opcode = *cmd_opcode++;
 
                gsi_trans_tre_fill(dest_tre, addr, len, last_tre, bei, opcode);
                dest_tre++;
        }
-       ring->index += trans->used;
-
-       if (channel->toward_ipa) {
-               /* We record TX bytes when they are sent */
-               trans->len = byte_count;
-               trans->trans_count = channel->trans_count;
-               trans->byte_count = channel->byte_count;
-               channel->trans_count++;
-               channel->byte_count += byte_count;
-       }
+       /* Associate the TRE with the transaction */
+       gsi_trans_map(trans, tre_ring->index);
 
-       /* Associate the last TRE with the transaction */
-       gsi_channel_trans_map(channel, ring->index - 1, trans);
+       tre_ring->index += trans->used_count;
+
+       trans->len = byte_count;
+       if (channel->toward_ipa)
+               gsi_trans_tx_committed(trans);
 
        gsi_trans_move_pending(trans);
 
@@ -603,7 +587,7 @@ static void __gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
        if (ring_db || !atomic_read(&channel->trans_info.tre_avail)) {
                /* Report what we're handing off to hardware for TX channels */
                if (channel->toward_ipa)
-                       gsi_channel_tx_queued(channel);
+                       gsi_trans_tx_queued(trans);
                gsi_channel_doorbell(channel);
        }
 }
@@ -611,7 +595,7 @@ static void __gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
 /* Commit a GSI transaction */
 void gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
 {
-       if (trans->used)
+       if (trans->used_count)
                __gsi_trans_commit(trans, ring_db);
        else
                gsi_trans_free(trans);
@@ -620,7 +604,7 @@ void gsi_trans_commit(struct gsi_trans *trans, bool ring_db)
 /* Commit a GSI transaction and wait for it to complete */
 void gsi_trans_commit_wait(struct gsi_trans *trans)
 {
-       if (!trans->used)
+       if (!trans->used_count)
                goto out_trans_free;
 
        refcount_inc(&trans->refcount);
@@ -638,7 +622,7 @@ void gsi_trans_complete(struct gsi_trans *trans)
 {
        /* If the entire SGL was mapped when added, unmap it now */
        if (trans->direction != DMA_NONE)
-               dma_unmap_sg(trans->gsi->dev, trans->sgl, trans->used,
+               dma_unmap_sg(trans->gsi->dev, trans->sgl, trans->used_count,
                             trans->direction);
 
        ipa_gsi_trans_complete(trans);
@@ -675,7 +659,7 @@ void gsi_channel_trans_cancel_pending(struct gsi_channel *channel)
 int gsi_trans_read_byte(struct gsi *gsi, u32 channel_id, dma_addr_t addr)
 {
        struct gsi_channel *channel = &gsi->channel[channel_id];
-       struct gsi_ring *ring = &channel->tre_ring;
+       struct gsi_ring *tre_ring = &channel->tre_ring;
        struct gsi_trans_info *trans_info;
        struct gsi_tre *dest_tre;
 
@@ -685,12 +669,12 @@ int gsi_trans_read_byte(struct gsi *gsi, u32 channel_id, dma_addr_t addr)
        if (!gsi_trans_tre_reserve(trans_info, 1))
                return -EBUSY;
 
-       /* Now fill the the reserved TRE and tell the hardware */
+       /* Now fill the reserved TRE and tell the hardware */
 
-       dest_tre = gsi_ring_virt(ring, ring->index);
+       dest_tre = gsi_ring_virt(tre_ring, tre_ring->index);
        gsi_trans_tre_fill(dest_tre, addr, 1, true, false, IPA_CMD_NONE);
 
-       ring->index++;
+       tre_ring->index++;
        gsi_channel_doorbell(channel);
 
        return 0;
@@ -745,14 +729,10 @@ int gsi_channel_trans_init(struct gsi *gsi, u32 channel_id)
         * element is used to fill a single TRE when the transaction is
         * committed.  So we need as many scatterlist elements as the
         * maximum number of TREs that can be outstanding.
-        *
-        * All TREs in a transaction must fit within the channel's TLV FIFO.
-        * A transaction on a channel can allocate as many TREs as that but
-        * no more.
         */
        ret = gsi_trans_pool_init(&trans_info->sg_pool,
                                  sizeof(struct scatterlist),
-                                 tre_max, channel->tlv_count);
+                                 tre_max, channel->trans_tre_max);
        if (ret)
                goto err_trans_pool_exit;
 
index 020c3b3..7084507 100644 (file)
@@ -33,9 +33,9 @@ struct gsi_trans_pool;
  * @gsi:       GSI pointer
  * @channel_id: Channel number transaction is associated with
  * @cancelled: If set by the core code, transaction was cancelled
- * @tre_count: Number of TREs reserved for this transaction
- * @used:      Number of TREs *used* (could be less than tre_count)
- * @len:       Total # of transfer bytes represented in sgl[] (set by core)
+ * @rsvd_count:        Number of TREs reserved for this transaction
+ * @used_count:        Number of TREs *used* (could be less than rsvd_count)
+ * @len:       Number of bytes sent or received by the transaction
  * @data:      Preserved but not touched by the core transaction code
  * @cmd_opcode:        Array of command opcodes (command channel only)
  * @sgl:       An array of scatter/gather entries managed by core code
@@ -45,8 +45,9 @@ struct gsi_trans_pool;
  * @byte_count:        TX channel byte count recorded when transaction committed
  * @trans_count: Channel transaction count when committed (for BQL accounting)
  *
- * The size used for some fields in this structure were chosen to ensure
- * the full structure size is no larger than 128 bytes.
+ * The @len field is set when the transaction is committed.  For RX
+ * transactions it is updated later to reflect the actual number of bytes
+ * received.
  */
 struct gsi_trans {
        struct list_head links;         /* gsi_channel lists */
@@ -56,8 +57,8 @@ struct gsi_trans {
 
        bool cancelled;                 /* true if transaction was cancelled */
 
-       u8 tre_count;                   /* # TREs requested */
-       u8 used;                        /* # entries used in sgl[] */
+       u8 rsvd_count;                  /* # TREs requested */
+       u8 used_count;                  /* # entries used in sgl[] */
        u32 len;                        /* total # bytes across sgl[] */
 
        union {
index e58cd44..6dea402 100644 (file)
@@ -353,13 +353,13 @@ int ipa_cmd_pool_init(struct gsi_channel *channel, u32 tre_max)
        /* This is as good a place as any to validate build constants */
        ipa_cmd_validate_build();
 
-       /* Even though command payloads are allocated one at a time,
-        * a single transaction can require up to tlv_count of them,
-        * so we treat them as if that many can be allocated at once.
+       /* Command payloads are allocated one at a time, but a single
+        * transaction can require up to the maximum supported by the
+        * channel; treat them as if they were allocated all at once.
         */
        return gsi_trans_pool_init_dma(dev, &trans_info->cmd_pool,
                                       sizeof(union ipa_cmd_payload),
-                                      tre_max, channel->tlv_count);
+                                      tre_max, channel->trans_tre_max);
 }
 
 void ipa_cmd_pool_exit(struct gsi_channel *channel)
index d3b3255..66d2bfd 100644 (file)
@@ -1020,7 +1020,7 @@ int ipa_endpoint_skb_tx(struct ipa_endpoint *endpoint, struct sk_buff *skb)
         * If not, see if we can linearize it before giving up.
         */
        nr_frags = skb_shinfo(skb)->nr_frags;
-       if (1 + nr_frags > endpoint->trans_tre_max) {
+       if (nr_frags > endpoint->skb_frag_max) {
                if (skb_linearize(skb))
                        return -E2BIG;
                nr_frags = 0;
@@ -1368,18 +1368,14 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint,
        }
 }
 
-/* Complete a TX transaction, command or from ipa_endpoint_skb_tx() */
-static void ipa_endpoint_tx_complete(struct ipa_endpoint *endpoint,
-                                    struct gsi_trans *trans)
-{
-}
-
-/* Complete transaction initiated in ipa_endpoint_replenish_one() */
-static void ipa_endpoint_rx_complete(struct ipa_endpoint *endpoint,
-                                    struct gsi_trans *trans)
+void ipa_endpoint_trans_complete(struct ipa_endpoint *endpoint,
+                                struct gsi_trans *trans)
 {
        struct page *page;
 
+       if (endpoint->toward_ipa)
+               return;
+
        if (trans->cancelled)
                goto done;
 
@@ -1393,15 +1389,6 @@ done:
        ipa_endpoint_replenish(endpoint);
 }
 
-void ipa_endpoint_trans_complete(struct ipa_endpoint *endpoint,
-                                struct gsi_trans *trans)
-{
-       if (endpoint->toward_ipa)
-               ipa_endpoint_tx_complete(endpoint, trans);
-       else
-               ipa_endpoint_rx_complete(endpoint, trans);
-}
-
 void ipa_endpoint_trans_release(struct ipa_endpoint *endpoint,
                                struct gsi_trans *trans)
 {
@@ -1721,7 +1708,7 @@ static void ipa_endpoint_setup_one(struct ipa_endpoint *endpoint)
        if (endpoint->ee_id != GSI_EE_AP)
                return;
 
-       endpoint->trans_tre_max = gsi_channel_trans_tre_max(gsi, channel_id);
+       endpoint->skb_frag_max = gsi->channel[channel_id].trans_tre_max - 1;
        if (!endpoint->toward_ipa) {
                /* RX transactions require a single TRE, so the maximum
                 * backlog is the same as the maximum outstanding TREs.
index 01790c6..28e0a73 100644 (file)
@@ -142,7 +142,7 @@ enum ipa_replenish_flag {
  * @endpoint_id:       IPA endpoint number
  * @toward_ipa:                Endpoint direction (true = TX, false = RX)
  * @config:            Default endpoint configuration
- * @trans_tre_max:     Maximum number of TRE descriptors per transaction
+ * @skb_frag_max:      Maximum allowed number of TX SKB fragments
  * @evt_ring_id:       GSI event ring used by the endpoint
  * @netdev:            Network device pointer, if endpoint uses one
  * @replenish_flags:   Replenishing state flags
@@ -157,7 +157,7 @@ struct ipa_endpoint {
        bool toward_ipa;
        struct ipa_endpoint_config config;
 
-       u32 trans_tre_max;
+       u32 skb_frag_max;       /* Used for netdev TX only */
        u32 evt_ring_id;
 
        /* Net device this endpoint is associated with, if any */
index 3837c89..de94921 100644 (file)
@@ -47,11 +47,11 @@ typedef enum {
 } ipvl_hdr_type;
 
 struct ipvl_pcpu_stats {
-       u64                     rx_pkts;
-       u64                     rx_bytes;
-       u64                     rx_mcast;
-       u64                     tx_pkts;
-       u64                     tx_bytes;
+       u64_stats_t             rx_pkts;
+       u64_stats_t             rx_bytes;
+       u64_stats_t             rx_mcast;
+       u64_stats_t             tx_pkts;
+       u64_stats_t             tx_bytes;
        struct u64_stats_sync   syncp;
        u32                     rx_errs;
        u32                     tx_drps;
index 6ffb274..dfeb5b3 100644 (file)
@@ -19,10 +19,10 @@ void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
 
                pcptr = this_cpu_ptr(ipvlan->pcpu_stats);
                u64_stats_update_begin(&pcptr->syncp);
-               pcptr->rx_pkts++;
-               pcptr->rx_bytes += len;
+               u64_stats_inc(&pcptr->rx_pkts);
+               u64_stats_add(&pcptr->rx_bytes, len);
                if (mcast)
-                       pcptr->rx_mcast++;
+                       u64_stats_inc(&pcptr->rx_mcast);
                u64_stats_update_end(&pcptr->syncp);
        } else {
                this_cpu_inc(ipvlan->pcpu_stats->rx_errs);
index aa28a29..49ba8a5 100644 (file)
@@ -224,8 +224,8 @@ static netdev_tx_t ipvlan_start_xmit(struct sk_buff *skb,
                pcptr = this_cpu_ptr(ipvlan->pcpu_stats);
 
                u64_stats_update_begin(&pcptr->syncp);
-               pcptr->tx_pkts++;
-               pcptr->tx_bytes += skblen;
+               u64_stats_inc(&pcptr->tx_pkts);
+               u64_stats_add(&pcptr->tx_bytes, skblen);
                u64_stats_update_end(&pcptr->syncp);
        } else {
                this_cpu_inc(ipvlan->pcpu_stats->tx_drps);
@@ -300,11 +300,11 @@ static void ipvlan_get_stats64(struct net_device *dev,
                        pcptr = per_cpu_ptr(ipvlan->pcpu_stats, idx);
                        do {
                                strt= u64_stats_fetch_begin_irq(&pcptr->syncp);
-                               rx_pkts = pcptr->rx_pkts;
-                               rx_bytes = pcptr->rx_bytes;
-                               rx_mcast = pcptr->rx_mcast;
-                               tx_pkts = pcptr->tx_pkts;
-                               tx_bytes = pcptr->tx_bytes;
+                               rx_pkts = u64_stats_read(&pcptr->rx_pkts);
+                               rx_bytes = u64_stats_read(&pcptr->rx_bytes);
+                               rx_mcast = u64_stats_read(&pcptr->rx_mcast);
+                               tx_pkts = u64_stats_read(&pcptr->tx_pkts);
+                               tx_bytes = u64_stats_read(&pcptr->tx_bytes);
                        } while (u64_stats_fetch_retry_irq(&pcptr->syncp,
                                                           strt));
 
@@ -315,8 +315,8 @@ static void ipvlan_get_stats64(struct net_device *dev,
                        s->tx_bytes += tx_bytes;
 
                        /* u32 values are updated without syncp protection. */
-                       rx_errs += pcptr->rx_errs;
-                       tx_drps += pcptr->tx_drps;
+                       rx_errs += READ_ONCE(pcptr->rx_errs);
+                       tx_drps += READ_ONCE(pcptr->tx_drps);
                }
                s->rx_errors = rx_errs;
                s->rx_dropped = rx_errs;
index 817577e..c881e1b 100644 (file)
@@ -523,8 +523,8 @@ static void count_tx(struct net_device *dev, int ret, int len)
                struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats);
 
                u64_stats_update_begin(&stats->syncp);
-               stats->tx_packets++;
-               stats->tx_bytes += len;
+               u64_stats_inc(&stats->tx_packets);
+               u64_stats_add(&stats->tx_bytes, len);
                u64_stats_update_end(&stats->syncp);
        }
 }
@@ -825,8 +825,8 @@ static void count_rx(struct net_device *dev, int len)
        struct pcpu_sw_netstats *stats = this_cpu_ptr(dev->tstats);
 
        u64_stats_update_begin(&stats->syncp);
-       stats->rx_packets++;
-       stats->rx_bytes += len;
+       u64_stats_inc(&stats->rx_packets);
+       u64_stats_add(&stats->rx_bytes, len);
        u64_stats_update_end(&stats->syncp);
 }
 
@@ -3462,7 +3462,7 @@ static int macsec_dev_init(struct net_device *dev)
                memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
 
        /* Get macsec's reference to real_dev */
-       dev_hold_track(real_dev, &macsec->dev_tracker, GFP_KERNEL);
+       netdev_hold(real_dev, &macsec->dev_tracker, GFP_KERNEL);
 
        return 0;
 }
@@ -3710,7 +3710,7 @@ static void macsec_free_netdev(struct net_device *dev)
        free_percpu(macsec->secy.tx_sc.stats);
 
        /* Get rid of the macsec's reference to real_dev */
-       dev_put_track(macsec->real_dev, &macsec->dev_tracker);
+       netdev_put(macsec->real_dev, &macsec->dev_tracker);
 }
 
 static void macsec_setup(struct net_device *dev)
index eff75be..1080d6e 100644 (file)
@@ -575,8 +575,8 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
 
                pcpu_stats = this_cpu_ptr(vlan->pcpu_stats);
                u64_stats_update_begin(&pcpu_stats->syncp);
-               pcpu_stats->tx_packets++;
-               pcpu_stats->tx_bytes += len;
+               u64_stats_inc(&pcpu_stats->tx_packets);
+               u64_stats_add(&pcpu_stats->tx_bytes, len);
                u64_stats_update_end(&pcpu_stats->syncp);
        } else {
                this_cpu_inc(vlan->pcpu_stats->tx_dropped);
@@ -915,7 +915,7 @@ static int macvlan_init(struct net_device *dev)
        port->count += 1;
 
        /* Get macvlan's reference to lowerdev */
-       dev_hold_track(lowerdev, &vlan->dev_tracker, GFP_KERNEL);
+       netdev_hold(lowerdev, &vlan->dev_tracker, GFP_KERNEL);
 
        return 0;
 }
@@ -949,11 +949,11 @@ static void macvlan_dev_get_stats64(struct net_device *dev,
                        p = per_cpu_ptr(vlan->pcpu_stats, i);
                        do {
                                start = u64_stats_fetch_begin_irq(&p->syncp);
-                               rx_packets      = p->rx_packets;
-                               rx_bytes        = p->rx_bytes;
-                               rx_multicast    = p->rx_multicast;
-                               tx_packets      = p->tx_packets;
-                               tx_bytes        = p->tx_bytes;
+                               rx_packets      = u64_stats_read(&p->rx_packets);
+                               rx_bytes        = u64_stats_read(&p->rx_bytes);
+                               rx_multicast    = u64_stats_read(&p->rx_multicast);
+                               tx_packets      = u64_stats_read(&p->tx_packets);
+                               tx_bytes        = u64_stats_read(&p->tx_bytes);
                        } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                        stats->rx_packets       += rx_packets;
@@ -964,8 +964,8 @@ static void macvlan_dev_get_stats64(struct net_device *dev,
                        /* rx_errors & tx_dropped are u32, updated
                         * without syncp protection.
                         */
-                       rx_errors       += p->rx_errors;
-                       tx_dropped      += p->tx_dropped;
+                       rx_errors       += READ_ONCE(p->rx_errors);
+                       tx_dropped      += READ_ONCE(p->tx_dropped);
                }
                stats->rx_errors        = rx_errors;
                stats->rx_dropped       = rx_errors;
@@ -1185,7 +1185,7 @@ static void macvlan_dev_free(struct net_device *dev)
        struct macvlan_dev *vlan = netdev_priv(dev);
 
        /* Get rid of the macvlan's reference to lowerdev */
-       dev_put_track(vlan->lowerdev, &vlan->dev_tracker);
+       netdev_put(vlan->lowerdev, &vlan->dev_tracker);
 }
 
 void macvlan_common_setup(struct net_device *dev)
index ab8cd55..ddac61d 100644 (file)
@@ -721,7 +721,7 @@ restart:
                                __netpoll_cleanup(&nt->np);
 
                                spin_lock_irqsave(&target_list_lock, flags);
-                               dev_put_track(nt->np.dev, &nt->np.dev_tracker);
+                               netdev_put(nt->np.dev, &nt->np.dev_tracker);
                                nt->np.dev = NULL;
                                nt->enabled = false;
                                stopped = true;
index 22ba7b0..6289b7c 100644 (file)
@@ -6,8 +6,8 @@
 menu "PCS device drivers"
 
 config PCS_XPCS
-       tristate "Synopsys DesignWare XPCS controller"
-       depends on MDIO_DEVICE && MDIO_BUS
+       tristate
+       select PHYLINK
        help
          This module provides helper functions for Synopsys DesignWare XPCS
          controllers.
@@ -18,4 +18,12 @@ config PCS_LYNX
          This module provides helpers to phylink for managing the Lynx PCS
          which is part of the Layerscape and QorIQ Ethernet SERDES.
 
+config PCS_RZN1_MIIC
+       tristate "Renesas RZ/N1 MII converter"
+       depends on OF && (ARCH_RZN1 || COMPILE_TEST)
+       help
+         This module provides a driver for the MII converter that is available
+         on RZ/N1 SoCs. This PCS converts MII to RMII/RGMII or can be set in
+         pass-through mode for MII.
+
 endmenu
index 0603d46..0ff5388 100644 (file)
@@ -5,3 +5,4 @@ pcs_xpcs-$(CONFIG_PCS_XPCS)     := pcs-xpcs.o pcs-xpcs-nxp.o
 
 obj-$(CONFIG_PCS_XPCS)         += pcs_xpcs.o
 obj-$(CONFIG_PCS_LYNX)         += pcs-lynx.o
+obj-$(CONFIG_PCS_RZN1_MIIC)    += pcs-rzn1-miic.o
index fd34453..7d5fc7f 100644 (file)
@@ -71,12 +71,10 @@ static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs,
 static void lynx_pcs_get_state_2500basex(struct mdio_device *pcs,
                                         struct phylink_link_state *state)
 {
-       struct mii_bus *bus = pcs->bus;
-       int addr = pcs->addr;
        int bmsr, lpa;
 
-       bmsr = mdiobus_read(bus, addr, MII_BMSR);
-       lpa = mdiobus_read(bus, addr, MII_LPA);
+       bmsr = mdiodev_read(pcs, MII_BMSR);
+       lpa = mdiodev_read(pcs, MII_LPA);
        if (bmsr < 0 || lpa < 0) {
                state->link = false;
                return;
@@ -124,57 +122,39 @@ static void lynx_pcs_get_state(struct phylink_pcs *pcs,
                state->link, state->an_enabled, state->an_complete);
 }
 
-static int lynx_pcs_config_1000basex(struct mdio_device *pcs,
-                                    unsigned int mode,
-                                    const unsigned long *advertising)
+static int lynx_pcs_config_giga(struct mdio_device *pcs, unsigned int mode,
+                               phy_interface_t interface,
+                               const unsigned long *advertising)
 {
-       struct mii_bus *bus = pcs->bus;
-       int addr = pcs->addr;
        u32 link_timer;
-       int err;
-
-       link_timer = LINK_TIMER_VAL(IEEE8023_LINK_TIMER_NS);
-       mdiobus_write(bus, addr, LINK_TIMER_LO, link_timer & 0xffff);
-       mdiobus_write(bus, addr, LINK_TIMER_HI, link_timer >> 16);
-
-       err = mdiobus_modify(bus, addr, IF_MODE,
-                            IF_MODE_SGMII_EN | IF_MODE_USE_SGMII_AN,
-                            0);
-       if (err)
-               return err;
-
-       return phylink_mii_c22_pcs_config(pcs, mode,
-                                         PHY_INTERFACE_MODE_1000BASEX,
-                                         advertising);
-}
-
-static int lynx_pcs_config_sgmii(struct mdio_device *pcs, unsigned int mode,
-                                const unsigned long *advertising)
-{
-       struct mii_bus *bus = pcs->bus;
-       int addr = pcs->addr;
        u16 if_mode;
        int err;
 
-       if_mode = IF_MODE_SGMII_EN;
-       if (mode == MLO_AN_INBAND) {
-               u32 link_timer;
-
-               if_mode |= IF_MODE_USE_SGMII_AN;
-
-               /* Adjust link timer for SGMII */
-               link_timer = LINK_TIMER_VAL(SGMII_AN_LINK_TIMER_NS);
-               mdiobus_write(bus, addr, LINK_TIMER_LO, link_timer & 0xffff);
-               mdiobus_write(bus, addr, LINK_TIMER_HI, link_timer >> 16);
+       if (interface == PHY_INTERFACE_MODE_1000BASEX) {
+               link_timer = LINK_TIMER_VAL(IEEE8023_LINK_TIMER_NS);
+               mdiodev_write(pcs, LINK_TIMER_LO, link_timer & 0xffff);
+               mdiodev_write(pcs, LINK_TIMER_HI, link_timer >> 16);
+
+               if_mode = 0;
+       } else {
+               if_mode = IF_MODE_SGMII_EN;
+               if (mode == MLO_AN_INBAND) {
+                       if_mode |= IF_MODE_USE_SGMII_AN;
+
+                       /* Adjust link timer for SGMII */
+                       link_timer = LINK_TIMER_VAL(SGMII_AN_LINK_TIMER_NS);
+                       mdiodev_write(pcs, LINK_TIMER_LO, link_timer & 0xffff);
+                       mdiodev_write(pcs, LINK_TIMER_HI, link_timer >> 16);
+               }
        }
-       err = mdiobus_modify(bus, addr, IF_MODE,
+
+       err = mdiodev_modify(pcs, IF_MODE,
                             IF_MODE_SGMII_EN | IF_MODE_USE_SGMII_AN,
                             if_mode);
        if (err)
                return err;
 
-       return phylink_mii_c22_pcs_config(pcs, mode, PHY_INTERFACE_MODE_SGMII,
-                                        advertising);
+       return phylink_mii_c22_pcs_config(pcs, mode, interface, advertising);
 }
 
 static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, unsigned int mode,
@@ -204,10 +184,10 @@ static int lynx_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
 
        switch (ifmode) {
        case PHY_INTERFACE_MODE_1000BASEX:
-               return lynx_pcs_config_1000basex(lynx->mdio, mode, advertising);
        case PHY_INTERFACE_MODE_SGMII:
        case PHY_INTERFACE_MODE_QSGMII:
-               return lynx_pcs_config_sgmii(lynx->mdio, mode, advertising);
+               return lynx_pcs_config_giga(lynx->mdio, mode, ifmode,
+                                           advertising);
        case PHY_INTERFACE_MODE_2500BASEX:
                if (phylink_autoneg_inband(mode)) {
                        dev_err(&lynx->mdio->dev,
@@ -237,9 +217,7 @@ static void lynx_pcs_an_restart(struct phylink_pcs *pcs)
 static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode,
                                   int speed, int duplex)
 {
-       struct mii_bus *bus = pcs->bus;
        u16 if_mode = 0, sgmii_speed;
-       int addr = pcs->addr;
 
        /* The PCS needs to be configured manually only
         * when not operating on in-band mode
@@ -269,7 +247,7 @@ static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode,
        }
        if_mode |= IF_MODE_SPEED(sgmii_speed);
 
-       mdiobus_modify(bus, addr, IF_MODE,
+       mdiodev_modify(pcs, IF_MODE,
                       IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
                       if_mode);
 }
@@ -294,8 +272,6 @@ static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs,
                                       unsigned int mode,
                                       int speed, int duplex)
 {
-       struct mii_bus *bus = pcs->bus;
-       int addr = pcs->addr;
        u16 if_mode = 0;
 
        if (mode == MLO_AN_INBAND) {
@@ -307,7 +283,7 @@ static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs,
                if_mode |= IF_MODE_HALF_DUPLEX;
        if_mode |= IF_MODE_SPEED(SGMII_SPEED_2500);
 
-       mdiobus_modify(bus, addr, IF_MODE,
+       mdiodev_modify(pcs, IF_MODE,
                       IF_MODE_HALF_DUPLEX | IF_MODE_SPEED_MSK,
                       if_mode);
 }
diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c
new file mode 100644 (file)
index 0000000..c142411
--- /dev/null
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Schneider Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/mdio.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pcs-rzn1-miic.h>
+#include <linux/phylink.h>
+#include <linux/pm_runtime.h>
+#include <dt-bindings/net/pcs-rzn1-miic.h>
+
+#define MIIC_PRCMD                     0x0
+#define MIIC_ESID_CODE                 0x4
+
+#define MIIC_MODCTRL                   0x20
+#define MIIC_MODCTRL_SW_MODE           GENMASK(4, 0)
+
+#define MIIC_CONVCTRL(port)            (0x100 + (port) * 4)
+
+#define MIIC_CONVCTRL_CONV_SPEED       GENMASK(1, 0)
+#define CONV_MODE_10MBPS               0
+#define CONV_MODE_100MBPS              1
+#define CONV_MODE_1000MBPS             2
+
+#define MIIC_CONVCTRL_CONV_MODE                GENMASK(3, 2)
+#define CONV_MODE_MII                  0
+#define CONV_MODE_RMII                 1
+#define CONV_MODE_RGMII                        2
+
+#define MIIC_CONVCTRL_FULLD            BIT(8)
+#define MIIC_CONVCTRL_RGMII_LINK       BIT(12)
+#define MIIC_CONVCTRL_RGMII_DUPLEX     BIT(13)
+#define MIIC_CONVCTRL_RGMII_SPEED      GENMASK(15, 14)
+
+#define MIIC_CONVRST                   0x114
+#define MIIC_CONVRST_PHYIF_RST(port)   BIT(port)
+#define MIIC_CONVRST_PHYIF_RST_MASK    GENMASK(4, 0)
+
+#define MIIC_SWCTRL                    0x304
+#define MIIC_SWDUPC                    0x308
+
+#define MIIC_MAX_NR_PORTS              5
+
+#define MIIC_MODCTRL_CONF_CONV_NUM     6
+#define MIIC_MODCTRL_CONF_NONE         -1
+
+/**
+ * struct modctrl_match - Matching table entry for  convctrl configuration
+ *                       See section 8.2.1 of manual.
+ * @mode_cfg: Configuration value for convctrl
+ * @conv: Configuration of ethernet port muxes. First index is SWITCH_PORTIN,
+ *       then index 1 - 5 are CONV1 - CONV5.
+ */
+struct modctrl_match {
+       u32 mode_cfg;
+       u8 conv[MIIC_MODCTRL_CONF_CONV_NUM];
+};
+
+static struct modctrl_match modctrl_match_table[] = {
+       {0x0, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_SWITCH_PORTC, MIIC_SERCOS_PORTB, MIIC_SERCOS_PORTA}},
+       {0x1, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_SWITCH_PORTC, MIIC_ETHERCAT_PORTB, MIIC_ETHERCAT_PORTA}},
+       {0x2, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_ETHERCAT_PORTC, MIIC_ETHERCAT_PORTB, MIIC_ETHERCAT_PORTA}},
+       {0x3, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_SWITCH_PORTC, MIIC_SWITCH_PORTB, MIIC_SWITCH_PORTA}},
+
+       {0x8, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_SWITCH_PORTC, MIIC_SERCOS_PORTB, MIIC_SERCOS_PORTA}},
+       {0x9, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_SWITCH_PORTC, MIIC_ETHERCAT_PORTB, MIIC_ETHERCAT_PORTA}},
+       {0xA, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_ETHERCAT_PORTC, MIIC_ETHERCAT_PORTB, MIIC_ETHERCAT_PORTA}},
+       {0xB, {MIIC_RTOS_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+              MIIC_SWITCH_PORTC, MIIC_SWITCH_PORTB, MIIC_SWITCH_PORTA}},
+
+       {0x10, {MIIC_GMAC2_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+               MIIC_SWITCH_PORTC, MIIC_SERCOS_PORTB, MIIC_SERCOS_PORTA}},
+       {0x11, {MIIC_GMAC2_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+               MIIC_SWITCH_PORTC, MIIC_ETHERCAT_PORTB, MIIC_ETHERCAT_PORTA}},
+       {0x12, {MIIC_GMAC2_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+               MIIC_ETHERCAT_PORTC, MIIC_ETHERCAT_PORTB, MIIC_ETHERCAT_PORTA}},
+       {0x13, {MIIC_GMAC2_PORT, MIIC_GMAC1_PORT, MIIC_SWITCH_PORTD,
+               MIIC_SWITCH_PORTC, MIIC_SWITCH_PORTB, MIIC_SWITCH_PORTA}}
+};
+
+static const char * const conf_to_string[] = {
+       [MIIC_GMAC1_PORT]       = "GMAC1_PORT",
+       [MIIC_GMAC2_PORT]       = "GMAC2_PORT",
+       [MIIC_RTOS_PORT]        = "RTOS_PORT",
+       [MIIC_SERCOS_PORTA]     = "SERCOS_PORTA",
+       [MIIC_SERCOS_PORTB]     = "SERCOS_PORTB",
+       [MIIC_ETHERCAT_PORTA]   = "ETHERCAT_PORTA",
+       [MIIC_ETHERCAT_PORTB]   = "ETHERCAT_PORTB",
+       [MIIC_ETHERCAT_PORTC]   = "ETHERCAT_PORTC",
+       [MIIC_SWITCH_PORTA]     = "SWITCH_PORTA",
+       [MIIC_SWITCH_PORTB]     = "SWITCH_PORTB",
+       [MIIC_SWITCH_PORTC]     = "SWITCH_PORTC",
+       [MIIC_SWITCH_PORTD]     = "SWITCH_PORTD",
+       [MIIC_HSR_PORTA]        = "HSR_PORTA",
+       [MIIC_HSR_PORTB]        = "HSR_PORTB",
+};
+
+static const char *index_to_string[MIIC_MODCTRL_CONF_CONV_NUM] = {
+       "SWITCH_PORTIN",
+       "CONV1",
+       "CONV2",
+       "CONV3",
+       "CONV4",
+       "CONV5",
+};
+
+/**
+ * struct miic - MII converter structure
+ * @base: base address of the MII converter
+ * @dev: Device associated to the MII converter
+ * @clks: Clocks used for this device
+ * @nclk: Number of clocks
+ * @lock: Lock used for read-modify-write access
+ */
+struct miic {
+       void __iomem *base;
+       struct device *dev;
+       struct clk_bulk_data *clks;
+       int nclk;
+       spinlock_t lock;
+};
+
+/**
+ * struct miic_port - Per port MII converter struct
+ * @miic: backiling to MII converter structure
+ * @pcs: PCS structure associated to the port
+ * @port: port number
+ * @interface: interface mode of the port
+ */
+struct miic_port {
+       struct miic *miic;
+       struct phylink_pcs pcs;
+       int port;
+       phy_interface_t interface;
+};
+
+static struct miic_port *phylink_pcs_to_miic_port(struct phylink_pcs *pcs)
+{
+       return container_of(pcs, struct miic_port, pcs);
+}
+
+static void miic_reg_writel(struct miic *miic, int offset, u32 value)
+{
+       writel(value, miic->base + offset);
+}
+
+static u32 miic_reg_readl(struct miic *miic, int offset)
+{
+       return readl(miic->base + offset);
+}
+
+static void miic_reg_rmw(struct miic *miic, int offset, u32 mask, u32 val)
+{
+       u32 reg;
+
+       spin_lock(&miic->lock);
+
+       reg = miic_reg_readl(miic, offset);
+       reg &= ~mask;
+       reg |= val;
+       miic_reg_writel(miic, offset, reg);
+
+       spin_unlock(&miic->lock);
+}
+
+static void miic_converter_enable(struct miic *miic, int port, int enable)
+{
+       u32 val = 0;
+
+       if (enable)
+               val = MIIC_CONVRST_PHYIF_RST(port);
+
+       miic_reg_rmw(miic, MIIC_CONVRST, MIIC_CONVRST_PHYIF_RST(port), val);
+}
+
+static int miic_config(struct phylink_pcs *pcs, unsigned int mode,
+                      phy_interface_t interface,
+                      const unsigned long *advertising, bool permit)
+{
+       struct miic_port *miic_port = phylink_pcs_to_miic_port(pcs);
+       struct miic *miic = miic_port->miic;
+       u32 speed, conv_mode, val, mask;
+       int port = miic_port->port;
+
+       switch (interface) {
+       case PHY_INTERFACE_MODE_RMII:
+               conv_mode = CONV_MODE_RMII;
+               speed = CONV_MODE_100MBPS;
+               break;
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+               conv_mode = CONV_MODE_RGMII;
+               speed = CONV_MODE_1000MBPS;
+               break;
+       case PHY_INTERFACE_MODE_MII:
+               conv_mode = CONV_MODE_MII;
+               /* When in MII mode, speed should be set to 0 (which is actually
+                * CONV_MODE_10MBPS)
+                */
+               speed = CONV_MODE_10MBPS;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       val = FIELD_PREP(MIIC_CONVCTRL_CONV_MODE, conv_mode);
+       mask = MIIC_CONVCTRL_CONV_MODE;
+
+       /* Update speed only if we are going to change the interface because
+        * the link might already be up and it would break it if the speed is
+        * changed.
+        */
+       if (interface != miic_port->interface) {
+               val |= FIELD_PREP(MIIC_CONVCTRL_CONV_SPEED, speed);
+               mask |= MIIC_CONVCTRL_CONV_SPEED;
+               miic_port->interface = interface;
+       }
+
+       miic_reg_rmw(miic, MIIC_CONVCTRL(port), mask, val);
+       miic_converter_enable(miic_port->miic, miic_port->port, 1);
+
+       return 0;
+}
+
+static void miic_link_up(struct phylink_pcs *pcs, unsigned int mode,
+                        phy_interface_t interface, int speed, int duplex)
+{
+       struct miic_port *miic_port = phylink_pcs_to_miic_port(pcs);
+       struct miic *miic = miic_port->miic;
+       u32 conv_speed = 0, val = 0;
+       int port = miic_port->port;
+
+       if (duplex == DUPLEX_FULL)
+               val |= MIIC_CONVCTRL_FULLD;
+
+       /* No speed in MII through-mode */
+       if (interface != PHY_INTERFACE_MODE_MII) {
+               switch (speed) {
+               case SPEED_1000:
+                       conv_speed = CONV_MODE_1000MBPS;
+                       break;
+               case SPEED_100:
+                       conv_speed = CONV_MODE_100MBPS;
+                       break;
+               case SPEED_10:
+                       conv_speed = CONV_MODE_10MBPS;
+                       break;
+               default:
+                       return;
+               }
+       }
+
+       val |= FIELD_PREP(MIIC_CONVCTRL_CONV_SPEED, conv_speed);
+
+       miic_reg_rmw(miic, MIIC_CONVCTRL(port),
+                    (MIIC_CONVCTRL_CONV_SPEED | MIIC_CONVCTRL_FULLD), val);
+}
+
+static int miic_validate(struct phylink_pcs *pcs, unsigned long *supported,
+                        const struct phylink_link_state *state)
+{
+       if (phy_interface_mode_is_rgmii(state->interface) ||
+           state->interface == PHY_INTERFACE_MODE_RMII ||
+           state->interface == PHY_INTERFACE_MODE_MII)
+               return 1;
+
+       return -EINVAL;
+}
+
+static const struct phylink_pcs_ops miic_phylink_ops = {
+       .pcs_validate = miic_validate,
+       .pcs_config = miic_config,
+       .pcs_link_up = miic_link_up,
+};
+
+struct phylink_pcs *miic_create(struct device *dev, struct device_node *np)
+{
+       struct platform_device *pdev;
+       struct miic_port *miic_port;
+       struct device_node *pcs_np;
+       struct miic *miic;
+       u32 port;
+
+       if (!of_device_is_available(np))
+               return ERR_PTR(-ENODEV);
+
+       if (of_property_read_u32(np, "reg", &port))
+               return ERR_PTR(-EINVAL);
+
+       if (port > MIIC_MAX_NR_PORTS || port < 1)
+               return ERR_PTR(-EINVAL);
+
+       /* The PCS pdev is attached to the parent node */
+       pcs_np = of_get_parent(np);
+       if (!pcs_np)
+               return ERR_PTR(-ENODEV);
+
+       if (!of_device_is_available(pcs_np)) {
+               of_node_put(pcs_np);
+               return ERR_PTR(-ENODEV);
+       }
+
+       pdev = of_find_device_by_node(pcs_np);
+       of_node_put(pcs_np);
+       if (!pdev || !platform_get_drvdata(pdev))
+               return ERR_PTR(-EPROBE_DEFER);
+
+       miic_port = kzalloc(sizeof(*miic_port), GFP_KERNEL);
+       if (!miic_port)
+               return ERR_PTR(-ENOMEM);
+
+       miic = platform_get_drvdata(pdev);
+       device_link_add(dev, miic->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+
+       miic_port->miic = miic;
+       miic_port->port = port - 1;
+       miic_port->pcs.ops = &miic_phylink_ops;
+
+       return &miic_port->pcs;
+}
+EXPORT_SYMBOL(miic_create);
+
+void miic_destroy(struct phylink_pcs *pcs)
+{
+       struct miic_port *miic_port = phylink_pcs_to_miic_port(pcs);
+
+       miic_converter_enable(miic_port->miic, miic_port->port, 0);
+       kfree(miic_port);
+}
+EXPORT_SYMBOL(miic_destroy);
+
+static int miic_init_hw(struct miic *miic, u32 cfg_mode)
+{
+       int port;
+
+       /* Unlock write access to accessory registers (cf datasheet). If this
+        * is going to be used in conjunction with the Cortex-M3, this sequence
+        * will have to be moved in register write
+        */
+       miic_reg_writel(miic, MIIC_PRCMD, 0x00A5);
+       miic_reg_writel(miic, MIIC_PRCMD, 0x0001);
+       miic_reg_writel(miic, MIIC_PRCMD, 0xFFFE);
+       miic_reg_writel(miic, MIIC_PRCMD, 0x0001);
+
+       miic_reg_writel(miic, MIIC_MODCTRL,
+                       FIELD_PREP(MIIC_MODCTRL_SW_MODE, cfg_mode));
+
+       for (port = 0; port < MIIC_MAX_NR_PORTS; port++) {
+               miic_converter_enable(miic, port, 0);
+               /* Disable speed/duplex control from these registers, datasheet
+                * says switch registers should be used to setup switch port
+                * speed and duplex.
+                */
+               miic_reg_writel(miic, MIIC_SWCTRL, 0x0);
+               miic_reg_writel(miic, MIIC_SWDUPC, 0x0);
+       }
+
+       return 0;
+}
+
+static bool miic_modctrl_match(s8 table_val[MIIC_MODCTRL_CONF_CONV_NUM],
+                              s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM])
+{
+       int i;
+
+       for (i = 0; i < MIIC_MODCTRL_CONF_CONV_NUM; i++) {
+               if (dt_val[i] == MIIC_MODCTRL_CONF_NONE)
+                       continue;
+
+               if (dt_val[i] != table_val[i])
+                       return false;
+       }
+
+       return true;
+}
+
+static void miic_dump_conf(struct device *dev,
+                          s8 conf[MIIC_MODCTRL_CONF_CONV_NUM])
+{
+       const char *conf_name;
+       int i;
+
+       for (i = 0; i < MIIC_MODCTRL_CONF_CONV_NUM; i++) {
+               if (conf[i] != MIIC_MODCTRL_CONF_NONE)
+                       conf_name = conf_to_string[conf[i]];
+               else
+                       conf_name = "NONE";
+
+               dev_err(dev, "%s: %s\n", index_to_string[i], conf_name);
+       }
+}
+
+static int miic_match_dt_conf(struct device *dev,
+                             s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM],
+                             u32 *mode_cfg)
+{
+       struct modctrl_match *table_entry;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(modctrl_match_table); i++) {
+               table_entry = &modctrl_match_table[i];
+
+               if (miic_modctrl_match(table_entry->conv, dt_val)) {
+                       *mode_cfg = table_entry->mode_cfg;
+                       return 0;
+               }
+       }
+
+       dev_err(dev, "Failed to apply requested configuration\n");
+       miic_dump_conf(dev, dt_val);
+
+       return -EINVAL;
+}
+
+static int miic_parse_dt(struct device *dev, u32 *mode_cfg)
+{
+       s8 dt_val[MIIC_MODCTRL_CONF_CONV_NUM];
+       struct device_node *np = dev->of_node;
+       struct device_node *conv;
+       u32 conf;
+       int port;
+
+       memset(dt_val, MIIC_MODCTRL_CONF_NONE, sizeof(dt_val));
+
+       if (of_property_read_u32(np, "renesas,miic-switch-portin", &conf) == 0)
+               dt_val[0] = conf;
+
+       for_each_child_of_node(np, conv) {
+               if (of_property_read_u32(conv, "reg", &port))
+                       continue;
+
+               if (!of_device_is_available(conv))
+                       continue;
+
+               if (of_property_read_u32(conv, "renesas,miic-input", &conf) == 0)
+                       dt_val[port] = conf;
+       }
+
+       return miic_match_dt_conf(dev, dt_val, mode_cfg);
+}
+
+static int miic_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct miic *miic;
+       u32 mode_cfg;
+       int ret;
+
+       ret = miic_parse_dt(dev, &mode_cfg);
+       if (ret < 0)
+               return ret;
+
+       miic = devm_kzalloc(dev, sizeof(*miic), GFP_KERNEL);
+       if (!miic)
+               return -ENOMEM;
+
+       spin_lock_init(&miic->lock);
+       miic->dev = dev;
+       miic->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(miic->base))
+               return PTR_ERR(miic->base);
+
+       ret = devm_pm_runtime_enable(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = pm_runtime_resume_and_get(dev);
+       if (ret < 0)
+               return ret;
+
+       ret = miic_init_hw(miic, mode_cfg);
+       if (ret)
+               goto disable_runtime_pm;
+
+       /* miic_create() relies on that fact that data are attached to the
+        * platform device to determine if the driver is ready so this needs to
+        * be the last thing to be done after everything is initialized
+        * properly.
+        */
+       platform_set_drvdata(pdev, miic);
+
+       return 0;
+
+disable_runtime_pm:
+       pm_runtime_put(dev);
+
+       return ret;
+}
+
+static int miic_remove(struct platform_device *pdev)
+{
+       pm_runtime_put(&pdev->dev);
+
+       return 0;
+}
+
+static const struct of_device_id miic_of_mtable[] = {
+       { .compatible = "renesas,rzn1-miic" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, miic_of_mtable);
+
+static struct platform_driver miic_driver = {
+       .driver = {
+               .name    = "rzn1_miic",
+               .suppress_bind_attrs = true,
+               .of_match_table = miic_of_mtable,
+       },
+       .probe = miic_probe,
+       .remove = miic_remove,
+};
+module_platform_driver(miic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas MII converter PCS driver");
+MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>");
index 4cfd05c..ab0af1d 100644 (file)
@@ -77,6 +77,14 @@ static const int xpcs_sgmii_features[] = {
        __ETHTOOL_LINK_MODE_MASK_NBITS,
 };
 
+static const int xpcs_1000basex_features[] = {
+       ETHTOOL_LINK_MODE_Pause_BIT,
+       ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+       ETHTOOL_LINK_MODE_Autoneg_BIT,
+       ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+       __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+
 static const int xpcs_2500basex_features[] = {
        ETHTOOL_LINK_MODE_Pause_BIT,
        ETHTOOL_LINK_MODE_Asym_Pause_BIT,
@@ -102,6 +110,10 @@ static const phy_interface_t xpcs_sgmii_interfaces[] = {
        PHY_INTERFACE_MODE_SGMII,
 };
 
+static const phy_interface_t xpcs_1000basex_interfaces[] = {
+       PHY_INTERFACE_MODE_1000BASEX,
+};
+
 static const phy_interface_t xpcs_2500basex_interfaces[] = {
        PHY_INTERFACE_MODE_2500BASEX,
        PHY_INTERFACE_MODE_MAX,
@@ -112,6 +124,7 @@ enum {
        DW_XPCS_10GKR,
        DW_XPCS_XLGMII,
        DW_XPCS_SGMII,
+       DW_XPCS_1000BASEX,
        DW_XPCS_2500BASEX,
        DW_XPCS_INTERFACE_MAX,
 };
@@ -189,6 +202,14 @@ int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
        return mdiobus_c45_write(bus, addr, dev, reg, val);
 }
 
+static int xpcs_modify_changed(struct dw_xpcs *xpcs, int dev, u32 reg,
+                              u16 mask, u16 set)
+{
+       u32 reg_addr = mdiobus_c45_addr(dev, reg);
+
+       return mdiodev_modify_changed(xpcs->mdiodev, reg_addr, mask, set);
+}
+
 static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)
 {
        return xpcs_read(xpcs, dev, DW_VENDOR | reg);
@@ -237,6 +258,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs,
                break;
        case DW_AN_C37_SGMII:
        case DW_2500BASEX:
+       case DW_AN_C37_1000BASEX:
                dev = MDIO_MMD_VEND2;
                break;
        default:
@@ -772,6 +794,68 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
        return ret;
 }
 
+static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, unsigned int mode,
+                                         const unsigned long *advertising)
+{
+       phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX;
+       int ret, mdio_ctrl, adv;
+       bool changed = 0;
+
+       /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
+        * be disabled first:-
+        * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
+        * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37)
+        */
+       mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
+       if (mdio_ctrl < 0)
+               return mdio_ctrl;
+
+       if (mdio_ctrl & AN_CL37_EN) {
+               ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
+                                mdio_ctrl & ~AN_CL37_EN);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
+       if (ret < 0)
+               return ret;
+
+       ret &= ~DW_VR_MII_PCS_MODE_MASK;
+       ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
+       if (ret < 0)
+               return ret;
+
+       /* Check for advertising changes and update the C45 MII ADV
+        * register accordingly.
+        */
+       adv = phylink_mii_c22_pcs_encode_advertisement(interface,
+                                                      advertising);
+       if (adv >= 0) {
+               ret = xpcs_modify_changed(xpcs, MDIO_MMD_VEND2,
+                                         MII_ADVERTISE, 0xffff, adv);
+               if (ret < 0)
+                       return ret;
+
+               changed = ret;
+       }
+
+       /* Clear CL37 AN complete status */
+       ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+       if (ret < 0)
+               return ret;
+
+       if (phylink_autoneg_inband(mode) &&
+           linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) {
+               ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
+                                mdio_ctrl | AN_CL37_EN);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return changed;
+}
+
 static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
 {
        int ret;
@@ -795,7 +879,7 @@ static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
 }
 
 int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
-                  unsigned int mode)
+                  unsigned int mode, const unsigned long *advertising)
 {
        const struct xpcs_compat *compat;
        int ret;
@@ -817,6 +901,12 @@ int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
                if (ret)
                        return ret;
                break;
+       case DW_AN_C37_1000BASEX:
+               ret = xpcs_config_aneg_c37_1000basex(xpcs, mode,
+                                                    advertising);
+               if (ret)
+                       return ret;
+               break;
        case DW_2500BASEX:
                ret = xpcs_config_2500basex(xpcs);
                if (ret)
@@ -843,7 +933,7 @@ static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
 {
        struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
 
-       return xpcs_do_config(xpcs, interface, mode);
+       return xpcs_do_config(xpcs, interface, mode, advertising);
 }
 
 static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
@@ -864,7 +954,7 @@ static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
 
                state->link = 0;
 
-               return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND);
+               return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND, NULL);
        }
 
        if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) {
@@ -921,6 +1011,29 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
        return 0;
 }
 
+static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
+                                       struct phylink_link_state *state)
+{
+       int lpa, bmsr;
+
+       if (state->an_enabled) {
+               /* Reset link state */
+               state->link = false;
+
+               lpa = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_LPA);
+               if (lpa < 0 || lpa & LPA_RFAULT)
+                       return lpa;
+
+               bmsr = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR);
+               if (bmsr < 0)
+                       return bmsr;
+
+               phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
+       }
+
+       return 0;
+}
+
 static void xpcs_get_state(struct phylink_pcs *pcs,
                           struct phylink_link_state *state)
 {
@@ -948,6 +1061,13 @@ static void xpcs_get_state(struct phylink_pcs *pcs,
                               ERR_PTR(ret));
                }
                break;
+       case DW_AN_C37_1000BASEX:
+               ret = xpcs_get_state_c37_1000basex(xpcs, state);
+               if (ret) {
+                       pr_err("xpcs_get_state_c37_1000basex returned %pe\n",
+                              ERR_PTR(ret));
+               }
+               break;
        default:
                return;
        }
@@ -961,22 +1081,35 @@ static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
        if (phylink_autoneg_inband(mode))
                return;
 
+       val = mii_bmcr_encode_fixed(speed, duplex);
+       ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
+       if (ret)
+               pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
+}
+
+static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int mode,
+                                  int speed, int duplex)
+{
+       int val, ret;
+
+       if (phylink_autoneg_inband(mode))
+               return;
+
        switch (speed) {
        case SPEED_1000:
                val = BMCR_SPEED1000;
                break;
        case SPEED_100:
-               val = BMCR_SPEED100;
-               break;
        case SPEED_10:
-               val = BMCR_SPEED10;
-               break;
        default:
+               pr_err("%s: speed = %d\n", __func__, speed);
                return;
        }
 
        if (duplex == DUPLEX_FULL)
                val |= BMCR_FULLDPLX;
+       else
+               pr_err("%s: half duplex not supported\n", __func__);
 
        ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
        if (ret)
@@ -992,9 +1125,23 @@ void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
                return xpcs_config_usxgmii(xpcs, speed);
        if (interface == PHY_INTERFACE_MODE_SGMII)
                return xpcs_link_up_sgmii(xpcs, mode, speed, duplex);
+       if (interface == PHY_INTERFACE_MODE_1000BASEX)
+               return xpcs_link_up_1000basex(xpcs, mode, speed, duplex);
 }
 EXPORT_SYMBOL_GPL(xpcs_link_up);
 
+static void xpcs_an_restart(struct phylink_pcs *pcs)
+{
+       struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
+       int ret;
+
+       ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+       if (ret >= 0) {
+               ret |= BMCR_ANRESTART;
+               xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
+       }
+}
+
 static u32 xpcs_get_id(struct dw_xpcs *xpcs)
 {
        int ret;
@@ -1060,6 +1207,12 @@ static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
                .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
                .an_mode = DW_AN_C37_SGMII,
        },
+       [DW_XPCS_1000BASEX] = {
+               .supported = xpcs_1000basex_features,
+               .interface = xpcs_1000basex_interfaces,
+               .num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces),
+               .an_mode = DW_AN_C37_1000BASEX,
+       },
        [DW_XPCS_2500BASEX] = {
                .supported = xpcs_2500basex_features,
                .interface = xpcs_2500basex_interfaces,
@@ -1115,6 +1268,7 @@ static const struct phylink_pcs_ops xpcs_phylink_ops = {
        .pcs_validate = xpcs_validate,
        .pcs_config = xpcs_config,
        .pcs_get_state = xpcs_get_state,
+       .pcs_an_restart = xpcs_an_restart,
        .pcs_link_up = xpcs_link_up,
 };
 
index 35651d3..770df50 100644 (file)
 
 int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg);
 int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val);
-
 int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs);
 int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs);
 int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs);
index 9fee639..c57a026 100644 (file)
@@ -104,6 +104,8 @@ config AX88796B_PHY
 config BROADCOM_PHY
        tristate "Broadcom 54XX PHYs"
        select BCM_NET_PHYLIB
+       select BCM_NET_PHYPTP if NETWORK_PHY_TIMESTAMPING
+       depends on PTP_1588_CLOCK_OPTIONAL
        help
          Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
          BCM5481, BCM54810 and BCM5482 PHYs.
@@ -160,6 +162,9 @@ config BCM_CYGNUS_PHY
 config BCM_NET_PHYLIB
        tristate
 
+config BCM_NET_PHYPTP
+       tristate
+
 config CICADA_PHY
        tristate "Cicada PHYs"
        help
@@ -216,6 +221,8 @@ config MARVELL_88X2222_PHY
 
 config MAXLINEAR_GPHY
        tristate "Maxlinear Ethernet PHYs"
+       select POLYNOMIAL if HWMON
+       depends on HWMON || HWMON=n
        help
          Support for the Maxlinear GPY115, GPY211, GPY212, GPY215,
          GPY241, GPY245 PHYs.
index b12b1d8..f7138d3 100644 (file)
@@ -47,6 +47,7 @@ obj-$(CONFIG_BCM84881_PHY)    += bcm84881.o
 obj-$(CONFIG_BCM87XX_PHY)      += bcm87xx.o
 obj-$(CONFIG_BCM_CYGNUS_PHY)   += bcm-cygnus.o
 obj-$(CONFIG_BCM_NET_PHYLIB)   += bcm-phy-lib.o
+obj-$(CONFIG_BCM_NET_PHYPTP)   += bcm-phy-ptp.o
 obj-$(CONFIG_BROADCOM_PHY)     += broadcom.o
 obj-$(CONFIG_CICADA_PHY)       += cicada.o
 obj-$(CONFIG_CORTINA_PHY)      += cortina.o
index c7047f5..8b7a46d 100644 (file)
@@ -22,6 +22,7 @@
 #define PHY_ID_AQR107  0x03a1b4e0
 #define PHY_ID_AQCS109 0x03a1b5c2
 #define PHY_ID_AQR405  0x03a1b4b0
+#define PHY_ID_AQR113C 0x31c31c12
 
 #define MDIO_PHYXS_VEND_IF_STATUS              0xe812
 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK    GENMASK(7, 3)
@@ -697,6 +698,24 @@ static struct phy_driver aqr_driver[] = {
        .handle_interrupt = aqr_handle_interrupt,
        .read_status    = aqr_read_status,
 },
+{
+       PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
+       .name           = "Aquantia AQR113C",
+       .probe          = aqr107_probe,
+       .config_init    = aqr107_config_init,
+       .config_aneg    = aqr_config_aneg,
+       .config_intr    = aqr_config_intr,
+       .handle_interrupt       = aqr_handle_interrupt,
+       .read_status    = aqr107_read_status,
+       .get_tunable    = aqr107_get_tunable,
+       .set_tunable    = aqr107_set_tunable,
+       .suspend        = aqr107_suspend,
+       .resume         = aqr107_resume,
+       .get_sset_count = aqr107_get_sset_count,
+       .get_strings    = aqr107_get_strings,
+       .get_stats      = aqr107_get_stats,
+       .link_change_notify = aqr107_link_change_notify,
+},
 };
 
 module_phy_driver(aqr_driver);
@@ -709,6 +728,7 @@ static struct mdio_device_id __maybe_unused aqr_tbl[] = {
        { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
        { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
        { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
+       { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
        { }
 };
 
index c3842f8..9902fb1 100644 (file)
@@ -87,4 +87,23 @@ int bcm_phy_cable_test_start_rdb(struct phy_device *phydev);
 int bcm_phy_cable_test_start(struct phy_device *phydev);
 int bcm_phy_cable_test_get_status(struct phy_device *phydev, bool *finished);
 
+#if IS_ENABLED(CONFIG_BCM_NET_PHYPTP)
+struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev);
+void bcm_ptp_config_init(struct phy_device *phydev);
+void bcm_ptp_stop(struct bcm_ptp_private *priv);
+#else
+static inline struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev)
+{
+       return NULL;
+}
+
+static inline void bcm_ptp_config_init(struct phy_device *phydev)
+{
+}
+
+static inline void bcm_ptp_stop(struct bcm_ptp_private *priv)
+{
+}
+#endif
+
 #endif /* _LINUX_BCM_PHY_LIB_H */
diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c
new file mode 100644 (file)
index 0000000..ef00d61
--- /dev/null
@@ -0,0 +1,944 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022 Meta Platforms Inc.
+ * Copyright (C) 2022 Jonathan Lemon <jonathan.lemon@gmail.com>
+ */
+
+#include <asm/unaligned.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+
+#include "bcm-phy-lib.h"
+
+/* IEEE 1588 Expansion registers */
+#define SLICE_CTRL             0x0810
+#define  SLICE_TX_EN                   BIT(0)
+#define  SLICE_RX_EN                   BIT(8)
+#define TX_EVENT_MODE          0x0811
+#define  MODE_TX_UPDATE_CF             BIT(0)
+#define  MODE_TX_REPLACE_TS_CF         BIT(1)
+#define  MODE_TX_REPLACE_TS            GENMASK(1, 0)
+#define RX_EVENT_MODE          0x0819
+#define  MODE_RX_UPDATE_CF             BIT(0)
+#define  MODE_RX_INSERT_TS_48          BIT(1)
+#define  MODE_RX_INSERT_TS_64          GENMASK(1, 0)
+
+#define MODE_EVT_SHIFT_SYNC            0
+#define MODE_EVT_SHIFT_DELAY_REQ       2
+#define MODE_EVT_SHIFT_PDELAY_REQ      4
+#define MODE_EVT_SHIFT_PDELAY_RESP     6
+
+#define MODE_SEL_SHIFT_PORT            0
+#define MODE_SEL_SHIFT_CPU             8
+
+#define RX_MODE_SEL(sel, evt, act) \
+       (((MODE_RX_##act) << (MODE_EVT_SHIFT_##evt)) << (MODE_SEL_SHIFT_##sel))
+
+#define TX_MODE_SEL(sel, evt, act) \
+       (((MODE_TX_##act) << (MODE_EVT_SHIFT_##evt)) << (MODE_SEL_SHIFT_##sel))
+
+/* needs global TS capture first */
+#define TX_TS_CAPTURE          0x0821
+#define  TX_TS_CAP_EN                  BIT(0)
+#define RX_TS_CAPTURE          0x0822
+#define  RX_TS_CAP_EN                  BIT(0)
+
+#define TIME_CODE_0            0x0854
+#define TIME_CODE_1            0x0855
+#define TIME_CODE_2            0x0856
+#define TIME_CODE_3            0x0857
+#define TIME_CODE_4            0x0858
+
+#define DPLL_SELECT            0x085b
+#define  DPLL_HB_MODE2                 BIT(6)
+
+#define SHADOW_CTRL            0x085c
+#define SHADOW_LOAD            0x085d
+#define  TIME_CODE_LOAD                        BIT(10)
+#define  SYNC_OUT_LOAD                 BIT(9)
+#define  NCO_TIME_LOAD                 BIT(7)
+#define  FREQ_LOAD                     BIT(6)
+#define INTR_MASK              0x085e
+#define INTR_STATUS            0x085f
+#define  INTC_FSYNC                    BIT(0)
+#define  INTC_SOP                      BIT(1)
+
+#define NCO_FREQ_LSB           0x0873
+#define NCO_FREQ_MSB           0x0874
+
+#define NCO_TIME_0             0x0875
+#define NCO_TIME_1             0x0876
+#define NCO_TIME_2_CTRL                0x0877
+#define  FREQ_MDIO_SEL                 BIT(14)
+
+#define SYNC_OUT_0             0x0878
+#define SYNC_OUT_1             0x0879
+#define SYNC_OUT_2             0x087a
+
+#define SYNC_IN_DIVIDER                0x087b
+
+#define SYNOUT_TS_0            0x087c
+#define SYNOUT_TS_1            0x087d
+#define SYNOUT_TS_2            0x087e
+
+#define NSE_CTRL               0x087f
+#define  NSE_GMODE_EN                  GENMASK(15, 14)
+#define  NSE_CAPTURE_EN                        BIT(13)
+#define  NSE_INIT                      BIT(12)
+#define  NSE_CPU_FRAMESYNC             BIT(5)
+#define  NSE_SYNC1_FRAMESYNC           BIT(3)
+#define  NSE_FRAMESYNC_MASK            GENMASK(5, 2)
+#define  NSE_PEROUT_EN                 BIT(1)
+#define  NSE_ONESHOT_EN                        BIT(0)
+#define  NSE_SYNC_OUT_MASK             GENMASK(1, 0)
+
+#define TS_READ_CTRL           0x0885
+#define  TS_READ_START                 BIT(0)
+#define  TS_READ_END                   BIT(1)
+
+#define HB_REG_0               0x0886
+#define HB_REG_1               0x0887
+#define HB_REG_2               0x0888
+#define HB_REG_3               0x08ec
+#define HB_REG_4               0x08ed
+#define HB_STAT_CTRL           0x088e
+#define  HB_READ_START                 BIT(10)
+#define  HB_READ_END                   BIT(11)
+#define  HB_READ_MASK                  GENMASK(11, 10)
+
+#define TS_REG_0               0x0889
+#define TS_REG_1               0x088a
+#define TS_REG_2               0x088b
+#define TS_REG_3               0x08c4
+
+#define TS_INFO_0              0x088c
+#define TS_INFO_1              0x088d
+
+#define TIMECODE_CTRL          0x08c3
+#define  TX_TIMECODE_SEL               GENMASK(7, 0)
+#define  RX_TIMECODE_SEL               GENMASK(15, 8)
+
+#define TIME_SYNC              0x0ff5
+#define  TIME_SYNC_EN                  BIT(0)
+
+struct bcm_ptp_private {
+       struct phy_device *phydev;
+       struct mii_timestamper mii_ts;
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info ptp_info;
+       struct ptp_pin_desc pin;
+       struct mutex mutex;
+       struct sk_buff_head tx_queue;
+       int tx_type;
+       bool hwts_rx;
+       u16 nse_ctrl;
+       bool pin_active;
+       struct delayed_work pin_work;
+};
+
+struct bcm_ptp_skb_cb {
+       unsigned long timeout;
+       u16 seq_id;
+       u8 msgtype;
+       bool discard;
+};
+
+struct bcm_ptp_capture {
+       ktime_t hwtstamp;
+       u16 seq_id;
+       u8 msgtype;
+       bool tx_dir;
+};
+
+#define BCM_SKB_CB(skb)                ((struct bcm_ptp_skb_cb *)(skb)->cb)
+#define SKB_TS_TIMEOUT         10                      /* jiffies */
+
+#define BCM_MAX_PULSE_8NS      ((1U << 9) - 1)
+#define BCM_MAX_PERIOD_8NS     ((1U << 30) - 1)
+
+#define BRCM_PHY_MODEL(phydev) \
+       ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
+
+static struct bcm_ptp_private *mii2priv(struct mii_timestamper *mii_ts)
+{
+       return container_of(mii_ts, struct bcm_ptp_private, mii_ts);
+}
+
+static struct bcm_ptp_private *ptp2priv(struct ptp_clock_info *info)
+{
+       return container_of(info, struct bcm_ptp_private, ptp_info);
+}
+
+static void bcm_ptp_get_framesync_ts(struct phy_device *phydev,
+                                    struct timespec64 *ts)
+{
+       u16 hb[4];
+
+       bcm_phy_write_exp(phydev, HB_STAT_CTRL, HB_READ_START);
+
+       hb[0] = bcm_phy_read_exp(phydev, HB_REG_0);
+       hb[1] = bcm_phy_read_exp(phydev, HB_REG_1);
+       hb[2] = bcm_phy_read_exp(phydev, HB_REG_2);
+       hb[3] = bcm_phy_read_exp(phydev, HB_REG_3);
+
+       bcm_phy_write_exp(phydev, HB_STAT_CTRL, HB_READ_END);
+       bcm_phy_write_exp(phydev, HB_STAT_CTRL, 0);
+
+       ts->tv_sec = (hb[3] << 16) | hb[2];
+       ts->tv_nsec = (hb[1] << 16) | hb[0];
+}
+
+static u16 bcm_ptp_framesync_disable(struct phy_device *phydev, u16 orig_ctrl)
+{
+       u16 ctrl = orig_ctrl & ~(NSE_FRAMESYNC_MASK | NSE_CAPTURE_EN);
+
+       bcm_phy_write_exp(phydev, NSE_CTRL, ctrl);
+
+       return ctrl;
+}
+
+static void bcm_ptp_framesync_restore(struct phy_device *phydev, u16 orig_ctrl)
+{
+       if (orig_ctrl & NSE_FRAMESYNC_MASK)
+               bcm_phy_write_exp(phydev, NSE_CTRL, orig_ctrl);
+}
+
+static void bcm_ptp_framesync(struct phy_device *phydev, u16 ctrl)
+{
+       /* trigger framesync - must have 0->1 transition. */
+       bcm_phy_write_exp(phydev, NSE_CTRL, ctrl | NSE_CPU_FRAMESYNC);
+}
+
+static int bcm_ptp_framesync_ts(struct phy_device *phydev,
+                               struct ptp_system_timestamp *sts,
+                               struct timespec64 *ts,
+                               u16 orig_ctrl)
+{
+       u16 ctrl, reg;
+       int i;
+
+       ctrl = bcm_ptp_framesync_disable(phydev, orig_ctrl);
+
+       ptp_read_system_prets(sts);
+
+       /* trigger framesync + capture */
+       bcm_ptp_framesync(phydev, ctrl | NSE_CAPTURE_EN);
+
+       ptp_read_system_postts(sts);
+
+       /* poll for FSYNC interrupt from TS capture */
+       for (i = 0; i < 10; i++) {
+               reg = bcm_phy_read_exp(phydev, INTR_STATUS);
+               if (reg & INTC_FSYNC) {
+                       bcm_ptp_get_framesync_ts(phydev, ts);
+                       break;
+               }
+       }
+
+       bcm_ptp_framesync_restore(phydev, orig_ctrl);
+
+       return reg & INTC_FSYNC ? 0 : -ETIMEDOUT;
+}
+
+static int bcm_ptp_gettimex(struct ptp_clock_info *info,
+                           struct timespec64 *ts,
+                           struct ptp_system_timestamp *sts)
+{
+       struct bcm_ptp_private *priv = ptp2priv(info);
+       int err;
+
+       mutex_lock(&priv->mutex);
+       err = bcm_ptp_framesync_ts(priv->phydev, sts, ts, priv->nse_ctrl);
+       mutex_unlock(&priv->mutex);
+
+       return err;
+}
+
+static int bcm_ptp_settime_locked(struct bcm_ptp_private *priv,
+                                 const struct timespec64 *ts)
+{
+       struct phy_device *phydev = priv->phydev;
+       u16 ctrl;
+       u64 ns;
+
+       ctrl = bcm_ptp_framesync_disable(phydev, priv->nse_ctrl);
+
+       /* set up time code */
+       bcm_phy_write_exp(phydev, TIME_CODE_0, ts->tv_nsec);
+       bcm_phy_write_exp(phydev, TIME_CODE_1, ts->tv_nsec >> 16);
+       bcm_phy_write_exp(phydev, TIME_CODE_2, ts->tv_sec);
+       bcm_phy_write_exp(phydev, TIME_CODE_3, ts->tv_sec >> 16);
+       bcm_phy_write_exp(phydev, TIME_CODE_4, ts->tv_sec >> 32);
+
+       /* set NCO counter to match */
+       ns = timespec64_to_ns(ts);
+       bcm_phy_write_exp(phydev, NCO_TIME_0, ns >> 4);
+       bcm_phy_write_exp(phydev, NCO_TIME_1, ns >> 20);
+       bcm_phy_write_exp(phydev, NCO_TIME_2_CTRL, (ns >> 36) & 0xfff);
+
+       /* set up load on next frame sync (auto-clears due to NSE_INIT) */
+       bcm_phy_write_exp(phydev, SHADOW_LOAD, TIME_CODE_LOAD | NCO_TIME_LOAD);
+
+       /* must have NSE_INIT in order to write time code */
+       bcm_ptp_framesync(phydev, ctrl | NSE_INIT);
+
+       bcm_ptp_framesync_restore(phydev, priv->nse_ctrl);
+
+       return 0;
+}
+
+static int bcm_ptp_settime(struct ptp_clock_info *info,
+                          const struct timespec64 *ts)
+{
+       struct bcm_ptp_private *priv = ptp2priv(info);
+       int err;
+
+       mutex_lock(&priv->mutex);
+       err = bcm_ptp_settime_locked(priv, ts);
+       mutex_unlock(&priv->mutex);
+
+       return err;
+}
+
+static int bcm_ptp_adjtime_locked(struct bcm_ptp_private *priv,
+                                 s64 delta_ns)
+{
+       struct timespec64 ts;
+       int err;
+       s64 ns;
+
+       err = bcm_ptp_framesync_ts(priv->phydev, NULL, &ts, priv->nse_ctrl);
+       if (!err) {
+               ns = timespec64_to_ns(&ts) + delta_ns;
+               ts = ns_to_timespec64(ns);
+               err = bcm_ptp_settime_locked(priv, &ts);
+       }
+       return err;
+}
+
+static int bcm_ptp_adjtime(struct ptp_clock_info *info, s64 delta_ns)
+{
+       struct bcm_ptp_private *priv = ptp2priv(info);
+       int err;
+
+       mutex_lock(&priv->mutex);
+       err = bcm_ptp_adjtime_locked(priv, delta_ns);
+       mutex_unlock(&priv->mutex);
+
+       return err;
+}
+
+/* A 125Mhz clock should adjust 8ns per pulse.
+ * The frequency adjustment base is 0x8000 0000, or 8*2^28.
+ *
+ * Frequency adjustment is
+ * adj = scaled_ppm * 8*2^28 / (10^6 * 2^16)
+ *   which simplifies to:
+ * adj = scaled_ppm * 2^9 / 5^6
+ */
+static int bcm_ptp_adjfine(struct ptp_clock_info *info, long scaled_ppm)
+{
+       struct bcm_ptp_private *priv = ptp2priv(info);
+       int neg_adj = 0;
+       u32 diff, freq;
+       u16 ctrl;
+       u64 adj;
+
+       if (scaled_ppm < 0) {
+               neg_adj = 1;
+               scaled_ppm = -scaled_ppm;
+       }
+
+       adj = scaled_ppm << 9;
+       diff = div_u64(adj, 15625);
+       freq = (8 << 28) + (neg_adj ? -diff : diff);
+
+       mutex_lock(&priv->mutex);
+
+       ctrl = bcm_ptp_framesync_disable(priv->phydev, priv->nse_ctrl);
+
+       bcm_phy_write_exp(priv->phydev, NCO_FREQ_LSB, freq);
+       bcm_phy_write_exp(priv->phydev, NCO_FREQ_MSB, freq >> 16);
+
+       bcm_phy_write_exp(priv->phydev, NCO_TIME_2_CTRL, FREQ_MDIO_SEL);
+
+       /* load on next framesync */
+       bcm_phy_write_exp(priv->phydev, SHADOW_LOAD, FREQ_LOAD);
+
+       bcm_ptp_framesync(priv->phydev, ctrl);
+
+       /* clear load */
+       bcm_phy_write_exp(priv->phydev, SHADOW_LOAD, 0);
+
+       bcm_ptp_framesync_restore(priv->phydev, priv->nse_ctrl);
+
+       mutex_unlock(&priv->mutex);
+
+       return 0;
+}
+
+static bool bcm_ptp_rxtstamp(struct mii_timestamper *mii_ts,
+                            struct sk_buff *skb, int type)
+{
+       struct bcm_ptp_private *priv = mii2priv(mii_ts);
+       struct skb_shared_hwtstamps *hwts;
+       struct ptp_header *header;
+       u32 sec, nsec;
+       u8 *data;
+       int off;
+
+       if (!priv->hwts_rx)
+               return false;
+
+       header = ptp_parse_header(skb, type);
+       if (!header)
+               return false;
+
+       data = (u8 *)(header + 1);
+       sec = get_unaligned_be32(data);
+       nsec = get_unaligned_be32(data + 4);
+
+       hwts = skb_hwtstamps(skb);
+       hwts->hwtstamp = ktime_set(sec, nsec);
+
+       off = data - skb->data + 8;
+       if (off < skb->len) {
+               memmove(data, data + 8, skb->len - off);
+               __pskb_trim(skb, skb->len - 8);
+       }
+
+       return false;
+}
+
+static bool bcm_ptp_get_tstamp(struct bcm_ptp_private *priv,
+                              struct bcm_ptp_capture *capts)
+{
+       struct phy_device *phydev = priv->phydev;
+       u16 ts[4], reg;
+       u32 sec, nsec;
+
+       mutex_lock(&priv->mutex);
+
+       reg = bcm_phy_read_exp(phydev, INTR_STATUS);
+       if ((reg & INTC_SOP) == 0) {
+               mutex_unlock(&priv->mutex);
+               return false;
+       }
+
+       bcm_phy_write_exp(phydev, TS_READ_CTRL, TS_READ_START);
+
+       ts[0] = bcm_phy_read_exp(phydev, TS_REG_0);
+       ts[1] = bcm_phy_read_exp(phydev, TS_REG_1);
+       ts[2] = bcm_phy_read_exp(phydev, TS_REG_2);
+       ts[3] = bcm_phy_read_exp(phydev, TS_REG_3);
+
+       /* not in be32 format for some reason */
+       capts->seq_id = bcm_phy_read_exp(priv->phydev, TS_INFO_0);
+
+       reg = bcm_phy_read_exp(phydev, TS_INFO_1);
+       capts->msgtype = reg >> 12;
+       capts->tx_dir = !!(reg & BIT(11));
+
+       bcm_phy_write_exp(phydev, TS_READ_CTRL, TS_READ_END);
+       bcm_phy_write_exp(phydev, TS_READ_CTRL, 0);
+
+       mutex_unlock(&priv->mutex);
+
+       sec = (ts[3] << 16) | ts[2];
+       nsec = (ts[1] << 16) | ts[0];
+       capts->hwtstamp = ktime_set(sec, nsec);
+
+       return true;
+}
+
+static void bcm_ptp_match_tstamp(struct bcm_ptp_private *priv,
+                                struct bcm_ptp_capture *capts)
+{
+       struct skb_shared_hwtstamps hwts;
+       struct sk_buff *skb, *ts_skb;
+       unsigned long flags;
+       bool first = false;
+
+       ts_skb = NULL;
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       skb_queue_walk(&priv->tx_queue, skb) {
+               if (BCM_SKB_CB(skb)->seq_id == capts->seq_id &&
+                   BCM_SKB_CB(skb)->msgtype == capts->msgtype) {
+                       first = skb_queue_is_first(&priv->tx_queue, skb);
+                       __skb_unlink(skb, &priv->tx_queue);
+                       ts_skb = skb;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+       /* TX captures one-step packets, discard them if needed. */
+       if (ts_skb) {
+               if (BCM_SKB_CB(ts_skb)->discard) {
+                       kfree_skb(ts_skb);
+               } else {
+                       memset(&hwts, 0, sizeof(hwts));
+                       hwts.hwtstamp = capts->hwtstamp;
+                       skb_complete_tx_timestamp(ts_skb, &hwts);
+               }
+       }
+
+       /* not first match, try and expire entries */
+       if (!first) {
+               while ((skb = skb_dequeue(&priv->tx_queue))) {
+                       if (!time_after(jiffies, BCM_SKB_CB(skb)->timeout)) {
+                               skb_queue_head(&priv->tx_queue, skb);
+                               break;
+                       }
+                       kfree_skb(skb);
+               }
+       }
+}
+
+static long bcm_ptp_do_aux_work(struct ptp_clock_info *info)
+{
+       struct bcm_ptp_private *priv = ptp2priv(info);
+       struct bcm_ptp_capture capts;
+       bool reschedule = false;
+
+       while (!skb_queue_empty_lockless(&priv->tx_queue)) {
+               if (!bcm_ptp_get_tstamp(priv, &capts)) {
+                       reschedule = true;
+                       break;
+               }
+               bcm_ptp_match_tstamp(priv, &capts);
+       }
+
+       return reschedule ? 1 : -1;
+}
+
+static int bcm_ptp_cancel_func(struct bcm_ptp_private *priv)
+{
+       if (!priv->pin_active)
+               return 0;
+
+       priv->pin_active = false;
+
+       priv->nse_ctrl &= ~(NSE_SYNC_OUT_MASK | NSE_SYNC1_FRAMESYNC |
+                           NSE_CAPTURE_EN);
+       bcm_phy_write_exp(priv->phydev, NSE_CTRL, priv->nse_ctrl);
+
+       cancel_delayed_work_sync(&priv->pin_work);
+
+       return 0;
+}
+
+static void bcm_ptp_perout_work(struct work_struct *pin_work)
+{
+       struct bcm_ptp_private *priv =
+               container_of(pin_work, struct bcm_ptp_private, pin_work.work);
+       struct phy_device *phydev = priv->phydev;
+       struct timespec64 ts;
+       u64 ns, next;
+       u16 ctrl;
+
+       mutex_lock(&priv->mutex);
+
+       /* no longer running */
+       if (!priv->pin_active) {
+               mutex_unlock(&priv->mutex);
+               return;
+       }
+
+       bcm_ptp_framesync_ts(phydev, NULL, &ts, priv->nse_ctrl);
+
+       /* this is 1PPS only */
+       next = NSEC_PER_SEC - ts.tv_nsec;
+       ts.tv_sec += next < NSEC_PER_MSEC ? 2 : 1;
+       ts.tv_nsec = 0;
+
+       ns = timespec64_to_ns(&ts);
+
+       /* force 0->1 transition for ONESHOT */
+       ctrl = bcm_ptp_framesync_disable(phydev,
+                                        priv->nse_ctrl & ~NSE_ONESHOT_EN);
+
+       bcm_phy_write_exp(phydev, SYNOUT_TS_0, ns & 0xfff0);
+       bcm_phy_write_exp(phydev, SYNOUT_TS_1, ns >> 16);
+       bcm_phy_write_exp(phydev, SYNOUT_TS_2, ns >> 32);
+
+       /* load values on next framesync */
+       bcm_phy_write_exp(phydev, SHADOW_LOAD, SYNC_OUT_LOAD);
+
+       bcm_ptp_framesync(phydev, ctrl | NSE_ONESHOT_EN | NSE_INIT);
+
+       priv->nse_ctrl |= NSE_ONESHOT_EN;
+       bcm_ptp_framesync_restore(phydev, priv->nse_ctrl);
+
+       mutex_unlock(&priv->mutex);
+
+       next = next + NSEC_PER_MSEC;
+       schedule_delayed_work(&priv->pin_work, nsecs_to_jiffies(next));
+}
+
+static int bcm_ptp_perout_locked(struct bcm_ptp_private *priv,
+                                struct ptp_perout_request *req, int on)
+{
+       struct phy_device *phydev = priv->phydev;
+       u64 period, pulse;
+       u16 val;
+
+       if (!on)
+               return bcm_ptp_cancel_func(priv);
+
+       /* 1PPS */
+       if (req->period.sec != 1 || req->period.nsec != 0)
+               return -EINVAL;
+
+       period = BCM_MAX_PERIOD_8NS;    /* write nonzero value */
+
+       if (req->flags & PTP_PEROUT_PHASE)
+               return -EOPNOTSUPP;
+
+       if (req->flags & PTP_PEROUT_DUTY_CYCLE)
+               pulse = ktime_to_ns(ktime_set(req->on.sec, req->on.nsec));
+       else
+               pulse = (u64)BCM_MAX_PULSE_8NS << 3;
+
+       /* convert to 8ns units */
+       pulse >>= 3;
+
+       if (!pulse || pulse > period || pulse > BCM_MAX_PULSE_8NS)
+               return -EINVAL;
+
+       bcm_phy_write_exp(phydev, SYNC_OUT_0, period);
+
+       val = ((pulse & 0x3) << 14) | ((period >> 16) & 0x3fff);
+       bcm_phy_write_exp(phydev, SYNC_OUT_1, val);
+
+       val = ((pulse >> 2) & 0x7f) | (pulse << 7);
+       bcm_phy_write_exp(phydev, SYNC_OUT_2, val);
+
+       if (priv->pin_active)
+               cancel_delayed_work_sync(&priv->pin_work);
+
+       priv->pin_active = true;
+       INIT_DELAYED_WORK(&priv->pin_work, bcm_ptp_perout_work);
+       schedule_delayed_work(&priv->pin_work, 0);
+
+       return 0;
+}
+
+static void bcm_ptp_extts_work(struct work_struct *pin_work)
+{
+       struct bcm_ptp_private *priv =
+               container_of(pin_work, struct bcm_ptp_private, pin_work.work);
+       struct phy_device *phydev = priv->phydev;
+       struct ptp_clock_event event;
+       struct timespec64 ts;
+       u16 reg;
+
+       mutex_lock(&priv->mutex);
+
+       /* no longer running */
+       if (!priv->pin_active) {
+               mutex_unlock(&priv->mutex);
+               return;
+       }
+
+       reg = bcm_phy_read_exp(phydev, INTR_STATUS);
+       if ((reg & INTC_FSYNC) == 0)
+               goto out;
+
+       bcm_ptp_get_framesync_ts(phydev, &ts);
+
+       event.index = 0;
+       event.type = PTP_CLOCK_EXTTS;
+       event.timestamp = timespec64_to_ns(&ts);
+       ptp_clock_event(priv->ptp_clock, &event);
+
+out:
+       mutex_unlock(&priv->mutex);
+       schedule_delayed_work(&priv->pin_work, HZ / 4);
+}
+
+static int bcm_ptp_extts_locked(struct bcm_ptp_private *priv, int on)
+{
+       struct phy_device *phydev = priv->phydev;
+
+       if (!on)
+               return bcm_ptp_cancel_func(priv);
+
+       if (priv->pin_active)
+               cancel_delayed_work_sync(&priv->pin_work);
+
+       bcm_ptp_framesync_disable(phydev, priv->nse_ctrl);
+
+       priv->nse_ctrl |= NSE_SYNC1_FRAMESYNC | NSE_CAPTURE_EN;
+
+       bcm_ptp_framesync_restore(phydev, priv->nse_ctrl);
+
+       priv->pin_active = true;
+       INIT_DELAYED_WORK(&priv->pin_work, bcm_ptp_extts_work);
+       schedule_delayed_work(&priv->pin_work, 0);
+
+       return 0;
+}
+
+static int bcm_ptp_enable(struct ptp_clock_info *info,
+                         struct ptp_clock_request *rq, int on)
+{
+       struct bcm_ptp_private *priv = ptp2priv(info);
+       int err = -EBUSY;
+
+       mutex_lock(&priv->mutex);
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_PEROUT:
+               if (priv->pin.func == PTP_PF_PEROUT)
+                       err = bcm_ptp_perout_locked(priv, &rq->perout, on);
+               break;
+       case PTP_CLK_REQ_EXTTS:
+               if (priv->pin.func == PTP_PF_EXTTS)
+                       err = bcm_ptp_extts_locked(priv, on);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       mutex_unlock(&priv->mutex);
+
+       return err;
+}
+
+static int bcm_ptp_verify(struct ptp_clock_info *info, unsigned int pin,
+                         enum ptp_pin_function func, unsigned int chan)
+{
+       switch (func) {
+       case PTP_PF_NONE:
+       case PTP_PF_EXTTS:
+       case PTP_PF_PEROUT:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static const struct ptp_clock_info bcm_ptp_clock_info = {
+       .owner          = THIS_MODULE,
+       .name           = KBUILD_MODNAME,
+       .max_adj        = 100000000,
+       .gettimex64     = bcm_ptp_gettimex,
+       .settime64      = bcm_ptp_settime,
+       .adjtime        = bcm_ptp_adjtime,
+       .adjfine        = bcm_ptp_adjfine,
+       .enable         = bcm_ptp_enable,
+       .verify         = bcm_ptp_verify,
+       .do_aux_work    = bcm_ptp_do_aux_work,
+       .n_pins         = 1,
+       .n_per_out      = 1,
+       .n_ext_ts       = 1,
+};
+
+static void bcm_ptp_txtstamp(struct mii_timestamper *mii_ts,
+                            struct sk_buff *skb, int type)
+{
+       struct bcm_ptp_private *priv = mii2priv(mii_ts);
+       struct ptp_header *hdr;
+       bool discard = false;
+       int msgtype;
+
+       hdr = ptp_parse_header(skb, type);
+       if (!hdr)
+               goto out;
+       msgtype = ptp_get_msgtype(hdr, type);
+
+       switch (priv->tx_type) {
+       case HWTSTAMP_TX_ONESTEP_P2P:
+               if (msgtype == PTP_MSGTYPE_PDELAY_RESP)
+                       discard = true;
+               fallthrough;
+       case HWTSTAMP_TX_ONESTEP_SYNC:
+               if (msgtype == PTP_MSGTYPE_SYNC)
+                       discard = true;
+               fallthrough;
+       case HWTSTAMP_TX_ON:
+               BCM_SKB_CB(skb)->timeout = jiffies + SKB_TS_TIMEOUT;
+               BCM_SKB_CB(skb)->seq_id = be16_to_cpu(hdr->sequence_id);
+               BCM_SKB_CB(skb)->msgtype = msgtype;
+               BCM_SKB_CB(skb)->discard = discard;
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               skb_queue_tail(&priv->tx_queue, skb);
+               ptp_schedule_worker(priv->ptp_clock, 0);
+               return;
+       default:
+               break;
+       }
+
+out:
+       kfree_skb(skb);
+}
+
+static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts,
+                           struct ifreq *ifr)
+{
+       struct bcm_ptp_private *priv = mii2priv(mii_ts);
+       struct hwtstamp_config cfg;
+       u16 mode, ctrl;
+
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+               return -EFAULT;
+
+       switch (cfg.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               priv->hwts_rx = false;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+               priv->hwts_rx = true;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       priv->tx_type = cfg.tx_type;
+
+       ctrl  = priv->hwts_rx ? SLICE_RX_EN : 0;
+       ctrl |= priv->tx_type != HWTSTAMP_TX_OFF ? SLICE_TX_EN : 0;
+
+       mode = TX_MODE_SEL(PORT, SYNC, REPLACE_TS) |
+              TX_MODE_SEL(PORT, DELAY_REQ, REPLACE_TS) |
+              TX_MODE_SEL(PORT, PDELAY_REQ, REPLACE_TS) |
+              TX_MODE_SEL(PORT, PDELAY_RESP, REPLACE_TS);
+
+       bcm_phy_write_exp(priv->phydev, TX_EVENT_MODE, mode);
+
+       mode = RX_MODE_SEL(PORT, SYNC, INSERT_TS_64) |
+              RX_MODE_SEL(PORT, DELAY_REQ, INSERT_TS_64) |
+              RX_MODE_SEL(PORT, PDELAY_REQ, INSERT_TS_64) |
+              RX_MODE_SEL(PORT, PDELAY_RESP, INSERT_TS_64);
+
+       bcm_phy_write_exp(priv->phydev, RX_EVENT_MODE, mode);
+
+       bcm_phy_write_exp(priv->phydev, SLICE_CTRL, ctrl);
+
+       if (ctrl & SLICE_TX_EN)
+               bcm_phy_write_exp(priv->phydev, TX_TS_CAPTURE, TX_TS_CAP_EN);
+       else
+               ptp_cancel_worker_sync(priv->ptp_clock);
+
+       /* purge existing data */
+       skb_queue_purge(&priv->tx_queue);
+
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static int bcm_ptp_ts_info(struct mii_timestamper *mii_ts,
+                          struct ethtool_ts_info *ts_info)
+{
+       struct bcm_ptp_private *priv = mii2priv(mii_ts);
+
+       ts_info->phc_index = ptp_clock_index(priv->ptp_clock);
+       ts_info->so_timestamping =
+               SOF_TIMESTAMPING_TX_HARDWARE |
+               SOF_TIMESTAMPING_RX_HARDWARE |
+               SOF_TIMESTAMPING_RAW_HARDWARE;
+       ts_info->tx_types =
+               BIT(HWTSTAMP_TX_ON) |
+               BIT(HWTSTAMP_TX_OFF) |
+               BIT(HWTSTAMP_TX_ONESTEP_SYNC) |
+               BIT(HWTSTAMP_TX_ONESTEP_P2P);
+       ts_info->rx_filters =
+               BIT(HWTSTAMP_FILTER_NONE) |
+               BIT(HWTSTAMP_FILTER_PTP_V2_EVENT);
+
+       return 0;
+}
+
+void bcm_ptp_stop(struct bcm_ptp_private *priv)
+{
+       ptp_cancel_worker_sync(priv->ptp_clock);
+       bcm_ptp_cancel_func(priv);
+}
+EXPORT_SYMBOL_GPL(bcm_ptp_stop);
+
+void bcm_ptp_config_init(struct phy_device *phydev)
+{
+       /* init network sync engine */
+       bcm_phy_write_exp(phydev, NSE_CTRL, NSE_GMODE_EN | NSE_INIT);
+
+       /* enable time sync (TX/RX SOP capture) */
+       bcm_phy_write_exp(phydev, TIME_SYNC, TIME_SYNC_EN);
+
+       /* use sec.nsec heartbeat capture */
+       bcm_phy_write_exp(phydev, DPLL_SELECT, DPLL_HB_MODE2);
+
+       /* use 64 bit timecode for TX */
+       bcm_phy_write_exp(phydev, TIMECODE_CTRL, TX_TIMECODE_SEL);
+
+       /* always allow FREQ_LOAD on framesync */
+       bcm_phy_write_exp(phydev, SHADOW_CTRL, FREQ_LOAD);
+
+       bcm_phy_write_exp(phydev, SYNC_IN_DIVIDER, 1);
+}
+EXPORT_SYMBOL_GPL(bcm_ptp_config_init);
+
+static void bcm_ptp_init(struct bcm_ptp_private *priv)
+{
+       priv->nse_ctrl = NSE_GMODE_EN;
+
+       mutex_init(&priv->mutex);
+       skb_queue_head_init(&priv->tx_queue);
+
+       priv->mii_ts.rxtstamp = bcm_ptp_rxtstamp;
+       priv->mii_ts.txtstamp = bcm_ptp_txtstamp;
+       priv->mii_ts.hwtstamp = bcm_ptp_hwtstamp;
+       priv->mii_ts.ts_info = bcm_ptp_ts_info;
+
+       priv->phydev->mii_ts = &priv->mii_ts;
+}
+
+struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev)
+{
+       struct bcm_ptp_private *priv;
+       struct ptp_clock *clock;
+
+       switch (BRCM_PHY_MODEL(phydev)) {
+       case PHY_ID_BCM54210E:
+               break;
+       default:
+               return NULL;
+       }
+
+       priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return ERR_PTR(-ENOMEM);
+
+       priv->ptp_info = bcm_ptp_clock_info;
+
+       snprintf(priv->pin.name, sizeof(priv->pin.name), "SYNC_OUT");
+       priv->ptp_info.pin_config = &priv->pin;
+
+       clock = ptp_clock_register(&priv->ptp_info, &phydev->mdio.dev);
+       if (IS_ERR(clock))
+               return ERR_CAST(clock);
+       priv->ptp_clock = clock;
+
+       priv->phydev = phydev;
+       bcm_ptp_init(priv);
+
+       return priv;
+}
+EXPORT_SYMBOL_GPL(bcm_ptp_probe);
+
+MODULE_LICENSE("GPL");
index e36809a..31fbcdd 100644 (file)
@@ -27,6 +27,11 @@ MODULE_DESCRIPTION("Broadcom PHY driver");
 MODULE_AUTHOR("Maciej W. Rozycki");
 MODULE_LICENSE("GPL");
 
+struct bcm54xx_phy_priv {
+       u64     *stats;
+       struct bcm_ptp_private *ptp;
+};
+
 static int bcm54xx_config_clock_delay(struct phy_device *phydev)
 {
        int rc, val;
@@ -313,6 +318,22 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
                bcm_phy_write_shadow(phydev, BCM54XX_SHD_APD, val);
 }
 
+static void bcm54xx_ptp_stop(struct phy_device *phydev)
+{
+       struct bcm54xx_phy_priv *priv = phydev->priv;
+
+       if (priv->ptp)
+               bcm_ptp_stop(priv->ptp);
+}
+
+static void bcm54xx_ptp_config_init(struct phy_device *phydev)
+{
+       struct bcm54xx_phy_priv *priv = phydev->priv;
+
+       if (priv->ptp)
+               bcm_ptp_config_init(phydev);
+}
+
 static int bcm54xx_config_init(struct phy_device *phydev)
 {
        int reg, err, val;
@@ -390,6 +411,8 @@ static int bcm54xx_config_init(struct phy_device *phydev)
                bcm_phy_write_exp(phydev, BCM_EXP_MULTICOLOR, val);
        }
 
+       bcm54xx_ptp_config_init(phydev);
+
        return 0;
 }
 
@@ -418,6 +441,8 @@ static int bcm54xx_suspend(struct phy_device *phydev)
 {
        int ret;
 
+       bcm54xx_ptp_stop(phydev);
+
        /* We cannot use a read/modify/write here otherwise the PHY gets into
         * a bad state where its LEDs keep flashing, thus defeating the purpose
         * of low power mode.
@@ -741,10 +766,6 @@ static irqreturn_t brcm_fet_handle_interrupt(struct phy_device *phydev)
        return IRQ_HANDLED;
 }
 
-struct bcm54xx_phy_priv {
-       u64     *stats;
-};
-
 static int bcm54xx_phy_probe(struct phy_device *phydev)
 {
        struct bcm54xx_phy_priv *priv;
@@ -761,6 +782,10 @@ static int bcm54xx_phy_probe(struct phy_device *phydev)
        if (!priv->stats)
                return -ENOMEM;
 
+       priv->ptp = bcm_ptp_probe(phydev);
+       if (IS_ERR(priv->ptp))
+               return PTR_ERR(priv->ptp);
+
        return 0;
 }
 
@@ -1042,6 +1067,20 @@ static struct phy_driver broadcom_drivers[] = {
        .handle_interrupt = bcm_phy_handle_interrupt,
        .link_change_notify     = bcm54xx_link_change_notify,
 }, {
+       .phy_id         = PHY_ID_BCM53128,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM53128",
+       .flags          = PHY_IS_INTERNAL,
+       /* PHY_GBIT_FEATURES */
+       .get_sset_count = bcm_phy_get_sset_count,
+       .get_strings    = bcm_phy_get_strings,
+       .get_stats      = bcm54xx_get_stats,
+       .probe          = bcm54xx_phy_probe,
+       .config_init    = bcm54xx_config_init,
+       .config_intr    = bcm_phy_config_intr,
+       .handle_interrupt = bcm_phy_handle_interrupt,
+       .link_change_notify     = bcm54xx_link_change_notify,
+}, {
        .phy_id         = PHY_ID_BCM89610,
        .phy_id_mask    = 0xfffffff0,
        .name           = "Broadcom BCM89610",
@@ -1077,6 +1116,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
        { PHY_ID_BCM5241, 0xfffffff0 },
        { PHY_ID_BCM5395, 0xfffffff0 },
        { PHY_ID_BCM53125, 0xfffffff0 },
+       { PHY_ID_BCM53128, 0xfffffff0 },
        { PHY_ID_BCM89610, 0xfffffff0 },
        { }
 };
index 13dafe7..1e38039 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/bitfield.h>
+#include <linux/nvmem-consumer.h>
 
 #include <dt-bindings/net/ti-dp83867.h>
 
@@ -522,6 +523,51 @@ static int dp83867_verify_rgmii_cfg(struct phy_device *phydev)
 }
 
 #if IS_ENABLED(CONFIG_OF_MDIO)
+static int dp83867_of_init_io_impedance(struct phy_device *phydev)
+{
+       struct dp83867_private *dp83867 = phydev->priv;
+       struct device *dev = &phydev->mdio.dev;
+       struct device_node *of_node = dev->of_node;
+       struct nvmem_cell *cell;
+       u8 *buf, val;
+       int ret;
+
+       cell = of_nvmem_cell_get(of_node, "io_impedance_ctrl");
+       if (IS_ERR(cell)) {
+               ret = PTR_ERR(cell);
+               if (ret != -ENOENT)
+                       return phydev_err_probe(phydev, ret,
+                                               "failed to get nvmem cell io_impedance_ctrl\n");
+
+               /* If no nvmem cell, check for the boolean properties. */
+               if (of_property_read_bool(of_node, "ti,max-output-impedance"))
+                       dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
+               else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
+                       dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
+               else
+                       dp83867->io_impedance = -1; /* leave at default */
+
+               return 0;
+       }
+
+       buf = nvmem_cell_read(cell, NULL);
+       nvmem_cell_put(cell);
+
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       val = *buf;
+       kfree(buf);
+
+       if ((val & DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK) != val) {
+               phydev_err(phydev, "nvmem cell 'io_impedance_ctrl' contents out of range\n");
+               return -ERANGE;
+       }
+       dp83867->io_impedance = val;
+
+       return 0;
+}
+
 static int dp83867_of_init(struct phy_device *phydev)
 {
        struct dp83867_private *dp83867 = phydev->priv;
@@ -549,12 +595,9 @@ static int dp83867_of_init(struct phy_device *phydev)
                }
        }
 
-       if (of_property_read_bool(of_node, "ti,max-output-impedance"))
-               dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX;
-       else if (of_property_read_bool(of_node, "ti,min-output-impedance"))
-               dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN;
-       else
-               dp83867->io_impedance = -1; /* leave at default */
+       ret = dp83867_of_init_io_impedance(phydev);
+       if (ret)
+               return ret;
 
        dp83867->rxctrl_strap_quirk = of_property_read_bool(of_node,
                                                            "ti,dp83867-rxctrl-strap-quirk");
index 1ae792b..3cd9a77 100644 (file)
 #define DP83TD510E_AN_STAT_1                   0x60c
 #define DP83TD510E_MASTER_SLAVE_RESOL_FAIL     BIT(15)
 
+#define DP83TD510E_MSE_DETECT                  0xa85
+
+#define DP83TD510_SQI_MAX      7
+
+/* Register values are converted to SNR(dB) as suggested by
+ * "Application Report - DP83TD510E Cable Diagnostics Toolkit":
+ * SNR(dB) = -10 * log10 (VAL/2^17) - 1.76 dB.
+ * SQI ranges are implemented according to "OPEN ALLIANCE - Advanced diagnostic
+ * features for 100BASE-T1 automotive Ethernet PHYs"
+ */
+static const u16 dp83td510_mse_sqi_map[] = {
+       0x0569, /* < 18dB */
+       0x044c, /* 18dB =< SNR < 19dB */
+       0x0369, /* 19dB =< SNR < 20dB */
+       0x02b6, /* 20dB =< SNR < 21dB */
+       0x0227, /* 21dB =< SNR < 22dB */
+       0x01b6, /* 22dB =< SNR < 23dB */
+       0x015b, /* 23dB =< SNR < 24dB */
+       0x0000  /* 24dB =< SNR */
+};
+
 static int dp83td510_config_intr(struct phy_device *phydev)
 {
        int ret;
@@ -164,6 +185,32 @@ static int dp83td510_config_aneg(struct phy_device *phydev)
        return genphy_c45_check_and_restart_aneg(phydev, changed);
 }
 
+static int dp83td510_get_sqi(struct phy_device *phydev)
+{
+       int sqi, ret;
+       u16 mse_val;
+
+       if (!phydev->link)
+               return 0;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_MSE_DETECT);
+       if (ret < 0)
+               return ret;
+
+       mse_val = 0xFFFF & ret;
+       for (sqi = 0; sqi < ARRAY_SIZE(dp83td510_mse_sqi_map); sqi++) {
+               if (mse_val >= dp83td510_mse_sqi_map[sqi])
+                       return sqi;
+       }
+
+       return -EINVAL;
+}
+
+static int dp83td510_get_sqi_max(struct phy_device *phydev)
+{
+       return DP83TD510_SQI_MAX;
+}
+
 static int dp83td510_get_features(struct phy_device *phydev)
 {
        /* This PHY can't respond on MDIO bus if no RMII clock is enabled.
@@ -192,6 +239,8 @@ static struct phy_driver dp83td510_driver[] = {
        .get_features   = dp83td510_get_features,
        .config_intr    = dp83td510_config_intr,
        .handle_interrupt = dp83td510_handle_interrupt,
+       .get_sqi        = dp83td510_get_sqi,
+       .get_sqi_max    = dp83td510_get_sqi_max,
 
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
index 03abe62..aef739c 100644 (file)
@@ -353,6 +353,7 @@ static int __init fixed_mdio_bus_init(void)
        fmb->mii_bus->parent = &pdev->dev;
        fmb->mii_bus->read = &fixed_mdio_read;
        fmb->mii_bus->write = &fixed_mdio_write;
+       fmb->mii_bus->phy_mask = ~0;
 
        ret = mdiobus_register(fmb->mii_bus);
        if (ret)
index d8b31d4..f070776 100644 (file)
@@ -490,6 +490,7 @@ static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
        dev = &phydev->mdio.dev;
 
        sfp_parse_support(phydev->sfp_bus, id, sfp_supported);
+       phydev->port = sfp_parse_port(phydev->sfp_bus, id, sfp_supported);
        sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
 
        dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
@@ -526,6 +527,7 @@ static void mv2222_sfp_remove(void *upstream)
 
        priv->line_interface = PHY_INTERFACE_MODE_NA;
        linkmode_zero(priv->supported);
+       phydev->port = PORT_NONE;
 }
 
 static void mv2222_sfp_link_up(void *upstream)
index d777c88..a714150 100644 (file)
@@ -1991,15 +1991,9 @@ static int m88e1510_loopback(struct phy_device *phydev, bool enable)
        int err;
 
        if (enable) {
-               u16 bmcr_ctl = 0, mscr2_ctl = 0;
+               u16 bmcr_ctl, mscr2_ctl = 0;
 
-               if (phydev->speed == SPEED_1000)
-                       bmcr_ctl = BMCR_SPEED1000;
-               else if (phydev->speed == SPEED_100)
-                       bmcr_ctl = BMCR_SPEED100;
-
-               if (phydev->duplex == DUPLEX_FULL)
-                       bmcr_ctl |= BMCR_FULLDPLX;
+               bmcr_ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
 
                err = phy_write(phydev, MII_BMCR, bmcr_ctl);
                if (err < 0)
index 2213990..e78d0bf 100644 (file)
 #define PTP_TSU_INT_STS_PTP_RX_TS_OVRFL_INT_   BIT(1)
 #define PTP_TSU_INT_STS_PTP_RX_TS_EN_          BIT(0)
 
+#define LAN8814_LED_CTRL_1                     0x0
+#define LAN8814_LED_CTRL_1_KSZ9031_LED_MODE_   BIT(6)
+
 /* PHY Control 1 */
 #define MII_KSZPHY_CTRL_1                      0x1e
 #define KSZ8081_CTRL1_MDIX_STAT                        BIT(4)
@@ -308,6 +311,10 @@ struct kszphy_priv {
        u64 stats[ARRAY_SIZE(kszphy_hw_stats)];
 };
 
+static const struct kszphy_type lan8814_type = {
+       .led_mode_reg           = ~LAN8814_LED_CTRL_1,
+};
+
 static const struct kszphy_type ksz8021_type = {
        .led_mode_reg           = MII_KSZPHY_CTRL_2,
        .has_broadcast_disable  = true,
@@ -1688,6 +1695,30 @@ static int kszphy_suspend(struct phy_device *phydev)
        return genphy_suspend(phydev);
 }
 
+static void kszphy_parse_led_mode(struct phy_device *phydev)
+{
+       const struct kszphy_type *type = phydev->drv->driver_data;
+       const struct device_node *np = phydev->mdio.dev.of_node;
+       struct kszphy_priv *priv = phydev->priv;
+       int ret;
+
+       if (type && type->led_mode_reg) {
+               ret = of_property_read_u32(np, "micrel,led-mode",
+                                          &priv->led_mode);
+
+               if (ret)
+                       priv->led_mode = -1;
+
+               if (priv->led_mode > 3) {
+                       phydev_err(phydev, "invalid led mode: 0x%02x\n",
+                                  priv->led_mode);
+                       priv->led_mode = -1;
+               }
+       } else {
+               priv->led_mode = -1;
+       }
+}
+
 static int kszphy_resume(struct phy_device *phydev)
 {
        int ret;
@@ -1720,7 +1751,6 @@ static int kszphy_probe(struct phy_device *phydev)
        const struct device_node *np = phydev->mdio.dev.of_node;
        struct kszphy_priv *priv;
        struct clk *clk;
-       int ret;
 
        priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -1730,20 +1760,7 @@ static int kszphy_probe(struct phy_device *phydev)
 
        priv->type = type;
 
-       if (type && type->led_mode_reg) {
-               ret = of_property_read_u32(np, "micrel,led-mode",
-                               &priv->led_mode);
-               if (ret)
-                       priv->led_mode = -1;
-
-               if (priv->led_mode > 3) {
-                       phydev_err(phydev, "invalid led mode: 0x%02x\n",
-                                  priv->led_mode);
-                       priv->led_mode = -1;
-               }
-       } else {
-               priv->led_mode = -1;
-       }
+       kszphy_parse_led_mode(phydev);
 
        clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref");
        /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
@@ -2815,8 +2832,23 @@ static int lan8814_ptp_probe_once(struct phy_device *phydev)
        return 0;
 }
 
+static void lan8814_setup_led(struct phy_device *phydev, int val)
+{
+       int temp;
+
+       temp = lanphy_read_page_reg(phydev, 5, LAN8814_LED_CTRL_1);
+
+       if (val)
+               temp |= LAN8814_LED_CTRL_1_KSZ9031_LED_MODE_;
+       else
+               temp &= ~LAN8814_LED_CTRL_1_KSZ9031_LED_MODE_;
+
+       lanphy_write_page_reg(phydev, 5, LAN8814_LED_CTRL_1, temp);
+}
+
 static int lan8814_config_init(struct phy_device *phydev)
 {
+       struct kszphy_priv *lan8814 = phydev->priv;
        int val;
 
        /* Reset the PHY */
@@ -2835,6 +2867,9 @@ static int lan8814_config_init(struct phy_device *phydev)
        val |= LAN8814_ALIGN_TX_A_B_SWAP;
        lanphy_write_page_reg(phydev, 2, LAN8814_ALIGN_SWAP, val);
 
+       if (lan8814->led_mode >= 0)
+               lan8814_setup_led(phydev, lan8814->led_mode);
+
        return 0;
 }
 
@@ -2855,6 +2890,7 @@ static int lan8814_release_coma_mode(struct phy_device *phydev)
 
 static int lan8814_probe(struct phy_device *phydev)
 {
+       const struct kszphy_type *type = phydev->drv->driver_data;
        struct kszphy_priv *priv;
        u16 addr;
        int err;
@@ -2863,10 +2899,12 @@ static int lan8814_probe(struct phy_device *phydev)
        if (!priv)
                return -ENOMEM;
 
-       priv->led_mode = -1;
-
        phydev->priv = priv;
 
+       priv->type = type;
+
+       kszphy_parse_led_mode(phydev);
+
        /* Strap-in value for PHY address, below register read gives starting
         * phy address value
         */
@@ -3068,6 +3106,7 @@ static struct phy_driver ksphy_driver[] = {
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Microchip INDY Gigabit Quad PHY",
        .config_init    = lan8814_config_init,
+       .driver_data    = &lan8814_type,
        .probe          = lan8814_probe,
        .soft_reset     = genphy_soft_reset,
        .read_status    = ksz9031_read_status,
index 5ce1bf0..5b99acf 100644 (file)
@@ -8,7 +8,9 @@
 
 #include <linux/module.h>
 #include <linux/bitfield.h>
+#include <linux/hwmon.h>
 #include <linux/phy.h>
+#include <linux/polynomial.h>
 #include <linux/netdevice.h>
 
 /* PHY ID */
 #define VSPEC1_SGMII_ANEN_ANRS (VSPEC1_SGMII_CTRL_ANEN | \
                                 VSPEC1_SGMII_CTRL_ANRS)
 
+/* Temperature sensor */
+#define VPSPEC1_TEMP_STA       0x0E
+#define VPSPEC1_TEMP_STA_DATA  GENMASK(9, 0)
+
 /* WoL */
 #define VPSPEC2_WOL_CTL                0x0E06
 #define VPSPEC2_WOL_AD01       0x0E08
@@ -80,6 +86,102 @@ static const struct {
        {9, 0x73},
 };
 
+#if IS_ENABLED(CONFIG_HWMON)
+/* The original translation formulae of the temperature (in degrees of Celsius)
+ * are as follows:
+ *
+ *   T = -2.5761e-11*(N^4) + 9.7332e-8*(N^3) + -1.9165e-4*(N^2) +
+ *       3.0762e-1*(N^1) + -5.2156e1
+ *
+ * where [-52.156, 137.961]C and N = [0, 1023].
+ *
+ * They must be accordingly altered to be suitable for the integer arithmetics.
+ * The technique is called 'factor redistribution', which just makes sure the
+ * multiplications and divisions are made so to have a result of the operations
+ * within the integer numbers limit. In addition we need to translate the
+ * formulae to accept millidegrees of Celsius. Here what it looks like after
+ * the alterations:
+ *
+ *   T = -25761e-12*(N^4) + 97332e-9*(N^3) + -191650e-6*(N^2) +
+ *       307620e-3*(N^1) + -52156
+ *
+ * where T = [-52156, 137961]mC and N = [0, 1023].
+ */
+static const struct polynomial poly_N_to_temp = {
+       .terms = {
+               {4,  -25761, 1000, 1},
+               {3,   97332, 1000, 1},
+               {2, -191650, 1000, 1},
+               {1,  307620, 1000, 1},
+               {0,  -52156,    1, 1}
+       }
+};
+
+static int gpy_hwmon_read(struct device *dev,
+                         enum hwmon_sensor_types type,
+                         u32 attr, int channel, long *value)
+{
+       struct phy_device *phydev = dev_get_drvdata(dev);
+       int ret;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VPSPEC1_TEMP_STA);
+       if (ret < 0)
+               return ret;
+       if (!ret)
+               return -ENODATA;
+
+       *value = polynomial_calc(&poly_N_to_temp,
+                                FIELD_GET(VPSPEC1_TEMP_STA_DATA, ret));
+
+       return 0;
+}
+
+static umode_t gpy_hwmon_is_visible(const void *data,
+                                   enum hwmon_sensor_types type,
+                                   u32 attr, int channel)
+{
+       return 0444;
+}
+
+static const struct hwmon_channel_info *gpy_hwmon_info[] = {
+       HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+       NULL
+};
+
+static const struct hwmon_ops gpy_hwmon_hwmon_ops = {
+       .is_visible     = gpy_hwmon_is_visible,
+       .read           = gpy_hwmon_read,
+};
+
+static const struct hwmon_chip_info gpy_hwmon_chip_info = {
+       .ops            = &gpy_hwmon_hwmon_ops,
+       .info           = gpy_hwmon_info,
+};
+
+static int gpy_hwmon_register(struct phy_device *phydev)
+{
+       struct device *dev = &phydev->mdio.dev;
+       struct device *hwmon_dev;
+       char *hwmon_name;
+
+       hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev));
+       if (IS_ERR(hwmon_name))
+               return PTR_ERR(hwmon_name);
+
+       hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
+                                                        phydev,
+                                                        &gpy_hwmon_chip_info,
+                                                        NULL);
+
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+#else
+static int gpy_hwmon_register(struct phy_device *phydev)
+{
+       return 0;
+}
+#endif
+
 static int gpy_config_init(struct phy_device *phydev)
 {
        int ret;
@@ -109,6 +211,10 @@ static int gpy_probe(struct phy_device *phydev)
        if (ret < 0)
                return ret;
 
+       ret = gpy_hwmon_register(phydev);
+       if (ret)
+               return ret;
+
        phydev_info(phydev, "Firmware Version: 0x%04X (%s)\n", ret,
                    (ret & PHY_FWV_REL_MASK) ? "release" : "test");
 
@@ -295,6 +401,9 @@ static void gpy_update_interface(struct phy_device *phydev)
                                   ret);
                break;
        }
+
+       if (phydev->speed == SPEED_2500 || phydev->speed == SPEED_1000)
+               genphy_read_master_slave(phydev);
 }
 
 static int gpy_read_status(struct phy_device *phydev)
index 9944cc5..2a8195c 100644 (file)
@@ -444,15 +444,10 @@ static int tja11xx_hwmon_register(struct phy_device *phydev,
                                  struct tja11xx_priv *priv)
 {
        struct device *dev = &phydev->mdio.dev;
-       int i;
-
-       priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
-       if (!priv->hwmon_name)
-               return -ENOMEM;
 
-       for (i = 0; priv->hwmon_name[i]; i++)
-               if (hwmon_is_bad_char(priv->hwmon_name[i]))
-                       priv->hwmon_name[i] = '_';
+       priv->hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev));
+       if (IS_ERR(priv->hwmon_name))
+               return PTR_ERR(priv->hwmon_name);
 
        priv->hwmon_dev =
                devm_hwmon_device_register_with_info(dev, priv->hwmon_name,
index 46acddd..a74b320 100644 (file)
@@ -2024,18 +2024,12 @@ EXPORT_SYMBOL(genphy_config_eee_advert);
  */
 int genphy_setup_forced(struct phy_device *phydev)
 {
-       u16 ctl = 0;
+       u16 ctl;
 
        phydev->pause = 0;
        phydev->asym_pause = 0;
 
-       if (SPEED_1000 == phydev->speed)
-               ctl |= BMCR_SPEED1000;
-       else if (SPEED_100 == phydev->speed)
-               ctl |= BMCR_SPEED100;
-
-       if (DUPLEX_FULL == phydev->duplex)
-               ctl |= BMCR_FULLDPLX;
+       ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
 
        return phy_modify(phydev, MII_BMCR,
                          ~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
@@ -2637,13 +2631,7 @@ int genphy_loopback(struct phy_device *phydev, bool enable)
                u16 val, ctl = BMCR_LOOPBACK;
                int ret;
 
-               if (phydev->speed == SPEED_1000)
-                       ctl |= BMCR_SPEED1000;
-               else if (phydev->speed == SPEED_100)
-                       ctl |= BMCR_SPEED100;
-
-               if (phydev->duplex == DUPLEX_FULL)
-                       ctl |= BMCR_FULLDPLX;
+               ctl |= mii_bmcr_encode_fixed(phydev->speed, phydev->duplex);
 
                phy_modify(phydev, MII_BMCR, ~0, ctl);
 
index 066684b..48f0b9b 100644 (file)
@@ -43,7 +43,6 @@ struct phylink {
        /* private: */
        struct net_device *netdev;
        const struct phylink_mac_ops *mac_ops;
-       const struct phylink_pcs_ops *pcs_ops;
        struct phylink_config *config;
        struct phylink_pcs *pcs;
        struct device *dev;
@@ -759,6 +758,18 @@ static void phylink_resolve_flow(struct phylink_link_state *state)
        }
 }
 
+static void phylink_pcs_poll_stop(struct phylink *pl)
+{
+       if (pl->cfg_link_an_mode == MLO_AN_INBAND)
+               del_timer(&pl->link_poll);
+}
+
+static void phylink_pcs_poll_start(struct phylink *pl)
+{
+       if (pl->pcs && pl->pcs->poll && pl->cfg_link_an_mode == MLO_AN_INBAND)
+               mod_timer(&pl->link_poll, jiffies + HZ);
+}
+
 static void phylink_mac_config(struct phylink *pl,
                               const struct phylink_link_state *state)
 {
@@ -779,8 +790,8 @@ static void phylink_mac_pcs_an_restart(struct phylink *pl)
        if (pl->link_config.an_enabled &&
            phy_interface_mode_is_8023z(pl->link_config.interface) &&
            phylink_autoneg_inband(pl->cur_link_an_mode)) {
-               if (pl->pcs_ops)
-                       pl->pcs_ops->pcs_an_restart(pl->pcs);
+               if (pl->pcs)
+                       pl->pcs->ops->pcs_an_restart(pl->pcs);
                else if (pl->config->legacy_pre_march2020)
                        pl->mac_ops->mac_an_restart(pl->config);
        }
@@ -790,6 +801,7 @@ static void phylink_major_config(struct phylink *pl, bool restart,
                                  const struct phylink_link_state *state)
 {
        struct phylink_pcs *pcs = NULL;
+       bool pcs_changed = false;
        int err;
 
        phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
@@ -802,8 +814,12 @@ static void phylink_major_config(struct phylink *pl, bool restart,
                                    pcs);
                        return;
                }
+
+               pcs_changed = pcs && pl->pcs != pcs;
        }
 
+       phylink_pcs_poll_stop(pl);
+
        if (pl->mac_ops->mac_prepare) {
                err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
                                               state->interface);
@@ -817,27 +833,17 @@ static void phylink_major_config(struct phylink *pl, bool restart,
        /* If we have a new PCS, switch to the new PCS after preparing the MAC
         * for the change.
         */
-       if (pcs) {
+       if (pcs_changed)
                pl->pcs = pcs;
-               pl->pcs_ops = pcs->ops;
-
-               if (!pl->phylink_disable_state &&
-                   pl->cfg_link_an_mode == MLO_AN_INBAND) {
-                       if (pcs->poll)
-                               mod_timer(&pl->link_poll, jiffies + HZ);
-                       else
-                               del_timer(&pl->link_poll);
-               }
-       }
 
        phylink_mac_config(pl, state);
 
-       if (pl->pcs_ops) {
-               err = pl->pcs_ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
-                                             state->interface,
-                                             state->advertising,
-                                             !!(pl->link_config.pause &
-                                                MLO_PAUSE_AN));
+       if (pl->pcs) {
+               err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
+                                              state->interface,
+                                              state->advertising,
+                                              !!(pl->link_config.pause &
+                                                 MLO_PAUSE_AN));
                if (err < 0)
                        phylink_err(pl, "pcs_config failed: %pe\n",
                                    ERR_PTR(err));
@@ -854,6 +860,8 @@ static void phylink_major_config(struct phylink *pl, bool restart,
                        phylink_err(pl, "mac_finish failed: %pe\n",
                                    ERR_PTR(err));
        }
+
+       phylink_pcs_poll_start(pl);
 }
 
 /*
@@ -869,7 +877,7 @@ static int phylink_change_inband_advert(struct phylink *pl)
        if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state))
                return 0;
 
-       if (!pl->pcs_ops && pl->config->legacy_pre_march2020) {
+       if (!pl->pcs && pl->config->legacy_pre_march2020) {
                /* Legacy method */
                phylink_mac_config(pl, &pl->link_config);
                phylink_mac_pcs_an_restart(pl);
@@ -886,10 +894,11 @@ static int phylink_change_inband_advert(struct phylink *pl)
         * restart negotiation if the pcs_config() helper indicates that
         * the programmed advertisement has changed.
         */
-       ret = pl->pcs_ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
-                                     pl->link_config.interface,
-                                     pl->link_config.advertising,
-                                     !!(pl->link_config.pause & MLO_PAUSE_AN));
+       ret = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
+                                      pl->link_config.interface,
+                                      pl->link_config.advertising,
+                                      !!(pl->link_config.pause &
+                                         MLO_PAUSE_AN));
        if (ret < 0)
                return ret;
 
@@ -918,8 +927,8 @@ static void phylink_mac_pcs_get_state(struct phylink *pl,
        state->an_complete = 0;
        state->link = 1;
 
-       if (pl->pcs_ops)
-               pl->pcs_ops->pcs_get_state(pl->pcs, state);
+       if (pl->pcs)
+               pl->pcs->ops->pcs_get_state(pl->pcs, state);
        else if (pl->mac_ops->mac_pcs_get_state &&
                 pl->config->legacy_pre_march2020)
                pl->mac_ops->mac_pcs_get_state(pl->config, state);
@@ -992,8 +1001,8 @@ static void phylink_link_up(struct phylink *pl,
 
        pl->cur_interface = link_state.interface;
 
-       if (pl->pcs_ops && pl->pcs_ops->pcs_link_up)
-               pl->pcs_ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode,
+       if (pl->pcs && pl->pcs->ops->pcs_link_up)
+               pl->pcs->ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode,
                                         pl->cur_interface,
                                         link_state.speed, link_state.duplex);
 
@@ -1115,7 +1124,7 @@ static void phylink_resolve(struct work_struct *w)
                        }
                        phylink_major_config(pl, false, &link_state);
                        pl->link_config.interface = link_state.interface;
-               } else if (!pl->pcs_ops && pl->config->legacy_pre_march2020) {
+               } else if (!pl->pcs && pl->config->legacy_pre_march2020) {
                        /* The interface remains unchanged, only the speed,
                         * duplex or pause settings have changed. Call the
                         * old mac_config() method to configure the MAC/PCS
@@ -2991,6 +3000,7 @@ int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface,
                        adv |= ADVERTISE_1000XPSE_ASYM;
                return adv;
        case PHY_INTERFACE_MODE_SGMII:
+       case PHY_INTERFACE_MODE_QSGMII:
                return 0x0001;
        default:
                /* Nothing to do for other modes */
index e7b0e12..63f90fe 100644 (file)
@@ -1290,7 +1290,7 @@ static const struct hwmon_chip_info sfp_hwmon_chip_info = {
 static void sfp_hwmon_probe(struct work_struct *work)
 {
        struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work);
-       int err, i;
+       int err;
 
        /* hwmon interface needs to access 16bit registers in atomic way to
         * guarantee coherency of the diagnostic monitoring data. If it is not
@@ -1318,16 +1318,12 @@ static void sfp_hwmon_probe(struct work_struct *work)
                return;
        }
 
-       sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL);
-       if (!sfp->hwmon_name) {
+       sfp->hwmon_name = hwmon_sanitize_name(dev_name(sfp->dev));
+       if (IS_ERR(sfp->hwmon_name)) {
                dev_err(sfp->dev, "out of memory for hwmon name\n");
                return;
        }
 
-       for (i = 0; sfp->hwmon_name[i]; i++)
-               if (hwmon_is_bad_char(sfp->hwmon_name[i]))
-                       sfp->hwmon_name[i] = '_';
-
        sfp->hwmon_dev = hwmon_device_register_with_info(sfp->dev,
                                                         sfp->hwmon_name, sfp,
                                                         &sfp_hwmon_chip_info,
index 96d3c40..69423b8 100644 (file)
@@ -121,10 +121,7 @@ static int smsc_phy_config_init(struct phy_device *phydev)
        /* Enable energy detect mode for this SMSC Transceivers */
        rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
                       rc | MII_LAN83C185_EDPWRDOWN);
-       if (rc < 0)
-               return rc;
-
-       return smsc_phy_ack_interrupt(phydev);
+       return rc;
 }
 
 static int smsc_phy_reset(struct phy_device *phydev)
@@ -146,11 +143,6 @@ static int smsc_phy_reset(struct phy_device *phydev)
        return genphy_soft_reset(phydev);
 }
 
-static int lan911x_config_init(struct phy_device *phydev)
-{
-       return smsc_phy_ack_interrupt(phydev);
-}
-
 static int lan87xx_config_aneg(struct phy_device *phydev)
 {
        int rc;
@@ -420,9 +412,6 @@ static struct phy_driver smsc_phy_driver[] = {
 
        .probe          = smsc_phy_probe,
 
-       /* basic functions */
-       .config_init    = lan911x_config_init,
-
        /* IRQ related */
        .config_intr    = smsc_phy_config_intr,
        .handle_interrupt = smsc_phy_handle_interrupt,
index 4a365f1..9206c66 100644 (file)
@@ -2968,7 +2968,7 @@ ppp_unregister_channel(struct ppp_channel *chan)
        chan->ppp = NULL;
 
        /*
-        * This ensures that we have returned from any calls into the
+        * This ensures that we have returned from any calls into
         * the channel's start_xmit or ioctl routine before we proceed.
         */
        down_write(&pch->chan_sem);
index b07dde6..aac133a 100644 (file)
@@ -749,10 +749,10 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
 
                pcpu_stats = this_cpu_ptr(team->pcpu_stats);
                u64_stats_update_begin(&pcpu_stats->syncp);
-               pcpu_stats->rx_packets++;
-               pcpu_stats->rx_bytes += skb->len;
+               u64_stats_inc(&pcpu_stats->rx_packets);
+               u64_stats_add(&pcpu_stats->rx_bytes, skb->len);
                if (skb->pkt_type == PACKET_MULTICAST)
-                       pcpu_stats->rx_multicast++;
+                       u64_stats_inc(&pcpu_stats->rx_multicast);
                u64_stats_update_end(&pcpu_stats->syncp);
 
                skb->dev = team->dev;
@@ -1720,8 +1720,8 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
 
                pcpu_stats = this_cpu_ptr(team->pcpu_stats);
                u64_stats_update_begin(&pcpu_stats->syncp);
-               pcpu_stats->tx_packets++;
-               pcpu_stats->tx_bytes += len;
+               u64_stats_inc(&pcpu_stats->tx_packets);
+               u64_stats_add(&pcpu_stats->tx_bytes, len);
                u64_stats_update_end(&pcpu_stats->syncp);
        } else {
                this_cpu_inc(team->pcpu_stats->tx_dropped);
@@ -1854,11 +1854,11 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                p = per_cpu_ptr(team->pcpu_stats, i);
                do {
                        start = u64_stats_fetch_begin_irq(&p->syncp);
-                       rx_packets      = p->rx_packets;
-                       rx_bytes        = p->rx_bytes;
-                       rx_multicast    = p->rx_multicast;
-                       tx_packets      = p->tx_packets;
-                       tx_bytes        = p->tx_bytes;
+                       rx_packets      = u64_stats_read(&p->rx_packets);
+                       rx_bytes        = u64_stats_read(&p->rx_bytes);
+                       rx_multicast    = u64_stats_read(&p->rx_multicast);
+                       tx_packets      = u64_stats_read(&p->tx_packets);
+                       tx_bytes        = u64_stats_read(&p->tx_bytes);
                } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                stats->rx_packets       += rx_packets;
@@ -1870,9 +1870,9 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                 * rx_dropped, tx_dropped & rx_nohandler are u32,
                 * updated without syncp protection.
                 */
-               rx_dropped      += p->rx_dropped;
-               tx_dropped      += p->tx_dropped;
-               rx_nohandler    += p->rx_nohandler;
+               rx_dropped      += READ_ONCE(p->rx_dropped);
+               tx_dropped      += READ_ONCE(p->tx_dropped);
+               rx_nohandler    += READ_ONCE(p->rx_nohandler);
        }
        stats->rx_dropped       = rx_dropped;
        stats->tx_dropped       = tx_dropped;
index 45d3cc5..21c1ca2 100644 (file)
@@ -212,9 +212,6 @@ void asix_rx_fixup_common_free(struct asix_common_private *dp);
 struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
                              gfp_t flags);
 
-int asix_set_sw_mii(struct usbnet *dev, int in_pm);
-int asix_set_hw_mii(struct usbnet *dev, int in_pm);
-
 int asix_read_phy_addr(struct usbnet *dev, bool internal);
 
 int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm);
index b4a1b7a..9ea91c3 100644 (file)
@@ -68,6 +68,27 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
                               value, index, data, size);
 }
 
+static int asix_set_sw_mii(struct usbnet *dev, int in_pm)
+{
+       int ret;
+
+       ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL, in_pm);
+
+       if (ret < 0)
+               netdev_err(dev->net, "Failed to enable software MII access\n");
+       return ret;
+}
+
+static int asix_set_hw_mii(struct usbnet *dev, int in_pm)
+{
+       int ret;
+
+       ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL, in_pm);
+       if (ret < 0)
+               netdev_err(dev->net, "Failed to enable hardware MII access\n");
+       return ret;
+}
+
 static int asix_check_host_enable(struct usbnet *dev, int in_pm)
 {
        int i, ret;
@@ -297,25 +318,6 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
        return skb;
 }
 
-int asix_set_sw_mii(struct usbnet *dev, int in_pm)
-{
-       int ret;
-       ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL, in_pm);
-
-       if (ret < 0)
-               netdev_err(dev->net, "Failed to enable software MII access\n");
-       return ret;
-}
-
-int asix_set_hw_mii(struct usbnet *dev, int in_pm)
-{
-       int ret;
-       ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL, in_pm);
-       if (ret < 0)
-               netdev_err(dev->net, "Failed to enable hardware MII access\n");
-       return ret;
-}
-
 int asix_read_phy_addr(struct usbnet *dev, bool internal)
 {
        int ret, offset;
index 1a376ed..1e5c153 100644 (file)
@@ -280,7 +280,7 @@ static void catc_irq_done(struct urb *urb)
        struct catc *catc = urb->context;
        u8 *data = urb->transfer_buffer;
        int status = urb->status;
-       unsigned int hasdata = 0, linksts = LinkNoChange;
+       unsigned int hasdata, linksts = LinkNoChange;
        int res;
 
        if (!catc->is_f5u011) {
index 359ea0d..baa9b14 100644 (file)
@@ -218,7 +218,7 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                                if (unlikely(!skb2))
                                        goto next;
                                skb_trim(skb2, len);
-                               put_unaligned_le16(BIT(15) | (1 << 11) | len,
+                               put_unaligned_le16(BIT(15) | BIT(11) | len,
                                                skb_push(skb2, 2));
                                eem_linkcmd(dev, skb2);
                                break;
index bd03e16..bfb58c9 100644 (file)
@@ -71,22 +71,22 @@ struct smsc95xx_priv {
        struct fwnode_handle *irqfwnode;
        struct mii_bus *mdiobus;
        struct phy_device *phydev;
+       struct task_struct *pm_task;
 };
 
 static bool turbo_mode = true;
 module_param(turbo_mode, bool, 0644);
 MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
 
-static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
-                                           u32 *data, int in_pm)
+static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
+                                         u32 *data)
 {
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        u32 buf;
        int ret;
        int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
 
-       BUG_ON(!dev);
-
-       if (!in_pm)
+       if (current != pdata->pm_task)
                fn = usbnet_read_cmd;
        else
                fn = usbnet_read_cmd_nopm;
@@ -107,16 +107,15 @@ static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
        return ret;
 }
 
-static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index,
-                                            u32 data, int in_pm)
+static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
+                                          u32 data)
 {
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        u32 buf;
        int ret;
        int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
 
-       BUG_ON(!dev);
-
-       if (!in_pm)
+       if (current != pdata->pm_task)
                fn = usbnet_write_cmd;
        else
                fn = usbnet_write_cmd_nopm;
@@ -134,41 +133,16 @@ static int __must_check __smsc95xx_write_reg(struct usbnet *dev, u32 index,
        return ret;
 }
 
-static int __must_check smsc95xx_read_reg_nopm(struct usbnet *dev, u32 index,
-                                              u32 *data)
-{
-       return __smsc95xx_read_reg(dev, index, data, 1);
-}
-
-static int __must_check smsc95xx_write_reg_nopm(struct usbnet *dev, u32 index,
-                                               u32 data)
-{
-       return __smsc95xx_write_reg(dev, index, data, 1);
-}
-
-static int __must_check smsc95xx_read_reg(struct usbnet *dev, u32 index,
-                                         u32 *data)
-{
-       return __smsc95xx_read_reg(dev, index, data, 0);
-}
-
-static int __must_check smsc95xx_write_reg(struct usbnet *dev, u32 index,
-                                          u32 data)
-{
-       return __smsc95xx_write_reg(dev, index, data, 0);
-}
-
 /* Loop until the read is completed with timeout
  * called with phy_mutex held */
-static int __must_check __smsc95xx_phy_wait_not_busy(struct usbnet *dev,
-                                                    int in_pm)
+static int __must_check smsc95xx_phy_wait_not_busy(struct usbnet *dev)
 {
        unsigned long start_time = jiffies;
        u32 val;
        int ret;
 
        do {
-               ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm);
+               ret = smsc95xx_read_reg(dev, MII_ADDR, &val);
                if (ret < 0) {
                        /* Ignore -ENODEV error during disconnect() */
                        if (ret == -ENODEV)
@@ -189,8 +163,7 @@ static u32 mii_address_cmd(int phy_id, int idx, u16 op)
        return (phy_id & 0x1f) << 11 | (idx & 0x1f) << 6 | op;
 }
 
-static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx,
-                               int in_pm)
+static int smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx)
 {
        u32 val, addr;
        int ret;
@@ -198,7 +171,7 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx,
        mutex_lock(&dev->phy_mutex);
 
        /* confirm MII not busy */
-       ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
+       ret = smsc95xx_phy_wait_not_busy(dev);
        if (ret < 0) {
                netdev_warn(dev->net, "%s: MII is busy\n", __func__);
                goto done;
@@ -206,20 +179,20 @@ static int __smsc95xx_mdio_read(struct usbnet *dev, int phy_id, int idx,
 
        /* set the address, index & direction (read from PHY) */
        addr = mii_address_cmd(phy_id, idx, MII_READ_ | MII_BUSY_);
-       ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
+       ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
        if (ret < 0) {
                if (ret != -ENODEV)
                        netdev_warn(dev->net, "Error writing MII_ADDR\n");
                goto done;
        }
 
-       ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
+       ret = smsc95xx_phy_wait_not_busy(dev);
        if (ret < 0) {
                netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
                goto done;
        }
 
-       ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm);
+       ret = smsc95xx_read_reg(dev, MII_DATA, &val);
        if (ret < 0) {
                if (ret != -ENODEV)
                        netdev_warn(dev->net, "Error reading MII_DATA\n");
@@ -237,8 +210,8 @@ done:
        return ret;
 }
 
-static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id,
-                                 int idx, int regval, int in_pm)
+static void smsc95xx_mdio_write(struct usbnet *dev, int phy_id, int idx,
+                               int regval)
 {
        u32 val, addr;
        int ret;
@@ -246,14 +219,14 @@ static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id,
        mutex_lock(&dev->phy_mutex);
 
        /* confirm MII not busy */
-       ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
+       ret = smsc95xx_phy_wait_not_busy(dev);
        if (ret < 0) {
                netdev_warn(dev->net, "%s: MII is busy\n", __func__);
                goto done;
        }
 
        val = regval;
-       ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm);
+       ret = smsc95xx_write_reg(dev, MII_DATA, val);
        if (ret < 0) {
                if (ret != -ENODEV)
                        netdev_warn(dev->net, "Error writing MII_DATA\n");
@@ -262,14 +235,14 @@ static void __smsc95xx_mdio_write(struct usbnet *dev, int phy_id,
 
        /* set the address, index & direction (write to PHY) */
        addr = mii_address_cmd(phy_id, idx, MII_WRITE_ | MII_BUSY_);
-       ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
+       ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
        if (ret < 0) {
                if (ret != -ENODEV)
                        netdev_warn(dev->net, "Error writing MII_ADDR\n");
                goto done;
        }
 
-       ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
+       ret = smsc95xx_phy_wait_not_busy(dev);
        if (ret < 0) {
                netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
                goto done;
@@ -279,25 +252,11 @@ done:
        mutex_unlock(&dev->phy_mutex);
 }
 
-static int smsc95xx_mdio_read_nopm(struct usbnet *dev, int idx)
-{
-       struct smsc95xx_priv *pdata = dev->driver_priv;
-
-       return __smsc95xx_mdio_read(dev, pdata->phydev->mdio.addr, idx, 1);
-}
-
-static void smsc95xx_mdio_write_nopm(struct usbnet *dev, int idx, int regval)
-{
-       struct smsc95xx_priv *pdata = dev->driver_priv;
-
-       __smsc95xx_mdio_write(dev, pdata->phydev->mdio.addr, idx, regval, 1);
-}
-
 static int smsc95xx_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)
 {
        struct usbnet *dev = bus->priv;
 
-       return __smsc95xx_mdio_read(dev, phy_id, idx, 0);
+       return smsc95xx_mdio_read(dev, phy_id, idx);
 }
 
 static int smsc95xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
@@ -305,7 +264,7 @@ static int smsc95xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
 {
        struct usbnet *dev = bus->priv;
 
-       __smsc95xx_mdio_write(dev, phy_id, idx, regval, 0);
+       smsc95xx_mdio_write(dev, phy_id, idx, regval);
        return 0;
 }
 
@@ -865,7 +824,7 @@ static int smsc95xx_start_tx_path(struct usbnet *dev)
 }
 
 /* Starts the Receive path */
-static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm)
+static int smsc95xx_start_rx_path(struct usbnet *dev)
 {
        struct smsc95xx_priv *pdata = dev->driver_priv;
        unsigned long flags;
@@ -874,7 +833,7 @@ static int smsc95xx_start_rx_path(struct usbnet *dev, int in_pm)
        pdata->mac_cr |= MAC_CR_RXEN_;
        spin_unlock_irqrestore(&pdata->mac_cr_lock, flags);
 
-       return __smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr, in_pm);
+       return smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
 }
 
 static int smsc95xx_reset(struct usbnet *dev)
@@ -1057,7 +1016,7 @@ static int smsc95xx_reset(struct usbnet *dev)
                return ret;
        }
 
-       ret = smsc95xx_start_rx_path(dev, 0);
+       ret = smsc95xx_start_rx_path(dev);
        if (ret < 0) {
                netdev_warn(dev->net, "Failed to start RX path\n");
                return ret;
@@ -1291,16 +1250,17 @@ static u32 smsc_crc(const u8 *buffer, size_t len, int filter)
        return crc << ((filter % 2) * 16);
 }
 
-static int smsc95xx_link_ok_nopm(struct usbnet *dev)
+static int smsc95xx_link_ok(struct usbnet *dev)
 {
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        int ret;
 
        /* first, a dummy read, needed to latch some MII phys */
-       ret = smsc95xx_mdio_read_nopm(dev, MII_BMSR);
+       ret = smsc95xx_mdio_read(dev, pdata->phydev->mdio.addr, MII_BMSR);
        if (ret < 0)
                return ret;
 
-       ret = smsc95xx_mdio_read_nopm(dev, MII_BMSR);
+       ret = smsc95xx_mdio_read(dev, pdata->phydev->mdio.addr, MII_BMSR);
        if (ret < 0)
                return ret;
 
@@ -1313,14 +1273,14 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
        u32 val;
        int ret;
 
-       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
        if (ret < 0)
                return ret;
 
        val &= (~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_));
        val |= PM_CTL_SUS_MODE_0;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
@@ -1332,12 +1292,12 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
        if (pdata->wolopts & WAKE_PHY)
                val |= PM_CTL_WUPS_ED_;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
        /* read back PM_CTRL */
-       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
        if (ret < 0)
                return ret;
 
@@ -1349,34 +1309,34 @@ static int smsc95xx_enter_suspend0(struct usbnet *dev)
 static int smsc95xx_enter_suspend1(struct usbnet *dev)
 {
        struct smsc95xx_priv *pdata = dev->driver_priv;
+       int ret, phy_id = pdata->phydev->mdio.addr;
        u32 val;
-       int ret;
 
        /* reconfigure link pulse detection timing for
         * compatibility with non-standard link partners
         */
        if (pdata->features & FEATURE_PHY_NLP_CROSSOVER)
-               smsc95xx_mdio_write_nopm(dev, PHY_EDPD_CONFIG,
-                                        PHY_EDPD_CONFIG_DEFAULT);
+               smsc95xx_mdio_write(dev, phy_id, PHY_EDPD_CONFIG,
+                                   PHY_EDPD_CONFIG_DEFAULT);
 
        /* enable energy detect power-down mode */
-       ret = smsc95xx_mdio_read_nopm(dev, PHY_MODE_CTRL_STS);
+       ret = smsc95xx_mdio_read(dev, phy_id, PHY_MODE_CTRL_STS);
        if (ret < 0)
                return ret;
 
        ret |= MODE_CTRL_STS_EDPWRDOWN_;
 
-       smsc95xx_mdio_write_nopm(dev, PHY_MODE_CTRL_STS, ret);
+       smsc95xx_mdio_write(dev, phy_id, PHY_MODE_CTRL_STS, ret);
 
        /* enter SUSPEND1 mode */
-       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
        if (ret < 0)
                return ret;
 
        val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
        val |= PM_CTL_SUS_MODE_1;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
@@ -1384,7 +1344,7 @@ static int smsc95xx_enter_suspend1(struct usbnet *dev)
        val &= ~PM_CTL_WUPS_;
        val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_);
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
@@ -1399,14 +1359,14 @@ static int smsc95xx_enter_suspend2(struct usbnet *dev)
        u32 val;
        int ret;
 
-       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
        if (ret < 0)
                return ret;
 
        val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
        val |= PM_CTL_SUS_MODE_2;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
@@ -1421,7 +1381,7 @@ static int smsc95xx_enter_suspend3(struct usbnet *dev)
        u32 val;
        int ret;
 
-       ret = smsc95xx_read_reg_nopm(dev, RX_FIFO_INF, &val);
+       ret = smsc95xx_read_reg(dev, RX_FIFO_INF, &val);
        if (ret < 0)
                return ret;
 
@@ -1430,14 +1390,14 @@ static int smsc95xx_enter_suspend3(struct usbnet *dev)
                return -EBUSY;
        }
 
-       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
        if (ret < 0)
                return ret;
 
        val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
        val |= PM_CTL_SUS_MODE_3 | PM_CTL_RES_CLR_WKP_STS;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
@@ -1445,7 +1405,7 @@ static int smsc95xx_enter_suspend3(struct usbnet *dev)
        val &= ~PM_CTL_WUPS_;
        val |= PM_CTL_WUPS_WOL_;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                return ret;
 
@@ -1490,9 +1450,12 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
        u32 val, link_up;
        int ret;
 
+       pdata->pm_task = current;
+
        ret = usbnet_suspend(intf, message);
        if (ret < 0) {
                netdev_warn(dev->net, "usbnet_suspend error\n");
+               pdata->pm_task = NULL;
                return ret;
        }
 
@@ -1501,8 +1464,7 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                pdata->suspend_flags = 0;
        }
 
-       /* determine if link is up using only _nopm functions */
-       link_up = smsc95xx_link_ok_nopm(dev);
+       link_up = smsc95xx_link_ok(dev);
 
        if (message.event == PM_EVENT_AUTO_SUSPEND &&
            (pdata->features & FEATURE_REMOTE_WAKEUP)) {
@@ -1519,23 +1481,23 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                netdev_info(dev->net, "entering SUSPEND2 mode\n");
 
                /* disable energy detect (link up) & wake up events */
-               ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
+               ret = smsc95xx_read_reg(dev, WUCSR, &val);
                if (ret < 0)
                        goto done;
 
                val &= ~(WUCSR_MPEN_ | WUCSR_WAKE_EN_);
 
-               ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
+               ret = smsc95xx_write_reg(dev, WUCSR, val);
                if (ret < 0)
                        goto done;
 
-               ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+               ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
                if (ret < 0)
                        goto done;
 
                val &= ~(PM_CTL_ED_EN_ | PM_CTL_WOL_EN_);
 
-               ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+               ret = smsc95xx_write_reg(dev, PM_CTRL, val);
                if (ret < 0)
                        goto done;
 
@@ -1626,7 +1588,7 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                }
 
                for (i = 0; i < (wuff_filter_count * 4); i++) {
-                       ret = smsc95xx_write_reg_nopm(dev, WUFF, filter_mask[i]);
+                       ret = smsc95xx_write_reg(dev, WUFF, filter_mask[i]);
                        if (ret < 0) {
                                kfree(filter_mask);
                                goto done;
@@ -1635,50 +1597,50 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                kfree(filter_mask);
 
                for (i = 0; i < (wuff_filter_count / 4); i++) {
-                       ret = smsc95xx_write_reg_nopm(dev, WUFF, command[i]);
+                       ret = smsc95xx_write_reg(dev, WUFF, command[i]);
                        if (ret < 0)
                                goto done;
                }
 
                for (i = 0; i < (wuff_filter_count / 4); i++) {
-                       ret = smsc95xx_write_reg_nopm(dev, WUFF, offset[i]);
+                       ret = smsc95xx_write_reg(dev, WUFF, offset[i]);
                        if (ret < 0)
                                goto done;
                }
 
                for (i = 0; i < (wuff_filter_count / 2); i++) {
-                       ret = smsc95xx_write_reg_nopm(dev, WUFF, crc[i]);
+                       ret = smsc95xx_write_reg(dev, WUFF, crc[i]);
                        if (ret < 0)
                                goto done;
                }
 
                /* clear any pending pattern match packet status */
-               ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
+               ret = smsc95xx_read_reg(dev, WUCSR, &val);
                if (ret < 0)
                        goto done;
 
                val |= WUCSR_WUFR_;
 
-               ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
+               ret = smsc95xx_write_reg(dev, WUCSR, val);
                if (ret < 0)
                        goto done;
        }
 
        if (pdata->wolopts & WAKE_MAGIC) {
                /* clear any pending magic packet status */
-               ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
+               ret = smsc95xx_read_reg(dev, WUCSR, &val);
                if (ret < 0)
                        goto done;
 
                val |= WUCSR_MPR_;
 
-               ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
+               ret = smsc95xx_write_reg(dev, WUCSR, val);
                if (ret < 0)
                        goto done;
        }
 
        /* enable/disable wakeup sources */
-       ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
+       ret = smsc95xx_read_reg(dev, WUCSR, &val);
        if (ret < 0)
                goto done;
 
@@ -1698,12 +1660,12 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
                val &= ~WUCSR_MPEN_;
        }
 
-       ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
+       ret = smsc95xx_write_reg(dev, WUCSR, val);
        if (ret < 0)
                goto done;
 
        /* enable wol wakeup source */
-       ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+       ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
        if (ret < 0)
                goto done;
 
@@ -1713,12 +1675,12 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
        if (pdata->wolopts & WAKE_PHY)
                val |= PM_CTL_ED_EN_;
 
-       ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+       ret = smsc95xx_write_reg(dev, PM_CTRL, val);
        if (ret < 0)
                goto done;
 
        /* enable receiver to enable frame reception */
-       smsc95xx_start_rx_path(dev, 1);
+       smsc95xx_start_rx_path(dev);
 
        /* some wol options are enabled, so enter SUSPEND0 */
        netdev_info(dev->net, "entering SUSPEND0 mode\n");
@@ -1732,6 +1694,7 @@ done:
        if (ret && PMSG_IS_AUTO(message))
                usbnet_resume(intf);
 
+       pdata->pm_task = NULL;
        return ret;
 }
 
@@ -1752,29 +1715,31 @@ static int smsc95xx_resume(struct usb_interface *intf)
        /* do this first to ensure it's cleared even in error case */
        pdata->suspend_flags = 0;
 
+       pdata->pm_task = current;
+
        if (suspend_flags & SUSPEND_ALLMODES) {
                /* clear wake-up sources */
-               ret = smsc95xx_read_reg_nopm(dev, WUCSR, &val);
+               ret = smsc95xx_read_reg(dev, WUCSR, &val);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);
 
-               ret = smsc95xx_write_reg_nopm(dev, WUCSR, val);
+               ret = smsc95xx_write_reg(dev, WUCSR, val);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                /* clear wake-up status */
-               ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
+               ret = smsc95xx_read_reg(dev, PM_CTRL, &val);
                if (ret < 0)
-                       return ret;
+                       goto done;
 
                val &= ~PM_CTL_WOL_EN_;
                val |= PM_CTL_WUPS_;
 
-               ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
+               ret = smsc95xx_write_reg(dev, PM_CTRL, val);
                if (ret < 0)
-                       return ret;
+                       goto done;
        }
 
        phy_init_hw(pdata->phydev);
@@ -1783,15 +1748,20 @@ static int smsc95xx_resume(struct usb_interface *intf)
        if (ret < 0)
                netdev_warn(dev->net, "usbnet_resume error\n");
 
+done:
+       pdata->pm_task = NULL;
        return ret;
 }
 
 static int smsc95xx_reset_resume(struct usb_interface *intf)
 {
        struct usbnet *dev = usb_get_intfdata(intf);
+       struct smsc95xx_priv *pdata = dev->driver_priv;
        int ret;
 
+       pdata->pm_task = current;
        ret = smsc95xx_reset(dev);
+       pdata->pm_task = NULL;
        if (ret < 0)
                return ret;
 
@@ -2088,6 +2058,11 @@ static const struct usb_device_id products[] = {
                USB_DEVICE(0x0424, 0x9E08),
                .driver_info = (unsigned long) &smsc95xx_info,
        },
+       {
+               /* Microchip's EVB-LAN8670-USB 10BASE-T1S Ethernet Device */
+               USB_DEVICE(0x184F, 0x0051),
+               .driver_info = (unsigned long)&smsc95xx_info,
+       },
        { },            /* END */
 };
 MODULE_DEVICE_TABLE(usb, products);
index 78a9275..e415465 100644 (file)
@@ -17,9 +17,6 @@
  * issues can usefully be addressed by this framework.
  */
 
-// #define     DEBUG                   // error path messages, extra info
-// #define     VERBOSE                 // more; success messages
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
@@ -337,8 +334,8 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
                skb->protocol = eth_type_trans (skb, dev->net);
 
        flags = u64_stats_update_begin_irqsave(&stats64->syncp);
-       stats64->rx_packets++;
-       stats64->rx_bytes += skb->len;
+       u64_stats_inc(&stats64->rx_packets);
+       u64_stats_add(&stats64->rx_bytes, skb->len);
        u64_stats_update_end_irqrestore(&stats64->syncp, flags);
 
        netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
@@ -849,13 +846,11 @@ int usbnet_stop (struct net_device *net)
 
        mpn = !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags);
 
-       /* deferred work (task, timer, softirq) must also stop.
-        * can't flush_scheduled_work() until we drop rtnl (later),
-        * else workers could deadlock; so make workers a NOP.
-        */
+       /* deferred work (timer, softirq, task) must also stop */
        dev->flags = 0;
        del_timer_sync (&dev->delay);
        tasklet_kill (&dev->bh);
+       cancel_work_sync(&dev->kevent);
        if (!pm)
                usb_autopm_put_interface(dev->intf);
 
@@ -1258,8 +1253,8 @@ static void tx_complete (struct urb *urb)
                unsigned long flags;
 
                flags = u64_stats_update_begin_irqsave(&stats64->syncp);
-               stats64->tx_packets += entry->packets;
-               stats64->tx_bytes += entry->length;
+               u64_stats_add(&stats64->tx_packets, entry->packets);
+               u64_stats_add(&stats64->tx_bytes, entry->length);
                u64_stats_update_end_irqrestore(&stats64->syncp, flags);
        } else {
                dev->net->stats.tx_errors++;
@@ -1619,8 +1614,6 @@ void usbnet_disconnect (struct usb_interface *intf)
        net = dev->net;
        unregister_netdev (net);
 
-       cancel_work_sync(&dev->kevent);
-
        usb_scuttle_anchored_urbs(&dev->deferred);
 
        if (dev->driver_info->unbind)
index 7a38925..a666a88 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Linux driver for VMware's vmxnet3 ethernet NIC.
 #
-# Copyright (C) 2007-2021, VMware, Inc. All Rights Reserved.
+# Copyright (C) 2007-2022, VMware, Inc. All Rights Reserved.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by the
index f9f3a23..41c0660 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Linux driver for VMware's vmxnet3 ethernet NIC.
  *
- * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2022, VMware, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
index 74d4e8b..41d6767 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Linux driver for VMware's vmxnet3 ethernet NIC.
  *
- * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2022, VMware, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -40,7 +40,13 @@ enum {
        VMXNET3_REG_MACL        = 0x28, /* MAC Address Low */
        VMXNET3_REG_MACH        = 0x30, /* MAC Address High */
        VMXNET3_REG_ICR         = 0x38, /* Interrupt Cause Register */
-       VMXNET3_REG_ECR         = 0x40  /* Event Cause Register */
+       VMXNET3_REG_ECR         = 0x40, /* Event Cause Register */
+       VMXNET3_REG_DCR         = 0x48, /* Device capability register,
+                                        * from 0x48 to 0x80
+                                        */
+       VMXNET3_REG_PTCR        = 0x88, /* Passthru capbility register
+                                        * from 0x88 to 0xb0
+                                        */
 };
 
 /* BAR 0 */
@@ -51,8 +57,18 @@ enum {
        VMXNET3_REG_RXPROD2     = 0xA00  /* Rx Producer Index for ring 2 */
 };
 
-#define VMXNET3_PT_REG_SIZE     4096   /* BAR 0 */
-#define VMXNET3_VD_REG_SIZE     4096   /* BAR 1 */
+/* For Large PT BAR, the following offset to DB register */
+enum {
+       VMXNET3_REG_LB_TXPROD   = 0x1000, /* Tx Producer Index */
+       VMXNET3_REG_LB_RXPROD   = 0x1400, /* Rx Producer Index for ring 1 */
+       VMXNET3_REG_LB_RXPROD2  = 0x1800, /* Rx Producer Index for ring 2 */
+};
+
+#define VMXNET3_PT_REG_SIZE         4096               /* BAR 0 */
+#define VMXNET3_LARGE_PT_REG_SIZE   8192               /* large PT pages */
+#define VMXNET3_VD_REG_SIZE         4096               /* BAR 1 */
+#define VMXNET3_LARGE_BAR0_REG_SIZE (4096 * 4096)      /* LARGE BAR 0 */
+#define VMXNET3_OOB_REG_SIZE        (4094 * 4096)      /* OOB pages */
 
 #define VMXNET3_REG_ALIGN       8      /* All registers are 8-byte aligned. */
 #define VMXNET3_REG_ALIGN_MASK  0x7
@@ -83,6 +99,9 @@ enum {
        VMXNET3_CMD_SET_COALESCE,
        VMXNET3_CMD_REGISTER_MEMREGS,
        VMXNET3_CMD_SET_RSS_FIELDS,
+       VMXNET3_CMD_RESERVED4,
+       VMXNET3_CMD_RESERVED5,
+       VMXNET3_CMD_SET_RING_BUFFER_SIZE,
 
        VMXNET3_CMD_FIRST_GET = 0xF00D0000,
        VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET,
@@ -101,6 +120,9 @@ enum {
        VMXNET3_CMD_GET_RESERVED2,
        VMXNET3_CMD_GET_RESERVED3,
        VMXNET3_CMD_GET_MAX_QUEUES_CONF,
+       VMXNET3_CMD_GET_RESERVED4,
+       VMXNET3_CMD_GET_MAX_CAPABILITIES,
+       VMXNET3_CMD_GET_DCR0_REG,
 };
 
 /*
@@ -126,17 +148,17 @@ struct Vmxnet3_TxDesc {
 
 #ifdef __BIG_ENDIAN_BITFIELD
        u32 msscof:14;  /* MSS, checksum offset, flags */
-       u32 ext1:1;
+       u32 ext1:1;     /* set to 1 to indicate inner csum/tso, vmxnet3 v7 */
        u32 dtype:1;    /* descriptor type */
-       u32 oco:1;
+       u32 oco:1;      /* Outer csum offload */
        u32 gen:1;      /* generation bit */
        u32 len:14;
 #else
        u32 len:14;
        u32 gen:1;      /* generation bit */
-       u32 oco:1;
+       u32 oco:1;      /* Outer csum offload */
        u32 dtype:1;    /* descriptor type */
-       u32 ext1:1;
+       u32 ext1:1;     /* set to 1 to indicate inner csum/tso, vmxnet3 v7 */
        u32 msscof:14;  /* MSS, checksum offset, flags */
 #endif  /* __BIG_ENDIAN_BITFIELD */
 
@@ -240,11 +262,13 @@ struct Vmxnet3_RxCompDesc {
        u32             rqID:10;      /* rx queue/ring ID */
        u32             sop:1;        /* Start of Packet */
        u32             eop:1;        /* End of Packet */
-       u32             ext1:2;
+       u32             ext1:2;       /* bit 0: indicating v4/v6/.. is for inner header */
+                                     /* bit 1: indicating rssType is based on inner header */
        u32             rxdIdx:12;    /* Index of the RxDesc */
 #else
        u32             rxdIdx:12;    /* Index of the RxDesc */
-       u32             ext1:2;
+       u32             ext1:2;       /* bit 0: indicating v4/v6/.. is for inner header */
+                                     /* bit 1: indicating rssType is based on inner header */
        u32             eop:1;        /* End of Packet */
        u32             sop:1;        /* Start of Packet */
        u32             rqID:10;      /* rx queue/ring ID */
@@ -378,6 +402,8 @@ union Vmxnet3_GenericDesc {
 
 /* max # of tx descs for a non-tso pkt */
 #define VMXNET3_MAX_TXD_PER_PKT 16
+/* max # of tx descs for a tso pkt */
+#define VMXNET3_MAX_TSO_TXD_PER_PKT 24
 
 /* Max size of a single rx buffer */
 #define VMXNET3_MAX_RX_BUF_SIZE  ((1 << 14) - 1)
@@ -724,6 +750,13 @@ enum Vmxnet3_RSSField {
        VMXNET3_RSS_FIELDS_ESPIP6 = 0x0020,
 };
 
+struct Vmxnet3_RingBufferSize {
+       __le16             ring1BufSizeType0;
+       __le16             ring1BufSizeType1;
+       __le16             ring2BufSizeType1;
+       __le16             pad;
+};
+
 /* If the command data <= 16 bytes, use the shared memory directly.
  * otherwise, use variable length configuration descriptor.
  */
@@ -731,6 +764,7 @@ union Vmxnet3_CmdInfo {
        struct Vmxnet3_VariableLenConfDesc      varConf;
        struct Vmxnet3_SetPolling               setPolling;
        enum   Vmxnet3_RSSField                 setRssFields;
+       struct Vmxnet3_RingBufferSize           ringBufSize;
        __le64                                  data[2];
 };
 
@@ -801,4 +835,30 @@ struct Vmxnet3_DriverShared {
 #define VMXNET3_LINK_UP         (10000 << 16 | 1)    /* 10 Gbps, up */
 #define VMXNET3_LINK_DOWN       0
 
+#define VMXNET3_DCR_ERROR                          31   /* error when bit 31 of DCR is set */
+#define VMXNET3_CAP_UDP_RSS                        0    /* bit 0 of DCR 0 */
+#define VMXNET3_CAP_ESP_RSS_IPV4                   1    /* bit 1 of DCR 0 */
+#define VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD        2    /* bit 2 of DCR 0 */
+#define VMXNET3_CAP_GENEVE_TSO                     3    /* bit 3 of DCR 0 */
+#define VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD         4    /* bit 4 of DCR 0 */
+#define VMXNET3_CAP_VXLAN_TSO                      5    /* bit 5 of DCR 0 */
+#define VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD  6    /* bit 6 of DCR 0 */
+#define VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD   7    /* bit 7 of DCR 0 */
+#define VMXNET3_CAP_PKT_STEERING_IPV4              8    /* bit 8 of DCR 0 */
+#define VMXNET3_CAP_VERSION_4_MAX                  VMXNET3_CAP_PKT_STEERING_IPV4
+#define VMXNET3_CAP_ESP_RSS_IPV6                   9    /* bit 9 of DCR 0 */
+#define VMXNET3_CAP_VERSION_5_MAX                  VMXNET3_CAP_ESP_RSS_IPV6
+#define VMXNET3_CAP_ESP_OVER_UDP_RSS               10   /* bit 10 of DCR 0 */
+#define VMXNET3_CAP_INNER_RSS                      11   /* bit 11 of DCR 0 */
+#define VMXNET3_CAP_INNER_ESP_RSS                  12   /* bit 12 of DCR 0 */
+#define VMXNET3_CAP_CRC32_HASH_FUNC                13   /* bit 13 of DCR 0 */
+#define VMXNET3_CAP_VERSION_6_MAX                  VMXNET3_CAP_CRC32_HASH_FUNC
+#define VMXNET3_CAP_OAM_FILTER                     14   /* bit 14 of DCR 0 */
+#define VMXNET3_CAP_ESP_QS                         15   /* bit 15 of DCR 0 */
+#define VMXNET3_CAP_LARGE_BAR                      16   /* bit 16 of DCR 0 */
+#define VMXNET3_CAP_OOORX_COMP                     17   /* bit 17 of DCR 0 */
+#define VMXNET3_CAP_VERSION_7_MAX                  18
+/* when new capability is introduced, update VMXNET3_CAP_MAX */
+#define VMXNET3_CAP_MAX                            VMXNET3_CAP_VERSION_7_MAX
+
 #endif /* _VMXNET3_DEFS_H_ */
index 93e8d11..19c4147 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Linux driver for VMware's vmxnet3 ethernet NIC.
  *
- * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2022, VMware, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -130,6 +130,20 @@ vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
        netif_stop_subqueue(adapter->netdev, (tq - adapter->tx_queue));
 }
 
+/* Check if capability is supported by UPT device or
+ * UPT is even requested
+ */
+bool
+vmxnet3_check_ptcapability(u32 cap_supported, u32 cap)
+{
+       if (cap_supported & (1UL << VMXNET3_DCR_ERROR) ||
+           cap_supported & (1UL << cap)) {
+               return true;
+       }
+
+       return false;
+}
+
 
 /*
  * Check the link state. This may start or stop the tx queue.
@@ -571,6 +585,7 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
 
                rbi = rbi_base + ring->next2fill;
                gd = ring->base + ring->next2fill;
+               rbi->comp_state = VMXNET3_RXD_COMP_PENDING;
 
                if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
                        if (rbi->skb == NULL) {
@@ -630,8 +645,10 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
 
                /* Fill the last buffer but dont mark it ready, or else the
                 * device will think that the queue is full */
-               if (num_allocated == num_to_alloc)
+               if (num_allocated == num_to_alloc) {
+                       rbi->comp_state = VMXNET3_RXD_COMP_DONE;
                        break;
+               }
 
                gd->dword[2] |= cpu_to_le32(ring->gen << VMXNET3_RXD_GEN_SHIFT);
                num_allocated++;
@@ -1044,6 +1061,23 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                        }
                        tq->stats.copy_skb_header++;
                }
+               if (unlikely(count > VMXNET3_MAX_TSO_TXD_PER_PKT)) {
+                       /* tso pkts must not use more than
+                        * VMXNET3_MAX_TSO_TXD_PER_PKT entries
+                        */
+                       if (skb_linearize(skb) != 0) {
+                               tq->stats.drop_too_many_frags++;
+                               goto drop_pkt;
+                       }
+                       tq->stats.linearized++;
+
+                       /* recalculate the # of descriptors to use */
+                       count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + 1;
+                       if (unlikely(count > VMXNET3_MAX_TSO_TXD_PER_PKT)) {
+                               tq->stats.drop_too_many_frags++;
+                               goto drop_pkt;
+                       }
+               }
                if (skb->encapsulation) {
                        vmxnet3_prepare_inner_tso(skb, &ctx);
                } else {
@@ -1127,7 +1161,12 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
        if (ctx.mss) {
                if (VMXNET3_VERSION_GE_4(adapter) && skb->encapsulation) {
                        gdesc->txd.hlen = ctx.l4_offset + ctx.l4_hdr_size;
-                       gdesc->txd.om = VMXNET3_OM_ENCAP;
+                       if (VMXNET3_VERSION_GE_7(adapter)) {
+                               gdesc->txd.om = VMXNET3_OM_TSO;
+                               gdesc->txd.ext1 = 1;
+                       } else {
+                               gdesc->txd.om = VMXNET3_OM_ENCAP;
+                       }
                        gdesc->txd.msscof = ctx.mss;
 
                        if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM)
@@ -1144,8 +1183,15 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                            skb->encapsulation) {
                                gdesc->txd.hlen = ctx.l4_offset +
                                                  ctx.l4_hdr_size;
-                               gdesc->txd.om = VMXNET3_OM_ENCAP;
-                               gdesc->txd.msscof = 0;          /* Reserved */
+                               if (VMXNET3_VERSION_GE_7(adapter)) {
+                                       gdesc->txd.om = VMXNET3_OM_CSUM;
+                                       gdesc->txd.msscof = ctx.l4_offset +
+                                                           skb->csum_offset;
+                                       gdesc->txd.ext1 = 1;
+                               } else {
+                                       gdesc->txd.om = VMXNET3_OM_ENCAP;
+                                       gdesc->txd.msscof = 0;          /* Reserved */
+                               }
                        } else {
                                gdesc->txd.hlen = ctx.l4_offset;
                                gdesc->txd.om = VMXNET3_OM_CSUM;
@@ -1193,7 +1239,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
        if (tx_num_deferred >= le32_to_cpu(tq->shared->txThreshold)) {
                tq->shared->txNumDeferred = 0;
                VMXNET3_WRITE_BAR0_REG(adapter,
-                                      VMXNET3_REG_TXPROD + tq->qid * 8,
+                                      adapter->tx_prod_offset + tq->qid * 8,
                                       tq->tx_ring.next2fill);
        }
 
@@ -1345,14 +1391,15 @@ static int
 vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                       struct vmxnet3_adapter *adapter, int quota)
 {
-       static const u32 rxprod_reg[2] = {
-               VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2
+       u32 rxprod_reg[2] = {
+               adapter->rx_prod_offset, adapter->rx_prod2_offset
        };
        u32 num_pkts = 0;
        bool skip_page_frags = false;
        struct Vmxnet3_RxCompDesc *rcd;
        struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
        u16 segCnt = 0, mss = 0;
+       int comp_offset, fill_offset;
 #ifdef __BIG_ENDIAN_BITFIELD
        struct Vmxnet3_RxDesc rxCmdDesc;
        struct Vmxnet3_RxCompDesc rxComp;
@@ -1625,9 +1672,15 @@ not_lro:
 
 rcd_done:
                /* device may have skipped some rx descs */
-               ring->next2comp = idx;
-               num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring);
                ring = rq->rx_ring + ring_idx;
+               rbi->comp_state = VMXNET3_RXD_COMP_DONE;
+
+               comp_offset = vmxnet3_cmd_ring_desc_avail(ring);
+               fill_offset = (idx > ring->next2fill ? 0 : ring->size) +
+                             idx - ring->next2fill - 1;
+               if (!ring->isOutOfOrder || fill_offset >= comp_offset)
+                       ring->next2comp = idx;
+               num_to_alloc = vmxnet3_cmd_ring_desc_avail(ring);
 
                /* Ensure that the writes to rxd->gen bits will be observed
                 * after all other writes to rxd objects.
@@ -1635,18 +1688,38 @@ rcd_done:
                dma_wmb();
 
                while (num_to_alloc) {
-                       vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd,
-                                         &rxCmdDesc);
-                       BUG_ON(!rxd->addr);
+                       rbi = rq->buf_info[ring_idx] + ring->next2fill;
+                       if (!(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_OOORX_COMP)))
+                               goto refill_buf;
+                       if (ring_idx == 0) {
+                               /* ring0 Type1 buffers can get skipped; re-fill them */
+                               if (rbi->buf_type != VMXNET3_RX_BUF_SKB)
+                                       goto refill_buf;
+                       }
+                       if (rbi->comp_state == VMXNET3_RXD_COMP_DONE) {
+refill_buf:
+                               vmxnet3_getRxDesc(rxd, &ring->base[ring->next2fill].rxd,
+                                                 &rxCmdDesc);
+                               WARN_ON(!rxd->addr);
+
+                               /* Recv desc is ready to be used by the device */
+                               rxd->gen = ring->gen;
+                               vmxnet3_cmd_ring_adv_next2fill(ring);
+                               rbi->comp_state = VMXNET3_RXD_COMP_PENDING;
+                               num_to_alloc--;
+                       } else {
+                               /* rx completion hasn't occurred */
+                               ring->isOutOfOrder = 1;
+                               break;
+                       }
+               }
 
-                       /* Recv desc is ready to be used by the device */
-                       rxd->gen = ring->gen;
-                       vmxnet3_cmd_ring_adv_next2fill(ring);
-                       num_to_alloc--;
+               if (num_to_alloc == 0) {
+                       ring->isOutOfOrder = 0;
                }
 
                /* if needed, update the register */
-               if (unlikely(rq->shared->updateRxProd)) {
+               if (unlikely(rq->shared->updateRxProd) && (ring->next2fill & 0xf) == 0) {
                        VMXNET3_WRITE_BAR0_REG(adapter,
                                               rxprod_reg[ring_idx] + rq->qid * 8,
                                               ring->next2fill);
@@ -1810,6 +1883,7 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
                memset(rq->rx_ring[i].base, 0, rq->rx_ring[i].size *
                       sizeof(struct Vmxnet3_RxDesc));
                rq->rx_ring[i].gen = VMXNET3_INIT_GEN;
+               rq->rx_ring[i].isOutOfOrder = 0;
        }
        if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1,
                                    adapter) == 0) {
@@ -2000,8 +2074,17 @@ vmxnet3_poll_rx_only(struct napi_struct *napi, int budget)
        rxd_done = vmxnet3_rq_rx_complete(rq, adapter, budget);
 
        if (rxd_done < budget) {
+               struct Vmxnet3_RxCompDesc *rcd;
+#ifdef __BIG_ENDIAN_BITFIELD
+               struct Vmxnet3_RxCompDesc rxComp;
+#endif
                napi_complete_done(napi, rxd_done);
                vmxnet3_enable_intr(adapter, rq->comp_ring.intr_idx);
+               /* after unmasking the interrupt, check if any descriptors were completed */
+               vmxnet3_getRxComp(rcd, &rq->comp_ring.base[rq->comp_ring.next2proc].rcd,
+                                 &rxComp);
+               if (rcd->gen == rq->comp_ring.gen && napi_reschedule(napi))
+                       vmxnet3_disable_intr(adapter, rq->comp_ring.intr_idx);
        }
        return rxd_done;
 }
@@ -2627,6 +2710,23 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
 }
 
 static void
+vmxnet3_init_bufsize(struct vmxnet3_adapter *adapter)
+{
+       struct Vmxnet3_DriverShared *shared = adapter->shared;
+       union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo;
+       unsigned long flags;
+
+       if (!VMXNET3_VERSION_GE_7(adapter))
+               return;
+
+       cmdInfo->ringBufSize = adapter->ringBufSize;
+       spin_lock_irqsave(&adapter->cmd_lock, flags);
+       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+                              VMXNET3_CMD_SET_RING_BUFFER_SIZE);
+       spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+}
+
+static void
 vmxnet3_init_coalesce(struct vmxnet3_adapter *adapter)
 {
        struct Vmxnet3_DriverShared *shared = adapter->shared;
@@ -2671,6 +2771,36 @@ vmxnet3_init_rssfields(struct vmxnet3_adapter *adapter)
                adapter->rss_fields =
                        VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
        } else {
+               if (VMXNET3_VERSION_GE_7(adapter)) {
+                       if ((adapter->rss_fields & VMXNET3_RSS_FIELDS_UDPIP4 ||
+                            adapter->rss_fields & VMXNET3_RSS_FIELDS_UDPIP6) &&
+                           vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                                      VMXNET3_CAP_UDP_RSS)) {
+                               adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_UDP_RSS;
+                       } else {
+                               adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_UDP_RSS);
+                       }
+
+                       if ((adapter->rss_fields & VMXNET3_RSS_FIELDS_ESPIP4) &&
+                           vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                                      VMXNET3_CAP_ESP_RSS_IPV4)) {
+                               adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_ESP_RSS_IPV4;
+                       } else {
+                               adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_ESP_RSS_IPV4);
+                       }
+
+                       if ((adapter->rss_fields & VMXNET3_RSS_FIELDS_ESPIP6) &&
+                           vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                                      VMXNET3_CAP_ESP_RSS_IPV6)) {
+                               adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_ESP_RSS_IPV6;
+                       } else {
+                               adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_ESP_RSS_IPV6);
+                       }
+
+                       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DCR, adapter->dev_caps[0]);
+                       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DCR0_REG);
+                       adapter->dev_caps[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+               }
                cmdInfo->setRssFields = adapter->rss_fields;
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
                                       VMXNET3_CMD_SET_RSS_FIELDS);
@@ -2734,14 +2864,15 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
                goto activate_err;
        }
 
+       vmxnet3_init_bufsize(adapter);
        vmxnet3_init_coalesce(adapter);
        vmxnet3_init_rssfields(adapter);
 
        for (i = 0; i < adapter->num_rx_queues; i++) {
                VMXNET3_WRITE_BAR0_REG(adapter,
-                               VMXNET3_REG_RXPROD + i * VMXNET3_REG_ALIGN,
+                               adapter->rx_prod_offset + i * VMXNET3_REG_ALIGN,
                                adapter->rx_queue[i].rx_ring[0].next2fill);
-               VMXNET3_WRITE_BAR0_REG(adapter, (VMXNET3_REG_RXPROD2 +
+               VMXNET3_WRITE_BAR0_REG(adapter, (adapter->rx_prod2_offset +
                                (i * VMXNET3_REG_ALIGN)),
                                adapter->rx_queue[i].rx_ring[1].next2fill);
        }
@@ -2907,19 +3038,29 @@ static void
 vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
 {
        size_t sz, i, ring0_size, ring1_size, comp_size;
-       if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE -
-                                   VMXNET3_MAX_ETH_HDR_SIZE) {
-               adapter->skb_buf_size = adapter->netdev->mtu +
-                                       VMXNET3_MAX_ETH_HDR_SIZE;
-               if (adapter->skb_buf_size < VMXNET3_MIN_T0_BUF_SIZE)
-                       adapter->skb_buf_size = VMXNET3_MIN_T0_BUF_SIZE;
-
-               adapter->rx_buf_per_pkt = 1;
+       /* With version7 ring1 will have only T0 buffers */
+       if (!VMXNET3_VERSION_GE_7(adapter)) {
+               if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE -
+                                           VMXNET3_MAX_ETH_HDR_SIZE) {
+                       adapter->skb_buf_size = adapter->netdev->mtu +
+                                               VMXNET3_MAX_ETH_HDR_SIZE;
+                       if (adapter->skb_buf_size < VMXNET3_MIN_T0_BUF_SIZE)
+                               adapter->skb_buf_size = VMXNET3_MIN_T0_BUF_SIZE;
+
+                       adapter->rx_buf_per_pkt = 1;
+               } else {
+                       adapter->skb_buf_size = VMXNET3_MAX_SKB_BUF_SIZE;
+                       sz = adapter->netdev->mtu - VMXNET3_MAX_SKB_BUF_SIZE +
+                                                   VMXNET3_MAX_ETH_HDR_SIZE;
+                       adapter->rx_buf_per_pkt = 1 + (sz + PAGE_SIZE - 1) / PAGE_SIZE;
+               }
        } else {
-               adapter->skb_buf_size = VMXNET3_MAX_SKB_BUF_SIZE;
-               sz = adapter->netdev->mtu - VMXNET3_MAX_SKB_BUF_SIZE +
-                                           VMXNET3_MAX_ETH_HDR_SIZE;
-               adapter->rx_buf_per_pkt = 1 + (sz + PAGE_SIZE - 1) / PAGE_SIZE;
+               adapter->skb_buf_size = min((int)adapter->netdev->mtu + VMXNET3_MAX_ETH_HDR_SIZE,
+                                           VMXNET3_MAX_SKB_BUF_SIZE);
+               adapter->rx_buf_per_pkt = 1;
+               adapter->ringBufSize.ring1BufSizeType0 = cpu_to_le16(adapter->skb_buf_size);
+               adapter->ringBufSize.ring1BufSizeType1 = 0;
+               adapter->ringBufSize.ring2BufSizeType1 = cpu_to_le16(PAGE_SIZE);
        }
 
        /*
@@ -2935,6 +3076,11 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
        ring1_size = (ring1_size + sz - 1) / sz * sz;
        ring1_size = min_t(u32, ring1_size, VMXNET3_RX_RING2_MAX_SIZE /
                           sz * sz);
+       /* For v7 and later, keep ring size power of 2 for UPT */
+       if (VMXNET3_VERSION_GE_7(adapter)) {
+               ring0_size = rounddown_pow_of_two(ring0_size);
+               ring1_size = rounddown_pow_of_two(ring1_size);
+       }
        comp_size = ring0_size + ring1_size;
 
        for (i = 0; i < adapter->num_rx_queues; i++) {
@@ -3185,6 +3331,54 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter)
                        NETIF_F_GSO_UDP_TUNNEL_CSUM;
        }
 
+       if (VMXNET3_VERSION_GE_7(adapter)) {
+               unsigned long flags;
+
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_GENEVE_TSO)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_GENEVE_TSO;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_VXLAN_TSO)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_VXLAN_TSO;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD;
+               }
+
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DCR, adapter->dev_caps[0]);
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DCR0_REG);
+               adapter->dev_caps[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+
+               if (!(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_GENEVE_TSO)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_VXLAN_TSO))) {
+                       netdev->hw_enc_features &= ~NETIF_F_GSO_UDP_TUNNEL;
+                       netdev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL;
+               }
+               if (!(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD))) {
+                       netdev->hw_enc_features &= ~NETIF_F_GSO_UDP_TUNNEL_CSUM;
+                       netdev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL_CSUM;
+               }
+       }
+
        netdev->vlan_features = netdev->hw_features &
                                ~(NETIF_F_HW_VLAN_CTAG_TX |
                                  NETIF_F_HW_VLAN_CTAG_RX);
@@ -3472,7 +3666,12 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                goto err_alloc_pci;
 
        ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
-       if (ver & (1 << VMXNET3_REV_6)) {
+       if (ver & (1 << VMXNET3_REV_7)) {
+               VMXNET3_WRITE_BAR1_REG(adapter,
+                                      VMXNET3_REG_VRRS,
+                                      1 << VMXNET3_REV_7);
+               adapter->version = VMXNET3_REV_7 + 1;
+       } else if (ver & (1 << VMXNET3_REV_6)) {
                VMXNET3_WRITE_BAR1_REG(adapter,
                                       VMXNET3_REG_VRRS,
                                       1 << VMXNET3_REV_6);
@@ -3520,6 +3719,39 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                goto err_ver;
        }
 
+       if (VMXNET3_VERSION_GE_7(adapter)) {
+               adapter->devcap_supported[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_DCR);
+               adapter->ptcap_supported[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_PTCR);
+               if (adapter->devcap_supported[0] & (1UL << VMXNET3_CAP_LARGE_BAR)) {
+                       adapter->dev_caps[0] = adapter->devcap_supported[0] &
+                                                       (1UL << VMXNET3_CAP_LARGE_BAR);
+               }
+               if (!(adapter->ptcap_supported[0] & (1UL << VMXNET3_DCR_ERROR)) &&
+                   adapter->ptcap_supported[0] & (1UL << VMXNET3_CAP_OOORX_COMP) &&
+                   adapter->devcap_supported[0] & (1UL << VMXNET3_CAP_OOORX_COMP)) {
+                       adapter->dev_caps[0] |= adapter->devcap_supported[0] &
+                                               (1UL << VMXNET3_CAP_OOORX_COMP);
+               }
+               if (adapter->dev_caps[0])
+                       VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DCR, adapter->dev_caps[0]);
+
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DCR0_REG);
+               adapter->dev_caps[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+       }
+
+       if (VMXNET3_VERSION_GE_7(adapter) &&
+           adapter->dev_caps[0] & (1UL << VMXNET3_CAP_LARGE_BAR)) {
+               adapter->tx_prod_offset = VMXNET3_REG_LB_TXPROD;
+               adapter->rx_prod_offset = VMXNET3_REG_LB_RXPROD;
+               adapter->rx_prod2_offset = VMXNET3_REG_LB_RXPROD2;
+       } else {
+               adapter->tx_prod_offset = VMXNET3_REG_TXPROD;
+               adapter->rx_prod_offset = VMXNET3_REG_RXPROD;
+               adapter->rx_prod2_offset = VMXNET3_REG_RXPROD2;
+       }
+
        if (VMXNET3_VERSION_GE_6(adapter)) {
                spin_lock_irqsave(&adapter->cmd_lock, flags);
                VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
index 3172d46..c3eaf1b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Linux driver for VMware's vmxnet3 ethernet NIC.
  *
- * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2022, VMware, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -298,7 +298,7 @@ netdev_features_t vmxnet3_features_check(struct sk_buff *skb,
        return features;
 }
 
-static void vmxnet3_enable_encap_offloads(struct net_device *netdev)
+static void vmxnet3_enable_encap_offloads(struct net_device *netdev, netdev_features_t features)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 
@@ -306,8 +306,56 @@ static void vmxnet3_enable_encap_offloads(struct net_device *netdev)
                netdev->hw_enc_features |= NETIF_F_SG | NETIF_F_RXCSUM |
                        NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
                        NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_TSO | NETIF_F_TSO6 |
-                       NETIF_F_LRO | NETIF_F_GSO_UDP_TUNNEL |
-                       NETIF_F_GSO_UDP_TUNNEL_CSUM;
+                       NETIF_F_LRO;
+               if (features & NETIF_F_GSO_UDP_TUNNEL)
+                       netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
+               if (features & NETIF_F_GSO_UDP_TUNNEL_CSUM)
+                       netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
+       }
+       if (VMXNET3_VERSION_GE_7(adapter)) {
+               unsigned long flags;
+
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_GENEVE_TSO)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_GENEVE_TSO;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_VXLAN_TSO)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_VXLAN_TSO;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD;
+               }
+               if (vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                              VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD)) {
+                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD;
+               }
+
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DCR, adapter->dev_caps[0]);
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DCR0_REG);
+               adapter->dev_caps[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+
+               if (!(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_GENEVE_TSO)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_VXLAN_TSO))) {
+                       netdev->hw_enc_features &= ~NETIF_F_GSO_UDP_TUNNEL;
+               }
+               if (!(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD)) &&
+                   !(adapter->dev_caps[0] & (1UL << VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD))) {
+                       netdev->hw_enc_features &= ~NETIF_F_GSO_UDP_TUNNEL_CSUM;
+               }
        }
 }
 
@@ -322,6 +370,22 @@ static void vmxnet3_disable_encap_offloads(struct net_device *netdev)
                        NETIF_F_LRO | NETIF_F_GSO_UDP_TUNNEL |
                        NETIF_F_GSO_UDP_TUNNEL_CSUM);
        }
+       if (VMXNET3_VERSION_GE_7(adapter)) {
+               unsigned long flags;
+
+               adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_GENEVE_CHECKSUM_OFFLOAD |
+                                         1UL << VMXNET3_CAP_VXLAN_CHECKSUM_OFFLOAD  |
+                                         1UL << VMXNET3_CAP_GENEVE_TSO |
+                                         1UL << VMXNET3_CAP_VXLAN_TSO  |
+                                         1UL << VMXNET3_CAP_GENEVE_OUTER_CHECKSUM_OFFLOAD |
+                                         1UL << VMXNET3_CAP_VXLAN_OUTER_CHECKSUM_OFFLOAD);
+
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DCR, adapter->dev_caps[0]);
+               spin_lock_irqsave(&adapter->cmd_lock, flags);
+               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_DCR0_REG);
+               adapter->dev_caps[0] = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+       }
 }
 
 int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
@@ -357,8 +421,8 @@ int vmxnet3_set_features(struct net_device *netdev, netdev_features_t features)
                        adapter->shared->devRead.misc.uptFeatures &=
                        ~UPT1_F_RXVLAN;
 
-               if ((features & tun_offload_mask) != 0 && !udp_tun_enabled) {
-                       vmxnet3_enable_encap_offloads(netdev);
+               if ((features & tun_offload_mask) != 0) {
+                       vmxnet3_enable_encap_offloads(netdev, features);
                        adapter->shared->devRead.misc.uptFeatures |=
                        UPT1_F_RXINNEROFLD;
                } else if ((features & tun_offload_mask) == 0 &&
@@ -462,7 +526,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
        for (i = 0; i < adapter->num_tx_queues; i++) {
                struct vmxnet3_tx_queue *tq = &adapter->tx_queue[i];
 
-               buf[j++] = VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_TXPROD +
+               buf[j++] = VMXNET3_READ_BAR0_REG(adapter, adapter->tx_prod_offset +
                                                 i * VMXNET3_REG_ALIGN);
 
                buf[j++] = VMXNET3_GET_ADDR_LO(tq->tx_ring.basePA);
@@ -490,9 +554,9 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
        for (i = 0; i < adapter->num_rx_queues; i++) {
                struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
 
-               buf[j++] =  VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_RXPROD +
+               buf[j++] =  VMXNET3_READ_BAR0_REG(adapter, adapter->rx_prod_offset +
                                                  i * VMXNET3_REG_ALIGN);
-               buf[j++] =  VMXNET3_READ_BAR0_REG(adapter, VMXNET3_REG_RXPROD2 +
+               buf[j++] =  VMXNET3_READ_BAR0_REG(adapter, adapter->rx_prod2_offset +
                                                  i * VMXNET3_REG_ALIGN);
 
                buf[j++] = VMXNET3_GET_ADDR_LO(rq->rx_ring[0].basePA);
@@ -660,6 +724,13 @@ vmxnet3_set_ringparam(struct net_device *netdev,
        new_rx_ring2_size = min_t(u32, new_rx_ring2_size,
                                  VMXNET3_RX_RING2_MAX_SIZE);
 
+       /* For v7 and later, keep ring size power of 2 for UPT */
+       if (VMXNET3_VERSION_GE_7(adapter)) {
+               new_tx_ring_size = rounddown_pow_of_two(new_tx_ring_size);
+               new_rx_ring_size = rounddown_pow_of_two(new_rx_ring_size);
+               new_rx_ring2_size = rounddown_pow_of_two(new_rx_ring2_size);
+       }
+
        /* rx data ring buffer size has to be a multiple of
         * VMXNET3_RXDATA_DESC_SIZE_ALIGN
         */
@@ -913,6 +984,39 @@ vmxnet3_set_rss_hash_opt(struct net_device *netdev,
                        union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo;
                        unsigned long flags;
 
+                       if (VMXNET3_VERSION_GE_7(adapter)) {
+                               if ((rss_fields & VMXNET3_RSS_FIELDS_UDPIP4 ||
+                                    rss_fields & VMXNET3_RSS_FIELDS_UDPIP6) &&
+                                   vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                                              VMXNET3_CAP_UDP_RSS)) {
+                                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_UDP_RSS;
+                               } else {
+                                       adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_UDP_RSS);
+                               }
+                               if ((rss_fields & VMXNET3_RSS_FIELDS_ESPIP4) &&
+                                   vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                                              VMXNET3_CAP_ESP_RSS_IPV4)) {
+                                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_ESP_RSS_IPV4;
+                               } else {
+                                       adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_ESP_RSS_IPV4);
+                               }
+                               if ((rss_fields & VMXNET3_RSS_FIELDS_ESPIP6) &&
+                                   vmxnet3_check_ptcapability(adapter->ptcap_supported[0],
+                                                              VMXNET3_CAP_ESP_RSS_IPV6)) {
+                                       adapter->dev_caps[0] |= 1UL << VMXNET3_CAP_ESP_RSS_IPV6;
+                               } else {
+                                       adapter->dev_caps[0] &= ~(1UL << VMXNET3_CAP_ESP_RSS_IPV6);
+                               }
+
+                               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DCR,
+                                                      adapter->dev_caps[0]);
+                               spin_lock_irqsave(&adapter->cmd_lock, flags);
+                               VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+                                                      VMXNET3_CMD_GET_DCR0_REG);
+                               adapter->dev_caps[0] = VMXNET3_READ_BAR1_REG(adapter,
+                                                                            VMXNET3_REG_CMD);
+                               spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+                       }
                        spin_lock_irqsave(&adapter->cmd_lock, flags);
                        cmdInfo->setRssFields = rss_fields;
                        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
index 7027ff4..3367db2 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Linux driver for VMware's vmxnet3 ethernet NIC.
  *
- * Copyright (C) 2008-2021, VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2008-2022, VMware, Inc. All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.6.0.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.7.0.0-k"
 
 /* Each byte of this 32-bit integer encodes a version number in
  * VMXNET3_DRIVER_VERSION_STRING.
  */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01060000
+#define VMXNET3_DRIVER_VERSION_NUM      0x01070000
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
        #define VMXNET3_RSS
 #endif
 
+#define VMXNET3_REV_7          6       /* Vmxnet3 Rev. 7 */
 #define VMXNET3_REV_6          5       /* Vmxnet3 Rev. 6 */
 #define VMXNET3_REV_5          4       /* Vmxnet3 Rev. 5 */
 #define VMXNET3_REV_4          3       /* Vmxnet3 Rev. 4 */
@@ -135,6 +136,7 @@ struct vmxnet3_cmd_ring {
        u32             next2fill;
        u32             next2comp;
        u8              gen;
+       u8              isOutOfOrder;
        dma_addr_t      basePA;
 };
 
@@ -259,9 +261,13 @@ enum vmxnet3_rx_buf_type {
        VMXNET3_RX_BUF_PAGE = 2
 };
 
+#define VMXNET3_RXD_COMP_PENDING        0
+#define VMXNET3_RXD_COMP_DONE           1
+
 struct vmxnet3_rx_buf_info {
        enum vmxnet3_rx_buf_type buf_type;
        u16     len;
+       u8      comp_state;
        union {
                struct sk_buff *skb;
                struct page    *page;
@@ -402,6 +408,13 @@ struct vmxnet3_adapter {
        dma_addr_t pm_conf_pa;
        dma_addr_t rss_conf_pa;
        bool   queuesExtEnabled;
+       struct Vmxnet3_RingBufferSize     ringBufSize;
+       u32    devcap_supported[8];
+       u32    ptcap_supported[8];
+       u32    dev_caps[8];
+       u16    tx_prod_offset;
+       u16    rx_prod_offset;
+       u16    rx_prod2_offset;
 };
 
 #define VMXNET3_WRITE_BAR0_REG(adapter, reg, val)  \
@@ -431,11 +444,13 @@ struct vmxnet3_adapter {
        (adapter->version >= VMXNET3_REV_5 + 1)
 #define VMXNET3_VERSION_GE_6(adapter) \
        (adapter->version >= VMXNET3_REV_6 + 1)
+#define VMXNET3_VERSION_GE_7(adapter) \
+       (adapter->version >= VMXNET3_REV_7 + 1)
 
 /* must be a multiple of VMXNET3_RING_SIZE_ALIGN */
 #define VMXNET3_DEF_TX_RING_SIZE    512
 #define VMXNET3_DEF_RX_RING_SIZE    1024
-#define VMXNET3_DEF_RX_RING2_SIZE   256
+#define VMXNET3_DEF_RX_RING2_SIZE   512
 
 #define VMXNET3_DEF_RXDATA_DESC_SIZE 128
 
@@ -494,6 +509,7 @@ void vmxnet3_set_ethtool_ops(struct net_device *netdev);
 
 void vmxnet3_get_stats64(struct net_device *dev,
                         struct rtnl_link_stats64 *stats);
+bool vmxnet3_check_ptcapability(u32 cap_supported, u32 cap);
 
 extern char vmxnet3_driver_name[];
 #endif
index cfc30ce..40445a1 100644 (file)
@@ -814,8 +814,8 @@ static void vrf_rt6_release(struct net_device *dev, struct net_vrf *vrf)
         */
        if (rt6) {
                dst = &rt6->dst;
-               dev_replace_track(dst->dev, net->loopback_dev,
-                                 &dst->dev_tracker, GFP_KERNEL);
+               netdev_ref_replace(dst->dev, net->loopback_dev,
+                                  &dst->dev_tracker, GFP_KERNEL);
                dst->dev = net->loopback_dev;
                dst_release(dst);
        }
@@ -1061,8 +1061,8 @@ static void vrf_rtable_release(struct net_device *dev, struct net_vrf *vrf)
         */
        if (rth) {
                dst = &rth->dst;
-               dev_replace_track(dst->dev, net->loopback_dev,
-                                 &dst->dev_tracker, GFP_KERNEL);
+               netdev_ref_replace(dst->dev, net->loopback_dev,
+                                  &dst->dev_tracker, GFP_KERNEL);
                dst->dev = net->loopback_dev;
                dst_release(dst);
        }
index 265d4a0..8b0710b 100644 (file)
@@ -2385,15 +2385,15 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
                vxlan_snoop(dev, &loopback, eth_hdr(skb)->h_source, 0, vni);
 
        u64_stats_update_begin(&tx_stats->syncp);
-       tx_stats->tx_packets++;
-       tx_stats->tx_bytes += len;
+       u64_stats_inc(&tx_stats->tx_packets);
+       u64_stats_add(&tx_stats->tx_bytes, len);
        u64_stats_update_end(&tx_stats->syncp);
        vxlan_vnifilter_count(src_vxlan, vni, NULL, VXLAN_VNI_STATS_TX, len);
 
        if (__netif_rx(skb) == NET_RX_SUCCESS) {
                u64_stats_update_begin(&rx_stats->syncp);
-               rx_stats->rx_packets++;
-               rx_stats->rx_bytes += len;
+               u64_stats_inc(&rx_stats->rx_packets);
+               u64_stats_add(&rx_stats->rx_bytes, len);
                u64_stats_update_end(&rx_stats->syncp);
                vxlan_vnifilter_count(dst_vxlan, vni, NULL, VXLAN_VNI_STATS_RX,
                                      len);
index 5f43568..63908db 100644 (file)
@@ -43,7 +43,7 @@
  *      This version number is incremented with each official release of the
  *      package and is a simplified number for normal user reference.
  *      Individual files are tracked by the version control system and may
- *      have individual versions (or IDs) that move much faster than the
+ *      have individual versions (or IDs) that move much faster than
  *      the release version as individual updates are tracked.
  */
 #define FST_USER_VERSION        "1.04"
index 7b8df40..7135d51 100644 (file)
 /* Must be called with bh disabled. */
 static void update_rx_stats(struct wg_peer *peer, size_t len)
 {
-       struct pcpu_sw_netstats *tstats =
-               get_cpu_ptr(peer->device->dev->tstats);
-
-       u64_stats_update_begin(&tstats->syncp);
-       ++tstats->rx_packets;
-       tstats->rx_bytes += len;
+       dev_sw_netstats_rx_add(peer->device->dev, len);
        peer->rx_bytes += len;
-       u64_stats_update_end(&tstats->syncp);
-       put_cpu_ptr(tstats);
 }
 
 #define SKB_TYPE_LE32(skb) (((struct message_header *)(skb)->data)->type)
index 5704def..237cbd5 100644 (file)
@@ -1782,9 +1782,7 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif,
        }
 
        /* Header Length = MAC header len + IP header len + TCP header len*/
-       hdrlen = ETH_HLEN +
-               (int)skb_network_header_len(skb) +
-               tcp_hdrlen(skb);
+       hdrlen = skb_tcp_all_headers(skb);
 
        gso_type = skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV6 | SKB_GSO_TCPV4);
        switch (gso_type) {
index 2f746eb..bd408d2 100644 (file)
@@ -290,8 +290,7 @@ static inline int hwsim_net_set_netgroup(struct net *net)
 {
        struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
 
-       hwsim_net->netgroup = ida_simple_get(&hwsim_netgroup_ida,
-                                            0, 0, GFP_KERNEL);
+       hwsim_net->netgroup = ida_alloc(&hwsim_netgroup_ida, GFP_KERNEL);
        return hwsim_net->netgroup >= 0 ? 0 : -ENOMEM;
 }
 
@@ -4733,7 +4732,7 @@ static void __net_exit hwsim_exit_net(struct net *net)
                                         NULL);
        }
 
-       ida_simple_remove(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net));
+       ida_free(&hwsim_netgroup_ida, hwsim_net_get_netgroup(net));
 }
 
 static struct pernet_operations hwsim_net_ops = {
index 8d8378b..1ac4684 100644 (file)
 static const struct ieee80211_txrx_stypes
        wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_STATION] = {
-               .tx = 0xffff,
+               .tx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4),
                .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
-                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+                       BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                       BIT(IEEE80211_STYPE_AUTH >> 4)
        },
        [NL80211_IFTYPE_AP] = {
                .tx = 0xffff,
@@ -305,6 +307,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
        int ret;
        u32 i;
        u8 security = WILC_FW_SEC_NO;
+       enum mfptype mfp_type = WILC_FW_MFP_NONE;
        enum authtype auth_type = WILC_FW_AUTH_ANY;
        u32 cipher_group;
        struct cfg80211_bss *bss;
@@ -313,32 +316,9 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
 
        vif->connecting = true;
 
-       memset(priv->wep_key, 0, sizeof(priv->wep_key));
-       memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
-
        cipher_group = sme->crypto.cipher_group;
        if (cipher_group != 0) {
-               if (cipher_group == WLAN_CIPHER_SUITE_WEP40) {
-                       security = WILC_FW_SEC_WEP;
-
-                       priv->wep_key_len[sme->key_idx] = sme->key_len;
-                       memcpy(priv->wep_key[sme->key_idx], sme->key,
-                              sme->key_len);
-
-                       wilc_set_wep_default_keyid(vif, sme->key_idx);
-                       wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
-                                                sme->key_idx);
-               } else if (cipher_group == WLAN_CIPHER_SUITE_WEP104) {
-                       security = WILC_FW_SEC_WEP_EXTENDED;
-
-                       priv->wep_key_len[sme->key_idx] = sme->key_len;
-                       memcpy(priv->wep_key[sme->key_idx], sme->key,
-                              sme->key_len);
-
-                       wilc_set_wep_default_keyid(vif, sme->key_idx);
-                       wilc_add_wep_key_bss_sta(vif, sme->key, sme->key_len,
-                                                sme->key_idx);
-               } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
+               if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) {
                        if (cipher_group == WLAN_CIPHER_SUITE_TKIP)
                                security = WILC_FW_SEC_WPA2_TKIP;
                        else
@@ -373,8 +353,14 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
                auth_type = WILC_FW_AUTH_OPEN_SYSTEM;
                break;
 
-       case NL80211_AUTHTYPE_SHARED_KEY:
-               auth_type = WILC_FW_AUTH_SHARED_KEY;
+       case NL80211_AUTHTYPE_SAE:
+               auth_type = WILC_FW_AUTH_SAE;
+               if (sme->ssid_len) {
+                       memcpy(vif->auth.ssid.ssid, sme->ssid, sme->ssid_len);
+                       vif->auth.ssid.ssid_len = sme->ssid_len;
+               }
+               vif->auth.key_mgmt_suite = cpu_to_be32(sme->crypto.akm_suites[0]);
+               ether_addr_copy(vif->auth.bssid, sme->bssid);
                break;
 
        default:
@@ -384,6 +370,10 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
        if (sme->crypto.n_akm_suites) {
                if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X)
                        auth_type = WILC_FW_AUTH_IEEE8021;
+               else if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_PSK_SHA256)
+                       auth_type = WILC_FW_AUTH_OPEN_SYSTEM_SHA256;
+               else if (sme->crypto.akm_suites[0] == WLAN_AKM_SUITE_8021X_SHA256)
+                       auth_type = WILC_FW_AUTH_IEE8021X_SHA256;
        }
 
        if (wfi_drv->usr_scan_req.scan_result) {
@@ -427,6 +417,13 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
        wfi_drv->conn_info.arg = priv;
        wfi_drv->conn_info.param = join_params;
 
+       if (sme->mfp == NL80211_MFP_OPTIONAL)
+               mfp_type = WILC_FW_MFP_OPTIONAL;
+       else if (sme->mfp == NL80211_MFP_REQUIRED)
+               mfp_type = WILC_FW_MFP_REQUIRED;
+
+       wfi_drv->conn_info.mfp_type = mfp_type;
+
        ret = wilc_set_join_req(vif, bss->bssid, sme->ie, sme->ie_len);
        if (ret) {
                netdev_err(dev, "wilc_set_join_req(): Error\n");
@@ -487,14 +484,6 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
-static inline void wilc_wfi_cfg_copy_wep_info(struct wilc_priv *priv,
-                                             u8 key_index,
-                                             struct key_params *params)
-{
-       priv->wep_key_len[key_index] = params->key_len;
-       memcpy(priv->wep_key[key_index], params->key, params->key_len);
-}
-
 static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
 {
        if (!priv->wilc_gtk[idx]) {
@@ -514,6 +503,18 @@ static int wilc_wfi_cfg_allocate_wpa_entry(struct wilc_priv *priv, u8 idx)
        return 0;
 }
 
+static int wilc_wfi_cfg_allocate_wpa_igtk_entry(struct wilc_priv *priv, u8 idx)
+{
+       idx -= 4;
+       if (!priv->wilc_igtk[idx]) {
+               priv->wilc_igtk[idx] = kzalloc(sizeof(*priv->wilc_igtk[idx]),
+                                              GFP_KERNEL);
+               if (!priv->wilc_igtk[idx])
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
 static int wilc_wfi_cfg_copy_wpa_info(struct wilc_wfi_key *key_info,
                                      struct key_params *params)
 {
@@ -550,35 +551,9 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
        u8 op_mode;
        struct wilc_vif *vif = netdev_priv(netdev);
        struct wilc_priv *priv = &vif->priv;
+       struct wilc_wfi_key *key;
 
        switch (params->cipher) {
-       case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               if (priv->wdev.iftype == NL80211_IFTYPE_AP) {
-                       wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
-
-                       if (params->cipher == WLAN_CIPHER_SUITE_WEP40)
-                               mode = WILC_FW_SEC_WEP;
-                       else
-                               mode = WILC_FW_SEC_WEP_EXTENDED;
-
-                       ret = wilc_add_wep_key_bss_ap(vif, params->key,
-                                                     params->key_len,
-                                                     key_index, mode,
-                                                     WILC_FW_AUTH_OPEN_SYSTEM);
-                       break;
-               }
-               if (memcmp(params->key, priv->wep_key[key_index],
-                          params->key_len)) {
-                       wilc_wfi_cfg_copy_wep_info(priv, key_index, params);
-
-                       ret = wilc_add_wep_key_bss_sta(vif, params->key,
-                                                      params->key_len,
-                                                      key_index);
-               }
-
-               break;
-
        case WLAN_CIPHER_SUITE_TKIP:
        case WLAN_CIPHER_SUITE_CCMP:
                if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
@@ -640,6 +615,26 @@ static int add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
                                           key_index);
 
                break;
+       case WLAN_CIPHER_SUITE_AES_CMAC:
+               ret = wilc_wfi_cfg_allocate_wpa_igtk_entry(priv, key_index);
+               if (ret)
+                       return -ENOMEM;
+
+               key = priv->wilc_igtk[key_index - 4];
+               ret = wilc_wfi_cfg_copy_wpa_info(key, params);
+               if (ret)
+                       return -ENOMEM;
+
+               if (priv->wdev.iftype == NL80211_IFTYPE_AP ||
+                   priv->wdev.iftype == NL80211_IFTYPE_P2P_GO)
+                       op_mode = WILC_AP_MODE;
+               else
+                       op_mode = WILC_STATION_MODE;
+
+               ret = wilc_add_igtk(vif, params->key, keylen, params->seq,
+                                   params->seq_len, mac_addr, op_mode,
+                                   key_index);
+               break;
 
        default:
                netdev_err(netdev, "%s: Unsupported cipher\n", __func__);
@@ -657,30 +652,34 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev,
        struct wilc_vif *vif = netdev_priv(netdev);
        struct wilc_priv *priv = &vif->priv;
 
-       if (priv->wilc_gtk[key_index]) {
-               kfree(priv->wilc_gtk[key_index]->key);
-               priv->wilc_gtk[key_index]->key = NULL;
-               kfree(priv->wilc_gtk[key_index]->seq);
-               priv->wilc_gtk[key_index]->seq = NULL;
-
-               kfree(priv->wilc_gtk[key_index]);
-               priv->wilc_gtk[key_index] = NULL;
-       }
-
-       if (priv->wilc_ptk[key_index]) {
-               kfree(priv->wilc_ptk[key_index]->key);
-               priv->wilc_ptk[key_index]->key = NULL;
-               kfree(priv->wilc_ptk[key_index]->seq);
-               priv->wilc_ptk[key_index]->seq = NULL;
-               kfree(priv->wilc_ptk[key_index]);
-               priv->wilc_ptk[key_index] = NULL;
-       }
-
-       if (key_index <= 3 && priv->wep_key_len[key_index]) {
-               memset(priv->wep_key[key_index], 0,
-                      priv->wep_key_len[key_index]);
-               priv->wep_key_len[key_index] = 0;
-               wilc_remove_wep_key(vif, key_index);
+       if (!pairwise && (key_index == 4 || key_index == 5)) {
+               key_index -= 4;
+               if (priv->wilc_igtk[key_index]) {
+                       kfree(priv->wilc_igtk[key_index]->key);
+                       priv->wilc_igtk[key_index]->key = NULL;
+                       kfree(priv->wilc_igtk[key_index]->seq);
+                       priv->wilc_igtk[key_index]->seq = NULL;
+                       kfree(priv->wilc_igtk[key_index]);
+                       priv->wilc_igtk[key_index] = NULL;
+               }
+       } else {
+               if (priv->wilc_gtk[key_index]) {
+                       kfree(priv->wilc_gtk[key_index]->key);
+                       priv->wilc_gtk[key_index]->key = NULL;
+                       kfree(priv->wilc_gtk[key_index]->seq);
+                       priv->wilc_gtk[key_index]->seq = NULL;
+
+                       kfree(priv->wilc_gtk[key_index]);
+                       priv->wilc_gtk[key_index] = NULL;
+               }
+               if (priv->wilc_ptk[key_index]) {
+                       kfree(priv->wilc_ptk[key_index]->key);
+                       priv->wilc_ptk[key_index]->key = NULL;
+                       kfree(priv->wilc_ptk[key_index]->seq);
+                       priv->wilc_ptk[key_index]->seq = NULL;
+                       kfree(priv->wilc_ptk[key_index]);
+                       priv->wilc_ptk[key_index] = NULL;
+               }
        }
 
        return 0;
@@ -695,11 +694,20 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
        struct  key_params key_params;
 
        if (!pairwise) {
-               key_params.key = priv->wilc_gtk[key_index]->key;
-               key_params.cipher = priv->wilc_gtk[key_index]->cipher;
-               key_params.key_len = priv->wilc_gtk[key_index]->key_len;
-               key_params.seq = priv->wilc_gtk[key_index]->seq;
-               key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
+               if (key_index == 4 || key_index == 5) {
+                       key_index -= 4;
+                       key_params.key = priv->wilc_igtk[key_index]->key;
+                       key_params.cipher = priv->wilc_igtk[key_index]->cipher;
+                       key_params.key_len = priv->wilc_igtk[key_index]->key_len;
+                       key_params.seq = priv->wilc_igtk[key_index]->seq;
+                       key_params.seq_len = priv->wilc_igtk[key_index]->seq_len;
+               } else {
+                       key_params.key = priv->wilc_gtk[key_index]->key;
+                       key_params.cipher = priv->wilc_gtk[key_index]->cipher;
+                       key_params.key_len = priv->wilc_gtk[key_index]->key_len;
+                       key_params.seq = priv->wilc_gtk[key_index]->seq;
+                       key_params.seq_len = priv->wilc_gtk[key_index]->seq_len;
+               }
        } else {
                key_params.key = priv->wilc_ptk[key_index]->key;
                key_params.cipher = priv->wilc_ptk[key_index]->cipher;
@@ -713,14 +721,19 @@ static int get_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index,
        return 0;
 }
 
+/* wiphy_new_nm() will WARNON if not present */
 static int set_default_key(struct wiphy *wiphy, struct net_device *netdev,
                           u8 key_index, bool unicast, bool multicast)
 {
-       struct wilc_vif *vif = netdev_priv(netdev);
+       return 0;
+}
 
-       wilc_set_wep_default_keyid(vif, key_index);
+static int set_default_mgmt_key(struct wiphy *wiphy, struct net_device *netdev,
+                               u8 key_index)
+{
+       struct wilc_vif *vif = netdev_priv(netdev);
 
-       return 0;
+       return wilc_set_default_mgmt_key_index(vif, key_index);
 }
 
 static int get_station(struct wiphy *wiphy, struct net_device *dev,
@@ -977,6 +990,18 @@ static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
        }
 }
 
+bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size)
+{
+       struct wilc *wl = vif->wilc;
+       struct wilc_priv *priv = &vif->priv;
+       int freq, ret;
+
+       freq = ieee80211_channel_to_frequency(wl->op_ch, NL80211_BAND_2GHZ);
+       ret = cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
+
+       return ret;
+}
+
 void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
 {
        struct wilc *wl = vif->wilc;
@@ -1162,8 +1187,14 @@ static int mgmt_tx(struct wiphy *wiphy,
                goto out_txq_add_pkt;
        }
 
-       if (!ieee80211_is_public_action((struct ieee80211_hdr *)buf, len))
+       if (!ieee80211_is_public_action((struct ieee80211_hdr *)buf, len)) {
+               if (chan)
+                       wilc_set_mac_chnl_num(vif, chan->hw_value);
+               else
+                       wilc_set_mac_chnl_num(vif, vif->wilc->op_ch);
+
                goto out_set_timeout;
+       }
 
        d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
        if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
@@ -1230,6 +1261,7 @@ void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
        struct wilc_vif *vif = netdev_priv(wdev->netdev);
        u32 presp_bit = BIT(IEEE80211_STYPE_PROBE_REQ >> 4);
        u32 action_bit = BIT(IEEE80211_STYPE_ACTION >> 4);
+       u32 pauth_bit = BIT(IEEE80211_STYPE_AUTH >> 4);
 
        if (wl->initialized) {
                bool prev = vif->mgmt_reg_stypes & presp_bit;
@@ -1243,10 +1275,26 @@ void wilc_update_mgmt_frame_registrations(struct wiphy *wiphy,
 
                if (now != prev)
                        wilc_frame_register(vif, IEEE80211_STYPE_ACTION, now);
+
+               prev = vif->mgmt_reg_stypes & pauth_bit;
+               now = upd->interface_stypes & pauth_bit;
+               if (now != prev)
+                       wilc_frame_register(vif, IEEE80211_STYPE_AUTH, now);
        }
 
        vif->mgmt_reg_stypes =
-               upd->interface_stypes & (presp_bit | action_bit);
+               upd->interface_stypes & (presp_bit | action_bit | pauth_bit);
+}
+
+static int external_auth(struct wiphy *wiphy, struct net_device *dev,
+                        struct cfg80211_external_auth_params *auth)
+{
+       struct wilc_vif *vif = netdev_priv(dev);
+
+       if (auth->status == WLAN_STATUS_SUCCESS)
+               wilc_set_external_auth_param(vif, auth);
+
+       return 0;
 }
 
 static int set_cqm_rssi_config(struct wiphy *wiphy, struct net_device *dev,
@@ -1647,6 +1695,7 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
        .del_key = del_key,
        .get_key = get_key,
        .set_default_key = set_default_key,
+       .set_default_mgmt_key = set_default_mgmt_key,
        .add_virtual_intf = add_virtual_intf,
        .del_virtual_intf = del_virtual_intf,
        .change_virtual_intf = change_virtual_intf,
@@ -1662,6 +1711,7 @@ static const struct cfg80211_ops wilc_cfg80211_ops = {
        .change_bss = change_bss,
        .set_wiphy_params = set_wiphy_params,
 
+       .external_auth = external_auth,
        .set_pmksa = set_pmksa,
        .del_pmksa = del_pmksa,
        .flush_pmksa = flush_pmksa,
@@ -1804,7 +1854,7 @@ struct wilc *wilc_create_wiphy(struct device *dev)
                                BIT(NL80211_IFTYPE_P2P_GO) |
                                BIT(NL80211_IFTYPE_P2P_CLIENT);
        wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
-
+       wiphy->features |= NL80211_FEATURE_SAE;
        set_wiphy_dev(wiphy, dev);
        wl->wiphy = wiphy;
        ret = wiphy_register(wiphy);
index 1114530..5c5cac4 100644 (file)
@@ -41,21 +41,23 @@ struct wilc_drv_handler {
        u8 mode;
 } __packed;
 
-struct wilc_wep_key {
-       u8 index;
+struct wilc_sta_wpa_ptk {
+       u8 mac_addr[ETH_ALEN];
        u8 key_len;
        u8 key[];
 } __packed;
 
-struct wilc_sta_wpa_ptk {
+struct wilc_ap_wpa_ptk {
        u8 mac_addr[ETH_ALEN];
+       u8 index;
        u8 key_len;
        u8 key[];
 } __packed;
 
-struct wilc_ap_wpa_ptk {
-       u8 mac_addr[ETH_ALEN];
+struct wilc_wpa_igtk {
        u8 index;
+       u8 pn_len;
+       u8 pn[6];
        u8 key_len;
        u8 key[];
 } __packed;
@@ -116,4 +118,13 @@ struct wilc_join_bss_param {
                struct wilc_noa_opp_enable opp_en;
        };
 } __packed;
+
+struct wilc_external_auth_param {
+       u8 action;
+       u8 bssid[ETH_ALEN];
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       u8 ssid_len;
+       __le32 key_mgmt_suites;
+       __le16 status;
+} __packed;
 #endif
index 71b44cf..4038a25 100644 (file)
@@ -271,12 +271,19 @@ error:
 static int wilc_send_connect_wid(struct wilc_vif *vif)
 {
        int result = 0;
-       struct wid wid_list[4];
+       struct wid wid_list[5];
        u32 wid_cnt = 0;
        struct host_if_drv *hif_drv = vif->hif_drv;
        struct wilc_conn_info *conn_attr = &hif_drv->conn_info;
        struct wilc_join_bss_param *bss_param = conn_attr->param;
 
+
+        wid_list[wid_cnt].id = WID_SET_MFP;
+        wid_list[wid_cnt].type = WID_CHAR;
+        wid_list[wid_cnt].size = sizeof(char);
+        wid_list[wid_cnt].val = (s8 *)&conn_attr->mfp_type;
+        wid_cnt++;
+
        wid_list[wid_cnt].id = WID_INFO_ELEMENT_ASSOCIATE;
        wid_list[wid_cnt].type = WID_BIN_DATA;
        wid_list[wid_cnt].val = conn_attr->req_ies;
@@ -306,7 +313,10 @@ static int wilc_send_connect_wid(struct wilc_vif *vif)
                netdev_err(vif->ndev, "failed to send config packet\n");
                goto error;
        } else {
-               hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
+                if (conn_attr->auth_type == WILC_FW_AUTH_SAE)
+                        hif_drv->hif_state = HOST_IF_EXTERNAL_AUTH;
+                else
+                        hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
        }
 
        return 0;
@@ -665,7 +675,12 @@ static void handle_rcvd_gnrl_async_info(struct work_struct *work)
                goto free_msg;
        }
 
-       if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
+
+        if (hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH) {
+                cfg80211_external_auth_request(vif->ndev, &vif->auth,
+                                              GFP_KERNEL);
+                hif_drv->hif_state = HOST_IF_WAITING_CONN_RESP;
+        } else if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP) {
                host_int_parse_assoc_resp_info(vif, mac_info->status);
        } else if (mac_info->status == WILC_MAC_STATUS_DISCONNECTED) {
                if (hif_drv->hif_state == HOST_IF_CONNECTED) {
@@ -710,7 +725,8 @@ int wilc_disconnect(struct wilc_vif *vif)
        }
 
        if (conn_info->conn_result) {
-               if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP)
+               if (hif_drv->hif_state == HOST_IF_WAITING_CONN_RESP ||
+                   hif_drv->hif_state == HOST_IF_EXTERNAL_AUTH)
                        del_timer(&hif_drv->connect_timer);
 
                conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
@@ -986,6 +1002,31 @@ void wilc_set_wowlan_trigger(struct wilc_vif *vif, bool enabled)
                pr_err("Failed to send wowlan trigger config packet\n");
 }
 
+int wilc_set_external_auth_param(struct wilc_vif *vif,
+                                struct cfg80211_external_auth_params *auth)
+{
+       int ret;
+       struct wid wid;
+       struct wilc_external_auth_param *param;
+
+       wid.id = WID_EXTERNAL_AUTH_PARAM;
+       wid.type = WID_BIN_DATA;
+       wid.size = sizeof(*param);
+       param = kzalloc(sizeof(*param), GFP_KERNEL);
+       if (!param)
+               return -EINVAL;
+
+       wid.val = (u8 *)param;
+       param->action = auth->action;
+       ether_addr_copy(param->bssid, auth->bssid);
+       memcpy(param->ssid, auth->ssid.ssid, auth->ssid.ssid_len);
+       param->ssid_len = auth->ssid.ssid_len;
+       ret = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+
+       kfree(param);
+       return ret;
+}
+
 static void handle_scan_timer(struct work_struct *work)
 {
        struct host_if_msg *msg = container_of(work, struct host_if_msg, work);
@@ -1038,108 +1079,6 @@ static void timer_connect_cb(struct timer_list *t)
                kfree(msg);
 }
 
-int wilc_remove_wep_key(struct wilc_vif *vif, u8 index)
-{
-       struct wid wid;
-       int result;
-
-       wid.id = WID_REMOVE_WEP_KEY;
-       wid.type = WID_STR;
-       wid.size = sizeof(char);
-       wid.val = &index;
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to send remove wep key config packet\n");
-       return result;
-}
-
-int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index)
-{
-       struct wid wid;
-       int result;
-
-       wid.id = WID_KEY_ID;
-       wid.type = WID_CHAR;
-       wid.size = sizeof(char);
-       wid.val = &index;
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to send wep default key config packet\n");
-
-       return result;
-}
-
-int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
-                            u8 index)
-{
-       struct wid wid;
-       int result;
-       struct wilc_wep_key *wep_key;
-
-       wid.id = WID_ADD_WEP_KEY;
-       wid.type = WID_STR;
-       wid.size = sizeof(*wep_key) + len;
-       wep_key = kzalloc(wid.size, GFP_KERNEL);
-       if (!wep_key)
-               return -ENOMEM;
-
-       wid.val = (u8 *)wep_key;
-
-       wep_key->index = index;
-       wep_key->key_len = len;
-       memcpy(wep_key->key, key, len);
-
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to add wep key config packet\n");
-
-       kfree(wep_key);
-       return result;
-}
-
-int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
-                           u8 index, u8 mode, enum authtype auth_type)
-{
-       struct wid wid_list[3];
-       int result;
-       struct wilc_wep_key *wep_key;
-
-       wid_list[0].id = WID_11I_MODE;
-       wid_list[0].type = WID_CHAR;
-       wid_list[0].size = sizeof(char);
-       wid_list[0].val = &mode;
-
-       wid_list[1].id = WID_AUTH_TYPE;
-       wid_list[1].type = WID_CHAR;
-       wid_list[1].size = sizeof(char);
-       wid_list[1].val = (s8 *)&auth_type;
-
-       wid_list[2].id = WID_WEP_KEY_VALUE;
-       wid_list[2].type = WID_STR;
-       wid_list[2].size = sizeof(*wep_key) + len;
-       wep_key = kzalloc(wid_list[2].size, GFP_KERNEL);
-       if (!wep_key)
-               return -ENOMEM;
-
-       wid_list[2].val = (u8 *)wep_key;
-
-       wep_key->index = index;
-       wep_key->key_len = len;
-       memcpy(wep_key->key, key, len);
-       result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list,
-                                     ARRAY_SIZE(wid_list));
-       if (result)
-               netdev_err(vif->ndev,
-                          "Failed to add wep ap key config packet\n");
-
-       kfree(wep_key);
-       return result;
-}
-
 int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
                 const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
                 u8 mode, u8 cipher_mode, u8 index)
@@ -1211,6 +1150,36 @@ int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
        return result;
 }
 
+int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,
+                 const u8 *pn, u8 pn_len, const u8 *mac_addr, u8 mode, u8 index)
+{
+       int result = 0;
+       u8 t_key_len = igtk_key_len;
+       struct wid wid;
+       struct wilc_wpa_igtk *key_buf;
+
+       key_buf = kzalloc(sizeof(*key_buf) + t_key_len, GFP_KERNEL);
+       if (!key_buf)
+               return -ENOMEM;
+
+       key_buf->index = index;
+
+       memcpy(&key_buf->pn[0], pn, pn_len);
+       key_buf->pn_len = pn_len;
+
+       memcpy(&key_buf->key[0], igtk, igtk_key_len);
+       key_buf->key_len = t_key_len;
+
+       wid.id = WID_ADD_IGTK;
+       wid.type = WID_STR;
+       wid.size = sizeof(*key_buf) + t_key_len;
+       wid.val = (s8 *)key_buf;
+       result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+       kfree(key_buf);
+
+       return result;
+}
+
 int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
                    u8 index, u32 key_rsc_len, const u8 *key_rsc,
                    const u8 *rx_mic, const u8 *tx_mic, u8 mode,
@@ -1749,6 +1718,10 @@ void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg)
                reg_frame.reg_id = WILC_FW_PROBE_REQ_IDX;
                break;
 
+        case IEEE80211_STYPE_AUTH:
+                reg_frame.reg_id = WILC_FW_AUTH_REQ_IDX;
+                break;
+
        default:
                break;
        }
@@ -1996,3 +1969,20 @@ int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power)
 
        return wilc_send_config_pkt(vif, WILC_GET_CFG, &wid, 1);
 }
+
+int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index)
+{
+        struct wid wid;
+        int result;
+
+        wid.id = WID_DEFAULT_MGMT_KEY_ID;
+        wid.type = WID_CHAR;
+        wid.size = sizeof(char);
+        wid.val = &index;
+        result = wilc_send_config_pkt(vif, WILC_SET_CFG, &wid, 1);
+        if (result)
+                netdev_err(vif->ndev,
+                           "Failed to send default mgmt key index\n");
+
+        return result;
+}
index 77616fc..d8dd94d 100644 (file)
@@ -47,6 +47,7 @@ enum host_if_state {
        HOST_IF_WAITING_CONN_RESP       = 3,
        HOST_IF_CONNECTED               = 4,
        HOST_IF_P2P_LISTEN              = 5,
+       HOST_IF_EXTERNAL_AUTH           = 6,
        HOST_IF_FORCE_32BIT             = 0xFFFFFFFF
 };
 
@@ -107,6 +108,7 @@ struct wilc_conn_info {
        u8 bssid[ETH_ALEN];
        u8 security;
        enum authtype auth_type;
+       enum mfptype mfp_type;
        u8 ch;
        u8 *req_ies;
        size_t req_ies_len;
@@ -151,15 +153,12 @@ struct host_if_drv {
 };
 
 struct wilc_vif;
-int wilc_remove_wep_key(struct wilc_vif *vif, u8 index);
-int wilc_set_wep_default_keyid(struct wilc_vif *vif, u8 index);
-int wilc_add_wep_key_bss_sta(struct wilc_vif *vif, const u8 *key, u8 len,
-                            u8 index);
-int wilc_add_wep_key_bss_ap(struct wilc_vif *vif, const u8 *key, u8 len,
-                           u8 index, u8 mode, enum authtype auth_type);
 int wilc_add_ptk(struct wilc_vif *vif, const u8 *ptk, u8 ptk_key_len,
                 const u8 *mac_addr, const u8 *rx_mic, const u8 *tx_mic,
                 u8 mode, u8 cipher_mode, u8 index);
+int wilc_add_igtk(struct wilc_vif *vif, const u8 *igtk, u8 igtk_key_len,
+                 const u8 *pn, u8 pn_len, const u8 *mac_addr, u8 mode,
+                 u8 index);
 s32 wilc_get_inactive_time(struct wilc_vif *vif, const u8 *mac,
                           u32 *out_val);
 int wilc_add_rx_gtk(struct wilc_vif *vif, const u8 *rx_gtk, u8 gtk_key_len,
@@ -208,9 +207,12 @@ int wilc_get_vif_idx(struct wilc_vif *vif);
 int wilc_set_tx_power(struct wilc_vif *vif, u8 tx_power);
 int wilc_get_tx_power(struct wilc_vif *vif, u8 *tx_power);
 void wilc_set_wowlan_trigger(struct wilc_vif *vif, bool enabled);
+int wilc_set_external_auth_param(struct wilc_vif *vif,
+                                struct cfg80211_external_auth_params *param);
 void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length);
 void wilc_network_info_received(struct wilc *wilc, u8 *buffer, u32 length);
 void wilc_gnrl_async_info_received(struct wilc *wilc, u8 *buffer, u32 length);
 void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
                                struct cfg80211_crypto_settings *crypto);
+int wilc_set_default_mgmt_key_index(struct wilc_vif *vif, u8 index);
 #endif
index 3c292e3..fcc4e61 100644 (file)
@@ -835,15 +835,24 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size,
        }
 }
 
-void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size, bool is_auth)
 {
        int srcu_idx;
        struct wilc_vif *vif;
 
        srcu_idx = srcu_read_lock(&wilc->srcu);
        list_for_each_entry_rcu(vif, &wilc->vif_list, list) {
+               struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buff;
                u16 type = le16_to_cpup((__le16 *)buff);
                u32 type_bit = BIT(type >> 4);
+               u32 auth_bit = BIT(IEEE80211_STYPE_AUTH >> 4);
+
+               if ((vif->mgmt_reg_stypes & auth_bit &&
+                    ieee80211_is_auth(mgmt->frame_control)) &&
+                   vif->iftype == WILC_STATION_MODE && is_auth) {
+                       wilc_wfi_mgmt_frame_rx(vif, buff, size);
+                       break;
+               }
 
                if (vif->priv.p2p_listen_state &&
                    vif->mgmt_reg_stypes & type_bit)
index a067274..822e65d 100644 (file)
@@ -45,12 +45,6 @@ struct wilc_wfi_key {
        u32 cipher;
 };
 
-struct wilc_wfi_wep_key {
-       u8 *key;
-       u8 key_len;
-       u8 key_idx;
-};
-
 struct sta_info {
        u8 sta_associated_bss[WILC_MAX_NUM_STA][ETH_ALEN];
 };
@@ -63,8 +57,6 @@ struct wilc_wfi_p2p_listen_params {
 };
 
 static const u32 wilc_cipher_suites[] = {
-       WLAN_CIPHER_SUITE_WEP40,
-       WLAN_CIPHER_SUITE_WEP104,
        WLAN_CIPHER_SUITE_TKIP,
        WLAN_CIPHER_SUITE_CCMP,
        WLAN_CIPHER_SUITE_AES_CMAC
@@ -132,13 +124,12 @@ struct wilc_priv {
        struct net_device *dev;
        struct host_if_drv *hif_drv;
        struct wilc_pmkid_attr pmkid_list;
-       u8 wep_key[4][WLAN_KEY_LEN_WEP104];
-       u8 wep_key_len[4];
 
        /* The real interface that the monitor is on */
        struct net_device *real_ndev;
        struct wilc_wfi_key *wilc_gtk[WILC_MAX_NUM_STA];
        struct wilc_wfi_key *wilc_ptk[WILC_MAX_NUM_STA];
+       struct wilc_wfi_key *wilc_igtk[2];
        u8 wilc_groupkey;
 
        /* mutexes */
@@ -195,6 +186,7 @@ struct wilc_vif {
        struct wilc_priv priv;
        struct list_head list;
        struct cfg80211_bss *bss;
+       struct cfg80211_external_auth_params auth;
 };
 
 struct wilc_tx_queue_status {
@@ -288,7 +280,7 @@ struct wilc_wfi_mon_priv {
 void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, u32 pkt_offset);
 void wilc_mac_indicate(struct wilc *wilc);
 void wilc_netdev_cleanup(struct wilc *wilc);
-void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size);
+void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size, bool is_auth);
 void wilc_wlan_set_bssid(struct net_device *wilc_netdev, const u8 *bssid,
                         u8 mode);
 struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name,
index 18420e9..2ae8dd3 100644 (file)
@@ -191,11 +191,11 @@ static void wilc_wlan_power(struct wilc *wilc, bool on)
                /* assert ENABLE: */
                gpiod_set_value(gpios->enable, 1);
                mdelay(5);
-               /* deassert RESET: */
-               gpiod_set_value(gpios->reset, 0);
-       } else {
                /* assert RESET: */
                gpiod_set_value(gpios->reset, 1);
+       } else {
+               /* deassert RESET: */
+               gpiod_set_value(gpios->reset, 0);
                /* deassert ENABLE: */
                gpiod_set_value(gpios->enable, 0);
        }
index 48441f0..f3f504d 100644 (file)
@@ -968,7 +968,8 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
 
                if (pkt_offset & IS_MANAGMEMENT) {
                        buff_ptr += HOST_HDR_OFFSET;
-                       wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len);
+                       wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len,
+                                        pkt_offset & IS_MGMT_AUTH_PKT);
                } else {
                        if (!is_cfg_packet) {
                                wilc_frmw_to_host(wilc, buff_ptr, pkt_len,
index eb79781..b45e727 100644 (file)
 #define IS_MANAGMEMENT         0x100
 #define IS_MANAGMEMENT_CALLBACK        0x080
 #define IS_MGMT_STATUS_SUCCES  0x040
+#define IS_MGMT_AUTH_PKT       0x010
 
 #define WILC_WID_TYPE          GENMASK(15, 12)
 #define WILC_VMM_ENTRY_FULL_RETRY      1
@@ -423,6 +424,7 @@ int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc);
 netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *dev);
 
 void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size);
+bool wilc_wfi_mgmt_frame_rx(struct wilc_vif *vif, u8 *buff, u32 size);
 void host_wakeup_notify(struct wilc *wilc);
 void host_sleep_notify(struct wilc *wilc);
 void chip_allow_sleep(struct wilc *wilc);
index 6eb7eb4..df2f5a6 100644 (file)
@@ -85,7 +85,16 @@ enum authtype {
        WILC_FW_AUTH_OPEN_SYSTEM = 1,
        WILC_FW_AUTH_SHARED_KEY = 2,
        WILC_FW_AUTH_ANY = 3,
-       WILC_FW_AUTH_IEEE8021 = 5
+       WILC_FW_AUTH_IEEE8021 = 5,
+       WILC_FW_AUTH_SAE = 7,
+       WILC_FW_AUTH_IEE8021X_SHA256 = 9,
+       WILC_FW_AUTH_OPEN_SYSTEM_SHA256 = 13
+};
+
+enum mfptype {
+       WILC_FW_MFP_NONE = 0x0,
+       WILC_FW_MFP_OPTIONAL = 0x1,
+       WILC_FW_MFP_REQUIRED = 0x2
 };
 
 enum site_survey {
@@ -176,7 +185,8 @@ enum {
 
 enum {
        WILC_FW_ACTION_FRM_IDX = 0,
-       WILC_FW_PROBE_REQ_IDX = 1
+       WILC_FW_PROBE_REQ_IDX = 1,
+       WILC_FW_AUTH_REQ_IDX = 2
 };
 
 enum wid_type {
@@ -657,6 +667,9 @@ enum {
        WID_LOG_TERMINAL_SWITCH         = 0x00CD,
        WID_TX_POWER                    = 0x00CE,
        WID_WOWLAN_TRIGGER              = 0X00CF,
+       WID_SET_MFP                     = 0x00D0,
+
+       WID_DEFAULT_MGMT_KEY_ID         = 0x00D2,
        /*  EMAC Short WID list */
        /*  RTS Threshold */
        /*
@@ -746,6 +759,7 @@ enum {
        WID_REMOVE_KEY                  = 0x301E,
        WID_ASSOC_REQ_INFO              = 0x301F,
        WID_ASSOC_RES_INFO              = 0x3020,
+       WID_ADD_IGTK                    = 0x3022,
        WID_MANUFACTURER                = 0x3026, /* Added for CAPI tool */
        WID_MODEL_NAME                  = 0x3027, /* Added for CAPI tool */
        WID_MODEL_NUM                   = 0x3028, /* Added for CAPI tool */
@@ -789,7 +803,7 @@ enum {
        WID_ADD_BEACON                  = 0x408a,
 
        WID_SETUP_MULTICAST_FILTER      = 0x408b,
-
+       WID_EXTERNAL_AUTH_PARAM         = 0x408d,
        /* Miscellaneous WIDs */
        WID_ALL                         = 0x7FFE,
        WID_MAX                         = 0xFFFF
index 87e98ab..1f57a00 100644 (file)
@@ -1643,38 +1643,34 @@ static void authenticate_timeout(struct timer_list *t)
 /*===========================================================================*/
 static int parse_addr(char *in_str, UCHAR *out)
 {
+       int i, k;
        int len;
-       int i, j, k;
-       int status;
 
        if (in_str == NULL)
                return 0;
-       if ((len = strlen(in_str)) < 2)
+       len = strnlen(in_str, ADDRLEN * 2 + 1) - 1;
+       if (len < 1)
                return 0;
        memset(out, 0, ADDRLEN);
 
-       status = 1;
-       j = len - 1;
-       if (j > 12)
-               j = 12;
        i = 5;
 
-       while (j > 0) {
-               if ((k = hex_to_bin(in_str[j--])) != -1)
+       while (len > 0) {
+               if ((k = hex_to_bin(in_str[len--])) != -1)
                        out[i] = k;
                else
                        return 0;
 
-               if (j == 0)
+               if (len == 0)
                        break;
-               if ((k = hex_to_bin(in_str[j--])) != -1)
+               if ((k = hex_to_bin(in_str[len--])) != -1)
                        out[i] += k << 4;
                else
                        return 0;
                if (!i--)
                        break;
        }
-       return status;
+       return 1;
 }
 
 /*===========================================================================*/
index 901cdfe..0b1bc04 100644 (file)
@@ -329,8 +329,8 @@ static ssize_t rtl_debugfs_set_write_h2c(struct file *filp,
 
        tmp_len = (count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count);
 
-       if (!buffer || copy_from_user(tmp, buffer, tmp_len))
-               return count;
+       if (copy_from_user(tmp, buffer, tmp_len))
+               return -EFAULT;
 
        tmp[tmp_len] = '\0';
 
@@ -340,8 +340,8 @@ static ssize_t rtl_debugfs_set_write_h2c(struct file *filp,
                         &h2c_data[4], &h2c_data[5],
                         &h2c_data[6], &h2c_data[7]);
 
-       if (h2c_len <= 0)
-               return count;
+       if (h2c_len == 0)
+               return -EINVAL;
 
        for (i = 0; i < h2c_len; i++)
                h2c_data_packed[i] = (u8)h2c_data[i];
index 1a52ff5..7cde6bc 100644 (file)
@@ -269,11 +269,7 @@ static int rtw_debugfs_get_rsvd_page(struct seq_file *m, void *v)
        for (i = 0 ; i < buf_size ; i += 8) {
                if (i % page_size == 0)
                        seq_printf(m, "PAGE %d\n", (i + offset) / page_size);
-               seq_printf(m, "%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
-                          *(buf + i), *(buf + i + 1),
-                          *(buf + i + 2), *(buf + i + 3),
-                          *(buf + i + 4), *(buf + i + 5),
-                          *(buf + i + 6), *(buf + i + 7));
+               seq_printf(m, "%8ph\n", buf + i);
        }
        vfree(buf);
 
index efabd5b..a44b181 100644 (file)
@@ -1383,9 +1383,12 @@ void rtw_core_scan_start(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
 void rtw_core_scan_complete(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
                            bool hw_scan)
 {
-       struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv;
+       struct rtw_vif *rtwvif = vif ? (struct rtw_vif *)vif->drv_priv : NULL;
        u32 config = 0;
 
+       if (!rtwvif)
+               return;
+
        clear_bit(RTW_FLAG_SCANNING, rtwdev->flags);
        clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags);
 
index 93cce44..993bd6b 100644 (file)
@@ -2701,7 +2701,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8723d[] = {
        {0x953, BIT(1), RTW_REG_DOMAIN_MAC8},
 };
 
-struct rtw_chip_info rtw8723d_hw_spec = {
+const struct rtw_chip_info rtw8723d_hw_spec = {
        .ops = &rtw8723d_ops,
        .id = RTW_CHIP_TYPE_8723D,
        .fw_name = "rtw88/rtw8723d_fw.bin",
index 41d3517..4641f6e 100644 (file)
@@ -72,6 +72,8 @@ struct rtw8723d_efuse {
        struct rtw8723de_efuse e;
 };
 
+extern const struct rtw_chip_info rtw8723d_hw_spec;
+
 /* phy status page0 */
 #define GET_PHY_STAT_P0_PWDB(phy_stat)                                         \
        le32_get_bits(*((__le32 *)(phy_stat) + 0x00), GENMASK(15, 8))
index 2dd6894..abbaafa 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include "pci.h"
-#include "rtw8723de.h"
+#include "rtw8723d.h"
 
 static const struct pci_device_id rtw_8723de_id_table[] = {
        {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723de.h b/drivers/net/wireless/realtek/rtw88/rtw8723de.h
deleted file mode 100644 (file)
index 2b48948..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
-/* Copyright(c) 2018-2019  Realtek Corporation
- */
-
-#ifndef __RTW_8723DE_H_
-#define __RTW_8723DE_H_
-
-extern struct rtw_chip_info rtw8723d_hw_spec;
-
-#endif
index ffee39e..42841f5 100644 (file)
@@ -1877,7 +1877,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8821c[] = {
        {0x60A, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
 };
 
-struct rtw_chip_info rtw8821c_hw_spec = {
+const struct rtw_chip_info rtw8821c_hw_spec = {
        .ops = &rtw8821c_ops,
        .id = RTW_CHIP_TYPE_8821C,
        .fw_name = "rtw88/rtw8821c_fw.bin",
index d9fbddd..2698801 100644 (file)
@@ -84,6 +84,8 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
        rtw_write32_mask(rtwdev, addr + 0x200, mask, data);
 }
 
+extern const struct rtw_chip_info rtw8821c_hw_spec;
+
 #define rtw_write32s_mask(rtwdev, addr, mask, data)                           \
        do {                                                                   \
                BUILD_BUG_ON((addr) < 0xC00 || (addr) >= 0xD00);               \
index 56d22f9..f3d971f 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include "pci.h"
-#include "rtw8821ce.h"
+#include "rtw8821c.h"
 
 static const struct pci_device_id rtw_8821ce_id_table[] = {
        {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821ce.h b/drivers/net/wireless/realtek/rtw88/rtw8821ce.h
deleted file mode 100644 (file)
index 54142ac..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
-/* Copyright(c) 2018-2019  Realtek Corporation
- */
-
-#ifndef __RTW_8821CE_H_
-#define __RTW_8821CE_H_
-
-extern struct rtw_chip_info rtw8821c_hw_spec;
-
-#endif
index dccd722..3218488 100644 (file)
@@ -2497,7 +2497,7 @@ static struct rtw_hw_reg_offset rtw8822b_edcca_th[] = {
        [EDCCA_TH_H2L_IDX] = {{.addr = 0x8a4, .mask = MASKBYTE1}, .offset = 0},
 };
 
-struct rtw_chip_info rtw8822b_hw_spec = {
+const struct rtw_chip_info rtw8822b_hw_spec = {
        .ops = &rtw8822b_ops,
        .id = RTW_CHIP_TYPE_8822B,
        .fw_name = "rtw88/rtw8822b_fw.bin",
index 3fff8b8..01d3644 100644 (file)
@@ -187,4 +187,6 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data)
 #define REG_ANTWT      0x1904
 #define REG_IQKFAILMSK 0x1bf0
 
+extern const struct rtw_chip_info rtw8822b_hw_spec;
+
 #endif
index 62ee7e6..4994950 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include "pci.h"
-#include "rtw8822be.h"
+#include "rtw8822b.h"
 
 static const struct pci_device_id rtw_8822be_id_table[] = {
        {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822be.h b/drivers/net/wireless/realtek/rtw88/rtw8822be.h
deleted file mode 100644 (file)
index 6668460..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
-/* Copyright(c) 2018-2019  Realtek Corporation
- */
-
-#ifndef __RTW_8822BE_H_
-#define __RTW_8822BE_H_
-
-extern struct rtw_chip_info rtw8822b_hw_spec;
-
-#endif
index c043b5c..09f9e4a 100644 (file)
@@ -5310,7 +5310,7 @@ static const struct rtw_reg_domain coex_info_hw_regs_8822c[] = {
        {0xc50, MASKBYTE0, RTW_REG_DOMAIN_MAC8},
 };
 
-struct rtw_chip_info rtw8822c_hw_spec = {
+const struct rtw_chip_info rtw8822c_hw_spec = {
        .ops = &rtw8822c_ops,
        .id = RTW_CHIP_TYPE_8822C,
        .fw_name = "rtw88/rtw8822c_fw.bin",
index 8201955..479d5d7 100644 (file)
@@ -118,6 +118,8 @@ enum rtw8822c_dpk_one_shot_action {
 void rtw8822c_parse_tbl_dpk(struct rtw_dev *rtwdev,
                            const struct rtw_table *tbl);
 
+extern const struct rtw_chip_info rtw8822c_hw_spec;
+
 #define RTW_DECL_TABLE_DPK(name)                       \
 const struct rtw_table name ## _tbl = {                        \
        .data = name,                                   \
index 3845b13..e26c6bc 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include "pci.h"
-#include "rtw8822ce.h"
+#include "rtw8822c.h"
 
 static const struct pci_device_id rtw_8822ce_id_table[] = {
        {
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822ce.h b/drivers/net/wireless/realtek/rtw88/rtw8822ce.h
deleted file mode 100644 (file)
index fee32d7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
-/* Copyright(c) 2018-2019  Realtek Corporation
- */
-
-#ifndef __RTW_8822CE_H_
-#define __RTW_8822CE_H_
-
-extern struct rtw_chip_info rtw8822c_hw_spec;
-
-#endif
index 8a26ade..db3c55f 100644 (file)
@@ -602,11 +602,18 @@ int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev,
        struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
        struct rtw89_bssid_cam_entry *bssid_cam = &rtwvif->bssid_cam;
        u8 bss_color = vif->bss_conf.he_bss_color.color;
+       u8 bss_mask;
+
+       if (vif->bss_conf.nontransmitted)
+               bss_mask = RTW89_BSSID_MATCH_5_BYTES;
+       else
+               bss_mask = RTW89_BSSID_MATCH_ALL;
 
        FWCMD_SET_ADDR_BSSID_IDX(cmd, bssid_cam->bssid_cam_idx);
        FWCMD_SET_ADDR_BSSID_OFFSET(cmd, bssid_cam->offset);
        FWCMD_SET_ADDR_BSSID_LEN(cmd, bssid_cam->len);
        FWCMD_SET_ADDR_BSSID_VALID(cmd, bssid_cam->valid);
+       FWCMD_SET_ADDR_BSSID_MASK(cmd, bss_mask);
        FWCMD_SET_ADDR_BSSID_BB_SEL(cmd, bssid_cam->phy_idx);
        FWCMD_SET_ADDR_BSSID_BSS_COLOR(cmd, bss_color);
 
index a3931d3..74a6c47 100644 (file)
@@ -9,6 +9,9 @@
 
 #define RTW89_SEC_CAM_LEN      20
 
+#define RTW89_BSSID_MATCH_ALL GENMASK(5, 0)
+#define RTW89_BSSID_MATCH_5_BYTES GENMASK(4, 0)
+
 static inline void FWCMD_SET_ADDR_IDX(void *cmd, u32 value)
 {
        le32p_replace_bits((__le32 *)(cmd) + 1, value, GENMASK(7, 0));
@@ -309,6 +312,11 @@ static inline void FWCMD_SET_ADDR_BSSID_BB_SEL(void *cmd, u32 value)
        le32p_replace_bits((__le32 *)(cmd) + 13, value, BIT(1));
 }
 
+static inline void FWCMD_SET_ADDR_BSSID_MASK(void *cmd, u32 value)
+{
+       le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(7, 2));
+}
+
 static inline void FWCMD_SET_ADDR_BSSID_BSS_COLOR(void *cmd, u32 value)
 {
        le32p_replace_bits((__le32 *)(cmd) + 13, value, GENMASK(13, 8));
index a6a9057..d2f2a3d 100644 (file)
@@ -1343,6 +1343,47 @@ struct rtw89_vif_rx_stats_iter_data {
        const u8 *bssid;
 };
 
+static void rtw89_stats_trigger_frame(struct rtw89_dev *rtwdev,
+                                     struct ieee80211_vif *vif,
+                                     struct sk_buff *skb)
+{
+       struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+       struct ieee80211_trigger *tf = (struct ieee80211_trigger *)skb->data;
+       u8 *pos, *end, type;
+       u16 aid;
+
+       if (!ether_addr_equal(vif->bss_conf.bssid, tf->ta) ||
+           rtwvif->wifi_role != RTW89_WIFI_ROLE_STATION ||
+           rtwvif->net_type == RTW89_NET_TYPE_NO_LINK)
+               return;
+
+       type = le64_get_bits(tf->common_info, IEEE80211_TRIGGER_TYPE_MASK);
+       if (type != IEEE80211_TRIGGER_TYPE_BASIC)
+               return;
+
+       end = (u8 *)tf + skb->len;
+       pos = tf->variable;
+
+       while (end - pos >= RTW89_TF_BASIC_USER_INFO_SZ) {
+               aid = RTW89_GET_TF_USER_INFO_AID12(pos);
+               rtw89_debug(rtwdev, RTW89_DBG_TXRX,
+                           "[TF] aid: %d, ul_mcs: %d, rua: %d\n",
+                           aid, RTW89_GET_TF_USER_INFO_UL_MCS(pos),
+                           RTW89_GET_TF_USER_INFO_RUA(pos));
+
+               if (aid == RTW89_TF_PAD)
+                       break;
+
+               if (aid == vif->bss_conf.aid) {
+                       rtwvif->stats.rx_tf_acc++;
+                       rtwdev->stats.rx_tf_acc++;
+                       break;
+               }
+
+               pos += RTW89_TF_BASIC_USER_INFO_SZ;
+       }
+}
+
 static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
                                    struct ieee80211_vif *vif)
 {
@@ -1355,6 +1396,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        const u8 *bssid = iter_data->bssid;
 
+       if (ieee80211_is_trigger(hdr->frame_control)) {
+               rtw89_stats_trigger_frame(rtwdev, vif, skb);
+               return;
+       }
+
        if (!ether_addr_equal(vif->bss_conf.bssid, bssid))
                return;
 
@@ -1608,7 +1654,7 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev,
 
        if (rtwdev->scanning &&
            RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) {
-               u8 chan = hal->current_channel;
+               u8 chan = hal->current_primary_channel;
                u8 band = hal->current_band_type;
                enum nl80211_band nl_band;
 
@@ -2023,6 +2069,8 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev,
        stats->rx_unicast = 0;
        stats->tx_cnt = 0;
        stats->rx_cnt = 0;
+       stats->rx_tf_periodic = stats->rx_tf_acc;
+       stats->rx_tf_acc = 0;
 
        if (tx_tfc_lv != stats->tx_tfc_lv || rx_tfc_lv != stats->rx_tfc_lv)
                return true;
@@ -2875,7 +2923,10 @@ void rtw89_core_scan_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
 void rtw89_core_scan_complete(struct rtw89_dev *rtwdev,
                              struct ieee80211_vif *vif, bool hw_scan)
 {
-       struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv;
+       struct rtw89_vif *rtwvif = vif ? (struct rtw89_vif *)vif->drv_priv : NULL;
+
+       if (!rtwvif)
+               return;
 
        ether_addr_copy(rtwvif->mac_addr, vif->addr);
        rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL);
@@ -3008,6 +3059,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev)
        ieee80211_hw_set(hw, SUPPORTS_PS);
        ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
        ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
+       ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
 
        hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                     BIT(NL80211_IFTYPE_AP);
index e8a7722..239d47d 100644 (file)
@@ -55,6 +55,16 @@ enum htc_om_channel_width {
 #define RTW89_HTC_MASK_HTC_OM_DL_MU_MIMO_RR BIT(16)
 #define RTW89_HTC_MASK_HTC_OM_UL_MU_DATA_DIS BIT(17)
 
+#define RTW89_TF_PAD GENMASK(11, 0)
+#define RTW89_TF_BASIC_USER_INFO_SZ 6
+
+#define RTW89_GET_TF_USER_INFO_AID12(data)     \
+       le32_get_bits(*((const __le32 *)(data)), GENMASK(11, 0))
+#define RTW89_GET_TF_USER_INFO_RUA(data)       \
+       le32_get_bits(*((const __le32 *)(data)), GENMASK(19, 12))
+#define RTW89_GET_TF_USER_INFO_UL_MCS(data)    \
+       le32_get_bits(*((const __le32 *)(data)), GENMASK(24, 21))
+
 enum rtw89_subband {
        RTW89_CH_2G = 0,
        RTW89_CH_5G_BAND_1 = 1,
@@ -943,6 +953,10 @@ struct rtw89_traffic_stats {
        u32 rx_throughput;
        u32 tx_throughput_raw;
        u32 rx_throughput_raw;
+
+       u32 rx_tf_acc;
+       u32 rx_tf_periodic;
+
        enum rtw89_tfc_lv tx_tfc_lv;
        enum rtw89_tfc_lv rx_tfc_lv;
        struct ewma_tp tx_ewma_tp;
@@ -2550,9 +2564,24 @@ enum rtw89_sar_sources {
        RTW89_SAR_SOURCE_NR,
 };
 
+enum rtw89_sar_subband {
+       RTW89_SAR_2GHZ_SUBBAND,
+       RTW89_SAR_5GHZ_SUBBAND_1_2, /* U-NII-1 and U-NII-2 */
+       RTW89_SAR_5GHZ_SUBBAND_2_E, /* U-NII-2-Extended */
+       RTW89_SAR_5GHZ_SUBBAND_3,   /* U-NII-3 */
+       RTW89_SAR_6GHZ_SUBBAND_5_L, /* U-NII-5 lower part */
+       RTW89_SAR_6GHZ_SUBBAND_5_H, /* U-NII-5 higher part */
+       RTW89_SAR_6GHZ_SUBBAND_6,   /* U-NII-6 */
+       RTW89_SAR_6GHZ_SUBBAND_7_L, /* U-NII-7 lower part */
+       RTW89_SAR_6GHZ_SUBBAND_7_H, /* U-NII-7 higher part */
+       RTW89_SAR_6GHZ_SUBBAND_8,   /* U-NII-8 */
+
+       RTW89_SAR_SUBBAND_NR,
+};
+
 struct rtw89_sar_cfg_common {
-       bool set[RTW89_SUBBAND_NR];
-       s32 cfg[RTW89_SUBBAND_NR];
+       bool set[RTW89_SAR_SUBBAND_NR];
+       s32 cfg[RTW89_SAR_SUBBAND_NR];
 };
 
 struct rtw89_sar_info {
@@ -2646,6 +2675,10 @@ struct rtw89_lck_info {
        u8 thermal[RF_PATH_MAX];
 };
 
+struct rtw89_rx_dck_info {
+       u8 thermal[RF_PATH_MAX];
+};
+
 struct rtw89_iqk_info {
        bool lok_cor_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
        bool lok_fin_fail[RTW89_IQK_CHS_NR][RTW89_IQK_PATH_NR];
@@ -2776,13 +2809,20 @@ enum rtw89_multi_cfo_mode {
 enum rtw89_phy_cfo_status {
        RTW89_PHY_DCFO_STATE_NORMAL = 0,
        RTW89_PHY_DCFO_STATE_ENHANCE = 1,
+       RTW89_PHY_DCFO_STATE_HOLD = 2,
        RTW89_PHY_DCFO_STATE_MAX
 };
 
+enum rtw89_phy_cfo_ul_ofdma_acc_mode {
+       RTW89_CFO_UL_OFDMA_ACC_DISABLE = 0,
+       RTW89_CFO_UL_OFDMA_ACC_ENABLE = 1
+};
+
 struct rtw89_cfo_tracking_info {
        u16 cfo_timer_ms;
        bool cfo_trig_by_timer_en;
        enum rtw89_phy_cfo_status phy_cfo_status;
+       enum rtw89_phy_cfo_ul_ofdma_acc_mode cfo_ul_ofdma_acc_mode;
        u8 phy_cfo_trk_cnt;
        bool is_adjust;
        enum rtw89_multi_cfo_mode rtw89_multi_cfo_mode;
@@ -3125,6 +3165,7 @@ struct rtw89_dev {
        struct rtw89_dpk_info dpk;
        struct rtw89_mcc_info mcc;
        struct rtw89_lck_info lck;
+       struct rtw89_rx_dck_info rx_dck;
        bool is_tssi_mode[RF_PATH_MAX];
        bool is_bt_iqk_timeout;
 
index 7820bc3..f00f819 100644 (file)
@@ -2376,7 +2376,8 @@ static int rtw89_debug_priv_phy_info_get(struct seq_file *m, void *v)
        seq_printf(m, "TP TX: %u [%u] Mbps (lv: %d), RX: %u [%u] Mbps (lv: %d)\n",
                   stats->tx_throughput, stats->tx_throughput_raw, stats->tx_tfc_lv,
                   stats->rx_throughput, stats->rx_throughput_raw, stats->rx_tfc_lv);
-       seq_printf(m, "Beacon: %u\n", pkt_stat->beacon_nr);
+       seq_printf(m, "Beacon: %u, TF: %u\n", pkt_stat->beacon_nr,
+                  stats->rx_tf_periodic);
        seq_printf(m, "Avg packet length: TX=%u, RX=%u\n", stats->tx_avg_len,
                   stats->rx_avg_len);
 
index de72155..561b04f 100644 (file)
@@ -24,6 +24,7 @@ enum rtw89_debug_mask {
        RTW89_DBG_BTC = BIT(13),
        RTW89_DBG_BF = BIT(14),
        RTW89_DBG_HW_SCAN = BIT(15),
+       RTW89_DBG_SAR = BIT(16),
 };
 
 enum rtw89_debug_mac_reg_sel {
index 4718ace..2d9c315 100644 (file)
@@ -2257,7 +2257,7 @@ static int rtw89_hw_scan_add_chan_list(struct rtw89_dev *rtwdev,
                list_add_tail(&ch_info->list, &chan_list);
                off_chan_time += ch_info->period;
        }
-       rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list);
+       ret = rtw89_fw_h2c_scan_list_offload(rtwdev, list_len, &chan_list);
 
 out:
        list_for_each_entry_safe(ch_info, tmp, &chan_list, list) {
@@ -2339,6 +2339,9 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
        rtwvif->scan_req = NULL;
        rtwvif->scan_ies = NULL;
        rtwdev->scan_info.scanning_vif = NULL;
+
+       if (rtwvif->net_type != RTW89_NET_TYPE_NO_LINK)
+               rtw89_store_op_chan(rtwdev, false);
 }
 
 void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
@@ -2365,20 +2368,27 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
                if (ret)
                        goto out;
        }
-       rtw89_fw_h2c_scan_offload(rtwdev, &opt, rtwvif);
+       ret = rtw89_fw_h2c_scan_offload(rtwdev, &opt, rtwvif);
 out:
        return ret;
 }
 
-void rtw89_store_op_chan(struct rtw89_dev *rtwdev)
+void rtw89_store_op_chan(struct rtw89_dev *rtwdev, bool backup)
 {
        struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info;
        struct rtw89_hal *hal = &rtwdev->hal;
 
-       scan_info->op_pri_ch = hal->current_primary_channel;
-       scan_info->op_chan = hal->current_channel;
-       scan_info->op_bw = hal->current_band_width;
-       scan_info->op_band = hal->current_band_type;
+       if (backup) {
+               scan_info->op_pri_ch = hal->current_primary_channel;
+               scan_info->op_chan = hal->current_channel;
+               scan_info->op_bw = hal->current_band_width;
+               scan_info->op_band = hal->current_band_type;
+       } else {
+               hal->current_primary_channel = scan_info->op_pri_ch;
+               hal->current_channel = scan_info->op_chan;
+               hal->current_band_width = scan_info->op_bw;
+               hal->current_band_type = scan_info->op_band;
+       }
 }
 
 #define H2C_FW_CPU_EXCEPTION_LEN 4
index 95a55c4..e75ad22 100644 (file)
@@ -2633,17 +2633,14 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev,
                     struct rtw89_mac_c2h_info *c2h_info);
 int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable);
 void rtw89_fw_st_dbg_dump(struct rtw89_dev *rtwdev);
-void rtw89_store_op_chan(struct rtw89_dev *rtwdev);
+void rtw89_store_op_chan(struct rtw89_dev *rtwdev, bool backup);
 void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
                         struct ieee80211_scan_request *req);
 void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
                            bool aborted);
 int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
                          bool enable);
-void rtw89_hw_scan_status_report(struct rtw89_dev *rtwdev, struct sk_buff *skb);
-void rtw89_hw_scan_chan_switch(struct rtw89_dev *rtwdev, struct sk_buff *skb);
 void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
-void rtw89_store_op_chan(struct rtw89_dev *rtwdev);
 int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev);
 
 #endif
index 3cf8929..93124b8 100644 (file)
@@ -3681,17 +3681,20 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
                rtw89_hw_scan_complete(rtwdev, vif, false);
                break;
        case RTW89_SCAN_ENTER_CH_NOTIFY:
-               if (rtw89_is_op_chan(rtwdev, band, chan))
+               hal->prev_band_type = hal->current_band_type;
+               hal->current_band_type = band;
+               hal->prev_primary_channel = hal->current_primary_channel;
+               hal->current_primary_channel = chan;
+               hal->current_channel = chan;
+               hal->current_band_width = RTW89_CHANNEL_WIDTH_20;
+               if (rtw89_is_op_chan(rtwdev, band, chan)) {
+                       rtw89_store_op_chan(rtwdev, false);
                        ieee80211_wake_queues(rtwdev->hw);
+               }
                break;
        default:
                return;
        }
-
-       hal->prev_band_type = hal->current_band_type;
-       hal->prev_primary_channel = hal->current_channel;
-       hal->current_channel = chan;
-       hal->current_band_type = band;
 }
 
 static void
index 9f511c8..f666193 100644 (file)
@@ -666,6 +666,7 @@ enum mac_ax_err_info {
        MAC_AX_ERR_L2_ERR_APB_BBRF_TO_RX4281 = 0x2360,
        MAC_AX_ERR_L2_ERR_APB_BBRF_TO_OTHERS = 0x2370,
        MAC_AX_ERR_L2_RESET_DONE = 0x2400,
+       MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT = 0x2599,
        MAC_AX_ERR_CPU_EXCEPTION = 0x3000,
        MAC_AX_ERR_ASSERTION = 0x4000,
        MAC_AX_GET_ERR_MAX,
index f24e4a2..6d0c62c 100644 (file)
@@ -350,7 +350,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
                        rtw89_phy_set_bss_color(rtwdev, vif);
                        rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif);
                        rtw89_mac_port_update(rtwdev, rtwvif);
-                       rtw89_store_op_chan(rtwdev);
+                       rtw89_store_op_chan(rtwdev, true);
                } else {
                        /* Abort ongoing scan if cancel_scan isn't issued
                         * when disconnected by peer
index 0ef7821..25872df 100644 (file)
@@ -738,6 +738,9 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
        if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN))
                rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
 
+       if (unlikely(isrs.halt_c2h_isrs & B_AX_WDT_TIMEOUT_INT_EN))
+               rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT);
+
        if (unlikely(rtwpci->under_recovery))
                goto enable_intr;
 
@@ -3126,7 +3129,7 @@ static void rtw89_pci_recovery_intr_mask_v1(struct rtw89_dev *rtwdev)
        struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
 
        rtwpci->ind_intrs = B_AX_HS0ISR_IND_INT_EN;
-       rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
+       rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN;
        rtwpci->intrs[0] = 0;
        rtwpci->intrs[1] = 0;
 }
@@ -3138,7 +3141,7 @@ static void rtw89_pci_default_intr_mask_v1(struct rtw89_dev *rtwdev)
        rtwpci->ind_intrs = B_AX_HCI_AXIDMA_INT_EN |
                            B_AX_HS1ISR_IND_INT_EN |
                            B_AX_HS0ISR_IND_INT_EN;
-       rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
+       rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN;
        rtwpci->intrs[0] = B_AX_TXDMA_STUCK_INT_EN |
                           B_AX_RXDMA_INT_EN |
                           B_AX_RXP1DMA_INT_EN |
@@ -3155,7 +3158,7 @@ static void rtw89_pci_low_power_intr_mask_v1(struct rtw89_dev *rtwdev)
 
        rtwpci->ind_intrs = B_AX_HS1ISR_IND_INT_EN |
                            B_AX_HS0ISR_IND_INT_EN;
-       rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN;
+       rtwpci->halt_c2h_intrs = B_AX_HALT_C2H_INT_EN | B_AX_WDT_TIMEOUT_INT_EN;
        rtwpci->intrs[0] = 0;
        rtwpci->intrs[1] = B_AX_GPIO18_INT_EN;
 }
index bb585ed..a118647 100644 (file)
@@ -94,6 +94,7 @@
 
 /* Interrupts */
 #define R_AX_HIMR0 0x01A0
+#define B_AX_WDT_TIMEOUT_INT_EN BIT(22)
 #define B_AX_HALT_C2H_INT_EN BIT(21)
 #define R_AX_HISR0 0x01A4
 
index 762cdba..217aacb 100644 (file)
@@ -2151,6 +2151,7 @@ static void rtw89_phy_cfo_init(struct rtw89_dev *rtwdev)
        cfo->cfo_trig_by_timer_en = false;
        cfo->phy_cfo_trk_cnt = 0;
        cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
+       cfo->cfo_ul_ofdma_acc_mode = RTW89_CFO_UL_OFDMA_ACC_ENABLE;
 }
 
 static void rtw89_phy_cfo_crystal_cap_adjust(struct rtw89_dev *rtwdev,
@@ -2419,6 +2420,13 @@ void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev)
 {
        struct rtw89_cfo_tracking_info *cfo = &rtwdev->cfo_tracking;
        struct rtw89_traffic_stats *stats = &rtwdev->stats;
+       bool is_ul_ofdma = false, ofdma_acc_en = false;
+
+       if (stats->rx_tf_periodic > CFO_TF_CNT_TH)
+               is_ul_ofdma = true;
+       if (cfo->cfo_ul_ofdma_acc_mode == RTW89_CFO_UL_OFDMA_ACC_ENABLE &&
+           is_ul_ofdma)
+               ofdma_acc_en = true;
 
        switch (cfo->phy_cfo_status) {
        case RTW89_PHY_DCFO_STATE_NORMAL:
@@ -2430,16 +2438,26 @@ void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev)
                }
                break;
        case RTW89_PHY_DCFO_STATE_ENHANCE:
-               if (cfo->phy_cfo_trk_cnt >= CFO_PERIOD_CNT) {
+               if (stats->tx_throughput <= CFO_TP_LOWER)
+                       cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
+               else if (ofdma_acc_en &&
+                        cfo->phy_cfo_trk_cnt >= CFO_PERIOD_CNT)
+                       cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_HOLD;
+               else
+                       cfo->phy_cfo_trk_cnt++;
+
+               if (cfo->phy_cfo_status == RTW89_PHY_DCFO_STATE_NORMAL) {
                        cfo->phy_cfo_trk_cnt = 0;
                        cfo->cfo_trig_by_timer_en = false;
                }
-               if (cfo->cfo_trig_by_timer_en == 1)
-                       cfo->phy_cfo_trk_cnt++;
+               break;
+       case RTW89_PHY_DCFO_STATE_HOLD:
                if (stats->tx_throughput <= CFO_TP_LOWER) {
                        cfo->phy_cfo_status = RTW89_PHY_DCFO_STATE_NORMAL;
                        cfo->phy_cfo_trk_cnt = 0;
                        cfo->cfo_trig_by_timer_en = false;
+               } else {
+                       cfo->phy_cfo_trk_cnt++;
                }
                break;
        default:
index 2916601..e20636f 100644 (file)
@@ -62,6 +62,7 @@
 #define CFO_COMP_PERIOD 250
 #define CFO_COMP_WEIGHT 8
 #define MAX_CFO_TOLERANCE 30
+#define CFO_TF_CNT_TH 300
 
 #define CCX_MAX_PERIOD 2097
 #define CCX_MAX_PERIOD_UNIT 32
index 64840c8..b697aef 100644 (file)
@@ -1861,6 +1861,7 @@ static void rtw8852c_rfk_track(struct rtw89_dev *rtwdev)
 {
        rtw8852c_dpk_track(rtwdev);
        rtw8852c_lck_track(rtwdev);
+       rtw8852c_rx_dck_track(rtwdev);
 }
 
 static u32 rtw8852c_bb_cal_txpwr_ref(struct rtw89_dev *rtwdev,
index dfb9cab..4186d82 100644 (file)
@@ -3864,6 +3864,7 @@ void rtw8852c_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
 
 void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_afe)
 {
+       struct rtw89_rx_dck_info *rx_dck = &rtwdev->rx_dck;
        u8 path, kpath;
        u32 rf_reg5;
 
@@ -3883,6 +3884,7 @@ void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_a
                rtw89_write_rf(rtwdev, path, RR_RSV1, RR_RSV1_RST, 0x0);
                rtw89_write_rf(rtwdev, path, RR_MOD, RR_MOD_MASK, RR_MOD_V_RX);
                _set_rx_dck(rtwdev, phy, path, is_afe);
+               rx_dck->thermal[path] = ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]);
                rtw89_write_rf(rtwdev, path, RR_RSV1, RFREG_MASK, rf_reg5);
 
                if (rtwdev->is_tssi_mode[path])
@@ -3891,6 +3893,31 @@ void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, bool is_a
        }
 }
 
+#define RTW8852C_RX_DCK_TH 8
+
+void rtw8852c_rx_dck_track(struct rtw89_dev *rtwdev)
+{
+       struct rtw89_rx_dck_info *rx_dck = &rtwdev->rx_dck;
+       u8 cur_thermal;
+       int delta;
+       int path;
+
+       for (path = 0; path < RF_PATH_NUM_8852C; path++) {
+               cur_thermal =
+                       ewma_thermal_read(&rtwdev->phystat.avg_thermal[path]);
+               delta = abs((int)cur_thermal - rx_dck->thermal[path]);
+
+               rtw89_debug(rtwdev, RTW89_DBG_RFK_TRACK,
+                           "[RX_DCK] path=%d current thermal=0x%x delta=0x%x\n",
+                           path, cur_thermal, delta);
+
+               if (delta >= RTW8852C_RX_DCK_TH) {
+                       rtw8852c_rx_dck(rtwdev, RTW89_PHY_0, false);
+                       return;
+               }
+       }
+}
+
 void rtw8852c_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx)
 {
        u32 tx_en;
index c32756f..5118a49 100644 (file)
@@ -12,6 +12,7 @@ void rtw8852c_rck(struct rtw89_dev *rtwdev);
 void rtw8852c_dack(struct rtw89_dev *rtwdev);
 void rtw8852c_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx);
 void rtw8852c_rx_dck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, bool is_afe);
+void rtw8852c_rx_dck_track(struct rtw89_dev *rtwdev);
 void rtw8852c_dpk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy);
 void rtw8852c_dpk_track(struct rtw89_dev *rtwdev);
 void rtw8852c_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy);
index 097c878..eb2d3ec 100644 (file)
 #include "debug.h"
 #include "sar.h"
 
+static enum rtw89_sar_subband rtw89_sar_get_subband(struct rtw89_dev *rtwdev,
+                                                   u32 center_freq)
+{
+       switch (center_freq) {
+       default:
+               rtw89_debug(rtwdev, RTW89_DBG_SAR,
+                           "center freq: %u to SAR subband is unhandled\n",
+                           center_freq);
+               fallthrough;
+       case 2412 ... 2484:
+               return RTW89_SAR_2GHZ_SUBBAND;
+       case 5180 ... 5320:
+               return RTW89_SAR_5GHZ_SUBBAND_1_2;
+       case 5500 ... 5720:
+               return RTW89_SAR_5GHZ_SUBBAND_2_E;
+       case 5745 ... 5825:
+               return RTW89_SAR_5GHZ_SUBBAND_3;
+       case 5955 ... 6155:
+               return RTW89_SAR_6GHZ_SUBBAND_5_L;
+       case 6175 ... 6415:
+               return RTW89_SAR_6GHZ_SUBBAND_5_H;
+       case 6435 ... 6515:
+               return RTW89_SAR_6GHZ_SUBBAND_6;
+       case 6535 ... 6695:
+               return RTW89_SAR_6GHZ_SUBBAND_7_L;
+       case 6715 ... 6855:
+               return RTW89_SAR_6GHZ_SUBBAND_7_H;
+
+       /* freq 6875 (ch 185, 20MHz) spans RTW89_SAR_6GHZ_SUBBAND_7_H
+        * and RTW89_SAR_6GHZ_SUBBAND_8, so directly describe it with
+        * struct rtw89_sar_span in the following.
+        */
+
+       case 6895 ... 7115:
+               return RTW89_SAR_6GHZ_SUBBAND_8;
+       }
+}
+
+struct rtw89_sar_span {
+       enum rtw89_sar_subband subband_low;
+       enum rtw89_sar_subband subband_high;
+};
+
+#define RTW89_SAR_SPAN_VALID(span) ((span)->subband_high)
+
+#define RTW89_SAR_6GHZ_SPAN_HEAD 6145
+#define RTW89_SAR_6GHZ_SPAN_IDX(center_freq) \
+       ((((int)(center_freq) - RTW89_SAR_6GHZ_SPAN_HEAD) / 5) / 2)
+
+#define RTW89_DECL_SAR_6GHZ_SPAN(center_freq, subband_l, subband_h) \
+       [RTW89_SAR_6GHZ_SPAN_IDX(center_freq)] = { \
+               .subband_low = RTW89_SAR_6GHZ_ ## subband_l, \
+               .subband_high = RTW89_SAR_6GHZ_ ## subband_h, \
+       }
+
+/* Since 6GHz SAR subbands are not edge aligned, some cases span two SAR
+ * subbands. In the following, we describe each of them with rtw89_sar_span.
+ */
+static const struct rtw89_sar_span rtw89_sar_overlapping_6ghz[] = {
+       RTW89_DECL_SAR_6GHZ_SPAN(6145, SUBBAND_5_L, SUBBAND_5_H),
+       RTW89_DECL_SAR_6GHZ_SPAN(6165, SUBBAND_5_L, SUBBAND_5_H),
+       RTW89_DECL_SAR_6GHZ_SPAN(6185, SUBBAND_5_L, SUBBAND_5_H),
+       RTW89_DECL_SAR_6GHZ_SPAN(6505, SUBBAND_6, SUBBAND_7_L),
+       RTW89_DECL_SAR_6GHZ_SPAN(6525, SUBBAND_6, SUBBAND_7_L),
+       RTW89_DECL_SAR_6GHZ_SPAN(6545, SUBBAND_6, SUBBAND_7_L),
+       RTW89_DECL_SAR_6GHZ_SPAN(6665, SUBBAND_7_L, SUBBAND_7_H),
+       RTW89_DECL_SAR_6GHZ_SPAN(6705, SUBBAND_7_L, SUBBAND_7_H),
+       RTW89_DECL_SAR_6GHZ_SPAN(6825, SUBBAND_7_H, SUBBAND_8),
+       RTW89_DECL_SAR_6GHZ_SPAN(6865, SUBBAND_7_H, SUBBAND_8),
+       RTW89_DECL_SAR_6GHZ_SPAN(6875, SUBBAND_7_H, SUBBAND_8),
+       RTW89_DECL_SAR_6GHZ_SPAN(6885, SUBBAND_7_H, SUBBAND_8),
+};
+
 static int rtw89_query_sar_config_common(struct rtw89_dev *rtwdev, s32 *cfg)
 {
        struct rtw89_sar_cfg_common *rtwsar = &rtwdev->sar.cfg_common;
-       enum rtw89_subband subband = rtwdev->hal.current_subband;
+       struct rtw89_hal *hal = &rtwdev->hal;
+       enum rtw89_band band = hal->current_band_type;
+       u32 center_freq = hal->current_freq;
+       const struct rtw89_sar_span *span = NULL;
+       enum rtw89_sar_subband subband_l, subband_h;
+       int idx;
+
+       if (band == RTW89_BAND_6G) {
+               idx = RTW89_SAR_6GHZ_SPAN_IDX(center_freq);
+               /* To decrease size of rtw89_sar_overlapping_6ghz[],
+                * RTW89_SAR_6GHZ_SPAN_IDX() truncates the leading NULLs
+                * to make first span as index 0 of the table. So, if center
+                * frequency is less than the first one, it will get netative.
+                */
+               if (idx >= 0 && idx < ARRAY_SIZE(rtw89_sar_overlapping_6ghz))
+                       span = &rtw89_sar_overlapping_6ghz[idx];
+       }
+
+       if (span && RTW89_SAR_SPAN_VALID(span)) {
+               subband_l = span->subband_low;
+               subband_h = span->subband_high;
+       } else {
+               subband_l = rtw89_sar_get_subband(rtwdev, center_freq);
+               subband_h = subband_l;
+       }
+
+       rtw89_debug(rtwdev, RTW89_DBG_SAR,
+                   "for {band %u, center_freq %u}, SAR subband: {%u, %u}\n",
+                   band, center_freq, subband_l, subband_h);
 
-       if (!rtwsar->set[subband])
+       if (!rtwsar->set[subband_l] && !rtwsar->set[subband_h])
                return -ENODATA;
 
-       *cfg = rtwsar->cfg[subband];
+       if (!rtwsar->set[subband_l])
+               *cfg = rtwsar->cfg[subband_h];
+       else if (!rtwsar->set[subband_h])
+               *cfg = rtwsar->cfg[subband_l];
+       else
+               *cfg = min(rtwsar->cfg[subband_l], rtwsar->cfg[subband_h]);
+
        return 0;
 }
 
@@ -128,21 +235,20 @@ exit:
        return ret;
 }
 
-static const u8 rtw89_common_sar_subband_map[] = {
-       RTW89_CH_2G,
-       RTW89_CH_5G_BAND_1,
-       RTW89_CH_5G_BAND_3,
-       RTW89_CH_5G_BAND_4,
-};
-
 static const struct cfg80211_sar_freq_ranges rtw89_common_sar_freq_ranges[] = {
        { .start_freq = 2412, .end_freq = 2484, },
        { .start_freq = 5180, .end_freq = 5320, },
        { .start_freq = 5500, .end_freq = 5720, },
        { .start_freq = 5745, .end_freq = 5825, },
+       { .start_freq = 5955, .end_freq = 6155, },
+       { .start_freq = 6175, .end_freq = 6415, },
+       { .start_freq = 6435, .end_freq = 6515, },
+       { .start_freq = 6535, .end_freq = 6695, },
+       { .start_freq = 6715, .end_freq = 6875, },
+       { .start_freq = 6875, .end_freq = 7115, },
 };
 
-static_assert(ARRAY_SIZE(rtw89_common_sar_subband_map) ==
+static_assert(RTW89_SAR_SUBBAND_NR ==
              ARRAY_SIZE(rtw89_common_sar_freq_ranges));
 
 const struct cfg80211_sar_capa rtw89_sar_capa = {
@@ -159,7 +265,6 @@ int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
        u8 fct;
        u32 freq_start;
        u32 freq_end;
-       u32 band;
        s32 power;
        u32 i, idx;
 
@@ -175,15 +280,14 @@ int rtw89_ops_set_sar_specs(struct ieee80211_hw *hw,
 
                freq_start = rtw89_common_sar_freq_ranges[idx].start_freq;
                freq_end = rtw89_common_sar_freq_ranges[idx].end_freq;
-               band = rtw89_common_sar_subband_map[idx];
                power = sar->sub_specs[i].power;
 
-               rtw89_info(rtwdev, "On freq %u to %u, ", freq_start, freq_end);
-               rtw89_info(rtwdev, "set SAR power limit %d (unit: 1/%lu dBm)\n",
-                          power, BIT(fct));
+               rtw89_debug(rtwdev, RTW89_DBG_SAR,
+                           "On freq %u to %u, set SAR limit %d (unit: 1/%lu dBm)\n",
+                           freq_start, freq_end, power, BIT(fct));
 
-               sar_common.set[band] = true;
-               sar_common.cfg[band] = power;
+               sar_common.set[idx] = true;
+               sar_common.cfg[idx] = power;
        }
 
        return rtw89_apply_sar_common(rtwdev, &sar_common);
index 3d1b8a1..52c7f56 100644 (file)
@@ -286,8 +286,7 @@ static int load_firmware_secure(struct wfx_dev *wdev)
 
 error:
        kfree(buf);
-       if (fw)
-               release_firmware(fw);
+       release_firmware(fw);
        if (ret)
                print_boot_status(wdev);
        return ret;
index 10e019c..3b4ded2 100644 (file)
@@ -327,18 +327,12 @@ static int cw1200_bh_rx_helper(struct cw1200_common *priv,
        if (WARN_ON(wsm_handle_rx(priv, wsm_id, wsm, &skb_rx)))
                goto err;
 
-       if (skb_rx) {
-               dev_kfree_skb(skb_rx);
-               skb_rx = NULL;
-       }
+       dev_kfree_skb(skb_rx);
 
        return 0;
 
 err:
-       if (skb_rx) {
-               dev_kfree_skb(skb_rx);
-               skb_rx = NULL;
-       }
+       dev_kfree_skb(skb_rx);
        return -1;
 }
 
index 514f2c1..ba14d83 100644 (file)
@@ -654,7 +654,7 @@ static int __init virt_wifi_init_module(void)
 {
        int err;
 
-       /* Guaranteed to be locallly-administered and not multicast. */
+       /* Guaranteed to be locally-administered and not multicast. */
        eth_random_addr(fake_router_bssid);
 
        err = register_netdevice_notifier(&virt_wifi_notifier);
index d9dea48..8174d7b 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/debugfs.h>
 
 typedef unsigned int pending_ring_idx_t;
-#define INVALID_PENDING_RING_IDX (~0U)
 
 struct pending_tx_info {
        struct xen_netif_tx_request req; /* tx request */
@@ -82,8 +81,6 @@ struct xenvif_rx_meta {
 /* Discriminate from any valid pending_idx value. */
 #define INVALID_PENDING_IDX 0xFFFF
 
-#define MAX_BUFFER_OFFSET XEN_PAGE_SIZE
-
 #define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE
 
 /* The maximum number of frags is derived from the size of a grant (same
@@ -367,11 +364,6 @@ void xenvif_free(struct xenvif *vif);
 int xenvif_xenbus_init(void);
 void xenvif_xenbus_fini(void);
 
-int xenvif_schedulable(struct xenvif *vif);
-
-int xenvif_queue_stopped(struct xenvif_queue *queue);
-void xenvif_wake_queue(struct xenvif_queue *queue);
-
 /* (Un)Map communication rings. */
 void xenvif_unmap_frontend_data_rings(struct xenvif_queue *queue);
 int xenvif_map_frontend_data_rings(struct xenvif_queue *queue,
@@ -394,7 +386,6 @@ int xenvif_dealloc_kthread(void *data);
 irqreturn_t xenvif_ctrl_irq_fn(int irq, void *data);
 
 bool xenvif_have_rx_work(struct xenvif_queue *queue, bool test_kthread);
-void xenvif_rx_action(struct xenvif_queue *queue);
 void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb);
 
 void xenvif_carrier_on(struct xenvif *vif);
@@ -403,9 +394,6 @@ void xenvif_carrier_on(struct xenvif *vif);
 void xenvif_zerocopy_callback(struct sk_buff *skb, struct ubuf_info *ubuf,
                              bool zerocopy_success);
 
-/* Unmap a pending page and release it back to the guest */
-void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx);
-
 static inline pending_ring_idx_t nr_pending_reqs(struct xenvif_queue *queue)
 {
        return MAX_PENDING_REQS -
index 8e03537..fb32ae8 100644 (file)
@@ -69,7 +69,7 @@ void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue)
        wake_up(&queue->dealloc_wq);
 }
 
-int xenvif_schedulable(struct xenvif *vif)
+static int xenvif_schedulable(struct xenvif *vif)
 {
        return netif_running(vif->dev) &&
                test_bit(VIF_STATUS_CONNECTED, &vif->status) &&
@@ -177,20 +177,6 @@ irqreturn_t xenvif_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-int xenvif_queue_stopped(struct xenvif_queue *queue)
-{
-       struct net_device *dev = queue->vif->dev;
-       unsigned int id = queue->id;
-       return netif_tx_queue_stopped(netdev_get_tx_queue(dev, id));
-}
-
-void xenvif_wake_queue(struct xenvif_queue *queue)
-{
-       struct net_device *dev = queue->vif->dev;
-       unsigned int id = queue->id;
-       netif_tx_wake_queue(netdev_get_tx_queue(dev, id));
-}
-
 static u16 xenvif_select_queue(struct net_device *dev, struct sk_buff *skb,
                               struct net_device *sb_dev)
 {
index d93814c..a256695 100644 (file)
@@ -112,6 +112,8 @@ static void make_tx_response(struct xenvif_queue *queue,
                             s8       st);
 static void push_tx_responses(struct xenvif_queue *queue);
 
+static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx);
+
 static inline int tx_work_todo(struct xenvif_queue *queue);
 
 static inline unsigned long idx_to_pfn(struct xenvif_queue *queue,
@@ -1199,9 +1201,7 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
                        }
 
                        mss = skb_shinfo(skb)->gso_size;
-                       hdrlen = skb_transport_header(skb) -
-                               skb_mac_header(skb) +
-                               tcp_hdrlen(skb);
+                       hdrlen = skb_tcp_all_headers(skb);
 
                        skb_shinfo(skb)->gso_segs =
                                DIV_ROUND_UP(skb->len - hdrlen, mss);
@@ -1418,7 +1418,7 @@ static void push_tx_responses(struct xenvif_queue *queue)
                notify_remote_via_irq(queue->tx_irq);
 }
 
-void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
+static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
 {
        int ret;
        struct gnttab_unmap_grant_ref tx_unmap_op;
index dbac4c0..8df2c73 100644 (file)
@@ -486,7 +486,7 @@ static void xenvif_rx_skb(struct xenvif_queue *queue)
 
 #define RX_BATCH_SIZE 64
 
-void xenvif_rx_action(struct xenvif_queue *queue)
+static void xenvif_rx_action(struct xenvif_queue *queue)
 {
        struct sk_buff_head completed_skbs;
        unsigned int work_done = 0;
index 4519ef4..e59ea21 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2020 Facebook */
 
+#include <linux/bits.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -88,10 +89,10 @@ struct tod_reg {
 #define TOD_CTRL_DISABLE_FMT_A BIT(17)
 #define TOD_CTRL_DISABLE_FMT_B BIT(16)
 #define TOD_CTRL_ENABLE                BIT(0)
-#define TOD_CTRL_GNSS_MASK     ((1U << 4) - 1)
+#define TOD_CTRL_GNSS_MASK     GENMASK(3, 0)
 #define TOD_CTRL_GNSS_SHIFT    24
 
-#define TOD_STATUS_UTC_MASK            0xff
+#define TOD_STATUS_UTC_MASK            GENMASK(7, 0)
 #define TOD_STATUS_UTC_VALID           BIT(8)
 #define TOD_STATUS_LEAP_ANNOUNCE       BIT(12)
 #define TOD_STATUS_LEAP_VALID          BIT(16)
@@ -205,7 +206,7 @@ struct frequency_reg {
 #define FREQ_STATUS_VALID      BIT(31)
 #define FREQ_STATUS_ERROR      BIT(30)
 #define FREQ_STATUS_OVERRUN    BIT(29)
-#define FREQ_STATUS_MASK       (BIT(24) - 1)
+#define FREQ_STATUS_MASK       GENMASK(23, 0)
 
 struct ptp_ocp_flash_info {
        const char *name;
@@ -674,9 +675,9 @@ static const struct ocp_selector ptp_ocp_clock[] = {
        { }
 };
 
+#define SMA_DISABLE            BIT(16)
 #define SMA_ENABLE             BIT(15)
-#define SMA_SELECT_MASK                ((1U << 15) - 1)
-#define SMA_DISABLE            0x10000
+#define SMA_SELECT_MASK                GENMASK(14, 0)
 
 static const struct ocp_selector ptp_ocp_sma_in[] = {
        { .name = "10Mhz",      .value = 0x0000 },
@@ -2154,7 +2155,7 @@ ptp_ocp_fb_set_pins(struct ptp_ocp *bp)
        struct ptp_pin_desc *config;
        int i;
 
-       config = kzalloc(sizeof(*config) * 4, GFP_KERNEL);
+       config = kcalloc(4, sizeof(*config), GFP_KERNEL);
        if (!config)
                return -ENOMEM;
 
@@ -3440,7 +3441,7 @@ ptp_ocp_tod_status_show(struct seq_file *s, void *data)
 
        val = ioread32(&bp->tod->utc_status);
        seq_printf(s, "UTC status register: 0x%08X\n", val);
-       seq_printf(s, "UTC offset: %d  valid:%d\n",
+       seq_printf(s, "UTC offset: %ld  valid:%d\n",
                val & TOD_STATUS_UTC_MASK, val & TOD_STATUS_UTC_VALID ? 1 : 0);
        seq_printf(s, "Leap second info valid:%d, Leap second announce %d\n",
                val & TOD_STATUS_LEAP_VALID ? 1 : 0,
@@ -3700,10 +3701,8 @@ ptp_ocp_detach(struct ptp_ocp *bp)
                serial8250_unregister_port(bp->mac_port);
        if (bp->nmea_port != -1)
                serial8250_unregister_port(bp->nmea_port);
-       if (bp->spi_flash)
-               platform_device_unregister(bp->spi_flash);
-       if (bp->i2c_ctrl)
-               platform_device_unregister(bp->i2c_ctrl);
+       platform_device_unregister(bp->spi_flash);
+       platform_device_unregister(bp->i2c_ctrl);
        if (bp->i2c_clk)
                clk_hw_unregister_fixed_rate(bp->i2c_clk);
        if (bp->n_irqs)
@@ -3773,7 +3772,6 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 out:
        ptp_ocp_detach(bp);
-       pci_set_drvdata(pdev, NULL);
 out_disable:
        pci_disable_device(pdev);
 out_free:
@@ -3789,7 +3787,6 @@ ptp_ocp_remove(struct pci_dev *pdev)
 
        devlink_unregister(devlink);
        ptp_ocp_detach(bp);
-       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 
        devlink_free(devlink);
index 113a3ef..6cd7fc9 100644 (file)
@@ -2461,7 +2461,7 @@ static int qlge_tso(struct sk_buff *skb, struct qlge_ob_mac_tso_iocb_req *mac_io
                mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC;
                mac_iocb_ptr->frame_len = cpu_to_le32((u32)skb->len);
                mac_iocb_ptr->total_hdrs_len =
-                       cpu_to_le16(skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       cpu_to_le16(skb_tcp_all_headers(skb));
                mac_iocb_ptr->net_trans_offset =
                        cpu_to_le16(skb_network_offset(skb) |
                                    skb_transport_offset(skb)
diff --git a/include/dt-bindings/net/pcs-rzn1-miic.h b/include/dt-bindings/net/pcs-rzn1-miic.h
new file mode 100644 (file)
index 0000000..784782e
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2022 Schneider-Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#ifndef _DT_BINDINGS_PCS_RZN1_MIIC
+#define _DT_BINDINGS_PCS_RZN1_MIIC
+
+/*
+ * Reefer to the datasheet [1] section 8.2.1, Internal Connection of Ethernet
+ * Ports to check the available combination
+ *
+ * [1] REN_r01uh0750ej0140-rzn1-introduction_MAT_20210228.pdf
+ */
+
+#define MIIC_GMAC1_PORT                        0
+#define MIIC_GMAC2_PORT                        1
+#define MIIC_RTOS_PORT                 2
+#define MIIC_SERCOS_PORTA              3
+#define MIIC_SERCOS_PORTB              4
+#define MIIC_ETHERCAT_PORTA            5
+#define MIIC_ETHERCAT_PORTB            6
+#define MIIC_ETHERCAT_PORTC            7
+#define MIIC_SWITCH_PORTA              8
+#define MIIC_SWITCH_PORTB              9
+#define MIIC_SWITCH_PORTC              10
+#define MIIC_SWITCH_PORTD              11
+#define MIIC_HSR_PORTA                 12
+#define MIIC_HSR_PORTB                 13
+
+#endif
index 2b914a5..0edd7d2 100644 (file)
@@ -5,6 +5,7 @@
 #define _LINUX_BPF_H 1
 
 #include <uapi/linux/bpf.h>
+#include <uapi/linux/filter.h>
 
 #include <linux/workqueue.h>
 #include <linux/file.h>
 #include <linux/sched/mm.h>
 #include <linux/slab.h>
 #include <linux/percpu-refcount.h>
+#include <linux/stddef.h>
 #include <linux/bpfptr.h>
 #include <linux/btf.h>
+#include <linux/rcupdate_trace.h>
 
 struct bpf_verifier_env;
 struct bpf_verifier_log;
@@ -398,6 +401,9 @@ enum bpf_type_flag {
        /* DYNPTR points to a ringbuf record. */
        DYNPTR_TYPE_RINGBUF     = BIT(9 + BPF_BASE_TYPE_BITS),
 
+       /* Size is known at compile time. */
+       MEM_FIXED_SIZE          = BIT(10 + BPF_BASE_TYPE_BITS),
+
        __BPF_TYPE_FLAG_MAX,
        __BPF_TYPE_LAST_FLAG    = __BPF_TYPE_FLAG_MAX - 1,
 };
@@ -461,6 +467,8 @@ enum bpf_arg_type {
         * all bytes or clear them in error case.
         */
        ARG_PTR_TO_UNINIT_MEM           = MEM_UNINIT | ARG_PTR_TO_MEM,
+       /* Pointer to valid memory of size known at compile time. */
+       ARG_PTR_TO_FIXED_SIZE_MEM       = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
 
        /* This must be the last entry. Its purpose is to ensure the enum is
         * wide enough to hold the higher bits reserved for bpf_type_flag.
@@ -526,6 +534,14 @@ struct bpf_func_proto {
                        u32 *arg5_btf_id;
                };
                u32 *arg_btf_id[5];
+               struct {
+                       size_t arg1_size;
+                       size_t arg2_size;
+                       size_t arg3_size;
+                       size_t arg4_size;
+                       size_t arg5_size;
+               };
+               size_t arg_size[5];
        };
        int *ret_btf_id; /* return value btf_id */
        bool (*allowed)(const struct bpf_prog *prog);
@@ -1084,6 +1100,40 @@ struct bpf_prog_aux {
        };
 };
 
+struct bpf_prog {
+       u16                     pages;          /* Number of allocated pages */
+       u16                     jited:1,        /* Is our filter JIT'ed? */
+                               jit_requested:1,/* archs need to JIT the prog */
+                               gpl_compatible:1, /* Is filter GPL compatible? */
+                               cb_access:1,    /* Is control block accessed? */
+                               dst_needed:1,   /* Do we need dst entry? */
+                               blinding_requested:1, /* needs constant blinding */
+                               blinded:1,      /* Was blinded */
+                               is_func:1,      /* program is a bpf function */
+                               kprobe_override:1, /* Do we override a kprobe? */
+                               has_callchain_buf:1, /* callchain buffer allocated? */
+                               enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */
+                               call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */
+                               call_get_func_ip:1, /* Do we call get_func_ip() */
+                               tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */
+       enum bpf_prog_type      type;           /* Type of BPF program */
+       enum bpf_attach_type    expected_attach_type; /* For some prog types */
+       u32                     len;            /* Number of filter blocks */
+       u32                     jited_len;      /* Size of jited insns in bytes */
+       u8                      tag[BPF_TAG_SIZE];
+       struct bpf_prog_stats __percpu *stats;
+       int __percpu            *active;
+       unsigned int            (*bpf_func)(const void *ctx,
+                                           const struct bpf_insn *insn);
+       struct bpf_prog_aux     *aux;           /* Auxiliary fields */
+       struct sock_fprog_kern  *orig_prog;     /* Original BPF program */
+       /* Instructions for interpreter */
+       union {
+               DECLARE_FLEX_ARRAY(struct sock_filter, insns);
+               DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi);
+       };
+};
+
 struct bpf_array_aux {
        /* Programs with direct jumps into programs part of this array. */
        struct list_head poke_progs;
@@ -1336,6 +1386,8 @@ extern struct bpf_empty_prog_array bpf_empty_prog_array;
 
 struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags);
 void bpf_prog_array_free(struct bpf_prog_array *progs);
+/* Use when traversal over the bpf_prog_array uses tasks_trace rcu */
+void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs);
 int bpf_prog_array_length(struct bpf_prog_array *progs);
 bool bpf_prog_array_is_empty(struct bpf_prog_array *array);
 int bpf_prog_array_copy_to_user(struct bpf_prog_array *progs,
@@ -1427,6 +1479,55 @@ bpf_prog_run_array(const struct bpf_prog_array *array,
        return ret;
 }
 
+/* Notes on RCU design for bpf_prog_arrays containing sleepable programs:
+ *
+ * We use the tasks_trace rcu flavor read section to protect the bpf_prog_array
+ * overall. As a result, we must use the bpf_prog_array_free_sleepable
+ * in order to use the tasks_trace rcu grace period.
+ *
+ * When a non-sleepable program is inside the array, we take the rcu read
+ * section and disable preemption for that program alone, so it can access
+ * rcu-protected dynamically sized maps.
+ */
+static __always_inline u32
+bpf_prog_run_array_sleepable(const struct bpf_prog_array __rcu *array_rcu,
+                            const void *ctx, bpf_prog_run_fn run_prog)
+{
+       const struct bpf_prog_array_item *item;
+       const struct bpf_prog *prog;
+       const struct bpf_prog_array *array;
+       struct bpf_run_ctx *old_run_ctx;
+       struct bpf_trace_run_ctx run_ctx;
+       u32 ret = 1;
+
+       might_fault();
+
+       rcu_read_lock_trace();
+       migrate_disable();
+
+       array = rcu_dereference_check(array_rcu, rcu_read_lock_trace_held());
+       if (unlikely(!array))
+               goto out;
+       old_run_ctx = bpf_set_run_ctx(&run_ctx.run_ctx);
+       item = &array->items[0];
+       while ((prog = READ_ONCE(item->prog))) {
+               if (!prog->aux->sleepable)
+                       rcu_read_lock();
+
+               run_ctx.bpf_cookie = item->bpf_cookie;
+               ret &= run_prog(prog, ctx);
+               item++;
+
+               if (!prog->aux->sleepable)
+                       rcu_read_unlock();
+       }
+       bpf_reset_run_ctx(old_run_ctx);
+out:
+       migrate_enable();
+       rcu_read_unlock_trace();
+       return ret;
+}
+
 #ifdef CONFIG_BPF_SYSCALL
 DECLARE_PER_CPU(int, bpf_prog_active);
 extern struct mutex bpf_stats_enabled_mutex;
@@ -2104,6 +2205,7 @@ int sock_map_bpf_prog_query(const union bpf_attr *attr,
                            union bpf_attr __user *uattr);
 
 void sock_map_unhash(struct sock *sk);
+void sock_map_destroy(struct sock *sk);
 void sock_map_close(struct sock *sk, long timeout);
 #else
 static inline int bpf_prog_offload_init(struct bpf_prog *prog,
@@ -2261,12 +2363,9 @@ extern const struct bpf_func_proto bpf_for_each_map_elem_proto;
 extern const struct bpf_func_proto bpf_btf_find_by_name_kind_proto;
 extern const struct bpf_func_proto bpf_sk_setsockopt_proto;
 extern const struct bpf_func_proto bpf_sk_getsockopt_proto;
-extern const struct bpf_func_proto bpf_kallsyms_lookup_name_proto;
 extern const struct bpf_func_proto bpf_find_vma_proto;
 extern const struct bpf_func_proto bpf_loop_proto;
-extern const struct bpf_func_proto bpf_strncmp_proto;
 extern const struct bpf_func_proto bpf_copy_from_user_task_proto;
-extern const struct bpf_func_proto bpf_kptr_xchg_proto;
 
 const struct bpf_func_proto *tracing_prog_func_proto(
   enum bpf_func_id func_id, const struct bpf_prog *prog);
index e8439f6..3930c96 100644 (file)
@@ -299,7 +299,7 @@ struct bpf_verifier_state {
         * If is_state_visited() sees a state with branches > 0 it means
         * there is a loop. If such state is exactly equal to the current state
         * it's an infinite loop. Note states_equal() checks for states
-        * equvalency, so two states being 'states_equal' does not mean
+        * equivalency, so two states being 'states_equal' does not mean
         * infinite loop. The exact comparison is provided by
         * states_maybe_looping() function. It's a stronger pre-check and
         * much faster than states_equal().
index 747fad2..6ff567e 100644 (file)
@@ -16,6 +16,7 @@
 #define PHY_ID_BCM5481                 0x0143bca0
 #define PHY_ID_BCM5395                 0x0143bcf0
 #define PHY_ID_BCM53125                        0x03625f20
+#define PHY_ID_BCM53128                        0x03625e10
 #define PHY_ID_BCM54810                        0x03625d00
 #define PHY_ID_BCM54811                        0x03625cc0
 #define PHY_ID_BCM5482                 0x0143bcb0
index 2611cea..1bfed7f 100644 (file)
@@ -177,6 +177,19 @@ static inline bool btf_type_is_enum(const struct btf_type *t)
        return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM;
 }
 
+static inline bool btf_is_any_enum(const struct btf_type *t)
+{
+       return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM ||
+              BTF_INFO_KIND(t->info) == BTF_KIND_ENUM64;
+}
+
+static inline bool btf_kind_core_compat(const struct btf_type *t1,
+                                       const struct btf_type *t2)
+{
+       return BTF_INFO_KIND(t1->info) == BTF_INFO_KIND(t2->info) ||
+              (btf_is_any_enum(t1) && btf_is_any_enum(t2));
+}
+
 static inline bool str_is_empty(const char *s)
 {
        return !s || !s[0];
@@ -192,6 +205,16 @@ static inline bool btf_is_enum(const struct btf_type *t)
        return btf_kind(t) == BTF_KIND_ENUM;
 }
 
+static inline bool btf_is_enum64(const struct btf_type *t)
+{
+       return btf_kind(t) == BTF_KIND_ENUM64;
+}
+
+static inline u64 btf_enum64_value(const struct btf_enum64 *e)
+{
+       return ((u64)e->val_hi32 << 32) | e->val_lo32;
+}
+
 static inline bool btf_is_composite(const struct btf_type *t)
 {
        u16 kind = btf_kind(t);
@@ -332,6 +355,11 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t)
        return (struct btf_enum *)(t + 1);
 }
 
+static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
+{
+       return (struct btf_enum64 *)(t + 1);
+}
+
 static inline const struct btf_var_secinfo *btf_type_var_secinfo(
                const struct btf_type *t)
 {
index 7ae21c0..ef0a771 100644 (file)
@@ -11,6 +11,8 @@
 
 #define CAN_SYNC_SEG 1
 
+#define CAN_BITRATE_UNSET 0
+#define CAN_BITRATE_UNKNOWN (-1U)
 
 #define CAN_CTRLMODE_TDC_MASK                                  \
        (CAN_CTRLMODE_TDC_AUTO | CAN_CTRLMODE_TDC_MANUAL)
index fdb22b0..182749e 100644 (file)
@@ -31,6 +31,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
                                struct canfd_frame **cfd);
 struct sk_buff *alloc_can_err_skb(struct net_device *dev,
                                  struct can_frame **cf);
+bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);
 
 /*
  * The struct can_skb_priv is used to transport additional information along
@@ -96,64 +97,6 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
        return nskb;
 }
 
-/* Check for outgoing skbs that have not been created by the CAN subsystem */
-static inline bool can_skb_headroom_valid(struct net_device *dev,
-                                         struct sk_buff *skb)
-{
-       /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
-       if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
-               return false;
-
-       /* af_packet does not apply CAN skb specific settings */
-       if (skb->ip_summed == CHECKSUM_NONE) {
-               /* init headroom */
-               can_skb_prv(skb)->ifindex = dev->ifindex;
-               can_skb_prv(skb)->skbcnt = 0;
-
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-               /* perform proper loopback on capable devices */
-               if (dev->flags & IFF_ECHO)
-                       skb->pkt_type = PACKET_LOOPBACK;
-               else
-                       skb->pkt_type = PACKET_HOST;
-
-               skb_reset_mac_header(skb);
-               skb_reset_network_header(skb);
-               skb_reset_transport_header(skb);
-       }
-
-       return true;
-}
-
-/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
-static inline bool can_dropped_invalid_skb(struct net_device *dev,
-                                         struct sk_buff *skb)
-{
-       const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
-
-       if (skb->protocol == htons(ETH_P_CAN)) {
-               if (unlikely(skb->len != CAN_MTU ||
-                            cfd->len > CAN_MAX_DLEN))
-                       goto inval_skb;
-       } else if (skb->protocol == htons(ETH_P_CANFD)) {
-               if (unlikely(skb->len != CANFD_MTU ||
-                            cfd->len > CANFD_MAX_DLEN))
-                       goto inval_skb;
-       } else
-               goto inval_skb;
-
-       if (!can_skb_headroom_valid(dev, skb))
-               goto inval_skb;
-
-       return false;
-
-inval_skb:
-       kfree_skb(skb);
-       dev->stats.tx_dropped++;
-       return true;
-}
-
 static inline bool can_is_canfd_skb(const struct sk_buff *skb)
 {
        /* the CAN specific type of skb is identified by its data length */
index ed0c0ff..d0cbb31 100644 (file)
@@ -559,40 +559,6 @@ struct bpf_prog_stats {
        struct u64_stats_sync syncp;
 } __aligned(2 * sizeof(u64));
 
-struct bpf_prog {
-       u16                     pages;          /* Number of allocated pages */
-       u16                     jited:1,        /* Is our filter JIT'ed? */
-                               jit_requested:1,/* archs need to JIT the prog */
-                               gpl_compatible:1, /* Is filter GPL compatible? */
-                               cb_access:1,    /* Is control block accessed? */
-                               dst_needed:1,   /* Do we need dst entry? */
-                               blinding_requested:1, /* needs constant blinding */
-                               blinded:1,      /* Was blinded */
-                               is_func:1,      /* program is a bpf function */
-                               kprobe_override:1, /* Do we override a kprobe? */
-                               has_callchain_buf:1, /* callchain buffer allocated? */
-                               enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */
-                               call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */
-                               call_get_func_ip:1, /* Do we call get_func_ip() */
-                               tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */
-       enum bpf_prog_type      type;           /* Type of BPF program */
-       enum bpf_attach_type    expected_attach_type; /* For some prog types */
-       u32                     len;            /* Number of filter blocks */
-       u32                     jited_len;      /* Size of jited insns in bytes */
-       u8                      tag[BPF_TAG_SIZE];
-       struct bpf_prog_stats __percpu *stats;
-       int __percpu            *active;
-       unsigned int            (*bpf_func)(const void *ctx,
-                                           const struct bpf_insn *insn);
-       struct bpf_prog_aux     *aux;           /* Auxiliary fields */
-       struct sock_fprog_kern  *orig_prog;     /* Original BPF program */
-       /* Instructions for interpreter */
-       union {
-               DECLARE_FLEX_ARRAY(struct sock_filter, insns);
-               DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi);
-       };
-};
-
 struct sk_filter {
        refcount_t      refcnt;
        struct rcu_head rcu;
index 75d40ac..5c65ae6 100644 (file)
@@ -76,6 +76,7 @@
 #define IEEE80211_STYPE_ACTION         0x00D0
 
 /* control */
+#define IEEE80211_STYPE_TRIGGER                0x0020
 #define IEEE80211_STYPE_CTL_EXT                0x0060
 #define IEEE80211_STYPE_BACK_REQ       0x0080
 #define IEEE80211_STYPE_BACK           0x0090
@@ -295,6 +296,17 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
 
 #define IEEE80211_HT_CTL_LEN           4
 
+/* trigger type within common_info of trigger frame */
+#define IEEE80211_TRIGGER_TYPE_MASK            0xf
+#define IEEE80211_TRIGGER_TYPE_BASIC           0x0
+#define IEEE80211_TRIGGER_TYPE_BFRP            0x1
+#define IEEE80211_TRIGGER_TYPE_MU_BAR          0x2
+#define IEEE80211_TRIGGER_TYPE_MU_RTS          0x3
+#define IEEE80211_TRIGGER_TYPE_BSRP            0x4
+#define IEEE80211_TRIGGER_TYPE_GCR_MU_BAR      0x5
+#define IEEE80211_TRIGGER_TYPE_BQRP            0x6
+#define IEEE80211_TRIGGER_TYPE_NFRP            0x7
+
 struct ieee80211_hdr {
        __le16 frame_control;
        __le16 duration_id;
@@ -324,6 +336,15 @@ struct ieee80211_qos_hdr {
        __le16 qos_ctrl;
 } __packed __aligned(2);
 
+struct ieee80211_trigger {
+       __le16 frame_control;
+       __le16 duration;
+       u8 ra[ETH_ALEN];
+       u8 ta[ETH_ALEN];
+       __le64 common_info;
+       u8 variable[];
+} __packed __aligned(2);
+
 /**
  * ieee80211_has_tods - check if IEEE80211_FCTL_TODS is set
  * @fc: frame control bytes in little-endian byteorder
@@ -730,6 +751,16 @@ static inline bool ieee80211_is_qos_nullfunc(__le16 fc)
 }
 
 /**
+ * ieee80211_is_trigger - check if frame is trigger frame
+ * @fc: frame control field in little-endian byteorder
+ */
+static inline bool ieee80211_is_trigger(__le16 fc)
+{
+       return (fc & cpu_to_le16(IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
+              cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_TRIGGER);
+}
+
+/**
  * ieee80211_is_any_nullfunc - check if frame is regular or QoS nullfunc frame
  * @fc: frame control bytes in little-endian byteorder
  */
index b422947..5230251 100644 (file)
@@ -46,10 +46,10 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan,
 
                pcpu_stats = get_cpu_ptr(vlan->pcpu_stats);
                u64_stats_update_begin(&pcpu_stats->syncp);
-               pcpu_stats->rx_packets++;
-               pcpu_stats->rx_bytes += len;
+               u64_stats_inc(&pcpu_stats->rx_packets);
+               u64_stats_add(&pcpu_stats->rx_bytes, len);
                if (multicast)
-                       pcpu_stats->rx_multicast++;
+                       u64_stats_inc(&pcpu_stats->rx_multicast);
                u64_stats_update_end(&pcpu_stats->syncp);
                put_cpu_ptr(vlan->pcpu_stats);
        } else {
index add6079..fc985e5 100644 (file)
 #include <uapi/linux/if_team.h>
 
 struct team_pcpu_stats {
-       u64                     rx_packets;
-       u64                     rx_bytes;
-       u64                     rx_multicast;
-       u64                     tx_packets;
-       u64                     tx_bytes;
+       u64_stats_t             rx_packets;
+       u64_stats_t             rx_bytes;
+       u64_stats_t             rx_multicast;
+       u64_stats_t             tx_packets;
+       u64_stats_t             tx_bytes;
        struct u64_stats_sync   syncp;
        u32                     rx_dropped;
        u32                     tx_dropped;
index 2be4dd7..e00c4ee 100644 (file)
@@ -118,11 +118,11 @@ static inline void vlan_drop_rx_stag_filter_info(struct net_device *dev)
  *     @tx_dropped: number of tx drops
  */
 struct vlan_pcpu_stats {
-       u64                     rx_packets;
-       u64                     rx_bytes;
-       u64                     rx_multicast;
-       u64                     tx_packets;
-       u64                     tx_bytes;
+       u64_stats_t             rx_packets;
+       u64_stats_t             rx_bytes;
+       u64_stats_t             rx_multicast;
+       u64_stats_t             tx_packets;
+       u64_stats_t             tx_bytes;
        struct u64_stats_sync   syncp;
        u32                     rx_errors;
        u32                     tx_dropped;
index 5ee1308..d5a959c 100644 (file)
@@ -545,4 +545,39 @@ static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
        return cap;
 }
 
+/**
+ * mii_bmcr_encode_fixed - encode fixed speed/duplex settings to a BMCR value
+ * @speed: a SPEED_* value
+ * @duplex: a DUPLEX_* value
+ *
+ * Encode the speed and duplex to a BMCR value. 2500, 1000, 100 and 10 Mbps are
+ * supported. 2500Mbps is encoded to 1000Mbps. Other speeds are encoded as 10
+ * Mbps. Unknown duplex values are encoded to half-duplex.
+ */
+static inline u16 mii_bmcr_encode_fixed(int speed, int duplex)
+{
+       u16 bmcr;
+
+       switch (speed) {
+       case SPEED_2500:
+       case SPEED_1000:
+               bmcr = BMCR_SPEED1000;
+               break;
+
+       case SPEED_100:
+               bmcr = BMCR_SPEED100;
+               break;
+
+       case SPEED_10:
+       default:
+               bmcr = BMCR_SPEED10;
+               break;
+       }
+
+       if (duplex == DUPLEX_FULL)
+               bmcr |= BMCR_FULLDPLX;
+
+       return bmcr;
+}
+
 #endif /* __LINUX_MII_H__ */
index 604b85d..b5f58fd 100644 (file)
@@ -387,21 +387,6 @@ enum {
 };
 
 enum {
-       MLX5_DEV_CAP_FLAG_XRC           = 1LL <<  3,
-       MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR = 1LL <<  8,
-       MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL <<  9,
-       MLX5_DEV_CAP_FLAG_APM           = 1LL << 17,
-       MLX5_DEV_CAP_FLAG_ATOMIC        = 1LL << 18,
-       MLX5_DEV_CAP_FLAG_BLOCK_MCAST   = 1LL << 23,
-       MLX5_DEV_CAP_FLAG_ON_DMND_PG    = 1LL << 24,
-       MLX5_DEV_CAP_FLAG_CQ_MODER      = 1LL << 29,
-       MLX5_DEV_CAP_FLAG_RESIZE_CQ     = 1LL << 30,
-       MLX5_DEV_CAP_FLAG_DCT           = 1LL << 37,
-       MLX5_DEV_CAP_FLAG_SIG_HAND_OVER = 1LL << 40,
-       MLX5_DEV_CAP_FLAG_CMDIF_CSUM    = 3LL << 46,
-};
-
-enum {
        MLX5_ROCE_VERSION_1             = 0,
        MLX5_ROCE_VERSION_2             = 2,
 };
@@ -455,6 +440,7 @@ enum {
 
        MLX5_OPCODE_UMR                 = 0x25,
 
+       MLX5_OPCODE_ACCESS_ASO          = 0x2d,
 };
 
 enum {
@@ -496,10 +482,6 @@ enum {
 };
 
 enum {
-       MLX5_CAP_OFF_CMDIF_CSUM         = 46,
-};
-
-enum {
        /*
         * Max wqe size for rdma read is 512 bytes, so this
         * limits our max_sge_rd as the wqe needs to fit:
@@ -840,7 +822,10 @@ struct mlx5_cqe64 {
        __be32          timestamp_l;
        __be32          sop_drop_qpn;
        __be16          wqe_counter;
-       u8              signature;
+       union {
+               u8      signature;
+               u8      validity_iteration_count;
+       };
        u8              op_own;
 };
 
@@ -872,6 +857,11 @@ enum {
        MLX5_CQE_FORMAT_CSUM_STRIDX = 0x3,
 };
 
+enum {
+       MLX5_CQE_COMPRESS_LAYOUT_BASIC = 0,
+       MLX5_CQE_COMPRESS_LAYOUT_ENHANCED = 1,
+};
+
 #define MLX5_MINI_CQE_ARRAY_SIZE 8
 
 static inline u8 mlx5_get_cqe_format(struct mlx5_cqe64 *cqe)
@@ -884,6 +874,12 @@ static inline u8 get_cqe_opcode(struct mlx5_cqe64 *cqe)
        return cqe->op_own >> 4;
 }
 
+static inline u8 get_cqe_enhanced_num_mini_cqes(struct mlx5_cqe64 *cqe)
+{
+       /* num_of_mini_cqes is zero based */
+       return get_cqe_opcode(cqe) + 1;
+}
+
 static inline u8 get_cqe_lro_tcppsh(struct mlx5_cqe64 *cqe)
 {
        return (cqe->lro.tcppsh_abort_dupack >> 6) & 1;
index 5040cd7..76d7661 100644 (file)
@@ -676,6 +676,7 @@ struct mlx5e_resources {
 enum mlx5_sw_icm_type {
        MLX5_SW_ICM_TYPE_STEERING,
        MLX5_SW_ICM_TYPE_HEADER_MODIFY,
+       MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN,
 };
 
 #define MLX5_MAX_RESERVED_GIDS 8
index 8b18fe9..e2701ed 100644 (file)
@@ -12,7 +12,6 @@
 #define MLX5_ESWITCH_MANAGER(mdev) MLX5_CAP_GEN(mdev, eswitch_manager)
 
 enum {
-       MLX5_ESWITCH_NONE,
        MLX5_ESWITCH_LEGACY,
        MLX5_ESWITCH_OFFLOADS
 };
@@ -153,7 +152,7 @@ struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitch *esw);
 
 static inline u8 mlx5_eswitch_mode(const struct mlx5_core_dev *dev)
 {
-       return MLX5_ESWITCH_NONE;
+       return MLX5_ESWITCH_LEGACY;
 }
 
 static inline enum devlink_eswitch_encap_mode
@@ -198,6 +197,11 @@ static inline struct mlx5_core_dev *mlx5_eswitch_get_core_dev(struct mlx5_eswitc
 
 #endif /* CONFIG_MLX5_ESWITCH */
 
+static inline bool is_mdev_legacy_mode(struct mlx5_core_dev *dev)
+{
+       return mlx5_eswitch_mode(dev) == MLX5_ESWITCH_LEGACY;
+}
+
 static inline bool is_mdev_switchdev_mode(struct mlx5_core_dev *dev)
 {
        return mlx5_eswitch_mode(dev) == MLX5_ESWITCH_OFFLOADS;
index 8135713..ece3e35 100644 (file)
@@ -212,6 +212,19 @@ struct mlx5_flow_group *
 mlx5_create_flow_group(struct mlx5_flow_table *ft, u32 *in);
 void mlx5_destroy_flow_group(struct mlx5_flow_group *fg);
 
+struct mlx5_exe_aso {
+       u32 object_id;
+       u8 type;
+       u8 return_reg_id;
+       union {
+               u32 ctrl_data;
+               struct {
+                       u8 meter_idx;
+                       u8 init_color;
+               } flow_meter;
+       };
+};
+
 struct mlx5_fs_vlan {
         u16 ethtype;
         u16 vid;
@@ -237,6 +250,7 @@ struct mlx5_flow_act {
        struct mlx5_fs_vlan vlan[MLX5_FS_VLAN_DEPTH];
        struct ib_counters *counters;
        struct mlx5_flow_group *fg;
+       struct mlx5_exe_aso exe_aso;
 };
 
 #define MLX5_DECLARE_FLOW_ACT(name) \
index fd7d083..8e87eb4 100644 (file)
@@ -442,7 +442,9 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
        u8         max_modify_header_actions[0x8];
        u8         max_ft_level[0x8];
 
-       u8         reserved_at_40[0x20];
+       u8         reserved_at_40[0x6];
+       u8         execute_aso[0x1];
+       u8         reserved_at_47[0x19];
 
        u8         reserved_at_60[0x2];
        u8         reformat_insert[0x1];
@@ -940,7 +942,17 @@ struct mlx5_ifc_qos_cap_bits {
 
        u8         max_tsar_bw_share[0x20];
 
-       u8         reserved_at_100[0x700];
+       u8         reserved_at_100[0x20];
+
+       u8         reserved_at_120[0x3];
+       u8         log_meter_aso_granularity[0x5];
+       u8         reserved_at_128[0x3];
+       u8         log_meter_aso_max_alloc[0x5];
+       u8         reserved_at_130[0x3];
+       u8         log_max_num_meter_aso[0x5];
+       u8         reserved_at_138[0x8];
+
+       u8         reserved_at_140[0x6c0];
 };
 
 struct mlx5_ifc_debug_cap_bits {
@@ -1086,11 +1098,14 @@ struct mlx5_ifc_device_mem_cap_bits {
        u8         log_sw_icm_alloc_granularity[0x6];
        u8         log_steering_sw_icm_size[0x8];
 
-       u8         reserved_at_120[0x20];
+       u8         reserved_at_120[0x18];
+       u8         log_header_modify_pattern_sw_icm_size[0x8];
 
        u8         header_modify_sw_icm_start_address[0x40];
 
-       u8         reserved_at_180[0x80];
+       u8         reserved_at_180[0x40];
+
+       u8         header_modify_pattern_sw_icm_start_address[0x40];
 
        u8         memic_operations[0x20];
 
@@ -1426,7 +1441,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
 
        u8         reserved_at_120[0xa];
        u8         log_max_ra_req_dc[0x6];
-       u8         reserved_at_130[0xa];
+       u8         reserved_at_130[0x9];
+       u8         vnic_env_cq_overrun[0x1];
        u8         log_max_ra_res_dc[0x6];
 
        u8         reserved_at_140[0x5];
@@ -1621,7 +1637,11 @@ struct mlx5_ifc_cmd_hca_cap_bits {
        u8         nic_receive_steering_discard[0x1];
        u8         receive_discard_vport_down[0x1];
        u8         transmit_discard_vport_down[0x1];
-       u8         reserved_at_343[0x5];
+       u8         eq_overrun_count[0x1];
+       u8         reserved_at_344[0x1];
+       u8         invalid_command_count[0x1];
+       u8         quota_exceeded_count[0x1];
+       u8         reserved_at_347[0x1];
        u8         log_max_flow_counter_bulk[0x8];
        u8         max_flow_counter_15_0[0x10];
 
@@ -1719,7 +1739,9 @@ struct mlx5_ifc_cmd_hca_cap_bits {
        u8         log_max_dci_errored_streams[0x5];
        u8         reserved_at_598[0x8];
 
-       u8         reserved_at_5a0[0x13];
+       u8         reserved_at_5a0[0x10];
+       u8         enhanced_cqe_compression[0x1];
+       u8         reserved_at_5b1[0x2];
        u8         log_max_dek[0x5];
        u8         reserved_at_5b8[0x4];
        u8         mini_cqe_resp_stride_index[0x1];
@@ -3277,6 +3299,7 @@ enum {
        MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH_2 = 0x800,
        MLX5_FLOW_CONTEXT_ACTION_IPSEC_DECRYPT = 0x1000,
        MLX5_FLOW_CONTEXT_ACTION_IPSEC_ENCRYPT = 0x2000,
+       MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO = 0x4000,
 };
 
 enum {
@@ -3292,6 +3315,38 @@ struct mlx5_ifc_vlan_bits {
        u8         vid[0xc];
 };
 
+enum {
+       MLX5_FLOW_METER_COLOR_RED       = 0x0,
+       MLX5_FLOW_METER_COLOR_YELLOW    = 0x1,
+       MLX5_FLOW_METER_COLOR_GREEN     = 0x2,
+       MLX5_FLOW_METER_COLOR_UNDEFINED = 0x3,
+};
+
+enum {
+       MLX5_EXE_ASO_FLOW_METER         = 0x2,
+};
+
+struct mlx5_ifc_exe_aso_ctrl_flow_meter_bits {
+       u8        return_reg_id[0x4];
+       u8        aso_type[0x4];
+       u8        reserved_at_8[0x14];
+       u8        action[0x1];
+       u8        init_color[0x2];
+       u8        meter_id[0x1];
+};
+
+union mlx5_ifc_exe_aso_ctrl {
+       struct mlx5_ifc_exe_aso_ctrl_flow_meter_bits exe_aso_ctrl_flow_meter;
+};
+
+struct mlx5_ifc_execute_aso_bits {
+       u8        valid[0x1];
+       u8        reserved_at_1[0x7];
+       u8        aso_object_id[0x18];
+
+       union mlx5_ifc_exe_aso_ctrl exe_aso_ctrl;
+};
+
 struct mlx5_ifc_flow_context_bits {
        struct mlx5_ifc_vlan_bits push_vlan;
 
@@ -3323,7 +3378,9 @@ struct mlx5_ifc_flow_context_bits {
 
        struct mlx5_ifc_fte_match_param_bits match_value;
 
-       u8         reserved_at_1200[0x600];
+       struct mlx5_ifc_execute_aso_bits execute_aso[4];
+
+       u8         reserved_at_1300[0x500];
 
        union mlx5_ifc_dest_format_struct_flow_counter_list_auto_bits destination[];
 };
@@ -3391,11 +3448,21 @@ struct mlx5_ifc_vnic_diagnostic_statistics_bits {
 
        u8         transmit_discard_vport_down[0x40];
 
-       u8         reserved_at_140[0xa0];
+       u8         async_eq_overrun[0x20];
+
+       u8         comp_eq_overrun[0x20];
+
+       u8         reserved_at_180[0x20];
+
+       u8         invalid_command[0x20];
+
+       u8         quota_exceeded_command[0x20];
 
        u8         internal_rq_out_of_buffer[0x20];
 
-       u8         reserved_at_200[0xe00];
+       u8         cq_overrun[0x20];
+
+       u8         reserved_at_220[0xde0];
 };
 
 struct mlx5_ifc_traffic_counter_bits {
@@ -4074,7 +4141,8 @@ struct mlx5_ifc_cqc_bits {
        u8         cqe_comp_en[0x1];
        u8         mini_cqe_res_format[0x2];
        u8         st[0x4];
-       u8         reserved_at_18[0x8];
+       u8         reserved_at_18[0x6];
+       u8         cqe_compression_layout[0x2];
 
        u8         reserved_at_20[0x20];
 
@@ -5970,7 +6038,9 @@ struct mlx5_ifc_general_obj_in_cmd_hdr_bits {
 
        u8         obj_id[0x20];
 
-       u8         reserved_at_60[0x20];
+       u8         reserved_at_60[0x3];
+       u8         log_obj_range[0x5];
+       u8         reserved_at_68[0x18];
 };
 
 struct mlx5_ifc_general_obj_out_cmd_hdr_bits {
@@ -11370,12 +11440,14 @@ enum {
        MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = BIT_ULL(0xc),
        MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_IPSEC = BIT_ULL(0x13),
        MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_SAMPLER = BIT_ULL(0x20),
+       MLX5_HCA_CAP_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = BIT_ULL(0x24),
 };
 
 enum {
        MLX5_GENERAL_OBJECT_TYPES_ENCRYPTION_KEY = 0xc,
        MLX5_GENERAL_OBJECT_TYPES_IPSEC = 0x13,
        MLX5_GENERAL_OBJECT_TYPES_SAMPLER = 0x20,
+       MLX5_GENERAL_OBJECT_TYPES_FLOW_METER_ASO = 0x24,
 };
 
 enum {
@@ -11448,6 +11520,61 @@ struct mlx5_ifc_create_encryption_key_in_bits {
        struct mlx5_ifc_encryption_key_obj_bits encryption_key_object;
 };
 
+enum {
+       MLX5_FLOW_METER_MODE_BYTES_IP_LENGTH            = 0x0,
+       MLX5_FLOW_METER_MODE_BYTES_CALC_WITH_L2         = 0x1,
+       MLX5_FLOW_METER_MODE_BYTES_CALC_WITH_L2_IPG     = 0x2,
+       MLX5_FLOW_METER_MODE_NUM_PACKETS                = 0x3,
+};
+
+struct mlx5_ifc_flow_meter_parameters_bits {
+       u8         valid[0x1];
+       u8         bucket_overflow[0x1];
+       u8         start_color[0x2];
+       u8         both_buckets_on_green[0x1];
+       u8         reserved_at_5[0x1];
+       u8         meter_mode[0x2];
+       u8         reserved_at_8[0x18];
+
+       u8         reserved_at_20[0x20];
+
+       u8         reserved_at_40[0x3];
+       u8         cbs_exponent[0x5];
+       u8         cbs_mantissa[0x8];
+       u8         reserved_at_50[0x3];
+       u8         cir_exponent[0x5];
+       u8         cir_mantissa[0x8];
+
+       u8         reserved_at_60[0x20];
+
+       u8         reserved_at_80[0x3];
+       u8         ebs_exponent[0x5];
+       u8         ebs_mantissa[0x8];
+       u8         reserved_at_90[0x3];
+       u8         eir_exponent[0x5];
+       u8         eir_mantissa[0x8];
+
+       u8         reserved_at_a0[0x60];
+};
+
+struct mlx5_ifc_flow_meter_aso_obj_bits {
+       u8         modify_field_select[0x40];
+
+       u8         reserved_at_40[0x40];
+
+       u8         reserved_at_80[0x8];
+       u8         meter_aso_access_pd[0x18];
+
+       u8         reserved_at_a0[0x160];
+
+       struct mlx5_ifc_flow_meter_parameters_bits flow_meter_parameters[2];
+};
+
+struct mlx5_ifc_create_flow_meter_aso_obj_in_bits {
+       struct mlx5_ifc_general_obj_in_cmd_hdr_bits hdr;
+       struct mlx5_ifc_flow_meter_aso_obj_bits flow_meter_aso_obj;
+};
+
 struct mlx5_ifc_sampler_obj_bits {
        u8         modify_field_select[0x40];
 
index e05ee9f..9dd4bf1 100644 (file)
@@ -26,7 +26,7 @@
  * @remote: Remote address for tunnels
  */
 struct vif_device {
-       struct net_device *dev;
+       struct net_device __rcu *dev;
        netdevice_tracker dev_tracker;
        unsigned long bytes_in, bytes_out;
        unsigned long pkt_in, pkt_out;
@@ -52,6 +52,7 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb,
                                       unsigned short family,
                                       enum fib_event_type event_type,
                                       struct vif_device *vif,
+                                      struct net_device *vif_dev,
                                       unsigned short vif_index, u32 tb_id,
                                       struct netlink_ext_ack *extack)
 {
@@ -60,7 +61,7 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb,
                        .family = family,
                        .extack = extack,
                },
-               .dev = vif->dev,
+               .dev = vif_dev,
                .vif_index = vif_index,
                .vif_flags = vif->flags,
                .tb_id = tb_id,
@@ -73,6 +74,7 @@ static inline int mr_call_vif_notifiers(struct net *net,
                                        unsigned short family,
                                        enum fib_event_type event_type,
                                        struct vif_device *vif,
+                                       struct net_device *vif_dev,
                                        unsigned short vif_index, u32 tb_id,
                                        unsigned int *ipmr_seq)
 {
@@ -80,7 +82,7 @@ static inline int mr_call_vif_notifiers(struct net *net,
                .info = {
                        .family = family,
                },
-               .dev = vif->dev,
+               .dev = vif_dev,
                .vif_index = vif_index,
                .vif_flags = vif->flags,
                .tb_id = tb_id,
@@ -98,7 +100,8 @@ static inline int mr_call_vif_notifiers(struct net *net,
 #define MAXVIFS        32
 #endif
 
-#define VIF_EXISTS(_mrt, _idx) (!!((_mrt)->vif_table[_idx].dev))
+/* Note: This helper is deprecated. */
+#define VIF_EXISTS(_mrt, _idx) (!!rcu_access_pointer((_mrt)->vif_table[_idx].dev))
 
 /* mfc_flags:
  * MFC_STATIC - the entry was added statically (not by a routing daemon)
@@ -305,7 +308,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
                              struct netlink_ext_ack *extack),
            struct mr_table *(*mr_iter)(struct net *net,
                                        struct mr_table *mrt),
-           rwlock_t *mrt_lock, struct netlink_ext_ack *extack);
+           struct netlink_ext_ack *extack);
 #else
 static inline void vif_device_init(struct vif_device *v,
                                   struct net_device *dev,
@@ -360,7 +363,7 @@ static inline int mr_dump(struct net *net, struct notifier_block *nb,
                                            struct netlink_ext_ack *extack),
                          struct mr_table *(*mr_iter)(struct net *net,
                                                      struct mr_table *mrt),
-                         rwlock_t *mrt_lock, struct netlink_ext_ack *extack)
+                         struct netlink_ext_ack *extack)
 {
        return -EINVAL;
 }
index 2563d30..1a3cb93 100644 (file)
@@ -2636,10 +2636,10 @@ struct packet_offload {
 
 /* often modified stats are per-CPU, other are shared (netdev->stats) */
 struct pcpu_sw_netstats {
-       u64     rx_packets;
-       u64     rx_bytes;
-       u64     tx_packets;
-       u64     tx_bytes;
+       u64_stats_t             rx_packets;
+       u64_stats_t             rx_bytes;
+       u64_stats_t             tx_packets;
+       u64_stats_t             tx_bytes;
        struct u64_stats_sync   syncp;
 } __aligned(4 * sizeof(u64));
 
@@ -2656,8 +2656,8 @@ static inline void dev_sw_netstats_rx_add(struct net_device *dev, unsigned int l
        struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
 
        u64_stats_update_begin(&tstats->syncp);
-       tstats->rx_bytes += len;
-       tstats->rx_packets++;
+       u64_stats_add(&tstats->rx_bytes, len);
+       u64_stats_inc(&tstats->rx_packets);
        u64_stats_update_end(&tstats->syncp);
 }
 
@@ -2668,8 +2668,8 @@ static inline void dev_sw_netstats_tx_add(struct net_device *dev,
        struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
 
        u64_stats_update_begin(&tstats->syncp);
-       tstats->tx_bytes += len;
-       tstats->tx_packets += packets;
+       u64_stats_add(&tstats->tx_bytes, len);
+       u64_stats_add(&tstats->tx_packets, packets);
        u64_stats_update_end(&tstats->syncp);
 }
 
@@ -3981,8 +3981,8 @@ static inline void netdev_tracker_free(struct net_device *dev,
 #endif
 }
 
-static inline void dev_hold_track(struct net_device *dev,
-                                 netdevice_tracker *tracker, gfp_t gfp)
+static inline void netdev_hold(struct net_device *dev,
+                              netdevice_tracker *tracker, gfp_t gfp)
 {
        if (dev) {
                __dev_hold(dev);
@@ -3990,8 +3990,8 @@ static inline void dev_hold_track(struct net_device *dev,
        }
 }
 
-static inline void dev_put_track(struct net_device *dev,
-                                netdevice_tracker *tracker)
+static inline void netdev_put(struct net_device *dev,
+                             netdevice_tracker *tracker)
 {
        if (dev) {
                netdev_tracker_free(dev, tracker);
@@ -4004,11 +4004,11 @@ static inline void dev_put_track(struct net_device *dev,
  *     @dev: network device
  *
  * Hold reference to device to keep it from being freed.
- * Try using dev_hold_track() instead.
+ * Try using netdev_hold() instead.
  */
 static inline void dev_hold(struct net_device *dev)
 {
-       dev_hold_track(dev, NULL, GFP_ATOMIC);
+       netdev_hold(dev, NULL, GFP_ATOMIC);
 }
 
 /**
@@ -4016,17 +4016,17 @@ static inline void dev_hold(struct net_device *dev)
  *     @dev: network device
  *
  * Release reference to device to allow it to be freed.
- * Try using dev_put_track() instead.
+ * Try using netdev_put() instead.
  */
 static inline void dev_put(struct net_device *dev)
 {
-       dev_put_track(dev, NULL);
+       netdev_put(dev, NULL);
 }
 
-static inline void dev_replace_track(struct net_device *odev,
-                                    struct net_device *ndev,
-                                    netdevice_tracker *tracker,
-                                    gfp_t gfp)
+static inline void netdev_ref_replace(struct net_device *odev,
+                                     struct net_device *ndev,
+                                     netdevice_tracker *tracker,
+                                     gfp_t gfp)
 {
        if (odev)
                netdev_tracker_free(odev, tracker);
diff --git a/include/linux/pcs-rzn1-miic.h b/include/linux/pcs-rzn1-miic.h
new file mode 100644 (file)
index 0000000..56d12b2
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022 Schneider Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#ifndef __LINUX_PCS_MIIC_H
+#define __LINUX_PCS_MIIC_H
+
+struct phylink;
+struct device_node;
+
+struct phylink_pcs *miic_create(struct device *dev, struct device_node *np);
+
+void miic_destroy(struct phylink_pcs *pcs);
+
+#endif /* __LINUX_PCS_MIIC_H */
index 266eb26..d2da1e0 100644 (file)
@@ -17,6 +17,7 @@
 #define DW_AN_C73                      1
 #define DW_AN_C37_SGMII                        2
 #define DW_2500BASEX                   3
+#define DW_AN_C37_1000BASEX            4
 
 struct xpcs_id;
 
@@ -30,7 +31,7 @@ int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface);
 void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
                  phy_interface_t interface, int speed, int duplex);
 int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
-                  unsigned int mode);
+                  unsigned int mode, const unsigned long *advertising);
 void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces);
 int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns,
                    int enable);
index b09f7d3..87638c5 100644 (file)
@@ -1545,6 +1545,9 @@ static inline void phy_device_reset(struct phy_device *phydev, int value)
 #define phydev_err(_phydev, format, args...)   \
        dev_err(&_phydev->mdio.dev, format, ##args)
 
+#define phydev_err_probe(_phydev, err, format, args...)        \
+       dev_err_probe(&_phydev->mdio.dev, err, format, ##args)
+
 #define phydev_info(_phydev, format, args...)  \
        dev_info(&_phydev->mdio.dev, format, ##args)
 
index d3d1055..f6a27ab 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/netfilter/nf_conntrack_common.h>
 #endif
 #include <net/net_debug.h>
+#include <net/dropreason.h>
 
 /**
  * DOC: skb checksums
@@ -337,184 +338,6 @@ struct sk_buff_head {
 
 struct sk_buff;
 
-/* The reason of skb drop, which is used in kfree_skb_reason().
- * en...maybe they should be splited by group?
- *
- * Each item here should also be in 'TRACE_SKB_DROP_REASON', which is
- * used to translate the reason to string.
- */
-enum skb_drop_reason {
-       SKB_NOT_DROPPED_YET = 0,
-       SKB_DROP_REASON_NOT_SPECIFIED,  /* drop reason is not specified */
-       SKB_DROP_REASON_NO_SOCKET,      /* socket not found */
-       SKB_DROP_REASON_PKT_TOO_SMALL,  /* packet size is too small */
-       SKB_DROP_REASON_TCP_CSUM,       /* TCP checksum error */
-       SKB_DROP_REASON_SOCKET_FILTER,  /* dropped by socket filter */
-       SKB_DROP_REASON_UDP_CSUM,       /* UDP checksum error */
-       SKB_DROP_REASON_NETFILTER_DROP, /* dropped by netfilter */
-       SKB_DROP_REASON_OTHERHOST,      /* packet don't belong to current
-                                        * host (interface is in promisc
-                                        * mode)
-                                        */
-       SKB_DROP_REASON_IP_CSUM,        /* IP checksum error */
-       SKB_DROP_REASON_IP_INHDR,       /* there is something wrong with
-                                        * IP header (see
-                                        * IPSTATS_MIB_INHDRERRORS)
-                                        */
-       SKB_DROP_REASON_IP_RPFILTER,    /* IP rpfilter validate failed.
-                                        * see the document for rp_filter
-                                        * in ip-sysctl.rst for more
-                                        * information
-                                        */
-       SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST, /* destination address of L2
-                                                 * is multicast, but L3 is
-                                                 * unicast.
-                                                 */
-       SKB_DROP_REASON_XFRM_POLICY,    /* xfrm policy check failed */
-       SKB_DROP_REASON_IP_NOPROTO,     /* no support for IP protocol */
-       SKB_DROP_REASON_SOCKET_RCVBUFF, /* socket receive buff is full */
-       SKB_DROP_REASON_PROTO_MEM,      /* proto memory limition, such as
-                                        * udp packet drop out of
-                                        * udp_memory_allocated.
-                                        */
-       SKB_DROP_REASON_TCP_MD5NOTFOUND,        /* no MD5 hash and one
-                                                * expected, corresponding
-                                                * to LINUX_MIB_TCPMD5NOTFOUND
-                                                */
-       SKB_DROP_REASON_TCP_MD5UNEXPECTED,      /* MD5 hash and we're not
-                                                * expecting one, corresponding
-                                                * to LINUX_MIB_TCPMD5UNEXPECTED
-                                                */
-       SKB_DROP_REASON_TCP_MD5FAILURE, /* MD5 hash and its wrong,
-                                        * corresponding to
-                                        * LINUX_MIB_TCPMD5FAILURE
-                                        */
-       SKB_DROP_REASON_SOCKET_BACKLOG, /* failed to add skb to socket
-                                        * backlog (see
-                                        * LINUX_MIB_TCPBACKLOGDROP)
-                                        */
-       SKB_DROP_REASON_TCP_FLAGS,      /* TCP flags invalid */
-       SKB_DROP_REASON_TCP_ZEROWINDOW, /* TCP receive window size is zero,
-                                        * see LINUX_MIB_TCPZEROWINDOWDROP
-                                        */
-       SKB_DROP_REASON_TCP_OLD_DATA,   /* the TCP data reveived is already
-                                        * received before (spurious retrans
-                                        * may happened), see
-                                        * LINUX_MIB_DELAYEDACKLOST
-                                        */
-       SKB_DROP_REASON_TCP_OVERWINDOW, /* the TCP data is out of window,
-                                        * the seq of the first byte exceed
-                                        * the right edges of receive
-                                        * window
-                                        */
-       SKB_DROP_REASON_TCP_OFOMERGE,   /* the data of skb is already in
-                                        * the ofo queue, corresponding to
-                                        * LINUX_MIB_TCPOFOMERGE
-                                        */
-       SKB_DROP_REASON_TCP_RFC7323_PAWS, /* PAWS check, corresponding to
-                                          * LINUX_MIB_PAWSESTABREJECTED
-                                          */
-       SKB_DROP_REASON_TCP_INVALID_SEQUENCE, /* Not acceptable SEQ field */
-       SKB_DROP_REASON_TCP_RESET,      /* Invalid RST packet */
-       SKB_DROP_REASON_TCP_INVALID_SYN, /* Incoming packet has unexpected SYN flag */
-       SKB_DROP_REASON_TCP_CLOSE,      /* TCP socket in CLOSE state */
-       SKB_DROP_REASON_TCP_FASTOPEN,   /* dropped by FASTOPEN request socket */
-       SKB_DROP_REASON_TCP_OLD_ACK,    /* TCP ACK is old, but in window */
-       SKB_DROP_REASON_TCP_TOO_OLD_ACK, /* TCP ACK is too old */
-       SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, /* TCP ACK for data we haven't sent yet */
-       SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE, /* pruned from TCP OFO queue */
-       SKB_DROP_REASON_TCP_OFO_DROP,   /* data already in receive queue */
-       SKB_DROP_REASON_IP_OUTNOROUTES, /* route lookup failed */
-       SKB_DROP_REASON_BPF_CGROUP_EGRESS,      /* dropped by
-                                                * BPF_PROG_TYPE_CGROUP_SKB
-                                                * eBPF program
-                                                */
-       SKB_DROP_REASON_IPV6DISABLED,   /* IPv6 is disabled on the device */
-       SKB_DROP_REASON_NEIGH_CREATEFAIL,       /* failed to create neigh
-                                                * entry
-                                                */
-       SKB_DROP_REASON_NEIGH_FAILED,   /* neigh entry in failed state */
-       SKB_DROP_REASON_NEIGH_QUEUEFULL,        /* arp_queue for neigh
-                                                * entry is full
-                                                */
-       SKB_DROP_REASON_NEIGH_DEAD,     /* neigh entry is dead */
-       SKB_DROP_REASON_TC_EGRESS,      /* dropped in TC egress HOOK */
-       SKB_DROP_REASON_QDISC_DROP,     /* dropped by qdisc when packet
-                                        * outputting (failed to enqueue to
-                                        * current qdisc)
-                                        */
-       SKB_DROP_REASON_CPU_BACKLOG,    /* failed to enqueue the skb to
-                                        * the per CPU backlog queue. This
-                                        * can be caused by backlog queue
-                                        * full (see netdev_max_backlog in
-                                        * net.rst) or RPS flow limit
-                                        */
-       SKB_DROP_REASON_XDP,            /* dropped by XDP in input path */
-       SKB_DROP_REASON_TC_INGRESS,     /* dropped in TC ingress HOOK */
-       SKB_DROP_REASON_UNHANDLED_PROTO,        /* protocol not implemented
-                                                * or not supported
-                                                */
-       SKB_DROP_REASON_SKB_CSUM,       /* sk_buff checksum computation
-                                        * error
-                                        */
-       SKB_DROP_REASON_SKB_GSO_SEG,    /* gso segmentation error */
-       SKB_DROP_REASON_SKB_UCOPY_FAULT,        /* failed to copy data from
-                                                * user space, e.g., via
-                                                * zerocopy_sg_from_iter()
-                                                * or skb_orphan_frags_rx()
-                                                */
-       SKB_DROP_REASON_DEV_HDR,        /* device driver specific
-                                        * header/metadata is invalid
-                                        */
-       /* the device is not ready to xmit/recv due to any of its data
-        * structure that is not up/ready/initialized, e.g., the IFF_UP is
-        * not set, or driver specific tun->tfiles[txq] is not initialized
-        */
-       SKB_DROP_REASON_DEV_READY,
-       SKB_DROP_REASON_FULL_RING,      /* ring buffer is full */
-       SKB_DROP_REASON_NOMEM,          /* error due to OOM */
-       SKB_DROP_REASON_HDR_TRUNC,      /* failed to trunc/extract the header
-                                        * from networking data, e.g., failed
-                                        * to pull the protocol header from
-                                        * frags via pskb_may_pull()
-                                        */
-       SKB_DROP_REASON_TAP_FILTER,     /* dropped by (ebpf) filter directly
-                                        * attached to tun/tap, e.g., via
-                                        * TUNSETFILTEREBPF
-                                        */
-       SKB_DROP_REASON_TAP_TXFILTER,   /* dropped by tx filter implemented
-                                        * at tun/tap, e.g., check_filter()
-                                        */
-       SKB_DROP_REASON_ICMP_CSUM,      /* ICMP checksum error */
-       SKB_DROP_REASON_INVALID_PROTO,  /* the packet doesn't follow RFC
-                                        * 2211, such as a broadcasts
-                                        * ICMP_TIMESTAMP
-                                        */
-       SKB_DROP_REASON_IP_INADDRERRORS,        /* host unreachable, corresponding
-                                                * to IPSTATS_MIB_INADDRERRORS
-                                                */
-       SKB_DROP_REASON_IP_INNOROUTES,  /* network unreachable, corresponding
-                                        * to IPSTATS_MIB_INADDRERRORS
-                                        */
-       SKB_DROP_REASON_PKT_TOO_BIG,    /* packet size is too big (maybe exceed
-                                        * the MTU)
-                                        */
-       SKB_DROP_REASON_MAX,
-};
-
-#define SKB_DR_INIT(name, reason)                              \
-       enum skb_drop_reason name = SKB_DROP_REASON_##reason
-#define SKB_DR(name)                                           \
-       SKB_DR_INIT(name, NOT_SPECIFIED)
-#define SKB_DR_SET(name, reason)                               \
-       (name = SKB_DROP_REASON_##reason)
-#define SKB_DR_OR(name, reason)                                        \
-       do {                                                    \
-               if (name == SKB_DROP_REASON_NOT_SPECIFIED ||    \
-                   name == SKB_NOT_DROPPED_YET)                \
-                       SKB_DR_SET(name, reason);               \
-       } while (0)
-
 /* To allow 64K frame to be packed as single skb without frag_list we
  * require 64K/PAGE_SIZE pages plus 1 additional page to allow for
  * buffers which do not start on a page boundary.
@@ -2529,6 +2352,18 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb)
 }
 
 /**
+ * skb_len_add - adds a number to len fields of skb
+ * @skb: buffer to add len to
+ * @delta: number of bytes to add
+ */
+static inline void skb_len_add(struct sk_buff *skb, int delta)
+{
+       skb->len += delta;
+       skb->data_len += delta;
+       skb->truesize += delta;
+}
+
+/**
  * __skb_fill_page_desc - initialise a paged fragment in an skb
  * @skb: buffer containing fragment to be initialised
  * @i: paged fragment index to initialise
@@ -2940,8 +2775,14 @@ static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
        skb->network_header += offset;
 }
 
+static inline int skb_mac_header_was_set(const struct sk_buff *skb)
+{
+       return skb->mac_header != (typeof(skb->mac_header))~0U;
+}
+
 static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
 {
+       DEBUG_NET_WARN_ON_ONCE(!skb_mac_header_was_set(skb));
        return skb->head + skb->mac_header;
 }
 
@@ -2952,14 +2793,10 @@ static inline int skb_mac_offset(const struct sk_buff *skb)
 
 static inline u32 skb_mac_header_len(const struct sk_buff *skb)
 {
+       DEBUG_NET_WARN_ON_ONCE(!skb_mac_header_was_set(skb));
        return skb->network_header - skb->mac_header;
 }
 
-static inline int skb_mac_header_was_set(const struct sk_buff *skb)
-{
-       return skb->mac_header != (typeof(skb->mac_header))~0U;
-}
-
 static inline void skb_unset_mac_header(struct sk_buff *skb)
 {
        skb->mac_header = (typeof(skb->mac_header))~0U;
index c5a2d6f..153b6de 100644 (file)
@@ -95,6 +95,7 @@ struct sk_psock {
        spinlock_t                      link_lock;
        refcount_t                      refcnt;
        void (*saved_unhash)(struct sock *sk);
+       void (*saved_destroy)(struct sock *sk);
        void (*saved_close)(struct sock *sk, long timeout);
        void (*saved_write_space)(struct sock *sk);
        void (*saved_data_ready)(struct sock *sk);
index 17311ad..414b8c7 100644 (file)
@@ -428,10 +428,6 @@ extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
 extern int __sys_sendto(int fd, void __user *buff, size_t len,
                        unsigned int flags, struct sockaddr __user *addr,
                        int addr_len);
-extern int __sys_accept4_file(struct file *file, unsigned file_flags,
-                       struct sockaddr __user *upeer_sockaddr,
-                        int __user *upeer_addrlen, int flags,
-                        unsigned long nofile);
 extern struct file *do_accept(struct file *file, unsigned file_flags,
                              struct sockaddr __user *upeer_sockaddr,
                              int __user *upeer_addrlen, int flags);
index ea19341..d45902f 100644 (file)
@@ -102,4 +102,12 @@ static inline long strncpy_from_sockptr(char *dst, sockptr_t src, size_t count)
        return strncpy_from_user(dst, src.user, count);
 }
 
+static inline int check_zeroed_sockptr(sockptr_t src, size_t offset,
+                                      size_t size)
+{
+       if (!sockptr_is_kernel(src))
+               return check_zeroed_user(src.user + offset, size);
+       return memchr_inv(src.kernel + offset, 0, size) == NULL;
+}
+
 #endif /* _LINUX_SOCKPTR_H */
index 80263f7..17b42ce 100644 (file)
@@ -75,6 +75,8 @@ int proc_douintvec_minmax(struct ctl_table *table, int write, void *buffer,
 int proc_dou8vec_minmax(struct ctl_table *table, int write, void *buffer,
                        size_t *lenp, loff_t *ppos);
 int proc_dointvec_jiffies(struct ctl_table *, int, void *, size_t *, loff_t *);
+int proc_dointvec_ms_jiffies_minmax(struct ctl_table *table, int write,
+               void *buffer, size_t *lenp, loff_t *ppos);
 int proc_dointvec_userhz_jiffies(struct ctl_table *, int, void *, size_t *,
                loff_t *);
 int proc_dointvec_ms_jiffies(struct ctl_table *, int, void *, size_t *,
index 1168302..a9fbe22 100644 (file)
@@ -46,6 +46,36 @@ static inline unsigned int inner_tcp_hdrlen(const struct sk_buff *skb)
        return inner_tcp_hdr(skb)->doff * 4;
 }
 
+/**
+ * skb_tcp_all_headers - Returns size of all headers for a TCP packet
+ * @skb: buffer
+ *
+ * Used in TX path, for a packet known to be a TCP one.
+ *
+ * if (skb_is_gso(skb)) {
+ *         int hlen = skb_tcp_all_headers(skb);
+ *         ...
+ */
+static inline int skb_tcp_all_headers(const struct sk_buff *skb)
+{
+       return skb_transport_offset(skb) + tcp_hdrlen(skb);
+}
+
+/**
+ * skb_inner_tcp_all_headers - Returns size of all headers for an encap TCP packet
+ * @skb: buffer
+ *
+ * Used in TX path, for a packet known to be a TCP one.
+ *
+ * if (skb_is_gso(skb) && skb->encapsulation) {
+ *         int hlen = skb_inner_tcp_all_headers(skb);
+ *         ...
+ */
+static inline int skb_inner_tcp_all_headers(const struct sk_buff *skb)
+{
+       return skb_inner_transport_offset(skb) + inner_tcp_hdrlen(skb);
+}
+
 static inline unsigned int tcp_optlen(const struct sk_buff *skb)
 {
        return (tcp_hdr(skb)->doff - 5) * 4;
index 81b9686..2fb8232 100644 (file)
@@ -20,6 +20,9 @@ struct itimerspec64 {
        struct timespec64 it_value;
 };
 
+/* Parameters used to convert the timespec values: */
+#define PSEC_PER_NSEC                  1000L
+
 /* Located here for timespec[64]_valid_strict */
 #define TIME64_MAX                     ((s64)~((u64)1 << 63))
 #define TIME64_MIN                     (-TIME64_MAX - 1)
index a7ef624..480fa57 100644 (file)
@@ -16,12 +16,11 @@ void wait_for_unix_gc(void);
 struct sock *unix_get_socket(struct file *filp);
 struct sock *unix_peer_get(struct sock *sk);
 
-#define UNIX_HASH_SIZE 256
+#define UNIX_HASH_MOD  (256 - 1)
+#define UNIX_HASH_SIZE (256 * 2)
 #define UNIX_HASH_BITS 8
 
 extern unsigned int unix_tot_inflight;
-extern spinlock_t unix_table_locks[2 * UNIX_HASH_SIZE];
-extern struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
 
 struct unix_address {
        refcount_t      refcnt;
index 61b4906..d2aea5c 100644 (file)
@@ -67,6 +67,7 @@ enum {
        BOND_OPT_LACP_ACTIVE,
        BOND_OPT_MISSED_MAX,
        BOND_OPT_NS_TARGETS,
+       BOND_OPT_PRIO,
        BOND_OPT_LAST
 };
 
@@ -83,7 +84,10 @@ struct bond_opt_value {
        char *string;
        u64 value;
        u32 flags;
-       char extra[BOND_OPT_EXTRA_MAXLEN];
+       union {
+               char extra[BOND_OPT_EXTRA_MAXLEN];
+               struct net_device *slave_dev;
+       };
 };
 
 struct bonding;
@@ -107,7 +111,8 @@ struct bond_option {
 };
 
 int __bond_opt_set(struct bonding *bond, unsigned int option,
-                  struct bond_opt_value *val);
+                  struct bond_opt_value *val,
+                  struct nlattr *bad_attr, struct netlink_ext_ack *extack);
 int __bond_opt_set_notify(struct bonding *bond, unsigned int option,
                          struct bond_opt_value *val);
 int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
@@ -132,13 +137,16 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
                optval->value = value;
        else if (string)
                optval->string = string;
-       else if (extra_len <= BOND_OPT_EXTRA_MAXLEN)
+
+       if (extra && extra_len <= BOND_OPT_EXTRA_MAXLEN)
                memcpy(optval->extra, extra, extra_len);
 }
 #define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value, NULL, 0)
 #define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX, NULL, 0)
 #define bond_opt_initextra(optval, extra, extra_len) \
        __bond_opt_init(optval, NULL, ULLONG_MAX, extra, extra_len)
+#define bond_opt_slave_initval(optval, slave_dev, value) \
+       __bond_opt_init(optval, NULL, value, slave_dev, sizeof(struct net_device *))
 
 void bond_option_arp_ip_targets_clear(struct bonding *bond);
 #if IS_ENABLED(CONFIG_IPV6)
index cb904d3..6e78d65 100644 (file)
@@ -178,6 +178,7 @@ struct slave {
        u32    speed;
        u16    queue_id;
        u8     perm_hwaddr[MAX_ADDR_LEN];
+       int    prio;
        struct ad_slave_info *ad_info;
        struct tlb_slave_info tlb_info;
 #ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/include/net/dropreason.h b/include/net/dropreason.h
new file mode 100644 (file)
index 0000000..fae9b40
--- /dev/null
@@ -0,0 +1,256 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _LINUX_DROPREASON_H
+#define _LINUX_DROPREASON_H
+
+/**
+ * enum skb_drop_reason - the reasons of skb drops
+ *
+ * The reason of skb drop, which is used in kfree_skb_reason().
+ */
+enum skb_drop_reason {
+       /**
+        * @SKB_NOT_DROPPED_YET: skb is not dropped yet (used for no-drop case)
+        */
+       SKB_NOT_DROPPED_YET = 0,
+       /** @SKB_DROP_REASON_NOT_SPECIFIED: drop reason is not specified */
+       SKB_DROP_REASON_NOT_SPECIFIED,
+       /** @SKB_DROP_REASON_NO_SOCKET: socket not found */
+       SKB_DROP_REASON_NO_SOCKET,
+       /** @SKB_DROP_REASON_PKT_TOO_SMALL: packet size is too small */
+       SKB_DROP_REASON_PKT_TOO_SMALL,
+       /** @SKB_DROP_REASON_TCP_CSUM: TCP checksum error */
+       SKB_DROP_REASON_TCP_CSUM,
+       /** @SKB_DROP_REASON_SOCKET_FILTER: dropped by socket filter */
+       SKB_DROP_REASON_SOCKET_FILTER,
+       /** @SKB_DROP_REASON_UDP_CSUM: UDP checksum error */
+       SKB_DROP_REASON_UDP_CSUM,
+       /** @SKB_DROP_REASON_NETFILTER_DROP: dropped by netfilter */
+       SKB_DROP_REASON_NETFILTER_DROP,
+       /**
+        * @SKB_DROP_REASON_OTHERHOST: packet don't belong to current host
+        * (interface is in promisc mode)
+        */
+       SKB_DROP_REASON_OTHERHOST,
+       /** @SKB_DROP_REASON_IP_CSUM: IP checksum error */
+       SKB_DROP_REASON_IP_CSUM,
+       /**
+        * @SKB_DROP_REASON_IP_INHDR: there is something wrong with IP header (see
+        * IPSTATS_MIB_INHDRERRORS)
+        */
+       SKB_DROP_REASON_IP_INHDR,
+       /**
+        * @SKB_DROP_REASON_IP_RPFILTER: IP rpfilter validate failed. see the
+        * document for rp_filter in ip-sysctl.rst for more information
+        */
+       SKB_DROP_REASON_IP_RPFILTER,
+       /**
+        * @SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST: destination address of L2 is
+        * multicast, but L3 is unicast.
+        */
+       SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST,
+       /** @SKB_DROP_REASON_XFRM_POLICY: xfrm policy check failed */
+       SKB_DROP_REASON_XFRM_POLICY,
+       /** @SKB_DROP_REASON_IP_NOPROTO: no support for IP protocol */
+       SKB_DROP_REASON_IP_NOPROTO,
+       /** @SKB_DROP_REASON_SOCKET_RCVBUFF: socket receive buff is full */
+       SKB_DROP_REASON_SOCKET_RCVBUFF,
+       /**
+        * @SKB_DROP_REASON_PROTO_MEM: proto memory limition, such as udp packet
+        * drop out of udp_memory_allocated.
+        */
+       SKB_DROP_REASON_PROTO_MEM,
+       /**
+        * @SKB_DROP_REASON_TCP_MD5NOTFOUND: no MD5 hash and one expected,
+        * corresponding to LINUX_MIB_TCPMD5NOTFOUND
+        */
+       SKB_DROP_REASON_TCP_MD5NOTFOUND,
+       /**
+        * @SKB_DROP_REASON_TCP_MD5UNEXPECTED: MD5 hash and we're not expecting
+        * one, corresponding to LINUX_MIB_TCPMD5UNEXPECTED
+        */
+       SKB_DROP_REASON_TCP_MD5UNEXPECTED,
+       /**
+        * @SKB_DROP_REASON_TCP_MD5FAILURE: MD5 hash and its wrong, corresponding
+        * to LINUX_MIB_TCPMD5FAILURE
+        */
+       SKB_DROP_REASON_TCP_MD5FAILURE,
+       /**
+        * @SKB_DROP_REASON_SOCKET_BACKLOG: failed to add skb to socket backlog (
+        * see LINUX_MIB_TCPBACKLOGDROP)
+        */
+       SKB_DROP_REASON_SOCKET_BACKLOG,
+       /** @SKB_DROP_REASON_TCP_FLAGS: TCP flags invalid */
+       SKB_DROP_REASON_TCP_FLAGS,
+       /**
+        * @SKB_DROP_REASON_TCP_ZEROWINDOW: TCP receive window size is zero,
+        * see LINUX_MIB_TCPZEROWINDOWDROP
+        */
+       SKB_DROP_REASON_TCP_ZEROWINDOW,
+       /**
+        * @SKB_DROP_REASON_TCP_OLD_DATA: the TCP data reveived is already
+        * received before (spurious retrans may happened), see
+        * LINUX_MIB_DELAYEDACKLOST
+        */
+       SKB_DROP_REASON_TCP_OLD_DATA,
+       /**
+        * @SKB_DROP_REASON_TCP_OVERWINDOW: the TCP data is out of window,
+        * the seq of the first byte exceed the right edges of receive
+        * window
+        */
+       SKB_DROP_REASON_TCP_OVERWINDOW,
+       /**
+        * @SKB_DROP_REASON_TCP_OFOMERGE: the data of skb is already in the ofo
+        * queue, corresponding to LINUX_MIB_TCPOFOMERGE
+        */
+       SKB_DROP_REASON_TCP_OFOMERGE,
+       /**
+        * @SKB_DROP_REASON_TCP_RFC7323_PAWS: PAWS check, corresponding to
+        * LINUX_MIB_PAWSESTABREJECTED
+        */
+       SKB_DROP_REASON_TCP_RFC7323_PAWS,
+       /** @SKB_DROP_REASON_TCP_INVALID_SEQUENCE: Not acceptable SEQ field */
+       SKB_DROP_REASON_TCP_INVALID_SEQUENCE,
+       /** @SKB_DROP_REASON_TCP_RESET: Invalid RST packet */
+       SKB_DROP_REASON_TCP_RESET,
+       /**
+        * @SKB_DROP_REASON_TCP_INVALID_SYN: Incoming packet has unexpected
+        * SYN flag
+        */
+       SKB_DROP_REASON_TCP_INVALID_SYN,
+       /** @SKB_DROP_REASON_TCP_CLOSE: TCP socket in CLOSE state */
+       SKB_DROP_REASON_TCP_CLOSE,
+       /** @SKB_DROP_REASON_TCP_FASTOPEN: dropped by FASTOPEN request socket */
+       SKB_DROP_REASON_TCP_FASTOPEN,
+       /** @SKB_DROP_REASON_TCP_OLD_ACK: TCP ACK is old, but in window */
+       SKB_DROP_REASON_TCP_OLD_ACK,
+       /** @SKB_DROP_REASON_TCP_TOO_OLD_ACK: TCP ACK is too old */
+       SKB_DROP_REASON_TCP_TOO_OLD_ACK,
+       /**
+        * @SKB_DROP_REASON_TCP_ACK_UNSENT_DATA: TCP ACK for data we haven't
+        * sent yet
+        */
+       SKB_DROP_REASON_TCP_ACK_UNSENT_DATA,
+       /** @SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE: pruned from TCP OFO queue */
+       SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE,
+       /** @SKB_DROP_REASON_TCP_OFO_DROP: data already in receive queue */
+       SKB_DROP_REASON_TCP_OFO_DROP,
+       /** @SKB_DROP_REASON_IP_OUTNOROUTES: route lookup failed */
+       SKB_DROP_REASON_IP_OUTNOROUTES,
+       /**
+        * @SKB_DROP_REASON_BPF_CGROUP_EGRESS: dropped by BPF_PROG_TYPE_CGROUP_SKB
+        * eBPF program
+        */
+       SKB_DROP_REASON_BPF_CGROUP_EGRESS,
+       /** @SKB_DROP_REASON_IPV6DISABLED: IPv6 is disabled on the device */
+       SKB_DROP_REASON_IPV6DISABLED,
+       /** @SKB_DROP_REASON_NEIGH_CREATEFAIL: failed to create neigh entry */
+       SKB_DROP_REASON_NEIGH_CREATEFAIL,
+       /** @SKB_DROP_REASON_NEIGH_FAILED: neigh entry in failed state */
+       SKB_DROP_REASON_NEIGH_FAILED,
+       /** @SKB_DROP_REASON_NEIGH_QUEUEFULL: arp_queue for neigh entry is full */
+       SKB_DROP_REASON_NEIGH_QUEUEFULL,
+       /** @SKB_DROP_REASON_NEIGH_DEAD: neigh entry is dead */
+       SKB_DROP_REASON_NEIGH_DEAD,
+       /** @SKB_DROP_REASON_TC_EGRESS: dropped in TC egress HOOK */
+       SKB_DROP_REASON_TC_EGRESS,
+       /**
+        * @SKB_DROP_REASON_QDISC_DROP: dropped by qdisc when packet outputting (
+        * failed to enqueue to current qdisc)
+        */
+       SKB_DROP_REASON_QDISC_DROP,
+       /**
+        * @SKB_DROP_REASON_CPU_BACKLOG: failed to enqueue the skb to the per CPU
+        * backlog queue. This can be caused by backlog queue full (see
+        * netdev_max_backlog in net.rst) or RPS flow limit
+        */
+       SKB_DROP_REASON_CPU_BACKLOG,
+       /** @SKB_DROP_REASON_XDP: dropped by XDP in input path */
+       SKB_DROP_REASON_XDP,
+       /** @SKB_DROP_REASON_TC_INGRESS: dropped in TC ingress HOOK */
+       SKB_DROP_REASON_TC_INGRESS,
+       /** @SKB_DROP_REASON_UNHANDLED_PROTO: protocol not implemented or not supported */
+       SKB_DROP_REASON_UNHANDLED_PROTO,
+       /** @SKB_DROP_REASON_SKB_CSUM: sk_buff checksum computation error */
+       SKB_DROP_REASON_SKB_CSUM,
+       /** @SKB_DROP_REASON_SKB_GSO_SEG: gso segmentation error */
+       SKB_DROP_REASON_SKB_GSO_SEG,
+       /**
+        * @SKB_DROP_REASON_SKB_UCOPY_FAULT: failed to copy data from user space,
+        * e.g., via zerocopy_sg_from_iter() or skb_orphan_frags_rx()
+        */
+       SKB_DROP_REASON_SKB_UCOPY_FAULT,
+       /** @SKB_DROP_REASON_DEV_HDR: device driver specific header/metadata is invalid */
+       SKB_DROP_REASON_DEV_HDR,
+       /**
+        * @SKB_DROP_REASON_DEV_READY: the device is not ready to xmit/recv due to
+        * any of its data structure that is not up/ready/initialized,
+        * e.g., the IFF_UP is not set, or driver specific tun->tfiles[txq]
+        * is not initialized
+        */
+       SKB_DROP_REASON_DEV_READY,
+       /** @SKB_DROP_REASON_FULL_RING: ring buffer is full */
+       SKB_DROP_REASON_FULL_RING,
+       /** @SKB_DROP_REASON_NOMEM: error due to OOM */
+       SKB_DROP_REASON_NOMEM,
+       /**
+        * @SKB_DROP_REASON_HDR_TRUNC: failed to trunc/extract the header from
+        * networking data, e.g., failed to pull the protocol header from
+        * frags via pskb_may_pull()
+        */
+       SKB_DROP_REASON_HDR_TRUNC,
+       /**
+        * @SKB_DROP_REASON_TAP_FILTER: dropped by (ebpf) filter directly attached
+        * to tun/tap, e.g., via TUNSETFILTEREBPF
+        */
+       SKB_DROP_REASON_TAP_FILTER,
+       /**
+        * @SKB_DROP_REASON_TAP_TXFILTER: dropped by tx filter implemented at
+        * tun/tap, e.g., check_filter()
+        */
+       SKB_DROP_REASON_TAP_TXFILTER,
+       /** @SKB_DROP_REASON_ICMP_CSUM: ICMP checksum error */
+       SKB_DROP_REASON_ICMP_CSUM,
+       /**
+        * @SKB_DROP_REASON_INVALID_PROTO: the packet doesn't follow RFC 2211,
+        * such as a broadcasts ICMP_TIMESTAMP
+        */
+       SKB_DROP_REASON_INVALID_PROTO,
+       /**
+        * @SKB_DROP_REASON_IP_INADDRERRORS: host unreachable, corresponding to
+        * IPSTATS_MIB_INADDRERRORS
+        */
+       SKB_DROP_REASON_IP_INADDRERRORS,
+       /**
+        * @SKB_DROP_REASON_IP_INNOROUTES: network unreachable, corresponding to
+        * IPSTATS_MIB_INADDRERRORS
+        */
+       SKB_DROP_REASON_IP_INNOROUTES,
+       /**
+        * @SKB_DROP_REASON_PKT_TOO_BIG: packet size is too big (maybe exceed the
+        * MTU)
+        */
+       SKB_DROP_REASON_PKT_TOO_BIG,
+       /**
+        * @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
+        * used as a real 'reason'
+        */
+       SKB_DROP_REASON_MAX,
+};
+
+#define SKB_DR_INIT(name, reason)                              \
+       enum skb_drop_reason name = SKB_DROP_REASON_##reason
+#define SKB_DR(name)                                           \
+       SKB_DR_INIT(name, NOT_SPECIFIED)
+#define SKB_DR_SET(name, reason)                               \
+       (name = SKB_DROP_REASON_##reason)
+#define SKB_DR_OR(name, reason)                                        \
+       do {                                                    \
+               if (name == SKB_DROP_REASON_NOT_SPECIFIED ||    \
+                   name == SKB_NOT_DROPPED_YET)                \
+                       SKB_DR_SET(name, reason);               \
+       } while (0)
+
+extern const char * const drop_reasons[];
+
+#endif
index 14f0727..b902b31 100644 (file)
@@ -53,6 +53,8 @@ struct phylink_link_state;
 #define DSA_TAG_PROTO_SJA1110_VALUE            23
 #define DSA_TAG_PROTO_RTL8_4_VALUE             24
 #define DSA_TAG_PROTO_RTL8_4T_VALUE            25
+#define DSA_TAG_PROTO_RZN1_A5PSW_VALUE         26
+#define DSA_TAG_PROTO_LAN937X_VALUE            27
 
 enum dsa_tag_protocol {
        DSA_TAG_PROTO_NONE              = DSA_TAG_PROTO_NONE_VALUE,
@@ -81,6 +83,8 @@ enum dsa_tag_protocol {
        DSA_TAG_PROTO_SJA1110           = DSA_TAG_PROTO_SJA1110_VALUE,
        DSA_TAG_PROTO_RTL8_4            = DSA_TAG_PROTO_RTL8_4_VALUE,
        DSA_TAG_PROTO_RTL8_4T           = DSA_TAG_PROTO_RTL8_4T_VALUE,
+       DSA_TAG_PROTO_RZN1_A5PSW        = DSA_TAG_PROTO_RZN1_A5PSW_VALUE,
+       DSA_TAG_PROTO_LAN937X           = DSA_TAG_PROTO_LAN937X_VALUE,
 };
 
 struct dsa_switch;
@@ -888,8 +892,13 @@ struct dsa_switch_ops {
                                     struct ethtool_eth_mac_stats *mac_stats);
        void    (*get_eth_ctrl_stats)(struct dsa_switch *ds, int port,
                                      struct ethtool_eth_ctrl_stats *ctrl_stats);
+       void    (*get_rmon_stats)(struct dsa_switch *ds, int port,
+                                 struct ethtool_rmon_stats *rmon_stats,
+                                 const struct ethtool_rmon_hist_range **ranges);
        void    (*get_stats64)(struct dsa_switch *ds, int port,
                                   struct rtnl_link_stats64 *s);
+       void    (*get_pause_stats)(struct dsa_switch *ds, int port,
+                                  struct ethtool_pause_stats *pause_stats);
        void    (*self_test)(struct dsa_switch *ds, int port,
                             struct ethtool_test *etest, u64 *data);
 
index c24fa93..70cbc4a 100644 (file)
@@ -456,8 +456,8 @@ static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len)
                struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
 
                u64_stats_update_begin(&tstats->syncp);
-               tstats->tx_bytes += pkt_len;
-               tstats->tx_packets++;
+               u64_stats_add(&tstats->tx_bytes, pkt_len);
+               u64_stats_inc(&tstats->tx_packets);
                u64_stats_update_end(&tstats->syncp);
                put_cpu_ptr(tstats);
        } else {
index ebadb21..5c9e97e 100644 (file)
@@ -1959,36 +1959,6 @@ struct ieee80211_key_seq {
 };
 
 /**
- * struct ieee80211_cipher_scheme - cipher scheme
- *
- * This structure contains a cipher scheme information defining
- * the secure packet crypto handling.
- *
- * @cipher: a cipher suite selector
- * @iftype: a cipher iftype bit mask indicating an allowed cipher usage
- * @hdr_len: a length of a security header used the cipher
- * @pn_len: a length of a packet number in the security header
- * @pn_off: an offset of pn from the beginning of the security header
- * @key_idx_off: an offset of key index byte in the security header
- * @key_idx_mask: a bit mask of key_idx bits
- * @key_idx_shift: a bit shift needed to get key_idx
- *     key_idx value calculation:
- *      (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift
- * @mic_len: a mic length in bytes
- */
-struct ieee80211_cipher_scheme {
-       u32 cipher;
-       u16 iftype;
-       u8 hdr_len;
-       u8 pn_len;
-       u8 pn_off;
-       u8 key_idx_off;
-       u8 key_idx_mask;
-       u8 key_idx_shift;
-       u8 mic_len;
-};
-
-/**
  * enum set_key_cmd - key command
  *
  * Used with the set_key() callback in &struct ieee80211_ops, this
@@ -2664,9 +2634,6 @@ enum ieee80211_hw_flags {
  *     deliver to a WMM STA during any Service Period triggered by the WMM STA.
  *     Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.
  *
- * @n_cipher_schemes: a size of an array of cipher schemes definitions.
- * @cipher_schemes: a pointer to an array of cipher scheme definitions
- *     supported by HW.
  * @max_nan_de_entries: maximum number of NAN DE functions supported by the
  *     device.
  *
@@ -2716,8 +2683,6 @@ struct ieee80211_hw {
        netdev_features_t netdev_features;
        u8 uapsd_queues;
        u8 uapsd_max_sp_len;
-       u8 n_cipher_schemes;
-       const struct ieee80211_cipher_scheme *cipher_schemes;
        u8 max_nan_de_entries;
        u8 tx_sk_pacing_shift;
        u8 weight_multiplier;
index 87419f7..9f0bab0 100644 (file)
@@ -48,6 +48,7 @@ enum {
        NEIGH_VAR_RETRANS_TIME,
        NEIGH_VAR_BASE_REACHABLE_TIME,
        NEIGH_VAR_DELAY_PROBE_TIME,
+       NEIGH_VAR_INTERVAL_PROBE_TIME_MS,
        NEIGH_VAR_GC_STALETIME,
        NEIGH_VAR_QUEUE_LEN_BYTES,
        NEIGH_VAR_PROXY_QLEN,
index c4f5601..20a2992 100644 (file)
@@ -120,7 +120,9 @@ struct net {
        struct netns_core       core;
        struct netns_mib        mib;
        struct netns_packet     packet;
+#if IS_ENABLED(CONFIG_UNIX)
        struct netns_unix       unx;
+#endif
        struct netns_nexthop    nexthop;
        struct netns_ipv4       ipv4;
 #if IS_ENABLED(CONFIG_IPV6)
index 91a3d7e..6f1a33d 100644 (file)
@@ -5,8 +5,14 @@
 #ifndef __NETNS_UNIX_H__
 #define __NETNS_UNIX_H__
 
+struct unix_table {
+       spinlock_t              *locks;
+       struct hlist_head       *buckets;
+};
+
 struct ctl_table_header;
 struct netns_unix {
+       struct unix_table       table;
        int                     sysctl_max_dgram_qlen;
        struct ctl_table_header *ctl;
 };
index 44a3553..3372a1f 100644 (file)
@@ -173,11 +173,28 @@ struct tc_taprio_qopt_offload {
        struct tc_taprio_sched_entry entries[];
 };
 
+#if IS_ENABLED(CONFIG_NET_SCH_TAPRIO)
+
 /* Reference counting */
 struct tc_taprio_qopt_offload *taprio_offload_get(struct tc_taprio_qopt_offload
                                                  *offload);
 void taprio_offload_free(struct tc_taprio_qopt_offload *offload);
 
+#else
+
+/* Reference counting */
+static inline struct tc_taprio_qopt_offload *
+taprio_offload_get(struct tc_taprio_qopt_offload *offload)
+{
+       return NULL;
+}
+
+static inline void taprio_offload_free(struct tc_taprio_qopt_offload *offload)
+{
+}
+
+#endif
+
 /* Ensure skb_mstamp_ns, which might have been populated with the txtime, is
  * not mistaken for a software timestamp, because this will otherwise prevent
  * the dispatch of hardware timestamps to the socket.
index 8ad8df5..d224376 100644 (file)
@@ -20,9 +20,8 @@
 extern struct proto raw_prot;
 
 extern struct raw_hashinfo raw_v4_hashinfo;
-struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
-                            unsigned short num, __be32 raddr,
-                            __be32 laddr, int dif, int sdif);
+bool raw_v4_match(struct net *net, struct sock *sk, unsigned short num,
+                 __be32 raddr, __be32 laddr, int dif, int sdif);
 
 int raw_abort(struct sock *sk, int err);
 void raw_icmp_error(struct sk_buff *, int, u32);
@@ -33,10 +32,19 @@ int raw_rcv(struct sock *, struct sk_buff *);
 #define RAW_HTABLE_SIZE        MAX_INET_PROTOS
 
 struct raw_hashinfo {
-       rwlock_t lock;
-       struct hlist_head ht[RAW_HTABLE_SIZE];
+       spinlock_t lock;
+       struct hlist_nulls_head ht[RAW_HTABLE_SIZE];
 };
 
+static inline void raw_hashinfo_init(struct raw_hashinfo *hashinfo)
+{
+       int i;
+
+       spin_lock_init(&hashinfo->lock);
+       for (i = 0; i < RAW_HTABLE_SIZE; i++)
+               INIT_HLIST_NULLS_HEAD(&hashinfo->ht[i], i);
+}
+
 #ifdef CONFIG_PROC_FS
 int raw_proc_init(void);
 void raw_proc_exit(void);
index 53d86b6..bc70909 100644 (file)
@@ -3,11 +3,12 @@
 #define _NET_RAWV6_H
 
 #include <net/protocol.h>
+#include <net/raw.h>
 
 extern struct raw_hashinfo raw_v6_hashinfo;
-struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
-                            unsigned short num, const struct in6_addr *loc_addr,
-                            const struct in6_addr *rmt_addr, int dif, int sdif);
+bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num,
+                 const struct in6_addr *loc_addr,
+                 const struct in6_addr *rmt_addr, int dif, int sdif);
 
 int raw_abort(struct sock *sk, int err);
 
index 72ca97c..0dd43c3 100644 (file)
@@ -609,7 +609,7 @@ void sock_net_set(struct sock *sk, struct net *net)
 
 int sk_set_peek_off(struct sock *sk, int val);
 
-static inline int sk_peek_offset(struct sock *sk, int flags)
+static inline int sk_peek_offset(const struct sock *sk, int flags)
 {
        if (unlikely(flags & MSG_PEEK)) {
                return READ_ONCE(sk->sk_peek_off);
@@ -849,7 +849,7 @@ static inline void sk_add_bind_node(struct sock *sk,
                ({ tpos = (typeof(*tpos) *)((void *)pos - offset); 1;});       \
             pos = rcu_dereference(hlist_next_rcu(pos)))
 
-static inline struct user_namespace *sk_user_ns(struct sock *sk)
+static inline struct user_namespace *sk_user_ns(const struct sock *sk)
 {
        /* Careful only use this in a context where these parameters
         * can not change and must all be valid, such as recvmsg from
@@ -895,7 +895,7 @@ enum sock_flags {
 
 #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
 
-static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
+static inline void sock_copy_flags(struct sock *nsk, const struct sock *osk)
 {
        nsk->sk_flags = osk->sk_flags;
 }
@@ -1240,6 +1240,7 @@ struct proto {
        void                    (*enter_memory_pressure)(struct sock *sk);
        void                    (*leave_memory_pressure)(struct sock *sk);
        atomic_long_t           *memory_allocated;      /* Current allocated memory. */
+       int  __percpu           *per_cpu_fw_alloc;
        struct percpu_counter   *sockets_allocated;     /* Current number of sockets. */
 
        /*
@@ -1383,21 +1384,46 @@ static inline bool sk_under_memory_pressure(const struct sock *sk)
 }
 
 static inline long
-sk_memory_allocated(const struct sock *sk)
+proto_memory_allocated(const struct proto *prot)
 {
-       return atomic_long_read(sk->sk_prot->memory_allocated);
+       return max(0L, atomic_long_read(prot->memory_allocated));
 }
 
 static inline long
+sk_memory_allocated(const struct sock *sk)
+{
+       return proto_memory_allocated(sk->sk_prot);
+}
+
+/* 1 MB per cpu, in page units */
+#define SK_MEMORY_PCPU_RESERVE (1 << (20 - PAGE_SHIFT))
+
+static inline void
 sk_memory_allocated_add(struct sock *sk, int amt)
 {
-       return atomic_long_add_return(amt, sk->sk_prot->memory_allocated);
+       int local_reserve;
+
+       preempt_disable();
+       local_reserve = __this_cpu_add_return(*sk->sk_prot->per_cpu_fw_alloc, amt);
+       if (local_reserve >= SK_MEMORY_PCPU_RESERVE) {
+               __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve);
+               atomic_long_add(local_reserve, sk->sk_prot->memory_allocated);
+       }
+       preempt_enable();
 }
 
 static inline void
 sk_memory_allocated_sub(struct sock *sk, int amt)
 {
-       atomic_long_sub(amt, sk->sk_prot->memory_allocated);
+       int local_reserve;
+
+       preempt_disable();
+       local_reserve = __this_cpu_sub_return(*sk->sk_prot->per_cpu_fw_alloc, amt);
+       if (local_reserve <= -SK_MEMORY_PCPU_RESERVE) {
+               __this_cpu_sub(*sk->sk_prot->per_cpu_fw_alloc, local_reserve);
+               atomic_long_add(local_reserve, sk->sk_prot->memory_allocated);
+       }
+       preempt_enable();
 }
 
 #define SK_ALLOC_PERCPU_COUNTER_BATCH 16
@@ -1426,12 +1452,6 @@ proto_sockets_allocated_sum_positive(struct proto *prot)
        return percpu_counter_sum_positive(prot->sockets_allocated);
 }
 
-static inline long
-proto_memory_allocated(struct proto *prot)
-{
-       return atomic_long_read(prot->memory_allocated);
-}
-
 static inline bool
 proto_memory_pressure(struct proto *prot)
 {
@@ -1518,30 +1538,18 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind);
 void __sk_mem_reduce_allocated(struct sock *sk, int amount);
 void __sk_mem_reclaim(struct sock *sk, int amount);
 
-/* We used to have PAGE_SIZE here, but systems with 64KB pages
- * do not necessarily have 16x time more memory than 4KB ones.
- */
-#define SK_MEM_QUANTUM 4096
-#define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM)
 #define SK_MEM_SEND    0
 #define SK_MEM_RECV    1
 
-/* sysctl_mem values are in pages, we convert them in SK_MEM_QUANTUM units */
+/* sysctl_mem values are in pages */
 static inline long sk_prot_mem_limits(const struct sock *sk, int index)
 {
-       long val = sk->sk_prot->sysctl_mem[index];
-
-#if PAGE_SIZE > SK_MEM_QUANTUM
-       val <<= PAGE_SHIFT - SK_MEM_QUANTUM_SHIFT;
-#elif PAGE_SIZE < SK_MEM_QUANTUM
-       val >>= SK_MEM_QUANTUM_SHIFT - PAGE_SHIFT;
-#endif
-       return val;
+       return sk->sk_prot->sysctl_mem[index];
 }
 
 static inline int sk_mem_pages(int amt)
 {
-       return (amt + SK_MEM_QUANTUM - 1) >> SK_MEM_QUANTUM_SHIFT;
+       return (amt + PAGE_SIZE - 1) >> PAGE_SHIFT;
 }
 
 static inline bool sk_has_account(struct sock *sk)
@@ -1552,19 +1560,23 @@ static inline bool sk_has_account(struct sock *sk)
 
 static inline bool sk_wmem_schedule(struct sock *sk, int size)
 {
+       int delta;
+
        if (!sk_has_account(sk))
                return true;
-       return size <= sk->sk_forward_alloc ||
-               __sk_mem_schedule(sk, size, SK_MEM_SEND);
+       delta = size - sk->sk_forward_alloc;
+       return delta <= 0 || __sk_mem_schedule(sk, delta, SK_MEM_SEND);
 }
 
 static inline bool
 sk_rmem_schedule(struct sock *sk, struct sk_buff *skb, int size)
 {
+       int delta;
+
        if (!sk_has_account(sk))
                return true;
-       return size <= sk->sk_forward_alloc ||
-               __sk_mem_schedule(sk, size, SK_MEM_RECV) ||
+       delta = size - sk->sk_forward_alloc;
+       return delta <= 0 || __sk_mem_schedule(sk, delta, SK_MEM_RECV) ||
                skb_pfmemalloc(skb);
 }
 
@@ -1590,7 +1602,7 @@ static inline void sk_mem_reclaim(struct sock *sk)
 
        reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk);
 
-       if (reclaimable >= SK_MEM_QUANTUM)
+       if (reclaimable >= (int)PAGE_SIZE)
                __sk_mem_reclaim(sk, reclaimable);
 }
 
@@ -1600,19 +1612,6 @@ static inline void sk_mem_reclaim_final(struct sock *sk)
        sk_mem_reclaim(sk);
 }
 
-static inline void sk_mem_reclaim_partial(struct sock *sk)
-{
-       int reclaimable;
-
-       if (!sk_has_account(sk))
-               return;
-
-       reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk);
-
-       if (reclaimable > SK_MEM_QUANTUM)
-               __sk_mem_reclaim(sk, reclaimable - 1);
-}
-
 static inline void sk_mem_charge(struct sock *sk, int size)
 {
        if (!sk_has_account(sk))
@@ -1620,29 +1619,12 @@ static inline void sk_mem_charge(struct sock *sk, int size)
        sk->sk_forward_alloc -= size;
 }
 
-/* the following macros control memory reclaiming in sk_mem_uncharge()
- */
-#define SK_RECLAIM_THRESHOLD   (1 << 21)
-#define SK_RECLAIM_CHUNK       (1 << 20)
-
 static inline void sk_mem_uncharge(struct sock *sk, int size)
 {
-       int reclaimable;
-
        if (!sk_has_account(sk))
                return;
        sk->sk_forward_alloc += size;
-       reclaimable = sk->sk_forward_alloc - sk_unused_reserved_mem(sk);
-
-       /* Avoid a possible overflow.
-        * TCP send queues can make this happen, if sk_mem_reclaim()
-        * is not called and more than 2 GBytes are released at once.
-        *
-        * If we reach 2 MBytes, reclaim 1 MBytes right now, there is
-        * no need to hold that much forward allocation anyway.
-        */
-       if (unlikely(reclaimable >= SK_RECLAIM_THRESHOLD))
-               __sk_mem_reclaim(sk, SK_RECLAIM_CHUNK);
+       sk_mem_reclaim(sk);
 }
 
 /*
@@ -2232,9 +2214,7 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *fro
        if (err)
                return err;
 
-       skb->len             += copy;
-       skb->data_len        += copy;
-       skb->truesize        += copy;
+       skb_len_add(skb, copy);
        sk_wmem_queued_add(sk, copy);
        sk_mem_charge(sk, copy);
        return 0;
index aa0171d..7dcdc97 100644 (file)
@@ -239,6 +239,9 @@ struct switchdev_notifier_info {
        const void *ctx;
 };
 
+/* Remember to update br_switchdev_fdb_populate() when adding
+ * new members to this structure
+ */
 struct switchdev_notifier_fdb_info {
        struct switchdev_notifier_info info; /* must be first */
        const unsigned char *addr;
index 1e99f5c..c21a9b5 100644 (file)
@@ -253,6 +253,8 @@ extern long sysctl_tcp_mem[3];
 #define TCP_RACK_NO_DUPTHRESH    0x4 /* Do not use DUPACK threshold in RACK */
 
 extern atomic_long_t tcp_memory_allocated;
+DECLARE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc);
+
 extern struct percpu_counter tcp_sockets_allocated;
 extern unsigned long tcp_memory_pressure;
 
@@ -432,6 +434,7 @@ u16 tcp_v4_get_syncookie(struct sock *sk, struct iphdr *iph,
                         struct tcphdr *th, u32 *cookie);
 u16 tcp_v6_get_syncookie(struct sock *sk, struct ipv6hdr *iph,
                         struct tcphdr *th, u32 *cookie);
+u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss);
 u16 tcp_get_syncookie_mss(struct request_sock_ops *rsk_ops,
                          const struct tcp_request_sock_ops *af_ops,
                          struct sock *sk, struct tcphdr *th);
index 8017f17..4fc16ca 100644 (file)
@@ -149,6 +149,7 @@ struct tls_sw_context_rx {
 
        struct sk_buff *recv_pkt;
        u8 async_capable:1;
+       u8 zc_capable:1;
        atomic_t decrypt_pending;
        /* protect crypto_wait with decrypt_pending*/
        spinlock_t decrypt_compl_lock;
@@ -239,6 +240,7 @@ struct tls_context {
        u8 tx_conf:3;
        u8 rx_conf:3;
        u8 zerocopy_sendfile:1;
+       u8 rx_no_pad:1;
 
        int (*push_pending_record)(struct sock *sk, int flags);
        void (*sk_write_space)(struct sock *sk);
@@ -358,6 +360,7 @@ int tls_sk_attach(struct sock *sk, int optname, char __user *optval,
 void tls_err_abort(struct sock *sk, int err);
 
 int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx);
+void tls_update_rx_zc_capable(struct tls_context *tls_ctx);
 void tls_sw_strparser_arm(struct sock *sk, struct tls_context *ctx);
 void tls_sw_strparser_done(struct tls_context *tls_ctx);
 int tls_sw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
index b83a003..b60eea2 100644 (file)
@@ -95,6 +95,7 @@ static inline struct udp_hslot *udp_hashslot2(struct udp_table *table,
 extern struct proto udp_prot;
 
 extern atomic_long_t udp_memory_allocated;
+DECLARE_PER_CPU(int, udp_memory_per_cpu_fw_alloc);
 
 /* sysctl variables for udp */
 extern long sysctl_udp_mem[3];
index c39d910..9287712 100644 (file)
@@ -1923,7 +1923,7 @@ static inline void xfrm_dev_state_free(struct xfrm_state *x)
                if (dev->xfrmdev_ops->xdo_dev_state_free)
                        dev->xfrmdev_ops->xdo_dev_state_free(x);
                xso->dev = NULL;
-               dev_put_track(dev, &xso->dev_tracker);
+               netdev_put(dev, &xso->dev_tracker);
        }
 }
 #else
index 5f88385..ac151ec 100644 (file)
@@ -575,6 +575,7 @@ struct ocelot_ops {
        int (*psfp_stats_get)(struct ocelot *ocelot, struct flow_cls_offload *f,
                              struct flow_stats *stats);
        void (*cut_through_fwd)(struct ocelot *ocelot);
+       void (*tas_clock_adjust)(struct ocelot *ocelot);
 };
 
 struct ocelot_vcap_policer {
@@ -669,6 +670,8 @@ struct ocelot_port {
        /* VLAN that untagged frames are classified to, on ingress */
        const struct ocelot_bridge_vlan *pvid_vlan;
 
+       struct tc_taprio_qopt_offload   *taprio;
+
        phy_interface_t                 phy_mode;
 
        unsigned int                    ptp_skbs_in_flight;
@@ -757,6 +760,9 @@ struct ocelot {
        /* Lock for serializing forwarding domain changes */
        struct mutex                    fwd_domain_lock;
 
+       /* Lock for serializing Time-Aware Shaper changes */
+       struct mutex                    tas_lock;
+
        struct workqueue_struct         *owq;
 
        u8                              ptp:1;
index 032b431..da611a7 100644 (file)
@@ -136,7 +136,7 @@ DECLARE_EVENT_CLASS(net_dev_template,
                __assign_str(name, skb->dev->name);
        ),
 
-       TP_printk("dev=%s skbaddr=%px len=%u",
+       TP_printk("dev=%s skbaddr=%p len=%u",
                __get_str(name), __entry->skbaddr, __entry->len)
 )
 
index 59c945b..a399592 100644 (file)
@@ -41,7 +41,7 @@ TRACE_EVENT(qdisc_dequeue,
                __entry->txq_state      = txq->state;
        ),
 
-       TP_printk("dequeue ifindex=%d qdisc handle=0x%X parent=0x%X txq_state=0x%lX packets=%d skbaddr=%px",
+       TP_printk("dequeue ifindex=%d qdisc handle=0x%X parent=0x%X txq_state=0x%lX packets=%d skbaddr=%p",
                  __entry->ifindex, __entry->handle, __entry->parent,
                  __entry->txq_state, __entry->packets, __entry->skbaddr )
 );
@@ -70,7 +70,7 @@ TRACE_EVENT(qdisc_enqueue,
                __entry->parent  = qdisc->parent;
        ),
 
-       TP_printk("enqueue ifindex=%d qdisc handle=0x%X parent=0x%X skbaddr=%px",
+       TP_printk("enqueue ifindex=%d qdisc handle=0x%X parent=0x%X skbaddr=%p",
                  __entry->ifindex, __entry->handle, __entry->parent, __entry->skbaddr)
 );
 
index a477bf9..45264e4 100644 (file)
@@ -9,92 +9,6 @@
 #include <linux/netdevice.h>
 #include <linux/tracepoint.h>
 
-#define TRACE_SKB_DROP_REASON                                  \
-       EM(SKB_DROP_REASON_NOT_SPECIFIED, NOT_SPECIFIED)        \
-       EM(SKB_DROP_REASON_NO_SOCKET, NO_SOCKET)                \
-       EM(SKB_DROP_REASON_PKT_TOO_SMALL, PKT_TOO_SMALL)        \
-       EM(SKB_DROP_REASON_TCP_CSUM, TCP_CSUM)                  \
-       EM(SKB_DROP_REASON_SOCKET_FILTER, SOCKET_FILTER)        \
-       EM(SKB_DROP_REASON_UDP_CSUM, UDP_CSUM)                  \
-       EM(SKB_DROP_REASON_NETFILTER_DROP, NETFILTER_DROP)      \
-       EM(SKB_DROP_REASON_OTHERHOST, OTHERHOST)                \
-       EM(SKB_DROP_REASON_IP_CSUM, IP_CSUM)                    \
-       EM(SKB_DROP_REASON_IP_INHDR, IP_INHDR)                  \
-       EM(SKB_DROP_REASON_IP_RPFILTER, IP_RPFILTER)            \
-       EM(SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST,             \
-          UNICAST_IN_L2_MULTICAST)                             \
-       EM(SKB_DROP_REASON_XFRM_POLICY, XFRM_POLICY)            \
-       EM(SKB_DROP_REASON_IP_NOPROTO, IP_NOPROTO)              \
-       EM(SKB_DROP_REASON_SOCKET_RCVBUFF, SOCKET_RCVBUFF)      \
-       EM(SKB_DROP_REASON_PROTO_MEM, PROTO_MEM)                \
-       EM(SKB_DROP_REASON_TCP_MD5NOTFOUND, TCP_MD5NOTFOUND)    \
-       EM(SKB_DROP_REASON_TCP_MD5UNEXPECTED,                   \
-          TCP_MD5UNEXPECTED)                                   \
-       EM(SKB_DROP_REASON_TCP_MD5FAILURE, TCP_MD5FAILURE)      \
-       EM(SKB_DROP_REASON_SOCKET_BACKLOG, SOCKET_BACKLOG)      \
-       EM(SKB_DROP_REASON_TCP_FLAGS, TCP_FLAGS)                \
-       EM(SKB_DROP_REASON_TCP_ZEROWINDOW, TCP_ZEROWINDOW)      \
-       EM(SKB_DROP_REASON_TCP_OLD_DATA, TCP_OLD_DATA)          \
-       EM(SKB_DROP_REASON_TCP_OVERWINDOW, TCP_OVERWINDOW)      \
-       EM(SKB_DROP_REASON_TCP_OFOMERGE, TCP_OFOMERGE)          \
-       EM(SKB_DROP_REASON_TCP_OFO_DROP, TCP_OFO_DROP)          \
-       EM(SKB_DROP_REASON_TCP_RFC7323_PAWS, TCP_RFC7323_PAWS)  \
-       EM(SKB_DROP_REASON_TCP_INVALID_SEQUENCE,                \
-          TCP_INVALID_SEQUENCE)                                \
-       EM(SKB_DROP_REASON_TCP_RESET, TCP_RESET)                \
-       EM(SKB_DROP_REASON_TCP_INVALID_SYN, TCP_INVALID_SYN)    \
-       EM(SKB_DROP_REASON_TCP_CLOSE, TCP_CLOSE)                \
-       EM(SKB_DROP_REASON_TCP_FASTOPEN, TCP_FASTOPEN)          \
-       EM(SKB_DROP_REASON_TCP_OLD_ACK, TCP_OLD_ACK)            \
-       EM(SKB_DROP_REASON_TCP_TOO_OLD_ACK, TCP_TOO_OLD_ACK)    \
-       EM(SKB_DROP_REASON_TCP_ACK_UNSENT_DATA,                 \
-          TCP_ACK_UNSENT_DATA)                                 \
-       EM(SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE,                 \
-         TCP_OFO_QUEUE_PRUNE)                                  \
-       EM(SKB_DROP_REASON_IP_OUTNOROUTES, IP_OUTNOROUTES)      \
-       EM(SKB_DROP_REASON_BPF_CGROUP_EGRESS,                   \
-          BPF_CGROUP_EGRESS)                                   \
-       EM(SKB_DROP_REASON_IPV6DISABLED, IPV6DISABLED)          \
-       EM(SKB_DROP_REASON_NEIGH_CREATEFAIL, NEIGH_CREATEFAIL)  \
-       EM(SKB_DROP_REASON_NEIGH_FAILED, NEIGH_FAILED)          \
-       EM(SKB_DROP_REASON_NEIGH_QUEUEFULL, NEIGH_QUEUEFULL)    \
-       EM(SKB_DROP_REASON_NEIGH_DEAD, NEIGH_DEAD)              \
-       EM(SKB_DROP_REASON_TC_EGRESS, TC_EGRESS)                \
-       EM(SKB_DROP_REASON_QDISC_DROP, QDISC_DROP)              \
-       EM(SKB_DROP_REASON_CPU_BACKLOG, CPU_BACKLOG)            \
-       EM(SKB_DROP_REASON_XDP, XDP)                            \
-       EM(SKB_DROP_REASON_TC_INGRESS, TC_INGRESS)              \
-       EM(SKB_DROP_REASON_UNHANDLED_PROTO, UNHANDLED_PROTO)    \
-       EM(SKB_DROP_REASON_SKB_CSUM, SKB_CSUM)                  \
-       EM(SKB_DROP_REASON_SKB_GSO_SEG, SKB_GSO_SEG)            \
-       EM(SKB_DROP_REASON_SKB_UCOPY_FAULT, SKB_UCOPY_FAULT)    \
-       EM(SKB_DROP_REASON_DEV_HDR, DEV_HDR)                    \
-       EM(SKB_DROP_REASON_DEV_READY, DEV_READY)                \
-       EM(SKB_DROP_REASON_FULL_RING, FULL_RING)                \
-       EM(SKB_DROP_REASON_NOMEM, NOMEM)                        \
-       EM(SKB_DROP_REASON_HDR_TRUNC, HDR_TRUNC)                \
-       EM(SKB_DROP_REASON_TAP_FILTER, TAP_FILTER)              \
-       EM(SKB_DROP_REASON_TAP_TXFILTER, TAP_TXFILTER)          \
-       EM(SKB_DROP_REASON_ICMP_CSUM, ICMP_CSUM)                \
-       EM(SKB_DROP_REASON_INVALID_PROTO, INVALID_PROTO)        \
-       EM(SKB_DROP_REASON_IP_INADDRERRORS, IP_INADDRERRORS)    \
-       EM(SKB_DROP_REASON_IP_INNOROUTES, IP_INNOROUTES)        \
-       EM(SKB_DROP_REASON_PKT_TOO_BIG, PKT_TOO_BIG)            \
-       EMe(SKB_DROP_REASON_MAX, MAX)
-
-#undef EM
-#undef EMe
-
-#define EM(a, b)       TRACE_DEFINE_ENUM(a);
-#define EMe(a, b)      TRACE_DEFINE_ENUM(a);
-
-TRACE_SKB_DROP_REASON
-
-#undef EM
-#undef EMe
-#define EM(a, b)       { a, #b },
-#define EMe(a, b)      { a, #b }
-
 /*
  * Tracepoint for free an sk_buff:
  */
@@ -121,8 +35,7 @@ TRACE_EVENT(kfree_skb,
 
        TP_printk("skbaddr=%p protocol=%u location=%p reason: %s",
                  __entry->skbaddr, __entry->protocol, __entry->location,
-                 __print_symbolic(__entry->reason,
-                                  TRACE_SKB_DROP_REASON))
+                 drop_reasons[__entry->reason])
 );
 
 TRACE_EVENT(consume_skb,
index f4009db..e813628 100644 (file)
@@ -3597,10 +3597,11 @@ union bpf_attr {
  *
  *             *iph* points to the start of the IPv4 or IPv6 header, while
  *             *iph_len* contains **sizeof**\ (**struct iphdr**) or
- *             **sizeof**\ (**struct ip6hdr**).
+ *             **sizeof**\ (**struct ipv6hdr**).
  *
  *             *th* points to the start of the TCP header, while *th_len*
- *             contains **sizeof**\ (**struct tcphdr**).
+ *             contains the length of the TCP header (at least
+ *             **sizeof**\ (**struct tcphdr**)).
  *     Return
  *             0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
  *             error otherwise.
@@ -3783,10 +3784,11 @@ union bpf_attr {
  *
  *             *iph* points to the start of the IPv4 or IPv6 header, while
  *             *iph_len* contains **sizeof**\ (**struct iphdr**) or
- *             **sizeof**\ (**struct ip6hdr**).
+ *             **sizeof**\ (**struct ipv6hdr**).
  *
  *             *th* points to the start of the TCP header, while *th_len*
- *             contains the length of the TCP header.
+ *             contains the length of the TCP header with options (at least
+ *             **sizeof**\ (**struct tcphdr**)).
  *     Return
  *             On success, lower 32 bits hold the generated SYN cookie in
  *             followed by 16 bits which hold the MSS value for that cookie,
@@ -5249,6 +5251,80 @@ union bpf_attr {
  *             Pointer to the underlying dynptr data, NULL if the dynptr is
  *             read-only, if the dynptr is invalid, or if the offset and length
  *             is out of bounds.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len)
+ *     Description
+ *             Try to issue a SYN cookie for the packet with corresponding
+ *             IPv4/TCP headers, *iph* and *th*, without depending on a
+ *             listening socket.
+ *
+ *             *iph* points to the IPv4 header.
+ *
+ *             *th* points to the start of the TCP header, while *th_len*
+ *             contains the length of the TCP header (at least
+ *             **sizeof**\ (**struct tcphdr**)).
+ *     Return
+ *             On success, lower 32 bits hold the generated SYN cookie in
+ *             followed by 16 bits which hold the MSS value for that cookie,
+ *             and the top 16 bits are unused.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EINVAL** if *th_len* is invalid.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len)
+ *     Description
+ *             Try to issue a SYN cookie for the packet with corresponding
+ *             IPv6/TCP headers, *iph* and *th*, without depending on a
+ *             listening socket.
+ *
+ *             *iph* points to the IPv6 header.
+ *
+ *             *th* points to the start of the TCP header, while *th_len*
+ *             contains the length of the TCP header (at least
+ *             **sizeof**\ (**struct tcphdr**)).
+ *     Return
+ *             On success, lower 32 bits hold the generated SYN cookie in
+ *             followed by 16 bits which hold the MSS value for that cookie,
+ *             and the top 16 bits are unused.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EINVAL** if *th_len* is invalid.
+ *
+ *             **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
+ *
+ * long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th)
+ *     Description
+ *             Check whether *iph* and *th* contain a valid SYN cookie ACK
+ *             without depending on a listening socket.
+ *
+ *             *iph* points to the IPv4 header.
+ *
+ *             *th* points to the TCP header.
+ *     Return
+ *             0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EACCES** if the SYN cookie is not valid.
+ *
+ * long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th)
+ *     Description
+ *             Check whether *iph* and *th* contain a valid SYN cookie ACK
+ *             without depending on a listening socket.
+ *
+ *             *iph* points to the IPv6 header.
+ *
+ *             *th* points to the TCP header.
+ *     Return
+ *             0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EACCES** if the SYN cookie is not valid.
+ *
+ *             **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -5455,6 +5531,10 @@ union bpf_attr {
        FN(dynptr_read),                \
        FN(dynptr_write),               \
        FN(dynptr_data),                \
+       FN(tcp_raw_gen_syncookie_ipv4), \
+       FN(tcp_raw_gen_syncookie_ipv6), \
+       FN(tcp_raw_check_syncookie_ipv4),       \
+       FN(tcp_raw_check_syncookie_ipv6),       \
        /* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
index a9162a6..ec1798b 100644 (file)
@@ -36,10 +36,10 @@ struct btf_type {
         * bits 24-28: kind (e.g. int, ptr, array...etc)
         * bits 29-30: unused
         * bit     31: kind_flag, currently used by
-        *             struct, union and fwd
+        *             struct, union, enum, fwd and enum64
         */
        __u32 info;
-       /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC.
+       /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
         * "size" tells the size of the type it is describing.
         *
         * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
@@ -63,7 +63,7 @@ enum {
        BTF_KIND_ARRAY          = 3,    /* Array        */
        BTF_KIND_STRUCT         = 4,    /* Struct       */
        BTF_KIND_UNION          = 5,    /* Union        */
-       BTF_KIND_ENUM           = 6,    /* Enumeration  */
+       BTF_KIND_ENUM           = 6,    /* Enumeration up to 32-bit values */
        BTF_KIND_FWD            = 7,    /* Forward      */
        BTF_KIND_TYPEDEF        = 8,    /* Typedef      */
        BTF_KIND_VOLATILE       = 9,    /* Volatile     */
@@ -76,6 +76,7 @@ enum {
        BTF_KIND_FLOAT          = 16,   /* Floating point       */
        BTF_KIND_DECL_TAG       = 17,   /* Decl Tag */
        BTF_KIND_TYPE_TAG       = 18,   /* Type Tag */
+       BTF_KIND_ENUM64         = 19,   /* Enumeration up to 64-bit values */
 
        NR_BTF_KINDS,
        BTF_KIND_MAX            = NR_BTF_KINDS - 1,
@@ -186,4 +187,14 @@ struct btf_decl_tag {
        __s32   component_idx;
 };
 
+/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64".
+ * The exact number of btf_enum64 is stored in the vlen (of the
+ * info in "struct btf_type").
+ */
+struct btf_enum64 {
+       __u32   name_off;
+       __u32   val_lo32;
+       __u32   val_hi32;
+};
+
 #endif /* _UAPI__LINUX_BTF_H__ */
index 1d0bccc..d370165 100644 (file)
 #define ETH_P_QINQ3    0x9300          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_EDSA     0xDADA          /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_DSA_8021Q        0xDADB          /* Fake VLAN Header for DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DSA_A5PSW        0xE001          /* A5PSW Tag Value [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_IFE      0xED3E          /* ForCES inter-FE LFB type */
 #define ETH_P_AF_IUCV   0xFBFB         /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
 
index 5f58dcf..e36d9d2 100644 (file)
@@ -963,6 +963,7 @@ enum {
        IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
        IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
        IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+       IFLA_BOND_SLAVE_PRIO,
        __IFLA_BOND_SLAVE_MAX,
 };
 
index 39c565e..a998bf7 100644 (file)
@@ -154,6 +154,7 @@ enum {
        NDTPA_QUEUE_LENBYTES,           /* u32 */
        NDTPA_MCAST_REPROBES,           /* u32 */
        NDTPA_PAD,
+       NDTPA_INTERVAL_PROBE_TIME_MS,   /* u64, msecs */
        __NDTPA_MAX
 };
 #define NDTPA_MAX (__NDTPA_MAX - 1)
index d9490e3..98f905f 100644 (file)
@@ -5874,7 +5874,7 @@ enum nl80211_ap_sme_features {
  * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
  *     the connected inactive stations in AP mode.
  * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
- *     to work properly to suppport receiving regulatory hints from
+ *     to work properly to support receiving regulatory hints from
  *     cellular base stations.
  * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: (no longer available, only
  *     here to reserve the value for API/ABI compatibility)
index 904909d..1c9152a 100644 (file)
@@ -344,6 +344,7 @@ enum
        LINUX_MIB_TLSRXDEVICE,                  /* TlsRxDevice */
        LINUX_MIB_TLSDECRYPTERROR,              /* TlsDecryptError */
        LINUX_MIB_TLSRXDEVICERESYNC,            /* TlsRxDeviceResync */
+       LINUX_MIN_TLSDECRYPTRETRY,              /* TlsDecryptRetry */
        __LINUX_MIB_TLSMAX
 };
 
index 6a3b194..8981f00 100644 (file)
@@ -584,24 +584,25 @@ enum {
 
 /* /proc/sys/net/<protocol>/neigh/<dev> */
 enum {
-       NET_NEIGH_MCAST_SOLICIT=1,
-       NET_NEIGH_UCAST_SOLICIT=2,
-       NET_NEIGH_APP_SOLICIT=3,
-       NET_NEIGH_RETRANS_TIME=4,
-       NET_NEIGH_REACHABLE_TIME=5,
-       NET_NEIGH_DELAY_PROBE_TIME=6,
-       NET_NEIGH_GC_STALE_TIME=7,
-       NET_NEIGH_UNRES_QLEN=8,
-       NET_NEIGH_PROXY_QLEN=9,
-       NET_NEIGH_ANYCAST_DELAY=10,
-       NET_NEIGH_PROXY_DELAY=11,
-       NET_NEIGH_LOCKTIME=12,
-       NET_NEIGH_GC_INTERVAL=13,
-       NET_NEIGH_GC_THRESH1=14,
-       NET_NEIGH_GC_THRESH2=15,
-       NET_NEIGH_GC_THRESH3=16,
-       NET_NEIGH_RETRANS_TIME_MS=17,
-       NET_NEIGH_REACHABLE_TIME_MS=18,
+       NET_NEIGH_MCAST_SOLICIT = 1,
+       NET_NEIGH_UCAST_SOLICIT = 2,
+       NET_NEIGH_APP_SOLICIT = 3,
+       NET_NEIGH_RETRANS_TIME = 4,
+       NET_NEIGH_REACHABLE_TIME = 5,
+       NET_NEIGH_DELAY_PROBE_TIME = 6,
+       NET_NEIGH_GC_STALE_TIME = 7,
+       NET_NEIGH_UNRES_QLEN = 8,
+       NET_NEIGH_PROXY_QLEN = 9,
+       NET_NEIGH_ANYCAST_DELAY = 10,
+       NET_NEIGH_PROXY_DELAY = 11,
+       NET_NEIGH_LOCKTIME = 12,
+       NET_NEIGH_GC_INTERVAL = 13,
+       NET_NEIGH_GC_THRESH1 = 14,
+       NET_NEIGH_GC_THRESH2 = 15,
+       NET_NEIGH_GC_THRESH3 = 16,
+       NET_NEIGH_RETRANS_TIME_MS = 17,
+       NET_NEIGH_REACHABLE_TIME_MS = 18,
+       NET_NEIGH_INTERVAL_PROBE_TIME_MS = 19,
 };
 
 /* /proc/sys/net/dccp */
index bb8f808..f1157d8 100644 (file)
@@ -40,6 +40,7 @@
 #define TLS_TX                 1       /* Set transmit parameters */
 #define TLS_RX                 2       /* Set receive parameters */
 #define TLS_TX_ZEROCOPY_RO     3       /* TX zerocopy (only sendfile now) */
+#define TLS_RX_EXPECT_NO_PAD   4       /* Attempt opportunistic zero-copy */
 
 /* Supported versions */
 #define TLS_VERSION_MINOR(ver) ((ver) & 0xFF)
@@ -162,6 +163,7 @@ enum {
        TLS_INFO_TXCONF,
        TLS_INFO_RXCONF,
        TLS_INFO_ZC_RO_TX,
+       TLS_INFO_RX_NO_PAD,
        __TLS_INFO_MAX,
 };
 #define TLS_INFO_MAX (__TLS_INFO_MAX - 1)
index 9d0f06b..68aeae2 100644 (file)
@@ -38,8 +38,9 @@
 #define N_NULL         27      /* Null ldisc used for error handling */
 #define N_MCTP         28      /* MCTP-over-serial */
 #define N_DEVELOPMENT  29      /* Manual out-of-tree testing */
+#define N_CAN327       30      /* ELM327 based OBD-II interfaces */
 
 /* Always the newest line discipline + 1 */
-#define NR_LDISCS      30
+#define NR_LDISCS      31
 
 #endif /* _UAPI_LINUX_TTY_H */
index a21ca8e..7af9e09 100644 (file)
@@ -63,6 +63,7 @@ enum mlx5_ib_uapi_dm_type {
        MLX5_IB_UAPI_DM_TYPE_MEMIC,
        MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM,
        MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM,
+       MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM,
 };
 
 enum mlx5_ib_uapi_devx_create_event_channel_flags {
index eb12d4f..d003d4d 100644 (file)
@@ -309,6 +309,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
        [BTF_KIND_FLOAT]        = "FLOAT",
        [BTF_KIND_DECL_TAG]     = "DECL_TAG",
        [BTF_KIND_TYPE_TAG]     = "TYPE_TAG",
+       [BTF_KIND_ENUM64]       = "ENUM64",
 };
 
 const char *btf_type_str(const struct btf_type *t)
@@ -666,6 +667,7 @@ static bool btf_type_has_size(const struct btf_type *t)
        case BTF_KIND_ENUM:
        case BTF_KIND_DATASEC:
        case BTF_KIND_FLOAT:
+       case BTF_KIND_ENUM64:
                return true;
        }
 
@@ -711,6 +713,11 @@ static const struct btf_decl_tag *btf_type_decl_tag(const struct btf_type *t)
        return (const struct btf_decl_tag *)(t + 1);
 }
 
+static const struct btf_enum64 *btf_type_enum64(const struct btf_type *t)
+{
+       return (const struct btf_enum64 *)(t + 1);
+}
+
 static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t)
 {
        return kind_ops[BTF_INFO_KIND(t->info)];
@@ -1019,6 +1026,7 @@ static const char *btf_show_name(struct btf_show *show)
                        parens = "{";
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                prefix = "enum";
                break;
        default:
@@ -1834,6 +1842,7 @@ __btf_resolve_size(const struct btf *btf, const struct btf_type *type,
                case BTF_KIND_UNION:
                case BTF_KIND_ENUM:
                case BTF_KIND_FLOAT:
+               case BTF_KIND_ENUM64:
                        size = type->size;
                        goto resolved;
 
@@ -3670,6 +3679,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
 {
        const struct btf_enum *enums = btf_type_enum(t);
        struct btf *btf = env->btf;
+       const char *fmt_str;
        u16 i, nr_enums;
        u32 meta_needed;
 
@@ -3683,11 +3693,6 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
                return -EINVAL;
        }
 
-       if (btf_type_kflag(t)) {
-               btf_verifier_log_type(env, t, "Invalid btf_info kind_flag");
-               return -EINVAL;
-       }
-
        if (t->size > 8 || !is_power_of_2(t->size)) {
                btf_verifier_log_type(env, t, "Unexpected size");
                return -EINVAL;
@@ -3718,7 +3723,8 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
 
                if (env->log.level == BPF_LOG_KERNEL)
                        continue;
-               btf_verifier_log(env, "\t%s val=%d\n",
+               fmt_str = btf_type_kflag(t) ? "\t%s val=%d\n" : "\t%s val=%u\n";
+               btf_verifier_log(env, fmt_str,
                                 __btf_name_by_offset(btf, enums[i].name_off),
                                 enums[i].val);
        }
@@ -3759,7 +3765,10 @@ static void btf_enum_show(const struct btf *btf, const struct btf_type *t,
                return;
        }
 
-       btf_show_type_value(show, "%d", v);
+       if (btf_type_kflag(t))
+               btf_show_type_value(show, "%d", v);
+       else
+               btf_show_type_value(show, "%u", v);
        btf_show_end_type(show);
 }
 
@@ -3772,6 +3781,109 @@ static struct btf_kind_operations enum_ops = {
        .show = btf_enum_show,
 };
 
+static s32 btf_enum64_check_meta(struct btf_verifier_env *env,
+                                const struct btf_type *t,
+                                u32 meta_left)
+{
+       const struct btf_enum64 *enums = btf_type_enum64(t);
+       struct btf *btf = env->btf;
+       const char *fmt_str;
+       u16 i, nr_enums;
+       u32 meta_needed;
+
+       nr_enums = btf_type_vlen(t);
+       meta_needed = nr_enums * sizeof(*enums);
+
+       if (meta_left < meta_needed) {
+               btf_verifier_log_basic(env, t,
+                                      "meta_left:%u meta_needed:%u",
+                                      meta_left, meta_needed);
+               return -EINVAL;
+       }
+
+       if (t->size > 8 || !is_power_of_2(t->size)) {
+               btf_verifier_log_type(env, t, "Unexpected size");
+               return -EINVAL;
+       }
+
+       /* enum type either no name or a valid one */
+       if (t->name_off &&
+           !btf_name_valid_identifier(env->btf, t->name_off)) {
+               btf_verifier_log_type(env, t, "Invalid name");
+               return -EINVAL;
+       }
+
+       btf_verifier_log_type(env, t, NULL);
+
+       for (i = 0; i < nr_enums; i++) {
+               if (!btf_name_offset_valid(btf, enums[i].name_off)) {
+                       btf_verifier_log(env, "\tInvalid name_offset:%u",
+                                        enums[i].name_off);
+                       return -EINVAL;
+               }
+
+               /* enum member must have a valid name */
+               if (!enums[i].name_off ||
+                   !btf_name_valid_identifier(btf, enums[i].name_off)) {
+                       btf_verifier_log_type(env, t, "Invalid name");
+                       return -EINVAL;
+               }
+
+               if (env->log.level == BPF_LOG_KERNEL)
+                       continue;
+
+               fmt_str = btf_type_kflag(t) ? "\t%s val=%lld\n" : "\t%s val=%llu\n";
+               btf_verifier_log(env, fmt_str,
+                                __btf_name_by_offset(btf, enums[i].name_off),
+                                btf_enum64_value(enums + i));
+       }
+
+       return meta_needed;
+}
+
+static void btf_enum64_show(const struct btf *btf, const struct btf_type *t,
+                           u32 type_id, void *data, u8 bits_offset,
+                           struct btf_show *show)
+{
+       const struct btf_enum64 *enums = btf_type_enum64(t);
+       u32 i, nr_enums = btf_type_vlen(t);
+       void *safe_data;
+       s64 v;
+
+       safe_data = btf_show_start_type(show, t, type_id, data);
+       if (!safe_data)
+               return;
+
+       v = *(u64 *)safe_data;
+
+       for (i = 0; i < nr_enums; i++) {
+               if (v != btf_enum64_value(enums + i))
+                       continue;
+
+               btf_show_type_value(show, "%s",
+                                   __btf_name_by_offset(btf,
+                                                        enums[i].name_off));
+
+               btf_show_end_type(show);
+               return;
+       }
+
+       if (btf_type_kflag(t))
+               btf_show_type_value(show, "%lld", v);
+       else
+               btf_show_type_value(show, "%llu", v);
+       btf_show_end_type(show);
+}
+
+static struct btf_kind_operations enum64_ops = {
+       .check_meta = btf_enum64_check_meta,
+       .resolve = btf_df_resolve,
+       .check_member = btf_enum_check_member,
+       .check_kflag_member = btf_enum_check_kflag_member,
+       .log_details = btf_enum_log,
+       .show = btf_enum64_show,
+};
+
 static s32 btf_func_proto_check_meta(struct btf_verifier_env *env,
                                     const struct btf_type *t,
                                     u32 meta_left)
@@ -4438,6 +4550,7 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = {
        [BTF_KIND_FLOAT] = &float_ops,
        [BTF_KIND_DECL_TAG] = &decl_tag_ops,
        [BTF_KIND_TYPE_TAG] = &modifier_ops,
+       [BTF_KIND_ENUM64] = &enum64_ops,
 };
 
 static s32 btf_check_meta(struct btf_verifier_env *env,
@@ -5304,7 +5417,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
        /* skip modifiers */
        while (btf_type_is_modifier(t))
                t = btf_type_by_id(btf, t->type);
-       if (btf_type_is_small_int(t) || btf_type_is_enum(t))
+       if (btf_type_is_small_int(t) || btf_is_any_enum(t))
                /* accessing a scalar */
                return true;
        if (!btf_type_is_ptr(t)) {
@@ -5768,7 +5881,7 @@ static int __get_type_size(struct btf *btf, u32 btf_id,
        if (btf_type_is_ptr(t))
                /* kernel size of pointer. Not BPF's size of pointer*/
                return sizeof(void *);
-       if (btf_type_is_int(t) || btf_type_is_enum(t))
+       if (btf_type_is_int(t) || btf_is_any_enum(t))
                return t->size;
        *bad_type = t;
        return -EINVAL;
@@ -5916,7 +6029,7 @@ static int btf_check_func_type_match(struct bpf_verifier_log *log,
                 * to context only. And only global functions can be replaced.
                 * Hence type check only those types.
                 */
-               if (btf_type_is_int(t1) || btf_type_is_enum(t1))
+               if (btf_type_is_int(t1) || btf_is_any_enum(t1))
                        continue;
                if (!btf_type_is_ptr(t1)) {
                        bpf_log(log,
@@ -6414,7 +6527,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
        t = btf_type_by_id(btf, t->type);
        while (btf_type_is_modifier(t))
                t = btf_type_by_id(btf, t->type);
-       if (!btf_type_is_int(t) && !btf_type_is_enum(t)) {
+       if (!btf_type_is_int(t) && !btf_is_any_enum(t)) {
                bpf_log(log,
                        "Global function %s() doesn't return scalar. Only those are supported.\n",
                        tname);
@@ -6429,7 +6542,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
                t = btf_type_by_id(btf, args[i].type);
                while (btf_type_is_modifier(t))
                        t = btf_type_by_id(btf, t->type);
-               if (btf_type_is_int(t) || btf_type_is_enum(t)) {
+               if (btf_type_is_int(t) || btf_is_any_enum(t)) {
                        reg->type = SCALAR_VALUE;
                        continue;
                }
@@ -7341,6 +7454,7 @@ recur:
        case BTF_KIND_UNION:
        case BTF_KIND_ENUM:
        case BTF_KIND_FWD:
+       case BTF_KIND_ENUM64:
                return 1;
        case BTF_KIND_INT:
                /* just reject deprecated bitfield-like integers; all other
@@ -7393,10 +7507,10 @@ recur:
  * field-based relocations. This function assumes that root types were already
  * checked for name match. Beyond that initial root-level name check, names
  * are completely ignored. Compatibility rules are as follows:
- *   - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs are considered compatible, but
+ *   - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs/ENUM64s are considered compatible, but
  *     kind should match for local and target types (i.e., STRUCT is not
  *     compatible with UNION);
- *   - for ENUMs, the size is ignored;
+ *   - for ENUMs/ENUM64s, the size is ignored;
  *   - for INT, size and signedness are ignored;
  *   - for ARRAY, dimensionality is ignored, element types are checked for
  *     compatibility recursively;
index afb414b..7a394f7 100644 (file)
@@ -721,6 +721,60 @@ static struct bpf_prog_list *find_detach_entry(struct list_head *progs,
 }
 
 /**
+ * purge_effective_progs() - After compute_effective_progs fails to alloc new
+ *                           cgrp->bpf.inactive table we can recover by
+ *                           recomputing the array in place.
+ *
+ * @cgrp: The cgroup which descendants to travers
+ * @prog: A program to detach or NULL
+ * @link: A link to detach or NULL
+ * @atype: Type of detach operation
+ */
+static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,
+                                 struct bpf_cgroup_link *link,
+                                 enum cgroup_bpf_attach_type atype)
+{
+       struct cgroup_subsys_state *css;
+       struct bpf_prog_array *progs;
+       struct bpf_prog_list *pl;
+       struct list_head *head;
+       struct cgroup *cg;
+       int pos;
+
+       /* recompute effective prog array in place */
+       css_for_each_descendant_pre(css, &cgrp->self) {
+               struct cgroup *desc = container_of(css, struct cgroup, self);
+
+               if (percpu_ref_is_zero(&desc->bpf.refcnt))
+                       continue;
+
+               /* find position of link or prog in effective progs array */
+               for (pos = 0, cg = desc; cg; cg = cgroup_parent(cg)) {
+                       if (pos && !(cg->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
+                               continue;
+
+                       head = &cg->bpf.progs[atype];
+                       list_for_each_entry(pl, head, node) {
+                               if (!prog_list_prog(pl))
+                                       continue;
+                               if (pl->prog == prog && pl->link == link)
+                                       goto found;
+                               pos++;
+                       }
+               }
+found:
+               BUG_ON(!cg);
+               progs = rcu_dereference_protected(
+                               desc->bpf.effective[atype],
+                               lockdep_is_held(&cgroup_mutex));
+
+               /* Remove the program from the array */
+               WARN_ONCE(bpf_prog_array_delete_safe_at(progs, pos),
+                         "Failed to purge a prog from array at index %d", pos);
+       }
+}
+
+/**
  * __cgroup_bpf_detach() - Detach the program or link from a cgroup, and
  *                         propagate the change to descendants
  * @cgrp: The cgroup which descendants to traverse
@@ -739,7 +793,6 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
        struct bpf_prog_list *pl;
        struct list_head *progs;
        u32 flags;
-       int err;
 
        atype = to_cgroup_bpf_attach_type(type);
        if (atype < 0)
@@ -761,9 +814,12 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
        pl->prog = NULL;
        pl->link = NULL;
 
-       err = update_effective_progs(cgrp, atype);
-       if (err)
-               goto cleanup;
+       if (update_effective_progs(cgrp, atype)) {
+               /* if update effective array failed replace the prog with a dummy prog*/
+               pl->prog = old_prog;
+               pl->link = link;
+               purge_effective_progs(cgrp, old_prog, link, atype);
+       }
 
        /* now can actually delete it from this cgroup list */
        list_del(&pl->node);
@@ -775,12 +831,6 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
                bpf_prog_put(old_prog);
        static_branch_dec(&cgroup_bpf_enabled_key[atype]);
        return 0;
-
-cleanup:
-       /* restore back prog or link */
-       pl->prog = old_prog;
-       pl->link = link;
-       return err;
 }
 
 static int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
index 5f6f3f8..b5ffebc 100644 (file)
@@ -176,7 +176,7 @@ void bpf_prog_jit_attempt_done(struct bpf_prog *prog)
  * here is relative to the prog itself instead of the main prog.
  * This array has one entry for each xlated bpf insn.
  *
- * jited_off is the byte off to the last byte of the jited insn.
+ * jited_off is the byte off to the end of the jited insn.
  *
  * Hence, with
  * insn_start:
@@ -2279,6 +2279,21 @@ void bpf_prog_array_free(struct bpf_prog_array *progs)
        kfree_rcu(progs, rcu);
 }
 
+static void __bpf_prog_array_free_sleepable_cb(struct rcu_head *rcu)
+{
+       struct bpf_prog_array *progs;
+
+       progs = container_of(rcu, struct bpf_prog_array, rcu);
+       kfree_rcu(progs, rcu);
+}
+
+void bpf_prog_array_free_sleepable(struct bpf_prog_array *progs)
+{
+       if (!progs || progs == &bpf_empty_prog_array.hdr)
+               return;
+       call_rcu_tasks_trace(&progs->rcu, __bpf_prog_array_free_sleepable_cb);
+}
+
 int bpf_prog_array_length(struct bpf_prog_array *array)
 {
        struct bpf_prog_array_item *item;
index 225806a..a1c84d2 100644 (file)
@@ -584,7 +584,7 @@ BPF_CALL_3(bpf_strncmp, const char *, s1, u32, s1_sz, const char *, s2)
        return strncmp(s1, s2, s1_sz);
 }
 
-const struct bpf_func_proto bpf_strncmp_proto = {
+static const struct bpf_func_proto bpf_strncmp_proto = {
        .func           = bpf_strncmp,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1402,7 +1402,7 @@ BPF_CALL_2(bpf_kptr_xchg, void *, map_value, void *, ptr)
  */
 #define BPF_PTR_POISON ((void *)((0xeB9FUL << 2) + POISON_POINTER_DELTA))
 
-const struct bpf_func_proto bpf_kptr_xchg_proto = {
+static const struct bpf_func_proto bpf_kptr_xchg_proto = {
        .func         = bpf_kptr_xchg,
        .gpl_only     = false,
        .ret_type     = RET_PTR_TO_BTF_ID_OR_NULL,
@@ -1487,7 +1487,7 @@ error:
        return err;
 }
 
-const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
+static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
        .func           = bpf_dynptr_from_mem,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1513,7 +1513,7 @@ BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src
        return 0;
 }
 
-const struct bpf_func_proto bpf_dynptr_read_proto = {
+static const struct bpf_func_proto bpf_dynptr_read_proto = {
        .func           = bpf_dynptr_read,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1539,7 +1539,7 @@ BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *,
        return 0;
 }
 
-const struct bpf_func_proto bpf_dynptr_write_proto = {
+static const struct bpf_func_proto bpf_dynptr_write_proto = {
        .func           = bpf_dynptr_write,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
@@ -1566,7 +1566,7 @@ BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len
        return (unsigned long)(ptr->data + ptr->offset + offset);
 }
 
-const struct bpf_func_proto bpf_dynptr_data_proto = {
+static const struct bpf_func_proto bpf_dynptr_data_proto = {
        .func           = bpf_dynptr_data,
        .gpl_only       = false,
        .ret_type       = RET_PTR_TO_DYNPTR_MEM_OR_NULL,
index 3d897de..00b874c 100644 (file)
@@ -31,7 +31,7 @@ static inline void pcpu_freelist_push_node(struct pcpu_freelist_head *head,
                                           struct pcpu_freelist_node *node)
 {
        node->next = head->first;
-       head->first = node;
+       WRITE_ONCE(head->first, node);
 }
 
 static inline void ___pcpu_freelist_push(struct pcpu_freelist_head *head,
@@ -130,14 +130,17 @@ static struct pcpu_freelist_node *___pcpu_freelist_pop(struct pcpu_freelist *s)
        orig_cpu = cpu = raw_smp_processor_id();
        while (1) {
                head = per_cpu_ptr(s->freelist, cpu);
+               if (!READ_ONCE(head->first))
+                       goto next_cpu;
                raw_spin_lock(&head->lock);
                node = head->first;
                if (node) {
-                       head->first = node->next;
+                       WRITE_ONCE(head->first, node->next);
                        raw_spin_unlock(&head->lock);
                        return node;
                }
                raw_spin_unlock(&head->lock);
+next_cpu:
                cpu = cpumask_next(cpu, cpu_possible_mask);
                if (cpu >= nr_cpu_ids)
                        cpu = 0;
@@ -146,10 +149,12 @@ static struct pcpu_freelist_node *___pcpu_freelist_pop(struct pcpu_freelist *s)
        }
 
        /* per cpu lists are all empty, try extralist */
+       if (!READ_ONCE(s->extralist.first))
+               return NULL;
        raw_spin_lock(&s->extralist.lock);
        node = s->extralist.first;
        if (node)
-               s->extralist.first = node->next;
+               WRITE_ONCE(s->extralist.first, node->next);
        raw_spin_unlock(&s->extralist.lock);
        return node;
 }
@@ -164,15 +169,18 @@ ___pcpu_freelist_pop_nmi(struct pcpu_freelist *s)
        orig_cpu = cpu = raw_smp_processor_id();
        while (1) {
                head = per_cpu_ptr(s->freelist, cpu);
+               if (!READ_ONCE(head->first))
+                       goto next_cpu;
                if (raw_spin_trylock(&head->lock)) {
                        node = head->first;
                        if (node) {
-                               head->first = node->next;
+                               WRITE_ONCE(head->first, node->next);
                                raw_spin_unlock(&head->lock);
                                return node;
                        }
                        raw_spin_unlock(&head->lock);
                }
+next_cpu:
                cpu = cpumask_next(cpu, cpu_possible_mask);
                if (cpu >= nr_cpu_ids)
                        cpu = 0;
@@ -181,11 +189,11 @@ ___pcpu_freelist_pop_nmi(struct pcpu_freelist *s)
        }
 
        /* cannot pop from per cpu lists, try extralist */
-       if (!raw_spin_trylock(&s->extralist.lock))
+       if (!READ_ONCE(s->extralist.first) || !raw_spin_trylock(&s->extralist.lock))
                return NULL;
        node = s->extralist.first;
        if (node)
-               s->extralist.first = node->next;
+               WRITE_ONCE(s->extralist.first, node->next);
        raw_spin_unlock(&s->extralist.lock);
        return node;
 }
index 2b69306..7d5af5b 100644 (file)
@@ -4090,14 +4090,15 @@ static int bpf_prog_get_info_by_fd(struct file *file,
                info.nr_jited_line_info = 0;
        if (info.nr_jited_line_info && ulen) {
                if (bpf_dump_raw_ok(file->f_cred)) {
+                       unsigned long line_addr;
                        __u64 __user *user_linfo;
                        u32 i;
 
                        user_linfo = u64_to_user_ptr(info.jited_line_info);
                        ulen = min_t(u32, info.nr_jited_line_info, ulen);
                        for (i = 0; i < ulen; i++) {
-                               if (put_user((__u64)(long)prog->aux->jited_linfo[i],
-                                            &user_linfo[i]))
+                               line_addr = (unsigned long)prog->aux->jited_linfo[i];
+                               if (put_user((__u64)line_addr, &user_linfo[i]))
                                        return -EFAULT;
                        }
                } else {
@@ -5130,7 +5131,7 @@ BPF_CALL_4(bpf_kallsyms_lookup_name, const char *, name, int, name_sz, int, flag
        return *res ? 0 : -ENOENT;
 }
 
-const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
+static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
        .func           = bpf_kallsyms_lookup_name,
        .gpl_only       = false,
        .ret_type       = RET_INTEGER,
index 0efbac0..a4012b3 100644 (file)
@@ -5847,6 +5847,7 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
        struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
        enum bpf_arg_type arg_type = fn->arg_type[arg];
        enum bpf_reg_type type = reg->type;
+       u32 *arg_btf_id = NULL;
        int err = 0;
 
        if (arg_type == ARG_DONTCARE)
@@ -5883,7 +5884,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
                 */
                goto skip_type_check;
 
-       err = check_reg_type(env, regno, arg_type, fn->arg_btf_id[arg], meta);
+       /* arg_btf_id and arg_size are in a union. */
+       if (base_type(arg_type) == ARG_PTR_TO_BTF_ID)
+               arg_btf_id = fn->arg_btf_id[arg];
+
+       err = check_reg_type(env, regno, arg_type, arg_btf_id, meta);
        if (err)
                return err;
 
@@ -6010,6 +6015,11 @@ skip_type_check:
                 * next is_mem_size argument below.
                 */
                meta->raw_mode = arg_type & MEM_UNINIT;
+               if (arg_type & MEM_FIXED_SIZE) {
+                       err = check_helper_mem_access(env, regno,
+                                                     fn->arg_size[arg], false,
+                                                     meta);
+               }
        } else if (arg_type_is_mem_size(arg_type)) {
                bool zero_size_allowed = (arg_type == ARG_CONST_SIZE_OR_ZERO);
 
@@ -6399,11 +6409,19 @@ static bool check_raw_mode_ok(const struct bpf_func_proto *fn)
        return count <= 1;
 }
 
-static bool check_args_pair_invalid(enum bpf_arg_type arg_curr,
-                                   enum bpf_arg_type arg_next)
+static bool check_args_pair_invalid(const struct bpf_func_proto *fn, int arg)
 {
-       return (base_type(arg_curr) == ARG_PTR_TO_MEM) !=
-               arg_type_is_mem_size(arg_next);
+       bool is_fixed = fn->arg_type[arg] & MEM_FIXED_SIZE;
+       bool has_size = fn->arg_size[arg] != 0;
+       bool is_next_size = false;
+
+       if (arg + 1 < ARRAY_SIZE(fn->arg_type))
+               is_next_size = arg_type_is_mem_size(fn->arg_type[arg + 1]);
+
+       if (base_type(fn->arg_type[arg]) != ARG_PTR_TO_MEM)
+               return is_next_size;
+
+       return has_size == is_next_size || is_next_size == is_fixed;
 }
 
 static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
@@ -6414,11 +6432,11 @@ static bool check_arg_pair_ok(const struct bpf_func_proto *fn)
         * helper function specification.
         */
        if (arg_type_is_mem_size(fn->arg1_type) ||
-           base_type(fn->arg5_type) == ARG_PTR_TO_MEM ||
-           check_args_pair_invalid(fn->arg1_type, fn->arg2_type) ||
-           check_args_pair_invalid(fn->arg2_type, fn->arg3_type) ||
-           check_args_pair_invalid(fn->arg3_type, fn->arg4_type) ||
-           check_args_pair_invalid(fn->arg4_type, fn->arg5_type))
+           check_args_pair_invalid(fn, 0) ||
+           check_args_pair_invalid(fn, 1) ||
+           check_args_pair_invalid(fn, 2) ||
+           check_args_pair_invalid(fn, 3) ||
+           check_args_pair_invalid(fn, 4))
                return false;
 
        return true;
@@ -6459,7 +6477,10 @@ static bool check_btf_id_ok(const struct bpf_func_proto *fn)
                if (base_type(fn->arg_type[i]) == ARG_PTR_TO_BTF_ID && !fn->arg_btf_id[i])
                        return false;
 
-               if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i])
+               if (base_type(fn->arg_type[i]) != ARG_PTR_TO_BTF_ID && fn->arg_btf_id[i] &&
+                   /* arg_btf_id and arg_size are in a union. */
+                   (base_type(fn->arg_type[i]) != ARG_PTR_TO_MEM ||
+                    !(fn->arg_type[i] & MEM_FIXED_SIZE)))
                        return false;
        }
 
@@ -10882,7 +10903,7 @@ static int check_btf_func(struct bpf_verifier_env *env,
                        goto err_free;
                ret_type = btf_type_skip_modifiers(btf, func_proto->type, NULL);
                scalar_return =
-                       btf_type_is_small_int(ret_type) || btf_type_is_enum(ret_type);
+                       btf_type_is_small_int(ret_type) || btf_is_any_enum(ret_type);
                if (i && !scalar_return && env->subprog_info[i].has_ld_abs) {
                        verbose(env, "LD_ABS is only allowed in functions that return 'int'.\n");
                        goto err_free;
@@ -14810,8 +14831,8 @@ static int check_attach_btf_id(struct bpf_verifier_env *env)
        }
 
        if (prog->aux->sleepable && prog->type != BPF_PROG_TYPE_TRACING &&
-           prog->type != BPF_PROG_TYPE_LSM) {
-               verbose(env, "Only fentry/fexit/fmod_ret and lsm programs can be sleepable\n");
+           prog->type != BPF_PROG_TYPE_LSM && prog->type != BPF_PROG_TYPE_KPROBE) {
+               verbose(env, "Only fentry/fexit/fmod_ret, lsm, and kprobe/uprobe programs can be sleepable\n");
                return -EINVAL;
        }
 
index 80782cd..48bae58 100644 (file)
@@ -10068,26 +10068,30 @@ static inline bool perf_event_is_tracing(struct perf_event *event)
 int perf_event_set_bpf_prog(struct perf_event *event, struct bpf_prog *prog,
                            u64 bpf_cookie)
 {
-       bool is_kprobe, is_tracepoint, is_syscall_tp;
+       bool is_kprobe, is_uprobe, is_tracepoint, is_syscall_tp;
 
        if (!perf_event_is_tracing(event))
                return perf_event_set_bpf_handler(event, prog, bpf_cookie);
 
-       is_kprobe = event->tp_event->flags & TRACE_EVENT_FL_UKPROBE;
+       is_kprobe = event->tp_event->flags & TRACE_EVENT_FL_KPROBE;
+       is_uprobe = event->tp_event->flags & TRACE_EVENT_FL_UPROBE;
        is_tracepoint = event->tp_event->flags & TRACE_EVENT_FL_TRACEPOINT;
        is_syscall_tp = is_syscall_trace_event(event->tp_event);
-       if (!is_kprobe && !is_tracepoint && !is_syscall_tp)
+       if (!is_kprobe && !is_uprobe && !is_tracepoint && !is_syscall_tp)
                /* bpf programs can only be attached to u/kprobe or tracepoint */
                return -EINVAL;
 
-       if ((is_kprobe && prog->type != BPF_PROG_TYPE_KPROBE) ||
+       if (((is_kprobe || is_uprobe) && prog->type != BPF_PROG_TYPE_KPROBE) ||
            (is_tracepoint && prog->type != BPF_PROG_TYPE_TRACEPOINT) ||
            (is_syscall_tp && prog->type != BPF_PROG_TYPE_TRACEPOINT))
                return -EINVAL;
 
+       if (prog->type == BPF_PROG_TYPE_KPROBE && prog->aux->sleepable && !is_uprobe)
+               /* only uprobe programs are allowed to be sleepable */
+               return -EINVAL;
+
        /* Kprobe override only works for kprobes, not uprobes. */
-       if (prog->kprobe_override &&
-           !(event->tp_event->flags & TRACE_EVENT_FL_KPROBE))
+       if (prog->kprobe_override && !is_kprobe)
                return -EINVAL;
 
        if (is_tracepoint || is_syscall_tp) {
index e52b6e3..85c92e2 100644 (file)
@@ -1237,6 +1237,30 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
        return 0;
 }
 
+static int do_proc_dointvec_ms_jiffies_minmax_conv(bool *negp, unsigned long *lvalp,
+                                               int *valp, int write, void *data)
+{
+       int tmp, ret;
+       struct do_proc_dointvec_minmax_conv_param *param = data;
+       /*
+        * If writing, first do so via a temporary local int so we can
+        * bounds-check it before touching *valp.
+        */
+       int *ip = write ? &tmp : valp;
+
+       ret = do_proc_dointvec_ms_jiffies_conv(negp, lvalp, ip, write, data);
+       if (ret)
+               return ret;
+
+       if (write) {
+               if ((param->min && *param->min > tmp) ||
+                               (param->max && *param->max < tmp))
+                       return -EINVAL;
+               *valp = tmp;
+       }
+       return 0;
+}
+
 /**
  * proc_dointvec_jiffies - read a vector of integers as seconds
  * @table: the sysctl table
@@ -1259,6 +1283,17 @@ int proc_dointvec_jiffies(struct ctl_table *table, int write,
                            do_proc_dointvec_jiffies_conv,NULL);
 }
 
+int proc_dointvec_ms_jiffies_minmax(struct ctl_table *table, int write,
+                         void *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct do_proc_dointvec_minmax_conv_param param = {
+               .min = (int *) table->extra1,
+               .max = (int *) table->extra2,
+       };
+       return do_proc_dointvec(table, write, buffer, lenp, ppos,
+                       do_proc_dointvec_ms_jiffies_minmax_conv, &param);
+}
+
 /**
  * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds
  * @table: the sysctl table
@@ -1523,6 +1558,12 @@ int proc_dointvec_jiffies(struct ctl_table *table, int write,
        return -ENOSYS;
 }
 
+int proc_dointvec_ms_jiffies_minmax(struct ctl_table *table, int write,
+                                   void *buffer, size_t *lenp, loff_t *ppos)
+{
+       return -ENOSYS;
+}
+
 int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
                    void *buffer, size_t *lenp, loff_t *ppos)
 {
index 88589d7..68e5cdd 100644 (file)
@@ -1936,7 +1936,7 @@ int perf_event_attach_bpf_prog(struct perf_event *event,
        event->prog = prog;
        event->bpf_cookie = bpf_cookie;
        rcu_assign_pointer(event->tp_event->prog_array, new_array);
-       bpf_prog_array_free(old_array);
+       bpf_prog_array_free_sleepable(old_array);
 
 unlock:
        mutex_unlock(&bpf_event_mutex);
@@ -1962,7 +1962,7 @@ void perf_event_detach_bpf_prog(struct perf_event *event)
                bpf_prog_array_delete_safe(old_array, event->prog);
        } else {
                rcu_assign_pointer(event->tp_event->prog_array, new_array);
-               bpf_prog_array_free(old_array);
+               bpf_prog_array_free_sleepable(old_array);
        }
 
        bpf_prog_put(event->prog);
index c3dc4f8..1f5351c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/namei.h>
 #include <linux/string.h>
 #include <linux/rculist.h>
+#include <linux/filter.h>
 
 #include "trace_dynevent.h"
 #include "trace_probe.h"
@@ -1345,9 +1346,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
        if (bpf_prog_array_valid(call)) {
                u32 ret;
 
-               preempt_disable();
-               ret = trace_call_bpf(call, regs);
-               preempt_enable();
+               ret = bpf_prog_run_array_sleepable(call->prog_array, regs, bpf_prog_run);
                if (!ret)
                        return;
        }
index d6bbbd4..7b37459 100644 (file)
 
 #include "nhc.h"
 
-static struct rb_root rb_root = RB_ROOT;
-static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX + 1];
+static const struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX + 1];
 static DEFINE_SPINLOCK(lowpan_nhc_lock);
 
-static int lowpan_nhc_insert(struct lowpan_nhc *nhc)
+static const struct lowpan_nhc *lowpan_nhc_by_nhcid(struct sk_buff *skb)
 {
-       struct rb_node **new = &rb_root.rb_node, *parent = NULL;
-
-       /* Figure out where to put new node */
-       while (*new) {
-               struct lowpan_nhc *this = rb_entry(*new, struct lowpan_nhc,
-                                                  node);
-               int result, len_dif, len;
-
-               len_dif = nhc->idlen - this->idlen;
-
-               if (nhc->idlen < this->idlen)
-                       len = nhc->idlen;
-               else
-                       len = this->idlen;
-
-               result = memcmp(nhc->id, this->id, len);
-               if (!result)
-                       result = len_dif;
-
-               parent = *new;
-               if (result < 0)
-                       new = &((*new)->rb_left);
-               else if (result > 0)
-                       new = &((*new)->rb_right);
-               else
-                       return -EEXIST;
-       }
+       const struct lowpan_nhc *nhc;
+       int i;
+       u8 id;
 
-       /* Add new node and rebalance tree. */
-       rb_link_node(&nhc->node, parent, new);
-       rb_insert_color(&nhc->node, &rb_root);
+       if (!pskb_may_pull(skb, 1))
+               return NULL;
 
-       return 0;
-}
+       id = *skb->data;
 
-static void lowpan_nhc_remove(struct lowpan_nhc *nhc)
-{
-       rb_erase(&nhc->node, &rb_root);
-}
+       for (i = 0; i < NEXTHDR_MAX + 1; i++) {
+               nhc = lowpan_nexthdr_nhcs[i];
+               if (!nhc)
+                       continue;
 
-static struct lowpan_nhc *lowpan_nhc_by_nhcid(const struct sk_buff *skb)
-{
-       struct rb_node *node = rb_root.rb_node;
-       const u8 *nhcid_skb_ptr = skb->data;
-
-       while (node) {
-               struct lowpan_nhc *nhc = rb_entry(node, struct lowpan_nhc,
-                                                 node);
-               u8 nhcid_skb_ptr_masked[LOWPAN_NHC_MAX_ID_LEN];
-               int result, i;
-
-               if (nhcid_skb_ptr + nhc->idlen > skb->data + skb->len)
-                       return NULL;
-
-               /* copy and mask afterwards the nhid value from skb */
-               memcpy(nhcid_skb_ptr_masked, nhcid_skb_ptr, nhc->idlen);
-               for (i = 0; i < nhc->idlen; i++)
-                       nhcid_skb_ptr_masked[i] &= nhc->idmask[i];
-
-               result = memcmp(nhcid_skb_ptr_masked, nhc->id, nhc->idlen);
-               if (result < 0)
-                       node = node->rb_left;
-               else if (result > 0)
-                       node = node->rb_right;
-               else
+               if ((id & nhc->idmask) == nhc->id)
                        return nhc;
        }
 
@@ -92,7 +41,7 @@ static struct lowpan_nhc *lowpan_nhc_by_nhcid(const struct sk_buff *skb)
 int lowpan_nhc_check_compression(struct sk_buff *skb,
                                 const struct ipv6hdr *hdr, u8 **hc_ptr)
 {
-       struct lowpan_nhc *nhc;
+       const struct lowpan_nhc *nhc;
        int ret = 0;
 
        spin_lock_bh(&lowpan_nhc_lock);
@@ -110,7 +59,7 @@ int lowpan_nhc_do_compression(struct sk_buff *skb, const struct ipv6hdr *hdr,
                              u8 **hc_ptr)
 {
        int ret;
-       struct lowpan_nhc *nhc;
+       const struct lowpan_nhc *nhc;
 
        spin_lock_bh(&lowpan_nhc_lock);
 
@@ -153,7 +102,7 @@ int lowpan_nhc_do_uncompression(struct sk_buff *skb,
                                const struct net_device *dev,
                                struct ipv6hdr *hdr)
 {
-       struct lowpan_nhc *nhc;
+       const struct lowpan_nhc *nhc;
        int ret;
 
        spin_lock_bh(&lowpan_nhc_lock);
@@ -189,18 +138,9 @@ int lowpan_nhc_do_uncompression(struct sk_buff *skb,
        return 0;
 }
 
-int lowpan_nhc_add(struct lowpan_nhc *nhc)
+int lowpan_nhc_add(const struct lowpan_nhc *nhc)
 {
-       int ret;
-
-       if (!nhc->idlen || !nhc->idsetup)
-               return -EINVAL;
-
-       WARN_ONCE(nhc->idlen > LOWPAN_NHC_MAX_ID_LEN,
-                 "LOWPAN_NHC_MAX_ID_LEN should be updated to %zd.\n",
-                 nhc->idlen);
-
-       nhc->idsetup(nhc);
+       int ret = 0;
 
        spin_lock_bh(&lowpan_nhc_lock);
 
@@ -209,10 +149,6 @@ int lowpan_nhc_add(struct lowpan_nhc *nhc)
                goto out;
        }
 
-       ret = lowpan_nhc_insert(nhc);
-       if (ret < 0)
-               goto out;
-
        lowpan_nexthdr_nhcs[nhc->nexthdr] = nhc;
 out:
        spin_unlock_bh(&lowpan_nhc_lock);
@@ -220,11 +156,10 @@ out:
 }
 EXPORT_SYMBOL(lowpan_nhc_add);
 
-void lowpan_nhc_del(struct lowpan_nhc *nhc)
+void lowpan_nhc_del(const struct lowpan_nhc *nhc)
 {
        spin_lock_bh(&lowpan_nhc_lock);
 
-       lowpan_nhc_remove(nhc);
        lowpan_nexthdr_nhcs[nhc->nexthdr] = NULL;
 
        spin_unlock_bh(&lowpan_nhc_lock);
index 67951c4..ab7b497 100644 (file)
  * @_name: const char * of common header compression name.
  * @_nexthdr: ipv6 nexthdr field for the header compression.
  * @_nexthdrlen: ipv6 nexthdr len for the reserved space.
- * @_idsetup: callback to setup id and mask values.
- * @_idlen: len for the next header id and mask, should be always the same.
+ * @_id: one byte nhc id value.
+ * @_idmask: one byte nhc id mask value.
  * @_uncompress: callback for uncompression call.
  * @_compress: callback for compression call.
  */
 #define LOWPAN_NHC(__nhc, _name, _nexthdr,     \
-                  _hdrlen, _idsetup, _idlen,   \
+                  _hdrlen, _id, _idmask,       \
                   _uncompress, _compress)      \
-static u8 __nhc##_val[_idlen];                 \
-static u8 __nhc##_mask[_idlen];                        \
-static struct lowpan_nhc __nhc = {             \
+static const struct lowpan_nhc __nhc = {       \
        .name           = _name,                \
        .nexthdr        = _nexthdr,             \
        .nexthdrlen     = _hdrlen,              \
-       .id             = __nhc##_val,          \
-       .idmask         = __nhc##_mask,         \
-       .idlen          = _idlen,               \
-       .idsetup        = _idsetup,             \
+       .id             = _id,                  \
+       .idmask         = _idmask,              \
        .uncompress     = _uncompress,          \
        .compress       = _compress,            \
 }
@@ -53,27 +49,21 @@ module_exit(__nhc##_exit);
 /**
  * struct lowpan_nhc - hold 6lowpan next hdr compression ifnformation
  *
- * @node: holder for the rbtree.
  * @name: name of the specific next header compression
  * @nexthdr: next header value of the protocol which should be compressed.
  * @nexthdrlen: ipv6 nexthdr len for the reserved space.
- * @id: array for nhc id. Note this need to be in network byteorder.
- * @mask: array for nhc id mask. Note this need to be in network byteorder.
- * @len: the length of the next header id and mask.
- * @setup: callback to setup fill the next header id value and mask.
+ * @id: one byte nhc id value.
+ * @idmask: one byte nhc id mask value.
  * @compress: callback to do the header compression.
  * @uncompress: callback to do the header uncompression.
  */
 struct lowpan_nhc {
-       struct rb_node  node;
        const char      *name;
-       const u8        nexthdr;
-       const size_t    nexthdrlen;
-       u8              *id;
-       u8              *idmask;
-       const size_t    idlen;
+       u8              nexthdr;
+       size_t          nexthdrlen;
+       u8              id;
+       u8              idmask;
 
-       void            (*idsetup)(struct lowpan_nhc *nhc);
        int             (*uncompress)(struct sk_buff *skb, size_t needed);
        int             (*compress)(struct sk_buff *skb, u8 **hc_ptr);
 };
@@ -126,14 +116,14 @@ int lowpan_nhc_do_uncompression(struct sk_buff *skb,
  *
  * @nhc: nhc which should be add.
  */
-int lowpan_nhc_add(struct lowpan_nhc *nhc);
+int lowpan_nhc_add(const struct lowpan_nhc *nhc);
 
 /**
  * lowpan_nhc_del - delete a next header compression from framework
  *
  * @nhc: nhc which should be delete.
  */
-void lowpan_nhc_del(struct lowpan_nhc *nhc);
+void lowpan_nhc_del(const struct lowpan_nhc *nhc);
 
 /**
  * lowpan_nhc_init - adding all default nhcs
index 4768a94..0cbcc78 100644 (file)
@@ -6,18 +6,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_NHC_DEST_IDLEN  1
 #define LOWPAN_NHC_DEST_ID_0   0xe6
 #define LOWPAN_NHC_DEST_MASK_0 0xfe
 
-static void dest_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_DEST_ID_0;
-       nhc->idmask[0] = LOWPAN_NHC_DEST_MASK_0;
-}
-
 LOWPAN_NHC(nhc_dest, "RFC6282 Destination Options", NEXTHDR_DEST, 0,
-          dest_nhid_setup, LOWPAN_NHC_DEST_IDLEN, NULL, NULL);
+          LOWPAN_NHC_DEST_ID_0, LOWPAN_NHC_DEST_MASK_0,  NULL, NULL);
 
 module_lowpan_nhc(nhc_dest);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Destination Options compression");
index be85f07..9414552 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_NHC_FRAGMENT_IDLEN      1
 #define LOWPAN_NHC_FRAGMENT_ID_0       0xe4
 #define LOWPAN_NHC_FRAGMENT_MASK_0     0xfe
 
-static void fragment_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_FRAGMENT_ID_0;
-       nhc->idmask[0] = LOWPAN_NHC_FRAGMENT_MASK_0;
-}
-
 LOWPAN_NHC(nhc_fragment, "RFC6282 Fragment", NEXTHDR_FRAGMENT, 0,
-          fragment_nhid_setup, LOWPAN_NHC_FRAGMENT_IDLEN, NULL, NULL);
+          LOWPAN_NHC_FRAGMENT_ID_0, LOWPAN_NHC_FRAGMENT_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(nhc_fragment);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Fragment compression");
index a9137f1..e4745dd 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_GHC_EXT_DEST_IDLEN      1
 #define LOWPAN_GHC_EXT_DEST_ID_0       0xb6
 #define LOWPAN_GHC_EXT_DEST_MASK_0     0xfe
 
-static void dest_ghid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_GHC_EXT_DEST_ID_0;
-       nhc->idmask[0] = LOWPAN_GHC_EXT_DEST_MASK_0;
-}
-
 LOWPAN_NHC(ghc_ext_dest, "RFC7400 Destination Extension Header", NEXTHDR_DEST,
-          0, dest_ghid_setup, LOWPAN_GHC_EXT_DEST_IDLEN, NULL, NULL);
+          0, LOWPAN_GHC_EXT_DEST_ID_0, LOWPAN_GHC_EXT_DEST_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(ghc_ext_dest);
 MODULE_DESCRIPTION("6LoWPAN generic header destination extension compression");
index d49b745..220e5ab 100644 (file)
@@ -5,19 +5,12 @@
 
 #include "nhc.h"
 
-#define LOWPAN_GHC_EXT_FRAG_IDLEN      1
 #define LOWPAN_GHC_EXT_FRAG_ID_0       0xb4
 #define LOWPAN_GHC_EXT_FRAG_MASK_0     0xfe
 
-static void frag_ghid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_GHC_EXT_FRAG_ID_0;
-       nhc->idmask[0] = LOWPAN_GHC_EXT_FRAG_MASK_0;
-}
-
 LOWPAN_NHC(ghc_ext_frag, "RFC7400 Fragmentation Extension Header",
-          NEXTHDR_FRAGMENT, 0, frag_ghid_setup,
-          LOWPAN_GHC_EXT_FRAG_IDLEN, NULL, NULL);
+          NEXTHDR_FRAGMENT, 0, LOWPAN_GHC_EXT_FRAG_ID_0,
+          LOWPAN_GHC_EXT_FRAG_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(ghc_ext_frag);
 MODULE_DESCRIPTION("6LoWPAN generic header fragmentation extension compression");
index 3beedf5..9b0de4d 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_GHC_EXT_HOP_IDLEN       1
 #define LOWPAN_GHC_EXT_HOP_ID_0                0xb0
 #define LOWPAN_GHC_EXT_HOP_MASK_0      0xfe
 
-static void hop_ghid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_GHC_EXT_HOP_ID_0;
-       nhc->idmask[0] = LOWPAN_GHC_EXT_HOP_MASK_0;
-}
-
 LOWPAN_NHC(ghc_ext_hop, "RFC7400 Hop-by-Hop Extension Header", NEXTHDR_HOP, 0,
-          hop_ghid_setup, LOWPAN_GHC_EXT_HOP_IDLEN, NULL, NULL);
+          LOWPAN_GHC_EXT_HOP_ID_0, LOWPAN_GHC_EXT_HOP_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(ghc_ext_hop);
 MODULE_DESCRIPTION("6LoWPAN generic header hop-by-hop extension compression");
index 70dc0ea..3e86fae 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_GHC_EXT_ROUTE_IDLEN     1
 #define LOWPAN_GHC_EXT_ROUTE_ID_0      0xb2
 #define LOWPAN_GHC_EXT_ROUTE_MASK_0    0xfe
 
-static void route_ghid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_GHC_EXT_ROUTE_ID_0;
-       nhc->idmask[0] = LOWPAN_GHC_EXT_ROUTE_MASK_0;
-}
-
 LOWPAN_NHC(ghc_ext_route, "RFC7400 Routing Extension Header", NEXTHDR_ROUTING,
-          0, route_ghid_setup, LOWPAN_GHC_EXT_ROUTE_IDLEN, NULL, NULL);
+          0, LOWPAN_GHC_EXT_ROUTE_ID_0, LOWPAN_GHC_EXT_ROUTE_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(ghc_ext_route);
 MODULE_DESCRIPTION("6LoWPAN generic header routing extension compression");
index 339ceff..1634f3e 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_GHC_ICMPV6_IDLEN                1
 #define LOWPAN_GHC_ICMPV6_ID_0         0xdf
 #define LOWPAN_GHC_ICMPV6_MASK_0       0xff
 
-static void icmpv6_ghid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_GHC_ICMPV6_ID_0;
-       nhc->idmask[0] = LOWPAN_GHC_ICMPV6_MASK_0;
-}
-
 LOWPAN_NHC(ghc_icmpv6, "RFC7400 ICMPv6", NEXTHDR_ICMP, 0,
-          icmpv6_ghid_setup, LOWPAN_GHC_ICMPV6_IDLEN, NULL, NULL);
+          LOWPAN_GHC_ICMPV6_ID_0, LOWPAN_GHC_ICMPV6_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(ghc_icmpv6);
 MODULE_DESCRIPTION("6LoWPAN generic header ICMPv6 compression");
index f47fec6..4ac4813 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_GHC_UDP_IDLEN   1
 #define LOWPAN_GHC_UDP_ID_0    0xd0
 #define LOWPAN_GHC_UDP_MASK_0  0xf8
 
-static void udp_ghid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_GHC_UDP_ID_0;
-       nhc->idmask[0] = LOWPAN_GHC_UDP_MASK_0;
-}
-
 LOWPAN_NHC(ghc_udp, "RFC7400 UDP", NEXTHDR_UDP, 0,
-          udp_ghid_setup, LOWPAN_GHC_UDP_IDLEN, NULL, NULL);
+          LOWPAN_GHC_UDP_ID_0, LOWPAN_GHC_UDP_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(ghc_udp);
 MODULE_DESCRIPTION("6LoWPAN generic header UDP compression");
index 158fc19..182087d 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_NHC_HOP_IDLEN   1
 #define LOWPAN_NHC_HOP_ID_0    0xe0
 #define LOWPAN_NHC_HOP_MASK_0  0xfe
 
-static void hop_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_HOP_ID_0;
-       nhc->idmask[0] = LOWPAN_NHC_HOP_MASK_0;
-}
-
 LOWPAN_NHC(nhc_hop, "RFC6282 Hop-by-Hop Options", NEXTHDR_HOP, 0,
-          hop_nhid_setup, LOWPAN_NHC_HOP_IDLEN, NULL, NULL);
+          LOWPAN_NHC_HOP_ID_0, LOWPAN_NHC_HOP_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(nhc_hop);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Hop-by-Hop Options compression");
index 08b7589..2024236 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_NHC_IPV6_IDLEN  1
 #define LOWPAN_NHC_IPV6_ID_0   0xee
 #define LOWPAN_NHC_IPV6_MASK_0 0xfe
 
-static void ipv6_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_IPV6_ID_0;
-       nhc->idmask[0] = LOWPAN_NHC_IPV6_MASK_0;
-}
-
-LOWPAN_NHC(nhc_ipv6, "RFC6282 IPv6", NEXTHDR_IPV6, 0, ipv6_nhid_setup,
-          LOWPAN_NHC_IPV6_IDLEN, NULL, NULL);
+LOWPAN_NHC(nhc_ipv6, "RFC6282 IPv6", NEXTHDR_IPV6, 0, LOWPAN_NHC_IPV6_ID_0,
+          LOWPAN_NHC_IPV6_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(nhc_ipv6);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 IPv6 compression");
index ac8fca6..1c31d87 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_NHC_MOBILITY_IDLEN      1
 #define LOWPAN_NHC_MOBILITY_ID_0       0xe8
 #define LOWPAN_NHC_MOBILITY_MASK_0     0xfe
 
-static void mobility_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_MOBILITY_ID_0;
-       nhc->idmask[0] = LOWPAN_NHC_MOBILITY_MASK_0;
-}
-
 LOWPAN_NHC(nhc_mobility, "RFC6282 Mobility", NEXTHDR_MOBILITY, 0,
-          mobility_nhid_setup, LOWPAN_NHC_MOBILITY_IDLEN, NULL, NULL);
+          LOWPAN_NHC_MOBILITY_ID_0, LOWPAN_NHC_MOBILITY_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(nhc_mobility);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Mobility compression");
index 1c17402..dae03eb 100644 (file)
@@ -5,18 +5,11 @@
 
 #include "nhc.h"
 
-#define LOWPAN_NHC_ROUTING_IDLEN       1
 #define LOWPAN_NHC_ROUTING_ID_0                0xe2
 #define LOWPAN_NHC_ROUTING_MASK_0      0xfe
 
-static void routing_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_ROUTING_ID_0;
-       nhc->idmask[0] = LOWPAN_NHC_ROUTING_MASK_0;
-}
-
 LOWPAN_NHC(nhc_routing, "RFC6282 Routing", NEXTHDR_ROUTING, 0,
-          routing_nhid_setup, LOWPAN_NHC_ROUTING_IDLEN, NULL, NULL);
+          LOWPAN_NHC_ROUTING_ID_0, LOWPAN_NHC_ROUTING_MASK_0, NULL, NULL);
 
 module_lowpan_nhc(nhc_routing);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 Routing compression");
index 33f17bd..0a506c7 100644 (file)
@@ -14,7 +14,6 @@
 
 #define LOWPAN_NHC_UDP_MASK            0xF8
 #define LOWPAN_NHC_UDP_ID              0xF0
-#define LOWPAN_NHC_UDP_IDLEN           1
 
 #define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
 #define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
@@ -169,14 +168,8 @@ static int udp_compress(struct sk_buff *skb, u8 **hc_ptr)
        return 0;
 }
 
-static void udp_nhid_setup(struct lowpan_nhc *nhc)
-{
-       nhc->id[0] = LOWPAN_NHC_UDP_ID;
-       nhc->idmask[0] = LOWPAN_NHC_UDP_MASK;
-}
-
 LOWPAN_NHC(nhc_udp, "RFC6282 UDP", NEXTHDR_UDP, sizeof(struct udphdr),
-          udp_nhid_setup, LOWPAN_NHC_UDP_IDLEN, udp_uncompress, udp_compress);
+          LOWPAN_NHC_UDP_ID, LOWPAN_NHC_UDP_MASK, udp_uncompress, udp_compress);
 
 module_lowpan_nhc(nhc_udp);
 MODULE_DESCRIPTION("6LoWPAN next header RFC6282 UDP compression");
index acf8c79..5aa8144 100644 (file)
@@ -63,10 +63,10 @@ bool vlan_do_receive(struct sk_buff **skbp)
        rx_stats = this_cpu_ptr(vlan_dev_priv(vlan_dev)->vlan_pcpu_stats);
 
        u64_stats_update_begin(&rx_stats->syncp);
-       rx_stats->rx_packets++;
-       rx_stats->rx_bytes += skb->len;
+       u64_stats_inc(&rx_stats->rx_packets);
+       u64_stats_add(&rx_stats->rx_bytes, skb->len);
        if (skb->pkt_type == PACKET_MULTICAST)
-               rx_stats->rx_multicast++;
+               u64_stats_inc(&rx_stats->rx_multicast);
        u64_stats_update_end(&rx_stats->syncp);
 
        return true;
index 839f202..035812b 100644 (file)
@@ -128,8 +128,8 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
 
                stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
                u64_stats_update_begin(&stats->syncp);
-               stats->tx_packets++;
-               stats->tx_bytes += len;
+               u64_stats_inc(&stats->tx_packets);
+               u64_stats_add(&stats->tx_bytes, len);
                u64_stats_update_end(&stats->syncp);
        } else {
                this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
@@ -615,7 +615,7 @@ static int vlan_dev_init(struct net_device *dev)
                return -ENOMEM;
 
        /* Get vlan's reference to real_dev */
-       dev_hold_track(real_dev, &vlan->dev_tracker, GFP_KERNEL);
+       netdev_hold(real_dev, &vlan->dev_tracker, GFP_KERNEL);
 
        return 0;
 }
@@ -713,11 +713,11 @@ static void vlan_dev_get_stats64(struct net_device *dev,
                p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
                do {
                        start = u64_stats_fetch_begin_irq(&p->syncp);
-                       rxpackets       = p->rx_packets;
-                       rxbytes         = p->rx_bytes;
-                       rxmulticast     = p->rx_multicast;
-                       txpackets       = p->tx_packets;
-                       txbytes         = p->tx_bytes;
+                       rxpackets       = u64_stats_read(&p->rx_packets);
+                       rxbytes         = u64_stats_read(&p->rx_bytes);
+                       rxmulticast     = u64_stats_read(&p->rx_multicast);
+                       txpackets       = u64_stats_read(&p->tx_packets);
+                       txbytes         = u64_stats_read(&p->tx_bytes);
                } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                stats->rx_packets       += rxpackets;
@@ -726,8 +726,8 @@ static void vlan_dev_get_stats64(struct net_device *dev,
                stats->tx_packets       += txpackets;
                stats->tx_bytes         += txbytes;
                /* rx_errors & tx_dropped are u32 */
-               rx_errors       += p->rx_errors;
-               tx_dropped      += p->tx_dropped;
+               rx_errors       += READ_ONCE(p->rx_errors);
+               tx_dropped      += READ_ONCE(p->tx_dropped);
        }
        stats->rx_errors  = rx_errors;
        stats->tx_dropped = tx_dropped;
@@ -852,7 +852,7 @@ static void vlan_dev_free(struct net_device *dev)
        vlan->vlan_pcpu_stats = NULL;
 
        /* Get rid of the vlan's reference to real_dev */
-       dev_put_track(vlan->real_dev, &vlan->dev_tracker);
+       netdev_put(vlan->real_dev, &vlan->dev_tracker);
 }
 
 void vlan_setup(struct net_device *dev)
index 4c7030e..bbac3cb 100644 (file)
@@ -102,7 +102,8 @@ again:
                        ax25_disconnect(s, ENETUNREACH);
                        s->ax25_dev = NULL;
                        if (sk->sk_socket) {
-                               dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+                               netdev_put(ax25_dev->dev,
+                                          &ax25_dev->dev_tracker);
                                ax25_dev_put(ax25_dev);
                        }
                        ax25_cb_del(s);
@@ -1065,7 +1066,7 @@ static int ax25_release(struct socket *sock)
                        del_timer_sync(&ax25->t3timer);
                        del_timer_sync(&ax25->idletimer);
                }
-               dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+               netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker);
                ax25_dev_put(ax25_dev);
        }
 
@@ -1146,7 +1147,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
        if (ax25_dev) {
                ax25_fillin_cb(ax25, ax25_dev);
-               dev_hold_track(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
+               netdev_hold(ax25_dev->dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
        }
 
 done:
index 95a76d5..c546248 100644 (file)
@@ -52,7 +52,8 @@ void ax25_dev_device_up(struct net_device *dev)
 {
        ax25_dev *ax25_dev;
 
-       if ((ax25_dev = kzalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) {
+       ax25_dev = kzalloc(sizeof(*ax25_dev), GFP_KERNEL);
+       if (!ax25_dev) {
                printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n");
                return;
        }
@@ -60,7 +61,7 @@ void ax25_dev_device_up(struct net_device *dev)
        refcount_set(&ax25_dev->refcount, 1);
        dev->ax25_ptr     = ax25_dev;
        ax25_dev->dev     = dev;
-       dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &ax25_dev->dev_tracker, GFP_KERNEL);
        ax25_dev->forward = NULL;
        ax25_dev->device_up = true;
 
@@ -136,7 +137,7 @@ unlock_put:
        spin_unlock_bh(&ax25_dev_lock);
        ax25_dev_put(ax25_dev);
        dev->ax25_ptr = NULL;
-       dev_put_track(dev, &ax25_dev->dev_tracker);
+       netdev_put(dev, &ax25_dev->dev_tracker);
        ax25_dev_put(ax25_dev);
 }
 
@@ -205,7 +206,7 @@ void __exit ax25_dev_free(void)
        ax25_dev = ax25_dev_list;
        while (ax25_dev != NULL) {
                s        = ax25_dev;
-               dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+               netdev_put(ax25_dev->dev, &ax25_dev->dev_tracker);
                ax25_dev = ax25_dev->next;
                kfree(s);
        }
index 56f059b..2ca96ac 100644 (file)
@@ -1420,9 +1420,6 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
        void *data;
        int ret;
 
-       if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR)
-               return -EINVAL;
-
        if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size)
                return -EINVAL;
 
@@ -1487,9 +1484,6 @@ int bpf_prog_test_run_sk_lookup(struct bpf_prog *prog, const union bpf_attr *kat
        u32 retval, duration;
        int ret = -EINVAL;
 
-       if (prog->type != BPF_PROG_TYPE_SK_LOOKUP)
-               return -EINVAL;
-
        if (kattr->test.flags || kattr->test.cpu || kattr->test.batch_size)
                return -EINVAL;
 
index 47fcbad..a84a7cf 100644 (file)
@@ -274,7 +274,7 @@ static void destroy_nbp(struct net_bridge_port *p)
 
        p->br = NULL;
        p->dev = NULL;
-       dev_put_track(dev, &p->dev_tracker);
+       netdev_put(dev, &p->dev_tracker);
 
        kobject_put(&p->kobj);
 }
@@ -423,7 +423,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
                return ERR_PTR(-ENOMEM);
 
        p->br = br;
-       dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
        p->dev = dev;
        p->path_cost = port_cost(dev);
        p->priority = 0x8000 >> BR_PORT_BITS;
@@ -434,7 +434,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        br_stp_port_timer_init(p);
        err = br_multicast_add_port(p);
        if (err) {
-               dev_put_track(dev, &p->dev_tracker);
+               netdev_put(dev, &p->dev_tracker);
                kfree(p);
                p = ERR_PTR(err);
        }
@@ -615,7 +615,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev,
        err = dev_set_allmulti(dev, 1);
        if (err) {
                br_multicast_del_port(p);
-               dev_put_track(dev, &p->dev_tracker);
+               netdev_put(dev, &p->dev_tracker);
                kfree(p);       /* kobject not yet init'd, manually free */
                goto err1;
        }
@@ -725,7 +725,7 @@ err3:
        sysfs_remove_link(br->ifobj, p->dev->name);
 err2:
        br_multicast_del_port(p);
-       dev_put_track(dev, &p->dev_tracker);
+       netdev_put(dev, &p->dev_tracker);
        kobject_put(&p->kobj);
        dev_set_allmulti(dev, -1);
 err1:
index fdcc641..589ff49 100644 (file)
@@ -1025,8 +1025,8 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh,
                        NL_SET_ERR_MSG_MOD(extack, "Port belongs to a different bridge device");
                        return -EINVAL;
                }
-               if (p->state == BR_STATE_DISABLED) {
-                       NL_SET_ERR_MSG_MOD(extack, "Port is in disabled state");
+               if (p->state == BR_STATE_DISABLED && entry->state != MDB_PERMANENT) {
+                       NL_SET_ERR_MSG_MOD(extack, "Port is in disabled state and entry is not permanent");
                        return -EINVAL;
                }
                vg = nbp_vlan_group(p);
@@ -1086,9 +1086,6 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry,
                if (!p->key.port || p->key.port->dev->ifindex != entry->ifindex)
                        continue;
 
-               if (p->key.port->state == BR_STATE_DISABLED)
-                       goto unlock;
-
                br_multicast_del_pg(mp, p, pp);
                err = 0;
                break;
@@ -1124,8 +1121,14 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh,
                        return -ENODEV;
 
                p = br_port_get_rtnl(pdev);
-               if (!p || p->br != br || p->state == BR_STATE_DISABLED)
+               if (!p) {
+                       NL_SET_ERR_MSG_MOD(extack, "Net device is not a bridge port");
+                       return -EINVAL;
+               }
+               if (p->br != br) {
+                       NL_SET_ERR_MSG_MOD(extack, "Port belongs to a different bridge device");
                        return -EINVAL;
+               }
                vg = nbp_vlan_group(p);
        } else {
                vg = br_vlan_group(br);
index bb01776..1ef14a0 100644 (file)
@@ -1770,10 +1770,10 @@ static int br_fill_linkxstats(struct sk_buff *skb,
                        if (v->vid == pvid)
                                vxi.flags |= BRIDGE_VLAN_INFO_PVID;
                        br_vlan_get_stats(v, &stats);
-                       vxi.rx_bytes = stats.rx_bytes;
-                       vxi.rx_packets = stats.rx_packets;
-                       vxi.tx_bytes = stats.tx_bytes;
-                       vxi.tx_packets = stats.tx_packets;
+                       vxi.rx_bytes = u64_stats_read(&stats.rx_bytes);
+                       vxi.rx_packets = u64_stats_read(&stats.rx_packets);
+                       vxi.tx_bytes = u64_stats_read(&stats.tx_bytes);
+                       vxi.tx_packets = u64_stats_read(&stats.tx_packets);
 
                        if (nla_put(skb, BRIDGE_XSTATS_VLAN, sizeof(vxi), &vxi))
                                goto nla_put_failure;
index 0f5e75c..6e53dc9 100644 (file)
@@ -505,8 +505,8 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
        if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
                stats = this_cpu_ptr(v->stats);
                u64_stats_update_begin(&stats->syncp);
-               stats->tx_bytes += skb->len;
-               stats->tx_packets++;
+               u64_stats_add(&stats->tx_bytes, skb->len);
+               u64_stats_inc(&stats->tx_packets);
                u64_stats_update_end(&stats->syncp);
        }
 
@@ -624,8 +624,8 @@ static bool __allowed_ingress(const struct net_bridge *br,
        if (br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) {
                stats = this_cpu_ptr(v->stats);
                u64_stats_update_begin(&stats->syncp);
-               stats->rx_bytes += skb->len;
-               stats->rx_packets++;
+               u64_stats_add(&stats->rx_bytes, skb->len);
+               u64_stats_inc(&stats->rx_packets);
                u64_stats_update_end(&stats->syncp);
        }
 
@@ -1379,16 +1379,16 @@ void br_vlan_get_stats(const struct net_bridge_vlan *v,
                cpu_stats = per_cpu_ptr(v->stats, i);
                do {
                        start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
-                       rxpackets = cpu_stats->rx_packets;
-                       rxbytes = cpu_stats->rx_bytes;
-                       txbytes = cpu_stats->tx_bytes;
-                       txpackets = cpu_stats->tx_packets;
+                       rxpackets = u64_stats_read(&cpu_stats->rx_packets);
+                       rxbytes = u64_stats_read(&cpu_stats->rx_bytes);
+                       txbytes = u64_stats_read(&cpu_stats->tx_bytes);
+                       txpackets = u64_stats_read(&cpu_stats->tx_packets);
                } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
-               stats->rx_packets += rxpackets;
-               stats->rx_bytes += rxbytes;
-               stats->tx_bytes += txbytes;
-               stats->tx_packets += txpackets;
+               u64_stats_add(&stats->rx_packets, rxpackets);
+               u64_stats_add(&stats->rx_bytes, rxbytes);
+               u64_stats_add(&stats->tx_bytes, txbytes);
+               u64_stats_add(&stats->tx_packets, txpackets);
        }
 }
 
@@ -1779,14 +1779,18 @@ static bool br_vlan_stats_fill(struct sk_buff *skb,
                return false;
 
        br_vlan_get_stats(v, &stats);
-       if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES, stats.rx_bytes,
+       if (nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_BYTES,
+                             u64_stats_read(&stats.rx_bytes),
                              BRIDGE_VLANDB_STATS_PAD) ||
            nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_RX_PACKETS,
-                             stats.rx_packets, BRIDGE_VLANDB_STATS_PAD) ||
-           nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES, stats.tx_bytes,
+                             u64_stats_read(&stats.rx_packets),
+                             BRIDGE_VLANDB_STATS_PAD) ||
+           nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_BYTES,
+                             u64_stats_read(&stats.tx_bytes),
                              BRIDGE_VLANDB_STATS_PAD) ||
            nla_put_u64_64bit(skb, BRIDGE_VLANDB_STATS_TX_PACKETS,
-                             stats.tx_packets, BRIDGE_VLANDB_STATS_PAD))
+                             u64_stats_read(&stats.tx_packets),
+                             BRIDGE_VLANDB_STATS_PAD))
                goto out_err;
 
        nla_nest_end(skb, nest);
index a9ac5ff..cb56be8 100644 (file)
@@ -15,7 +15,8 @@ menuconfig CAN
          PF_CAN is contained in <Documentation/networking/can.rst>.
 
          If you want CAN support you should say Y here and also to the
-         specific driver for your controller(s) below.
+         specific driver for your controller(s) under the Network device
+         support section.
 
 if CAN
 
@@ -69,6 +70,4 @@ config CAN_ISOTP
          If you want to perform automotive vehicle diagnostic services (UDS),
          say 'y'.
 
-source "drivers/net/can/Kconfig"
-
 endif
diff --git a/net/core/.gitignore b/net/core/.gitignore
new file mode 100644 (file)
index 0000000..df1e743
--- /dev/null
@@ -0,0 +1 @@
+dropreason_str.c
index a8e4f73..e8ce3bd 100644 (file)
@@ -4,7 +4,8 @@
 #
 
 obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \
-        gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o
+        gen_stats.o gen_estimator.o net_namespace.o secure_seq.o \
+        flow_dissector.o dropreason_str.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
@@ -39,3 +40,23 @@ obj-$(CONFIG_NET_SOCK_MSG) += skmsg.o
 obj-$(CONFIG_BPF_SYSCALL) += sock_map.o
 obj-$(CONFIG_BPF_SYSCALL) += bpf_sk_storage.o
 obj-$(CONFIG_OF)       += of_net.o
+
+clean-files := dropreason_str.c
+
+quiet_cmd_dropreason_str = GEN     $@
+cmd_dropreason_str = awk -F ',' 'BEGIN{ print "\#include <net/dropreason.h>\n"; \
+       print "const char * const drop_reasons[] = {" }\
+       /^enum skb_drop/ { dr=1; }\
+       /^\};/ { dr=0; }\
+       /^\tSKB_DROP_REASON_/ {\
+               if (dr) {\
+                       sub(/\tSKB_DROP_REASON_/, "", $$1);\
+                       printf "\t[SKB_DROP_REASON_%s] = \"%s\",\n", $$1, $$1;\
+               }\
+       }\
+       END{ print "};" }' $< > $@
+
+$(obj)/dropreason_str.c: $(srctree)/include/net/dropreason.h
+       $(call cmd,dropreason_str)
+
+$(obj)/dropreason_str.o: $(obj)/dropreason_str.c
index 50f4fae..35791f8 100644 (file)
@@ -320,7 +320,6 @@ EXPORT_SYMBOL(skb_recv_datagram);
 void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
 {
        consume_skb(skb);
-       sk_mem_reclaim_partial(sk);
 }
 EXPORT_SYMBOL(skb_free_datagram);
 
@@ -336,7 +335,6 @@ void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len)
        slow = lock_sock_fast(sk);
        sk_peek_offset_bwd(sk, len);
        skb_orphan(skb);
-       sk_mem_reclaim_partial(sk);
        unlock_sock_fast(sk, slow);
 
        /* skb is now orphaned, can be freed outside of locked section */
@@ -396,7 +394,6 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
                                      NULL);
 
        kfree_skb(skb);
-       sk_mem_reclaim_partial(sk);
        return err;
 }
 EXPORT_SYMBOL(skb_kill_datagram);
index 8e6f229..978ed06 100644 (file)
@@ -3927,7 +3927,7 @@ int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
        skb->pkt_type = PACKET_LOOPBACK;
        if (skb->ip_summed == CHECKSUM_NONE)
                skb->ip_summed = CHECKSUM_UNNECESSARY;
-       WARN_ON(!skb_dst(skb));
+       DEBUG_NET_WARN_ON_ONCE(!skb_dst(skb));
        skb_dst_force(skb);
        netif_rx(skb);
        return 0;
@@ -6353,6 +6353,23 @@ int dev_set_threaded(struct net_device *dev, bool threaded)
 }
 EXPORT_SYMBOL(dev_set_threaded);
 
+/* Double check that napi_get_frags() allocates skbs with
+ * skb->head being backed by slab, not a page fragment.
+ * This is to make sure bug fixed in 3226b158e67c
+ * ("net: avoid 32 x truesize under-estimation for tiny skbs")
+ * does not accidentally come back.
+ */
+static void napi_get_frags_check(struct napi_struct *napi)
+{
+       struct sk_buff *skb;
+
+       local_bh_disable();
+       skb = napi_get_frags(napi);
+       WARN_ON_ONCE(skb && skb->head_frag);
+       napi_free_frags(napi);
+       local_bh_enable();
+}
+
 void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
                           int (*poll)(struct napi_struct *, int), int weight)
 {
@@ -6380,6 +6397,7 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
        set_bit(NAPI_STATE_NPSVC, &napi->state);
        list_add_rcu(&napi->dev_list, &dev->napi_list);
        napi_hash_add(napi);
+       napi_get_frags_check(napi);
        /* Create kthread for this napi if dev->threaded is set.
         * Clear dev->threaded if kthread creation failed so that
         * threaded mode will not be enabled in napi_enable().
@@ -7465,7 +7483,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
        adj->ref_nr = 1;
        adj->private = private;
        adj->ignore = false;
-       dev_hold_track(adj_dev, &adj->dev_tracker, GFP_KERNEL);
+       netdev_hold(adj_dev, &adj->dev_tracker, GFP_KERNEL);
 
        pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n",
                 dev->name, adj_dev->name, adj->ref_nr, adj_dev->name);
@@ -7494,7 +7512,7 @@ remove_symlinks:
        if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list))
                netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list);
 free_adj:
-       dev_put_track(adj_dev, &adj->dev_tracker);
+       netdev_put(adj_dev, &adj->dev_tracker);
        kfree(adj);
 
        return ret;
@@ -7536,7 +7554,7 @@ static void __netdev_adjacent_dev_remove(struct net_device *dev,
        list_del_rcu(&adj->list);
        pr_debug("adjacency: dev_put for %s, because link removed from %s to %s\n",
                 adj_dev->name, dev->name, adj_dev->name);
-       dev_put_track(adj_dev, &adj->dev_tracker);
+       netdev_put(adj_dev, &adj->dev_tracker);
        kfree_rcu(adj, rcu);
 }
 
@@ -10064,7 +10082,7 @@ int register_netdevice(struct net_device *dev)
 
        dev_init_scheduler(dev);
 
-       dev_hold_track(dev, &dev->dev_registered_tracker, GFP_KERNEL);
+       netdev_hold(dev, &dev->dev_registered_tracker, GFP_KERNEL);
        list_netdevice(dev);
 
        add_device_randomness(dev->dev_addr, dev->addr_len);
@@ -10463,23 +10481,23 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s,
        int cpu;
 
        for_each_possible_cpu(cpu) {
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
                const struct pcpu_sw_netstats *stats;
-               struct pcpu_sw_netstats tmp;
                unsigned int start;
 
                stats = per_cpu_ptr(netstats, cpu);
                do {
                        start = u64_stats_fetch_begin_irq(&stats->syncp);
-                       tmp.rx_packets = stats->rx_packets;
-                       tmp.rx_bytes   = stats->rx_bytes;
-                       tmp.tx_packets = stats->tx_packets;
-                       tmp.tx_bytes   = stats->tx_bytes;
+                       rx_packets = u64_stats_read(&stats->rx_packets);
+                       rx_bytes   = u64_stats_read(&stats->rx_bytes);
+                       tx_packets = u64_stats_read(&stats->tx_packets);
+                       tx_bytes   = u64_stats_read(&stats->tx_bytes);
                } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
 
-               s->rx_packets += tmp.rx_packets;
-               s->rx_bytes   += tmp.rx_bytes;
-               s->tx_packets += tmp.tx_packets;
-               s->tx_bytes   += tmp.tx_bytes;
+               s->rx_packets += rx_packets;
+               s->rx_bytes   += rx_bytes;
+               s->tx_packets += tx_packets;
+               s->tx_bytes   += tx_bytes;
        }
 }
 EXPORT_SYMBOL_GPL(dev_fetch_sw_netstats);
@@ -10873,7 +10891,7 @@ void unregister_netdevice_many(struct list_head *head)
        synchronize_net();
 
        list_for_each_entry(dev, head, unreg_list) {
-               dev_put_track(dev, &dev->dev_registered_tracker);
+               netdev_put(dev, &dev->dev_registered_tracker);
                net_set_todo(dev);
        }
 
index 4f6be44..7674bb9 100644 (file)
@@ -384,10 +384,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
                        return -ENODEV;
                if (!netif_is_bridge_master(dev))
                        return -EOPNOTSUPP;
-               dev_hold_track(dev, &dev_tracker, GFP_KERNEL);
+               netdev_hold(dev, &dev_tracker, GFP_KERNEL);
                rtnl_unlock();
                err = br_ioctl_call(net, netdev_priv(dev), cmd, ifr, NULL);
-               dev_put_track(dev, &dev_tracker);
+               netdev_put(dev, &dev_tracker);
                rtnl_lock();
                return err;
 
index 5cc8849..db61f3a 100644 (file)
@@ -7946,8 +7946,8 @@ static int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
 }
 
 struct devlink_stats {
-       u64 rx_bytes;
-       u64 rx_packets;
+       u64_stats_t rx_bytes;
+       u64_stats_t rx_packets;
        struct u64_stats_sync syncp;
 };
 
@@ -8104,12 +8104,12 @@ static void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
                cpu_stats = per_cpu_ptr(trap_stats, i);
                do {
                        start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
-                       rx_packets = cpu_stats->rx_packets;
-                       rx_bytes = cpu_stats->rx_bytes;
+                       rx_packets = u64_stats_read(&cpu_stats->rx_packets);
+                       rx_bytes = u64_stats_read(&cpu_stats->rx_bytes);
                } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
-               stats->rx_packets += rx_packets;
-               stats->rx_bytes += rx_bytes;
+               u64_stats_add(&stats->rx_packets, rx_packets);
+               u64_stats_add(&stats->rx_bytes, rx_bytes);
        }
 }
 
@@ -8127,11 +8127,13 @@ devlink_trap_group_stats_put(struct sk_buff *msg,
                return -EMSGSIZE;
 
        if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
-                             stats.rx_packets, DEVLINK_ATTR_PAD))
+                             u64_stats_read(&stats.rx_packets),
+                             DEVLINK_ATTR_PAD))
                goto nla_put_failure;
 
        if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
-                             stats.rx_bytes, DEVLINK_ATTR_PAD))
+                             u64_stats_read(&stats.rx_bytes),
+                             DEVLINK_ATTR_PAD))
                goto nla_put_failure;
 
        nla_nest_end(msg, attr);
@@ -8171,11 +8173,13 @@ static int devlink_trap_stats_put(struct sk_buff *msg, struct devlink *devlink,
                goto nla_put_failure;
 
        if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
-                             stats.rx_packets, DEVLINK_ATTR_PAD))
+                             u64_stats_read(&stats.rx_packets),
+                             DEVLINK_ATTR_PAD))
                goto nla_put_failure;
 
        if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
-                             stats.rx_bytes, DEVLINK_ATTR_PAD))
+                             u64_stats_read(&stats.rx_bytes),
+                             DEVLINK_ATTR_PAD))
                goto nla_put_failure;
 
        nla_nest_end(msg, attr);
@@ -11641,8 +11645,8 @@ devlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
 
        stats = this_cpu_ptr(trap_stats);
        u64_stats_update_begin(&stats->syncp);
-       stats->rx_bytes += skb_len;
-       stats->rx_packets++;
+       u64_stats_add(&stats->rx_bytes, skb_len);
+       u64_stats_inc(&stats->rx_packets);
        u64_stats_update_end(&stats->syncp);
 }
 
index 41cac0e..75501e1 100644 (file)
 static int trace_state = TRACE_OFF;
 static bool monitor_hw;
 
-#undef EM
-#undef EMe
-
-#define EM(a, b)       [a] = #b,
-#define EMe(a, b)      [a] = #b
-
-/* drop_reasons is used to translate 'enum skb_drop_reason' to string,
- * which is reported to user space.
- */
-static const char * const drop_reasons[] = {
-       TRACE_SKB_DROP_REASON
-};
-
 /* net_dm_mutex
  *
  * An overall lock guarding every operation coming from userspace.
@@ -68,7 +55,7 @@ static const char * const drop_reasons[] = {
 static DEFINE_MUTEX(net_dm_mutex);
 
 struct net_dm_stats {
-       u64 dropped;
+       u64_stats_t dropped;
        struct u64_stats_sync syncp;
 };
 
@@ -543,7 +530,7 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
 unlock_free:
        spin_unlock_irqrestore(&data->drop_queue.lock, flags);
        u64_stats_update_begin(&data->stats.syncp);
-       data->stats.dropped++;
+       u64_stats_inc(&data->stats.dropped);
        u64_stats_update_end(&data->stats.syncp);
        consume_skb(nskb);
 }
@@ -877,7 +864,8 @@ net_dm_hw_metadata_copy(const struct devlink_trap_metadata *metadata)
        }
 
        hw_metadata->input_dev = metadata->input_dev;
-       dev_hold_track(hw_metadata->input_dev, &hw_metadata->dev_tracker, GFP_ATOMIC);
+       netdev_hold(hw_metadata->input_dev, &hw_metadata->dev_tracker,
+                   GFP_ATOMIC);
 
        return hw_metadata;
 
@@ -893,7 +881,7 @@ free_hw_metadata:
 static void
 net_dm_hw_metadata_free(struct devlink_trap_metadata *hw_metadata)
 {
-       dev_put_track(hw_metadata->input_dev, &hw_metadata->dev_tracker);
+       netdev_put(hw_metadata->input_dev, &hw_metadata->dev_tracker);
        kfree(hw_metadata->fa_cookie);
        kfree(hw_metadata->trap_name);
        kfree(hw_metadata->trap_group_name);
@@ -998,7 +986,7 @@ net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink,
 unlock_free:
        spin_unlock_irqrestore(&hw_data->drop_queue.lock, flags);
        u64_stats_update_begin(&hw_data->stats.syncp);
-       hw_data->stats.dropped++;
+       u64_stats_inc(&hw_data->stats.dropped);
        u64_stats_update_end(&hw_data->stats.syncp);
        net_dm_hw_metadata_free(n_hw_metadata);
 free:
@@ -1445,10 +1433,10 @@ static void net_dm_stats_read(struct net_dm_stats *stats)
 
                do {
                        start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
-                       dropped = cpu_stats->dropped;
+                       dropped = u64_stats_read(&cpu_stats->dropped);
                } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
-               stats->dropped += dropped;
+               u64_stats_add(&stats->dropped, dropped);
        }
 }
 
@@ -1464,7 +1452,7 @@ static int net_dm_stats_put(struct sk_buff *msg)
                return -EMSGSIZE;
 
        if (nla_put_u64_64bit(msg, NET_DM_ATTR_STATS_DROPPED,
-                             stats.dropped, NET_DM_ATTR_PAD))
+                             u64_stats_read(&stats.dropped), NET_DM_ATTR_PAD))
                goto nla_put_failure;
 
        nla_nest_end(msg, attr);
@@ -1489,10 +1477,10 @@ static void net_dm_hw_stats_read(struct net_dm_stats *stats)
 
                do {
                        start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
-                       dropped = cpu_stats->dropped;
+                       dropped = u64_stats_read(&cpu_stats->dropped);
                } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
-               stats->dropped += dropped;
+               u64_stats_add(&stats->dropped, dropped);
        }
 }
 
@@ -1508,7 +1496,7 @@ static int net_dm_hw_stats_put(struct sk_buff *msg)
                return -EMSGSIZE;
 
        if (nla_put_u64_64bit(msg, NET_DM_ATTR_STATS_DROPPED,
-                             stats.dropped, NET_DM_ATTR_PAD))
+                             u64_stats_read(&stats.dropped), NET_DM_ATTR_PAD))
                goto nla_put_failure;
 
        nla_nest_end(msg, attr);
index d16c2c9..bc9c9be 100644 (file)
@@ -49,7 +49,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
              unsigned short flags)
 {
        dst->dev = dev;
-       dev_hold_track(dev, &dst->dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &dst->dev_tracker, GFP_ATOMIC);
        dst->ops = ops;
        dst_init_metrics(dst, dst_default_metrics.metrics, true);
        dst->expires = 0UL;
@@ -117,7 +117,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
 
        if (dst->ops->destroy)
                dst->ops->destroy(dst);
-       dev_put_track(dst->dev, &dst->dev_tracker);
+       netdev_put(dst->dev, &dst->dev_tracker);
 
        lwtstate_put(dst->lwtstate);
 
@@ -159,8 +159,8 @@ void dst_dev_put(struct dst_entry *dst)
        dst->input = dst_discard;
        dst->output = dst_discard_out;
        dst->dev = blackhole_netdev;
-       dev_replace_track(dev, blackhole_netdev, &dst->dev_tracker,
-                         GFP_ATOMIC);
+       netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker,
+                          GFP_ATOMIC);
 }
 EXPORT_SYMBOL(dst_dev_put);
 
index dcaa92a..864d2d8 100644 (file)
@@ -252,7 +252,7 @@ struct failover *failover_register(struct net_device *dev,
                return ERR_PTR(-ENOMEM);
 
        rcu_assign_pointer(failover->ops, ops);
-       dev_hold_track(dev, &failover->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &failover->dev_tracker, GFP_KERNEL);
        dev->priv_flags |= IFF_FAILOVER;
        rcu_assign_pointer(failover->failover_dev, dev);
 
@@ -285,7 +285,7 @@ void failover_unregister(struct failover *failover)
                    failover_dev->name);
 
        failover_dev->priv_flags &= ~IFF_FAILOVER;
-       dev_put_track(failover_dev, &failover->dev_tracker);
+       netdev_put(failover_dev, &failover->dev_tracker);
 
        spin_lock(&failover_lock);
        list_del(&failover->list);
index 5d16d66..994d916 100644 (file)
@@ -6463,8 +6463,6 @@ static struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple,
 
 /* bpf_skc_lookup performs the core lookup for different types of sockets,
  * taking a reference on the socket if it doesn't have the flag SOCK_RCU_FREE.
- * Returns the socket as an 'unsigned long' to simplify the casting in the
- * callers to satisfy BPF_CALL declarations.
  */
 static struct sock *
 __bpf_skc_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len,
@@ -7466,6 +7464,114 @@ static const struct bpf_func_proto bpf_skb_set_tstamp_proto = {
        .arg3_type      = ARG_ANYTHING,
 };
 
+#ifdef CONFIG_SYN_COOKIES
+BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv4, struct iphdr *, iph,
+          struct tcphdr *, th, u32, th_len)
+{
+       u32 cookie;
+       u16 mss;
+
+       if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
+               return -EINVAL;
+
+       mss = tcp_parse_mss_option(th, 0) ?: TCP_MSS_DEFAULT;
+       cookie = __cookie_v4_init_sequence(iph, th, &mss);
+
+       return cookie | ((u64)mss << 32);
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv4_proto = {
+       .func           = bpf_tcp_raw_gen_syncookie_ipv4,
+       .gpl_only       = true, /* __cookie_v4_init_sequence() is GPL */
+       .pkt_access     = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_FIXED_SIZE_MEM,
+       .arg1_size      = sizeof(struct iphdr),
+       .arg2_type      = ARG_PTR_TO_MEM,
+       .arg3_type      = ARG_CONST_SIZE,
+};
+
+BPF_CALL_3(bpf_tcp_raw_gen_syncookie_ipv6, struct ipv6hdr *, iph,
+          struct tcphdr *, th, u32, th_len)
+{
+#if IS_BUILTIN(CONFIG_IPV6)
+       const u16 mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) -
+               sizeof(struct ipv6hdr);
+       u32 cookie;
+       u16 mss;
+
+       if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4))
+               return -EINVAL;
+
+       mss = tcp_parse_mss_option(th, 0) ?: mss_clamp;
+       cookie = __cookie_v6_init_sequence(iph, th, &mss);
+
+       return cookie | ((u64)mss << 32);
+#else
+       return -EPROTONOSUPPORT;
+#endif
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_gen_syncookie_ipv6_proto = {
+       .func           = bpf_tcp_raw_gen_syncookie_ipv6,
+       .gpl_only       = true, /* __cookie_v6_init_sequence() is GPL */
+       .pkt_access     = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_FIXED_SIZE_MEM,
+       .arg1_size      = sizeof(struct ipv6hdr),
+       .arg2_type      = ARG_PTR_TO_MEM,
+       .arg3_type      = ARG_CONST_SIZE,
+};
+
+BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv4, struct iphdr *, iph,
+          struct tcphdr *, th)
+{
+       u32 cookie = ntohl(th->ack_seq) - 1;
+
+       if (__cookie_v4_check(iph, th, cookie) > 0)
+               return 0;
+
+       return -EACCES;
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv4_proto = {
+       .func           = bpf_tcp_raw_check_syncookie_ipv4,
+       .gpl_only       = true, /* __cookie_v4_check is GPL */
+       .pkt_access     = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_FIXED_SIZE_MEM,
+       .arg1_size      = sizeof(struct iphdr),
+       .arg2_type      = ARG_PTR_TO_FIXED_SIZE_MEM,
+       .arg2_size      = sizeof(struct tcphdr),
+};
+
+BPF_CALL_2(bpf_tcp_raw_check_syncookie_ipv6, struct ipv6hdr *, iph,
+          struct tcphdr *, th)
+{
+#if IS_BUILTIN(CONFIG_IPV6)
+       u32 cookie = ntohl(th->ack_seq) - 1;
+
+       if (__cookie_v6_check(iph, th, cookie) > 0)
+               return 0;
+
+       return -EACCES;
+#else
+       return -EPROTONOSUPPORT;
+#endif
+}
+
+static const struct bpf_func_proto bpf_tcp_raw_check_syncookie_ipv6_proto = {
+       .func           = bpf_tcp_raw_check_syncookie_ipv6,
+       .gpl_only       = true, /* __cookie_v6_check is GPL */
+       .pkt_access     = true,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_FIXED_SIZE_MEM,
+       .arg1_size      = sizeof(struct ipv6hdr),
+       .arg2_type      = ARG_PTR_TO_FIXED_SIZE_MEM,
+       .arg2_size      = sizeof(struct tcphdr),
+};
+#endif /* CONFIG_SYN_COOKIES */
+
 #endif /* CONFIG_INET */
 
 bool bpf_helper_changes_pkt_data(void *func)
@@ -7829,6 +7935,16 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_sk_assign_proto;
        case BPF_FUNC_skb_set_tstamp:
                return &bpf_skb_set_tstamp_proto;
+#ifdef CONFIG_SYN_COOKIES
+       case BPF_FUNC_tcp_raw_gen_syncookie_ipv4:
+               return &bpf_tcp_raw_gen_syncookie_ipv4_proto;
+       case BPF_FUNC_tcp_raw_gen_syncookie_ipv6:
+               return &bpf_tcp_raw_gen_syncookie_ipv6_proto;
+       case BPF_FUNC_tcp_raw_check_syncookie_ipv4:
+               return &bpf_tcp_raw_check_syncookie_ipv4_proto;
+       case BPF_FUNC_tcp_raw_check_syncookie_ipv6:
+               return &bpf_tcp_raw_check_syncookie_ipv6_proto;
+#endif
 #endif
        default:
                return bpf_sk_base_func_proto(func_id);
@@ -7878,6 +7994,16 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_tcp_check_syncookie_proto;
        case BPF_FUNC_tcp_gen_syncookie:
                return &bpf_tcp_gen_syncookie_proto;
+#ifdef CONFIG_SYN_COOKIES
+       case BPF_FUNC_tcp_raw_gen_syncookie_ipv4:
+               return &bpf_tcp_raw_gen_syncookie_ipv4_proto;
+       case BPF_FUNC_tcp_raw_gen_syncookie_ipv6:
+               return &bpf_tcp_raw_gen_syncookie_ipv6_proto;
+       case BPF_FUNC_tcp_raw_check_syncookie_ipv4:
+               return &bpf_tcp_raw_check_syncookie_ipv4_proto;
+       case BPF_FUNC_tcp_raw_check_syncookie_ipv6:
+               return &bpf_tcp_raw_check_syncookie_ipv6_proto;
+#endif
 #endif
        default:
                return bpf_sk_base_func_proto(func_id);
index a244d3b..aa6cb1f 100644 (file)
@@ -110,7 +110,7 @@ static void linkwatch_add_event(struct net_device *dev)
        spin_lock_irqsave(&lweventlist_lock, flags);
        if (list_empty(&dev->link_watch_list)) {
                list_add_tail(&dev->link_watch_list, &lweventlist);
-               dev_hold_track(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC);
+               netdev_hold(dev, &dev->linkwatch_dev_tracker, GFP_ATOMIC);
        }
        spin_unlock_irqrestore(&lweventlist_lock, flags);
 }
index 5462528..6a8c259 100644 (file)
@@ -624,7 +624,7 @@ ___neigh_create(struct neigh_table *tbl, const void *pkey,
 
        memcpy(n->primary_key, pkey, key_len);
        n->dev = dev;
-       dev_hold_track(dev, &n->dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &n->dev_tracker, GFP_ATOMIC);
 
        /* Protocol specific setup. */
        if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
@@ -770,10 +770,10 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
        write_pnet(&n->net, net);
        memcpy(n->key, pkey, key_len);
        n->dev = dev;
-       dev_hold_track(dev, &n->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &n->dev_tracker, GFP_KERNEL);
 
        if (tbl->pconstructor && tbl->pconstructor(n)) {
-               dev_put_track(dev, &n->dev_tracker);
+               netdev_put(dev, &n->dev_tracker);
                kfree(n);
                n = NULL;
                goto out;
@@ -805,7 +805,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
                        write_unlock_bh(&tbl->lock);
                        if (tbl->pdestructor)
                                tbl->pdestructor(n);
-                       dev_put_track(n->dev, &n->dev_tracker);
+                       netdev_put(n->dev, &n->dev_tracker);
                        kfree(n);
                        return 0;
                }
@@ -838,7 +838,7 @@ static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
                n->next = NULL;
                if (tbl->pdestructor)
                        tbl->pdestructor(n);
-               dev_put_track(n->dev, &n->dev_tracker);
+               netdev_put(n->dev, &n->dev_tracker);
                kfree(n);
        }
        return -ENOENT;
@@ -879,7 +879,7 @@ void neigh_destroy(struct neighbour *neigh)
        if (dev->netdev_ops->ndo_neigh_destroy)
                dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
 
-       dev_put_track(dev, &neigh->dev_tracker);
+       netdev_put(dev, &neigh->dev_tracker);
        neigh_parms_put(neigh->parms);
 
        neigh_dbg(2, "neigh %p is destroyed\n", neigh);
@@ -1579,7 +1579,7 @@ static void neigh_managed_work(struct work_struct *work)
        list_for_each_entry(neigh, &tbl->managed_list, managed_list)
                neigh_event_send_probe(neigh, NULL, false);
        queue_delayed_work(system_power_efficient_wq, &tbl->managed_work,
-                          max(NEIGH_VAR(&tbl->parms, DELAY_PROBE_TIME), HZ));
+                          NEIGH_VAR(&tbl->parms, INTERVAL_PROBE_TIME_MS));
        write_unlock_bh(&tbl->lock);
 }
 
@@ -1671,13 +1671,13 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
                refcount_set(&p->refcnt, 1);
                p->reachable_time =
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
-               dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL);
+               netdev_hold(dev, &p->dev_tracker, GFP_KERNEL);
                p->dev = dev;
                write_pnet(&p->net, net);
                p->sysctl_table = NULL;
 
                if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
-                       dev_put_track(dev, &p->dev_tracker);
+                       netdev_put(dev, &p->dev_tracker);
                        kfree(p);
                        return NULL;
                }
@@ -1708,7 +1708,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
        list_del(&parms->list);
        parms->dead = 1;
        write_unlock_bh(&tbl->lock);
-       dev_put_track(parms->dev, &parms->dev_tracker);
+       netdev_put(parms->dev, &parms->dev_tracker);
        call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
 }
 EXPORT_SYMBOL(neigh_parms_release);
@@ -2100,7 +2100,9 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
            nla_put_msecs(skb, NDTPA_PROXY_DELAY,
                          NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
            nla_put_msecs(skb, NDTPA_LOCKTIME,
-                         NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
+                         NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD) ||
+           nla_put_msecs(skb, NDTPA_INTERVAL_PROBE_TIME_MS,
+                         NEIGH_VAR(parms, INTERVAL_PROBE_TIME_MS), NDTPA_PAD))
                goto nla_put_failure;
        return nla_nest_end(skb, nest);
 
@@ -2255,6 +2257,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
        [NDTPA_ANYCAST_DELAY]           = { .type = NLA_U64 },
        [NDTPA_PROXY_DELAY]             = { .type = NLA_U64 },
        [NDTPA_LOCKTIME]                = { .type = NLA_U64 },
+       [NDTPA_INTERVAL_PROBE_TIME_MS]  = { .type = NLA_U64, .min = 1 },
 };
 
 static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -2373,6 +2376,10 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
                                              nla_get_msecs(tbp[i]));
                                call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
                                break;
+                       case NDTPA_INTERVAL_PROBE_TIME_MS:
+                               NEIGH_VAR_SET(p, INTERVAL_PROBE_TIME_MS,
+                                             nla_get_msecs(tbp[i]));
+                               break;
                        case NDTPA_RETRANS_TIME:
                                NEIGH_VAR_SET(p, RETRANS_TIME,
                                              nla_get_msecs(tbp[i]));
@@ -3562,6 +3569,22 @@ static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
        return ret;
 }
 
+static int neigh_proc_dointvec_ms_jiffies_positive(struct ctl_table *ctl, int write,
+                                                  void *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table tmp = *ctl;
+       int ret;
+
+       int min = msecs_to_jiffies(1);
+
+       tmp.extra1 = &min;
+       tmp.extra2 = NULL;
+
+       ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos);
+       neigh_proc_update(ctl, write);
+       return ret;
+}
+
 int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
                        size_t *lenp, loff_t *ppos)
 {
@@ -3658,6 +3681,9 @@ static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
 #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
        NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
 
+#define NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(attr, name) \
+       NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies_positive)
+
 #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
        NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
 
@@ -3676,6 +3702,8 @@ static struct neigh_sysctl_table {
                NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
                NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
                NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
+               NEIGH_SYSCTL_MS_JIFFIES_POSITIVE_ENTRY(INTERVAL_PROBE_TIME_MS,
+                                                      "interval_probe_time_ms"),
                NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
                NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
                NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
index a364256..d61afd2 100644 (file)
@@ -1017,7 +1017,7 @@ static void rx_queue_release(struct kobject *kobj)
 #endif
 
        memset(kobj, 0, sizeof(*kobj));
-       dev_put_track(queue->dev, &queue->dev_tracker);
+       netdev_put(queue->dev, &queue->dev_tracker);
 }
 
 static const void *rx_queue_namespace(struct kobject *kobj)
@@ -1057,7 +1057,7 @@ static int rx_queue_add_kobject(struct net_device *dev, int index)
        /* Kobject_put later will trigger rx_queue_release call which
         * decreases dev refcount: Take that reference here
         */
-       dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL);
+       netdev_hold(queue->dev, &queue->dev_tracker, GFP_KERNEL);
 
        kobj->kset = dev->queues_kset;
        error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL,
@@ -1620,7 +1620,7 @@ static void netdev_queue_release(struct kobject *kobj)
        struct netdev_queue *queue = to_netdev_queue(kobj);
 
        memset(kobj, 0, sizeof(*kobj));
-       dev_put_track(queue->dev, &queue->dev_tracker);
+       netdev_put(queue->dev, &queue->dev_tracker);
 }
 
 static const void *netdev_queue_namespace(struct kobject *kobj)
@@ -1660,7 +1660,7 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index)
        /* Kobject_put later will trigger netdev_queue_release call
         * which decreases dev refcount: Take that reference here
         */
-       dev_hold_track(queue->dev, &queue->dev_tracker, GFP_KERNEL);
+       netdev_hold(queue->dev, &queue->dev_tracker, GFP_KERNEL);
 
        kobj->kset = dev->queues_kset;
        error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL,
index db72446..5d27067 100644 (file)
@@ -853,7 +853,7 @@ void netpoll_cleanup(struct netpoll *np)
        if (!np->dev)
                goto out;
        __netpoll_cleanup(np);
-       dev_put_track(np->dev, &np->dev_tracker);
+       netdev_put(np->dev, &np->dev_tracker);
        np->dev = NULL;
 out:
        rtnl_unlock();
index 84b62cd..88906ba 100644 (file)
@@ -2100,7 +2100,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn,
 
        /* Clean old setups */
        if (pkt_dev->odev) {
-               dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
+               netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker);
                pkt_dev->odev = NULL;
        }
 
@@ -3807,7 +3807,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 
        return add_dev_to_thread(t, pkt_dev);
 out2:
-       dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
+       netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker);
 out1:
 #ifdef CONFIG_XFRM
        free_SAs(pkt_dev);
@@ -3901,7 +3901,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        /* Dis-associate from the interface */
 
        if (pkt_dev->odev) {
-               dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
+               netdev_put(pkt_dev->odev, &pkt_dev->dev_tracker);
                pkt_dev->odev = NULL;
        }
 
index 5b3559c..c62e42d 100644 (file)
@@ -91,6 +91,9 @@ static struct kmem_cache *skbuff_ext_cache __ro_after_init;
 int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS;
 EXPORT_SYMBOL(sysctl_max_skb_frags);
 
+/* The array 'drop_reasons' is auto-generated in dropreason_str.c */
+EXPORT_SYMBOL(drop_reasons);
+
 /**
  *     skb_panic - private function for out-of-line support
  *     @skb:   buffer
@@ -172,13 +175,14 @@ static struct sk_buff *napi_skb_cache_get(void)
        struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
        struct sk_buff *skb;
 
-       if (unlikely(!nc->skb_count))
+       if (unlikely(!nc->skb_count)) {
                nc->skb_count = kmem_cache_alloc_bulk(skbuff_head_cache,
                                                      GFP_ATOMIC,
                                                      NAPI_SKB_CACHE_BULK,
                                                      nc->skb_cache);
-       if (unlikely(!nc->skb_count))
-               return NULL;
+               if (unlikely(!nc->skb_count))
+                       return NULL;
+       }
 
        skb = nc->skb_cache[--nc->skb_count];
        kasan_unpoison_object_data(skbuff_head_cache, skb);
@@ -557,6 +561,7 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
        struct sk_buff *skb;
        void *data;
 
+       DEBUG_NET_WARN_ON_ONCE(!in_softirq());
        len += NET_SKB_PAD + NET_IP_ALIGN;
 
        /* If requested length is either too small or too big,
@@ -725,7 +730,7 @@ void skb_release_head_state(struct sk_buff *skb)
 {
        skb_dst_drop(skb);
        if (skb->destructor) {
-               WARN_ON(in_hardirq());
+               DEBUG_NET_WARN_ON_ONCE(in_hardirq());
                skb->destructor(skb);
        }
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
@@ -978,7 +983,7 @@ void napi_consume_skb(struct sk_buff *skb, int budget)
                return;
        }
 
-       lockdep_assert_in_softirq();
+       DEBUG_NET_WARN_ON_ONCE(!in_softirq());
 
        if (!skb_unref(skb))
                return;
@@ -3190,9 +3195,7 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
                }
        }
 
-       to->truesize += len + plen;
-       to->len += len + plen;
-       to->data_len += len + plen;
+       skb_len_add(to, len + plen);
 
        if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
                skb_tx_error(from);
@@ -3629,13 +3632,8 @@ onlymerged:
        tgt->ip_summed = CHECKSUM_PARTIAL;
        skb->ip_summed = CHECKSUM_PARTIAL;
 
-       /* Yak, is it really working this way? Some helper please? */
-       skb->len -= shiftlen;
-       skb->data_len -= shiftlen;
-       skb->truesize -= shiftlen;
-       tgt->len += shiftlen;
-       tgt->data_len += shiftlen;
-       tgt->truesize += shiftlen;
+       skb_len_add(skb, -shiftlen);
+       skb_len_add(tgt, shiftlen);
 
        return shiftlen;
 }
index b0fcd02..fc69154 100644 (file)
@@ -720,6 +720,7 @@ struct sk_psock *sk_psock_init(struct sock *sk, int node)
        psock->eval = __SK_NONE;
        psock->sk_proto = prot;
        psock->saved_unhash = prot->unhash;
+       psock->saved_destroy = prot->destroy;
        psock->saved_close = prot->close;
        psock->saved_write_space = sk->sk_write_space;
 
index 2ff40dd..4cb957d 100644 (file)
@@ -991,7 +991,7 @@ EXPORT_SYMBOL(sock_set_mark);
 static void sock_release_reserved_memory(struct sock *sk, int bytes)
 {
        /* Round down bytes to multiple of pages */
-       bytes &= ~(SK_MEM_QUANTUM - 1);
+       bytes = round_down(bytes, PAGE_SIZE);
 
        WARN_ON(bytes > sk->sk_reserved_mem);
        sk->sk_reserved_mem -= bytes;
@@ -1019,7 +1019,8 @@ static int sock_reserve_memory(struct sock *sk, int bytes)
                return -ENOMEM;
 
        /* pre-charge to forward_alloc */
-       allocated = sk_memory_allocated_add(sk, pages);
+       sk_memory_allocated_add(sk, pages);
+       allocated = sk_memory_allocated(sk);
        /* If the system goes into memory pressure with this
         * precharge, give up and return error.
         */
@@ -1028,9 +1029,9 @@ static int sock_reserve_memory(struct sock *sk, int bytes)
                mem_cgroup_uncharge_skmem(sk->sk_memcg, pages);
                return -ENOMEM;
        }
-       sk->sk_forward_alloc += pages << SK_MEM_QUANTUM_SHIFT;
+       sk->sk_forward_alloc += pages << PAGE_SHIFT;
 
-       sk->sk_reserved_mem += pages << SK_MEM_QUANTUM_SHIFT;
+       sk->sk_reserved_mem += pages << PAGE_SHIFT;
 
        return 0;
 }
@@ -2844,7 +2845,7 @@ void __release_sock(struct sock *sk)
                do {
                        next = skb->next;
                        prefetch(next);
-                       WARN_ON_ONCE(skb_dst_is_noref(skb));
+                       DEBUG_NET_WARN_ON_ONCE(skb_dst_is_noref(skb));
                        skb_mark_not_on_list(skb);
                        sk_backlog_rcv(sk, skb);
 
@@ -2869,6 +2870,7 @@ void __sk_flush_backlog(struct sock *sk)
        __release_sock(sk);
        spin_unlock_bh(&sk->sk_lock.slock);
 }
+EXPORT_SYMBOL_GPL(__sk_flush_backlog);
 
 /**
  * sk_wait_data - wait for data to arrive at sk_receive_queue
@@ -2906,11 +2908,13 @@ EXPORT_SYMBOL(sk_wait_data);
  */
 int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind)
 {
-       struct proto *prot = sk->sk_prot;
-       long allocated = sk_memory_allocated_add(sk, amt);
        bool memcg_charge = mem_cgroup_sockets_enabled && sk->sk_memcg;
+       struct proto *prot = sk->sk_prot;
        bool charged = true;
+       long allocated;
 
+       sk_memory_allocated_add(sk, amt);
+       allocated = sk_memory_allocated(sk);
        if (memcg_charge &&
            !(charged = mem_cgroup_charge_skmem(sk->sk_memcg, amt,
                                                gfp_memcg_charge())))
@@ -2987,7 +2991,6 @@ suppress_allocation:
 
        return 0;
 }
-EXPORT_SYMBOL(__sk_mem_raise_allocated);
 
 /**
  *     __sk_mem_schedule - increase sk_forward_alloc and memory_allocated
@@ -3003,10 +3006,10 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)
 {
        int ret, amt = sk_mem_pages(size);
 
-       sk->sk_forward_alloc += amt << SK_MEM_QUANTUM_SHIFT;
+       sk->sk_forward_alloc += amt << PAGE_SHIFT;
        ret = __sk_mem_raise_allocated(sk, size, amt, kind);
        if (!ret)
-               sk->sk_forward_alloc -= amt << SK_MEM_QUANTUM_SHIFT;
+               sk->sk_forward_alloc -= amt << PAGE_SHIFT;
        return ret;
 }
 EXPORT_SYMBOL(__sk_mem_schedule);
@@ -3029,17 +3032,16 @@ void __sk_mem_reduce_allocated(struct sock *sk, int amount)
            (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)))
                sk_leave_memory_pressure(sk);
 }
-EXPORT_SYMBOL(__sk_mem_reduce_allocated);
 
 /**
  *     __sk_mem_reclaim - reclaim sk_forward_alloc and memory_allocated
  *     @sk: socket
- *     @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple)
+ *     @amount: number of bytes (rounded down to a PAGE_SIZE multiple)
  */
 void __sk_mem_reclaim(struct sock *sk, int amount)
 {
-       amount >>= SK_MEM_QUANTUM_SHIFT;
-       sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT;
+       amount >>= PAGE_SHIFT;
+       sk->sk_forward_alloc -= amount << PAGE_SHIFT;
        __sk_mem_reduce_allocated(sk, amount);
 }
 EXPORT_SYMBOL(__sk_mem_reclaim);
@@ -3798,6 +3800,10 @@ int proto_register(struct proto *prot, int alloc_slab)
                pr_err("%s: missing sysctl_mem\n", prot->name);
                return -EINVAL;
        }
+       if (prot->memory_allocated && !prot->per_cpu_fw_alloc) {
+               pr_err("%s: missing per_cpu_fw_alloc\n", prot->name);
+               return -EINVAL;
+       }
        if (alloc_slab) {
                prot->slab = kmem_cache_create_usercopy(prot->name,
                                        prot->obj_size, 0,
index 81d4b47..9f08ccf 100644 (file)
@@ -1561,6 +1561,29 @@ void sock_map_unhash(struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(sock_map_unhash);
 
+void sock_map_destroy(struct sock *sk)
+{
+       void (*saved_destroy)(struct sock *sk);
+       struct sk_psock *psock;
+
+       rcu_read_lock();
+       psock = sk_psock_get(sk);
+       if (unlikely(!psock)) {
+               rcu_read_unlock();
+               if (sk->sk_prot->destroy)
+                       sk->sk_prot->destroy(sk);
+               return;
+       }
+
+       saved_destroy = psock->saved_destroy;
+       sock_map_remove_links(sk, psock);
+       rcu_read_unlock();
+       sk_psock_stop(psock, true);
+       sk_psock_put(sk, psock);
+       saved_destroy(sk);
+}
+EXPORT_SYMBOL_GPL(sock_map_destroy);
+
 void sock_map_close(struct sock *sk, long timeout)
 {
        void (*saved_close)(struct sock *sk, long timeout);
index 06b36c7..ccc083c 100644 (file)
@@ -196,13 +196,13 @@ void sk_stream_kill_queues(struct sock *sk)
        __skb_queue_purge(&sk->sk_receive_queue);
 
        /* Next, the write queue. */
-       WARN_ON(!skb_queue_empty(&sk->sk_write_queue));
+       WARN_ON_ONCE(!skb_queue_empty(&sk->sk_write_queue));
 
        /* Account for returned memory. */
        sk_mem_reclaim_final(sk);
 
-       WARN_ON(sk->sk_wmem_queued);
-       WARN_ON(sk->sk_forward_alloc);
+       WARN_ON_ONCE(sk->sk_wmem_queued);
+       WARN_ON_ONCE(sk->sk_forward_alloc);
 
        /* It is _impossible_ for the backlog to contain anything
         * when we get here.  All user references to this socket
index dc92a67..aa4f43f 100644 (file)
@@ -149,6 +149,7 @@ static DEFINE_RWLOCK(dn_hash_lock);
 static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE];
 static struct hlist_head dn_wild_sk;
 static atomic_long_t decnet_memory_allocated;
+static DEFINE_PER_CPU(int, decnet_memory_per_cpu_fw_alloc);
 
 static int __dn_setsockopt(struct socket *sock, int level, int optname,
                sockptr_t optval, unsigned int optlen, int flags);
@@ -454,7 +455,10 @@ static struct proto dn_proto = {
        .owner                  = THIS_MODULE,
        .enter_memory_pressure  = dn_enter_memory_pressure,
        .memory_pressure        = &dn_memory_pressure,
+
        .memory_allocated       = &decnet_memory_allocated,
+       .per_cpu_fw_alloc       = &decnet_memory_per_cpu_fw_alloc,
+
        .sysctl_mem             = sysctl_decnet_mem,
        .sysctl_wmem            = sysctl_decnet_wmem,
        .sysctl_rmem            = sysctl_decnet_rmem,
index fbd98ac..7c569bc 100644 (file)
@@ -94,6 +94,7 @@ struct neigh_table dn_neigh_table = {
                        [NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
                        [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
                        [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
+                       [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ,
                        [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
                        [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX,
                        [NEIGH_VAR_PROXY_QLEN] = 0,
index 8cb87b5..3eef72c 100644 (file)
@@ -87,10 +87,10 @@ config NET_DSA_TAG_MTK
          Mediatek switches.
 
 config NET_DSA_TAG_KSZ
-       tristate "Tag driver for Microchip 8795/9477/9893 families of switches"
+       tristate "Tag driver for Microchip 8795/937x/9477/9893 families of switches"
        help
          Say Y if you want to enable support for tagging frames for the
-         Microchip 8795/9477/9893 families of switches.
+         Microchip 8795/937x/9477/9893 families of switches.
 
 config NET_DSA_TAG_OCELOT
        tristate "Tag driver for Ocelot family of switches, using NPI port"
@@ -132,6 +132,13 @@ config NET_DSA_TAG_RTL8_4
          Say Y or M if you want to enable support for tagging frames for Realtek
          switches with 8 byte protocol 4 tags, such as the Realtek RTL8365MB-VC.
 
+config NET_DSA_TAG_RZN1_A5PSW
+       tristate "Tag driver for Renesas RZ/N1 A5PSW switch"
+       help
+         Say Y or M if you want to enable support for tagging frames for
+         Renesas RZ/N1 embedded switch that uses an 8 byte tag located after
+         destination MAC address.
+
 config NET_DSA_TAG_LAN9303
        tristate "Tag driver for SMSC/Microchip LAN9303 family of switches"
        help
index 9f75820..af28c24 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_NET_DSA_TAG_OCELOT_8021Q) += tag_ocelot_8021q.o
 obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
 obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
 obj-$(CONFIG_NET_DSA_TAG_RTL8_4) += tag_rtl8_4.o
+obj-$(CONFIG_NET_DSA_TAG_RZN1_A5PSW) += tag_rzn1_a5psw.o
 obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
 obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
 obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o
index 801a5d4..ad6a666 100644 (file)
@@ -935,10 +935,10 @@ static void dsa_slave_get_ethtool_stats(struct net_device *dev,
                s = per_cpu_ptr(dev->tstats, i);
                do {
                        start = u64_stats_fetch_begin_irq(&s->syncp);
-                       tx_packets = s->tx_packets;
-                       tx_bytes = s->tx_bytes;
-                       rx_packets = s->rx_packets;
-                       rx_bytes = s->rx_bytes;
+                       tx_packets = u64_stats_read(&s->tx_packets);
+                       tx_bytes = u64_stats_read(&s->tx_bytes);
+                       rx_packets = u64_stats_read(&s->rx_packets);
+                       rx_bytes = u64_stats_read(&s->rx_bytes);
                } while (u64_stats_fetch_retry_irq(&s->syncp, start));
                data[0] += tx_packets;
                data[1] += tx_bytes;
@@ -1002,6 +1002,18 @@ dsa_slave_get_eth_ctrl_stats(struct net_device *dev,
                ds->ops->get_eth_ctrl_stats(ds, dp->index, ctrl_stats);
 }
 
+static void
+dsa_slave_get_rmon_stats(struct net_device *dev,
+                        struct ethtool_rmon_stats *rmon_stats,
+                        const struct ethtool_rmon_hist_range **ranges)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct dsa_switch *ds = dp->ds;
+
+       if (ds->ops->get_rmon_stats)
+               ds->ops->get_rmon_stats(ds, dp->index, rmon_stats, ranges);
+}
+
 static void dsa_slave_net_selftest(struct net_device *ndev,
                                   struct ethtool_test *etest, u64 *buf)
 {
@@ -1097,6 +1109,16 @@ static int dsa_slave_set_link_ksettings(struct net_device *dev,
        return phylink_ethtool_ksettings_set(dp->pl, cmd);
 }
 
+static void dsa_slave_get_pause_stats(struct net_device *dev,
+                                 struct ethtool_pause_stats *pause_stats)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct dsa_switch *ds = dp->ds;
+
+       if (ds->ops->get_pause_stats)
+               ds->ops->get_pause_stats(ds, dp->index, pause_stats);
+}
+
 static void dsa_slave_get_pauseparam(struct net_device *dev,
                                     struct ethtool_pauseparam *pause)
 {
@@ -2081,12 +2103,14 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
        .get_eth_phy_stats      = dsa_slave_get_eth_phy_stats,
        .get_eth_mac_stats      = dsa_slave_get_eth_mac_stats,
        .get_eth_ctrl_stats     = dsa_slave_get_eth_ctrl_stats,
+       .get_rmon_stats         = dsa_slave_get_rmon_stats,
        .set_wol                = dsa_slave_set_wol,
        .get_wol                = dsa_slave_get_wol,
        .set_eee                = dsa_slave_set_eee,
        .get_eee                = dsa_slave_get_eee,
        .get_link_ksettings     = dsa_slave_get_link_ksettings,
        .set_link_ksettings     = dsa_slave_set_link_ksettings,
+       .get_pause_stats        = dsa_slave_get_pause_stats,
        .get_pauseparam         = dsa_slave_get_pauseparam,
        .set_pauseparam         = dsa_slave_set_pauseparam,
        .get_rxnfc              = dsa_slave_get_rxnfc,
@@ -2460,8 +2484,9 @@ static int dsa_slave_changeupper(struct net_device *dev,
                        if (!err)
                                dsa_bridge_mtu_normalization(dp);
                        if (err == -EOPNOTSUPP) {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "Offloading not supported");
+                               if (!extack->_msg)
+                                       NL_SET_ERR_MSG_MOD(extack,
+                                                          "Offloading not supported");
                                err = 0;
                        }
                        err = notifier_from_errno(err);
index 3509fc9..38fa19c 100644 (file)
@@ -193,10 +193,69 @@ static const struct dsa_device_ops ksz9893_netdev_ops = {
 DSA_TAG_DRIVER(ksz9893_netdev_ops);
 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893);
 
+/* For xmit, 2 bytes are added before FCS.
+ * ---------------------------------------------------------------------------
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|tag1(1byte)|FCS(4bytes)
+ * ---------------------------------------------------------------------------
+ * tag0 : represents tag override, lookup and valid
+ * tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8)
+ *
+ * For rcv, 1 byte is added before FCS.
+ * ---------------------------------------------------------------------------
+ * DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes)
+ * ---------------------------------------------------------------------------
+ * tag0 : zero-based value represents port
+ *       (eg, 0x00=port1, 0x02=port3, 0x07=port8)
+ */
+#define LAN937X_EGRESS_TAG_LEN         2
+
+#define LAN937X_TAIL_TAG_BLOCKING_OVERRIDE     BIT(11)
+#define LAN937X_TAIL_TAG_LOOKUP                        BIT(12)
+#define LAN937X_TAIL_TAG_VALID                 BIT(13)
+#define LAN937X_TAIL_TAG_PORT_MASK             7
+
+static struct sk_buff *lan937x_xmit(struct sk_buff *skb,
+                                   struct net_device *dev)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       const struct ethhdr *hdr = eth_hdr(skb);
+       __be16 *tag;
+       u16 val;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+               return NULL;
+
+       tag = skb_put(skb, LAN937X_EGRESS_TAG_LEN);
+
+       val = BIT(dp->index);
+
+       if (is_link_local_ether_addr(hdr->h_dest))
+               val |= LAN937X_TAIL_TAG_BLOCKING_OVERRIDE;
+
+       /* Tail tag valid bit - This bit should always be set by the CPU */
+       val |= LAN937X_TAIL_TAG_VALID;
+
+       put_unaligned_be16(val, tag);
+
+       return skb;
+}
+
+static const struct dsa_device_ops lan937x_netdev_ops = {
+       .name   = "lan937x",
+       .proto  = DSA_TAG_PROTO_LAN937X,
+       .xmit   = lan937x_xmit,
+       .rcv    = ksz9477_rcv,
+       .needed_tailroom = LAN937X_EGRESS_TAG_LEN,
+};
+
+DSA_TAG_DRIVER(lan937x_netdev_ops);
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X);
+
 static struct dsa_tag_driver *dsa_tag_driver_array[] = {
        &DSA_TAG_DRIVER_NAME(ksz8795_netdev_ops),
        &DSA_TAG_DRIVER_NAME(ksz9477_netdev_ops),
        &DSA_TAG_DRIVER_NAME(ksz9893_netdev_ops),
+       &DSA_TAG_DRIVER_NAME(lan937x_netdev_ops),
 };
 
 module_dsa_tag_drivers(dsa_tag_driver_array);
diff --git a/net/dsa/tag_rzn1_a5psw.c b/net/dsa/tag_rzn1_a5psw.c
new file mode 100644 (file)
index 0000000..e2a5ee6
--- /dev/null
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Schneider Electric
+ *
+ * Clément Léger <clement.leger@bootlin.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <net/dsa.h>
+
+#include "dsa_priv.h"
+
+/* To define the outgoing port and to discover the incoming port a TAG is
+ * inserted after Src MAC :
+ *
+ *       Dest MAC       Src MAC           TAG         Type
+ * ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 7 8 | 1 2 |...
+ *                                |<--------------->|
+ *
+ * See struct a5psw_tag for layout
+ */
+
+#define ETH_P_DSA_A5PSW                        0xE001
+#define A5PSW_TAG_LEN                  8
+#define A5PSW_CTRL_DATA_FORCE_FORWARD  BIT(0)
+/* This is both used for xmit tag and rcv tagging */
+#define A5PSW_CTRL_DATA_PORT           GENMASK(3, 0)
+
+struct a5psw_tag {
+       __be16 ctrl_tag;
+       __be16 ctrl_data;
+       __be16 ctrl_data2_hi;
+       __be16 ctrl_data2_lo;
+};
+
+static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct dsa_port *dp = dsa_slave_to_port(dev);
+       struct a5psw_tag *ptag;
+       u32 data2_val;
+
+       BUILD_BUG_ON(sizeof(*ptag) != A5PSW_TAG_LEN);
+
+       /* The Ethernet switch we are interfaced with needs packets to be at
+        * least 60 bytes otherwise they will be discarded when they enter the
+        * switch port logic.
+        */
+       if (__skb_put_padto(skb, ETH_ZLEN, false))
+               return NULL;
+
+       /* provide 'A5PSW_TAG_LEN' bytes additional space */
+       skb_push(skb, A5PSW_TAG_LEN);
+
+       /* make room between MACs and Ether-Type to insert tag */
+       dsa_alloc_etype_header(skb, A5PSW_TAG_LEN);
+
+       ptag = dsa_etype_header_pos_tx(skb);
+
+       data2_val = FIELD_PREP(A5PSW_CTRL_DATA_PORT, BIT(dp->index));
+       ptag->ctrl_tag = htons(ETH_P_DSA_A5PSW);
+       ptag->ctrl_data = htons(A5PSW_CTRL_DATA_FORCE_FORWARD);
+       ptag->ctrl_data2_lo = htons(data2_val);
+       ptag->ctrl_data2_hi = 0;
+
+       return skb;
+}
+
+static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
+                                    struct net_device *dev)
+{
+       struct a5psw_tag *tag;
+       int port;
+
+       if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) {
+               dev_warn_ratelimited(&dev->dev,
+                                    "Dropping packet, cannot pull\n");
+               return NULL;
+       }
+
+       tag = dsa_etype_header_pos_rx(skb);
+
+       if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) {
+               dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n");
+               return NULL;
+       }
+
+       port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data));
+
+       skb->dev = dsa_master_find_slave(dev, 0, port);
+       if (!skb->dev)
+               return NULL;
+
+       skb_pull_rcsum(skb, A5PSW_TAG_LEN);
+       dsa_strip_etype_header(skb, A5PSW_TAG_LEN);
+
+       dsa_default_offload_fwd_mark(skb);
+
+       return skb;
+}
+
+static const struct dsa_device_ops a5psw_netdev_ops = {
+       .name   = "a5psw",
+       .proto  = DSA_TAG_PROTO_RZN1_A5PSW,
+       .xmit   = a5psw_tag_xmit,
+       .rcv    = a5psw_tag_rcv,
+       .needed_headroom = A5PSW_TAG_LEN,
+};
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_A5PSW);
+module_dsa_tag_driver(a5psw_netdev_ops);
index 326e14e..6a7308d 100644 (file)
@@ -369,22 +369,9 @@ EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode);
 bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
                                             const unsigned long *src)
 {
-       bool retval = true;
-
-       /* TODO: following test will soon always be true */
-       if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
-               __ETHTOOL_DECLARE_LINK_MODE_MASK(ext);
-
-               linkmode_zero(ext);
-               bitmap_fill(ext, 32);
-               bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
-               if (linkmode_intersects(ext, src)) {
-                       /* src mask goes beyond bit 31 */
-                       retval = false;
-               }
-       }
        *legacy_u32 = src[0];
-       return retval;
+       return find_next_bit(src, __ETHTOOL_LINK_MODE_MASK_NBITS, 32) ==
+               __ETHTOOL_LINK_MODE_MASK_NBITS;
 }
 EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
 
@@ -2010,7 +1997,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
         * removal of the device.
         */
        busy = true;
-       dev_hold_track(dev, &dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &dev_tracker, GFP_KERNEL);
        rtnl_unlock();
 
        if (rc == 0) {
@@ -2034,7 +2021,7 @@ static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
        }
 
        rtnl_lock();
-       dev_put_track(dev, &dev_tracker);
+       netdev_put(dev, &dev_tracker);
        busy = false;
 
        (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
index 5fe8f4a..e26079e 100644 (file)
@@ -402,7 +402,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
                ops->cleanup_data(reply_data);
 
        genlmsg_end(rskb, reply_payload);
-       dev_put_track(req_info->dev, &req_info->dev_tracker);
+       netdev_put(req_info->dev, &req_info->dev_tracker);
        kfree(reply_data);
        kfree(req_info);
        return genlmsg_reply(rskb, info);
@@ -414,7 +414,7 @@ err_cleanup:
        if (ops->cleanup_data)
                ops->cleanup_data(reply_data);
 err_dev:
-       dev_put_track(req_info->dev, &req_info->dev_tracker);
+       netdev_put(req_info->dev, &req_info->dev_tracker);
        kfree(reply_data);
        kfree(req_info);
        return ret;
@@ -550,7 +550,7 @@ static int ethnl_default_start(struct netlink_callback *cb)
                 * same parser as for non-dump (doit) requests is used, it
                 * would take reference to the device if it finds one
                 */
-               dev_put_track(req_info->dev, &req_info->dev_tracker);
+               netdev_put(req_info->dev, &req_info->dev_tracker);
                req_info->dev = NULL;
        }
        if (ret < 0)
index 7919ddb..c0d5876 100644 (file)
@@ -237,7 +237,7 @@ struct ethnl_req_info {
 
 static inline void ethnl_parse_header_dev_put(struct ethnl_req_info *req_info)
 {
-       dev_put_track(req_info->dev, &req_info->dev_tracker);
+       netdev_put(req_info->dev, &req_info->dev_tracker);
 }
 
 /**
index 93da9f7..da81f56 100644 (file)
@@ -148,10 +148,10 @@ void inet_sock_destruct(struct sock *sk)
                return;
        }
 
-       WARN_ON(atomic_read(&sk->sk_rmem_alloc));
-       WARN_ON(refcount_read(&sk->sk_wmem_alloc));
-       WARN_ON(sk->sk_wmem_queued);
-       WARN_ON(sk_forward_alloc_get(sk));
+       WARN_ON_ONCE(atomic_read(&sk->sk_rmem_alloc));
+       WARN_ON_ONCE(refcount_read(&sk->sk_wmem_alloc));
+       WARN_ON_ONCE(sk->sk_wmem_queued);
+       WARN_ON_ONCE(sk_forward_alloc_get(sk));
 
        kfree(rcu_dereference_protected(inet->inet_opt, 1));
        dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1));
@@ -1929,6 +1929,8 @@ static int __init inet_init(void)
 
        sock_skb_cb_check_size(sizeof(struct inet_skb_parm));
 
+       raw_hashinfo_init(&raw_v4_hashinfo);
+
        rc = proto_register(&tcp_prot, 1);
        if (rc)
                goto out;
index ab4a560..af2f12f 100644 (file)
@@ -168,6 +168,7 @@ struct neigh_table arp_tbl = {
                        [NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
                        [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
                        [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
+                       [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ,
                        [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
                        [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX,
                        [NEIGH_VAR_PROXY_QLEN] = 64,
index b2366ad..92b778e 100644 (file)
@@ -244,7 +244,7 @@ void in_dev_finish_destroy(struct in_device *idev)
 #ifdef NET_REFCNT_DEBUG
        pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL");
 #endif
-       dev_put_track(dev, &idev->dev_tracker);
+       netdev_put(dev, &idev->dev_tracker);
        if (!idev->dead)
                pr_err("Freeing alive in_device %p\n", idev);
        else
@@ -272,7 +272,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
        if (IPV4_DEVCONF(in_dev->cnf, FORWARDING))
                dev_disable_lro(dev);
        /* Reference in_dev->dev */
-       dev_hold_track(dev, &in_dev->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &in_dev->dev_tracker, GFP_KERNEL);
        /* Account for reference dev->ip_ptr (below) */
        refcount_set(&in_dev->refcnt, 1);
 
index b21238d..7eae8d6 100644 (file)
@@ -502,9 +502,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
 
                        nfrags++;
 
-                       skb->len += tailen;
-                       skb->data_len += tailen;
-                       skb->truesize += tailen;
+                       skb_len_add(skb, tailen);
                        if (sk && sk_fullsock(sk))
                                refcount_add(tailen, &sk->sk_wmem_alloc);
 
index a57ba23..a5439a8 100644 (file)
@@ -211,7 +211,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
 
 void fib_nh_common_release(struct fib_nh_common *nhc)
 {
-       dev_put_track(nhc->nhc_dev, &nhc->nhc_dev_tracker);
+       netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker);
        lwtstate_put(nhc->nhc_lwtstate);
        rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
        rt_fibinfo_free(&nhc->nhc_rth_input);
@@ -1057,7 +1057,8 @@ static int fib_check_nh_v6_gw(struct net *net, struct fib_nh *nh,
        err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack);
        if (!err) {
                nh->fib_nh_dev = fib6_nh.fib_nh_dev;
-               dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_KERNEL);
+               netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker,
+                           GFP_KERNEL);
                nh->fib_nh_oif = nh->fib_nh_dev->ifindex;
                nh->fib_nh_scope = RT_SCOPE_LINK;
 
@@ -1141,7 +1142,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
                if (!netif_carrier_ok(dev))
                        nh->fib_nh_flags |= RTNH_F_LINKDOWN;
                nh->fib_nh_dev = dev;
-               dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
+               netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
                nh->fib_nh_scope = RT_SCOPE_LINK;
                return 0;
        }
@@ -1195,7 +1196,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
                               "No egress device for nexthop gateway");
                goto out;
        }
-       dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
        if (!netif_carrier_ok(dev))
                nh->fib_nh_flags |= RTNH_F_LINKDOWN;
        err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
@@ -1229,7 +1230,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
        }
 
        nh->fib_nh_dev = in_dev->dev;
-       dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
+       netdev_hold(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
        nh->fib_nh_scope = RT_SCOPE_HOST;
        if (!netif_carrier_ok(nh->fib_nh_dev))
                nh->fib_nh_flags |= RTNH_F_LINKDOWN;
index 00b4bf2..5e32a2f 100644 (file)
@@ -1214,9 +1214,7 @@ alloc_new_skb:
 
                        pfrag->offset += copy;
                        skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
-                       skb->len += copy;
-                       skb->data_len += copy;
-                       skb->truesize += copy;
+                       skb_len_add(skb, copy);
                        wmem_alloc_delta += copy;
                } else {
                        err = skb_zerocopy_iter_dgram(skb, from, copy);
@@ -1443,9 +1441,7 @@ ssize_t   ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
                        skb->csum = csum_block_add(skb->csum, csum, skb->len);
                }
 
-               skb->len += len;
-               skb->data_len += len;
-               skb->truesize += len;
+               skb_len_add(skb, len);
                refcount_add(len, &sk->sk_wmem_alloc);
                offset += len;
                size -= len;
index 9d41d5d..f53a0f2 100644 (file)
@@ -1759,15 +1759,15 @@ static int __init ip_auto_config_setup(char *addrs)
                        case 4:
                                if ((dp = strchr(ip, '.'))) {
                                        *dp++ = '\0';
-                                       strlcpy(utsname()->domainname, dp,
+                                       strscpy(utsname()->domainname, dp,
                                                sizeof(utsname()->domainname));
                                }
-                               strlcpy(utsname()->nodename, ip,
+                               strscpy(utsname()->nodename, ip,
                                        sizeof(utsname()->nodename));
                                ic_host_name_set = 1;
                                break;
                        case 5:
-                               strlcpy(user_dev_name, ip, sizeof(user_dev_name));
+                               strscpy(user_dev_name, ip, sizeof(user_dev_name));
                                break;
                        case 6:
                                if (ic_proto_name(ip) == 0 &&
@@ -1814,7 +1814,7 @@ __setup("nfsaddrs=", nfsaddrs_config_setup);
 
 static int __init vendor_class_identifier_setup(char *addrs)
 {
-       if (strlcpy(vendor_class_identifier, addrs,
+       if (strscpy(vendor_class_identifier, addrs,
                    sizeof(vendor_class_identifier))
            >= sizeof(vendor_class_identifier))
                pr_warn("DHCP: vendorclass too long, truncated to \"%s\"\n",
index 13e6329..73651d1 100644 (file)
@@ -77,7 +77,12 @@ struct ipmr_result {
  * Note that the changes are semaphored via rtnl_lock.
  */
 
-static DEFINE_RWLOCK(mrt_lock);
+static DEFINE_SPINLOCK(mrt_lock);
+
+static struct net_device *vif_dev_read(const struct vif_device *vif)
+{
+       return rcu_dereference(vif->dev);
+}
 
 /* Multicast router control variables */
 
@@ -100,11 +105,11 @@ static void ipmr_free_table(struct mr_table *mrt);
 static void ip_mr_forward(struct net *net, struct mr_table *mrt,
                          struct net_device *dev, struct sk_buff *skb,
                          struct mfc_cache *cache, int local);
-static int ipmr_cache_report(struct mr_table *mrt,
+static int ipmr_cache_report(const struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert);
 static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
                                 int cmd);
-static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
+static void igmpmsg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt);
 static void mroute_clean_tables(struct mr_table *mrt, int flags);
 static void ipmr_expire_process(struct timer_list *t);
 
@@ -501,11 +506,15 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
                return err;
        }
 
-       read_lock(&mrt_lock);
        dev->stats.tx_bytes += skb->len;
        dev->stats.tx_packets++;
-       ipmr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, IGMPMSG_WHOLEPKT);
-       read_unlock(&mrt_lock);
+       rcu_read_lock();
+
+       /* Pairs with WRITE_ONCE() in vif_add() and vif_delete() */
+       ipmr_cache_report(mrt, skb, READ_ONCE(mrt->mroute_reg_vif_num),
+                         IGMPMSG_WHOLEPKT);
+
+       rcu_read_unlock();
        kfree_skb(skb);
        return NETDEV_TX_OK;
 }
@@ -572,6 +581,7 @@ static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
 {
        struct net_device *reg_dev = NULL;
        struct iphdr *encap;
+       int vif_num;
 
        encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
        /* Check that:
@@ -584,11 +594,10 @@ static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
            ntohs(encap->tot_len) + pimlen > skb->len)
                return 1;
 
-       read_lock(&mrt_lock);
-       if (mrt->mroute_reg_vif_num >= 0)
-               reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
-       read_unlock(&mrt_lock);
-
+       /* Pairs with WRITE_ONCE() in vif_add()/vid_delete() */
+       vif_num = READ_ONCE(mrt->mroute_reg_vif_num);
+       if (vif_num >= 0)
+               reg_dev = vif_dev_read(&mrt->vif_table[vif_num]);
        if (!reg_dev)
                return 1;
 
@@ -614,10 +623,11 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
 static int call_ipmr_vif_entry_notifiers(struct net *net,
                                         enum fib_event_type event_type,
                                         struct vif_device *vif,
+                                        struct net_device *vif_dev,
                                         vifi_t vif_index, u32 tb_id)
 {
        return mr_call_vif_notifiers(net, RTNL_FAMILY_IPMR, event_type,
-                                    vif, vif_index, tb_id,
+                                    vif, vif_dev, vif_index, tb_id,
                                     &net->ipv4.ipmr_seq);
 }
 
@@ -649,22 +659,19 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
 
        v = &mrt->vif_table[vifi];
 
-       if (VIF_EXISTS(mrt, vifi))
-               call_ipmr_vif_entry_notifiers(net, FIB_EVENT_VIF_DEL, v, vifi,
-                                             mrt->id);
-
-       write_lock_bh(&mrt_lock);
-       dev = v->dev;
-       v->dev = NULL;
-
-       if (!dev) {
-               write_unlock_bh(&mrt_lock);
+       dev = rtnl_dereference(v->dev);
+       if (!dev)
                return -EADDRNOTAVAIL;
-       }
 
-       if (vifi == mrt->mroute_reg_vif_num)
-               mrt->mroute_reg_vif_num = -1;
+       spin_lock(&mrt_lock);
+       call_ipmr_vif_entry_notifiers(net, FIB_EVENT_VIF_DEL, v, dev,
+                                     vifi, mrt->id);
+       RCU_INIT_POINTER(v->dev, NULL);
 
+       if (vifi == mrt->mroute_reg_vif_num) {
+               /* Pairs with READ_ONCE() in ipmr_cache_report() and reg_vif_xmit() */
+               WRITE_ONCE(mrt->mroute_reg_vif_num, -1);
+       }
        if (vifi + 1 == mrt->maxvif) {
                int tmp;
 
@@ -672,10 +679,10 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
                        if (VIF_EXISTS(mrt, tmp))
                                break;
                }
-               mrt->maxvif = tmp+1;
+               WRITE_ONCE(mrt->maxvif, tmp + 1);
        }
 
-       write_unlock_bh(&mrt_lock);
+       spin_unlock(&mrt_lock);
 
        dev_set_allmulti(dev, -1);
 
@@ -691,7 +698,7 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
        if (v->flags & (VIFF_TUNNEL | VIFF_REGISTER) && !notify)
                unregister_netdevice_queue(dev, head);
 
-       dev_put_track(dev, &v->dev_tracker);
+       netdev_put(dev, &v->dev_tracker);
        return 0;
 }
 
@@ -777,7 +784,7 @@ out:
        spin_unlock(&mfc_unres_lock);
 }
 
-/* Fill oifs list. It is called under write locked mrt_lock. */
+/* Fill oifs list. It is called under locked mrt_lock. */
 static void ipmr_update_thresholds(struct mr_table *mrt, struct mr_mfc *cache,
                                   unsigned char *ttls)
 {
@@ -889,15 +896,18 @@ static int vif_add(struct net *net, struct mr_table *mrt,
        v->remote = vifc->vifc_rmt_addr.s_addr;
 
        /* And finish update writing critical data */
-       write_lock_bh(&mrt_lock);
-       v->dev = dev;
+       spin_lock(&mrt_lock);
+       rcu_assign_pointer(v->dev, dev);
        netdev_tracker_alloc(dev, &v->dev_tracker, GFP_ATOMIC);
-       if (v->flags & VIFF_REGISTER)
-               mrt->mroute_reg_vif_num = vifi;
+       if (v->flags & VIFF_REGISTER) {
+               /* Pairs with READ_ONCE() in ipmr_cache_report() and reg_vif_xmit() */
+               WRITE_ONCE(mrt->mroute_reg_vif_num, vifi);
+       }
        if (vifi+1 > mrt->maxvif)
-               mrt->maxvif = vifi+1;
-       write_unlock_bh(&mrt_lock);
-       call_ipmr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD, v, vifi, mrt->id);
+               WRITE_ONCE(mrt->maxvif, vifi + 1);
+       spin_unlock(&mrt_lock);
+       call_ipmr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD, v, dev,
+                                     vifi, mrt->id);
        return 0;
 }
 
@@ -1001,9 +1011,9 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
 
 /* Bounce a cache query up to mrouted and netlink.
  *
- * Called under mrt_lock.
+ * Called under rcu_read_lock().
  */
-static int ipmr_cache_report(struct mr_table *mrt,
+static int ipmr_cache_report(const struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert)
 {
        const int ihl = ip_hdrlen(pkt);
@@ -1038,8 +1048,11 @@ static int ipmr_cache_report(struct mr_table *mrt,
                        msg->im_vif = vifi;
                        msg->im_vif_hi = vifi >> 8;
                } else {
-                       msg->im_vif = mrt->mroute_reg_vif_num;
-                       msg->im_vif_hi = mrt->mroute_reg_vif_num >> 8;
+                       /* Pairs with WRITE_ONCE() in vif_add() and vif_delete() */
+                       int vif_num = READ_ONCE(mrt->mroute_reg_vif_num);
+
+                       msg->im_vif = vif_num;
+                       msg->im_vif_hi = vif_num >> 8;
                }
                ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
                ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
@@ -1064,10 +1077,8 @@ static int ipmr_cache_report(struct mr_table *mrt,
                skb->transport_header = skb->network_header;
        }
 
-       rcu_read_lock();
        mroute_sk = rcu_dereference(mrt->mroute_sk);
        if (!mroute_sk) {
-               rcu_read_unlock();
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -1076,7 +1087,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
 
        /* Deliver to mrouted */
        ret = sock_queue_rcv_skb(mroute_sk, skb);
-       rcu_read_unlock();
+
        if (ret < 0) {
                net_warn_ratelimited("mroute: pending queue full, dropping entries\n");
                kfree_skb(skb);
@@ -1086,6 +1097,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
 }
 
 /* Queue a packet for resolution. It gets locked cache entry! */
+/* Called under rcu_read_lock() */
 static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
                                 struct sk_buff *skb, struct net_device *dev)
 {
@@ -1198,12 +1210,12 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
                                   mfc->mfcc_mcastgrp.s_addr, parent);
        rcu_read_unlock();
        if (c) {
-               write_lock_bh(&mrt_lock);
+               spin_lock(&mrt_lock);
                c->_c.mfc_parent = mfc->mfcc_parent;
                ipmr_update_thresholds(mrt, &c->_c, mfc->mfcc_ttls);
                if (!mrtsock)
                        c->_c.mfc_flags |= MFC_STATIC;
-               write_unlock_bh(&mrt_lock);
+               spin_unlock(&mrt_lock);
                call_ipmr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, c,
                                              mrt->id);
                mroute_netlink_event(mrt, c, RTM_NEWROUTE);
@@ -1598,20 +1610,20 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
                if (vr.vifi >= mrt->maxvif)
                        return -EINVAL;
                vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif);
-               read_lock(&mrt_lock);
+               rcu_read_lock();
                vif = &mrt->vif_table[vr.vifi];
                if (VIF_EXISTS(mrt, vr.vifi)) {
-                       vr.icount = vif->pkt_in;
-                       vr.ocount = vif->pkt_out;
-                       vr.ibytes = vif->bytes_in;
-                       vr.obytes = vif->bytes_out;
-                       read_unlock(&mrt_lock);
+                       vr.icount = READ_ONCE(vif->pkt_in);
+                       vr.ocount = READ_ONCE(vif->pkt_out);
+                       vr.ibytes = READ_ONCE(vif->bytes_in);
+                       vr.obytes = READ_ONCE(vif->bytes_out);
+                       rcu_read_unlock();
 
                        if (copy_to_user(arg, &vr, sizeof(vr)))
                                return -EFAULT;
                        return 0;
                }
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
                return -EADDRNOTAVAIL;
        case SIOCGETSGCNT:
                if (copy_from_user(&sr, arg, sizeof(sr)))
@@ -1673,20 +1685,20 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
                if (vr.vifi >= mrt->maxvif)
                        return -EINVAL;
                vr.vifi = array_index_nospec(vr.vifi, mrt->maxvif);
-               read_lock(&mrt_lock);
+               rcu_read_lock();
                vif = &mrt->vif_table[vr.vifi];
                if (VIF_EXISTS(mrt, vr.vifi)) {
-                       vr.icount = vif->pkt_in;
-                       vr.ocount = vif->pkt_out;
-                       vr.ibytes = vif->bytes_in;
-                       vr.obytes = vif->bytes_out;
-                       read_unlock(&mrt_lock);
+                       vr.icount = READ_ONCE(vif->pkt_in);
+                       vr.ocount = READ_ONCE(vif->pkt_out);
+                       vr.ibytes = READ_ONCE(vif->bytes_in);
+                       vr.obytes = READ_ONCE(vif->bytes_out);
+                       rcu_read_unlock();
 
                        if (copy_to_user(arg, &vr, sizeof(vr)))
                                return -EFAULT;
                        return 0;
                }
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
                return -EADDRNOTAVAIL;
        case SIOCGETSGCNT:
                if (copy_from_user(&sr, arg, sizeof(sr)))
@@ -1726,7 +1738,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
        ipmr_for_each_table(mrt, net) {
                v = &mrt->vif_table[0];
                for (ct = 0; ct < mrt->maxvif; ct++, v++) {
-                       if (v->dev == dev)
+                       if (rcu_access_pointer(v->dev) == dev)
                                vif_delete(mrt, ct, 1, NULL);
                }
        }
@@ -1804,26 +1816,28 @@ static bool ipmr_forward_offloaded(struct sk_buff *skb, struct mr_table *mrt,
 }
 #endif
 
-/* Processing handlers for ipmr_forward */
+/* Processing handlers for ipmr_forward, under rcu_read_lock() */
 
 static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
                            int in_vifi, struct sk_buff *skb, int vifi)
 {
        const struct iphdr *iph = ip_hdr(skb);
        struct vif_device *vif = &mrt->vif_table[vifi];
+       struct net_device *vif_dev;
        struct net_device *dev;
        struct rtable *rt;
        struct flowi4 fl4;
        int    encap = 0;
 
-       if (!vif->dev)
+       vif_dev = vif_dev_read(vif);
+       if (!vif_dev)
                goto out_free;
 
        if (vif->flags & VIFF_REGISTER) {
-               vif->pkt_out++;
-               vif->bytes_out += skb->len;
-               vif->dev->stats.tx_bytes += skb->len;
-               vif->dev->stats.tx_packets++;
+               WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
+               WRITE_ONCE(vif->bytes_out, vif->bytes_out + skb->len);
+               vif_dev->stats.tx_bytes += skb->len;
+               vif_dev->stats.tx_packets++;
                ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
                goto out_free;
        }
@@ -1868,8 +1882,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
                goto out_free;
        }
 
-       vif->pkt_out++;
-       vif->bytes_out += skb->len;
+       WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
+       WRITE_ONCE(vif->bytes_out, vif->bytes_out + skb->len);
 
        skb_dst_drop(skb);
        skb_dst_set(skb, &rt->dst);
@@ -1881,8 +1895,8 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
        if (vif->flags & VIFF_TUNNEL) {
                ip_encap(net, skb, vif->local, vif->remote);
                /* FIXME: extra output firewall step used to be here. --RR */
-               vif->dev->stats.tx_packets++;
-               vif->dev->stats.tx_bytes += skb->len;
+               vif_dev->stats.tx_packets++;
+               vif_dev->stats.tx_bytes += skb->len;
        }
 
        IPCB(skb)->flags |= IPSKB_FORWARDED;
@@ -1906,18 +1920,20 @@ out_free:
        kfree_skb(skb);
 }
 
-static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev)
+/* Called with mrt_lock or rcu_read_lock() */
+static int ipmr_find_vif(const struct mr_table *mrt, struct net_device *dev)
 {
        int ct;
-
-       for (ct = mrt->maxvif-1; ct >= 0; ct--) {
-               if (mrt->vif_table[ct].dev == dev)
+       /* Pairs with WRITE_ONCE() in vif_delete()/vif_add() */
+       for (ct = READ_ONCE(mrt->maxvif) - 1; ct >= 0; ct--) {
+               if (rcu_access_pointer(mrt->vif_table[ct].dev) == dev)
                        break;
        }
        return ct;
 }
 
 /* "local" means that we should preserve one skb (for local delivery) */
+/* Called uner rcu_read_lock() */
 static void ip_mr_forward(struct net *net, struct mr_table *mrt,
                          struct net_device *dev, struct sk_buff *skb,
                          struct mfc_cache *c, int local)
@@ -1944,7 +1960,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
        }
 
        /* Wrong interface: drop packet and (maybe) send PIM assert. */
-       if (mrt->vif_table[vif].dev != dev) {
+       if (rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
                if (rt_is_output_route(skb_rtable(skb))) {
                        /* It is our own packet, looped back.
                         * Very complicated situation...
@@ -1983,8 +1999,10 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
        }
 
 forward:
-       mrt->vif_table[vif].pkt_in++;
-       mrt->vif_table[vif].bytes_in += skb->len;
+       WRITE_ONCE(mrt->vif_table[vif].pkt_in,
+                  mrt->vif_table[vif].pkt_in + 1);
+       WRITE_ONCE(mrt->vif_table[vif].bytes_in,
+                  mrt->vif_table[vif].bytes_in + skb->len);
 
        /* Forward the frame */
        if (c->mfc_origin == htonl(INADDR_ANY) &&
@@ -2140,22 +2158,14 @@ int ip_mr_input(struct sk_buff *skb)
                        skb = skb2;
                }
 
-               read_lock(&mrt_lock);
                vif = ipmr_find_vif(mrt, dev);
-               if (vif >= 0) {
-                       int err2 = ipmr_cache_unresolved(mrt, vif, skb, dev);
-                       read_unlock(&mrt_lock);
-
-                       return err2;
-               }
-               read_unlock(&mrt_lock);
+               if (vif >= 0)
+                       return ipmr_cache_unresolved(mrt, vif, skb, dev);
                kfree_skb(skb);
                return -ENODEV;
        }
 
-       read_lock(&mrt_lock);
        ip_mr_forward(net, mrt, dev, skb, cache, local);
-       read_unlock(&mrt_lock);
 
        if (local)
                return ip_local_deliver(skb);
@@ -2252,18 +2262,15 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
                int vif = -1;
 
                dev = skb->dev;
-               read_lock(&mrt_lock);
                if (dev)
                        vif = ipmr_find_vif(mrt, dev);
                if (vif < 0) {
-                       read_unlock(&mrt_lock);
                        rcu_read_unlock();
                        return -ENODEV;
                }
 
                skb2 = skb_realloc_headroom(skb, sizeof(struct iphdr));
                if (!skb2) {
-                       read_unlock(&mrt_lock);
                        rcu_read_unlock();
                        return -ENOMEM;
                }
@@ -2277,14 +2284,11 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
                iph->daddr = daddr;
                iph->version = 0;
                err = ipmr_cache_unresolved(mrt, vif, skb2, dev);
-               read_unlock(&mrt_lock);
                rcu_read_unlock();
                return err;
        }
 
-       read_lock(&mrt_lock);
        err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
-       read_unlock(&mrt_lock);
        rcu_read_unlock();
        return err;
 }
@@ -2404,7 +2408,7 @@ static size_t igmpmsg_netlink_msgsize(size_t payloadlen)
        return len;
 }
 
-static void igmpmsg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
+static void igmpmsg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt)
 {
        struct net *net = read_pnet(&mrt->net);
        struct nlmsghdr *nlh;
@@ -2744,18 +2748,21 @@ static bool ipmr_fill_table(struct mr_table *mrt, struct sk_buff *skb)
 
 static bool ipmr_fill_vif(struct mr_table *mrt, u32 vifid, struct sk_buff *skb)
 {
+       struct net_device *vif_dev;
        struct nlattr *vif_nest;
        struct vif_device *vif;
 
+       vif = &mrt->vif_table[vifid];
+       vif_dev = rtnl_dereference(vif->dev);
        /* if the VIF doesn't exist just continue */
-       if (!VIF_EXISTS(mrt, vifid))
+       if (!vif_dev)
                return true;
 
-       vif = &mrt->vif_table[vifid];
        vif_nest = nla_nest_start_noflag(skb, IPMRA_VIF);
        if (!vif_nest)
                return false;
-       if (nla_put_u32(skb, IPMRA_VIFA_IFINDEX, vif->dev->ifindex) ||
+
+       if (nla_put_u32(skb, IPMRA_VIFA_IFINDEX, vif_dev->ifindex) ||
            nla_put_u32(skb, IPMRA_VIFA_VIF_ID, vifid) ||
            nla_put_u16(skb, IPMRA_VIFA_FLAGS, vif->flags) ||
            nla_put_u64_64bit(skb, IPMRA_VIFA_BYTES_IN, vif->bytes_in,
@@ -2887,7 +2894,7 @@ out:
  */
 
 static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(mrt_lock)
+       __acquires(RCU)
 {
        struct mr_vif_iter *iter = seq->private;
        struct net *net = seq_file_net(seq);
@@ -2899,14 +2906,14 @@ static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
 
        iter->mrt = mrt;
 
-       read_lock(&mrt_lock);
+       rcu_read_lock();
        return mr_vif_seq_start(seq, pos);
 }
 
 static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
-       __releases(mrt_lock)
+       __releases(RCU)
 {
-       read_unlock(&mrt_lock);
+       rcu_read_unlock();
 }
 
 static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
@@ -2919,9 +2926,11 @@ static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
                         "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags Local    Remote\n");
        } else {
                const struct vif_device *vif = v;
-               const char *name =  vif->dev ?
-                                   vif->dev->name : "none";
+               const struct net_device *vif_dev;
+               const char *name;
 
+               vif_dev = vif_dev_read(vif);
+               name = vif_dev ? vif_dev->name : "none";
                seq_printf(seq,
                           "%2td %-10s %8ld %7ld  %8ld %7ld %05X %08X %08X\n",
                           vif - mrt->vif_table,
@@ -3017,7 +3026,7 @@ static int ipmr_dump(struct net *net, struct notifier_block *nb,
                     struct netlink_ext_ack *extack)
 {
        return mr_dump(net, nb, RTNL_FAMILY_IPMR, ipmr_rules_dump,
-                      ipmr_mr_table_iter, &mrt_lock, extack);
+                      ipmr_mr_table_iter, extack);
 }
 
 static const struct fib_notifier_ops ipmr_notifier_ops_template = {
index aa8738a..271dc03 100644 (file)
@@ -13,7 +13,7 @@ void vif_device_init(struct vif_device *v,
                     unsigned short flags,
                     unsigned short get_iflink_mask)
 {
-       v->dev = NULL;
+       RCU_INIT_POINTER(v->dev, NULL);
        v->bytes_in = 0;
        v->bytes_out = 0;
        v->pkt_in = 0;
@@ -208,6 +208,7 @@ EXPORT_SYMBOL(mr_mfc_seq_next);
 int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
                   struct mr_mfc *c, struct rtmsg *rtm)
 {
+       struct net_device *vif_dev;
        struct rta_mfc_stats mfcs;
        struct nlattr *mp_attr;
        struct rtnexthop *nhp;
@@ -220,10 +221,13 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
                return -ENOENT;
        }
 
-       if (VIF_EXISTS(mrt, c->mfc_parent) &&
-           nla_put_u32(skb, RTA_IIF,
-                       mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
+       rcu_read_lock();
+       vif_dev = rcu_dereference(mrt->vif_table[c->mfc_parent].dev);
+       if (vif_dev && nla_put_u32(skb, RTA_IIF, vif_dev->ifindex) < 0) {
+               rcu_read_unlock();
                return -EMSGSIZE;
+       }
+       rcu_read_unlock();
 
        if (c->mfc_flags & MFC_OFFLOAD)
                rtm->rtm_flags |= RTNH_F_OFFLOAD;
@@ -232,23 +236,27 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
        if (!mp_attr)
                return -EMSGSIZE;
 
+       rcu_read_lock();
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
-               if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
-                       struct vif_device *vif;
+               struct vif_device *vif = &mrt->vif_table[ct];
+
+               vif_dev = rcu_dereference(vif->dev);
+               if (vif_dev && c->mfc_un.res.ttls[ct] < 255) {
 
                        nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
                        if (!nhp) {
+                               rcu_read_unlock();
                                nla_nest_cancel(skb, mp_attr);
                                return -EMSGSIZE;
                        }
 
                        nhp->rtnh_flags = 0;
                        nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
-                       vif = &mrt->vif_table[ct];
-                       nhp->rtnh_ifindex = vif->dev->ifindex;
+                       nhp->rtnh_ifindex = vif_dev->ifindex;
                        nhp->rtnh_len = sizeof(*nhp);
                }
        }
+       rcu_read_unlock();
 
        nla_nest_end(skb, mp_attr);
 
@@ -275,13 +283,14 @@ static bool mr_mfc_uses_dev(const struct mr_table *mrt,
        int ct;
 
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
-               if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
-                       const struct vif_device *vif;
-
-                       vif = &mrt->vif_table[ct];
-                       if (vif->dev == dev)
-                               return true;
-               }
+               const struct net_device *vif_dev;
+               const struct vif_device *vif;
+
+               vif = &mrt->vif_table[ct];
+               vif_dev = rcu_access_pointer(vif->dev);
+               if (vif_dev && c->mfc_un.res.ttls[ct] < 255 &&
+                   vif_dev == dev)
+                       return true;
        }
        return false;
 }
@@ -390,7 +399,6 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
                              struct netlink_ext_ack *extack),
            struct mr_table *(*mr_iter)(struct net *net,
                                        struct mr_table *mrt),
-           rwlock_t *mrt_lock,
            struct netlink_ext_ack *extack)
 {
        struct mr_table *mrt;
@@ -402,22 +410,25 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
 
        for (mrt = mr_iter(net, NULL); mrt; mrt = mr_iter(net, mrt)) {
                struct vif_device *v = &mrt->vif_table[0];
+               struct net_device *vif_dev;
                struct mr_mfc *mfc;
                int vifi;
 
                /* Notifiy on table VIF entries */
-               read_lock(mrt_lock);
+               rcu_read_lock();
                for (vifi = 0; vifi < mrt->maxvif; vifi++, v++) {
-                       if (!v->dev)
+                       vif_dev = rcu_dereference(v->dev);
+                       if (!vif_dev)
                                continue;
 
                        err = mr_call_vif_notifier(nb, family,
-                                                  FIB_EVENT_VIF_ADD,
-                                                  v, vifi, mrt->id, extack);
+                                                  FIB_EVENT_VIF_ADD, v,
+                                                  vif_dev, vifi,
+                                                  mrt->id, extack);
                        if (err)
                                break;
                }
-               read_unlock(mrt_lock);
+               rcu_read_unlock();
 
                if (err)
                        return err;
index 3c6101d..b83c2bd 100644 (file)
@@ -50,7 +50,7 @@
 
 struct ping_table {
        struct hlist_nulls_head hash[PING_HTABLE_SIZE];
-       rwlock_t                lock;
+       spinlock_t              lock;
 };
 
 static struct ping_table ping_table;
@@ -82,7 +82,7 @@ int ping_get_port(struct sock *sk, unsigned short ident)
        struct sock *sk2 = NULL;
 
        isk = inet_sk(sk);
-       write_lock_bh(&ping_table.lock);
+       spin_lock(&ping_table.lock);
        if (ident == 0) {
                u32 i;
                u16 result = ping_port_rover + 1;
@@ -128,14 +128,15 @@ next_port:
        if (sk_unhashed(sk)) {
                pr_debug("was not hashed\n");
                sock_hold(sk);
-               hlist_nulls_add_head(&sk->sk_nulls_node, hlist);
+               sock_set_flag(sk, SOCK_RCU_FREE);
+               hlist_nulls_add_head_rcu(&sk->sk_nulls_node, hlist);
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
        }
-       write_unlock_bh(&ping_table.lock);
+       spin_unlock(&ping_table.lock);
        return 0;
 
 fail:
-       write_unlock_bh(&ping_table.lock);
+       spin_unlock(&ping_table.lock);
        return 1;
 }
 EXPORT_SYMBOL_GPL(ping_get_port);
@@ -153,19 +154,19 @@ void ping_unhash(struct sock *sk)
        struct inet_sock *isk = inet_sk(sk);
 
        pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
-       write_lock_bh(&ping_table.lock);
+       spin_lock(&ping_table.lock);
        if (sk_hashed(sk)) {
-               hlist_nulls_del(&sk->sk_nulls_node);
-               sk_nulls_node_init(&sk->sk_nulls_node);
+               hlist_nulls_del_init_rcu(&sk->sk_nulls_node);
                sock_put(sk);
                isk->inet_num = 0;
                isk->inet_sport = 0;
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
        }
-       write_unlock_bh(&ping_table.lock);
+       spin_unlock(&ping_table.lock);
 }
 EXPORT_SYMBOL_GPL(ping_unhash);
 
+/* Called under rcu_read_lock() */
 static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 {
        struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
@@ -190,8 +191,6 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
                return NULL;
        }
 
-       read_lock_bh(&ping_table.lock);
-
        ping_portaddr_for_each_entry(sk, hnode, hslot) {
                isk = inet_sk(sk);
 
@@ -230,13 +229,11 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
                    sk->sk_bound_dev_if != sdif)
                        continue;
 
-               sock_hold(sk);
                goto exit;
        }
 
        sk = NULL;
 exit:
-       read_unlock_bh(&ping_table.lock);
 
        return sk;
 }
@@ -592,7 +589,7 @@ void ping_err(struct sk_buff *skb, int offset, u32 info)
        sk->sk_err = err;
        sk_error_report(sk);
 out:
-       sock_put(sk);
+       return;
 }
 EXPORT_SYMBOL_GPL(ping_err);
 
@@ -998,7 +995,6 @@ enum skb_drop_reason ping_rcv(struct sk_buff *skb)
                        reason = __ping_queue_rcv_skb(sk, skb2);
                else
                        reason = SKB_DROP_REASON_NOMEM;
-               sock_put(sk);
        }
 
        if (reason)
@@ -1084,13 +1080,13 @@ static struct sock *ping_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family)
-       __acquires(ping_table.lock)
+       __acquires(RCU)
 {
        struct ping_iter_state *state = seq->private;
        state->bucket = 0;
        state->family = family;
 
-       read_lock_bh(&ping_table.lock);
+       rcu_read_lock();
 
        return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
 }
@@ -1116,9 +1112,9 @@ void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 EXPORT_SYMBOL_GPL(ping_seq_next);
 
 void ping_seq_stop(struct seq_file *seq, void *v)
-       __releases(ping_table.lock)
+       __releases(RCU)
 {
-       read_unlock_bh(&ping_table.lock);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ping_seq_stop);
 
@@ -1202,5 +1198,5 @@ void __init ping_init(void)
 
        for (i = 0; i < PING_HTABLE_SIZE; i++)
                INIT_HLIST_NULLS_HEAD(&ping_table.hash[i], i);
-       rwlock_init(&ping_table.lock);
+       spin_lock_init(&ping_table.lock);
 }
index bbd7178..006c1f0 100644 (file)
@@ -85,21 +85,20 @@ struct raw_frag_vec {
        int hlen;
 };
 
-struct raw_hashinfo raw_v4_hashinfo = {
-       .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
-};
+struct raw_hashinfo raw_v4_hashinfo;
 EXPORT_SYMBOL_GPL(raw_v4_hashinfo);
 
 int raw_hash_sk(struct sock *sk)
 {
        struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
-       struct hlist_head *head;
+       struct hlist_nulls_head *hlist;
 
-       head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)];
+       hlist = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)];
 
-       write_lock_bh(&h->lock);
-       sk_add_node(sk, head);
-       write_unlock_bh(&h->lock);
+       spin_lock(&h->lock);
+       __sk_nulls_add_node_rcu(sk, hlist);
+       sock_set_flag(sk, SOCK_RCU_FREE);
+       spin_unlock(&h->lock);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 
        return 0;
@@ -110,31 +109,26 @@ void raw_unhash_sk(struct sock *sk)
 {
        struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
 
-       write_lock_bh(&h->lock);
-       if (sk_del_node_init(sk))
+       spin_lock(&h->lock);
+       if (__sk_nulls_del_node_init_rcu(sk))
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
-       write_unlock_bh(&h->lock);
+       spin_unlock(&h->lock);
 }
 EXPORT_SYMBOL_GPL(raw_unhash_sk);
 
-struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
-                            unsigned short num, __be32 raddr, __be32 laddr,
-                            int dif, int sdif)
+bool raw_v4_match(struct net *net, struct sock *sk, unsigned short num,
+                 __be32 raddr, __be32 laddr, int dif, int sdif)
 {
-       sk_for_each_from(sk) {
-               struct inet_sock *inet = inet_sk(sk);
-
-               if (net_eq(sock_net(sk), net) && inet->inet_num == num  &&
-                   !(inet->inet_daddr && inet->inet_daddr != raddr)    &&
-                   !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
-                   raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
-                       goto found; /* gotcha */
-       }
-       sk = NULL;
-found:
-       return sk;
+       struct inet_sock *inet = inet_sk(sk);
+
+       if (net_eq(sock_net(sk), net) && inet->inet_num == num  &&
+           !(inet->inet_daddr && inet->inet_daddr != raddr)    &&
+           !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
+           raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif))
+               return true;
+       return false;
 }
-EXPORT_SYMBOL_GPL(__raw_v4_lookup);
+EXPORT_SYMBOL_GPL(raw_v4_match);
 
 /*
  *     0 - deliver
@@ -168,23 +162,20 @@ static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
  */
 static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
 {
+       struct net *net = dev_net(skb->dev);
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
        int sdif = inet_sdif(skb);
        int dif = inet_iif(skb);
-       struct sock *sk;
-       struct hlist_head *head;
        int delivered = 0;
-       struct net *net;
-
-       read_lock(&raw_v4_hashinfo.lock);
-       head = &raw_v4_hashinfo.ht[hash];
-       if (hlist_empty(head))
-               goto out;
-
-       net = dev_net(skb->dev);
-       sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
-                            iph->saddr, iph->daddr, dif, sdif);
+       struct sock *sk;
 
-       while (sk) {
+       hlist = &raw_v4_hashinfo.ht[hash];
+       rcu_read_lock();
+       sk_nulls_for_each(sk, hnode, hlist) {
+               if (!raw_v4_match(net, sk, iph->protocol,
+                                 iph->saddr, iph->daddr, dif, sdif))
+                       continue;
                delivered = 1;
                if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) &&
                    ip_mc_sf_allow(sk, iph->daddr, iph->saddr,
@@ -195,31 +186,16 @@ static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash)
                        if (clone)
                                raw_rcv(sk, clone);
                }
-               sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol,
-                                    iph->saddr, iph->daddr,
-                                    dif, sdif);
        }
-out:
-       read_unlock(&raw_v4_hashinfo.lock);
+       rcu_read_unlock();
        return delivered;
 }
 
 int raw_local_deliver(struct sk_buff *skb, int protocol)
 {
-       int hash;
-       struct sock *raw_sk;
-
-       hash = protocol & (RAW_HTABLE_SIZE - 1);
-       raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
-
-       /* If there maybe a raw socket we must check - if not we
-        * don't care less
-        */
-       if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash))
-               raw_sk = NULL;
-
-       return raw_sk != NULL;
+       int hash = protocol & (RAW_HTABLE_SIZE - 1);
 
+       return raw_v4_input(skb, ip_hdr(skb), hash);
 }
 
 static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
@@ -286,31 +262,27 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
 
 void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
 {
-       int hash;
-       struct sock *raw_sk;
+       struct net *net = dev_net(skb->dev);
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
+       int dif = skb->dev->ifindex;
+       int sdif = inet_sdif(skb);
        const struct iphdr *iph;
-       struct net *net;
+       struct sock *sk;
+       int hash;
 
        hash = protocol & (RAW_HTABLE_SIZE - 1);
+       hlist = &raw_v4_hashinfo.ht[hash];
 
-       read_lock(&raw_v4_hashinfo.lock);
-       raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
-       if (raw_sk) {
-               int dif = skb->dev->ifindex;
-               int sdif = inet_sdif(skb);
-
+       rcu_read_lock();
+       sk_nulls_for_each(sk, hnode, hlist) {
                iph = (const struct iphdr *)skb->data;
-               net = dev_net(skb->dev);
-
-               while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol,
-                                               iph->daddr, iph->saddr,
-                                               dif, sdif)) != NULL) {
-                       raw_err(raw_sk, skb, info);
-                       raw_sk = sk_next(raw_sk);
-                       iph = (const struct iphdr *)skb->data;
-               }
+               if (!raw_v4_match(net, sk, iph->protocol,
+                                 iph->daddr, iph->saddr, dif, sdif))
+                       continue;
+               raw_err(sk, skb, info);
        }
-       read_unlock(&raw_v4_hashinfo.lock);
+       rcu_read_unlock();
 }
 
 static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
@@ -971,44 +943,41 @@ struct proto raw_prot = {
 };
 
 #ifdef CONFIG_PROC_FS
-static struct sock *raw_get_first(struct seq_file *seq)
+static struct sock *raw_get_first(struct seq_file *seq, int bucket)
 {
-       struct sock *sk;
        struct raw_hashinfo *h = pde_data(file_inode(seq->file));
        struct raw_iter_state *state = raw_seq_private(seq);
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
+       struct sock *sk;
 
-       for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE;
+       for (state->bucket = bucket; state->bucket < RAW_HTABLE_SIZE;
                        ++state->bucket) {
-               sk_for_each(sk, &h->ht[state->bucket])
+               hlist = &h->ht[state->bucket];
+               sk_nulls_for_each(sk, hnode, hlist) {
                        if (sock_net(sk) == seq_file_net(seq))
-                               goto found;
+                               return sk;
+               }
        }
-       sk = NULL;
-found:
-       return sk;
+       return NULL;
 }
 
 static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
 {
-       struct raw_hashinfo *h = pde_data(file_inode(seq->file));
        struct raw_iter_state *state = raw_seq_private(seq);
 
        do {
-               sk = sk_next(sk);
-try_again:
-               ;
+               sk = sk_nulls_next(sk);
        } while (sk && sock_net(sk) != seq_file_net(seq));
 
-       if (!sk && ++state->bucket < RAW_HTABLE_SIZE) {
-               sk = sk_head(&h->ht[state->bucket]);
-               goto try_again;
-       }
+       if (!sk)
+               return raw_get_first(seq, state->bucket + 1);
        return sk;
 }
 
 static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos)
 {
-       struct sock *sk = raw_get_first(seq);
+       struct sock *sk = raw_get_first(seq, 0);
 
        if (sk)
                while (pos && (sk = raw_get_next(seq, sk)) != NULL)
@@ -1017,11 +986,9 @@ static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 void *raw_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(&h->lock)
+       __acquires(RCU)
 {
-       struct raw_hashinfo *h = pde_data(file_inode(seq->file));
-
-       read_lock(&h->lock);
+       rcu_read_lock();
        return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 }
 EXPORT_SYMBOL_GPL(raw_seq_start);
@@ -1031,7 +998,7 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct sock *sk;
 
        if (v == SEQ_START_TOKEN)
-               sk = raw_get_first(seq);
+               sk = raw_get_first(seq, 0);
        else
                sk = raw_get_next(seq, v);
        ++*pos;
@@ -1040,11 +1007,9 @@ void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 EXPORT_SYMBOL_GPL(raw_seq_next);
 
 void raw_seq_stop(struct seq_file *seq, void *v)
-       __releases(&h->lock)
+       __releases(RCU)
 {
-       struct raw_hashinfo *h = pde_data(file_inode(seq->file));
-
-       read_unlock(&h->lock);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(raw_seq_stop);
 
@@ -1106,6 +1071,7 @@ static __net_initdata struct pernet_operations raw_net_ops = {
 
 int __init raw_proc_init(void)
 {
+
        return register_pernet_subsys(&raw_net_ops);
 }
 
index ccacbde..9993218 100644 (file)
@@ -34,57 +34,57 @@ raw_get_hashinfo(const struct inet_diag_req_v2 *r)
  * use helper to figure it out.
  */
 
-static struct sock *raw_lookup(struct net *net, struct sock *from,
-                              const struct inet_diag_req_v2 *req)
+static bool raw_lookup(struct net *net, struct sock *sk,
+                      const struct inet_diag_req_v2 *req)
 {
        struct inet_diag_req_raw *r = (void *)req;
-       struct sock *sk = NULL;
 
        if (r->sdiag_family == AF_INET)
-               sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol,
-                                    r->id.idiag_dst[0],
-                                    r->id.idiag_src[0],
-                                    r->id.idiag_if, 0);
+               return raw_v4_match(net, sk, r->sdiag_raw_protocol,
+                                   r->id.idiag_dst[0],
+                                   r->id.idiag_src[0],
+                                   r->id.idiag_if, 0);
 #if IS_ENABLED(CONFIG_IPV6)
        else
-               sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol,
-                                    (const struct in6_addr *)r->id.idiag_src,
-                                    (const struct in6_addr *)r->id.idiag_dst,
-                                    r->id.idiag_if, 0);
+               return raw_v6_match(net, sk, r->sdiag_raw_protocol,
+                                   (const struct in6_addr *)r->id.idiag_src,
+                                   (const struct in6_addr *)r->id.idiag_dst,
+                                   r->id.idiag_if, 0);
 #endif
-       return sk;
+       return false;
 }
 
 static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
 {
        struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
-       struct sock *sk = NULL, *s;
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
+       struct sock *sk;
        int slot;
 
        if (IS_ERR(hashinfo))
                return ERR_CAST(hashinfo);
 
-       read_lock(&hashinfo->lock);
+       rcu_read_lock();
        for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
-               sk_for_each(s, &hashinfo->ht[slot]) {
-                       sk = raw_lookup(net, s, r);
-                       if (sk) {
+               hlist = &hashinfo->ht[slot];
+               sk_nulls_for_each(sk, hnode, hlist) {
+                       if (raw_lookup(net, sk, r)) {
                                /*
                                 * Grab it and keep until we fill
-                                * diag meaage to be reported, so
+                                * diag message to be reported, so
                                 * caller should call sock_put then.
-                                * We can do that because we're keeping
-                                * hashinfo->lock here.
                                 */
-                               sock_hold(sk);
-                               goto out_unlock;
+                               if (refcount_inc_not_zero(&sk->sk_refcnt))
+                                       goto out_unlock;
                        }
                }
        }
+       sk = ERR_PTR(-ENOENT);
 out_unlock:
-       read_unlock(&hashinfo->lock);
+       rcu_read_unlock();
 
-       return sk ? sk : ERR_PTR(-ENOENT);
+       return sk;
 }
 
 static int raw_diag_dump_one(struct netlink_callback *cb,
@@ -142,6 +142,8 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
        struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
        struct net *net = sock_net(skb->sk);
        struct inet_diag_dump_data *cb_data;
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
        int num, s_num, slot, s_slot;
        struct sock *sk = NULL;
        struct nlattr *bc;
@@ -154,11 +156,12 @@ static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
        s_slot = cb->args[0];
        num = s_num = cb->args[1];
 
-       read_lock(&hashinfo->lock);
+       rcu_read_lock();
        for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) {
                num = 0;
 
-               sk_for_each(sk, &hashinfo->ht[slot]) {
+               hlist = &hashinfo->ht[slot];
+               sk_nulls_for_each(sk, hnode, hlist) {
                        struct inet_sock *inet = inet_sk(sk);
 
                        if (!net_eq(sock_net(sk), net))
@@ -181,7 +184,7 @@ next:
        }
 
 out_unlock:
-       read_unlock(&hashinfo->lock);
+       rcu_read_unlock();
 
        cb->args[0] = slot;
        cb->args[1] = num;
index 356f535..2d16bcc 100644 (file)
@@ -1550,9 +1550,8 @@ void rt_flush_dev(struct net_device *dev)
                        if (rt->dst.dev != dev)
                                continue;
                        rt->dst.dev = blackhole_netdev;
-                       dev_replace_track(dev, blackhole_netdev,
-                                         &rt->dst.dev_tracker,
-                                         GFP_ATOMIC);
+                       netdev_ref_replace(dev, blackhole_netdev,
+                                          &rt->dst.dev_tracker, GFP_ATOMIC);
                        list_move(&rt->rt_uncached, &ul->quarantine);
                }
                spin_unlock_bh(&ul->lock);
@@ -2851,7 +2850,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                new->output = dst_discard_out;
 
                new->dev = net->loopback_dev;
-               dev_hold_track(new->dev, &new->dev_tracker, GFP_ATOMIC);
+               netdev_hold(new->dev, &new->dev_tracker, GFP_ATOMIC);
 
                rt->rt_is_input = ort->rt_is_input;
                rt->rt_iif = ort->rt_iif;
index 028513d..d2ca56a 100644 (file)
@@ -294,6 +294,8 @@ EXPORT_SYMBOL(sysctl_tcp_mem);
 
 atomic_long_t tcp_memory_allocated ____cacheline_aligned_in_smp;       /* Current allocated memory. */
 EXPORT_SYMBOL(tcp_memory_allocated);
+DEFINE_PER_CPU(int, tcp_memory_per_cpu_fw_alloc);
+EXPORT_PER_CPU_SYMBOL_GPL(tcp_memory_per_cpu_fw_alloc);
 
 #if IS_ENABLED(CONFIG_SMC)
 DEFINE_STATIC_KEY_FALSE(tcp_have_smc);
@@ -856,9 +858,6 @@ struct sk_buff *tcp_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp,
 {
        struct sk_buff *skb;
 
-       if (unlikely(tcp_under_memory_pressure(sk)))
-               sk_mem_reclaim_partial(sk);
-
        skb = alloc_skb_fclone(size + MAX_TCP_HEADER, gfp);
        if (likely(skb)) {
                bool mem_scheduled;
@@ -952,6 +951,24 @@ static int tcp_downgrade_zcopy_pure(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
+
+static int tcp_wmem_schedule(struct sock *sk, int copy)
+{
+       int left;
+
+       if (likely(sk_wmem_schedule(sk, copy)))
+               return copy;
+
+       /* We could be in trouble if we have nothing queued.
+        * Use whatever is left in sk->sk_forward_alloc and tcp_wmem[0]
+        * to guarantee some progress.
+        */
+       left = sock_net(sk)->ipv4.sysctl_tcp_wmem[0] - sk->sk_wmem_queued;
+       if (left > 0)
+               sk_forced_mem_schedule(sk, min(left, copy));
+       return min(copy, sk->sk_forward_alloc);
+}
+
 static struct sk_buff *tcp_build_frag(struct sock *sk, int size_goal, int flags,
                                      struct page *page, int offset, size_t *size)
 {
@@ -987,7 +1004,11 @@ new_segment:
                tcp_mark_push(tp, skb);
                goto new_segment;
        }
-       if (tcp_downgrade_zcopy_pure(sk, skb) || !sk_wmem_schedule(sk, copy))
+       if (tcp_downgrade_zcopy_pure(sk, skb))
+               return NULL;
+
+       copy = tcp_wmem_schedule(sk, copy);
+       if (!copy)
                return NULL;
 
        if (can_coalesce) {
@@ -1335,8 +1356,11 @@ new_segment:
 
                        copy = min_t(int, copy, pfrag->size - pfrag->offset);
 
-                       if (tcp_downgrade_zcopy_pure(sk, skb) ||
-                           !sk_wmem_schedule(sk, copy))
+                       if (tcp_downgrade_zcopy_pure(sk, skb))
+                               goto wait_for_space;
+
+                       copy = tcp_wmem_schedule(sk, copy);
+                       if (!copy)
                                goto wait_for_space;
 
                        err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb,
@@ -1363,7 +1387,8 @@ new_segment:
                                skb_shinfo(skb)->flags |= SKBFL_PURE_ZEROCOPY;
 
                        if (!skb_zcopy_pure(skb)) {
-                               if (!sk_wmem_schedule(sk, copy))
+                               copy = tcp_wmem_schedule(sk, copy);
+                               if (!copy)
                                        goto wait_for_space;
                        }
 
@@ -2762,8 +2787,6 @@ void __tcp_close(struct sock *sk, long timeout)
                __kfree_skb(skb);
        }
 
-       sk_mem_reclaim(sk);
-
        /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */
        if (sk->sk_state == TCP_CLOSE)
                goto adjudge_to_death;
@@ -2871,7 +2894,6 @@ adjudge_to_death:
                }
        }
        if (sk->sk_state != TCP_CLOSE) {
-               sk_mem_reclaim(sk);
                if (tcp_check_oom(sk, 0)) {
                        tcp_set_state(sk, TCP_CLOSE);
                        tcp_send_active_reset(sk, GFP_ATOMIC);
@@ -2949,7 +2971,6 @@ void tcp_write_queue_purge(struct sock *sk)
        }
        tcp_rtx_queue_purge(sk);
        INIT_LIST_HEAD(&tcp_sk(sk)->tsorted_sent_queue);
-       sk_mem_reclaim(sk);
        tcp_clear_all_retrans_hints(tcp_sk(sk));
        tcp_sk(sk)->packets_out = 0;
        inet_csk(sk)->icsk_backoff = 0;
@@ -4510,16 +4531,24 @@ EXPORT_SYMBOL_GPL(tcp_done);
 
 int tcp_abort(struct sock *sk, int err)
 {
-       if (!sk_fullsock(sk)) {
-               if (sk->sk_state == TCP_NEW_SYN_RECV) {
-                       struct request_sock *req = inet_reqsk(sk);
+       int state = inet_sk_state_load(sk);
 
-                       local_bh_disable();
-                       inet_csk_reqsk_queue_drop(req->rsk_listener, req);
-                       local_bh_enable();
-                       return 0;
-               }
-               return -EOPNOTSUPP;
+       if (state == TCP_NEW_SYN_RECV) {
+               struct request_sock *req = inet_reqsk(sk);
+
+               local_bh_disable();
+               inet_csk_reqsk_queue_drop(req->rsk_listener, req);
+               local_bh_enable();
+               return 0;
+       }
+       if (state == TCP_TIME_WAIT) {
+               struct inet_timewait_sock *tw = inet_twsk(sk);
+
+               refcount_inc(&tw->tw_refcnt);
+               local_bh_disable();
+               inet_twsk_deschedule_put(tw);
+               local_bh_enable();
+               return 0;
        }
 
        /* Don't race with userspace socket closes such as tcp_close. */
@@ -4651,11 +4680,11 @@ void __init tcp_init(void)
        max_wshare = min(4UL*1024*1024, limit);
        max_rshare = min(6UL*1024*1024, limit);
 
-       init_net.ipv4.sysctl_tcp_wmem[0] = SK_MEM_QUANTUM;
+       init_net.ipv4.sysctl_tcp_wmem[0] = PAGE_SIZE;
        init_net.ipv4.sysctl_tcp_wmem[1] = 16*1024;
        init_net.ipv4.sysctl_tcp_wmem[2] = max(64*1024, max_wshare);
 
-       init_net.ipv4.sysctl_tcp_rmem[0] = SK_MEM_QUANTUM;
+       init_net.ipv4.sysctl_tcp_rmem[0] = PAGE_SIZE;
        init_net.ipv4.sysctl_tcp_rmem[1] = 131072;
        init_net.ipv4.sysctl_tcp_rmem[2] = max(131072, max_rshare);
 
index 0d3f68b..a1626af 100644 (file)
@@ -540,6 +540,7 @@ static void tcp_bpf_rebuild_protos(struct proto prot[TCP_BPF_NUM_CFGS],
                                   struct proto *base)
 {
        prot[TCP_BPF_BASE]                      = *base;
+       prot[TCP_BPF_BASE].destroy              = sock_map_destroy;
        prot[TCP_BPF_BASE].close                = sock_map_close;
        prot[TCP_BPF_BASE].recvmsg              = tcp_bpf_recvmsg;
        prot[TCP_BPF_BASE].sock_is_readable     = sk_msg_is_readable;
index 2e2a9ec..80cb112 100644 (file)
@@ -805,7 +805,6 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
                         * restart window, so that we send ACKs quickly.
                         */
                        tcp_incr_quickack(sk, TCP_MAX_QUICKACKS);
-                       sk_mem_reclaim(sk);
                }
        }
        icsk->icsk_ack.lrcvtime = now;
@@ -3967,7 +3966,7 @@ static bool smc_parse_options(const struct tcphdr *th,
 /* Try to parse the MSS option from the TCP header. Return 0 on failure, clamped
  * value on success.
  */
-static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
+u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
 {
        const unsigned char *ptr = (const unsigned char *)(th + 1);
        int length = (th->doff * 4) - sizeof(struct tcphdr);
@@ -4006,6 +4005,7 @@ static u16 tcp_parse_mss_option(const struct tcphdr *th, u16 user_mss)
        }
        return mss;
 }
+EXPORT_SYMBOL_GPL(tcp_parse_mss_option);
 
 /* Look for tcp options. Normally only called on SYN and SYNACK packets.
  * But, this can also be called on packets in the established flow when
@@ -4390,7 +4390,6 @@ void tcp_fin(struct sock *sk)
        skb_rbtree_purge(&tp->out_of_order_queue);
        if (tcp_is_sack(tp))
                tcp_sack_reset(&tp->rx_opt);
-       sk_mem_reclaim(sk);
 
        if (!sock_flag(sk, SOCK_DEAD)) {
                sk->sk_state_change(sk);
@@ -5287,7 +5286,7 @@ new_range:
                    before(TCP_SKB_CB(skb)->end_seq, start)) {
                        /* Do not attempt collapsing tiny skbs */
                        if (range_truesize != head->truesize ||
-                           end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) {
+                           end - start >= SKB_WITH_OVERHEAD(PAGE_SIZE)) {
                                tcp_collapse(sk, NULL, &tp->out_of_order_queue,
                                             head, skb, start, end);
                        } else {
@@ -5336,7 +5335,6 @@ static bool tcp_prune_ofo_queue(struct sock *sk)
                tcp_drop_reason(sk, rb_to_skb(node),
                                SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE);
                if (!prev || goal <= 0) {
-                       sk_mem_reclaim(sk);
                        if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
                            !tcp_under_memory_pressure(sk))
                                break;
@@ -5383,7 +5381,6 @@ static int tcp_prune_queue(struct sock *sk)
                             skb_peek(&sk->sk_receive_queue),
                             NULL,
                             tp->copied_seq, tp->rcv_nxt);
-       sk_mem_reclaim(sk);
 
        if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
                return 0;
index da5a3c4..68d0d8a 100644 (file)
@@ -3049,7 +3049,10 @@ struct proto tcp_prot = {
        .stream_memory_free     = tcp_stream_memory_free,
        .sockets_allocated      = &tcp_sockets_allocated,
        .orphan_count           = &tcp_orphan_count,
+
        .memory_allocated       = &tcp_memory_allocated,
+       .per_cpu_fw_alloc       = &tcp_memory_per_cpu_fw_alloc,
+
        .memory_pressure        = &tcp_memory_pressure,
        .sysctl_mem             = sysctl_tcp_mem,
        .sysctl_wmem_offset     = offsetof(struct net, ipv4.sysctl_tcp_wmem),
index 1c05443..18c913a 100644 (file)
@@ -3362,12 +3362,13 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
  */
 void sk_forced_mem_schedule(struct sock *sk, int size)
 {
-       int amt;
+       int delta, amt;
 
-       if (size <= sk->sk_forward_alloc)
+       delta = size - sk->sk_forward_alloc;
+       if (delta <= 0)
                return;
-       amt = sk_mem_pages(size);
-       sk->sk_forward_alloc += amt * SK_MEM_QUANTUM;
+       amt = sk_mem_pages(delta);
+       sk->sk_forward_alloc += amt << PAGE_SHIFT;
        sk_memory_allocated_add(sk, amt);
 
        if (mem_cgroup_sockets_enabled && sk->sk_memcg)
index 20cf4a9..2208755 100644 (file)
@@ -290,15 +290,13 @@ void tcp_delack_timer_handler(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
 
-       sk_mem_reclaim_partial(sk);
-
        if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
            !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
-               goto out;
+               return;
 
        if (time_after(icsk->icsk_ack.timeout, jiffies)) {
                sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout);
-               goto out;
+               return;
        }
        icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER;
 
@@ -317,10 +315,6 @@ void tcp_delack_timer_handler(struct sock *sk)
                tcp_send_ack(sk);
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS);
        }
-
-out:
-       if (tcp_under_memory_pressure(sk))
-               sk_mem_reclaim(sk);
 }
 
 
@@ -600,11 +594,11 @@ void tcp_write_timer_handler(struct sock *sk)
 
        if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
            !icsk->icsk_pending)
-               goto out;
+               return;
 
        if (time_after(icsk->icsk_timeout, jiffies)) {
                sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout);
-               goto out;
+               return;
        }
 
        tcp_mstamp_refresh(tcp_sk(sk));
@@ -626,9 +620,6 @@ void tcp_write_timer_handler(struct sock *sk)
                tcp_probe_timer(sk);
                break;
        }
-
-out:
-       sk_mem_reclaim(sk);
 }
 
 static void tcp_write_timer(struct timer_list *t)
@@ -743,8 +734,6 @@ static void tcp_keepalive_timer (struct timer_list *t)
                elapsed = keepalive_time_when(tp) - elapsed;
        }
 
-       sk_mem_reclaim(sk);
-
 resched:
        inet_csk_reset_keepalive_timer (sk, elapsed);
        goto out;
index aa9f2ec..6172b47 100644 (file)
@@ -125,6 +125,8 @@ EXPORT_SYMBOL(sysctl_udp_mem);
 
 atomic_long_t udp_memory_allocated ____cacheline_aligned_in_smp;
 EXPORT_SYMBOL(udp_memory_allocated);
+DEFINE_PER_CPU(int, udp_memory_per_cpu_fw_alloc);
+EXPORT_PER_CPU_SYMBOL_GPL(udp_memory_per_cpu_fw_alloc);
 
 #define MAX_UDP_PORTS 65536
 #define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN)
@@ -1461,11 +1463,11 @@ static void udp_rmem_release(struct sock *sk, int size, int partial,
 
 
        sk->sk_forward_alloc += size;
-       amt = (sk->sk_forward_alloc - partial) & ~(SK_MEM_QUANTUM - 1);
+       amt = (sk->sk_forward_alloc - partial) & ~(PAGE_SIZE - 1);
        sk->sk_forward_alloc -= amt;
 
        if (amt)
-               __sk_mem_reduce_allocated(sk, amt >> SK_MEM_QUANTUM_SHIFT);
+               __sk_mem_reduce_allocated(sk, amt >> PAGE_SHIFT);
 
        atomic_sub(size, &sk->sk_rmem_alloc);
 
@@ -1558,7 +1560,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
        spin_lock(&list->lock);
        if (size >= sk->sk_forward_alloc) {
                amt = sk_mem_pages(size);
-               delta = amt << SK_MEM_QUANTUM_SHIFT;
+               delta = amt << PAGE_SHIFT;
                if (!__sk_mem_raise_allocated(sk, delta, amt, SK_MEM_RECV)) {
                        err = -ENOBUFS;
                        spin_unlock(&list->lock);
@@ -2946,6 +2948,8 @@ struct proto udp_prot = {
        .psock_update_sk_prot   = udp_bpf_update_proto,
 #endif
        .memory_allocated       = &udp_memory_allocated,
+       .per_cpu_fw_alloc       = &udp_memory_per_cpu_fw_alloc,
+
        .sysctl_mem             = sysctl_udp_mem,
        .sysctl_wmem_offset     = offsetof(struct net, ipv4.sysctl_udp_wmem_min),
        .sysctl_rmem_offset     = offsetof(struct net, ipv4.sysctl_udp_rmem_min),
@@ -3263,8 +3267,8 @@ EXPORT_SYMBOL(udp_flow_hashrnd);
 
 static void __udp_sysctl_init(struct net *net)
 {
-       net->ipv4.sysctl_udp_rmem_min = SK_MEM_QUANTUM;
-       net->ipv4.sysctl_udp_wmem_min = SK_MEM_QUANTUM;
+       net->ipv4.sysctl_udp_rmem_min = PAGE_SIZE;
+       net->ipv4.sysctl_udp_wmem_min = PAGE_SIZE;
 
 #ifdef CONFIG_NET_L3_MASTER_DEV
        net->ipv4.sysctl_udp_l3mdev_accept = 0;
index cd1cd68..6e08a76 100644 (file)
@@ -51,7 +51,10 @@ struct proto         udplite_prot = {
        .unhash            = udp_lib_unhash,
        .rehash            = udp_v4_rehash,
        .get_port          = udp_v4_get_port,
+
        .memory_allocated  = &udp_memory_allocated,
+       .per_cpu_fw_alloc  = &udp_memory_per_cpu_fw_alloc,
+
        .sysctl_mem        = sysctl_udp_mem,
        .obj_size          = sizeof(struct udp_sock),
        .h.udp_table       = &udplite_table,
index 6fde0b1..3d0dfa6 100644 (file)
@@ -75,7 +75,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        xdst->u.rt.rt_iif = fl4->flowi4_iif;
 
        xdst->u.dst.dev = dev;
-       dev_hold_track(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
 
        /* Sheit... I remember I did this right. Apparently,
         * it was magically lost, so this code needs audit */
index 49cc658..88becb0 100644 (file)
@@ -398,13 +398,13 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        if (ndev->cnf.forwarding)
                dev_disable_lro(dev);
        /* We refer to the device */
-       dev_hold_track(dev, &ndev->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &ndev->dev_tracker, GFP_KERNEL);
 
        if (snmp6_alloc_dev(ndev) < 0) {
                netdev_dbg(dev, "%s: cannot allocate memory for statistics\n",
                           __func__);
                neigh_parms_release(&nd_tbl, ndev->nd_parms);
-               dev_put_track(dev, &ndev->dev_tracker);
+               netdev_put(dev, &ndev->dev_tracker);
                kfree(ndev);
                return ERR_PTR(err);
        }
@@ -4520,6 +4520,39 @@ restart:
                        /* We try to batch several events at once. */
                        age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
 
+                       if ((ifp->flags&IFA_F_TEMPORARY) &&
+                           !(ifp->flags&IFA_F_TENTATIVE) &&
+                           ifp->prefered_lft != INFINITY_LIFE_TIME &&
+                           !ifp->regen_count && ifp->ifpub) {
+                               /* This is a non-regenerated temporary addr. */
+
+                               unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
+                                       ifp->idev->cnf.dad_transmits *
+                                       max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), HZ/100) / HZ;
+
+                               if (age + regen_advance >= ifp->prefered_lft) {
+                                       struct inet6_ifaddr *ifpub = ifp->ifpub;
+                                       if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+                                               next = ifp->tstamp + ifp->prefered_lft * HZ;
+
+                                       ifp->regen_count++;
+                                       in6_ifa_hold(ifp);
+                                       in6_ifa_hold(ifpub);
+                                       spin_unlock(&ifp->lock);
+
+                                       spin_lock(&ifpub->lock);
+                                       ifpub->regen_count = 0;
+                                       spin_unlock(&ifpub->lock);
+                                       rcu_read_unlock_bh();
+                                       ipv6_create_tempaddr(ifpub, true);
+                                       in6_ifa_put(ifpub);
+                                       in6_ifa_put(ifp);
+                                       rcu_read_lock_bh();
+                                       goto restart;
+                               } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
+                                       next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
+                       }
+
                        if (ifp->valid_lft != INFINITY_LIFE_TIME &&
                            age >= ifp->valid_lft) {
                                spin_unlock(&ifp->lock);
@@ -4553,35 +4586,6 @@ restart:
                                        in6_ifa_put(ifp);
                                        goto restart;
                                }
-                       } else if ((ifp->flags&IFA_F_TEMPORARY) &&
-                                  !(ifp->flags&IFA_F_TENTATIVE)) {
-                               unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
-                                       ifp->idev->cnf.dad_transmits *
-                                       max(NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME), HZ/100) / HZ;
-
-                               if (age >= ifp->prefered_lft - regen_advance) {
-                                       struct inet6_ifaddr *ifpub = ifp->ifpub;
-                                       if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
-                                               next = ifp->tstamp + ifp->prefered_lft * HZ;
-                                       if (!ifp->regen_count && ifpub) {
-                                               ifp->regen_count++;
-                                               in6_ifa_hold(ifp);
-                                               in6_ifa_hold(ifpub);
-                                               spin_unlock(&ifp->lock);
-
-                                               spin_lock(&ifpub->lock);
-                                               ifpub->regen_count = 0;
-                                               spin_unlock(&ifpub->lock);
-                                               rcu_read_unlock_bh();
-                                               ipv6_create_tempaddr(ifpub, true);
-                                               in6_ifa_put(ifpub);
-                                               in6_ifa_put(ifp);
-                                               rcu_read_lock_bh();
-                                               goto restart;
-                                       }
-                               } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
-                                       next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
-                               spin_unlock(&ifp->lock);
                        } else {
                                /* ifp->prefered_lft <= ifp->valid_lft */
                                if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
index 881d147..507a835 100644 (file)
@@ -263,7 +263,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
 #ifdef NET_REFCNT_DEBUG
        pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL");
 #endif
-       dev_put_track(dev, &idev->dev_tracker);
+       netdev_put(dev, &idev->dev_tracker);
        if (!idev->dead) {
                pr_warn("Freeing alive inet6 device %p\n", idev);
                return;
index 70564dd..658823e 100644 (file)
@@ -63,6 +63,7 @@
 #include <net/compat.h>
 #include <net/xfrm.h>
 #include <net/ioam6.h>
+#include <net/rawv6.h>
 
 #include <linux/uaccess.h>
 #include <linux/mroute6.h>
@@ -1073,6 +1074,8 @@ static int __init inet6_init(void)
                goto out;
        }
 
+       raw_hashinfo_init(&raw_v6_hashinfo);
+
        err = proto_register(&tcpv6_prot, 1);
        if (err)
                goto out;
index a9051df..1bd10ae 100644 (file)
@@ -398,7 +398,7 @@ static void ip6erspan_tunnel_uninit(struct net_device *dev)
        ip6erspan_tunnel_unlink_md(ign, t);
        ip6gre_tunnel_unlink(ign, t);
        dst_cache_reset(&t->dst_cache);
-       dev_put_track(dev, &t->dev_tracker);
+       netdev_put(dev, &t->dev_tracker);
 }
 
 static void ip6gre_tunnel_uninit(struct net_device *dev)
@@ -411,7 +411,7 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
        if (ign->fb_tunnel_dev == dev)
                WRITE_ONCE(ign->fb_tunnel_dev, NULL);
        dst_cache_reset(&t->dst_cache);
-       dev_put_track(dev, &t->dev_tracker);
+       netdev_put(dev, &t->dev_tracker);
 }
 
 
@@ -1500,7 +1500,7 @@ static int ip6gre_tunnel_init_common(struct net_device *dev)
        }
        ip6gre_tnl_init_features(dev);
 
-       dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL);
        return 0;
 
 cleanup_dst_cache_init:
@@ -1892,7 +1892,7 @@ static int ip6erspan_tap_init(struct net_device *dev)
        dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
        ip6erspan_tnl_link_config(tunnel, 1);
 
-       dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL);
        return 0;
 
 cleanup_dst_cache_init:
index 19325b7..c7279f2 100644 (file)
@@ -381,7 +381,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
        else
                ip6_tnl_unlink(ip6n, t);
        dst_cache_reset(&t->dst_cache);
-       dev_put_track(dev, &t->dev_tracker);
+       netdev_put(dev, &t->dev_tracker);
 }
 
 /**
@@ -796,7 +796,6 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
                                                struct sk_buff *skb),
                         bool log_ecn_err)
 {
-       struct pcpu_sw_netstats *tstats;
        const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
        int err;
 
@@ -856,11 +855,7 @@ static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
                }
        }
 
-       tstats = this_cpu_ptr(tunnel->dev->tstats);
-       u64_stats_update_begin(&tstats->syncp);
-       tstats->rx_packets++;
-       tstats->rx_bytes += skb->len;
-       u64_stats_update_end(&tstats->syncp);
+       dev_sw_netstats_rx_add(tunnel->dev, skb->len);
 
        skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev)));
 
@@ -1889,7 +1884,7 @@ ip6_tnl_dev_init_gen(struct net_device *dev)
        dev->min_mtu = ETH_MIN_MTU;
        dev->max_mtu = IP6_MAX_MTU - dev->hard_header_len;
 
-       dev_hold_track(dev, &t->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &t->dev_tracker, GFP_KERNEL);
        return 0;
 
 destroy_dst:
index 3a434d7..8fe59a7 100644 (file)
@@ -293,7 +293,7 @@ static void vti6_dev_uninit(struct net_device *dev)
                RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
        else
                vti6_tnl_unlink(ip6n, t);
-       dev_put_track(dev, &t->dev_tracker);
+       netdev_put(dev, &t->dev_tracker);
 }
 
 static int vti6_input_proto(struct sk_buff *skb, int nexthdr, __be32 spi,
@@ -936,7 +936,7 @@ static inline int vti6_dev_init_gen(struct net_device *dev)
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
-       dev_hold_track(dev, &t->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &t->dev_tracker, GFP_KERNEL);
        return 0;
 }
 
index 4e74bc6..ec6e150 100644 (file)
@@ -62,7 +62,12 @@ struct ip6mr_result {
    Note that the changes are semaphored via rtnl_lock.
  */
 
-static DEFINE_RWLOCK(mrt_lock);
+static DEFINE_SPINLOCK(mrt_lock);
+
+static struct net_device *vif_dev_read(const struct vif_device *vif)
+{
+       return rcu_dereference(vif->dev);
+}
 
 /* Multicast router control variables */
 
@@ -85,11 +90,11 @@ static void ip6mr_free_table(struct mr_table *mrt);
 static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
                           struct net_device *dev, struct sk_buff *skb,
                           struct mfc6_cache *cache);
-static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
+static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt,
                              mifi_t mifi, int assert);
 static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
                              int cmd);
-static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt);
+static void mrt6msg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt);
 static int ip6mr_rtm_dumproute(struct sk_buff *skb,
                               struct netlink_callback *cb);
 static void mroute_clean_tables(struct mr_table *mrt, int flags);
@@ -398,7 +403,7 @@ static void ip6mr_free_table(struct mr_table *mrt)
  */
 
 static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(mrt_lock)
+       __acquires(RCU)
 {
        struct mr_vif_iter *iter = seq->private;
        struct net *net = seq_file_net(seq);
@@ -410,14 +415,14 @@ static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
 
        iter->mrt = mrt;
 
-       read_lock(&mrt_lock);
+       rcu_read_lock();
        return mr_vif_seq_start(seq, pos);
 }
 
 static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
-       __releases(mrt_lock)
+       __releases(RCU)
 {
-       read_unlock(&mrt_lock);
+       rcu_read_unlock();
 }
 
 static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
@@ -430,7 +435,11 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
                         "Interface      BytesIn  PktsIn  BytesOut PktsOut Flags\n");
        } else {
                const struct vif_device *vif = v;
-               const char *name = vif->dev ? vif->dev->name : "none";
+               const struct net_device *vif_dev;
+               const char *name;
+
+               vif_dev = vif_dev_read(vif);
+               name = vif_dev ? vif_dev->name : "none";
 
                seq_printf(seq,
                           "%2td %-10s %8ld %7ld  %8ld %7ld %05X\n",
@@ -549,13 +558,11 @@ static int pim6_rcv(struct sk_buff *skb)
 
        if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
                goto drop;
-       reg_vif_num = mrt->mroute_reg_vif_num;
 
-       read_lock(&mrt_lock);
+       /* Pairs with WRITE_ONCE() in mif6_add()/mif6_delete() */
+       reg_vif_num = READ_ONCE(mrt->mroute_reg_vif_num);
        if (reg_vif_num >= 0)
-               reg_dev = mrt->vif_table[reg_vif_num].dev;
-       dev_hold(reg_dev);
-       read_unlock(&mrt_lock);
+               reg_dev = vif_dev_read(&mrt->vif_table[reg_vif_num]);
 
        if (!reg_dev)
                goto drop;
@@ -570,7 +577,6 @@ static int pim6_rcv(struct sk_buff *skb)
 
        netif_rx(skb);
 
-       dev_put(reg_dev);
        return 0;
  drop:
        kfree_skb(skb);
@@ -600,11 +606,12 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
        if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
                goto tx_err;
 
-       read_lock(&mrt_lock);
        dev->stats.tx_bytes += skb->len;
        dev->stats.tx_packets++;
-       ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
-       read_unlock(&mrt_lock);
+       rcu_read_lock();
+       ip6mr_cache_report(mrt, skb, READ_ONCE(mrt->mroute_reg_vif_num),
+                          MRT6MSG_WHOLEPKT);
+       rcu_read_unlock();
        kfree_skb(skb);
        return NETDEV_TX_OK;
 
@@ -670,10 +677,11 @@ failure:
 static int call_ip6mr_vif_entry_notifiers(struct net *net,
                                          enum fib_event_type event_type,
                                          struct vif_device *vif,
+                                         struct net_device *vif_dev,
                                          mifi_t vif_index, u32 tb_id)
 {
        return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type,
-                                    vif, vif_index, tb_id,
+                                    vif, vif_dev, vif_index, tb_id,
                                     &net->ipv6.ipmr_seq);
 }
 
@@ -698,23 +706,21 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
 
        v = &mrt->vif_table[vifi];
 
-       if (VIF_EXISTS(mrt, vifi))
-               call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
-                                              FIB_EVENT_VIF_DEL, v, vifi,
-                                              mrt->id);
-
-       write_lock_bh(&mrt_lock);
-       dev = v->dev;
-       v->dev = NULL;
-
-       if (!dev) {
-               write_unlock_bh(&mrt_lock);
+       dev = rtnl_dereference(v->dev);
+       if (!dev)
                return -EADDRNOTAVAIL;
-       }
+
+       call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net),
+                                      FIB_EVENT_VIF_DEL, v, dev,
+                                      vifi, mrt->id);
+       spin_lock(&mrt_lock);
+       RCU_INIT_POINTER(v->dev, NULL);
 
 #ifdef CONFIG_IPV6_PIMSM_V2
-       if (vifi == mrt->mroute_reg_vif_num)
-               mrt->mroute_reg_vif_num = -1;
+       if (vifi == mrt->mroute_reg_vif_num) {
+               /* Pairs with READ_ONCE() in ip6mr_cache_report() and reg_vif_xmit() */
+               WRITE_ONCE(mrt->mroute_reg_vif_num, -1);
+       }
 #endif
 
        if (vifi + 1 == mrt->maxvif) {
@@ -723,10 +729,10 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
                        if (VIF_EXISTS(mrt, tmp))
                                break;
                }
-               mrt->maxvif = tmp + 1;
+               WRITE_ONCE(mrt->maxvif, tmp + 1);
        }
 
-       write_unlock_bh(&mrt_lock);
+       spin_unlock(&mrt_lock);
 
        dev_set_allmulti(dev, -1);
 
@@ -741,7 +747,7 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
        if ((v->flags & MIFF_REGISTER) && !notify)
                unregister_netdevice_queue(dev, head);
 
-       dev_put_track(dev, &v->dev_tracker);
+       netdev_put(dev, &v->dev_tracker);
        return 0;
 }
 
@@ -826,7 +832,7 @@ static void ipmr_expire_process(struct timer_list *t)
        spin_unlock(&mfc_unres_lock);
 }
 
-/* Fill oifs list. It is called under write locked mrt_lock. */
+/* Fill oifs list. It is called under locked mrt_lock. */
 
 static void ip6mr_update_thresholds(struct mr_table *mrt,
                                    struct mr_mfc *cache,
@@ -912,18 +918,18 @@ static int mif6_add(struct net *net, struct mr_table *mrt,
                        MIFF_REGISTER);
 
        /* And finish update writing critical data */
-       write_lock_bh(&mrt_lock);
-       v->dev = dev;
+       spin_lock(&mrt_lock);
+       rcu_assign_pointer(v->dev, dev);
        netdev_tracker_alloc(dev, &v->dev_tracker, GFP_ATOMIC);
 #ifdef CONFIG_IPV6_PIMSM_V2
        if (v->flags & MIFF_REGISTER)
-               mrt->mroute_reg_vif_num = vifi;
+               WRITE_ONCE(mrt->mroute_reg_vif_num, vifi);
 #endif
        if (vifi + 1 > mrt->maxvif)
-               mrt->maxvif = vifi + 1;
-       write_unlock_bh(&mrt_lock);
+               WRITE_ONCE(mrt->maxvif, vifi + 1);
+       spin_unlock(&mrt_lock);
        call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD,
-                                      v, vifi, mrt->id);
+                                      v, dev, vifi, mrt->id);
        return 0;
 }
 
@@ -1028,10 +1034,10 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
 /*
  *     Bounce a cache query up to pim6sd and netlink.
  *
- *     Called under mrt_lock.
+ *     Called under rcu_read_lock()
  */
 
-static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
+static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt,
                              mifi_t mifi, int assert)
 {
        struct sock *mroute6_sk;
@@ -1072,7 +1078,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
                if (assert == MRT6MSG_WRMIFWHOLE)
                        msg->im6_mif = mifi;
                else
-                       msg->im6_mif = mrt->mroute_reg_vif_num;
+                       msg->im6_mif = READ_ONCE(mrt->mroute_reg_vif_num);
                msg->im6_pad = 0;
                msg->im6_src = ipv6_hdr(pkt)->saddr;
                msg->im6_dst = ipv6_hdr(pkt)->daddr;
@@ -1107,10 +1113,8 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
-       rcu_read_lock();
        mroute6_sk = rcu_dereference(mrt->mroute_sk);
        if (!mroute6_sk) {
-               rcu_read_unlock();
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -1119,7 +1123,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
 
        /* Deliver to user space multicast routing algorithms */
        ret = sock_queue_rcv_skb(mroute6_sk, skb);
-       rcu_read_unlock();
+
        if (ret < 0) {
                net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
                kfree_skb(skb);
@@ -1243,7 +1247,7 @@ static int ip6mr_device_event(struct notifier_block *this,
        ip6mr_for_each_table(mrt, net) {
                v = &mrt->vif_table[0];
                for (ct = 0; ct < mrt->maxvif; ct++, v++) {
-                       if (v->dev == dev)
+                       if (rcu_access_pointer(v->dev) == dev)
                                mif6_delete(mrt, ct, 1, NULL);
                }
        }
@@ -1262,7 +1266,7 @@ static int ip6mr_dump(struct net *net, struct notifier_block *nb,
                      struct netlink_ext_ack *extack)
 {
        return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump,
-                      ip6mr_mr_table_iter, &mrt_lock, extack);
+                      ip6mr_mr_table_iter, extack);
 }
 
 static struct notifier_block ip6_mr_notifier = {
@@ -1437,12 +1441,12 @@ static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt,
                                    &mfc->mf6cc_mcastgrp.sin6_addr, parent);
        rcu_read_unlock();
        if (c) {
-               write_lock_bh(&mrt_lock);
+               spin_lock(&mrt_lock);
                c->_c.mfc_parent = mfc->mf6cc_parent;
                ip6mr_update_thresholds(mrt, &c->_c, ttls);
                if (!mrtsock)
                        c->_c.mfc_flags |= MFC_STATIC;
-               write_unlock_bh(&mrt_lock);
+               spin_unlock(&mrt_lock);
                call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE,
                                               c, mrt->id);
                mr6_netlink_event(mrt, c, RTM_NEWROUTE);
@@ -1560,7 +1564,7 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
        struct net *net = sock_net(sk);
 
        rtnl_lock();
-       write_lock_bh(&mrt_lock);
+       spin_lock(&mrt_lock);
        if (rtnl_dereference(mrt->mroute_sk)) {
                err = -EADDRINUSE;
        } else {
@@ -1568,7 +1572,7 @@ static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk)
                sock_set_flag(sk, SOCK_RCU_FREE);
                atomic_inc(&net->ipv6.devconf_all->mc_forwarding);
        }
-       write_unlock_bh(&mrt_lock);
+       spin_unlock(&mrt_lock);
 
        if (!err)
                inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
@@ -1598,14 +1602,14 @@ int ip6mr_sk_done(struct sock *sk)
        rtnl_lock();
        ip6mr_for_each_table(mrt, net) {
                if (sk == rtnl_dereference(mrt->mroute_sk)) {
-                       write_lock_bh(&mrt_lock);
+                       spin_lock(&mrt_lock);
                        RCU_INIT_POINTER(mrt->mroute_sk, NULL);
                        /* Note that mroute_sk had SOCK_RCU_FREE set,
                         * so the RCU grace period before sk freeing
                         * is guaranteed by sk_destruct()
                         */
                        atomic_dec(&devconf->mc_forwarding);
-                       write_unlock_bh(&mrt_lock);
+                       spin_unlock(&mrt_lock);
                        inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
                                                     NETCONFA_MC_FORWARDING,
                                                     NETCONFA_IFINDEX_ALL,
@@ -1891,20 +1895,20 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
                if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
                vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
-               read_lock(&mrt_lock);
+               rcu_read_lock();
                vif = &mrt->vif_table[vr.mifi];
                if (VIF_EXISTS(mrt, vr.mifi)) {
-                       vr.icount = vif->pkt_in;
-                       vr.ocount = vif->pkt_out;
-                       vr.ibytes = vif->bytes_in;
-                       vr.obytes = vif->bytes_out;
-                       read_unlock(&mrt_lock);
+                       vr.icount = READ_ONCE(vif->pkt_in);
+                       vr.ocount = READ_ONCE(vif->pkt_out);
+                       vr.ibytes = READ_ONCE(vif->bytes_in);
+                       vr.obytes = READ_ONCE(vif->bytes_out);
+                       rcu_read_unlock();
 
                        if (copy_to_user(arg, &vr, sizeof(vr)))
                                return -EFAULT;
                        return 0;
                }
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
                return -EADDRNOTAVAIL;
        case SIOCGETSGCNT_IN6:
                if (copy_from_user(&sr, arg, sizeof(sr)))
@@ -1966,20 +1970,20 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
                if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
                vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
-               read_lock(&mrt_lock);
+               rcu_read_lock();
                vif = &mrt->vif_table[vr.mifi];
                if (VIF_EXISTS(mrt, vr.mifi)) {
-                       vr.icount = vif->pkt_in;
-                       vr.ocount = vif->pkt_out;
-                       vr.ibytes = vif->bytes_in;
-                       vr.obytes = vif->bytes_out;
-                       read_unlock(&mrt_lock);
+                       vr.icount = READ_ONCE(vif->pkt_in);
+                       vr.ocount = READ_ONCE(vif->pkt_out);
+                       vr.ibytes = READ_ONCE(vif->bytes_in);
+                       vr.obytes = READ_ONCE(vif->bytes_out);
+                       rcu_read_unlock();
 
                        if (copy_to_user(arg, &vr, sizeof(vr)))
                                return -EFAULT;
                        return 0;
                }
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
                return -EADDRNOTAVAIL;
        case SIOCGETSGCNT_IN6:
                if (copy_from_user(&sr, arg, sizeof(sr)))
@@ -2021,21 +2025,22 @@ static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct
 static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
                          struct sk_buff *skb, int vifi)
 {
-       struct ipv6hdr *ipv6h;
        struct vif_device *vif = &mrt->vif_table[vifi];
-       struct net_device *dev;
+       struct net_device *vif_dev;
+       struct ipv6hdr *ipv6h;
        struct dst_entry *dst;
        struct flowi6 fl6;
 
-       if (!vif->dev)
+       vif_dev = vif_dev_read(vif);
+       if (!vif_dev)
                goto out_free;
 
 #ifdef CONFIG_IPV6_PIMSM_V2
        if (vif->flags & MIFF_REGISTER) {
-               vif->pkt_out++;
-               vif->bytes_out += skb->len;
-               vif->dev->stats.tx_bytes += skb->len;
-               vif->dev->stats.tx_packets++;
+               WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
+               WRITE_ONCE(vif->bytes_out, vif->bytes_out + skb->len);
+               vif_dev->stats.tx_bytes += skb->len;
+               vif_dev->stats.tx_packets++;
                ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
                goto out_free;
        }
@@ -2068,14 +2073,13 @@ static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
         * not mrouter) cannot join to more than one interface - it will
         * result in receiving multiple packets.
         */
-       dev = vif->dev;
-       skb->dev = dev;
-       vif->pkt_out++;
-       vif->bytes_out += skb->len;
+       skb->dev = vif_dev;
+       WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
+       WRITE_ONCE(vif->bytes_out, vif->bytes_out + skb->len);
 
        /* We are about to write */
        /* XXX: extension headers? */
-       if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev)))
+       if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(vif_dev)))
                goto out_free;
 
        ipv6h = ipv6_hdr(skb);
@@ -2084,7 +2088,7 @@ static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
        IP6CB(skb)->flags |= IP6SKB_FORWARDED;
 
        return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
-                      net, NULL, skb, skb->dev, dev,
+                      net, NULL, skb, skb->dev, vif_dev,
                       ip6mr_forward2_finish);
 
 out_free:
@@ -2092,17 +2096,20 @@ out_free:
        return 0;
 }
 
+/* Called with rcu_read_lock() */
 static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev)
 {
        int ct;
 
-       for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
-               if (mrt->vif_table[ct].dev == dev)
+       /* Pairs with WRITE_ONCE() in mif6_delete()/mif6_add() */
+       for (ct = READ_ONCE(mrt->maxvif) - 1; ct >= 0; ct--) {
+               if (rcu_access_pointer(mrt->vif_table[ct].dev) == dev)
                        break;
        }
        return ct;
 }
 
+/* Called under rcu_read_lock() */
 static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
                           struct net_device *dev, struct sk_buff *skb,
                           struct mfc6_cache *c)
@@ -2122,20 +2129,18 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
                /* For an (*,G) entry, we only check that the incoming
                 * interface is part of the static tree.
                 */
-               rcu_read_lock();
                cache_proxy = mr_mfc_find_any_parent(mrt, vif);
                if (cache_proxy &&
                    cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) {
                        rcu_read_unlock();
                        goto forward;
                }
-               rcu_read_unlock();
        }
 
        /*
         * Wrong interface: drop packet and (maybe) send PIM assert.
         */
-       if (mrt->vif_table[vif].dev != dev) {
+       if (rcu_access_pointer(mrt->vif_table[vif].dev) != dev) {
                c->_c.mfc_un.res.wrong_if++;
 
                if (true_vifi >= 0 && mrt->mroute_do_assert &&
@@ -2159,8 +2164,10 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
        }
 
 forward:
-       mrt->vif_table[vif].pkt_in++;
-       mrt->vif_table[vif].bytes_in += skb->len;
+       WRITE_ONCE(mrt->vif_table[vif].pkt_in,
+                  mrt->vif_table[vif].pkt_in + 1);
+       WRITE_ONCE(mrt->vif_table[vif].bytes_in,
+                  mrt->vif_table[vif].bytes_in + skb->len);
 
        /*
         *      Forward the frame
@@ -2238,7 +2245,6 @@ int ip6_mr_input(struct sk_buff *skb)
                return err;
        }
 
-       read_lock(&mrt_lock);
        cache = ip6mr_cache_find(mrt,
                                 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
        if (!cache) {
@@ -2259,19 +2265,15 @@ int ip6_mr_input(struct sk_buff *skb)
                vif = ip6mr_find_vif(mrt, dev);
                if (vif >= 0) {
                        int err = ip6mr_cache_unresolved(mrt, vif, skb, dev);
-                       read_unlock(&mrt_lock);
 
                        return err;
                }
-               read_unlock(&mrt_lock);
                kfree_skb(skb);
                return -ENODEV;
        }
 
        ip6_mr_forward(net, mrt, dev, skb, cache);
 
-       read_unlock(&mrt_lock);
-
        return 0;
 }
 
@@ -2287,7 +2289,7 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
        if (!mrt)
                return -ENOENT;
 
-       read_lock(&mrt_lock);
+       rcu_read_lock();
        cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
        if (!cache && skb->dev) {
                int vif = ip6mr_find_vif(mrt, skb->dev);
@@ -2305,14 +2307,14 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
 
                dev = skb->dev;
                if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
-                       read_unlock(&mrt_lock);
+                       rcu_read_unlock();
                        return -ENODEV;
                }
 
                /* really correct? */
                skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
                if (!skb2) {
-                       read_unlock(&mrt_lock);
+                       rcu_read_unlock();
                        return -ENOMEM;
                }
 
@@ -2335,13 +2337,13 @@ int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm,
                iph->daddr = rt->rt6i_dst.addr;
 
                err = ip6mr_cache_unresolved(mrt, vif, skb2, dev);
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
 
                return err;
        }
 
        err = mr_fill_mroute(mrt, skb, &cache->_c, rtm);
-       read_unlock(&mrt_lock);
+       rcu_read_unlock();
        return err;
 }
 
@@ -2460,7 +2462,7 @@ static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
        return len;
 }
 
-static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
+static void mrt6msg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt)
 {
        struct net *net = read_pnet(&mrt->net);
        struct nlmsghdr *nlh;
index b0dfe97..cd84cbd 100644 (file)
@@ -128,6 +128,7 @@ struct neigh_table nd_tbl = {
                        [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER,
                        [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME,
                        [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
+                       [NEIGH_VAR_INTERVAL_PROBE_TIME_MS] = 5 * HZ,
                        [NEIGH_VAR_GC_STALETIME] = 60 * HZ,
                        [NEIGH_VAR_QUEUE_LEN_BYTES] = SK_WMEM_MAX,
                        [NEIGH_VAR_PROXY_QLEN] = 64,
index 3b7cbd5..722de9d 100644 (file)
 
 #define        ICMPV6_HDRLEN   4       /* ICMPv6 header, RFC 4443 Section 2.1 */
 
-struct raw_hashinfo raw_v6_hashinfo = {
-       .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock),
-};
+struct raw_hashinfo raw_v6_hashinfo;
 EXPORT_SYMBOL_GPL(raw_v6_hashinfo);
 
-struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
-               unsigned short num, const struct in6_addr *loc_addr,
-               const struct in6_addr *rmt_addr, int dif, int sdif)
+bool raw_v6_match(struct net *net, struct sock *sk, unsigned short num,
+                 const struct in6_addr *loc_addr,
+                 const struct in6_addr *rmt_addr, int dif, int sdif)
 {
-       bool is_multicast = ipv6_addr_is_multicast(loc_addr);
-
-       sk_for_each_from(sk)
-               if (inet_sk(sk)->inet_num == num) {
-
-                       if (!net_eq(sock_net(sk), net))
-                               continue;
-
-                       if (!ipv6_addr_any(&sk->sk_v6_daddr) &&
-                           !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr))
-                               continue;
-
-                       if (!raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if,
-                                                dif, sdif))
-                               continue;
-
-                       if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
-                               if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr))
-                                       goto found;
-                               if (is_multicast &&
-                                   inet6_mc_check(sk, loc_addr, rmt_addr))
-                                       goto found;
-                               continue;
-                       }
-                       goto found;
-               }
-       sk = NULL;
-found:
-       return sk;
+       if (inet_sk(sk)->inet_num != num ||
+           !net_eq(sock_net(sk), net) ||
+           (!ipv6_addr_any(&sk->sk_v6_daddr) &&
+            !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) ||
+           !raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if,
+                                dif, sdif))
+               return false;
+
+       if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) ||
+           ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr) ||
+           (ipv6_addr_is_multicast(loc_addr) &&
+            inet6_mc_check(sk, loc_addr, rmt_addr)))
+               return true;
+
+       return false;
 }
-EXPORT_SYMBOL_GPL(__raw_v6_lookup);
+EXPORT_SYMBOL_GPL(raw_v6_match);
 
 /*
  *     0 - deliver
@@ -156,31 +140,27 @@ EXPORT_SYMBOL(rawv6_mh_filter_unregister);
  */
 static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
+       struct net *net = dev_net(skb->dev);
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
        const struct in6_addr *saddr;
        const struct in6_addr *daddr;
        struct sock *sk;
        bool delivered = false;
        __u8 hash;
-       struct net *net;
 
        saddr = &ipv6_hdr(skb)->saddr;
        daddr = saddr + 1;
 
        hash = nexthdr & (RAW_HTABLE_SIZE - 1);
-
-       read_lock(&raw_v6_hashinfo.lock);
-       sk = sk_head(&raw_v6_hashinfo.ht[hash]);
-
-       if (!sk)
-               goto out;
-
-       net = dev_net(skb->dev);
-       sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr,
-                            inet6_iif(skb), inet6_sdif(skb));
-
-       while (sk) {
+       hlist = &raw_v6_hashinfo.ht[hash];
+       rcu_read_lock();
+       sk_nulls_for_each(sk, hnode, hlist) {
                int filtered;
 
+               if (!raw_v6_match(net, sk, nexthdr, daddr, saddr,
+                                 inet6_iif(skb), inet6_sdif(skb)))
+                       continue;
                delivered = true;
                switch (nexthdr) {
                case IPPROTO_ICMPV6:
@@ -219,23 +199,14 @@ static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
                                rawv6_rcv(sk, clone);
                        }
                }
-               sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr,
-                                    inet6_iif(skb), inet6_sdif(skb));
        }
-out:
-       read_unlock(&raw_v6_hashinfo.lock);
+       rcu_read_unlock();
        return delivered;
 }
 
 bool raw6_local_deliver(struct sk_buff *skb, int nexthdr)
 {
-       struct sock *raw_sk;
-
-       raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]);
-       if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
-               raw_sk = NULL;
-
-       return raw_sk != NULL;
+       return ipv6_raw_deliver(skb, nexthdr);
 }
 
 /* This cleans up af_inet6 a bit. -DaveM */
@@ -361,30 +332,25 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb,
 void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
                u8 type, u8 code, int inner_offset, __be32 info)
 {
+       struct net *net = dev_net(skb->dev);
+       struct hlist_nulls_head *hlist;
+       struct hlist_nulls_node *hnode;
        struct sock *sk;
        int hash;
-       const struct in6_addr *saddr, *daddr;
-       struct net *net;
 
        hash = nexthdr & (RAW_HTABLE_SIZE - 1);
-
-       read_lock(&raw_v6_hashinfo.lock);
-       sk = sk_head(&raw_v6_hashinfo.ht[hash]);
-       if (sk) {
+       hlist = &raw_v6_hashinfo.ht[hash];
+       rcu_read_lock();
+       sk_nulls_for_each(sk, hnode, hlist) {
                /* Note: ipv6_hdr(skb) != skb->data */
                const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
-               saddr = &ip6h->saddr;
-               daddr = &ip6h->daddr;
-               net = dev_net(skb->dev);
-
-               while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr,
-                                            inet6_iif(skb), inet6_iif(skb)))) {
-                       rawv6_err(sk, skb, NULL, type, code,
-                                       inner_offset, info);
-                       sk = sk_next(sk);
-               }
+
+               if (!raw_v6_match(net, sk, nexthdr, &ip6h->saddr, &ip6h->daddr,
+                                 inet6_iif(skb), inet6_iif(skb)))
+                       continue;
+               rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
        }
-       read_unlock(&raw_v6_hashinfo.lock);
+       rcu_read_unlock();
 }
 
 static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb)
index 8283557..70cd50c 100644 (file)
@@ -182,9 +182,9 @@ static void rt6_uncached_list_flush_dev(struct net_device *dev)
 
                        if (rt_dev == dev) {
                                rt->dst.dev = blackhole_netdev;
-                               dev_replace_track(rt_dev, blackhole_netdev,
-                                                 &rt->dst.dev_tracker,
-                                                 GFP_ATOMIC);
+                               netdev_ref_replace(rt_dev, blackhole_netdev,
+                                                  &rt->dst.dev_tracker,
+                                                  GFP_ATOMIC);
                                handled = true;
                        }
                        if (handled)
@@ -607,7 +607,7 @@ static void rt6_probe_deferred(struct work_struct *w)
 
        addrconf_addr_solict_mult(&work->target, &mcaddr);
        ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, 0);
-       dev_put_track(work->dev, &work->dev_tracker);
+       netdev_put(work->dev, &work->dev_tracker);
        kfree(work);
 }
 
@@ -661,7 +661,7 @@ static void rt6_probe(struct fib6_nh *fib6_nh)
        } else {
                INIT_WORK(&work->work, rt6_probe_deferred);
                work->target = *nh_gw;
-               dev_hold_track(dev, &work->dev_tracker, GFP_ATOMIC);
+               netdev_hold(dev, &work->dev_tracker, GFP_ATOMIC);
                work->dev = dev;
                schedule_work(&work->work);
        }
@@ -5941,7 +5941,7 @@ int rt6_dump_route(struct fib6_info *rt, void *p_arg, unsigned int skip)
                rcu_read_unlock();
 
                if (err)
-                       return count += w.count;
+                       return count + w.count;
        }
 
        return -1;
index 6bcd5e4..6b73b7a 100644 (file)
@@ -519,7 +519,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
                ipip6_tunnel_del_prl(tunnel, NULL);
        }
        dst_cache_reset(&tunnel->dst_cache);
-       dev_put_track(dev, &tunnel->dev_tracker);
+       netdev_put(dev, &tunnel->dev_tracker);
 }
 
 static int ipip6_err(struct sk_buff *skb, u32 info)
@@ -684,8 +684,6 @@ static int ipip6_rcv(struct sk_buff *skb)
        tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
                                     iph->saddr, iph->daddr, sifindex);
        if (tunnel) {
-               struct pcpu_sw_netstats *tstats;
-
                if (tunnel->parms.iph.protocol != IPPROTO_IPV6 &&
                    tunnel->parms.iph.protocol != 0)
                        goto out;
@@ -722,11 +720,7 @@ static int ipip6_rcv(struct sk_buff *skb)
                        }
                }
 
-               tstats = this_cpu_ptr(tunnel->dev->tstats);
-               u64_stats_update_begin(&tstats->syncp);
-               tstats->rx_packets++;
-               tstats->rx_bytes += skb->len;
-               u64_stats_update_end(&tstats->syncp);
+               dev_sw_netstats_rx_add(tunnel->dev, skb->len);
 
                netif_rx(skb);
 
@@ -1461,7 +1455,7 @@ static int ipip6_tunnel_init(struct net_device *dev)
                dev->tstats = NULL;
                return err;
        }
-       dev_hold_track(dev, &tunnel->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &tunnel->dev_tracker, GFP_KERNEL);
        return 0;
 }
 
index f37dd4a..c72448b 100644 (file)
@@ -2159,7 +2159,10 @@ struct proto tcpv6_prot = {
        .leave_memory_pressure  = tcp_leave_memory_pressure,
        .stream_memory_free     = tcp_stream_memory_free,
        .sockets_allocated      = &tcp_sockets_allocated,
+
        .memory_allocated       = &tcp_memory_allocated,
+       .per_cpu_fw_alloc       = &tcp_memory_per_cpu_fw_alloc,
+
        .memory_pressure        = &tcp_memory_pressure,
        .orphan_count           = &tcp_orphan_count,
        .sysctl_mem             = sysctl_tcp_mem,
index 55afd7f..be074f0 100644 (file)
@@ -1740,7 +1740,10 @@ struct proto udpv6_prot = {
 #ifdef CONFIG_BPF_SYSCALL
        .psock_update_sk_prot   = udp_bpf_update_proto,
 #endif
+
        .memory_allocated       = &udp_memory_allocated,
+       .per_cpu_fw_alloc       = &udp_memory_per_cpu_fw_alloc,
+
        .sysctl_mem             = sysctl_udp_mem,
        .sysctl_wmem_offset     = offsetof(struct net, ipv4.sysctl_udp_wmem_min),
        .sysctl_rmem_offset     = offsetof(struct net, ipv4.sysctl_udp_rmem_min),
index fbb700d..b707258 100644 (file)
@@ -48,7 +48,10 @@ struct proto udplitev6_prot = {
        .unhash            = udp_lib_unhash,
        .rehash            = udp_v6_rehash,
        .get_port          = udp_v6_get_port,
+
        .memory_allocated  = &udp_memory_allocated,
+       .per_cpu_fw_alloc  = &udp_memory_per_cpu_fw_alloc,
+
        .sysctl_mem        = sysctl_udp_mem,
        .obj_size          = sizeof(struct udp6_sock),
        .h.udp_table       = &udplite_table,
index e64e427..4a4b0e4 100644 (file)
@@ -73,11 +73,11 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        struct rt6_info *rt = (struct rt6_info *)xdst->route;
 
        xdst->u.dst.dev = dev;
-       dev_hold_track(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &xdst->u.dst.dev_tracker, GFP_ATOMIC);
 
        xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
        if (!xdst->u.rt6.rt6i_idev) {
-               dev_put_track(dev, &xdst->u.dst.dev_tracker);
+               netdev_put(dev, &xdst->u.dst.dev_tracker);
                return -ENODEV;
        }
 
index a0385dd..498a0c3 100644 (file)
@@ -278,8 +278,6 @@ static void iucv_sock_destruct(struct sock *sk)
        skb_queue_purge(&sk->sk_receive_queue);
        skb_queue_purge(&sk->sk_error_queue);
 
-       sk_mem_reclaim(sk);
-
        if (!sock_flag(sk, SOCK_DEAD)) {
                pr_err("Attempt to release alive iucv socket %p\n", sk);
                return;
index 7f555d2..da7fe94 100644 (file)
@@ -224,7 +224,7 @@ static int llc_ui_release(struct socket *sock)
        } else {
                release_sock(sk);
        }
-       dev_put_track(llc->dev, &llc->dev_tracker);
+       netdev_put(llc->dev, &llc->dev_tracker);
        sock_put(sk);
        llc_sk_free(sk);
 out:
index f7896f2..881efbf 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2015  Intel Mobile Communications GmbH
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -438,7 +438,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta = NULL;
-       const struct ieee80211_cipher_scheme *cs = NULL;
        struct ieee80211_key *key;
        int err;
 
@@ -456,23 +455,12 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                if (WARN_ON_ONCE(fips_enabled))
                        return -EINVAL;
                break;
-       case WLAN_CIPHER_SUITE_CCMP:
-       case WLAN_CIPHER_SUITE_CCMP_256:
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-       case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-       case WLAN_CIPHER_SUITE_BIP_GMAC_128:
-       case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-       case WLAN_CIPHER_SUITE_GCMP:
-       case WLAN_CIPHER_SUITE_GCMP_256:
-               break;
        default:
-               cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);
                break;
        }
 
        key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,
-                                 params->key, params->seq_len, params->seq,
-                                 cs);
+                                 params->key, params->seq_len, params->seq);
        if (IS_ERR(key))
                return PTR_ERR(key);
 
@@ -537,9 +525,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
                break;
        }
 
-       if (sta)
-               sta->cipher_scheme = cs;
-
        err = ieee80211_key_link(key, sdata, sta);
 
  out_unlock:
@@ -548,33 +533,53 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
        return err;
 }
 
+static struct ieee80211_key *
+ieee80211_lookup_key(struct ieee80211_sub_if_data *sdata,
+                    u8 key_idx, bool pairwise, const u8 *mac_addr)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+
+       if (mac_addr) {
+               sta = sta_info_get_bss(sdata, mac_addr);
+               if (!sta)
+                       return NULL;
+
+               if (pairwise && key_idx < NUM_DEFAULT_KEYS)
+                       return rcu_dereference_check_key_mtx(local,
+                                                            sta->ptk[key_idx]);
+
+               if (!pairwise &&
+                   key_idx < NUM_DEFAULT_KEYS +
+                             NUM_DEFAULT_MGMT_KEYS +
+                             NUM_DEFAULT_BEACON_KEYS)
+                       return rcu_dereference_check_key_mtx(local,
+                                                            sta->deflink.gtk[key_idx]);
+
+               return NULL;
+       }
+
+       if (key_idx < NUM_DEFAULT_KEYS +
+                     NUM_DEFAULT_MGMT_KEYS +
+                     NUM_DEFAULT_BEACON_KEYS)
+               return rcu_dereference_check_key_mtx(local,
+                                                    sdata->keys[key_idx]);
+
+       return NULL;
+}
+
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
                             u8 key_idx, bool pairwise, const u8 *mac_addr)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
-       struct sta_info *sta;
-       struct ieee80211_key *key = NULL;
+       struct ieee80211_key *key;
        int ret;
 
        mutex_lock(&local->sta_mtx);
        mutex_lock(&local->key_mtx);
 
-       if (mac_addr) {
-               ret = -ENOENT;
-
-               sta = sta_info_get_bss(sdata, mac_addr);
-               if (!sta)
-                       goto out_unlock;
-
-               if (pairwise)
-                       key = key_mtx_dereference(local, sta->ptk[key_idx]);
-               else
-                       key = key_mtx_dereference(local,
-                                                 sta->deflink.gtk[key_idx]);
-       } else
-               key = key_mtx_dereference(local, sdata->keys[key_idx]);
-
+       key = ieee80211_lookup_key(sdata, key_idx, pairwise, mac_addr);
        if (!key) {
                ret = -ENOENT;
                goto out_unlock;
@@ -597,10 +602,9 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
                                              struct key_params *params))
 {
        struct ieee80211_sub_if_data *sdata;
-       struct sta_info *sta = NULL;
        u8 seq[6] = {0};
        struct key_params params;
-       struct ieee80211_key *key = NULL;
+       struct ieee80211_key *key;
        u64 pn64;
        u32 iv32;
        u16 iv16;
@@ -611,20 +615,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 
        rcu_read_lock();
 
-       if (mac_addr) {
-               sta = sta_info_get_bss(sdata, mac_addr);
-               if (!sta)
-                       goto out;
-
-               if (pairwise && key_idx < NUM_DEFAULT_KEYS)
-                       key = rcu_dereference(sta->ptk[key_idx]);
-               else if (!pairwise &&
-                        key_idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
-                        NUM_DEFAULT_BEACON_KEYS)
-                       key = rcu_dereference(sta->deflink.gtk[key_idx]);
-       } else
-               key = rcu_dereference(sdata->keys[key_idx]);
-
+       key = ieee80211_lookup_key(sdata, key_idx, pairwise, mac_addr);
        if (!key)
                goto out;
 
@@ -1207,9 +1198,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                                params->crypto.control_port_over_nl80211;
        sdata->control_port_no_preauth =
                                params->crypto.control_port_no_preauth;
-       sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,
-                                                       &params->crypto,
-                                                       sdata->vif.type);
 
        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
                vlan->control_port_protocol =
@@ -1220,10 +1208,6 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                        params->crypto.control_port_over_nl80211;
                vlan->control_port_no_preauth =
                        params->crypto.control_port_no_preauth;
-               vlan->encrypt_headroom =
-                       ieee80211_cs_headroom(sdata->local,
-                                             &params->crypto,
-                                             vlan->vif.type);
        }
 
        sdata->vif.bss_conf.dtim_period = params->dtim_period;
index 86ef0a4..1cf3315 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2015  Intel Mobile Communications GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  */
 
 #ifndef IEEE80211_I_H
@@ -944,7 +944,6 @@ struct ieee80211_sub_if_data {
        bool control_port_no_encrypt;
        bool control_port_no_preauth;
        bool control_port_over_nl80211;
-       int encrypt_headroom;
 
        atomic_t num_tx_queued;
        struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
@@ -2483,14 +2482,6 @@ void ieee80211_dfs_radar_detected_work(struct work_struct *work);
 int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
                              struct cfg80211_csa_settings *csa_settings);
 
-bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs);
-bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n);
-const struct ieee80211_cipher_scheme *
-ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
-                enum nl80211_iftype iftype);
-int ieee80211_cs_headroom(struct ieee80211_local *local,
-                         struct cfg80211_crypto_settings *crypto,
-                         enum nl80211_iftype iftype);
 void ieee80211_recalc_dtim(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata);
 int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
index 4153147..fb8d102 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (c) 2016        Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  */
 #include <linux/slab.h>
 #include <linux/kernel.h>
@@ -1036,8 +1036,6 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
                 wiphy_name(local->hw.wiphy));
        sdata->wdev.iftype = NL80211_IFTYPE_MONITOR;
 
-       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
-
        ieee80211_set_default_queues(sdata);
 
        ret = drv_add_interface(local, sdata);
@@ -1644,7 +1642,6 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
        sdata->control_port_no_encrypt = false;
        sdata->control_port_over_nl80211 = false;
        sdata->control_port_no_preauth = false;
-       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
        sdata->vif.bss_conf.idle = true;
        sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
 
@@ -2116,8 +2113,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
        sdata->user_power_level = local->user_power_level;
 
-       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
-
        /* setup type-dependent data */
        ieee80211_setup_sdata(sdata, type);
 
index 0fcf8ae..c3476de 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright 2018-2020  Intel Corporation
+ * Copyright 2018-2020, 2022  Intel Corporation
  */
 
 #include <linux/if_ether.h>
@@ -531,8 +531,7 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
 struct ieee80211_key *
 ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                    const u8 *key_data,
-                   size_t seq_len, const u8 *seq,
-                   const struct ieee80211_cipher_scheme *cs)
+                   size_t seq_len, const u8 *seq)
 {
        struct ieee80211_key *key;
        int i, j, err;
@@ -675,21 +674,6 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                        return ERR_PTR(err);
                }
                break;
-       default:
-               if (cs) {
-                       if (seq_len && seq_len != cs->pn_len) {
-                               kfree(key);
-                               return ERR_PTR(-EINVAL);
-                       }
-
-                       key->conf.iv_len = cs->hdr_len;
-                       key->conf.icv_len = cs->mic_len;
-                       for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
-                               for (j = 0; j < seq_len; j++)
-                                       key->u.gen.rx_pn[i][j] =
-                                                       seq[seq_len - j - 1];
-                       key->flags |= KEY_FLAG_CIPHER_SCHEME;
-               }
        }
        memcpy(key->conf.key, key_data, key_len);
        INIT_LIST_HEAD(&key->list);
@@ -1294,7 +1278,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
 
        key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,
                                  keyconf->keylen, keyconf->key,
-                                 0, NULL, NULL);
+                                 0, NULL);
        if (IS_ERR(key))
                return ERR_CAST(key);
 
index 1e326c8..e994dce 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Copyright 2002-2004, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
- * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2019, 2022 Intel Corporation
  */
 
 #ifndef IEEE80211_KEY_H
@@ -30,12 +30,10 @@ struct sta_info;
  * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
  *     in the hardware for TX crypto hardware acceleration.
  * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped.
- * @KEY_FLAG_CIPHER_SCHEME: This key is for a hardware cipher scheme
  */
 enum ieee80211_internal_key_flags {
        KEY_FLAG_UPLOADED_TO_HARDWARE   = BIT(0),
        KEY_FLAG_TAINTED                = BIT(1),
-       KEY_FLAG_CIPHER_SCHEME          = BIT(2),
 };
 
 enum ieee80211_internal_tkip_state {
@@ -140,8 +138,7 @@ struct ieee80211_key {
 struct ieee80211_key *
 ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                    const u8 *key_data,
-                   size_t seq_len, const u8 *seq,
-                   const struct ieee80211_cipher_scheme *cs);
+                   size_t seq_len, const u8 *seq);
 /*
  * Insert a key into data structures (sdata, sta if necessary)
  * to make it used, free old key. On failure, also free the new key.
@@ -166,6 +163,8 @@ void ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata);
 
 #define key_mtx_dereference(local, ref) \
        rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
+#define rcu_dereference_check_key_mtx(local, ref) \
+       rcu_dereference_check(ref, lockdep_is_held(&((local)->key_mtx)))
 
 void ieee80211_delayed_tailroom_dec(struct work_struct *wk);
 
index 5a385d4..4f3e93c 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (C) 2017     Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  */
 
 #include <net/mac80211.h>
@@ -778,7 +778,7 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
 {
        bool have_wep = !fips_enabled; /* FIPS does not permit the use of RC4 */
        bool have_mfp = ieee80211_hw_check(&local->hw, MFP_CAPABLE);
-       int n_suites = 0, r = 0, w = 0;
+       int r = 0, w = 0;
        u32 *suites;
        static const u32 cipher_suites[] = {
                /* keep WEP first, it may be removed below */
@@ -824,10 +824,9 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
                                continue;
                        suites[w++] = suite;
                }
-       } else if (!local->hw.cipher_schemes) {
-               /* If the driver doesn't have cipher schemes, there's nothing
-                * else to do other than assign the (software supported and
-                * perhaps offloaded) cipher suites.
+       } else {
+               /* assign the (software supported and perhaps offloaded)
+                * cipher suites
                 */
                local->hw.wiphy->cipher_suites = cipher_suites;
                local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
@@ -842,58 +841,6 @@ static int ieee80211_init_cipher_suites(struct ieee80211_local *local)
 
                /* not dynamically allocated, so just return */
                return 0;
-       } else {
-               const struct ieee80211_cipher_scheme *cs;
-
-               cs = local->hw.cipher_schemes;
-
-               /* Driver specifies cipher schemes only (but not cipher suites
-                * including the schemes)
-                *
-                * We start counting ciphers defined by schemes, TKIP, CCMP,
-                * CCMP-256, GCMP, and GCMP-256
-                */
-               n_suites = local->hw.n_cipher_schemes + 5;
-
-               /* check if we have WEP40 and WEP104 */
-               if (have_wep)
-                       n_suites += 2;
-
-               /* check if we have AES_CMAC, BIP-CMAC-256, BIP-GMAC-128,
-                * BIP-GMAC-256
-                */
-               if (have_mfp)
-                       n_suites += 4;
-
-               suites = kmalloc_array(n_suites, sizeof(u32), GFP_KERNEL);
-               if (!suites)
-                       return -ENOMEM;
-
-               suites[w++] = WLAN_CIPHER_SUITE_CCMP;
-               suites[w++] = WLAN_CIPHER_SUITE_CCMP_256;
-               suites[w++] = WLAN_CIPHER_SUITE_TKIP;
-               suites[w++] = WLAN_CIPHER_SUITE_GCMP;
-               suites[w++] = WLAN_CIPHER_SUITE_GCMP_256;
-
-               if (have_wep) {
-                       suites[w++] = WLAN_CIPHER_SUITE_WEP40;
-                       suites[w++] = WLAN_CIPHER_SUITE_WEP104;
-               }
-
-               if (have_mfp) {
-                       suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;
-                       suites[w++] = WLAN_CIPHER_SUITE_BIP_CMAC_256;
-                       suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_128;
-                       suites[w++] = WLAN_CIPHER_SUITE_BIP_GMAC_256;
-               }
-
-               for (r = 0; r < local->hw.n_cipher_schemes; r++) {
-                       suites[w++] = cs[r].cipher;
-                       if (WARN_ON(cs[r].pn_len > IEEE80211_MAX_PN_LEN)) {
-                               kfree(suites);
-                               return -EINVAL;
-                       }
-               }
        }
 
        local->hw.wiphy->cipher_suites = suites;
@@ -1168,12 +1115,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (local->hw.wiphy->max_scan_ie_len)
                local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;
 
-       if (WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,
-                                            local->hw.n_cipher_schemes))) {
-               result = -EINVAL;
-               goto fail_workqueue;
-       }
-
        result = ieee80211_init_cipher_suites(local);
        if (result < 0)
                goto fail_workqueue;
index 58ebdcd..45e7c1b 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2008, 2009 open80211s Ltd.
- * Copyright (C) 2019, 2021 Intel Corporation
+ * Copyright (C) 2019, 2021-2022 Intel Corporation
  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
  */
 
@@ -247,13 +247,13 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata,
                return -EAGAIN;
 
        skb = dev_alloc_skb(local->tx_headroom +
-                           sdata->encrypt_headroom +
+                           IEEE80211_ENCRYPT_HEADROOM +
                            IEEE80211_ENCRYPT_TAILROOM +
                            hdr_len +
                            2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
-       skb_reserve(skb, local->tx_headroom + sdata->encrypt_headroom);
+       skb_reserve(skb, local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
        mgmt = skb_put_zero(skb, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
index 58d48dc..6d5ad71 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2021 Intel Corporation
+ * Copyright (C) 2018 - 2022 Intel Corporation
  */
 
 #include <linux/delay.h>
@@ -2496,8 +2496,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        memset(ifmgd->tx_tspec, 0, sizeof(ifmgd->tx_tspec));
        cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
 
-       sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
-
        bss_conf->pwr_reduction = 0;
        bss_conf->tx_pwr_env_num = 0;
        memset(bss_conf->tx_pwr_env, 0, sizeof(bss_conf->tx_pwr_env));
@@ -6071,8 +6069,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        sdata->control_port_over_nl80211 =
                                        req->crypto.control_port_over_nl80211;
        sdata->control_port_no_preauth = req->crypto.control_port_no_preauth;
-       sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,
-                                                       sdata->vif.type);
 
        /* kick off associate process */
 
index 3c08ae0..a9f4e90 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  */
 
 #include <linux/jiffies.h>
@@ -1009,43 +1009,20 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        return -1;
 }
 
-static int ieee80211_get_keyid(struct sk_buff *skb,
-                              const struct ieee80211_cipher_scheme *cs)
+static int ieee80211_get_keyid(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       __le16 fc;
-       int hdrlen;
-       int minlen;
-       u8 key_idx_off;
-       u8 key_idx_shift;
+       __le16 fc = hdr->frame_control;
+       int hdrlen = ieee80211_hdrlen(fc);
        u8 keyid;
 
-       fc = hdr->frame_control;
-       hdrlen = ieee80211_hdrlen(fc);
-
-       if (cs) {
-               minlen = hdrlen + cs->hdr_len;
-               key_idx_off = hdrlen + cs->key_idx_off;
-               key_idx_shift = cs->key_idx_shift;
-       } else {
-               /* WEP, TKIP, CCMP and GCMP */
-               minlen = hdrlen + IEEE80211_WEP_IV_LEN;
-               key_idx_off = hdrlen + 3;
-               key_idx_shift = 6;
-       }
-
-       if (unlikely(skb->len < minlen))
+       /* WEP, TKIP, CCMP and GCMP */
+       if (unlikely(skb->len < hdrlen + IEEE80211_WEP_IV_LEN))
                return -EINVAL;
 
-       skb_copy_bits(skb, key_idx_off, &keyid, 1);
+       skb_copy_bits(skb, hdrlen + 3, &keyid, 1);
 
-       if (cs)
-               keyid &= cs->key_idx_mask;
-       keyid >>= key_idx_shift;
-
-       /* cs could use more than the usual two bits for the keyid */
-       if (unlikely(keyid >= NUM_DEFAULT_KEYS))
-               return -EINVAL;
+       keyid >>= 6;
 
        return keyid;
 }
@@ -1916,7 +1893,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
        struct ieee80211_key *ptk_idx = NULL;
        int mmie_keyidx = -1;
        __le16 fc;
-       const struct ieee80211_cipher_scheme *cs = NULL;
 
        if (ieee80211_is_ext(hdr->frame_control))
                return RX_CONTINUE;
@@ -1959,8 +1935,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 
                if (ieee80211_has_protected(fc) &&
                    !(status->flag & RX_FLAG_IV_STRIPPED)) {
-                       cs = rx->sta->cipher_scheme;
-                       keyid = ieee80211_get_keyid(rx->skb, cs);
+                       keyid = ieee80211_get_keyid(rx->skb);
 
                        if (unlikely(keyid < 0))
                                return RX_DROP_UNUSABLE;
@@ -2065,7 +2040,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                    (status->flag & RX_FLAG_IV_STRIPPED))
                        return RX_CONTINUE;
 
-               keyidx = ieee80211_get_keyid(rx->skb, cs);
+               keyidx = ieee80211_get_keyid(rx->skb);
 
                if (unlikely(keyidx < 0))
                        return RX_DROP_UNUSABLE;
@@ -2131,7 +2106,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                result = ieee80211_crypto_gcmp_decrypt(rx);
                break;
        default:
-               result = ieee80211_crypto_hw_decrypt(rx);
+               result = RX_DROP_UNUSABLE;
        }
 
        /* the hdr variable is invalid after the decrypt handlers */
@@ -2945,7 +2920,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                tailroom = IEEE80211_ENCRYPT_TAILROOM;
 
        fwd_skb = skb_copy_expand(skb, local->tx_headroom +
-                                      sdata->encrypt_headroom,
+                                      IEEE80211_ENCRYPT_HEADROOM,
                                  tailroom, GFP_ATOMIC);
        if (!fwd_skb)
                goto out;
index 35c390b..aa6950a 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2002-2005, Devicescape Software, Inc.
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
- * Copyright(c) 2020-2021 Intel Corporation
+ * Copyright(c) 2020-2022 Intel Corporation
  */
 
 #ifndef STA_INFO_H
@@ -616,7 +616,6 @@ struct link_sta_info {
  *     taken from HT/VHT capabilities or VHT operating mode notification
  * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
  *     AP only.
- * @cipher_scheme: optional cipher scheme for this station
  * @cparams: CoDel parameters for this station.
  * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
  * @fast_tx: TX fastpath information
@@ -700,7 +699,6 @@ struct sta_info {
 #endif
 
        enum ieee80211_smps_mode known_smps_mode;
-       const struct ieee80211_cipher_scheme *cipher_scheme;
 
        struct codel_params cparams;
 
index 0e4efc0..37fe72b 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  *
  * Transmit and frame generation functions.
  */
@@ -882,7 +882,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
                rem -= fraglen;
                tmp = dev_alloc_skb(local->tx_headroom +
                                    frag_threshold +
-                                   tx->sdata->encrypt_headroom +
+                                   IEEE80211_ENCRYPT_HEADROOM +
                                    IEEE80211_ENCRYPT_TAILROOM);
                if (!tmp)
                        return -ENOMEM;
@@ -890,7 +890,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
                __skb_queue_tail(&tx->skbs, tmp);
 
                skb_reserve(tmp,
-                           local->tx_headroom + tx->sdata->encrypt_headroom);
+                           local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM);
 
                /* copy control information */
                memcpy(tmp->cb, skb->cb, sizeof(tmp->cb));
@@ -1040,8 +1040,6 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_GCMP_256:
                return ieee80211_crypto_gcmp_encrypt(tx);
-       default:
-               return ieee80211_crypto_hw_encrypt(tx);
        }
 
        return TX_DROP;
@@ -2013,7 +2011,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
        headroom = local->tx_headroom;
        if (encrypt != ENCRYPT_NO)
-               headroom += sdata->encrypt_headroom;
+               headroom += IEEE80211_ENCRYPT_HEADROOM;
        headroom -= skb_headroom(skb);
        headroom = max_t(int, 0, headroom);
 
@@ -2867,7 +2865,7 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
         */
 
        if (head_need > 0 || skb_cloned(skb)) {
-               head_need += sdata->encrypt_headroom;
+               head_need += IEEE80211_ENCRYPT_HEADROOM;
                head_need += local->tx_headroom;
                head_need = max_t(int, 0, head_need);
                if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
@@ -3128,15 +3126,6 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
                        /* we don't know how to generate IVs for this at all */
                        if (WARN_ON(gen_iv))
                                goto out;
-                       /* pure hardware keys are OK, of course */
-                       if (!(build.key->flags & KEY_FLAG_CIPHER_SCHEME))
-                               break;
-                       /* cipher scheme might require space allocation */
-                       if (iv_spc &&
-                           build.key->conf.iv_len > IEEE80211_FAST_XMIT_MAX_IV)
-                               goto out;
-                       if (iv_spc)
-                               build.hdr_len += build.key->conf.iv_len;
                }
 
                fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
index 1e26b52..9e6c4dc 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (C) 2015-2017     Intel Deutschland GmbH
- * Copyright (C) 2018-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  *
  * utilities for mac80211
  */
@@ -4212,74 +4212,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
-{
-       return !(cs == NULL || cs->cipher == 0 ||
-                cs->hdr_len < cs->pn_len + cs->pn_off ||
-                cs->hdr_len <= cs->key_idx_off ||
-                cs->key_idx_shift > 7 ||
-                cs->key_idx_mask == 0);
-}
-
-bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
-{
-       int i;
-
-       /* Ensure we have enough iftype bitmap space for all iftype values */
-       WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
-
-       for (i = 0; i < n; i++)
-               if (!ieee80211_cs_valid(&cs[i]))
-                       return false;
-
-       return true;
-}
-
-const struct ieee80211_cipher_scheme *
-ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
-                enum nl80211_iftype iftype)
-{
-       const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
-       int n = local->hw.n_cipher_schemes;
-       int i;
-       const struct ieee80211_cipher_scheme *cs = NULL;
-
-       for (i = 0; i < n; i++) {
-               if (l[i].cipher == cipher) {
-                       cs = &l[i];
-                       break;
-               }
-       }
-
-       if (!cs || !(cs->iftype & BIT(iftype)))
-               return NULL;
-
-       return cs;
-}
-
-int ieee80211_cs_headroom(struct ieee80211_local *local,
-                         struct cfg80211_crypto_settings *crypto,
-                         enum nl80211_iftype iftype)
-{
-       const struct ieee80211_cipher_scheme *cs;
-       int headroom = IEEE80211_ENCRYPT_HEADROOM;
-       int i;
-
-       for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
-               cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
-                                     iftype);
-
-               if (cs && headroom < cs->hdr_len)
-                       headroom = cs->hdr_len;
-       }
-
-       cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
-       if (cs && headroom < cs->hdr_len)
-               headroom = cs->hdr_len;
-
-       return headroom;
-}
-
 static bool
 ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
 {
index 5fd8a3e..93ec2f3 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright 2002-2004, Instant802 Networks, Inc.
  * Copyright 2008, Jouni Malinen <j@w1.fi>
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
- * Copyright (C) 2020-2021 Intel Corporation
+ * Copyright (C) 2020-2022 Intel Corporation
  */
 
 #include <linux/netdevice.h>
@@ -778,102 +778,6 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-static ieee80211_tx_result
-ieee80211_crypto_cs_encrypt(struct ieee80211_tx_data *tx,
-                           struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_key *key = tx->key;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       int hdrlen;
-       u8 *pos, iv_len = key->conf.iv_len;
-
-       if (info->control.hw_key &&
-           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
-               /* hwaccel has no need for preallocated head room */
-               return TX_CONTINUE;
-       }
-
-       if (unlikely(skb_headroom(skb) < iv_len &&
-                    pskb_expand_head(skb, iv_len, 0, GFP_ATOMIC)))
-               return TX_DROP;
-
-       hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
-       pos = skb_push(skb, iv_len);
-       memmove(pos, pos + iv_len, hdrlen);
-
-       return TX_CONTINUE;
-}
-
-static inline int ieee80211_crypto_cs_pn_compare(u8 *pn1, u8 *pn2, int len)
-{
-       int i;
-
-       /* pn is little endian */
-       for (i = len - 1; i >= 0; i--) {
-               if (pn1[i] < pn2[i])
-                       return -1;
-               else if (pn1[i] > pn2[i])
-                       return 1;
-       }
-
-       return 0;
-}
-
-static ieee80211_rx_result
-ieee80211_crypto_cs_decrypt(struct ieee80211_rx_data *rx)
-{
-       struct ieee80211_key *key = rx->key;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       const struct ieee80211_cipher_scheme *cs = NULL;
-       int hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
-       int data_len;
-       u8 *rx_pn;
-       u8 *skb_pn;
-       u8 qos_tid;
-
-       if (!rx->sta || !rx->sta->cipher_scheme ||
-           !(status->flag & RX_FLAG_DECRYPTED))
-               return RX_DROP_UNUSABLE;
-
-       if (!ieee80211_is_data(hdr->frame_control))
-               return RX_CONTINUE;
-
-       cs = rx->sta->cipher_scheme;
-
-       data_len = rx->skb->len - hdrlen - cs->hdr_len;
-
-       if (data_len < 0)
-               return RX_DROP_UNUSABLE;
-
-       if (ieee80211_is_data_qos(hdr->frame_control))
-               qos_tid = ieee80211_get_tid(hdr);
-       else
-               qos_tid = 0;
-
-       if (skb_linearize(rx->skb))
-               return RX_DROP_UNUSABLE;
-
-       rx_pn = key->u.gen.rx_pn[qos_tid];
-       skb_pn = rx->skb->data + hdrlen + cs->pn_off;
-
-       if (ieee80211_crypto_cs_pn_compare(skb_pn, rx_pn, cs->pn_len) <= 0)
-               return RX_DROP_UNUSABLE;
-
-       memcpy(rx_pn, skb_pn, cs->pn_len);
-
-       /* remove security header and MIC */
-       if (pskb_trim(rx->skb, rx->skb->len - cs->mic_len))
-               return RX_DROP_UNUSABLE;
-
-       memmove(rx->skb->data + cs->hdr_len, rx->skb->data, hdrlen);
-       skb_pull(rx->skb, cs->hdr_len);
-
-       return RX_CONTINUE;
-}
-
 static void bip_aad(struct sk_buff *skb, u8 *aad)
 {
        __le16 mask_fc;
@@ -1212,38 +1116,3 @@ ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx)
 
        return RX_CONTINUE;
 }
-
-ieee80211_tx_result
-ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx)
-{
-       struct sk_buff *skb;
-       struct ieee80211_tx_info *info = NULL;
-       ieee80211_tx_result res;
-
-       skb_queue_walk(&tx->skbs, skb) {
-               info  = IEEE80211_SKB_CB(skb);
-
-               /* handle hw-only algorithm */
-               if (!info->control.hw_key)
-                       return TX_DROP;
-
-               if (tx->key->flags & KEY_FLAG_CIPHER_SCHEME) {
-                       res = ieee80211_crypto_cs_encrypt(tx, skb);
-                       if (res != TX_CONTINUE)
-                               return res;
-               }
-       }
-
-       ieee80211_tx_set_protected(tx);
-
-       return TX_CONTINUE;
-}
-
-ieee80211_rx_result
-ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx)
-{
-       if (rx->sta && rx->sta->cipher_scheme)
-               return ieee80211_crypto_cs_decrypt(rx);
-
-       return RX_DROP_UNUSABLE;
-}
index af32722..a9a81ab 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright (C) 2022 Intel Corporation
  */
 
 #ifndef WPA_H
@@ -39,10 +40,6 @@ ieee80211_tx_result
 ieee80211_crypto_aes_gmac_encrypt(struct ieee80211_tx_data *tx);
 ieee80211_rx_result
 ieee80211_crypto_aes_gmac_decrypt(struct ieee80211_rx_data *rx);
-ieee80211_tx_result
-ieee80211_crypto_hw_encrypt(struct ieee80211_tx_data *tx);
-ieee80211_rx_result
-ieee80211_crypto_hw_decrypt(struct ieee80211_rx_data *rx);
 
 ieee80211_tx_result
 ieee80211_crypto_gcmp_encrypt(struct ieee80211_tx_data *tx);
index 7c7395b..5bdb559 100644 (file)
@@ -1134,7 +1134,7 @@ void mptcp_pm_nl_subflow_chk_stale(const struct mptcp_sock *msk, struct sock *ss
                        }
                        unlock_sock_fast(ssk, slow);
 
-                       /* always try to push the pending data regarless of re-injections:
+                       /* always try to push the pending data regardless of re-injections:
                         * we can possibly use backup subflows now, and subflow selection
                         * is cheap under the msk socket lock
                         */
index cc21faf..2caad4a 100644 (file)
@@ -167,8 +167,8 @@ static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff *to,
 
 static void __mptcp_rmem_reclaim(struct sock *sk, int amount)
 {
-       amount >>= SK_MEM_QUANTUM_SHIFT;
-       mptcp_sk(sk)->rmem_fwd_alloc -= amount << SK_MEM_QUANTUM_SHIFT;
+       amount >>= PAGE_SHIFT;
+       mptcp_sk(sk)->rmem_fwd_alloc -= amount << PAGE_SHIFT;
        __sk_mem_reduce_allocated(sk, amount);
 }
 
@@ -181,8 +181,8 @@ static void mptcp_rmem_uncharge(struct sock *sk, int size)
        reclaimable = msk->rmem_fwd_alloc - sk_unused_reserved_mem(sk);
 
        /* see sk_mem_uncharge() for the rationale behind the following schema */
-       if (unlikely(reclaimable >= SK_RECLAIM_THRESHOLD))
-               __mptcp_rmem_reclaim(sk, SK_RECLAIM_CHUNK);
+       if (unlikely(reclaimable >= PAGE_SIZE))
+               __mptcp_rmem_reclaim(sk, reclaimable);
 }
 
 static void mptcp_rfree(struct sk_buff *skb)
@@ -323,20 +323,16 @@ static bool mptcp_rmem_schedule(struct sock *sk, struct sock *ssk, int size)
        struct mptcp_sock *msk = mptcp_sk(sk);
        int amt, amount;
 
-       if (size < msk->rmem_fwd_alloc)
+       if (size <= msk->rmem_fwd_alloc)
                return true;
 
+       size -= msk->rmem_fwd_alloc;
        amt = sk_mem_pages(size);
-       amount = amt << SK_MEM_QUANTUM_SHIFT;
-       msk->rmem_fwd_alloc += amount;
-       if (!__sk_mem_raise_allocated(sk, size, amt, SK_MEM_RECV)) {
-               if (ssk->sk_forward_alloc < amount) {
-                       msk->rmem_fwd_alloc -= amount;
-                       return false;
-               }
+       amount = amt << PAGE_SHIFT;
+       if (!__sk_mem_raise_allocated(sk, size, amt, SK_MEM_RECV))
+               return false;
 
-               ssk->sk_forward_alloc -= amount;
-       }
+       msk->rmem_fwd_alloc += amount;
        return true;
 }
 
@@ -971,25 +967,6 @@ static bool mptcp_frag_can_collapse_to(const struct mptcp_sock *msk,
                df->data_seq + df->data_len == msk->write_seq;
 }
 
-static void __mptcp_mem_reclaim_partial(struct sock *sk)
-{
-       int reclaimable = mptcp_sk(sk)->rmem_fwd_alloc - sk_unused_reserved_mem(sk);
-
-       lockdep_assert_held_once(&sk->sk_lock.slock);
-
-       if (reclaimable > SK_MEM_QUANTUM)
-               __mptcp_rmem_reclaim(sk, reclaimable - 1);
-
-       sk_mem_reclaim_partial(sk);
-}
-
-static void mptcp_mem_reclaim_partial(struct sock *sk)
-{
-       mptcp_data_lock(sk);
-       __mptcp_mem_reclaim_partial(sk);
-       mptcp_data_unlock(sk);
-}
-
 static void dfrag_uncharge(struct sock *sk, int len)
 {
        sk_mem_uncharge(sk, len);
@@ -1009,7 +986,6 @@ static void __mptcp_clean_una(struct sock *sk)
 {
        struct mptcp_sock *msk = mptcp_sk(sk);
        struct mptcp_data_frag *dtmp, *dfrag;
-       bool cleaned = false;
        u64 snd_una;
 
        /* on fallback we just need to ignore snd_una, as this is really
@@ -1032,7 +1008,6 @@ static void __mptcp_clean_una(struct sock *sk)
                }
 
                dfrag_clear(sk, dfrag);
-               cleaned = true;
        }
 
        dfrag = mptcp_rtx_head(sk);
@@ -1054,7 +1029,6 @@ static void __mptcp_clean_una(struct sock *sk)
                dfrag->already_sent -= delta;
 
                dfrag_uncharge(sk, delta);
-               cleaned = true;
        }
 
        /* all retransmitted data acked, recovery completed */
@@ -1062,9 +1036,6 @@ static void __mptcp_clean_una(struct sock *sk)
                msk->recovery = false;
 
 out:
-       if (cleaned && tcp_under_memory_pressure(sk))
-               __mptcp_mem_reclaim_partial(sk);
-
        if (snd_una == READ_ONCE(msk->snd_nxt) &&
            snd_una == READ_ONCE(msk->write_seq)) {
                if (mptcp_timer_pending(sk) && !mptcp_data_fin_enabled(msk))
@@ -1216,12 +1187,6 @@ static struct sk_buff *mptcp_alloc_tx_skb(struct sock *sk, struct sock *ssk, boo
 {
        gfp_t gfp = data_lock_held ? GFP_ATOMIC : sk->sk_allocation;
 
-       if (unlikely(tcp_under_memory_pressure(sk))) {
-               if (data_lock_held)
-                       __mptcp_mem_reclaim_partial(sk);
-               else
-                       mptcp_mem_reclaim_partial(sk);
-       }
        return __mptcp_alloc_tx_skb(sk, ssk, gfp);
 }
 
@@ -3464,7 +3429,10 @@ static struct proto mptcp_prot = {
        .get_port       = mptcp_get_port,
        .forward_alloc_get      = mptcp_forward_alloc_get,
        .sockets_allocated      = &mptcp_sockets_allocated,
+
        .memory_allocated       = &tcp_memory_allocated,
+       .per_cpu_fw_alloc       = &tcp_memory_per_cpu_fw_alloc,
+
        .memory_pressure        = &tcp_memory_pressure,
        .sysctl_wmem_offset     = offsetof(struct net, ipv4.sysctl_tcp_wmem),
        .sysctl_rmem_offset     = offsetof(struct net, ipv4.sysctl_tcp_rmem),
index 63e8892..d4b16d0 100644 (file)
@@ -1634,7 +1634,7 @@ int mptcp_subflow_create_socket(struct sock *sk, struct socket **new_sock)
        /* the newly created socket really belongs to the owning MPTCP master
         * socket, even if for additional subflows the allocation is performed
         * by a kernel workqueue. Adjust inode references, so that the
-        * procfs/diag interaces really show this one belonging to the correct
+        * procfs/diag interfaces really show this one belonging to the correct
         * user.
         */
        SOCK_INODE(sf)->i_ino = SOCK_INODE(sk->sk_socket)->i_ino;
index b498dac..2f61d5b 100644 (file)
@@ -115,7 +115,7 @@ error_master_upper_dev_unlink:
 error_unlock:
        rtnl_unlock();
 error_put:
-       dev_put_track(vport->dev, &vport->dev_tracker);
+       netdev_put(vport->dev, &vport->dev_tracker);
 error_free_vport:
        ovs_vport_free(vport);
        return ERR_PTR(err);
@@ -137,7 +137,7 @@ static void vport_netdev_free(struct rcu_head *rcu)
 {
        struct vport *vport = container_of(rcu, struct vport, rcu);
 
-       dev_put_track(vport->dev, &vport->dev_tracker);
+       netdev_put(vport->dev, &vport->dev_tracker);
        ovs_vport_free(vport);
 }
 
@@ -173,7 +173,7 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
         */
        if (vport->dev->reg_state == NETREG_REGISTERED)
                rtnl_delete_link(vport->dev);
-       dev_put_track(vport->dev, &vport->dev_tracker);
+       netdev_put(vport->dev, &vport->dev_tracker);
        vport->dev = NULL;
        rtnl_unlock();
 
index ca6e92a..d08c472 100644 (file)
@@ -3134,7 +3134,7 @@ static int packet_release(struct socket *sock)
        packet_cached_dev_reset(po);
 
        if (po->prot_hook.dev) {
-               dev_put_track(po->prot_hook.dev, &po->prot_hook.dev_tracker);
+               netdev_put(po->prot_hook.dev, &po->prot_hook.dev_tracker);
                po->prot_hook.dev = NULL;
        }
        spin_unlock(&po->bind_lock);
@@ -3235,15 +3235,15 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
                WRITE_ONCE(po->num, proto);
                po->prot_hook.type = proto;
 
-               dev_put_track(po->prot_hook.dev, &po->prot_hook.dev_tracker);
+               netdev_put(po->prot_hook.dev, &po->prot_hook.dev_tracker);
 
                if (unlikely(unlisted)) {
                        po->prot_hook.dev = NULL;
                        WRITE_ONCE(po->ifindex, -1);
                        packet_cached_dev_reset(po);
                } else {
-                       dev_hold_track(dev, &po->prot_hook.dev_tracker,
-                                      GFP_ATOMIC);
+                       netdev_hold(dev, &po->prot_hook.dev_tracker,
+                                   GFP_ATOMIC);
                        po->prot_hook.dev = dev;
                        WRITE_ONCE(po->ifindex, dev ? dev->ifindex : 0);
                        packet_cached_dev_assign(po, dev);
@@ -4167,8 +4167,8 @@ static int packet_notifier(struct notifier_block *this,
                                if (msg == NETDEV_UNREGISTER) {
                                        packet_cached_dev_reset(po);
                                        WRITE_ONCE(po->ifindex, -1);
-                                       dev_put_track(po->prot_hook.dev,
-                                                     &po->prot_hook.dev_tracker);
+                                       netdev_put(po->prot_hook.dev,
+                                                  &po->prot_hook.dev_tracker);
                                        po->prot_hook.dev = NULL;
                                }
                                spin_unlock(&po->bind_lock);
index ebb92fb..a1d70cf 100644 (file)
@@ -79,7 +79,7 @@ static void tcf_mirred_release(struct tc_action *a)
 
        /* last reference to action, no need to lock */
        dev = rcu_dereference_protected(m->tcfm_dev, 1);
-       dev_put_track(dev, &m->tcfm_dev_tracker);
+       netdev_put(dev, &m->tcfm_dev_tracker);
 }
 
 static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
@@ -181,7 +181,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                mac_header_xmit = dev_is_mac_header_xmit(ndev);
                odev = rcu_replace_pointer(m->tcfm_dev, ndev,
                                          lockdep_is_held(&m->tcf_lock));
-               dev_put_track(odev, &m->tcfm_dev_tracker);
+               netdev_put(odev, &m->tcfm_dev_tracker);
                netdev_tracker_alloc(ndev, &m->tcfm_dev_tracker, GFP_ATOMIC);
                m->tcfm_mac_header_xmit = mac_header_xmit;
        }
@@ -402,7 +402,7 @@ static int mirred_device_event(struct notifier_block *unused,
                list_for_each_entry(m, &mirred_list, tcfm_list) {
                        spin_lock_bh(&m->tcf_lock);
                        if (tcf_mirred_dev_dereference(m) == dev) {
-                               dev_put_track(dev, &m->tcfm_dev_tracker);
+                               netdev_put(dev, &m->tcfm_dev_tracker);
                                /* Note : no rcu grace period necessary, as
                                 * net_device are already rcu protected.
                                 */
index e3c0e8e..bf87b50 100644 (file)
@@ -1292,7 +1292,7 @@ err_out5:
        if (ops->destroy)
                ops->destroy(sch);
 err_out3:
-       dev_put_track(dev, &sch->dev_tracker);
+       netdev_put(dev, &sch->dev_tracker);
        qdisc_free(sch);
 err_out2:
        module_put(ops->owner);
index dba0b3e..cc6eabe 100644 (file)
@@ -541,7 +541,7 @@ static void dev_watchdog(struct timer_list *t)
        spin_unlock(&dev->tx_global_lock);
 
        if (release)
-               dev_put_track(dev, &dev->watchdog_dev_tracker);
+               netdev_put(dev, &dev->watchdog_dev_tracker);
 }
 
 void __netdev_watchdog_up(struct net_device *dev)
@@ -551,7 +551,8 @@ void __netdev_watchdog_up(struct net_device *dev)
                        dev->watchdog_timeo = 5*HZ;
                if (!mod_timer(&dev->watchdog_timer,
                               round_jiffies(jiffies + dev->watchdog_timeo)))
-                       dev_hold_track(dev, &dev->watchdog_dev_tracker, GFP_ATOMIC);
+                       netdev_hold(dev, &dev->watchdog_dev_tracker,
+                                   GFP_ATOMIC);
        }
 }
 EXPORT_SYMBOL_GPL(__netdev_watchdog_up);
@@ -565,7 +566,7 @@ static void dev_watchdog_down(struct net_device *dev)
 {
        netif_tx_lock_bh(dev);
        if (del_timer(&dev->watchdog_timer))
-               dev_put_track(dev, &dev->watchdog_dev_tracker);
+               netdev_put(dev, &dev->watchdog_dev_tracker);
        netif_tx_unlock_bh(dev);
 }
 
@@ -975,7 +976,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
        sch->enqueue = ops->enqueue;
        sch->dequeue = ops->dequeue;
        sch->dev_queue = dev_queue;
-       dev_hold_track(dev, &sch->dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &sch->dev_tracker, GFP_KERNEL);
        refcount_set(&sch->refcnt, 1);
 
        return sch;
@@ -1067,7 +1068,7 @@ static void qdisc_destroy(struct Qdisc *qdisc)
                ops->destroy(qdisc);
 
        module_put(ops->owner);
-       dev_put_track(qdisc_dev(qdisc), &qdisc->dev_tracker);
+       netdev_put(qdisc_dev(qdisc), &qdisc->dev_tracker);
 
        trace_qdisc_destroy(qdisc);
 
index b9c71a3..0b941dd 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
+#include <linux/time.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <net/pkt_cls.h>
@@ -176,7 +177,7 @@ static ktime_t get_interval_end_time(struct sched_gate_list *sched,
 
 static int length_to_duration(struct taprio_sched *q, int len)
 {
-       return div_u64(len * atomic64_read(&q->picos_per_byte), 1000);
+       return div_u64(len * atomic64_read(&q->picos_per_byte), PSEC_PER_NSEC);
 }
 
 /* Returns the entry corresponding to next available interval. If
@@ -551,7 +552,7 @@ static struct sk_buff *taprio_peek(struct Qdisc *sch)
 static void taprio_set_budget(struct taprio_sched *q, struct sched_entry *entry)
 {
        atomic_set(&entry->budget,
-                  div64_u64((u64)entry->interval * 1000,
+                  div64_u64((u64)entry->interval * PSEC_PER_NSEC,
                             atomic64_read(&q->picos_per_byte)));
 }
 
index 35928fe..fa500ea 100644 (file)
@@ -1523,11 +1523,11 @@ static __init int sctp_init(void)
        limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7);
        max_share = min(4UL*1024*1024, limit);
 
-       sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */
+       sysctl_sctp_rmem[0] = PAGE_SIZE; /* give each asoc 1 page min */
        sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1);
        sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share);
 
-       sysctl_sctp_wmem[0] = SK_MEM_QUANTUM;
+       sysctl_sctp_wmem[0] = PAGE_SIZE;
        sysctl_sctp_wmem[1] = 16*1024;
        sysctl_sctp_wmem[2] = max(64*1024, max_share);
 
index 52edee1..f6ee7f4 100644 (file)
@@ -6590,8 +6590,6 @@ static int sctp_eat_data(const struct sctp_association *asoc,
                        pr_debug("%s: under pressure, reneging for tsn:%u\n",
                                 __func__, tsn);
                        deliver = SCTP_CMD_RENEGE;
-               } else {
-                       sk_mem_reclaim(sk);
                }
        }
 
index 6d37d2d..171f1a3 100644 (file)
@@ -93,6 +93,7 @@ static int sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
 
 static unsigned long sctp_memory_pressure;
 static atomic_long_t sctp_memory_allocated;
+static DEFINE_PER_CPU(int, sctp_memory_per_cpu_fw_alloc);
 struct percpu_counter sctp_sockets_allocated;
 
 static void sctp_enter_memory_pressure(struct sock *sk)
@@ -1823,9 +1824,6 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc,
        if (sctp_wspace(asoc) < (int)msg_len)
                sctp_prsctp_prune(asoc, sinfo, msg_len - sctp_wspace(asoc));
 
-       if (sk_under_memory_pressure(sk))
-               sk_mem_reclaim(sk);
-
        if (sctp_wspace(asoc) <= 0 || !sk_wmem_schedule(sk, msg_len)) {
                timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
                err = sctp_wait_for_sndbuf(asoc, &timeo, msg_len);
@@ -9194,8 +9192,6 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                        goto do_error;
                if (signal_pending(current))
                        goto do_interrupted;
-               if (sk_under_memory_pressure(sk))
-                       sk_mem_reclaim(sk);
                if ((int)msg_len <= sctp_wspace(asoc) &&
                    sk_wmem_schedule(sk, msg_len))
                        break;
@@ -9657,7 +9653,10 @@ struct proto sctp_prot = {
        .sysctl_wmem =  sysctl_sctp_wmem,
        .memory_pressure = &sctp_memory_pressure,
        .enter_memory_pressure = sctp_enter_memory_pressure,
+
        .memory_allocated = &sctp_memory_allocated,
+       .per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc,
+
        .sockets_allocated = &sctp_sockets_allocated,
 };
 
@@ -9700,7 +9699,10 @@ struct proto sctpv6_prot = {
        .sysctl_wmem    = sysctl_sctp_wmem,
        .memory_pressure = &sctp_memory_pressure,
        .enter_memory_pressure = sctp_enter_memory_pressure,
+
        .memory_allocated = &sctp_memory_allocated,
+       .per_cpu_fw_alloc = &sctp_memory_per_cpu_fw_alloc,
+
        .sockets_allocated = &sctp_sockets_allocated,
 };
 #endif /* IS_ENABLED(CONFIG_IPV6) */
index 6b13f73..bb22b71 100644 (file)
@@ -979,8 +979,6 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
 
        if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0)
                sctp_intl_start_pd(ulpq, gfp);
-
-       sk_mem_reclaim(asoc->base.sk);
 }
 
 static void sctp_intl_stream_abort_pd(struct sctp_ulpq *ulpq, __u16 sid,
index 407fed4..0a8510a 100644 (file)
@@ -1100,12 +1100,8 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
                else if (retval == 1)
                        sctp_ulpq_reasm_drain(ulpq);
        }
-
-       sk_mem_reclaim(asoc->base.sk);
 }
 
-
-
 /* Notify the application if an association is aborted and in
  * partial delivery mode.  Send up any pending received messages.
  */
index 7055ed1..4c3bf6d 100644 (file)
@@ -120,7 +120,8 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
                    smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
                        list_del(&pnetelem->list);
                        if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev) {
-                               dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
+                               netdev_put(pnetelem->ndev,
+                                          &pnetelem->dev_tracker);
                                pr_warn_ratelimited("smc: net device %s "
                                                    "erased user defined "
                                                    "pnetid %.16s\n",
@@ -196,7 +197,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev)
        list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
                if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev &&
                    !strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) {
-                       dev_hold_track(ndev, &pnetelem->dev_tracker, GFP_ATOMIC);
+                       netdev_hold(ndev, &pnetelem->dev_tracker, GFP_ATOMIC);
                        pnetelem->ndev = ndev;
                        rc = 0;
                        pr_warn_ratelimited("smc: adding net device %s with "
@@ -227,7 +228,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
        mutex_lock(&pnettable->lock);
        list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
                if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) {
-                       dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
+                       netdev_put(pnetelem->ndev, &pnetelem->dev_tracker);
                        pnetelem->ndev = NULL;
                        rc = 0;
                        pr_warn_ratelimited("smc: removing net device %s with "
index 96300cd..3d7eb2a 100644 (file)
@@ -1878,10 +1878,8 @@ out_fd:
        return ERR_PTR(err);
 }
 
-int __sys_accept4_file(struct file *file, unsigned file_flags,
-                      struct sockaddr __user *upeer_sockaddr,
-                      int __user *upeer_addrlen, int flags,
-                      unsigned long nofile)
+static int __sys_accept4_file(struct file *file, struct sockaddr __user *upeer_sockaddr,
+                             int __user *upeer_addrlen, int flags)
 {
        struct file *newfile;
        int newfd;
@@ -1892,11 +1890,11 @@ int __sys_accept4_file(struct file *file, unsigned file_flags,
        if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
                flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
 
-       newfd = __get_unused_fd_flags(flags, nofile);
+       newfd = get_unused_fd_flags(flags);
        if (unlikely(newfd < 0))
                return newfd;
 
-       newfile = do_accept(file, file_flags, upeer_sockaddr, upeer_addrlen,
+       newfile = do_accept(file, 0, upeer_sockaddr, upeer_addrlen,
                            flags);
        if (IS_ERR(newfile)) {
                put_unused_fd(newfd);
@@ -1926,9 +1924,8 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
 
        f = fdget(fd);
        if (f.file) {
-               ret = __sys_accept4_file(f.file, 0, upeer_sockaddr,
-                                               upeer_addrlen, flags,
-                                               rlimit(RLIMIT_NOFILE));
+               ret = __sys_accept4_file(f.file, upeer_sockaddr,
+                                        upeer_addrlen, flags);
                fdput(f);
        }
 
index 474f763..8cc42ae 100644 (file)
@@ -64,7 +64,7 @@ void switchdev_deferred_process(void)
 
        while ((dfitem = switchdev_deferred_dequeue())) {
                dfitem->func(dfitem->dev, dfitem->data);
-               dev_put_track(dfitem->dev, &dfitem->dev_tracker);
+               netdev_put(dfitem->dev, &dfitem->dev_tracker);
                kfree(dfitem);
        }
 }
@@ -91,7 +91,7 @@ static int switchdev_deferred_enqueue(struct net_device *dev,
        dfitem->dev = dev;
        dfitem->func = func;
        memcpy(dfitem->data, data, data_len);
-       dev_hold_track(dev, &dfitem->dev_tracker, GFP_ATOMIC);
+       netdev_hold(dev, &dfitem->dev_tracker, GFP_ATOMIC);
        spin_lock_bh(&deferred_lock);
        list_add_tail(&dfitem->list, &deferred);
        spin_unlock_bh(&deferred_lock);
index 932c87b..35cac77 100644 (file)
@@ -788,7 +788,7 @@ int tipc_attach_loopback(struct net *net)
        if (!dev)
                return -ENODEV;
 
-       dev_hold_track(dev, &tn->loopback_pt.dev_tracker, GFP_KERNEL);
+       netdev_hold(dev, &tn->loopback_pt.dev_tracker, GFP_KERNEL);
        tn->loopback_pt.dev = dev;
        tn->loopback_pt.type = htons(ETH_P_TIPC);
        tn->loopback_pt.func = tipc_loopback_rcv_pkt;
@@ -801,7 +801,7 @@ void tipc_detach_loopback(struct net *net)
        struct tipc_net *tn = tipc_net(net);
 
        dev_remove_pack(&tn->loopback_pt);
-       dev_put_track(net->loopback_dev, &tn->loopback_pt.dev_tracker);
+       netdev_put(net->loopback_dev, &tn->loopback_pt.dev_tracker);
 }
 
 /* Caller should hold rtnl_lock to protect the bearer */
index 1d8ba23..d118037 100644 (file)
@@ -1202,14 +1202,3 @@ void tipc_dest_list_purge(struct list_head *l)
                kfree(dst);
        }
 }
-
-int tipc_dest_list_len(struct list_head *l)
-{
-       struct tipc_dest *dst;
-       int i = 0;
-
-       list_for_each_entry(dst, l, list) {
-               i++;
-       }
-       return i;
-}
index 259f95e..3bcd9ef 100644 (file)
@@ -151,6 +151,5 @@ bool tipc_dest_push(struct list_head *l, u32 node, u32 port);
 bool tipc_dest_pop(struct list_head *l, u32 *node, u32 *port);
 bool tipc_dest_del(struct list_head *l, u32 node, u32 port);
 void tipc_dest_list_purge(struct list_head *l);
-int tipc_dest_list_len(struct list_head *l);
 
 #endif
index e40bedd..3bae29a 100644 (file)
@@ -232,7 +232,7 @@ static int fill_sg_in(struct scatterlist *sg_in,
                      s32 *sync_size,
                      int *resync_sgs)
 {
-       int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       int tcp_payload_offset = skb_tcp_all_headers(skb);
        int payload_len = skb->len - tcp_payload_offset;
        u32 tcp_seq = ntohl(tcp_hdr(skb)->seq);
        struct tls_record_info *record;
@@ -310,8 +310,8 @@ static struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx,
                                   struct sk_buff *skb,
                                   s32 sync_size, u64 rcd_sn)
 {
-       int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
        struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
+       int tcp_payload_offset = skb_tcp_all_headers(skb);
        int payload_len = skb->len - tcp_payload_offset;
        void *buf, *iv, *aad, *dummy_buf;
        struct aead_request *aead_req;
@@ -372,7 +372,7 @@ free_nskb:
 
 static struct sk_buff *tls_sw_fallback(struct sock *sk, struct sk_buff *skb)
 {
-       int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
+       int tcp_payload_offset = skb_tcp_all_headers(skb);
        struct tls_context *tls_ctx = tls_get_ctx(sk);
        struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
        int payload_len = skb->len - tcp_payload_offset;
index 2ffede4..1b3efc9 100644 (file)
@@ -533,6 +533,37 @@ static int do_tls_getsockopt_tx_zc(struct sock *sk, char __user *optval,
        return 0;
 }
 
+static int do_tls_getsockopt_no_pad(struct sock *sk, char __user *optval,
+                                   int __user *optlen)
+{
+       struct tls_context *ctx = tls_get_ctx(sk);
+       unsigned int value;
+       int err, len;
+
+       if (ctx->prot_info.version != TLS_1_3_VERSION)
+               return -EINVAL;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+       if (len < sizeof(value))
+               return -EINVAL;
+
+       lock_sock(sk);
+       err = -EINVAL;
+       if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW)
+               value = ctx->rx_no_pad;
+       release_sock(sk);
+       if (err)
+               return err;
+
+       if (put_user(sizeof(value), optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &value, sizeof(value)))
+               return -EFAULT;
+
+       return 0;
+}
+
 static int do_tls_getsockopt(struct sock *sk, int optname,
                             char __user *optval, int __user *optlen)
 {
@@ -547,6 +578,9 @@ static int do_tls_getsockopt(struct sock *sk, int optname,
        case TLS_TX_ZEROCOPY_RO:
                rc = do_tls_getsockopt_tx_zc(sk, optval, optlen);
                break;
+       case TLS_RX_EXPECT_NO_PAD:
+               rc = do_tls_getsockopt_no_pad(sk, optval, optlen);
+               break;
        default:
                rc = -ENOPROTOOPT;
                break;
@@ -718,6 +752,38 @@ static int do_tls_setsockopt_tx_zc(struct sock *sk, sockptr_t optval,
        return 0;
 }
 
+static int do_tls_setsockopt_no_pad(struct sock *sk, sockptr_t optval,
+                                   unsigned int optlen)
+{
+       struct tls_context *ctx = tls_get_ctx(sk);
+       u32 val;
+       int rc;
+
+       if (ctx->prot_info.version != TLS_1_3_VERSION ||
+           sockptr_is_null(optval) || optlen < sizeof(val))
+               return -EINVAL;
+
+       rc = copy_from_sockptr(&val, optval, sizeof(val));
+       if (rc)
+               return -EFAULT;
+       if (val > 1)
+               return -EINVAL;
+       rc = check_zeroed_sockptr(optval, sizeof(val), optlen - sizeof(val));
+       if (rc < 1)
+               return rc == 0 ? -EINVAL : rc;
+
+       lock_sock(sk);
+       rc = -EINVAL;
+       if (ctx->rx_conf == TLS_SW || ctx->rx_conf == TLS_HW) {
+               ctx->rx_no_pad = val;
+               tls_update_rx_zc_capable(ctx);
+               rc = 0;
+       }
+       release_sock(sk);
+
+       return rc;
+}
+
 static int do_tls_setsockopt(struct sock *sk, int optname, sockptr_t optval,
                             unsigned int optlen)
 {
@@ -736,6 +802,9 @@ static int do_tls_setsockopt(struct sock *sk, int optname, sockptr_t optval,
                rc = do_tls_setsockopt_tx_zc(sk, optval, optlen);
                release_sock(sk);
                break;
+       case TLS_RX_EXPECT_NO_PAD:
+               rc = do_tls_setsockopt_no_pad(sk, optval, optlen);
+               break;
        default:
                rc = -ENOPROTOOPT;
                break;
@@ -976,6 +1045,11 @@ static int tls_get_info(const struct sock *sk, struct sk_buff *skb)
                if (err)
                        goto nla_failure;
        }
+       if (ctx->rx_no_pad) {
+               err = nla_put_flag(skb, TLS_INFO_RX_NO_PAD);
+               if (err)
+                       goto nla_failure;
+       }
 
        rcu_read_unlock();
        nla_nest_end(skb, start);
@@ -997,6 +1071,7 @@ static size_t tls_get_info_size(const struct sock *sk)
                nla_total_size(sizeof(u16)) +   /* TLS_INFO_RXCONF */
                nla_total_size(sizeof(u16)) +   /* TLS_INFO_TXCONF */
                nla_total_size(0) +             /* TLS_INFO_ZC_RO_TX */
+               nla_total_size(0) +             /* TLS_INFO_RX_NO_PAD */
                0;
 
        return size;
index feeceb0..0c20000 100644 (file)
@@ -18,6 +18,7 @@ static const struct snmp_mib tls_mib_list[] = {
        SNMP_MIB_ITEM("TlsRxDevice", LINUX_MIB_TLSRXDEVICE),
        SNMP_MIB_ITEM("TlsDecryptError", LINUX_MIB_TLSDECRYPTERROR),
        SNMP_MIB_ITEM("TlsRxDeviceResync", LINUX_MIB_TLSRXDEVICERESYNC),
+       SNMP_MIB_ITEM("TlsDecryptRetry", LINUX_MIN_TLSDECRYPTRETRY),
        SNMP_MIB_SENTINEL
 };
 
index e30649f..f1777d6 100644 (file)
@@ -47,6 +47,7 @@
 struct tls_decrypt_arg {
        bool zc;
        bool async;
+       u8 tail;
 };
 
 noinline void tls_err_abort(struct sock *sk, int err)
@@ -133,7 +134,8 @@ static int skb_nsg(struct sk_buff *skb, int offset, int len)
         return __skb_nsg(skb, offset, len, 0);
 }
 
-static int padding_length(struct tls_prot_info *prot, struct sk_buff *skb)
+static int tls_padding_length(struct tls_prot_info *prot, struct sk_buff *skb,
+                             struct tls_decrypt_arg *darg)
 {
        struct strp_msg *rxm = strp_msg(skb);
        struct tls_msg *tlm = tls_msg(skb);
@@ -142,7 +144,7 @@ static int padding_length(struct tls_prot_info *prot, struct sk_buff *skb)
        /* Determine zero-padding length */
        if (prot->version == TLS_1_3_VERSION) {
                int offset = rxm->full_len - TLS_TAG_SIZE - 1;
-               char content_type = 0;
+               char content_type = darg->zc ? darg->tail : 0;
                int err;
 
                while (content_type == 0) {
@@ -1415,18 +1417,18 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
        struct strp_msg *rxm = strp_msg(skb);
        struct tls_msg *tlm = tls_msg(skb);
        int n_sgin, n_sgout, nsg, mem_size, aead_size, err, pages = 0;
+       u8 *aad, *iv, *tail, *mem = NULL;
        struct aead_request *aead_req;
        struct sk_buff *unused;
-       u8 *aad, *iv, *mem = NULL;
        struct scatterlist *sgin = NULL;
        struct scatterlist *sgout = NULL;
-       const int data_len = rxm->full_len - prot->overhead_size +
-                            prot->tail_size;
+       const int data_len = rxm->full_len - prot->overhead_size;
+       int tail_pages = !!prot->tail_size;
        int iv_offset = 0;
 
        if (darg->zc && (out_iov || out_sg)) {
                if (out_iov)
-                       n_sgout = 1 +
+                       n_sgout = 1 + tail_pages +
                                iov_iter_npages_cap(out_iov, INT_MAX, data_len);
                else
                        n_sgout = sg_nents(out_sg);
@@ -1450,9 +1452,10 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
        mem_size = aead_size + (nsg * sizeof(struct scatterlist));
        mem_size = mem_size + prot->aad_size;
        mem_size = mem_size + MAX_IV_SIZE;
+       mem_size = mem_size + prot->tail_size;
 
        /* Allocate a single block of memory which contains
-        * aead_req || sgin[] || sgout[] || aad || iv.
+        * aead_req || sgin[] || sgout[] || aad || iv || tail.
         * This order achieves correct alignment for aead_req, sgin, sgout.
         */
        mem = kmalloc(mem_size, sk->sk_allocation);
@@ -1465,6 +1468,7 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
        sgout = sgin + n_sgin;
        aad = (u8 *)(sgout + n_sgout);
        iv = aad + prot->aad_size;
+       tail = iv + MAX_IV_SIZE;
 
        /* For CCM based ciphers, first byte of nonce+iv is a constant */
        switch (prot->cipher_type) {
@@ -1518,9 +1522,16 @@ static int decrypt_internal(struct sock *sk, struct sk_buff *skb,
 
                        err = tls_setup_from_iter(out_iov, data_len,
                                                  &pages, &sgout[1],
-                                                 (n_sgout - 1));
+                                                 (n_sgout - 1 - tail_pages));
                        if (err < 0)
                                goto fallback_to_reg_recv;
+
+                       if (prot->tail_size) {
+                               sg_unmark_end(&sgout[pages]);
+                               sg_set_buf(&sgout[pages + 1], tail,
+                                          prot->tail_size);
+                               sg_mark_end(&sgout[pages + 1]);
+                       }
                } else if (out_sg) {
                        memcpy(sgout, out_sg, n_sgout * sizeof(*sgout));
                } else {
@@ -1535,10 +1546,13 @@ fallback_to_reg_recv:
 
        /* Prepare and submit AEAD request */
        err = tls_do_decryption(sk, skb, sgin, sgout, iv,
-                               data_len, aead_req, darg);
+                               data_len + prot->tail_size, aead_req, darg);
        if (darg->async)
                return 0;
 
+       if (prot->tail_size)
+               darg->tail = *tail;
+
        /* Release the pages in case iov was mapped to pages */
        for (; pages > 0; pages--)
                put_page(sg_page(&sgout[pages]));
@@ -1583,9 +1597,16 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb,
        }
        if (darg->async)
                goto decrypt_next;
+       /* If opportunistic TLS 1.3 ZC failed retry without ZC */
+       if (unlikely(darg->zc && prot->version == TLS_1_3_VERSION &&
+                    darg->tail != TLS_RECORD_TYPE_DATA)) {
+               darg->zc = false;
+               TLS_INC_STATS(sock_net(sk), LINUX_MIN_TLSDECRYPTRETRY);
+               return decrypt_skb_update(sk, skb, dest, darg);
+       }
 
 decrypt_done:
-       pad = padding_length(prot, skb);
+       pad = tls_padding_length(prot, skb, darg);
        if (pad < 0)
                return pad;
 
@@ -1717,6 +1738,24 @@ out:
        return copied ? : err;
 }
 
+static void
+tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot,
+                      size_t len_left, size_t decrypted, ssize_t done,
+                      size_t *flushed_at)
+{
+       size_t max_rec;
+
+       if (len_left <= decrypted)
+               return;
+
+       max_rec = prot->overhead_size - prot->tail_size + TLS_MAX_PAYLOAD_SIZE;
+       if (done - *flushed_at < SZ_128K && tcp_inq(sk) > max_rec)
+               return;
+
+       *flushed_at = done;
+       sk_flush_backlog(sk);
+}
+
 int tls_sw_recvmsg(struct sock *sk,
                   struct msghdr *msg,
                   size_t len,
@@ -1729,6 +1768,7 @@ int tls_sw_recvmsg(struct sock *sk,
        struct sk_psock *psock;
        unsigned char control = 0;
        ssize_t decrypted = 0;
+       size_t flushed_at = 0;
        struct strp_msg *rxm;
        struct tls_msg *tlm;
        struct sk_buff *skb;
@@ -1767,7 +1807,7 @@ int tls_sw_recvmsg(struct sock *sk,
        timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
 
        zc_capable = !bpf_strp_enabled && !is_kvec && !is_peek &&
-                    prot->version != TLS_1_3_VERSION;
+               ctx->zc_capable;
        decrypted = 0;
        while (len && (decrypted + copied < target || ctx->recv_pkt)) {
                struct tls_decrypt_arg darg = {};
@@ -1818,6 +1858,10 @@ int tls_sw_recvmsg(struct sock *sk,
                if (err <= 0)
                        goto recv_end;
 
+               /* periodically flush backlog, and feed strparser */
+               tls_read_flush_backlog(sk, prot, len, to_decrypt,
+                                      decrypted + copied, &flushed_at);
+
                ctx->recv_pkt = NULL;
                __strp_unpause(&ctx->strp);
                __skb_queue_tail(&ctx->rx_list, skb);
@@ -2249,6 +2293,14 @@ void tls_sw_strparser_arm(struct sock *sk, struct tls_context *tls_ctx)
        strp_check_rcv(&rx_ctx->strp);
 }
 
+void tls_update_rx_zc_capable(struct tls_context *tls_ctx)
+{
+       struct tls_sw_context_rx *rx_ctx = tls_sw_ctx_rx(tls_ctx);
+
+       rx_ctx->zc_capable = tls_ctx->rx_no_pad ||
+               tls_ctx->prot_info.version != TLS_1_3_VERSION;
+}
+
 int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
 {
        struct tls_context *tls_ctx = tls_get_ctx(sk);
@@ -2484,12 +2536,10 @@ int tls_set_sw_offload(struct sock *sk, struct tls_context *ctx, int tx)
        if (sw_ctx_rx) {
                tfm = crypto_aead_tfm(sw_ctx_rx->aead_recv);
 
-               if (crypto_info->version == TLS_1_3_VERSION)
-                       sw_ctx_rx->async_capable = 0;
-               else
-                       sw_ctx_rx->async_capable =
-                               !!(tfm->__crt_alg->cra_flags &
-                                  CRYPTO_ALG_ASYNC);
+               tls_update_rx_zc_capable(ctx);
+               sw_ctx_rx->async_capable =
+                       crypto_info->version != TLS_1_3_VERSION &&
+                       !!(tfm->__crt_alg->cra_flags & CRYPTO_ALG_ASYNC);
 
                /* Set up strparser */
                memset(&cb, 0, sizeof(cb));
index 2206e6f..784b4b3 100644 (file)
 
 #include "scm.h"
 
-spinlock_t unix_table_locks[2 * UNIX_HASH_SIZE];
-EXPORT_SYMBOL_GPL(unix_table_locks);
-struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
-EXPORT_SYMBOL_GPL(unix_socket_table);
 static atomic_long_t unix_nr_socks;
+static struct hlist_head bsd_socket_buckets[UNIX_HASH_SIZE / 2];
+static spinlock_t bsd_socket_locks[UNIX_HASH_SIZE / 2];
 
 /* SMP locking strategy:
- *    hash table is protected with spinlock unix_table_locks
- *    each socket state is protected by separate spin lock.
+ *    hash table is protected with spinlock.
+ *    each socket state is protected by separate spinlock.
  */
 
 static unsigned int unix_unbound_hash(struct sock *sk)
@@ -137,12 +135,12 @@ static unsigned int unix_unbound_hash(struct sock *sk)
        hash ^= hash >> 8;
        hash ^= sk->sk_type;
 
-       return UNIX_HASH_SIZE + (hash & (UNIX_HASH_SIZE - 1));
+       return hash & UNIX_HASH_MOD;
 }
 
 static unsigned int unix_bsd_hash(struct inode *i)
 {
-       return i->i_ino & (UNIX_HASH_SIZE - 1);
+       return i->i_ino & UNIX_HASH_MOD;
 }
 
 static unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr,
@@ -155,26 +153,34 @@ static unsigned int unix_abstract_hash(struct sockaddr_un *sunaddr,
        hash ^= hash >> 8;
        hash ^= type;
 
-       return hash & (UNIX_HASH_SIZE - 1);
+       return UNIX_HASH_MOD + 1 + (hash & UNIX_HASH_MOD);
 }
 
-static void unix_table_double_lock(unsigned int hash1, unsigned int hash2)
+static void unix_table_double_lock(struct net *net,
+                                  unsigned int hash1, unsigned int hash2)
 {
-       /* hash1 and hash2 is never the same because
-        * one is between 0 and UNIX_HASH_SIZE - 1, and
-        * another is between UNIX_HASH_SIZE and UNIX_HASH_SIZE * 2.
-        */
+       if (hash1 == hash2) {
+               spin_lock(&net->unx.table.locks[hash1]);
+               return;
+       }
+
        if (hash1 > hash2)
                swap(hash1, hash2);
 
-       spin_lock(&unix_table_locks[hash1]);
-       spin_lock_nested(&unix_table_locks[hash2], SINGLE_DEPTH_NESTING);
+       spin_lock(&net->unx.table.locks[hash1]);
+       spin_lock_nested(&net->unx.table.locks[hash2], SINGLE_DEPTH_NESTING);
 }
 
-static void unix_table_double_unlock(unsigned int hash1, unsigned int hash2)
+static void unix_table_double_unlock(struct net *net,
+                                    unsigned int hash1, unsigned int hash2)
 {
-       spin_unlock(&unix_table_locks[hash1]);
-       spin_unlock(&unix_table_locks[hash2]);
+       if (hash1 == hash2) {
+               spin_unlock(&net->unx.table.locks[hash1]);
+               return;
+       }
+
+       spin_unlock(&net->unx.table.locks[hash1]);
+       spin_unlock(&net->unx.table.locks[hash2]);
 }
 
 #ifdef CONFIG_SECURITY_NETWORK
@@ -300,34 +306,52 @@ static void __unix_remove_socket(struct sock *sk)
        sk_del_node_init(sk);
 }
 
-static void __unix_insert_socket(struct sock *sk)
+static void __unix_insert_socket(struct net *net, struct sock *sk)
 {
-       WARN_ON(!sk_unhashed(sk));
-       sk_add_node(sk, &unix_socket_table[sk->sk_hash]);
+       DEBUG_NET_WARN_ON_ONCE(!sk_unhashed(sk));
+       sk_add_node(sk, &net->unx.table.buckets[sk->sk_hash]);
 }
 
-static void __unix_set_addr_hash(struct sock *sk, struct unix_address *addr,
-                                unsigned int hash)
+static void __unix_set_addr_hash(struct net *net, struct sock *sk,
+                                struct unix_address *addr, unsigned int hash)
 {
        __unix_remove_socket(sk);
        smp_store_release(&unix_sk(sk)->addr, addr);
 
        sk->sk_hash = hash;
-       __unix_insert_socket(sk);
+       __unix_insert_socket(net, sk);
 }
 
-static void unix_remove_socket(struct sock *sk)
+static void unix_remove_socket(struct net *net, struct sock *sk)
 {
-       spin_lock(&unix_table_locks[sk->sk_hash]);
+       spin_lock(&net->unx.table.locks[sk->sk_hash]);
        __unix_remove_socket(sk);
-       spin_unlock(&unix_table_locks[sk->sk_hash]);
+       spin_unlock(&net->unx.table.locks[sk->sk_hash]);
+}
+
+static void unix_insert_unbound_socket(struct net *net, struct sock *sk)
+{
+       spin_lock(&net->unx.table.locks[sk->sk_hash]);
+       __unix_insert_socket(net, sk);
+       spin_unlock(&net->unx.table.locks[sk->sk_hash]);
+}
+
+static void unix_insert_bsd_socket(struct sock *sk)
+{
+       spin_lock(&bsd_socket_locks[sk->sk_hash]);
+       sk_add_bind_node(sk, &bsd_socket_buckets[sk->sk_hash]);
+       spin_unlock(&bsd_socket_locks[sk->sk_hash]);
 }
 
-static void unix_insert_unbound_socket(struct sock *sk)
+static void unix_remove_bsd_socket(struct sock *sk)
 {
-       spin_lock(&unix_table_locks[sk->sk_hash]);
-       __unix_insert_socket(sk);
-       spin_unlock(&unix_table_locks[sk->sk_hash]);
+       if (!hlist_unhashed(&sk->sk_bind_node)) {
+               spin_lock(&bsd_socket_locks[sk->sk_hash]);
+               __sk_del_bind_node(sk);
+               spin_unlock(&bsd_socket_locks[sk->sk_hash]);
+
+               sk_node_init(&sk->sk_bind_node);
+       }
 }
 
 static struct sock *__unix_find_socket_byname(struct net *net,
@@ -336,12 +360,9 @@ static struct sock *__unix_find_socket_byname(struct net *net,
 {
        struct sock *s;
 
-       sk_for_each(s, &unix_socket_table[hash]) {
+       sk_for_each(s, &net->unx.table.buckets[hash]) {
                struct unix_sock *u = unix_sk(s);
 
-               if (!net_eq(sock_net(s), net))
-                       continue;
-
                if (u->addr->len == len &&
                    !memcmp(u->addr->name, sunname, len))
                        return s;
@@ -355,11 +376,11 @@ static inline struct sock *unix_find_socket_byname(struct net *net,
 {
        struct sock *s;
 
-       spin_lock(&unix_table_locks[hash]);
+       spin_lock(&net->unx.table.locks[hash]);
        s = __unix_find_socket_byname(net, sunname, len, hash);
        if (s)
                sock_hold(s);
-       spin_unlock(&unix_table_locks[hash]);
+       spin_unlock(&net->unx.table.locks[hash]);
        return s;
 }
 
@@ -368,17 +389,17 @@ static struct sock *unix_find_socket_byinode(struct inode *i)
        unsigned int hash = unix_bsd_hash(i);
        struct sock *s;
 
-       spin_lock(&unix_table_locks[hash]);
-       sk_for_each(s, &unix_socket_table[hash]) {
+       spin_lock(&bsd_socket_locks[hash]);
+       sk_for_each_bound(s, &bsd_socket_buckets[hash]) {
                struct dentry *dentry = unix_sk(s)->path.dentry;
 
                if (dentry && d_backing_inode(dentry) == i) {
                        sock_hold(s);
-                       spin_unlock(&unix_table_locks[hash]);
+                       spin_unlock(&bsd_socket_locks[hash]);
                        return s;
                }
        }
-       spin_unlock(&unix_table_locks[hash]);
+       spin_unlock(&bsd_socket_locks[hash]);
        return NULL;
 }
 
@@ -554,9 +575,9 @@ static void unix_sock_destructor(struct sock *sk)
                u->oob_skb = NULL;
        }
 #endif
-       WARN_ON(refcount_read(&sk->sk_wmem_alloc));
-       WARN_ON(!sk_unhashed(sk));
-       WARN_ON(sk->sk_socket);
+       DEBUG_NET_WARN_ON_ONCE(refcount_read(&sk->sk_wmem_alloc));
+       DEBUG_NET_WARN_ON_ONCE(!sk_unhashed(sk));
+       DEBUG_NET_WARN_ON_ONCE(sk->sk_socket);
        if (!sock_flag(sk, SOCK_DEAD)) {
                pr_info("Attempt to release alive unix socket: %p\n", sk);
                return;
@@ -576,12 +597,13 @@ static void unix_sock_destructor(struct sock *sk)
 static void unix_release_sock(struct sock *sk, int embrion)
 {
        struct unix_sock *u = unix_sk(sk);
-       struct path path;
        struct sock *skpair;
        struct sk_buff *skb;
+       struct path path;
        int state;
 
-       unix_remove_socket(sk);
+       unix_remove_socket(sock_net(sk), sk);
+       unix_remove_bsd_socket(sk);
 
        /* Clear state */
        unix_state_lock(sk);
@@ -930,9 +952,9 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern,
        init_waitqueue_head(&u->peer_wait);
        init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
        memset(&u->scm_stat, 0, sizeof(struct scm_stat));
-       unix_insert_unbound_socket(sk);
+       unix_insert_unbound_socket(net, sk);
 
-       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+       sock_prot_inuse_add(net, sk->sk_prot, 1);
 
        return sk;
 
@@ -993,8 +1015,8 @@ static int unix_release(struct socket *sock)
        return 0;
 }
 
-static struct sock *unix_find_bsd(struct net *net, struct sockaddr_un *sunaddr,
-                                 int addr_len, int type)
+static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
+                                 int type)
 {
        struct inode *inode;
        struct path path;
@@ -1063,7 +1085,7 @@ static struct sock *unix_find_other(struct net *net,
        struct sock *sk;
 
        if (sunaddr->sun_path[0])
-               sk = unix_find_bsd(net, sunaddr, addr_len, type);
+               sk = unix_find_bsd(sunaddr, addr_len, type);
        else
                sk = unix_find_abstract(net, sunaddr, addr_len, type);
 
@@ -1074,6 +1096,7 @@ static int unix_autobind(struct sock *sk)
 {
        unsigned int new_hash, old_hash = sk->sk_hash;
        struct unix_sock *u = unix_sk(sk);
+       struct net *net = sock_net(sk);
        struct unix_address *addr;
        u32 lastnum, ordernum;
        int err;
@@ -1102,11 +1125,10 @@ retry:
        sprintf(addr->name->sun_path + 1, "%05x", ordernum);
 
        new_hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type);
-       unix_table_double_lock(old_hash, new_hash);
+       unix_table_double_lock(net, old_hash, new_hash);
 
-       if (__unix_find_socket_byname(sock_net(sk), addr->name, addr->len,
-                                     new_hash)) {
-               unix_table_double_unlock(old_hash, new_hash);
+       if (__unix_find_socket_byname(net, addr->name, addr->len, new_hash)) {
+               unix_table_double_unlock(net, old_hash, new_hash);
 
                /* __unix_find_socket_byname() may take long time if many names
                 * are already in use.
@@ -1123,8 +1145,8 @@ retry:
                goto retry;
        }
 
-       __unix_set_addr_hash(sk, addr, new_hash);
-       unix_table_double_unlock(old_hash, new_hash);
+       __unix_set_addr_hash(net, sk, addr, new_hash);
+       unix_table_double_unlock(net, old_hash, new_hash);
        err = 0;
 
 out:   mutex_unlock(&u->bindlock);
@@ -1138,6 +1160,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
               (SOCK_INODE(sk->sk_socket)->i_mode & ~current_umask());
        unsigned int new_hash, old_hash = sk->sk_hash;
        struct unix_sock *u = unix_sk(sk);
+       struct net *net = sock_net(sk);
        struct user_namespace *ns; // barf...
        struct unix_address *addr;
        struct dentry *dentry;
@@ -1178,11 +1201,12 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
                goto out_unlock;
 
        new_hash = unix_bsd_hash(d_backing_inode(dentry));
-       unix_table_double_lock(old_hash, new_hash);
+       unix_table_double_lock(net, old_hash, new_hash);
        u->path.mnt = mntget(parent.mnt);
        u->path.dentry = dget(dentry);
-       __unix_set_addr_hash(sk, addr, new_hash);
-       unix_table_double_unlock(old_hash, new_hash);
+       __unix_set_addr_hash(net, sk, addr, new_hash);
+       unix_table_double_unlock(net, old_hash, new_hash);
+       unix_insert_bsd_socket(sk);
        mutex_unlock(&u->bindlock);
        done_path_create(&parent, dentry);
        return 0;
@@ -1205,6 +1229,7 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr,
 {
        unsigned int new_hash, old_hash = sk->sk_hash;
        struct unix_sock *u = unix_sk(sk);
+       struct net *net = sock_net(sk);
        struct unix_address *addr;
        int err;
 
@@ -1222,19 +1247,18 @@ static int unix_bind_abstract(struct sock *sk, struct sockaddr_un *sunaddr,
        }
 
        new_hash = unix_abstract_hash(addr->name, addr->len, sk->sk_type);
-       unix_table_double_lock(old_hash, new_hash);
+       unix_table_double_lock(net, old_hash, new_hash);
 
-       if (__unix_find_socket_byname(sock_net(sk), addr->name, addr->len,
-                                     new_hash))
+       if (__unix_find_socket_byname(net, addr->name, addr->len, new_hash))
                goto out_spin;
 
-       __unix_set_addr_hash(sk, addr, new_hash);
-       unix_table_double_unlock(old_hash, new_hash);
+       __unix_set_addr_hash(net, sk, addr, new_hash);
+       unix_table_double_unlock(net, old_hash, new_hash);
        mutex_unlock(&u->bindlock);
        return 0;
 
 out_spin:
-       unix_table_double_unlock(old_hash, new_hash);
+       unix_table_double_unlock(net, old_hash, new_hash);
        err = -EADDRINUSE;
 out_mutex:
        mutex_unlock(&u->bindlock);
@@ -1293,9 +1317,8 @@ static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
 static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
                              int alen, int flags)
 {
-       struct sock *sk = sock->sk;
-       struct net *net = sock_net(sk);
        struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr;
+       struct sock *sk = sock->sk;
        struct sock *other;
        int err;
 
@@ -1316,7 +1339,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
                }
 
 restart:
-               other = unix_find_other(net, sunaddr, alen, sock->type);
+               other = unix_find_other(sock_net(sk), sunaddr, alen, sock->type);
                if (IS_ERR(other)) {
                        err = PTR_ERR(other);
                        goto out;
@@ -1404,15 +1427,13 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
                               int addr_len, int flags)
 {
        struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
-       struct sock *sk = sock->sk;
-       struct net *net = sock_net(sk);
+       struct sock *sk = sock->sk, *newsk = NULL, *other = NULL;
        struct unix_sock *u = unix_sk(sk), *newu, *otheru;
-       struct sock *newsk = NULL;
-       struct sock *other = NULL;
+       struct net *net = sock_net(sk);
        struct sk_buff *skb = NULL;
-       int st;
-       int err;
        long timeo;
+       int err;
+       int st;
 
        err = unix_validate_addr(sunaddr, addr_len);
        if (err)
@@ -1432,7 +1453,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
         */
 
        /* create new sock for complete connection */
-       newsk = unix_create1(sock_net(sk), NULL, 0, sock->type);
+       newsk = unix_create1(net, NULL, 0, sock->type);
        if (IS_ERR(newsk)) {
                err = PTR_ERR(newsk);
                newsk = NULL;
@@ -1541,9 +1562,9 @@ restart:
         *
         * The contents of *(otheru->addr) and otheru->path
         * are seen fully set up here, since we have found
-        * otheru in hash under unix_table_locks.  Insertion
-        * into the hash chain we'd found it in had been done
-        * in an earlier critical area protected by unix_table_locks,
+        * otheru in hash under its lock.  Insertion into the
+        * hash chain we'd found it in had been done in an
+        * earlier critical area protected by the chain's lock,
         * the same one where we'd set *(otheru->addr) contents,
         * as well as otheru->path and otheru->addr itself.
         *
@@ -1840,17 +1861,15 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb)
 static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
                              size_t len)
 {
-       struct sock *sk = sock->sk;
-       struct net *net = sock_net(sk);
-       struct unix_sock *u = unix_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name);
-       struct sock *other = NULL;
-       int err;
-       struct sk_buff *skb;
-       long timeo;
+       struct sock *sk = sock->sk, *other = NULL;
+       struct unix_sock *u = unix_sk(sk);
        struct scm_cookie scm;
+       struct sk_buff *skb;
        int data_len = 0;
        int sk_locked;
+       long timeo;
+       int err;
 
        wait_for_unix_gc();
        err = scm_send(sock, msg, &scm, false);
@@ -1917,7 +1936,7 @@ restart:
                if (sunaddr == NULL)
                        goto out_free;
 
-               other = unix_find_other(net, sunaddr, msg->msg_namelen,
+               other = unix_find_other(sock_net(sk), sunaddr, msg->msg_namelen,
                                        sk->sk_type);
                if (IS_ERR(other)) {
                        err = PTR_ERR(other);
@@ -3226,12 +3245,11 @@ static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos)
 {
        unsigned long offset = get_offset(*pos);
        unsigned long bucket = get_bucket(*pos);
-       struct sock *sk;
        unsigned long count = 0;
+       struct sock *sk;
 
-       for (sk = sk_head(&unix_socket_table[bucket]); sk; sk = sk_next(sk)) {
-               if (sock_net(sk) != seq_file_net(seq))
-                       continue;
+       for (sk = sk_head(&seq_file_net(seq)->unx.table.buckets[bucket]);
+            sk; sk = sk_next(sk)) {
                if (++count == offset)
                        break;
        }
@@ -3242,16 +3260,17 @@ static struct sock *unix_from_bucket(struct seq_file *seq, loff_t *pos)
 static struct sock *unix_get_first(struct seq_file *seq, loff_t *pos)
 {
        unsigned long bucket = get_bucket(*pos);
+       struct net *net = seq_file_net(seq);
        struct sock *sk;
 
-       while (bucket < ARRAY_SIZE(unix_socket_table)) {
-               spin_lock(&unix_table_locks[bucket]);
+       while (bucket < UNIX_HASH_SIZE) {
+               spin_lock(&net->unx.table.locks[bucket]);
 
                sk = unix_from_bucket(seq, pos);
                if (sk)
                        return sk;
 
-               spin_unlock(&unix_table_locks[bucket]);
+               spin_unlock(&net->unx.table.locks[bucket]);
 
                *pos = set_bucket_offset(++bucket, 1);
        }
@@ -3264,11 +3283,12 @@ static struct sock *unix_get_next(struct seq_file *seq, struct sock *sk,
 {
        unsigned long bucket = get_bucket(*pos);
 
-       for (sk = sk_next(sk); sk; sk = sk_next(sk))
-               if (sock_net(sk) == seq_file_net(seq))
-                       return sk;
+       sk = sk_next(sk);
+       if (sk)
+               return sk;
+
 
-       spin_unlock(&unix_table_locks[bucket]);
+       spin_unlock(&seq_file_net(seq)->unx.table.locks[bucket]);
 
        *pos = set_bucket_offset(++bucket, 1);
 
@@ -3298,7 +3318,7 @@ static void unix_seq_stop(struct seq_file *seq, void *v)
        struct sock *sk = v;
 
        if (sk)
-               spin_unlock(&unix_table_locks[sk->sk_hash]);
+               spin_unlock(&seq_file_net(seq)->unx.table.locks[sk->sk_hash]);
 }
 
 static int unix_seq_show(struct seq_file *seq, void *v)
@@ -3323,7 +3343,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
                        (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),
                        sock_i_ino(s));
 
-               if (u->addr) {  // under unix_table_locks here
+               if (u->addr) {  // under a hash table lock here
                        int i, len;
                        seq_putc(seq, ' ');
 
@@ -3393,9 +3413,6 @@ static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk)
        iter->batch[iter->end_sk++] = start_sk;
 
        for (sk = sk_next(start_sk); sk; sk = sk_next(sk)) {
-               if (sock_net(sk) != seq_file_net(seq))
-                       continue;
-
                if (iter->end_sk < iter->max_sk) {
                        sock_hold(sk);
                        iter->batch[iter->end_sk++] = sk;
@@ -3404,7 +3421,7 @@ static int bpf_iter_unix_hold_batch(struct seq_file *seq, struct sock *start_sk)
                expected++;
        }
 
-       spin_unlock(&unix_table_locks[start_sk->sk_hash]);
+       spin_unlock(&seq_file_net(seq)->unx.table.locks[start_sk->sk_hash]);
 
        return expected;
 }
@@ -3564,7 +3581,7 @@ static const struct net_proto_family unix_family_ops = {
 
 static int __net_init unix_net_init(struct net *net)
 {
-       int error = -ENOMEM;
+       int i;
 
        net->unx.sysctl_max_dgram_qlen = 10;
        if (unix_sysctl_register(net))
@@ -3572,18 +3589,44 @@ static int __net_init unix_net_init(struct net *net)
 
 #ifdef CONFIG_PROC_FS
        if (!proc_create_net("unix", 0, net->proc_net, &unix_seq_ops,
-                       sizeof(struct seq_net_private))) {
-               unix_sysctl_unregister(net);
-               goto out;
+                            sizeof(struct seq_net_private)))
+               goto err_sysctl;
+#endif
+
+       net->unx.table.locks = kvmalloc_array(UNIX_HASH_SIZE,
+                                             sizeof(spinlock_t), GFP_KERNEL);
+       if (!net->unx.table.locks)
+               goto err_proc;
+
+       net->unx.table.buckets = kvmalloc_array(UNIX_HASH_SIZE,
+                                               sizeof(struct hlist_head),
+                                               GFP_KERNEL);
+       if (!net->unx.table.buckets)
+               goto free_locks;
+
+       for (i = 0; i < UNIX_HASH_SIZE; i++) {
+               spin_lock_init(&net->unx.table.locks[i]);
+               INIT_HLIST_HEAD(&net->unx.table.buckets[i]);
        }
+
+       return 0;
+
+free_locks:
+       kvfree(net->unx.table.locks);
+err_proc:
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("unix", net->proc_net);
+err_sysctl:
 #endif
-       error = 0;
+       unix_sysctl_unregister(net);
 out:
-       return error;
+       return -ENOMEM;
 }
 
 static void __net_exit unix_net_exit(struct net *net)
 {
+       kvfree(net->unx.table.buckets);
+       kvfree(net->unx.table.locks);
        unix_sysctl_unregister(net);
        remove_proc_entry("unix", net->proc_net);
 }
@@ -3671,8 +3714,10 @@ static int __init af_unix_init(void)
 
        BUILD_BUG_ON(sizeof(struct unix_skb_parms) > sizeof_field(struct sk_buff, cb));
 
-       for (i = 0; i < 2 * UNIX_HASH_SIZE; i++)
-               spin_lock_init(&unix_table_locks[i]);
+       for (i = 0; i < UNIX_HASH_SIZE / 2; i++) {
+               spin_lock_init(&bsd_socket_locks[i]);
+               INIT_HLIST_HEAD(&bsd_socket_buckets[i]);
+       }
 
        rc = proto_register(&unix_dgram_proto, 1);
        if (rc != 0) {
index bb0b5ea..105f522 100644 (file)
@@ -13,7 +13,7 @@
 
 static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb)
 {
-       /* might or might not have unix_table_locks */
+       /* might or might not have a hash table lock */
        struct unix_address *addr = smp_load_acquire(&unix_sk(sk)->addr);
 
        if (!addr)
@@ -195,25 +195,21 @@ static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
 
 static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct unix_diag_req *req;
-       int num, s_num, slot, s_slot;
        struct net *net = sock_net(skb->sk);
+       int num, s_num, slot, s_slot;
+       struct unix_diag_req *req;
 
        req = nlmsg_data(cb->nlh);
 
        s_slot = cb->args[0];
        num = s_num = cb->args[1];
 
-       for (slot = s_slot;
-            slot < ARRAY_SIZE(unix_socket_table);
-            s_num = 0, slot++) {
+       for (slot = s_slot; slot < UNIX_HASH_SIZE; s_num = 0, slot++) {
                struct sock *sk;
 
                num = 0;
-               spin_lock(&unix_table_locks[slot]);
-               sk_for_each(sk, &unix_socket_table[slot]) {
-                       if (!net_eq(sock_net(sk), net))
-                               continue;
+               spin_lock(&net->unx.table.locks[slot]);
+               sk_for_each(sk, &net->unx.table.buckets[slot]) {
                        if (num < s_num)
                                goto next;
                        if (!(req->udiag_states & (1 << sk->sk_state)))
@@ -222,13 +218,13 @@ static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                                         NETLINK_CB(cb->skb).portid,
                                         cb->nlh->nlmsg_seq,
                                         NLM_F_MULTI) < 0) {
-                               spin_unlock(&unix_table_locks[slot]);
+                               spin_unlock(&net->unx.table.locks[slot]);
                                goto done;
                        }
 next:
                        num++;
                }
-               spin_unlock(&unix_table_locks[slot]);
+               spin_unlock(&net->unx.table.locks[slot]);
        }
 done:
        cb->args[0] = slot;
@@ -237,20 +233,21 @@ done:
        return skb->len;
 }
 
-static struct sock *unix_lookup_by_ino(unsigned int ino)
+static struct sock *unix_lookup_by_ino(struct net *net, unsigned int ino)
 {
        struct sock *sk;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(unix_socket_table); i++) {
-               spin_lock(&unix_table_locks[i]);
-               sk_for_each(sk, &unix_socket_table[i])
+       for (i = 0; i < UNIX_HASH_SIZE; i++) {
+               spin_lock(&net->unx.table.locks[i]);
+               sk_for_each(sk, &net->unx.table.buckets[i]) {
                        if (ino == sock_i_ino(sk)) {
                                sock_hold(sk);
-                               spin_unlock(&unix_table_locks[i]);
+                               spin_unlock(&net->unx.table.locks[i]);
                                return sk;
                        }
-               spin_unlock(&unix_table_locks[i]);
+               }
+               spin_unlock(&net->unx.table.locks[i]);
        }
        return NULL;
 }
@@ -259,21 +256,20 @@ static int unix_diag_get_exact(struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh,
                               struct unix_diag_req *req)
 {
-       int err = -EINVAL;
-       struct sock *sk;
-       struct sk_buff *rep;
-       unsigned int extra_len;
        struct net *net = sock_net(in_skb->sk);
+       unsigned int extra_len;
+       struct sk_buff *rep;
+       struct sock *sk;
+       int err;
 
+       err = -EINVAL;
        if (req->udiag_ino == 0)
                goto out_nosk;
 
-       sk = unix_lookup_by_ino(req->udiag_ino);
+       sk = unix_lookup_by_ino(net, req->udiag_ino);
        err = -ENOENT;
        if (sk == NULL)
                goto out_nosk;
-       if (!net_eq(sock_net(sk), net))
-               goto out;
 
        err = sock_diag_check_cookie(sk, req->udiag_cookie);
        if (err)
@@ -308,7 +304,6 @@ out_nosk:
 static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 {
        int hdrlen = sizeof(struct unix_diag_req);
-       struct net *net = sock_net(skb->sk);
 
        if (nlmsg_len(h) < hdrlen)
                return -EINVAL;
@@ -317,7 +312,7 @@ static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
                struct netlink_dump_control c = {
                        .dump = unix_diag_dump,
                };
-               return netlink_dump_start(net->diag_nlsk, skb, h, &c);
+               return netlink_dump_start(sock_net(skb->sk)->diag_nlsk, skb, h, &c);
        } else
                return unix_diag_get_exact(skb, h, nlmsg_data(h));
 }
index 01d44e2..3f1fdff 100644 (file)
@@ -26,11 +26,16 @@ int __net_init unix_sysctl_register(struct net *net)
 {
        struct ctl_table *table;
 
-       table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
-       if (table == NULL)
-               goto err_alloc;
+       if (net_eq(net, &init_net)) {
+               table = unix_table;
+       } else {
+               table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
+               if (!table)
+                       goto err_alloc;
+
+               table[0].data = &net->unx.sysctl_max_dgram_qlen;
+       }
 
-       table[0].data = &net->unx.sysctl_max_dgram_qlen;
        net->unx.ctl = register_net_sysctl(net, "net/unix", table);
        if (net->unx.ctl == NULL)
                goto err_reg;
@@ -38,7 +43,8 @@ int __net_init unix_sysctl_register(struct net *net)
        return 0;
 
 err_reg:
-       kfree(table);
+       if (net_eq(net, &init_net))
+               kfree(table);
 err_alloc:
        return -ENOMEM;
 }
@@ -49,5 +55,6 @@ void unix_sysctl_unregister(struct net *net)
 
        table = net->unx.ctl->ctl_table_arg;
        unregister_net_sysctl_table(net->unx.ctl);
-       kfree(table);
+       if (!net_eq(net, &init_net))
+               kfree(table);
 }
index f01ef6b..869b9b9 100644 (file)
@@ -57,7 +57,7 @@ static int xdp_umem_addr_map(struct xdp_umem *umem, struct page **pages,
 static void xdp_umem_release(struct xdp_umem *umem)
 {
        umem->zc = false;
-       ida_simple_remove(&umem_ida, umem->id);
+       ida_free(&umem_ida, umem->id);
 
        xdp_umem_addr_unmap(umem);
        xdp_umem_unpin_pages(umem);
@@ -242,7 +242,7 @@ struct xdp_umem *xdp_umem_create(struct xdp_umem_reg *mr)
        if (!umem)
                return ERR_PTR(-ENOMEM);
 
-       err = ida_simple_get(&umem_ida, 0, 0, GFP_KERNEL);
+       err = ida_alloc(&umem_ida, GFP_KERNEL);
        if (err < 0) {
                kfree(umem);
                return ERR_PTR(err);
@@ -251,7 +251,7 @@ struct xdp_umem *xdp_umem_create(struct xdp_umem_reg *mr)
 
        err = xdp_umem_reg(umem, mr);
        if (err) {
-               ida_simple_remove(&umem_ida, umem->id);
+               ida_free(&umem_ida, umem->id);
                kfree(umem);
                return ERR_PTR(err);
        }
index 35c7e89..637ca88 100644 (file)
@@ -275,7 +275,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
                xso->dev = NULL;
                xso->dir = 0;
                xso->real_dev = NULL;
-               dev_put_track(dev, &xso->dev_tracker);
+               netdev_put(dev, &xso->dev_tracker);
 
                if (err != -EOPNOTSUPP)
                        return err;
index 1828487..84f57f1 100644 (file)
@@ -47,17 +47,60 @@ static int do_attach(int idx, int prog_fd, int map_fd, const char *name)
        return err;
 }
 
-static int do_detach(int idx, const char *name)
+static int do_detach(int ifindex, const char *ifname, const char *app_name)
 {
-       int err;
+       LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
+       struct bpf_prog_info prog_info = {};
+       char prog_name[BPF_OBJ_NAME_LEN];
+       __u32 info_len, curr_prog_id;
+       int prog_fd;
+       int err = 1;
+
+       if (bpf_xdp_query_id(ifindex, xdp_flags, &curr_prog_id)) {
+               printf("ERROR: bpf_xdp_query_id failed (%s)\n",
+                      strerror(errno));
+               return err;
+       }
 
-       err = bpf_xdp_detach(idx, xdp_flags, NULL);
-       if (err < 0)
-               printf("ERROR: failed to detach program from %s\n", name);
+       if (!curr_prog_id) {
+               printf("ERROR: flags(0x%x) xdp prog is not attached to %s\n",
+                      xdp_flags, ifname);
+               return err;
+       }
 
+       info_len = sizeof(prog_info);
+       prog_fd = bpf_prog_get_fd_by_id(curr_prog_id);
+       if (prog_fd < 0) {
+               printf("ERROR: bpf_prog_get_fd_by_id failed (%s)\n",
+                      strerror(errno));
+               return prog_fd;
+       }
+
+       err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
+       if (err) {
+               printf("ERROR: bpf_obj_get_info_by_fd failed (%s)\n",
+                      strerror(errno));
+               goto close_out;
+       }
+       snprintf(prog_name, sizeof(prog_name), "%s_prog", app_name);
+       prog_name[BPF_OBJ_NAME_LEN - 1] = '\0';
+
+       if (strcmp(prog_info.name, prog_name)) {
+               printf("ERROR: %s isn't attached to %s\n", app_name, ifname);
+               err = 1;
+               goto close_out;
+       }
+
+       opts.old_prog_fd = prog_fd;
+       err = bpf_xdp_detach(ifindex, xdp_flags, &opts);
+       if (err < 0)
+               printf("ERROR: failed to detach program from %s (%s)\n",
+                      ifname, strerror(errno));
        /* TODO: Remember to cleanup map, when adding use of shared map
         *  bpf_map_delete_elem((map_fd, &idx);
         */
+close_out:
+       close(prog_fd);
        return err;
 }
 
@@ -169,7 +212,7 @@ int main(int argc, char **argv)
                        return 1;
                }
                if (!attach) {
-                       err = do_detach(idx, argv[i]);
+                       err = do_detach(idx, argv[i], prog_name);
                        if (err)
                                ret = err;
                } else {
index 248119c..0643330 100644 (file)
@@ -150,6 +150,15 @@ int xdp_router_ipv4_prog(struct xdp_md *ctx)
 
                                dest_mac = bpf_map_lookup_elem(&arp_table,
                                                               &prefix_value->gw);
+                               if (!dest_mac) {
+                                       /* Forward the packet to the kernel in
+                                        * order to trigger ARP discovery for
+                                        * the default gw.
+                                        */
+                                       if (rec)
+                                               NO_TEAR_INC(rec->xdp_pass);
+                                       return XDP_PASS;
+                               }
                        }
                }
 
index 855b937..a0ec321 100755 (executable)
@@ -635,6 +635,8 @@ class PrinterHelpers(Printer):
             'struct bpf_timer',
             'struct mptcp_sock',
             'struct bpf_dynptr',
+            'struct iphdr',
+            'struct ipv6hdr',
     ]
     known_types = {
             '...',
@@ -686,6 +688,8 @@ class PrinterHelpers(Printer):
             'struct bpf_timer',
             'struct mptcp_sock',
             'struct bpf_dynptr',
+            'struct iphdr',
+            'struct ipv6hdr',
     }
     mapped_types = {
             'u8': '__u8',
index a17e9aa..bd015ec 100644 (file)
@@ -31,11 +31,17 @@ CGROUP COMMANDS
 |      **bpftool** **cgroup help**
 |
 |      *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
-|      *ATTACH_TYPE* := { **ingress** | **egress** | **sock_create** | **sock_ops** | **device** |
-|              **bind4** | **bind6** | **post_bind4** | **post_bind6** | **connect4** | **connect6** |
-|              **getpeername4** | **getpeername6** | **getsockname4** | **getsockname6** | **sendmsg4** |
-|              **sendmsg6** | **recvmsg4** | **recvmsg6** | **sysctl** | **getsockopt** | **setsockopt** |
-|              **sock_release** }
+|      *ATTACH_TYPE* := { **cgroup_inet_ingress** | **cgroup_inet_egress** |
+|              **cgroup_inet_sock_create** | **cgroup_sock_ops** |
+|              **cgroup_device** | **cgroup_inet4_bind** | **cgroup_inet6_bind** |
+|              **cgroup_inet4_post_bind** | **cgroup_inet6_post_bind** |
+|              **cgroup_inet4_connect** | **cgroup_inet6_connect** |
+|              **cgroup_inet4_getpeername** | **cgroup_inet6_getpeername** |
+|              **cgroup_inet4_getsockname** | **cgroup_inet6_getsockname** |
+|              **cgroup_udp4_sendmsg** | **cgroup_udp6_sendmsg** |
+|              **cgroup_udp4_recvmsg** | **cgroup_udp6_recvmsg** |
+|              **cgroup_sysctl** | **cgroup_getsockopt** | **cgroup_setsockopt** |
+|              **cgroup_inet_sock_release** }
 |      *ATTACH_FLAGS* := { **multi** | **override** }
 
 DESCRIPTION
index a2e9359..eb1b2a2 100644 (file)
@@ -53,8 +53,9 @@ PROG COMMANDS
 |              **cgroup/getsockopt** | **cgroup/setsockopt** | **cgroup/sock_release** |
 |              **struct_ops** | **fentry** | **fexit** | **freplace** | **sk_lookup**
 |      }
-|       *ATTACH_TYPE* := {
-|              **msg_verdict** | **skb_verdict** | **stream_verdict** | **stream_parser** | **flow_dissector**
+|      *ATTACH_TYPE* := {
+|              **sk_msg_verdict** | **sk_skb_verdict** | **sk_skb_stream_verdict** |
+|              **sk_skb_stream_parser** | **flow_dissector**
 |      }
 |      *METRICs* := {
 |              **cycles** | **instructions** | **l1d_loads** | **llc_misses** |
index c6d2c77..c19e0e4 100644 (file)
@@ -53,7 +53,7 @@ $(LIBBPF_INTERNAL_HDRS): $(LIBBPF_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_HDRS_
 $(LIBBPF_BOOTSTRAP): $(wildcard $(BPF_DIR)/*.[ch] $(BPF_DIR)/Makefile) | $(LIBBPF_BOOTSTRAP_OUTPUT)
        $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(LIBBPF_BOOTSTRAP_OUTPUT) \
                DESTDIR=$(LIBBPF_BOOTSTRAP_DESTDIR:/=) prefix= \
-               ARCH= CROSS_COMPILE= CC=$(HOSTCC) LD=$(HOSTLD) $@ install_headers
+               ARCH= CROSS_COMPILE= CC=$(HOSTCC) LD=$(HOSTLD) AR=$(HOSTAR) $@ install_headers
 
 $(LIBBPF_BOOTSTRAP_INTERNAL_HDRS): $(LIBBPF_BOOTSTRAP_HDRS_DIR)/%.h: $(BPF_DIR)/%.h | $(LIBBPF_BOOTSTRAP_HDRS_DIR)
        $(call QUIET_INSTALL, $@)
index 5df8d72..91f89a9 100644 (file)
@@ -407,8 +407,8 @@ _bpftool()
                             return 0
                             ;;
                         5)
-                            local BPFTOOL_PROG_ATTACH_TYPES='msg_verdict \
-                                skb_verdict stream_verdict stream_parser \
+                            local BPFTOOL_PROG_ATTACH_TYPES='sk_msg_verdict \
+                                sk_skb_verdict sk_skb_stream_verdict sk_skb_stream_parser \
                                 flow_dissector'
                             COMPREPLY=( $( compgen -W "$BPFTOOL_PROG_ATTACH_TYPES" -- "$cur" ) )
                             return 0
@@ -1039,12 +1039,14 @@ _bpftool()
                     return 0
                     ;;
                 attach|detach)
-                    local BPFTOOL_CGROUP_ATTACH_TYPES='ingress egress \
-                        sock_create sock_ops device \
-                        bind4 bind6 post_bind4 post_bind6 connect4 connect6 \
-                        getpeername4 getpeername6 getsockname4 getsockname6 \
-                        sendmsg4 sendmsg6 recvmsg4 recvmsg6 sysctl getsockopt \
-                        setsockopt sock_release'
+                    local BPFTOOL_CGROUP_ATTACH_TYPES='cgroup_inet_ingress cgroup_inet_egress \
+                        cgroup_inet_sock_create cgroup_sock_ops cgroup_device cgroup_inet4_bind \
+                        cgroup_inet6_bind cgroup_inet4_post_bind cgroup_inet6_post_bind \
+                        cgroup_inet4_connect cgroup_inet6_connect cgroup_inet4_getpeername \
+                        cgroup_inet6_getpeername cgroup_inet4_getsockname cgroup_inet6_getsockname \
+                        cgroup_udp4_sendmsg cgroup_udp6_sendmsg cgroup_udp4_recvmsg \
+                        cgroup_udp6_recvmsg cgroup_sysctl cgroup_getsockopt cgroup_setsockopt \
+                        cgroup_inet_sock_release'
                     local ATTACH_FLAGS='multi override'
                     local PROG_TYPE='id pinned tag name'
                     # Check for $prev = $command first
index 7e6accb..0744bd1 100644 (file)
@@ -40,6 +40,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
        [BTF_KIND_FLOAT]        = "FLOAT",
        [BTF_KIND_DECL_TAG]     = "DECL_TAG",
        [BTF_KIND_TYPE_TAG]     = "TYPE_TAG",
+       [BTF_KIND_ENUM64]       = "ENUM64",
 };
 
 struct btf_attach_point {
@@ -212,26 +213,76 @@ static int dump_btf_type(const struct btf *btf, __u32 id,
        case BTF_KIND_ENUM: {
                const struct btf_enum *v = (const void *)(t + 1);
                __u16 vlen = BTF_INFO_VLEN(t->info);
+               const char *encoding;
                int i;
 
+               encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
                if (json_output) {
+                       jsonw_string_field(w, "encoding", encoding);
                        jsonw_uint_field(w, "size", t->size);
                        jsonw_uint_field(w, "vlen", vlen);
                        jsonw_name(w, "values");
                        jsonw_start_array(w);
                } else {
-                       printf(" size=%u vlen=%u", t->size, vlen);
+                       printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
+               }
+               for (i = 0; i < vlen; i++, v++) {
+                       const char *name = btf_str(btf, v->name_off);
+
+                       if (json_output) {
+                               jsonw_start_object(w);
+                               jsonw_string_field(w, "name", name);
+                               if (btf_kflag(t))
+                                       jsonw_int_field(w, "val", v->val);
+                               else
+                                       jsonw_uint_field(w, "val", v->val);
+                               jsonw_end_object(w);
+                       } else {
+                               if (btf_kflag(t))
+                                       printf("\n\t'%s' val=%d", name, v->val);
+                               else
+                                       printf("\n\t'%s' val=%u", name, v->val);
+                       }
+               }
+               if (json_output)
+                       jsonw_end_array(w);
+               break;
+       }
+       case BTF_KIND_ENUM64: {
+               const struct btf_enum64 *v = btf_enum64(t);
+               __u16 vlen = btf_vlen(t);
+               const char *encoding;
+               int i;
+
+               encoding = btf_kflag(t) ? "SIGNED" : "UNSIGNED";
+               if (json_output) {
+                       jsonw_string_field(w, "encoding", encoding);
+                       jsonw_uint_field(w, "size", t->size);
+                       jsonw_uint_field(w, "vlen", vlen);
+                       jsonw_name(w, "values");
+                       jsonw_start_array(w);
+               } else {
+                       printf(" encoding=%s size=%u vlen=%u", encoding, t->size, vlen);
                }
                for (i = 0; i < vlen; i++, v++) {
                        const char *name = btf_str(btf, v->name_off);
+                       __u64 val = ((__u64)v->val_hi32 << 32) | v->val_lo32;
 
                        if (json_output) {
                                jsonw_start_object(w);
                                jsonw_string_field(w, "name", name);
-                               jsonw_uint_field(w, "val", v->val);
+                               if (btf_kflag(t))
+                                       jsonw_int_field(w, "val", val);
+                               else
+                                       jsonw_uint_field(w, "val", val);
                                jsonw_end_object(w);
                        } else {
-                               printf("\n\t'%s' val=%u", name, v->val);
+                               if (btf_kflag(t))
+                                       printf("\n\t'%s' val=%lldLL", name,
+                                              (unsigned long long)val);
+                               else
+                                       printf("\n\t'%s' val=%lluULL", name,
+                                              (unsigned long long)val);
                        }
                }
                if (json_output)
index f5dddf8..125798b 100644 (file)
@@ -182,6 +182,32 @@ static int btf_dumper_enum(const struct btf_dumper *d,
        return 0;
 }
 
+static int btf_dumper_enum64(const struct btf_dumper *d,
+                            const struct btf_type *t,
+                            const void *data)
+{
+       const struct btf_enum64 *enums = btf_enum64(t);
+       __u32 val_lo32, val_hi32;
+       __u64 value;
+       __u16 i;
+
+       value = *(__u64 *)data;
+       val_lo32 = (__u32)value;
+       val_hi32 = value >> 32;
+
+       for (i = 0; i < btf_vlen(t); i++) {
+               if (val_lo32 == enums[i].val_lo32 && val_hi32 == enums[i].val_hi32) {
+                       jsonw_string(d->jw,
+                                    btf__name_by_offset(d->btf,
+                                                        enums[i].name_off));
+                       return 0;
+               }
+       }
+
+       jsonw_int(d->jw, value);
+       return 0;
+}
+
 static bool is_str_array(const struct btf *btf, const struct btf_array *arr,
                         const char *s)
 {
@@ -542,6 +568,8 @@ static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
                return btf_dumper_array(d, type_id, data);
        case BTF_KIND_ENUM:
                return btf_dumper_enum(d, t, data);
+       case BTF_KIND_ENUM64:
+               return btf_dumper_enum64(d, t, data);
        case BTF_KIND_PTR:
                btf_dumper_ptr(d, t, data);
                return 0;
@@ -618,6 +646,7 @@ static int __btf_dumper_type_only(const struct btf *btf, __u32 type_id,
                              btf__name_by_offset(btf, t->name_off));
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                BTF_PRINT_ARG("enum %s ",
                              btf__name_by_offset(btf, t->name_off));
                break;
index effe136..42421fe 100644 (file)
 #define HELP_SPEC_ATTACH_FLAGS                                         \
        "ATTACH_FLAGS := { multi | override }"
 
-#define HELP_SPEC_ATTACH_TYPES                                                \
-       "       ATTACH_TYPE := { ingress | egress | sock_create |\n"           \
-       "                        sock_ops | device | bind4 | bind6 |\n"        \
-       "                        post_bind4 | post_bind6 | connect4 |\n"       \
-       "                        connect6 | getpeername4 | getpeername6 |\n"   \
-       "                        getsockname4 | getsockname6 | sendmsg4 |\n"   \
-       "                        sendmsg6 | recvmsg4 | recvmsg6 |\n"           \
-       "                        sysctl | getsockopt | setsockopt |\n"         \
-       "                        sock_release }"
+#define HELP_SPEC_ATTACH_TYPES                                         \
+       "       ATTACH_TYPE := { cgroup_inet_ingress | cgroup_inet_egress |\n" \
+       "                        cgroup_inet_sock_create | cgroup_sock_ops |\n" \
+       "                        cgroup_device | cgroup_inet4_bind |\n" \
+       "                        cgroup_inet6_bind | cgroup_inet4_post_bind |\n" \
+       "                        cgroup_inet6_post_bind | cgroup_inet4_connect |\n" \
+       "                        cgroup_inet6_connect | cgroup_inet4_getpeername |\n" \
+       "                        cgroup_inet6_getpeername | cgroup_inet4_getsockname |\n" \
+       "                        cgroup_inet6_getsockname | cgroup_udp4_sendmsg |\n" \
+       "                        cgroup_udp6_sendmsg | cgroup_udp4_recvmsg |\n" \
+       "                        cgroup_udp6_recvmsg | cgroup_sysctl |\n" \
+       "                        cgroup_getsockopt | cgroup_setsockopt |\n" \
+       "                        cgroup_inet_sock_release }"
 
 static unsigned int query_flags;
 
 static enum bpf_attach_type parse_attach_type(const char *str)
 {
+       const char *attach_type_str;
        enum bpf_attach_type type;
 
-       for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
-               if (attach_type_name[type] &&
-                   is_prefix(str, attach_type_name[type]))
+       for (type = 0; ; type++) {
+               attach_type_str = libbpf_bpf_attach_type_str(type);
+               if (!attach_type_str)
+                       break;
+               if (!strcmp(str, attach_type_str))
+                       return type;
+       }
+
+       /* Also check traditionally used attach type strings. For these we keep
+        * allowing prefixed usage.
+        */
+       for (type = 0; ; type++) {
+               attach_type_str = bpf_attach_type_input_str(type);
+               if (!attach_type_str)
+                       break;
+               if (is_prefix(str, attach_type_str))
                        return type;
        }
 
@@ -52,6 +70,7 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
 {
        char prog_name[MAX_PROG_FULL_NAME];
        struct bpf_prog_info info = {};
+       const char *attach_type_str;
        __u32 info_len = sizeof(info);
        int prog_fd;
 
@@ -64,13 +83,13 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
                return -1;
        }
 
+       attach_type_str = libbpf_bpf_attach_type_str(attach_type);
        get_prog_full_name(&info, prog_fd, prog_name, sizeof(prog_name));
        if (json_output) {
                jsonw_start_object(json_wtr);
                jsonw_uint_field(json_wtr, "id", info.id);
-               if (attach_type < ARRAY_SIZE(attach_type_name))
-                       jsonw_string_field(json_wtr, "attach_type",
-                                          attach_type_name[attach_type]);
+               if (attach_type_str)
+                       jsonw_string_field(json_wtr, "attach_type", attach_type_str);
                else
                        jsonw_uint_field(json_wtr, "attach_type", attach_type);
                jsonw_string_field(json_wtr, "attach_flags",
@@ -79,8 +98,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
                jsonw_end_object(json_wtr);
        } else {
                printf("%s%-8u ", level ? "    " : "", info.id);
-               if (attach_type < ARRAY_SIZE(attach_type_name))
-                       printf("%-15s", attach_type_name[attach_type]);
+               if (attach_type_str)
+                       printf("%-15s", attach_type_str);
                else
                        printf("type %-10u", attach_type);
                printf(" %-15s %-15s\n", attach_flags_str, prog_name);
index c740142..a0d4acd 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/magic.h>
 #include <net/if.h>
 #include <sys/mount.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/vfs.h>
 
 #define BPF_FS_MAGIC           0xcafe4a11
 #endif
 
-const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE] = {
-       [BPF_CGROUP_INET_INGRESS]       = "ingress",
-       [BPF_CGROUP_INET_EGRESS]        = "egress",
-       [BPF_CGROUP_INET_SOCK_CREATE]   = "sock_create",
-       [BPF_CGROUP_INET_SOCK_RELEASE]  = "sock_release",
-       [BPF_CGROUP_SOCK_OPS]           = "sock_ops",
-       [BPF_CGROUP_DEVICE]             = "device",
-       [BPF_CGROUP_INET4_BIND]         = "bind4",
-       [BPF_CGROUP_INET6_BIND]         = "bind6",
-       [BPF_CGROUP_INET4_CONNECT]      = "connect4",
-       [BPF_CGROUP_INET6_CONNECT]      = "connect6",
-       [BPF_CGROUP_INET4_POST_BIND]    = "post_bind4",
-       [BPF_CGROUP_INET6_POST_BIND]    = "post_bind6",
-       [BPF_CGROUP_INET4_GETPEERNAME]  = "getpeername4",
-       [BPF_CGROUP_INET6_GETPEERNAME]  = "getpeername6",
-       [BPF_CGROUP_INET4_GETSOCKNAME]  = "getsockname4",
-       [BPF_CGROUP_INET6_GETSOCKNAME]  = "getsockname6",
-       [BPF_CGROUP_UDP4_SENDMSG]       = "sendmsg4",
-       [BPF_CGROUP_UDP6_SENDMSG]       = "sendmsg6",
-       [BPF_CGROUP_SYSCTL]             = "sysctl",
-       [BPF_CGROUP_UDP4_RECVMSG]       = "recvmsg4",
-       [BPF_CGROUP_UDP6_RECVMSG]       = "recvmsg6",
-       [BPF_CGROUP_GETSOCKOPT]         = "getsockopt",
-       [BPF_CGROUP_SETSOCKOPT]         = "setsockopt",
-       [BPF_SK_SKB_STREAM_PARSER]      = "sk_skb_stream_parser",
-       [BPF_SK_SKB_STREAM_VERDICT]     = "sk_skb_stream_verdict",
-       [BPF_SK_SKB_VERDICT]            = "sk_skb_verdict",
-       [BPF_SK_MSG_VERDICT]            = "sk_msg_verdict",
-       [BPF_LIRC_MODE2]                = "lirc_mode2",
-       [BPF_FLOW_DISSECTOR]            = "flow_dissector",
-       [BPF_TRACE_RAW_TP]              = "raw_tp",
-       [BPF_TRACE_FENTRY]              = "fentry",
-       [BPF_TRACE_FEXIT]               = "fexit",
-       [BPF_MODIFY_RETURN]             = "mod_ret",
-       [BPF_LSM_MAC]                   = "lsm_mac",
-       [BPF_SK_LOOKUP]                 = "sk_lookup",
-       [BPF_TRACE_ITER]                = "trace_iter",
-       [BPF_XDP_DEVMAP]                = "xdp_devmap",
-       [BPF_XDP_CPUMAP]                = "xdp_cpumap",
-       [BPF_XDP]                       = "xdp",
-       [BPF_SK_REUSEPORT_SELECT]       = "sk_skb_reuseport_select",
-       [BPF_SK_REUSEPORT_SELECT_OR_MIGRATE]    = "sk_skb_reuseport_select_or_migrate",
-       [BPF_PERF_EVENT]                = "perf_event",
-       [BPF_TRACE_KPROBE_MULTI]        = "trace_kprobe_multi",
-};
-
 void p_err(const char *fmt, ...)
 {
        va_list ap;
@@ -118,6 +73,13 @@ static bool is_bpffs(char *path)
        return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
 }
 
+void set_max_rlimit(void)
+{
+       struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
+
+       setrlimit(RLIMIT_MEMLOCK, &rinf);
+}
+
 static int
 mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
 {
@@ -1009,3 +971,39 @@ bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx)
 {
        return k1 == k2;
 }
+
+const char *bpf_attach_type_input_str(enum bpf_attach_type t)
+{
+       switch (t) {
+       case BPF_CGROUP_INET_INGRESS:           return "ingress";
+       case BPF_CGROUP_INET_EGRESS:            return "egress";
+       case BPF_CGROUP_INET_SOCK_CREATE:       return "sock_create";
+       case BPF_CGROUP_INET_SOCK_RELEASE:      return "sock_release";
+       case BPF_CGROUP_SOCK_OPS:               return "sock_ops";
+       case BPF_CGROUP_DEVICE:                 return "device";
+       case BPF_CGROUP_INET4_BIND:             return "bind4";
+       case BPF_CGROUP_INET6_BIND:             return "bind6";
+       case BPF_CGROUP_INET4_CONNECT:          return "connect4";
+       case BPF_CGROUP_INET6_CONNECT:          return "connect6";
+       case BPF_CGROUP_INET4_POST_BIND:        return "post_bind4";
+       case BPF_CGROUP_INET6_POST_BIND:        return "post_bind6";
+       case BPF_CGROUP_INET4_GETPEERNAME:      return "getpeername4";
+       case BPF_CGROUP_INET6_GETPEERNAME:      return "getpeername6";
+       case BPF_CGROUP_INET4_GETSOCKNAME:      return "getsockname4";
+       case BPF_CGROUP_INET6_GETSOCKNAME:      return "getsockname6";
+       case BPF_CGROUP_UDP4_SENDMSG:           return "sendmsg4";
+       case BPF_CGROUP_UDP6_SENDMSG:           return "sendmsg6";
+       case BPF_CGROUP_SYSCTL:                 return "sysctl";
+       case BPF_CGROUP_UDP4_RECVMSG:           return "recvmsg4";
+       case BPF_CGROUP_UDP6_RECVMSG:           return "recvmsg6";
+       case BPF_CGROUP_GETSOCKOPT:             return "getsockopt";
+       case BPF_CGROUP_SETSOCKOPT:             return "setsockopt";
+       case BPF_TRACE_RAW_TP:                  return "raw_tp";
+       case BPF_TRACE_FENTRY:                  return "fentry";
+       case BPF_TRACE_FEXIT:                   return "fexit";
+       case BPF_MODIFY_RETURN:                 return "mod_ret";
+       case BPF_SK_REUSEPORT_SELECT:           return "sk_skb_reuseport_select";
+       case BPF_SK_REUSEPORT_SELECT_OR_MIGRATE:        return "sk_skb_reuseport_select_or_migrate";
+       default:        return libbpf_bpf_attach_type_str(t);
+       }
+}
index d12f460..bac4ef4 100644 (file)
@@ -548,8 +548,8 @@ static bool probe_prog_type_ifindex(enum bpf_prog_type prog_type, __u32 ifindex)
 }
 
 static void
-probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
-               const char *define_prefix, __u32 ifindex)
+probe_prog_type(enum bpf_prog_type prog_type, const char *prog_type_str,
+               bool *supported_types, const char *define_prefix, __u32 ifindex)
 {
        char feat_name[128], plain_desc[128], define_name[128];
        const char *plain_comment = "eBPF program_type ";
@@ -580,20 +580,16 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
 
        supported_types[prog_type] |= res;
 
-       if (!prog_type_name[prog_type]) {
-               p_info("program type name not found (type %d)", prog_type);
-               return;
-       }
        maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
-       if (strlen(prog_type_name[prog_type]) > maxlen) {
+       if (strlen(prog_type_str) > maxlen) {
                p_info("program type name too long");
                return;
        }
 
-       sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]);
-       sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]);
+       sprintf(feat_name, "have_%s_prog_type", prog_type_str);
+       sprintf(define_name, "%s_prog_type", prog_type_str);
        uppercase(define_name, sizeof(define_name));
-       sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
+       sprintf(plain_desc, "%s%s", plain_comment, prog_type_str);
        print_bool_feature(feat_name, plain_desc, define_name, res,
                           define_prefix);
 }
@@ -619,8 +615,8 @@ static bool probe_map_type_ifindex(enum bpf_map_type map_type, __u32 ifindex)
 }
 
 static void
-probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
-              __u32 ifindex)
+probe_map_type(enum bpf_map_type map_type, char const *map_type_str,
+              const char *define_prefix, __u32 ifindex)
 {
        char feat_name[128], plain_desc[128], define_name[128];
        const char *plain_comment = "eBPF map_type ";
@@ -645,20 +641,16 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
         * check required for unprivileged users
         */
 
-       if (!map_type_name[map_type]) {
-               p_info("map type name not found (type %d)", map_type);
-               return;
-       }
        maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
-       if (strlen(map_type_name[map_type]) > maxlen) {
+       if (strlen(map_type_str) > maxlen) {
                p_info("map type name too long");
                return;
        }
 
-       sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
-       sprintf(define_name, "%s_map_type", map_type_name[map_type]);
+       sprintf(feat_name, "have_%s_map_type", map_type_str);
+       sprintf(define_name, "%s_map_type", map_type_str);
        uppercase(define_name, sizeof(define_name));
-       sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
+       sprintf(plain_desc, "%s%s", plain_comment, map_type_str);
        print_bool_feature(feat_name, plain_desc, define_name, res,
                           define_prefix);
 }
@@ -728,10 +720,10 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
 }
 
 static void
-probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
+probe_helpers_for_progtype(enum bpf_prog_type prog_type,
+                          const char *prog_type_str, bool supported_type,
                           const char *define_prefix, __u32 ifindex)
 {
-       const char *ptype_name = prog_type_name[prog_type];
        char feat_name[128];
        unsigned int id;
        bool probe_res = false;
@@ -747,12 +739,12 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
                }
 
        if (json_output) {
-               sprintf(feat_name, "%s_available_helpers", ptype_name);
+               sprintf(feat_name, "%s_available_helpers", prog_type_str);
                jsonw_name(json_wtr, feat_name);
                jsonw_start_array(json_wtr);
        } else if (!define_prefix) {
                printf("eBPF helpers supported for program type %s:",
-                      ptype_name);
+                      prog_type_str);
        }
 
        for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
@@ -768,7 +760,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
                        /* fallthrough */
                default:
                        probe_res |= probe_helper_for_progtype(prog_type, supported_type,
-                                                 define_prefix, id, ptype_name,
+                                                 define_prefix, id, prog_type_str,
                                                  ifindex);
                }
        }
@@ -943,30 +935,47 @@ static void
 section_program_types(bool *supported_types, const char *define_prefix,
                      __u32 ifindex)
 {
-       unsigned int i;
+       unsigned int prog_type = BPF_PROG_TYPE_UNSPEC;
+       const char *prog_type_str;
 
        print_start_section("program_types",
                            "Scanning eBPF program types...",
                            "/*** eBPF program types ***/",
                            define_prefix);
 
-       for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
-               probe_prog_type(i, supported_types, define_prefix, ifindex);
+       while (true) {
+               prog_type++;
+               prog_type_str = libbpf_bpf_prog_type_str(prog_type);
+               /* libbpf will return NULL for variants unknown to it. */
+               if (!prog_type_str)
+                       break;
+
+               probe_prog_type(prog_type, prog_type_str, supported_types, define_prefix,
+                               ifindex);
+       }
 
        print_end_section();
 }
 
 static void section_map_types(const char *define_prefix, __u32 ifindex)
 {
-       unsigned int i;
+       unsigned int map_type = BPF_MAP_TYPE_UNSPEC;
+       const char *map_type_str;
 
        print_start_section("map_types",
                            "Scanning eBPF map types...",
                            "/*** eBPF map types ***/",
                            define_prefix);
 
-       for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
-               probe_map_type(i, define_prefix, ifindex);
+       while (true) {
+               map_type++;
+               map_type_str = libbpf_bpf_map_type_str(map_type);
+               /* libbpf will return NULL for variants unknown to it. */
+               if (!map_type_str)
+                       break;
+
+               probe_map_type(map_type, map_type_str, define_prefix, ifindex);
+       }
 
        print_end_section();
 }
@@ -974,7 +983,8 @@ static void section_map_types(const char *define_prefix, __u32 ifindex)
 static void
 section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
 {
-       unsigned int i;
+       unsigned int prog_type = BPF_PROG_TYPE_UNSPEC;
+       const char *prog_type_str;
 
        print_start_section("helpers",
                            "Scanning eBPF helper functions...",
@@ -996,9 +1006,18 @@ section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex)
                       "        %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n",
                       define_prefix, define_prefix, define_prefix,
                       define_prefix);
-       for (i = BPF_PROG_TYPE_UNSPEC + 1; i < prog_type_name_size; i++)
-               probe_helpers_for_progtype(i, supported_types[i], define_prefix,
+       while (true) {
+               prog_type++;
+               prog_type_str = libbpf_bpf_prog_type_str(prog_type);
+               /* libbpf will return NULL for variants unknown to it. */
+               if (!prog_type_str)
+                       break;
+
+               probe_helpers_for_progtype(prog_type, prog_type_str,
+                                          supported_types[prog_type],
+                                          define_prefix,
                                           ifindex);
+       }
 
        print_end_section();
 }
@@ -1148,6 +1167,8 @@ static int do_probe(int argc, char **argv)
        __u32 ifindex = 0;
        char *ifname;
 
+       set_max_rlimit();
+
        while (argc) {
                if (is_prefix(*argv, "kernel")) {
                        if (target != COMPONENT_UNSPEC) {
index 4c9477f..480cbd8 100644 (file)
@@ -474,6 +474,9 @@ static void codegen_asserts(struct bpf_object *obj, const char *obj_name)
        const struct btf_type *sec;
        char map_ident[256], var_ident[256];
 
+       if (!btf)
+               return;
+
        codegen("\
                \n\
                __attribute__((unused)) static void                         \n\
@@ -1747,6 +1750,7 @@ btfgen_mark_type(struct btfgen_info *info, unsigned int type_id, bool follow_poi
        case BTF_KIND_INT:
        case BTF_KIND_FLOAT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_STRUCT:
        case BTF_KIND_UNION:
                break;
index 6353a78..7a20931 100644 (file)
 #include "json_writer.h"
 #include "main.h"
 
-static const char * const link_type_name[] = {
-       [BPF_LINK_TYPE_UNSPEC]                  = "unspec",
-       [BPF_LINK_TYPE_RAW_TRACEPOINT]          = "raw_tracepoint",
-       [BPF_LINK_TYPE_TRACING]                 = "tracing",
-       [BPF_LINK_TYPE_CGROUP]                  = "cgroup",
-       [BPF_LINK_TYPE_ITER]                    = "iter",
-       [BPF_LINK_TYPE_NETNS]                   = "netns",
-       [BPF_LINK_TYPE_XDP]                     = "xdp",
-       [BPF_LINK_TYPE_PERF_EVENT]              = "perf_event",
-       [BPF_LINK_TYPE_KPROBE_MULTI]            = "kprobe_multi",
-       [BPF_LINK_TYPE_STRUCT_OPS]               = "struct_ops",
-};
-
 static struct hashmap *link_table;
 
 static int link_parse_fd(int *argc, char ***argv)
@@ -67,9 +54,12 @@ static int link_parse_fd(int *argc, char ***argv)
 static void
 show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr)
 {
+       const char *link_type_str;
+
        jsonw_uint_field(wtr, "id", info->id);
-       if (info->type < ARRAY_SIZE(link_type_name))
-               jsonw_string_field(wtr, "type", link_type_name[info->type]);
+       link_type_str = libbpf_bpf_link_type_str(info->type);
+       if (link_type_str)
+               jsonw_string_field(wtr, "type", link_type_str);
        else
                jsonw_uint_field(wtr, "type", info->type);
 
@@ -78,9 +68,11 @@ show_link_header_json(struct bpf_link_info *info, json_writer_t *wtr)
 
 static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr)
 {
-       if (attach_type < ARRAY_SIZE(attach_type_name))
-               jsonw_string_field(wtr, "attach_type",
-                                  attach_type_name[attach_type]);
+       const char *attach_type_str;
+
+       attach_type_str = libbpf_bpf_attach_type_str(attach_type);
+       if (attach_type_str)
+               jsonw_string_field(wtr, "attach_type", attach_type_str);
        else
                jsonw_uint_field(wtr, "attach_type", attach_type);
 }
@@ -121,6 +113,7 @@ static int get_prog_info(int prog_id, struct bpf_prog_info *info)
 static int show_link_close_json(int fd, struct bpf_link_info *info)
 {
        struct bpf_prog_info prog_info;
+       const char *prog_type_str;
        int err;
 
        jsonw_start_object(json_wtr);
@@ -137,12 +130,12 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
                if (err)
                        return err;
 
-               if (prog_info.type < prog_type_name_size)
-                       jsonw_string_field(json_wtr, "prog_type",
-                                          prog_type_name[prog_info.type]);
+               prog_type_str = libbpf_bpf_prog_type_str(prog_info.type);
+               /* libbpf will return NULL for variants unknown to it. */
+               if (prog_type_str)
+                       jsonw_string_field(json_wtr, "prog_type", prog_type_str);
                else
-                       jsonw_uint_field(json_wtr, "prog_type",
-                                        prog_info.type);
+                       jsonw_uint_field(json_wtr, "prog_type", prog_info.type);
 
                show_link_attach_type_json(info->tracing.attach_type,
                                           json_wtr);
@@ -184,9 +177,12 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
 
 static void show_link_header_plain(struct bpf_link_info *info)
 {
+       const char *link_type_str;
+
        printf("%u: ", info->id);
-       if (info->type < ARRAY_SIZE(link_type_name))
-               printf("%s  ", link_type_name[info->type]);
+       link_type_str = libbpf_bpf_link_type_str(info->type);
+       if (link_type_str)
+               printf("%s  ", link_type_str);
        else
                printf("type %u  ", info->type);
 
@@ -195,8 +191,11 @@ static void show_link_header_plain(struct bpf_link_info *info)
 
 static void show_link_attach_type_plain(__u32 attach_type)
 {
-       if (attach_type < ARRAY_SIZE(attach_type_name))
-               printf("attach_type %s  ", attach_type_name[attach_type]);
+       const char *attach_type_str;
+
+       attach_type_str = libbpf_bpf_attach_type_str(attach_type);
+       if (attach_type_str)
+               printf("attach_type %s  ", attach_type_str);
        else
                printf("attach_type %u  ", attach_type);
 }
@@ -214,6 +213,7 @@ static void show_iter_plain(struct bpf_link_info *info)
 static int show_link_close_plain(int fd, struct bpf_link_info *info)
 {
        struct bpf_prog_info prog_info;
+       const char *prog_type_str;
        int err;
 
        show_link_header_plain(info);
@@ -228,9 +228,10 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
                if (err)
                        return err;
 
-               if (prog_info.type < prog_type_name_size)
-                       printf("\n\tprog_type %s  ",
-                              prog_type_name[prog_info.type]);
+               prog_type_str = libbpf_bpf_prog_type_str(prog_info.type);
+               /* libbpf will return NULL for variants unknown to it. */
+               if (prog_type_str)
+                       printf("\n\tprog_type %s  ", prog_type_str);
                else
                        printf("\n\tprog_type %u  ", prog_info.type);
 
index 9062ef2..451cefc 100644 (file)
@@ -508,8 +508,6 @@ int main(int argc, char **argv)
                 * mode for loading generated skeleton.
                 */
                libbpf_set_strict_mode(LIBBPF_STRICT_ALL & ~LIBBPF_STRICT_MAP_DEFINITIONS);
-       } else {
-               libbpf_set_strict_mode(LIBBPF_STRICT_AUTO_RLIMIT_MEMLOCK);
        }
 
        argc -= optind;
index aa99ffa..589cb76 100644 (file)
@@ -63,14 +63,8 @@ static inline void *u64_to_ptr(__u64 ptr)
 #define HELP_SPEC_LINK                                                 \
        "LINK := { id LINK_ID | pinned FILE }"
 
-extern const char * const prog_type_name[];
-extern const size_t prog_type_name_size;
-
 extern const char * const attach_type_name[__MAX_BPF_ATTACH_TYPE];
 
-extern const char * const map_type_name[];
-extern const size_t map_type_name_size;
-
 /* keep in sync with the definition in skeleton/pid_iter.bpf.c */
 enum bpf_obj_type {
        BPF_OBJ_UNKNOWN,
@@ -102,6 +96,8 @@ int detect_common_prefix(const char *arg, ...);
 void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
 void usage(void) __noreturn;
 
+void set_max_rlimit(void);
+
 int mount_tracefs(const char *target);
 
 struct obj_ref {
@@ -249,6 +245,20 @@ int print_all_levels(__maybe_unused enum libbpf_print_level level,
 size_t hash_fn_for_key_as_id(const void *key, void *ctx);
 bool equal_fn_for_key_as_id(const void *k1, const void *k2, void *ctx);
 
+/* bpf_attach_type_input_str - convert the provided attach type value into a
+ * textual representation that we accept for input purposes.
+ *
+ * This function is similar in nature to libbpf_bpf_attach_type_str, but
+ * recognizes some attach type names that have been used by the program in the
+ * past and which do not follow the string inference scheme that libbpf uses.
+ * These textual representations should only be used for user input.
+ *
+ * @t: The attach type
+ * Returns a pointer to a static string identifying the attach type. NULL is
+ * returned for unknown bpf_attach_type values.
+ */
+const char *bpf_attach_type_input_str(enum bpf_attach_type t);
+
 static inline void *u32_as_hash_field(__u32 x)
 {
        return (void *)(uintptr_t)x;
index 877387e..38b6bc9 100644 (file)
 #include "json_writer.h"
 #include "main.h"
 
-const char * const map_type_name[] = {
-       [BPF_MAP_TYPE_UNSPEC]                   = "unspec",
-       [BPF_MAP_TYPE_HASH]                     = "hash",
-       [BPF_MAP_TYPE_ARRAY]                    = "array",
-       [BPF_MAP_TYPE_PROG_ARRAY]               = "prog_array",
-       [BPF_MAP_TYPE_PERF_EVENT_ARRAY]         = "perf_event_array",
-       [BPF_MAP_TYPE_PERCPU_HASH]              = "percpu_hash",
-       [BPF_MAP_TYPE_PERCPU_ARRAY]             = "percpu_array",
-       [BPF_MAP_TYPE_STACK_TRACE]              = "stack_trace",
-       [BPF_MAP_TYPE_CGROUP_ARRAY]             = "cgroup_array",
-       [BPF_MAP_TYPE_LRU_HASH]                 = "lru_hash",
-       [BPF_MAP_TYPE_LRU_PERCPU_HASH]          = "lru_percpu_hash",
-       [BPF_MAP_TYPE_LPM_TRIE]                 = "lpm_trie",
-       [BPF_MAP_TYPE_ARRAY_OF_MAPS]            = "array_of_maps",
-       [BPF_MAP_TYPE_HASH_OF_MAPS]             = "hash_of_maps",
-       [BPF_MAP_TYPE_DEVMAP]                   = "devmap",
-       [BPF_MAP_TYPE_DEVMAP_HASH]              = "devmap_hash",
-       [BPF_MAP_TYPE_SOCKMAP]                  = "sockmap",
-       [BPF_MAP_TYPE_CPUMAP]                   = "cpumap",
-       [BPF_MAP_TYPE_XSKMAP]                   = "xskmap",
-       [BPF_MAP_TYPE_SOCKHASH]                 = "sockhash",
-       [BPF_MAP_TYPE_CGROUP_STORAGE]           = "cgroup_storage",
-       [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY]      = "reuseport_sockarray",
-       [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE]    = "percpu_cgroup_storage",
-       [BPF_MAP_TYPE_QUEUE]                    = "queue",
-       [BPF_MAP_TYPE_STACK]                    = "stack",
-       [BPF_MAP_TYPE_SK_STORAGE]               = "sk_storage",
-       [BPF_MAP_TYPE_STRUCT_OPS]               = "struct_ops",
-       [BPF_MAP_TYPE_RINGBUF]                  = "ringbuf",
-       [BPF_MAP_TYPE_INODE_STORAGE]            = "inode_storage",
-       [BPF_MAP_TYPE_TASK_STORAGE]             = "task_storage",
-       [BPF_MAP_TYPE_BLOOM_FILTER]             = "bloom_filter",
-};
-
-const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
-
 static struct hashmap *map_table;
 
 static bool map_is_per_cpu(__u32 type)
@@ -81,12 +45,18 @@ static bool map_is_map_of_progs(__u32 type)
 
 static int map_type_from_str(const char *type)
 {
+       const char *map_type_str;
        unsigned int i;
 
-       for (i = 0; i < ARRAY_SIZE(map_type_name); i++)
+       for (i = 0; ; i++) {
+               map_type_str = libbpf_bpf_map_type_str(i);
+               if (!map_type_str)
+                       break;
+
                /* Don't allow prefixing in case of possible future shadowing */
-               if (map_type_name[i] && !strcmp(map_type_name[i], type))
+               if (!strcmp(map_type_str, type))
                        return i;
+       }
        return -1;
 }
 
@@ -472,9 +442,12 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
 
 static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
 {
+       const char *map_type_str;
+
        jsonw_uint_field(wtr, "id", info->id);
-       if (info->type < ARRAY_SIZE(map_type_name))
-               jsonw_string_field(wtr, "type", map_type_name[info->type]);
+       map_type_str = libbpf_bpf_map_type_str(info->type);
+       if (map_type_str)
+               jsonw_string_field(wtr, "type", map_type_str);
        else
                jsonw_uint_field(wtr, "type", info->type);
 
@@ -513,10 +486,12 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
 
                if (owner_prog_type) {
                        unsigned int prog_type = atoi(owner_prog_type);
+                       const char *prog_type_str;
 
-                       if (prog_type < prog_type_name_size)
+                       prog_type_str = libbpf_bpf_prog_type_str(prog_type);
+                       if (prog_type_str)
                                jsonw_string_field(json_wtr, "owner_prog_type",
-                                                  prog_type_name[prog_type]);
+                                                  prog_type_str);
                        else
                                jsonw_uint_field(json_wtr, "owner_prog_type",
                                                 prog_type);
@@ -559,9 +534,13 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
 
 static void show_map_header_plain(struct bpf_map_info *info)
 {
+       const char *map_type_str;
+
        printf("%u: ", info->id);
-       if (info->type < ARRAY_SIZE(map_type_name))
-               printf("%s  ", map_type_name[info->type]);
+
+       map_type_str = libbpf_bpf_map_type_str(info->type);
+       if (map_type_str)
+               printf("%s  ", map_type_str);
        else
                printf("type %u  ", info->type);
 
@@ -597,10 +576,11 @@ static int show_map_close_plain(int fd, struct bpf_map_info *info)
                        printf("\n\t");
                if (owner_prog_type) {
                        unsigned int prog_type = atoi(owner_prog_type);
+                       const char *prog_type_str;
 
-                       if (prog_type < prog_type_name_size)
-                               printf("owner_prog_type %s  ",
-                                      prog_type_name[prog_type]);
+                       prog_type_str = libbpf_bpf_prog_type_str(prog_type);
+                       if (prog_type_str)
+                               printf("owner_prog_type %s  ", prog_type_str);
                        else
                                printf("owner_prog_type %d  ", prog_type);
                }
@@ -876,9 +856,13 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t *wtr,
        }
 
        if (info->type == BPF_MAP_TYPE_REUSEPORT_SOCKARRAY &&
-           info->value_size != 8)
+           info->value_size != 8) {
+               const char *map_type_str;
+
+               map_type_str = libbpf_bpf_map_type_str(info->type);
                p_info("Warning: cannot read values from %s map with value_size != 8",
-                      map_type_name[info->type]);
+                      map_type_str);
+       }
        while (true) {
                err = bpf_map_get_next_key(fd, prev_key, key);
                if (err) {
@@ -1342,6 +1326,8 @@ static int do_create(int argc, char **argv)
                goto exit;
        }
 
+       set_max_rlimit();
+
        fd = bpf_map_create(map_type, map_name, key_size, value_size, max_entries, &attr);
        if (fd < 0) {
                p_err("map create failed: %s", strerror(errno));
index e2d00d3..bb6c969 100644 (file)
@@ -108,6 +108,7 @@ int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
                p_err("failed to create hashmap for PID references");
                return -1;
        }
+       set_max_rlimit();
 
        skel = pid_iter_bpf__open();
        if (!skel) {
index 5c2c63d..f081de3 100644 (file)
 #define BPF_METADATA_PREFIX "bpf_metadata_"
 #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1)
 
-const char * const prog_type_name[] = {
-       [BPF_PROG_TYPE_UNSPEC]                  = "unspec",
-       [BPF_PROG_TYPE_SOCKET_FILTER]           = "socket_filter",
-       [BPF_PROG_TYPE_KPROBE]                  = "kprobe",
-       [BPF_PROG_TYPE_SCHED_CLS]               = "sched_cls",
-       [BPF_PROG_TYPE_SCHED_ACT]               = "sched_act",
-       [BPF_PROG_TYPE_TRACEPOINT]              = "tracepoint",
-       [BPF_PROG_TYPE_XDP]                     = "xdp",
-       [BPF_PROG_TYPE_PERF_EVENT]              = "perf_event",
-       [BPF_PROG_TYPE_CGROUP_SKB]              = "cgroup_skb",
-       [BPF_PROG_TYPE_CGROUP_SOCK]             = "cgroup_sock",
-       [BPF_PROG_TYPE_LWT_IN]                  = "lwt_in",
-       [BPF_PROG_TYPE_LWT_OUT]                 = "lwt_out",
-       [BPF_PROG_TYPE_LWT_XMIT]                = "lwt_xmit",
-       [BPF_PROG_TYPE_SOCK_OPS]                = "sock_ops",
-       [BPF_PROG_TYPE_SK_SKB]                  = "sk_skb",
-       [BPF_PROG_TYPE_CGROUP_DEVICE]           = "cgroup_device",
-       [BPF_PROG_TYPE_SK_MSG]                  = "sk_msg",
-       [BPF_PROG_TYPE_RAW_TRACEPOINT]          = "raw_tracepoint",
-       [BPF_PROG_TYPE_CGROUP_SOCK_ADDR]        = "cgroup_sock_addr",
-       [BPF_PROG_TYPE_LWT_SEG6LOCAL]           = "lwt_seg6local",
-       [BPF_PROG_TYPE_LIRC_MODE2]              = "lirc_mode2",
-       [BPF_PROG_TYPE_SK_REUSEPORT]            = "sk_reuseport",
-       [BPF_PROG_TYPE_FLOW_DISSECTOR]          = "flow_dissector",
-       [BPF_PROG_TYPE_CGROUP_SYSCTL]           = "cgroup_sysctl",
-       [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
-       [BPF_PROG_TYPE_CGROUP_SOCKOPT]          = "cgroup_sockopt",
-       [BPF_PROG_TYPE_TRACING]                 = "tracing",
-       [BPF_PROG_TYPE_STRUCT_OPS]              = "struct_ops",
-       [BPF_PROG_TYPE_EXT]                     = "ext",
-       [BPF_PROG_TYPE_LSM]                     = "lsm",
-       [BPF_PROG_TYPE_SK_LOOKUP]               = "sk_lookup",
-       [BPF_PROG_TYPE_SYSCALL]                 = "syscall",
-};
-
-const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name);
-
 enum dump_mode {
        DUMP_JITED,
        DUMP_XLATED,
 };
 
+static const bool attach_types[] = {
+       [BPF_SK_SKB_STREAM_PARSER] = true,
+       [BPF_SK_SKB_STREAM_VERDICT] = true,
+       [BPF_SK_SKB_VERDICT] = true,
+       [BPF_SK_MSG_VERDICT] = true,
+       [BPF_FLOW_DISSECTOR] = true,
+       [__MAX_BPF_ATTACH_TYPE] = false,
+};
+
+/* Textual representations traditionally used by the program and kept around
+ * for the sake of backwards compatibility.
+ */
 static const char * const attach_type_strings[] = {
        [BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
        [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
        [BPF_SK_SKB_VERDICT] = "skb_verdict",
        [BPF_SK_MSG_VERDICT] = "msg_verdict",
-       [BPF_FLOW_DISSECTOR] = "flow_dissector",
        [__MAX_BPF_ATTACH_TYPE] = NULL,
 };
 
@@ -94,6 +68,14 @@ static enum bpf_attach_type parse_attach_type(const char *str)
        enum bpf_attach_type type;
 
        for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
+               if (attach_types[type]) {
+                       const char *attach_type_str;
+
+                       attach_type_str = libbpf_bpf_attach_type_str(type);
+                       if (!strcmp(str, attach_type_str))
+                               return type;
+               }
+
                if (attach_type_strings[type] &&
                    is_prefix(str, attach_type_strings[type]))
                        return type;
@@ -428,12 +410,14 @@ out_free:
 
 static void print_prog_header_json(struct bpf_prog_info *info, int fd)
 {
+       const char *prog_type_str;
        char prog_name[MAX_PROG_FULL_NAME];
 
        jsonw_uint_field(json_wtr, "id", info->id);
-       if (info->type < ARRAY_SIZE(prog_type_name))
-               jsonw_string_field(json_wtr, "type",
-                                  prog_type_name[info->type]);
+       prog_type_str = libbpf_bpf_prog_type_str(info->type);
+
+       if (prog_type_str)
+               jsonw_string_field(json_wtr, "type", prog_type_str);
        else
                jsonw_uint_field(json_wtr, "type", info->type);
 
@@ -515,11 +499,13 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
 
 static void print_prog_header_plain(struct bpf_prog_info *info, int fd)
 {
+       const char *prog_type_str;
        char prog_name[MAX_PROG_FULL_NAME];
 
        printf("%u: ", info->id);
-       if (info->type < ARRAY_SIZE(prog_type_name))
-               printf("%s  ", prog_type_name[info->type]);
+       prog_type_str = libbpf_bpf_prog_type_str(info->type);
+       if (prog_type_str)
+               printf("%s  ", prog_type_str);
        else
                printf("type %u  ", info->type);
 
@@ -1604,6 +1590,8 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
                }
        }
 
+       set_max_rlimit();
+
        if (verifier_logs)
                /* log_level1 + log_level2 + stats, but not stable UAPI */
                open_opts.kernel_log_level = 1 + 2 + 4;
@@ -2301,6 +2289,7 @@ static int do_profile(int argc, char **argv)
                }
        }
 
+       set_max_rlimit();
        err = profiler_bpf__load(profile_obj);
        if (err) {
                p_err("failed to load profile_obj");
@@ -2374,8 +2363,8 @@ static int do_help(int argc, char **argv)
                "                 cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n"
                "                 cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n"
                "                 struct_ops | fentry | fexit | freplace | sk_lookup }\n"
-               "       ATTACH_TYPE := { msg_verdict | skb_verdict | stream_verdict |\n"
-               "                        stream_parser | flow_dissector }\n"
+               "       ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n"
+               "                        sk_skb_stream_parser | flow_dissector }\n"
                "       METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n"
                "       " HELP_SPEC_OPTIONS " |\n"
                "                    {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n"
index 2535f07..e08a6ff 100644 (file)
@@ -501,6 +501,8 @@ static int do_register(int argc, char **argv)
        if (libbpf_get_error(obj))
                return -1;
 
+       set_max_rlimit();
+
        if (bpf_object__load(obj)) {
                bpf_object__close(obj);
                return -1;
index f4009db..e813628 100644 (file)
@@ -3597,10 +3597,11 @@ union bpf_attr {
  *
  *             *iph* points to the start of the IPv4 or IPv6 header, while
  *             *iph_len* contains **sizeof**\ (**struct iphdr**) or
- *             **sizeof**\ (**struct ip6hdr**).
+ *             **sizeof**\ (**struct ipv6hdr**).
  *
  *             *th* points to the start of the TCP header, while *th_len*
- *             contains **sizeof**\ (**struct tcphdr**).
+ *             contains the length of the TCP header (at least
+ *             **sizeof**\ (**struct tcphdr**)).
  *     Return
  *             0 if *iph* and *th* are a valid SYN cookie ACK, or a negative
  *             error otherwise.
@@ -3783,10 +3784,11 @@ union bpf_attr {
  *
  *             *iph* points to the start of the IPv4 or IPv6 header, while
  *             *iph_len* contains **sizeof**\ (**struct iphdr**) or
- *             **sizeof**\ (**struct ip6hdr**).
+ *             **sizeof**\ (**struct ipv6hdr**).
  *
  *             *th* points to the start of the TCP header, while *th_len*
- *             contains the length of the TCP header.
+ *             contains the length of the TCP header with options (at least
+ *             **sizeof**\ (**struct tcphdr**)).
  *     Return
  *             On success, lower 32 bits hold the generated SYN cookie in
  *             followed by 16 bits which hold the MSS value for that cookie,
@@ -5249,6 +5251,80 @@ union bpf_attr {
  *             Pointer to the underlying dynptr data, NULL if the dynptr is
  *             read-only, if the dynptr is invalid, or if the offset and length
  *             is out of bounds.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th, u32 th_len)
+ *     Description
+ *             Try to issue a SYN cookie for the packet with corresponding
+ *             IPv4/TCP headers, *iph* and *th*, without depending on a
+ *             listening socket.
+ *
+ *             *iph* points to the IPv4 header.
+ *
+ *             *th* points to the start of the TCP header, while *th_len*
+ *             contains the length of the TCP header (at least
+ *             **sizeof**\ (**struct tcphdr**)).
+ *     Return
+ *             On success, lower 32 bits hold the generated SYN cookie in
+ *             followed by 16 bits which hold the MSS value for that cookie,
+ *             and the top 16 bits are unused.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EINVAL** if *th_len* is invalid.
+ *
+ * s64 bpf_tcp_raw_gen_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th, u32 th_len)
+ *     Description
+ *             Try to issue a SYN cookie for the packet with corresponding
+ *             IPv6/TCP headers, *iph* and *th*, without depending on a
+ *             listening socket.
+ *
+ *             *iph* points to the IPv6 header.
+ *
+ *             *th* points to the start of the TCP header, while *th_len*
+ *             contains the length of the TCP header (at least
+ *             **sizeof**\ (**struct tcphdr**)).
+ *     Return
+ *             On success, lower 32 bits hold the generated SYN cookie in
+ *             followed by 16 bits which hold the MSS value for that cookie,
+ *             and the top 16 bits are unused.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EINVAL** if *th_len* is invalid.
+ *
+ *             **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
+ *
+ * long bpf_tcp_raw_check_syncookie_ipv4(struct iphdr *iph, struct tcphdr *th)
+ *     Description
+ *             Check whether *iph* and *th* contain a valid SYN cookie ACK
+ *             without depending on a listening socket.
+ *
+ *             *iph* points to the IPv4 header.
+ *
+ *             *th* points to the TCP header.
+ *     Return
+ *             0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EACCES** if the SYN cookie is not valid.
+ *
+ * long bpf_tcp_raw_check_syncookie_ipv6(struct ipv6hdr *iph, struct tcphdr *th)
+ *     Description
+ *             Check whether *iph* and *th* contain a valid SYN cookie ACK
+ *             without depending on a listening socket.
+ *
+ *             *iph* points to the IPv6 header.
+ *
+ *             *th* points to the TCP header.
+ *     Return
+ *             0 if *iph* and *th* are a valid SYN cookie ACK.
+ *
+ *             On failure, the returned value is one of the following:
+ *
+ *             **-EACCES** if the SYN cookie is not valid.
+ *
+ *             **-EPROTONOSUPPORT** if CONFIG_IPV6 is not builtin.
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -5455,6 +5531,10 @@ union bpf_attr {
        FN(dynptr_read),                \
        FN(dynptr_write),               \
        FN(dynptr_data),                \
+       FN(tcp_raw_gen_syncookie_ipv4), \
+       FN(tcp_raw_gen_syncookie_ipv6), \
+       FN(tcp_raw_check_syncookie_ipv4),       \
+       FN(tcp_raw_check_syncookie_ipv6),       \
        /* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
index a9162a6..ec1798b 100644 (file)
@@ -36,10 +36,10 @@ struct btf_type {
         * bits 24-28: kind (e.g. int, ptr, array...etc)
         * bits 29-30: unused
         * bit     31: kind_flag, currently used by
-        *             struct, union and fwd
+        *             struct, union, enum, fwd and enum64
         */
        __u32 info;
-       /* "size" is used by INT, ENUM, STRUCT, UNION and DATASEC.
+       /* "size" is used by INT, ENUM, STRUCT, UNION, DATASEC and ENUM64.
         * "size" tells the size of the type it is describing.
         *
         * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
@@ -63,7 +63,7 @@ enum {
        BTF_KIND_ARRAY          = 3,    /* Array        */
        BTF_KIND_STRUCT         = 4,    /* Struct       */
        BTF_KIND_UNION          = 5,    /* Union        */
-       BTF_KIND_ENUM           = 6,    /* Enumeration  */
+       BTF_KIND_ENUM           = 6,    /* Enumeration up to 32-bit values */
        BTF_KIND_FWD            = 7,    /* Forward      */
        BTF_KIND_TYPEDEF        = 8,    /* Typedef      */
        BTF_KIND_VOLATILE       = 9,    /* Volatile     */
@@ -76,6 +76,7 @@ enum {
        BTF_KIND_FLOAT          = 16,   /* Floating point       */
        BTF_KIND_DECL_TAG       = 17,   /* Decl Tag */
        BTF_KIND_TYPE_TAG       = 18,   /* Type Tag */
+       BTF_KIND_ENUM64         = 19,   /* Enumeration up to 64-bit values */
 
        NR_BTF_KINDS,
        BTF_KIND_MAX            = NR_BTF_KINDS - 1,
@@ -186,4 +187,14 @@ struct btf_decl_tag {
        __s32   component_idx;
 };
 
+/* BTF_KIND_ENUM64 is followed by multiple "struct btf_enum64".
+ * The exact number of btf_enum64 is stored in the vlen (of the
+ * info in "struct btf_type").
+ */
+struct btf_enum64 {
+       __u32   name_off;
+       __u32   val_lo32;
+       __u32   val_hi32;
+};
+
 #endif /* _UAPI__LINUX_BTF_H__ */
index b339bf2..0242f31 100644 (file)
@@ -890,6 +890,7 @@ enum {
        IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
        IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
        IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+       IFLA_BOND_SLAVE_PRIO,
        __IFLA_BOND_SLAVE_MAX,
 };
 
index bb1e06e..ae1520f 100644 (file)
@@ -130,7 +130,7 @@ static inline __u64 ptr_to_u64(const void *ptr)
 
 /* Ensure given dynamically allocated memory region pointed to by *data* with
  * capacity of *cap_cnt* elements each taking *elem_sz* bytes has enough
- * memory to accomodate *add_cnt* new elements, assuming *cur_cnt* elements
+ * memory to accommodate *add_cnt* new elements, assuming *cur_cnt* elements
  * are already used. At most *max_cnt* elements can be ever allocated.
  * If necessary, memory is reallocated and all existing data is copied over,
  * new pointer to the memory region is stored at *data, new memory region
@@ -305,6 +305,8 @@ static int btf_type_size(const struct btf_type *t)
                return base_size + sizeof(__u32);
        case BTF_KIND_ENUM:
                return base_size + vlen * sizeof(struct btf_enum);
+       case BTF_KIND_ENUM64:
+               return base_size + vlen * sizeof(struct btf_enum64);
        case BTF_KIND_ARRAY:
                return base_size + sizeof(struct btf_array);
        case BTF_KIND_STRUCT:
@@ -334,6 +336,7 @@ static void btf_bswap_type_base(struct btf_type *t)
 static int btf_bswap_type_rest(struct btf_type *t)
 {
        struct btf_var_secinfo *v;
+       struct btf_enum64 *e64;
        struct btf_member *m;
        struct btf_array *a;
        struct btf_param *p;
@@ -361,6 +364,13 @@ static int btf_bswap_type_rest(struct btf_type *t)
                        e->val = bswap_32(e->val);
                }
                return 0;
+       case BTF_KIND_ENUM64:
+               for (i = 0, e64 = btf_enum64(t); i < vlen; i++, e64++) {
+                       e64->name_off = bswap_32(e64->name_off);
+                       e64->val_lo32 = bswap_32(e64->val_lo32);
+                       e64->val_hi32 = bswap_32(e64->val_hi32);
+               }
+               return 0;
        case BTF_KIND_ARRAY:
                a = btf_array(t);
                a->type = bswap_32(a->type);
@@ -472,9 +482,22 @@ const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
 
 static int determine_ptr_size(const struct btf *btf)
 {
+       static const char * const long_aliases[] = {
+               "long",
+               "long int",
+               "int long",
+               "unsigned long",
+               "long unsigned",
+               "unsigned long int",
+               "unsigned int long",
+               "long unsigned int",
+               "long int unsigned",
+               "int unsigned long",
+               "int long unsigned",
+       };
        const struct btf_type *t;
        const char *name;
-       int i, n;
+       int i, j, n;
 
        if (btf->base_btf && btf->base_btf->ptr_sz > 0)
                return btf->base_btf->ptr_sz;
@@ -485,15 +508,16 @@ static int determine_ptr_size(const struct btf *btf)
                if (!btf_is_int(t))
                        continue;
 
+               if (t->size != 4 && t->size != 8)
+                       continue;
+
                name = btf__name_by_offset(btf, t->name_off);
                if (!name)
                        continue;
 
-               if (strcmp(name, "long int") == 0 ||
-                   strcmp(name, "long unsigned int") == 0) {
-                       if (t->size != 4 && t->size != 8)
-                               continue;
-                       return t->size;
+               for (j = 0; j < ARRAY_SIZE(long_aliases); j++) {
+                       if (strcmp(name, long_aliases[j]) == 0)
+                               return t->size;
                }
        }
 
@@ -597,6 +621,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
                case BTF_KIND_STRUCT:
                case BTF_KIND_UNION:
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                case BTF_KIND_DATASEC:
                case BTF_KIND_FLOAT:
                        size = t->size;
@@ -644,6 +669,7 @@ int btf__align_of(const struct btf *btf, __u32 id)
        switch (kind) {
        case BTF_KIND_INT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_FLOAT:
                return min(btf_ptr_sz(btf), (size_t)t->size);
        case BTF_KIND_PTR:
@@ -2115,20 +2141,8 @@ int btf__add_field(struct btf *btf, const char *name, int type_id,
        return 0;
 }
 
-/*
- * Append new BTF_KIND_ENUM type with:
- *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
- *   - *byte_sz* - size of the enum, in bytes.
- *
- * Enum initially has no enum values in it (and corresponds to enum forward
- * declaration). Enumerator values can be added by btf__add_enum_value()
- * immediately after btf__add_enum() succeeds.
- *
- * Returns:
- *   - >0, type ID of newly added BTF type;
- *   - <0, on error.
- */
-int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
+static int btf_add_enum_common(struct btf *btf, const char *name, __u32 byte_sz,
+                              bool is_signed, __u8 kind)
 {
        struct btf_type *t;
        int sz, name_off = 0;
@@ -2153,13 +2167,35 @@ int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
 
        /* start out with vlen=0; it will be adjusted when adding enum values */
        t->name_off = name_off;
-       t->info = btf_type_info(BTF_KIND_ENUM, 0, 0);
+       t->info = btf_type_info(kind, 0, is_signed);
        t->size = byte_sz;
 
        return btf_commit_type(btf, sz);
 }
 
 /*
+ * Append new BTF_KIND_ENUM type with:
+ *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
+ *   - *byte_sz* - size of the enum, in bytes.
+ *
+ * Enum initially has no enum values in it (and corresponds to enum forward
+ * declaration). Enumerator values can be added by btf__add_enum_value()
+ * immediately after btf__add_enum() succeeds.
+ *
+ * Returns:
+ *   - >0, type ID of newly added BTF type;
+ *   - <0, on error.
+ */
+int btf__add_enum(struct btf *btf, const char *name, __u32 byte_sz)
+{
+       /*
+        * set the signedness to be unsigned, it will change to signed
+        * if any later enumerator is negative.
+        */
+       return btf_add_enum_common(btf, name, byte_sz, false, BTF_KIND_ENUM);
+}
+
+/*
  * Append new enum value for the current ENUM type with:
  *   - *name* - name of the enumerator value, can't be NULL or empty;
  *   - *value* - integer value corresponding to enum value *name*;
@@ -2206,6 +2242,82 @@ int btf__add_enum_value(struct btf *btf, const char *name, __s64 value)
        t = btf_last_type(btf);
        btf_type_inc_vlen(t);
 
+       /* if negative value, set signedness to signed */
+       if (value < 0)
+               t->info = btf_type_info(btf_kind(t), btf_vlen(t), true);
+
+       btf->hdr->type_len += sz;
+       btf->hdr->str_off += sz;
+       return 0;
+}
+
+/*
+ * Append new BTF_KIND_ENUM64 type with:
+ *   - *name* - name of the enum, can be NULL or empty for anonymous enums;
+ *   - *byte_sz* - size of the enum, in bytes.
+ *   - *is_signed* - whether the enum values are signed or not;
+ *
+ * Enum initially has no enum values in it (and corresponds to enum forward
+ * declaration). Enumerator values can be added by btf__add_enum64_value()
+ * immediately after btf__add_enum64() succeeds.
+ *
+ * Returns:
+ *   - >0, type ID of newly added BTF type;
+ *   - <0, on error.
+ */
+int btf__add_enum64(struct btf *btf, const char *name, __u32 byte_sz,
+                   bool is_signed)
+{
+       return btf_add_enum_common(btf, name, byte_sz, is_signed,
+                                  BTF_KIND_ENUM64);
+}
+
+/*
+ * Append new enum value for the current ENUM64 type with:
+ *   - *name* - name of the enumerator value, can't be NULL or empty;
+ *   - *value* - integer value corresponding to enum value *name*;
+ * Returns:
+ *   -  0, on success;
+ *   - <0, on error.
+ */
+int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value)
+{
+       struct btf_enum64 *v;
+       struct btf_type *t;
+       int sz, name_off;
+
+       /* last type should be BTF_KIND_ENUM64 */
+       if (btf->nr_types == 0)
+               return libbpf_err(-EINVAL);
+       t = btf_last_type(btf);
+       if (!btf_is_enum64(t))
+               return libbpf_err(-EINVAL);
+
+       /* non-empty name */
+       if (!name || !name[0])
+               return libbpf_err(-EINVAL);
+
+       /* decompose and invalidate raw data */
+       if (btf_ensure_modifiable(btf))
+               return libbpf_err(-ENOMEM);
+
+       sz = sizeof(struct btf_enum64);
+       v = btf_add_type_mem(btf, sz);
+       if (!v)
+               return libbpf_err(-ENOMEM);
+
+       name_off = btf__add_str(btf, name);
+       if (name_off < 0)
+               return name_off;
+
+       v->name_off = name_off;
+       v->val_lo32 = (__u32)value;
+       v->val_hi32 = value >> 32;
+
+       /* update parent type's vlen */
+       t = btf_last_type(btf);
+       btf_type_inc_vlen(t);
+
        btf->hdr->type_len += sz;
        btf->hdr->str_off += sz;
        return 0;
@@ -3470,7 +3582,7 @@ static bool btf_equal_int_tag(struct btf_type *t1, struct btf_type *t2)
        return info1 == info2;
 }
 
-/* Calculate type signature hash of ENUM. */
+/* Calculate type signature hash of ENUM/ENUM64. */
 static long btf_hash_enum(struct btf_type *t)
 {
        long h;
@@ -3504,9 +3616,31 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
        return true;
 }
 
+static bool btf_equal_enum64(struct btf_type *t1, struct btf_type *t2)
+{
+       const struct btf_enum64 *m1, *m2;
+       __u16 vlen;
+       int i;
+
+       if (!btf_equal_common(t1, t2))
+               return false;
+
+       vlen = btf_vlen(t1);
+       m1 = btf_enum64(t1);
+       m2 = btf_enum64(t2);
+       for (i = 0; i < vlen; i++) {
+               if (m1->name_off != m2->name_off || m1->val_lo32 != m2->val_lo32 ||
+                   m1->val_hi32 != m2->val_hi32)
+                       return false;
+               m1++;
+               m2++;
+       }
+       return true;
+}
+
 static inline bool btf_is_enum_fwd(struct btf_type *t)
 {
-       return btf_is_enum(t) && btf_vlen(t) == 0;
+       return btf_is_any_enum(t) && btf_vlen(t) == 0;
 }
 
 static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
@@ -3519,6 +3653,17 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
               t1->size == t2->size;
 }
 
+static bool btf_compat_enum64(struct btf_type *t1, struct btf_type *t2)
+{
+       if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
+               return btf_equal_enum64(t1, t2);
+
+       /* ignore vlen when comparing */
+       return t1->name_off == t2->name_off &&
+              (t1->info & ~0xffff) == (t2->info & ~0xffff) &&
+              t1->size == t2->size;
+}
+
 /*
  * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
  * as referenced type IDs equivalence is established separately during type
@@ -3731,6 +3876,7 @@ static int btf_dedup_prep(struct btf_dedup *d)
                        h = btf_hash_int_decl_tag(t);
                        break;
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                        h = btf_hash_enum(t);
                        break;
                case BTF_KIND_STRUCT:
@@ -3820,6 +3966,27 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
                }
                break;
 
+       case BTF_KIND_ENUM64:
+               h = btf_hash_enum(t);
+               for_each_dedup_cand(d, hash_entry, h) {
+                       cand_id = (__u32)(long)hash_entry->value;
+                       cand = btf_type_by_id(d->btf, cand_id);
+                       if (btf_equal_enum64(t, cand)) {
+                               new_id = cand_id;
+                               break;
+                       }
+                       if (btf_compat_enum64(t, cand)) {
+                               if (btf_is_enum_fwd(t)) {
+                                       /* resolve fwd to full enum */
+                                       new_id = cand_id;
+                                       break;
+                               }
+                               /* resolve canonical enum fwd to full enum */
+                               d->map[cand_id] = type_id;
+                       }
+               }
+               break;
+
        case BTF_KIND_FWD:
        case BTF_KIND_FLOAT:
                h = btf_hash_common(t);
@@ -4115,6 +4282,9 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
        case BTF_KIND_ENUM:
                return btf_compat_enum(cand_type, canon_type);
 
+       case BTF_KIND_ENUM64:
+               return btf_compat_enum64(cand_type, canon_type);
+
        case BTF_KIND_FWD:
        case BTF_KIND_FLOAT:
                return btf_equal_common(cand_type, canon_type);
@@ -4717,6 +4887,7 @@ int btf_type_visit_type_ids(struct btf_type *t, type_id_visit_fn visit, void *ct
        case BTF_KIND_INT:
        case BTF_KIND_FLOAT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                return 0;
 
        case BTF_KIND_FWD:
@@ -4811,6 +4982,16 @@ int btf_type_visit_str_offs(struct btf_type *t, str_off_visit_fn visit, void *ct
                }
                break;
        }
+       case BTF_KIND_ENUM64: {
+               struct btf_enum64 *m = btf_enum64(t);
+
+               for (i = 0, n = btf_vlen(t); i < n; i++, m++) {
+                       err = visit(&m->name_off, ctx);
+                       if (err)
+                               return err;
+               }
+               break;
+       }
        case BTF_KIND_FUNC_PROTO: {
                struct btf_param *m = btf_params(t);
 
index 951ac74..9fb416e 100644 (file)
@@ -215,6 +215,8 @@ LIBBPF_API int btf__add_field(struct btf *btf, const char *name, int field_type_
 /* enum construction APIs */
 LIBBPF_API int btf__add_enum(struct btf *btf, const char *name, __u32 bytes_sz);
 LIBBPF_API int btf__add_enum_value(struct btf *btf, const char *name, __s64 value);
+LIBBPF_API int btf__add_enum64(struct btf *btf, const char *name, __u32 bytes_sz, bool is_signed);
+LIBBPF_API int btf__add_enum64_value(struct btf *btf, const char *name, __u64 value);
 
 enum btf_fwd_kind {
        BTF_FWD_STRUCT = 0,
@@ -393,9 +395,10 @@ btf_dump__dump_type_data(struct btf_dump *d, __u32 id,
 #ifndef BTF_KIND_FLOAT
 #define BTF_KIND_FLOAT         16      /* Floating point       */
 #endif
-/* The kernel header switched to enums, so these two were never #defined */
+/* The kernel header switched to enums, so the following were never #defined */
 #define BTF_KIND_DECL_TAG      17      /* Decl Tag */
 #define BTF_KIND_TYPE_TAG      18      /* Type Tag */
+#define BTF_KIND_ENUM64                19      /* Enum for up-to 64bit values */
 
 static inline __u16 btf_kind(const struct btf_type *t)
 {
@@ -454,6 +457,11 @@ static inline bool btf_is_enum(const struct btf_type *t)
        return btf_kind(t) == BTF_KIND_ENUM;
 }
 
+static inline bool btf_is_enum64(const struct btf_type *t)
+{
+       return btf_kind(t) == BTF_KIND_ENUM64;
+}
+
 static inline bool btf_is_fwd(const struct btf_type *t)
 {
        return btf_kind(t) == BTF_KIND_FWD;
@@ -524,6 +532,18 @@ static inline bool btf_is_type_tag(const struct btf_type *t)
        return btf_kind(t) == BTF_KIND_TYPE_TAG;
 }
 
+static inline bool btf_is_any_enum(const struct btf_type *t)
+{
+       return btf_is_enum(t) || btf_is_enum64(t);
+}
+
+static inline bool btf_kind_core_compat(const struct btf_type *t1,
+                                       const struct btf_type *t2)
+{
+       return btf_kind(t1) == btf_kind(t2) ||
+              (btf_is_any_enum(t1) && btf_is_any_enum(t2));
+}
+
 static inline __u8 btf_int_encoding(const struct btf_type *t)
 {
        return BTF_INT_ENCODING(*(__u32 *)(t + 1));
@@ -549,6 +569,16 @@ static inline struct btf_enum *btf_enum(const struct btf_type *t)
        return (struct btf_enum *)(t + 1);
 }
 
+static inline struct btf_enum64 *btf_enum64(const struct btf_type *t)
+{
+       return (struct btf_enum64 *)(t + 1);
+}
+
+static inline __u64 btf_enum64_value(const struct btf_enum64 *e)
+{
+       return ((__u64)e->val_hi32 << 32) | e->val_lo32;
+}
+
 static inline struct btf_member *btf_members(const struct btf_type *t)
 {
        return (struct btf_member *)(t + 1);
index 6b1bc1f..f5275f8 100644 (file)
@@ -318,6 +318,7 @@ static int btf_dump_mark_referenced(struct btf_dump *d)
                switch (btf_kind(t)) {
                case BTF_KIND_INT:
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                case BTF_KIND_FWD:
                case BTF_KIND_FLOAT:
                        break;
@@ -538,6 +539,7 @@ static int btf_dump_order_type(struct btf_dump *d, __u32 id, bool through_ptr)
                return 1;
        }
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_FWD:
                /*
                 * non-anonymous or non-referenced enums are top-level
@@ -739,6 +741,7 @@ static void btf_dump_emit_type(struct btf_dump *d, __u32 id, __u32 cont_id)
                tstate->emit_state = EMITTED;
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                if (top_level_def) {
                        btf_dump_emit_enum_def(d, id, t, 0);
                        btf_dump_printf(d, ";\n\n");
@@ -989,38 +992,81 @@ static void btf_dump_emit_enum_fwd(struct btf_dump *d, __u32 id,
        btf_dump_printf(d, "enum %s", btf_dump_type_name(d, id));
 }
 
-static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
-                                  const struct btf_type *t,
-                                  int lvl)
+static void btf_dump_emit_enum32_val(struct btf_dump *d,
+                                    const struct btf_type *t,
+                                    int lvl, __u16 vlen)
 {
        const struct btf_enum *v = btf_enum(t);
-       __u16 vlen = btf_vlen(t);
+       bool is_signed = btf_kflag(t);
+       const char *fmt_str;
        const char *name;
        size_t dup_cnt;
        int i;
 
+       for (i = 0; i < vlen; i++, v++) {
+               name = btf_name_of(d, v->name_off);
+               /* enumerators share namespace with typedef idents */
+               dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
+               if (dup_cnt > 1) {
+                       fmt_str = is_signed ? "\n%s%s___%zd = %d," : "\n%s%s___%zd = %u,";
+                       btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, dup_cnt, v->val);
+               } else {
+                       fmt_str = is_signed ? "\n%s%s = %d," : "\n%s%s = %u,";
+                       btf_dump_printf(d, fmt_str, pfx(lvl + 1), name, v->val);
+               }
+       }
+}
+
+static void btf_dump_emit_enum64_val(struct btf_dump *d,
+                                    const struct btf_type *t,
+                                    int lvl, __u16 vlen)
+{
+       const struct btf_enum64 *v = btf_enum64(t);
+       bool is_signed = btf_kflag(t);
+       const char *fmt_str;
+       const char *name;
+       size_t dup_cnt;
+       __u64 val;
+       int i;
+
+       for (i = 0; i < vlen; i++, v++) {
+               name = btf_name_of(d, v->name_off);
+               dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
+               val = btf_enum64_value(v);
+               if (dup_cnt > 1) {
+                       fmt_str = is_signed ? "\n%s%s___%zd = %lldLL,"
+                                           : "\n%s%s___%zd = %lluULL,";
+                       btf_dump_printf(d, fmt_str,
+                                       pfx(lvl + 1), name, dup_cnt,
+                                       (unsigned long long)val);
+               } else {
+                       fmt_str = is_signed ? "\n%s%s = %lldLL,"
+                                           : "\n%s%s = %lluULL,";
+                       btf_dump_printf(d, fmt_str,
+                                       pfx(lvl + 1), name,
+                                       (unsigned long long)val);
+               }
+       }
+}
+static void btf_dump_emit_enum_def(struct btf_dump *d, __u32 id,
+                                  const struct btf_type *t,
+                                  int lvl)
+{
+       __u16 vlen = btf_vlen(t);
+
        btf_dump_printf(d, "enum%s%s",
                        t->name_off ? " " : "",
                        btf_dump_type_name(d, id));
 
-       if (vlen) {
-               btf_dump_printf(d, " {");
-               for (i = 0; i < vlen; i++, v++) {
-                       name = btf_name_of(d, v->name_off);
-                       /* enumerators share namespace with typedef idents */
-                       dup_cnt = btf_dump_name_dups(d, d->ident_names, name);
-                       if (dup_cnt > 1) {
-                               btf_dump_printf(d, "\n%s%s___%zu = %u,",
-                                               pfx(lvl + 1), name, dup_cnt,
-                                               (__u32)v->val);
-                       } else {
-                               btf_dump_printf(d, "\n%s%s = %u,",
-                                               pfx(lvl + 1), name,
-                                               (__u32)v->val);
-                       }
-               }
-               btf_dump_printf(d, "\n%s}", pfx(lvl));
-       }
+       if (!vlen)
+               return;
+
+       btf_dump_printf(d, " {");
+       if (btf_is_enum(t))
+               btf_dump_emit_enum32_val(d, t, lvl, vlen);
+       else
+               btf_dump_emit_enum64_val(d, t, lvl, vlen);
+       btf_dump_printf(d, "\n%s}", pfx(lvl));
 }
 
 static void btf_dump_emit_fwd_def(struct btf_dump *d, __u32 id,
@@ -1178,6 +1224,7 @@ skip_mod:
                        break;
                case BTF_KIND_INT:
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                case BTF_KIND_FWD:
                case BTF_KIND_STRUCT:
                case BTF_KIND_UNION:
@@ -1312,6 +1359,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
                                btf_dump_emit_struct_fwd(d, id, t);
                        break;
                case BTF_KIND_ENUM:
+               case BTF_KIND_ENUM64:
                        btf_dump_emit_mods(d, decls);
                        /* inline anonymous enum */
                        if (t->name_off == 0 && !d->skip_anon_defs)
@@ -1988,7 +2036,8 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
                                   __u32 id,
                                   __s64 *value)
 {
-       /* handle unaligned enum value */
+       bool is_signed = btf_kflag(t);
+
        if (!ptr_is_aligned(d->btf, id, data)) {
                __u64 val;
                int err;
@@ -2005,13 +2054,13 @@ static int btf_dump_get_enum_value(struct btf_dump *d,
                *value = *(__s64 *)data;
                return 0;
        case 4:
-               *value = *(__s32 *)data;
+               *value = is_signed ? *(__s32 *)data : *(__u32 *)data;
                return 0;
        case 2:
-               *value = *(__s16 *)data;
+               *value = is_signed ? *(__s16 *)data : *(__u16 *)data;
                return 0;
        case 1:
-               *value = *(__s8 *)data;
+               *value = is_signed ? *(__s8 *)data : *(__u8 *)data;
                return 0;
        default:
                pr_warn("unexpected size %d for enum, id:[%u]\n", t->size, id);
@@ -2024,7 +2073,7 @@ static int btf_dump_enum_data(struct btf_dump *d,
                              __u32 id,
                              const void *data)
 {
-       const struct btf_enum *e;
+       bool is_signed;
        __s64 value;
        int i, err;
 
@@ -2032,14 +2081,31 @@ static int btf_dump_enum_data(struct btf_dump *d,
        if (err)
                return err;
 
-       for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
-               if (value != e->val)
-                       continue;
-               btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
-               return 0;
-       }
+       is_signed = btf_kflag(t);
+       if (btf_is_enum(t)) {
+               const struct btf_enum *e;
+
+               for (i = 0, e = btf_enum(t); i < btf_vlen(t); i++, e++) {
+                       if (value != e->val)
+                               continue;
+                       btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
+                       return 0;
+               }
 
-       btf_dump_type_values(d, "%d", value);
+               btf_dump_type_values(d, is_signed ? "%d" : "%u", value);
+       } else {
+               const struct btf_enum64 *e;
+
+               for (i = 0, e = btf_enum64(t); i < btf_vlen(t); i++, e++) {
+                       if (value != btf_enum64_value(e))
+                               continue;
+                       btf_dump_type_values(d, "%s", btf_name_of(d, e->name_off));
+                       return 0;
+               }
+
+               btf_dump_type_values(d, is_signed ? "%lldLL" : "%lluULL",
+                                    (unsigned long long)value);
+       }
        return 0;
 }
 
@@ -2099,6 +2165,7 @@ static int btf_dump_type_data_check_overflow(struct btf_dump *d,
        case BTF_KIND_FLOAT:
        case BTF_KIND_PTR:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                if (data + bits_offset / 8 + size > d->typed_dump->data_end)
                        return -E2BIG;
                break;
@@ -2203,6 +2270,7 @@ static int btf_dump_type_data_check_zero(struct btf_dump *d,
                return -ENODATA;
        }
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                err = btf_dump_get_enum_value(d, t, data, id, &value);
                if (err)
                        return err;
@@ -2275,6 +2343,7 @@ static int btf_dump_dump_type_data(struct btf_dump *d,
                err = btf_dump_struct_data(d, t, id, data);
                break;
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                /* handle bitfield and int enum values */
                if (bit_sz) {
                        __u64 print_num;
index e89cc9c..49e359c 100644 (file)
 static struct bpf_map *bpf_object__add_map(struct bpf_object *obj);
 static bool prog_is_subprog(const struct bpf_object *obj, const struct bpf_program *prog);
 
+static const char * const attach_type_name[] = {
+       [BPF_CGROUP_INET_INGRESS]       = "cgroup_inet_ingress",
+       [BPF_CGROUP_INET_EGRESS]        = "cgroup_inet_egress",
+       [BPF_CGROUP_INET_SOCK_CREATE]   = "cgroup_inet_sock_create",
+       [BPF_CGROUP_INET_SOCK_RELEASE]  = "cgroup_inet_sock_release",
+       [BPF_CGROUP_SOCK_OPS]           = "cgroup_sock_ops",
+       [BPF_CGROUP_DEVICE]             = "cgroup_device",
+       [BPF_CGROUP_INET4_BIND]         = "cgroup_inet4_bind",
+       [BPF_CGROUP_INET6_BIND]         = "cgroup_inet6_bind",
+       [BPF_CGROUP_INET4_CONNECT]      = "cgroup_inet4_connect",
+       [BPF_CGROUP_INET6_CONNECT]      = "cgroup_inet6_connect",
+       [BPF_CGROUP_INET4_POST_BIND]    = "cgroup_inet4_post_bind",
+       [BPF_CGROUP_INET6_POST_BIND]    = "cgroup_inet6_post_bind",
+       [BPF_CGROUP_INET4_GETPEERNAME]  = "cgroup_inet4_getpeername",
+       [BPF_CGROUP_INET6_GETPEERNAME]  = "cgroup_inet6_getpeername",
+       [BPF_CGROUP_INET4_GETSOCKNAME]  = "cgroup_inet4_getsockname",
+       [BPF_CGROUP_INET6_GETSOCKNAME]  = "cgroup_inet6_getsockname",
+       [BPF_CGROUP_UDP4_SENDMSG]       = "cgroup_udp4_sendmsg",
+       [BPF_CGROUP_UDP6_SENDMSG]       = "cgroup_udp6_sendmsg",
+       [BPF_CGROUP_SYSCTL]             = "cgroup_sysctl",
+       [BPF_CGROUP_UDP4_RECVMSG]       = "cgroup_udp4_recvmsg",
+       [BPF_CGROUP_UDP6_RECVMSG]       = "cgroup_udp6_recvmsg",
+       [BPF_CGROUP_GETSOCKOPT]         = "cgroup_getsockopt",
+       [BPF_CGROUP_SETSOCKOPT]         = "cgroup_setsockopt",
+       [BPF_SK_SKB_STREAM_PARSER]      = "sk_skb_stream_parser",
+       [BPF_SK_SKB_STREAM_VERDICT]     = "sk_skb_stream_verdict",
+       [BPF_SK_SKB_VERDICT]            = "sk_skb_verdict",
+       [BPF_SK_MSG_VERDICT]            = "sk_msg_verdict",
+       [BPF_LIRC_MODE2]                = "lirc_mode2",
+       [BPF_FLOW_DISSECTOR]            = "flow_dissector",
+       [BPF_TRACE_RAW_TP]              = "trace_raw_tp",
+       [BPF_TRACE_FENTRY]              = "trace_fentry",
+       [BPF_TRACE_FEXIT]               = "trace_fexit",
+       [BPF_MODIFY_RETURN]             = "modify_return",
+       [BPF_LSM_MAC]                   = "lsm_mac",
+       [BPF_SK_LOOKUP]                 = "sk_lookup",
+       [BPF_TRACE_ITER]                = "trace_iter",
+       [BPF_XDP_DEVMAP]                = "xdp_devmap",
+       [BPF_XDP_CPUMAP]                = "xdp_cpumap",
+       [BPF_XDP]                       = "xdp",
+       [BPF_SK_REUSEPORT_SELECT]       = "sk_reuseport_select",
+       [BPF_SK_REUSEPORT_SELECT_OR_MIGRATE]    = "sk_reuseport_select_or_migrate",
+       [BPF_PERF_EVENT]                = "perf_event",
+       [BPF_TRACE_KPROBE_MULTI]        = "trace_kprobe_multi",
+};
+
+static const char * const link_type_name[] = {
+       [BPF_LINK_TYPE_UNSPEC]                  = "unspec",
+       [BPF_LINK_TYPE_RAW_TRACEPOINT]          = "raw_tracepoint",
+       [BPF_LINK_TYPE_TRACING]                 = "tracing",
+       [BPF_LINK_TYPE_CGROUP]                  = "cgroup",
+       [BPF_LINK_TYPE_ITER]                    = "iter",
+       [BPF_LINK_TYPE_NETNS]                   = "netns",
+       [BPF_LINK_TYPE_XDP]                     = "xdp",
+       [BPF_LINK_TYPE_PERF_EVENT]              = "perf_event",
+       [BPF_LINK_TYPE_KPROBE_MULTI]            = "kprobe_multi",
+       [BPF_LINK_TYPE_STRUCT_OPS]              = "struct_ops",
+};
+
+static const char * const map_type_name[] = {
+       [BPF_MAP_TYPE_UNSPEC]                   = "unspec",
+       [BPF_MAP_TYPE_HASH]                     = "hash",
+       [BPF_MAP_TYPE_ARRAY]                    = "array",
+       [BPF_MAP_TYPE_PROG_ARRAY]               = "prog_array",
+       [BPF_MAP_TYPE_PERF_EVENT_ARRAY]         = "perf_event_array",
+       [BPF_MAP_TYPE_PERCPU_HASH]              = "percpu_hash",
+       [BPF_MAP_TYPE_PERCPU_ARRAY]             = "percpu_array",
+       [BPF_MAP_TYPE_STACK_TRACE]              = "stack_trace",
+       [BPF_MAP_TYPE_CGROUP_ARRAY]             = "cgroup_array",
+       [BPF_MAP_TYPE_LRU_HASH]                 = "lru_hash",
+       [BPF_MAP_TYPE_LRU_PERCPU_HASH]          = "lru_percpu_hash",
+       [BPF_MAP_TYPE_LPM_TRIE]                 = "lpm_trie",
+       [BPF_MAP_TYPE_ARRAY_OF_MAPS]            = "array_of_maps",
+       [BPF_MAP_TYPE_HASH_OF_MAPS]             = "hash_of_maps",
+       [BPF_MAP_TYPE_DEVMAP]                   = "devmap",
+       [BPF_MAP_TYPE_DEVMAP_HASH]              = "devmap_hash",
+       [BPF_MAP_TYPE_SOCKMAP]                  = "sockmap",
+       [BPF_MAP_TYPE_CPUMAP]                   = "cpumap",
+       [BPF_MAP_TYPE_XSKMAP]                   = "xskmap",
+       [BPF_MAP_TYPE_SOCKHASH]                 = "sockhash",
+       [BPF_MAP_TYPE_CGROUP_STORAGE]           = "cgroup_storage",
+       [BPF_MAP_TYPE_REUSEPORT_SOCKARRAY]      = "reuseport_sockarray",
+       [BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE]    = "percpu_cgroup_storage",
+       [BPF_MAP_TYPE_QUEUE]                    = "queue",
+       [BPF_MAP_TYPE_STACK]                    = "stack",
+       [BPF_MAP_TYPE_SK_STORAGE]               = "sk_storage",
+       [BPF_MAP_TYPE_STRUCT_OPS]               = "struct_ops",
+       [BPF_MAP_TYPE_RINGBUF]                  = "ringbuf",
+       [BPF_MAP_TYPE_INODE_STORAGE]            = "inode_storage",
+       [BPF_MAP_TYPE_TASK_STORAGE]             = "task_storage",
+       [BPF_MAP_TYPE_BLOOM_FILTER]             = "bloom_filter",
+};
+
+static const char * const prog_type_name[] = {
+       [BPF_PROG_TYPE_UNSPEC]                  = "unspec",
+       [BPF_PROG_TYPE_SOCKET_FILTER]           = "socket_filter",
+       [BPF_PROG_TYPE_KPROBE]                  = "kprobe",
+       [BPF_PROG_TYPE_SCHED_CLS]               = "sched_cls",
+       [BPF_PROG_TYPE_SCHED_ACT]               = "sched_act",
+       [BPF_PROG_TYPE_TRACEPOINT]              = "tracepoint",
+       [BPF_PROG_TYPE_XDP]                     = "xdp",
+       [BPF_PROG_TYPE_PERF_EVENT]              = "perf_event",
+       [BPF_PROG_TYPE_CGROUP_SKB]              = "cgroup_skb",
+       [BPF_PROG_TYPE_CGROUP_SOCK]             = "cgroup_sock",
+       [BPF_PROG_TYPE_LWT_IN]                  = "lwt_in",
+       [BPF_PROG_TYPE_LWT_OUT]                 = "lwt_out",
+       [BPF_PROG_TYPE_LWT_XMIT]                = "lwt_xmit",
+       [BPF_PROG_TYPE_SOCK_OPS]                = "sock_ops",
+       [BPF_PROG_TYPE_SK_SKB]                  = "sk_skb",
+       [BPF_PROG_TYPE_CGROUP_DEVICE]           = "cgroup_device",
+       [BPF_PROG_TYPE_SK_MSG]                  = "sk_msg",
+       [BPF_PROG_TYPE_RAW_TRACEPOINT]          = "raw_tracepoint",
+       [BPF_PROG_TYPE_CGROUP_SOCK_ADDR]        = "cgroup_sock_addr",
+       [BPF_PROG_TYPE_LWT_SEG6LOCAL]           = "lwt_seg6local",
+       [BPF_PROG_TYPE_LIRC_MODE2]              = "lirc_mode2",
+       [BPF_PROG_TYPE_SK_REUSEPORT]            = "sk_reuseport",
+       [BPF_PROG_TYPE_FLOW_DISSECTOR]          = "flow_dissector",
+       [BPF_PROG_TYPE_CGROUP_SYSCTL]           = "cgroup_sysctl",
+       [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
+       [BPF_PROG_TYPE_CGROUP_SOCKOPT]          = "cgroup_sockopt",
+       [BPF_PROG_TYPE_TRACING]                 = "tracing",
+       [BPF_PROG_TYPE_STRUCT_OPS]              = "struct_ops",
+       [BPF_PROG_TYPE_EXT]                     = "ext",
+       [BPF_PROG_TYPE_LSM]                     = "lsm",
+       [BPF_PROG_TYPE_SK_LOOKUP]               = "sk_lookup",
+       [BPF_PROG_TYPE_SYSCALL]                 = "syscall",
+};
+
 static int __base_pr(enum libbpf_print_level level, const char *format,
                     va_list args)
 {
@@ -2114,6 +2242,7 @@ static const char *__btf_kind_str(__u16 kind)
        case BTF_KIND_FLOAT: return "float";
        case BTF_KIND_DECL_TAG: return "decl_tag";
        case BTF_KIND_TYPE_TAG: return "type_tag";
+       case BTF_KIND_ENUM64: return "enum64";
        default: return "unknown";
        }
 }
@@ -2642,12 +2771,13 @@ static bool btf_needs_sanitization(struct bpf_object *obj)
        bool has_func = kernel_supports(obj, FEAT_BTF_FUNC);
        bool has_decl_tag = kernel_supports(obj, FEAT_BTF_DECL_TAG);
        bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
+       bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
 
        return !has_func || !has_datasec || !has_func_global || !has_float ||
-              !has_decl_tag || !has_type_tag;
+              !has_decl_tag || !has_type_tag || !has_enum64;
 }
 
-static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
+static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
 {
        bool has_func_global = kernel_supports(obj, FEAT_BTF_GLOBAL_FUNC);
        bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC);
@@ -2655,6 +2785,8 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
        bool has_func = kernel_supports(obj, FEAT_BTF_FUNC);
        bool has_decl_tag = kernel_supports(obj, FEAT_BTF_DECL_TAG);
        bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG);
+       bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64);
+       int enum64_placeholder_id = 0;
        struct btf_type *t;
        int i, j, vlen;
 
@@ -2717,8 +2849,32 @@ static void bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf)
                        /* replace TYPE_TAG with a CONST */
                        t->name_off = 0;
                        t->info = BTF_INFO_ENC(BTF_KIND_CONST, 0, 0);
-               }
+               } else if (!has_enum64 && btf_is_enum(t)) {
+                       /* clear the kflag */
+                       t->info = btf_type_info(btf_kind(t), btf_vlen(t), false);
+               } else if (!has_enum64 && btf_is_enum64(t)) {
+                       /* replace ENUM64 with a union */
+                       struct btf_member *m;
+
+                       if (enum64_placeholder_id == 0) {
+                               enum64_placeholder_id = btf__add_int(btf, "enum64_placeholder", 1, 0);
+                               if (enum64_placeholder_id < 0)
+                                       return enum64_placeholder_id;
+
+                               t = (struct btf_type *)btf__type_by_id(btf, i);
+                       }
+
+                       m = btf_members(t);
+                       vlen = btf_vlen(t);
+                       t->info = BTF_INFO_ENC(BTF_KIND_UNION, 0, vlen);
+                       for (j = 0; j < vlen; j++, m++) {
+                               m->type = enum64_placeholder_id;
+                               m->offset = 0;
+                       }
+                }
        }
+
+       return 0;
 }
 
 static bool libbpf_needs_btf(const struct bpf_object *obj)
@@ -3056,7 +3212,9 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
 
                /* enforce 8-byte pointers for BPF-targeted BTFs */
                btf__set_pointer_size(obj->btf, 8);
-               bpf_object__sanitize_btf(obj, kern_btf);
+               err = bpf_object__sanitize_btf(obj, kern_btf);
+               if (err)
+                       return err;
        }
 
        if (obj->gen_loader) {
@@ -3563,6 +3721,10 @@ static enum kcfg_type find_kcfg_type(const struct btf *btf, int id,
                if (strcmp(name, "libbpf_tristate"))
                        return KCFG_UNKNOWN;
                return KCFG_TRISTATE;
+       case BTF_KIND_ENUM64:
+               if (strcmp(name, "libbpf_tristate"))
+                       return KCFG_UNKNOWN;
+               return KCFG_TRISTATE;
        case BTF_KIND_ARRAY:
                if (btf_array(t)->nelems == 0)
                        return KCFG_UNKNOWN;
@@ -4746,6 +4908,17 @@ static int probe_kern_bpf_cookie(void)
        return probe_fd(ret);
 }
 
+static int probe_kern_btf_enum64(void)
+{
+       static const char strs[] = "\0enum64";
+       __u32 types[] = {
+               BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
+       };
+
+       return probe_fd(libbpf__load_raw_btf((char *)types, sizeof(types),
+                                            strs, sizeof(strs)));
+}
+
 enum kern_feature_result {
        FEAT_UNKNOWN = 0,
        FEAT_SUPPORTED = 1,
@@ -4811,6 +4984,9 @@ static struct kern_feature_desc {
        [FEAT_BPF_COOKIE] = {
                "BPF cookie support", probe_kern_bpf_cookie,
        },
+       [FEAT_BTF_ENUM64] = {
+               "BTF_KIND_ENUM64 support", probe_kern_btf_enum64,
+       },
 };
 
 bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
@@ -4943,11 +5119,6 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map)
 
 static void bpf_map__destroy(struct bpf_map *map);
 
-static bool is_pow_of_2(size_t x)
-{
-       return x && (x & (x - 1));
-}
-
 static size_t adjust_ringbuf_sz(size_t sz)
 {
        __u32 page_sz = sysconf(_SC_PAGE_SIZE);
@@ -5353,7 +5524,7 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
        n = btf__type_cnt(targ_btf);
        for (i = targ_start_id; i < n; i++) {
                t = btf__type_by_id(targ_btf, i);
-               if (btf_kind(t) != btf_kind(local_t))
+               if (!btf_kind_core_compat(t, local_t))
                        continue;
 
                targ_name = btf__name_by_offset(targ_btf, t->name_off);
@@ -5567,7 +5738,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
        /* caller made sure that names match (ignoring flavor suffix) */
        local_type = btf__type_by_id(local_btf, local_id);
        targ_type = btf__type_by_id(targ_btf, targ_id);
-       if (btf_kind(local_type) != btf_kind(targ_type))
+       if (!btf_kind_core_compat(local_type, targ_type))
                return 0;
 
 recur:
@@ -5580,7 +5751,7 @@ recur:
        if (!local_type || !targ_type)
                return -EINVAL;
 
-       if (btf_kind(local_type) != btf_kind(targ_type))
+       if (!btf_kind_core_compat(local_type, targ_type))
                return 0;
 
        switch (btf_kind(local_type)) {
@@ -5588,6 +5759,7 @@ recur:
        case BTF_KIND_STRUCT:
        case BTF_KIND_UNION:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_FWD:
                return 1;
        case BTF_KIND_INT:
@@ -9005,8 +9177,10 @@ static const struct bpf_sec_def section_defs[] = {
        SEC_DEF("sk_reuseport",         SK_REUSEPORT, BPF_SK_REUSEPORT_SELECT, SEC_ATTACHABLE | SEC_SLOPPY_PFX),
        SEC_DEF("kprobe+",              KPROBE, 0, SEC_NONE, attach_kprobe),
        SEC_DEF("uprobe+",              KPROBE, 0, SEC_NONE, attach_uprobe),
+       SEC_DEF("uprobe.s+",            KPROBE, 0, SEC_SLEEPABLE, attach_uprobe),
        SEC_DEF("kretprobe+",           KPROBE, 0, SEC_NONE, attach_kprobe),
        SEC_DEF("uretprobe+",           KPROBE, 0, SEC_NONE, attach_uprobe),
+       SEC_DEF("uretprobe.s+",         KPROBE, 0, SEC_SLEEPABLE, attach_uprobe),
        SEC_DEF("kprobe.multi+",        KPROBE, BPF_TRACE_KPROBE_MULTI, SEC_NONE, attach_kprobe_multi),
        SEC_DEF("kretprobe.multi+",     KPROBE, BPF_TRACE_KPROBE_MULTI, SEC_NONE, attach_kprobe_multi),
        SEC_DEF("usdt+",                KPROBE, 0, SEC_NONE, attach_usdt),
@@ -9300,6 +9474,38 @@ int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
        return libbpf_err(-ESRCH);
 }
 
+const char *libbpf_bpf_attach_type_str(enum bpf_attach_type t)
+{
+       if (t < 0 || t >= ARRAY_SIZE(attach_type_name))
+               return NULL;
+
+       return attach_type_name[t];
+}
+
+const char *libbpf_bpf_link_type_str(enum bpf_link_type t)
+{
+       if (t < 0 || t >= ARRAY_SIZE(link_type_name))
+               return NULL;
+
+       return link_type_name[t];
+}
+
+const char *libbpf_bpf_map_type_str(enum bpf_map_type t)
+{
+       if (t < 0 || t >= ARRAY_SIZE(map_type_name))
+               return NULL;
+
+       return map_type_name[t];
+}
+
+const char *libbpf_bpf_prog_type_str(enum bpf_prog_type t)
+{
+       if (t < 0 || t >= ARRAY_SIZE(prog_type_name))
+               return NULL;
+
+       return prog_type_name[t];
+}
+
 static struct bpf_map *find_struct_ops_map_by_offset(struct bpf_object *obj,
                                                     size_t offset)
 {
@@ -10988,43 +11194,6 @@ static int perf_event_uprobe_open_legacy(const char *probe_name, bool retprobe,
        return pfd;
 }
 
-/* uprobes deal in relative offsets; subtract the base address associated with
- * the mapped binary.  See Documentation/trace/uprobetracer.rst for more
- * details.
- */
-static long elf_find_relative_offset(const char *filename, Elf *elf, long addr)
-{
-       size_t n;
-       int i;
-
-       if (elf_getphdrnum(elf, &n)) {
-               pr_warn("elf: failed to find program headers for '%s': %s\n", filename,
-                       elf_errmsg(-1));
-               return -ENOENT;
-       }
-
-       for (i = 0; i < n; i++) {
-               int seg_start, seg_end, seg_offset;
-               GElf_Phdr phdr;
-
-               if (!gelf_getphdr(elf, i, &phdr)) {
-                       pr_warn("elf: failed to get program header %d from '%s': %s\n", i, filename,
-                               elf_errmsg(-1));
-                       return -ENOENT;
-               }
-               if (phdr.p_type != PT_LOAD || !(phdr.p_flags & PF_X))
-                       continue;
-
-               seg_start = phdr.p_vaddr;
-               seg_end = seg_start + phdr.p_memsz;
-               seg_offset = phdr.p_offset;
-               if (addr >= seg_start && addr < seg_end)
-                       return addr - seg_start + seg_offset;
-       }
-       pr_warn("elf: failed to find prog header containing 0x%lx in '%s'\n", addr, filename);
-       return -ENOENT;
-}
-
 /* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
 static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
 {
@@ -11111,6 +11280,8 @@ static long elf_find_func_offset(const char *binary_path, const char *name)
                for (idx = 0; idx < nr_syms; idx++) {
                        int curr_bind;
                        GElf_Sym sym;
+                       Elf_Scn *sym_scn;
+                       GElf_Shdr sym_sh;
 
                        if (!gelf_getsym(symbols, idx, &sym))
                                continue;
@@ -11148,12 +11319,28 @@ static long elf_find_func_offset(const char *binary_path, const char *name)
                                        continue;
                                }
                        }
-                       ret = sym.st_value;
+
+                       /* Transform symbol's virtual address (absolute for
+                        * binaries and relative for shared libs) into file
+                        * offset, which is what kernel is expecting for
+                        * uprobe/uretprobe attachment.
+                        * See Documentation/trace/uprobetracer.rst for more
+                        * details.
+                        * This is done by looking up symbol's containing
+                        * section's header and using it's virtual address
+                        * (sh_addr) and corresponding file offset (sh_offset)
+                        * to transform sym.st_value (virtual address) into
+                        * desired final file offset.
+                        */
+                       sym_scn = elf_getscn(elf, sym.st_shndx);
+                       if (!sym_scn)
+                               continue;
+                       if (!gelf_getshdr(sym_scn, &sym_sh))
+                               continue;
+
+                       ret = sym.st_value - sym_sh.sh_addr + sym_sh.sh_offset;
                        last_bind = curr_bind;
                }
-               /* For binaries that are not shared libraries, we need relative offset */
-               if (ret > 0 && !is_shared_lib)
-                       ret = elf_find_relative_offset(binary_path, elf, ret);
                if (ret > 0)
                        break;
        }
@@ -11386,7 +11573,8 @@ static int attach_uprobe(const struct bpf_program *prog, long cookie, struct bpf
                break;
        case 3:
        case 4:
-               opts.retprobe = strcmp(probe_type, "uretprobe") == 0;
+               opts.retprobe = strcmp(probe_type, "uretprobe") == 0 ||
+                               strcmp(probe_type, "uretprobe.s") == 0;
                if (opts.retprobe && offset != 0) {
                        pr_warn("prog '%s': uretprobes do not support offset specification\n",
                                prog->name);
index 9e9a3fd..fa27969 100644 (file)
@@ -51,6 +51,42 @@ enum libbpf_errno {
 
 LIBBPF_API int libbpf_strerror(int err, char *buf, size_t size);
 
+/**
+ * @brief **libbpf_bpf_attach_type_str()** converts the provided attach type
+ * value into a textual representation.
+ * @param t The attach type.
+ * @return Pointer to a static string identifying the attach type. NULL is
+ * returned for unknown **bpf_attach_type** values.
+ */
+LIBBPF_API const char *libbpf_bpf_attach_type_str(enum bpf_attach_type t);
+
+/**
+ * @brief **libbpf_bpf_link_type_str()** converts the provided link type value
+ * into a textual representation.
+ * @param t The link type.
+ * @return Pointer to a static string identifying the link type. NULL is
+ * returned for unknown **bpf_link_type** values.
+ */
+LIBBPF_API const char *libbpf_bpf_link_type_str(enum bpf_link_type t);
+
+/**
+ * @brief **libbpf_bpf_map_type_str()** converts the provided map type value
+ * into a textual representation.
+ * @param t The map type.
+ * @return Pointer to a static string identifying the map type. NULL is
+ * returned for unknown **bpf_map_type** values.
+ */
+LIBBPF_API const char *libbpf_bpf_map_type_str(enum bpf_map_type t);
+
+/**
+ * @brief **libbpf_bpf_prog_type_str()** converts the provided program type
+ * value into a textual representation.
+ * @param t The program type.
+ * @return Pointer to a static string identifying the program type. NULL is
+ * returned for unknown **bpf_prog_type** values.
+ */
+LIBBPF_API const char *libbpf_bpf_prog_type_str(enum bpf_prog_type t);
+
 enum libbpf_print_level {
         LIBBPF_WARN,
         LIBBPF_INFO,
@@ -71,7 +107,7 @@ struct bpf_object_open_attr {
 };
 
 struct bpf_object_open_opts {
-       /* size of this struct, for forward/backward compatiblity */
+       /* size of this struct, for forward/backward compatibility */
        size_t sz;
        /* object name override, if provided:
         * - for object open from file, this will override setting object
index 52973cf..116a2a8 100644 (file)
@@ -461,5 +461,13 @@ LIBBPF_0.8.0 {
 } LIBBPF_0.7.0;
 
 LIBBPF_1.0.0 {
+       global:
+               btf__add_enum64;
+               btf__add_enum64_value;
+               libbpf_bpf_attach_type_str;
+               libbpf_bpf_link_type_str;
+               libbpf_bpf_map_type_str;
+               libbpf_bpf_prog_type_str;
+
        local: *;
 };
index 4abdbe2..a1ad145 100644 (file)
@@ -351,6 +351,8 @@ enum kern_feature_id {
        FEAT_MEMCG_ACCOUNT,
        /* BPF cookie (bpf_get_attach_cookie() BPF helper) support */
        FEAT_BPF_COOKIE,
+       /* BTF_KIND_ENUM64 support and BTF_KIND_ENUM kflag support */
+       FEAT_BTF_ENUM64,
        __FEAT_CNT,
 };
 
@@ -580,4 +582,9 @@ struct bpf_link * usdt_manager_attach_usdt(struct usdt_manager *man,
                                           const char *usdt_provider, const char *usdt_name,
                                           __u64 usdt_cookie);
 
+static inline bool is_pow_of_2(size_t x)
+{
+       return x && (x & (x - 1)) == 0;
+}
+
 #endif /* __LIBBPF_LIBBPF_INTERNAL_H */
index 9aa016f..4ac02c2 100644 (file)
@@ -697,11 +697,6 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
        return err;
 }
 
-static bool is_pow_of_2(size_t x)
-{
-       return x && (x & (x - 1)) == 0;
-}
-
 static int linker_sanity_check_elf(struct src_obj *obj)
 {
        struct src_sec *sec;
@@ -1340,6 +1335,7 @@ recur:
        case BTF_KIND_STRUCT:
        case BTF_KIND_UNION:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_FWD:
        case BTF_KIND_FUNC:
        case BTF_KIND_VAR:
@@ -1362,6 +1358,7 @@ recur:
        case BTF_KIND_INT:
        case BTF_KIND_FLOAT:
        case BTF_KIND_ENUM:
+       case BTF_KIND_ENUM64:
                /* ignore encoding for int and enum values for enum */
                if (t1->size != t2->size) {
                        pr_warn("global '%s': incompatible %s '%s' size %u and %u\n",
index ba4453d..6ad3c38 100644 (file)
@@ -167,7 +167,7 @@ static bool core_relo_is_enumval_based(enum bpf_core_relo_kind kind)
  * just a parsed access string representation): [0, 1, 2, 3].
  *
  * High-level spec will capture only 3 points:
- *   - intial zero-index access by pointer (&s->... is the same as &s[0]...);
+ *   - initial zero-index access by pointer (&s->... is the same as &s[0]...);
  *   - field 'a' access (corresponds to '2' in low-level spec);
  *   - array element #3 access (corresponds to '3' in low-level spec).
  *
@@ -186,7 +186,7 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
        struct bpf_core_accessor *acc;
        const struct btf_type *t;
        const char *name, *spec_str;
-       __u32 id;
+       __u32 id, name_off;
        __s64 sz;
 
        spec_str = btf__name_by_offset(btf, relo->access_str_off);
@@ -231,11 +231,13 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
        spec->len++;
 
        if (core_relo_is_enumval_based(relo->kind)) {
-               if (!btf_is_enum(t) || spec->raw_len > 1 || access_idx >= btf_vlen(t))
+               if (!btf_is_any_enum(t) || spec->raw_len > 1 || access_idx >= btf_vlen(t))
                        return -EINVAL;
 
                /* record enumerator name in a first accessor */
-               acc->name = btf__name_by_offset(btf, btf_enum(t)[access_idx].name_off);
+               name_off = btf_is_enum(t) ? btf_enum(t)[access_idx].name_off
+                                         : btf_enum64(t)[access_idx].name_off;
+               acc->name = btf__name_by_offset(btf, name_off);
                return 0;
        }
 
@@ -340,7 +342,7 @@ recur:
 
        if (btf_is_composite(local_type) && btf_is_composite(targ_type))
                return 1;
-       if (btf_kind(local_type) != btf_kind(targ_type))
+       if (!btf_kind_core_compat(local_type, targ_type))
                return 0;
 
        switch (btf_kind(local_type)) {
@@ -348,6 +350,7 @@ recur:
        case BTF_KIND_FLOAT:
                return 1;
        case BTF_KIND_FWD:
+       case BTF_KIND_ENUM64:
        case BTF_KIND_ENUM: {
                const char *local_name, *targ_name;
                size_t local_len, targ_len;
@@ -477,6 +480,7 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
        const struct bpf_core_accessor *local_acc;
        struct bpf_core_accessor *targ_acc;
        int i, sz, matched;
+       __u32 name_off;
 
        memset(targ_spec, 0, sizeof(*targ_spec));
        targ_spec->btf = targ_btf;
@@ -494,18 +498,22 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
 
        if (core_relo_is_enumval_based(local_spec->relo_kind)) {
                size_t local_essent_len, targ_essent_len;
-               const struct btf_enum *e;
                const char *targ_name;
 
                /* has to resolve to an enum */
                targ_type = skip_mods_and_typedefs(targ_spec->btf, targ_id, &targ_id);
-               if (!btf_is_enum(targ_type))
+               if (!btf_is_any_enum(targ_type))
                        return 0;
 
                local_essent_len = bpf_core_essential_name_len(local_acc->name);
 
-               for (i = 0, e = btf_enum(targ_type); i < btf_vlen(targ_type); i++, e++) {
-                       targ_name = btf__name_by_offset(targ_spec->btf, e->name_off);
+               for (i = 0; i < btf_vlen(targ_type); i++) {
+                       if (btf_is_enum(targ_type))
+                               name_off = btf_enum(targ_type)[i].name_off;
+                       else
+                               name_off = btf_enum64(targ_type)[i].name_off;
+
+                       targ_name = btf__name_by_offset(targ_spec->btf, name_off);
                        targ_essent_len = bpf_core_essential_name_len(targ_name);
                        if (targ_essent_len != local_essent_len)
                                continue;
@@ -583,7 +591,7 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
 static int bpf_core_calc_field_relo(const char *prog_name,
                                    const struct bpf_core_relo *relo,
                                    const struct bpf_core_spec *spec,
-                                   __u32 *val, __u32 *field_sz, __u32 *type_id,
+                                   __u64 *val, __u32 *field_sz, __u32 *type_id,
                                    bool *validate)
 {
        const struct bpf_core_accessor *acc;
@@ -680,8 +688,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
                *val = byte_sz;
                break;
        case BPF_CORE_FIELD_SIGNED:
-               /* enums will be assumed unsigned */
-               *val = btf_is_enum(mt) ||
+               *val = (btf_is_any_enum(mt) && BTF_INFO_KFLAG(mt->info)) ||
                       (btf_int_encoding(mt) & BTF_INT_SIGNED);
                if (validate)
                        *validate = true; /* signedness is never ambiguous */
@@ -708,7 +715,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
 
 static int bpf_core_calc_type_relo(const struct bpf_core_relo *relo,
                                   const struct bpf_core_spec *spec,
-                                  __u32 *val, bool *validate)
+                                  __u64 *val, bool *validate)
 {
        __s64 sz;
 
@@ -751,10 +758,9 @@ static int bpf_core_calc_type_relo(const struct bpf_core_relo *relo,
 
 static int bpf_core_calc_enumval_relo(const struct bpf_core_relo *relo,
                                      const struct bpf_core_spec *spec,
-                                     __u32 *val)
+                                     __u64 *val)
 {
        const struct btf_type *t;
-       const struct btf_enum *e;
 
        switch (relo->kind) {
        case BPF_CORE_ENUMVAL_EXISTS:
@@ -764,8 +770,10 @@ static int bpf_core_calc_enumval_relo(const struct bpf_core_relo *relo,
                if (!spec)
                        return -EUCLEAN; /* request instruction poisoning */
                t = btf_type_by_id(spec->btf, spec->spec[0].type_id);
-               e = btf_enum(t) + spec->spec[0].idx;
-               *val = e->val;
+               if (btf_is_enum(t))
+                       *val = btf_enum(t)[spec->spec[0].idx].val;
+               else
+                       *val = btf_enum64_value(btf_enum64(t) + spec->spec[0].idx);
                break;
        default:
                return -EOPNOTSUPP;
@@ -929,7 +937,7 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
                        int insn_idx, const struct bpf_core_relo *relo,
                        int relo_idx, const struct bpf_core_relo_res *res)
 {
-       __u32 orig_val, new_val;
+       __u64 orig_val, new_val;
        __u8 class;
 
        class = BPF_CLASS(insn->code);
@@ -954,28 +962,30 @@ poison:
                if (BPF_SRC(insn->code) != BPF_K)
                        return -EINVAL;
                if (res->validate && insn->imm != orig_val) {
-                       pr_warn("prog '%s': relo #%d: unexpected insn #%d (ALU/ALU64) value: got %u, exp %u -> %u\n",
+                       pr_warn("prog '%s': relo #%d: unexpected insn #%d (ALU/ALU64) value: got %u, exp %llu -> %llu\n",
                                prog_name, relo_idx,
-                               insn_idx, insn->imm, orig_val, new_val);
+                               insn_idx, insn->imm, (unsigned long long)orig_val,
+                               (unsigned long long)new_val);
                        return -EINVAL;
                }
                orig_val = insn->imm;
                insn->imm = new_val;
-               pr_debug("prog '%s': relo #%d: patched insn #%d (ALU/ALU64) imm %u -> %u\n",
+               pr_debug("prog '%s': relo #%d: patched insn #%d (ALU/ALU64) imm %llu -> %llu\n",
                         prog_name, relo_idx, insn_idx,
-                        orig_val, new_val);
+                        (unsigned long long)orig_val, (unsigned long long)new_val);
                break;
        case BPF_LDX:
        case BPF_ST:
        case BPF_STX:
                if (res->validate && insn->off != orig_val) {
-                       pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDX/ST/STX) value: got %u, exp %u -> %u\n",
-                               prog_name, relo_idx, insn_idx, insn->off, orig_val, new_val);
+                       pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDX/ST/STX) value: got %u, exp %llu -> %llu\n",
+                               prog_name, relo_idx, insn_idx, insn->off, (unsigned long long)orig_val,
+                               (unsigned long long)new_val);
                        return -EINVAL;
                }
                if (new_val > SHRT_MAX) {
-                       pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) value too big: %u\n",
-                               prog_name, relo_idx, insn_idx, new_val);
+                       pr_warn("prog '%s': relo #%d: insn #%d (LDX/ST/STX) value too big: %llu\n",
+                               prog_name, relo_idx, insn_idx, (unsigned long long)new_val);
                        return -ERANGE;
                }
                if (res->fail_memsz_adjust) {
@@ -987,8 +997,9 @@ poison:
 
                orig_val = insn->off;
                insn->off = new_val;
-               pr_debug("prog '%s': relo #%d: patched insn #%d (LDX/ST/STX) off %u -> %u\n",
-                        prog_name, relo_idx, insn_idx, orig_val, new_val);
+               pr_debug("prog '%s': relo #%d: patched insn #%d (LDX/ST/STX) off %llu -> %llu\n",
+                        prog_name, relo_idx, insn_idx, (unsigned long long)orig_val,
+                        (unsigned long long)new_val);
 
                if (res->new_sz != res->orig_sz) {
                        int insn_bytes_sz, insn_bpf_sz;
@@ -1024,20 +1035,20 @@ poison:
                        return -EINVAL;
                }
 
-               imm = insn[0].imm + ((__u64)insn[1].imm << 32);
+               imm = (__u32)insn[0].imm | ((__u64)insn[1].imm << 32);
                if (res->validate && imm != orig_val) {
-                       pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDIMM64) value: got %llu, exp %u -> %u\n",
+                       pr_warn("prog '%s': relo #%d: unexpected insn #%d (LDIMM64) value: got %llu, exp %llu -> %llu\n",
                                prog_name, relo_idx,
                                insn_idx, (unsigned long long)imm,
-                               orig_val, new_val);
+                               (unsigned long long)orig_val, (unsigned long long)new_val);
                        return -EINVAL;
                }
 
                insn[0].imm = new_val;
-               insn[1].imm = 0; /* currently only 32-bit values are supported */
-               pr_debug("prog '%s': relo #%d: patched insn #%d (LDIMM64) imm64 %llu -> %u\n",
+               insn[1].imm = new_val >> 32;
+               pr_debug("prog '%s': relo #%d: patched insn #%d (LDIMM64) imm64 %llu -> %llu\n",
                         prog_name, relo_idx, insn_idx,
-                        (unsigned long long)imm, new_val);
+                        (unsigned long long)imm, (unsigned long long)new_val);
                break;
        }
        default:
@@ -1057,7 +1068,6 @@ poison:
 int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *spec)
 {
        const struct btf_type *t;
-       const struct btf_enum *e;
        const char *s;
        __u32 type_id;
        int i, len = 0;
@@ -1086,10 +1096,23 @@ int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *s
 
        if (core_relo_is_enumval_based(spec->relo_kind)) {
                t = skip_mods_and_typedefs(spec->btf, type_id, NULL);
-               e = btf_enum(t) + spec->raw_spec[0];
-               s = btf__name_by_offset(spec->btf, e->name_off);
+               if (btf_is_enum(t)) {
+                       const struct btf_enum *e;
+                       const char *fmt_str;
+
+                       e = btf_enum(t) + spec->raw_spec[0];
+                       s = btf__name_by_offset(spec->btf, e->name_off);
+                       fmt_str = BTF_INFO_KFLAG(t->info) ? "::%s = %d" : "::%s = %u";
+                       append_buf(fmt_str, s, e->val);
+               } else {
+                       const struct btf_enum64 *e;
+                       const char *fmt_str;
 
-               append_buf("::%s = %u", s, e->val);
+                       e = btf_enum64(t) + spec->raw_spec[0];
+                       s = btf__name_by_offset(spec->btf, e->name_off);
+                       fmt_str = BTF_INFO_KFLAG(t->info) ? "::%s = %lld" : "::%s = %llu";
+                       append_buf(fmt_str, s, (unsigned long long)btf_enum64_value(e));
+               }
                return len;
        }
 
@@ -1148,11 +1171,11 @@ int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *s
  * 3. It is supported and expected that there might be multiple flavors
  *    matching the spec. As long as all the specs resolve to the same set of
  *    offsets across all candidates, there is no error. If there is any
- *    ambiguity, CO-RE relocation will fail. This is necessary to accomodate
- *    imprefection of BTF deduplication, which can cause slight duplication of
+ *    ambiguity, CO-RE relocation will fail. This is necessary to accommodate
+ *    imperfection of BTF deduplication, which can cause slight duplication of
  *    the same BTF type, if some directly or indirectly referenced (by
  *    pointer) type gets resolved to different actual types in different
- *    object files. If such situation occurs, deduplicated BTF will end up
+ *    object files. If such situation occurs, deduplicated BTF will end up
  *    with two (or more) structurally identical types, which differ only in
  *    types they refer to through pointer. This should be OK in most cases and
  *    is not an error.
@@ -1261,10 +1284,12 @@ int bpf_core_calc_relo_insn(const char *prog_name,
                         * decision and value, otherwise it's dangerous to
                         * proceed due to ambiguity
                         */
-                       pr_warn("prog '%s': relo #%d: relocation decision ambiguity: %s %u != %s %u\n",
+                       pr_warn("prog '%s': relo #%d: relocation decision ambiguity: %s %llu != %s %llu\n",
                                prog_name, relo_idx,
-                               cand_res.poison ? "failure" : "success", cand_res.new_val,
-                               targ_res->poison ? "failure" : "success", targ_res->new_val);
+                               cand_res.poison ? "failure" : "success",
+                               (unsigned long long)cand_res.new_val,
+                               targ_res->poison ? "failure" : "success",
+                               (unsigned long long)targ_res->new_val);
                        return -EINVAL;
                }
 
index 073039d..7df0da0 100644 (file)
@@ -46,9 +46,9 @@ struct bpf_core_spec {
 
 struct bpf_core_relo_res {
        /* expected value in the instruction, unless validate == false */
-       __u32 orig_val;
+       __u64 orig_val;
        /* new value that needs to be patched up to */
-       __u32 new_val;
+       __u64 new_val;
        /* relocation unsuccessful, poison instruction, but don't fail load */
        bool poison;
        /* some relocations can't be validated against orig_val */
index f1c9339..5159207 100644 (file)
@@ -441,7 +441,7 @@ static int parse_elf_segs(Elf *elf, const char *path, struct elf_seg **segs, siz
        return 0;
 }
 
-static int parse_lib_segs(int pid, const char *lib_path, struct elf_seg **segs, size_t *seg_cnt)
+static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, size_t *seg_cnt)
 {
        char path[PATH_MAX], line[PATH_MAX], mode[16];
        size_t seg_start, seg_end, seg_off;
@@ -531,35 +531,40 @@ err_out:
        return err;
 }
 
-static struct elf_seg *find_elf_seg(struct elf_seg *segs, size_t seg_cnt, long addr, bool relative)
+static struct elf_seg *find_elf_seg(struct elf_seg *segs, size_t seg_cnt, long virtaddr)
 {
        struct elf_seg *seg;
        int i;
 
-       if (relative) {
-               /* for shared libraries, address is relative offset and thus
-                * should be fall within logical offset-based range of
-                * [offset_start, offset_end)
-                */
-               for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
-                       if (seg->offset <= addr && addr < seg->offset + (seg->end - seg->start))
-                               return seg;
-               }
-       } else {
-               /* for binaries, address is absolute and thus should be within
-                * absolute address range of [seg_start, seg_end)
-                */
-               for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
-                       if (seg->start <= addr && addr < seg->end)
-                               return seg;
-               }
+       /* for ELF binaries (both executables and shared libraries), we are
+        * given virtual address (absolute for executables, relative for
+        * libraries) which should match address range of [seg_start, seg_end)
+        */
+       for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
+               if (seg->start <= virtaddr && virtaddr < seg->end)
+                       return seg;
        }
+       return NULL;
+}
 
+static struct elf_seg *find_vma_seg(struct elf_seg *segs, size_t seg_cnt, long offset)
+{
+       struct elf_seg *seg;
+       int i;
+
+       /* for VMA segments from /proc/<pid>/maps file, provided "address" is
+        * actually a file offset, so should be fall within logical
+        * offset-based range of [offset_start, offset_end)
+        */
+       for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
+               if (seg->offset <= offset && offset < seg->offset + (seg->end - seg->start))
+                       return seg;
+       }
        return NULL;
 }
 
-static int parse_usdt_note(Elf *elf, const char *path, long base_addr,
-                          GElf_Nhdr *nhdr, const char *data, size_t name_off, size_t desc_off,
+static int parse_usdt_note(Elf *elf, const char *path, GElf_Nhdr *nhdr,
+                          const char *data, size_t name_off, size_t desc_off,
                           struct usdt_note *usdt_note);
 
 static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note, __u64 usdt_cookie);
@@ -568,8 +573,8 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                                const char *usdt_provider, const char *usdt_name, __u64 usdt_cookie,
                                struct usdt_target **out_targets, size_t *out_target_cnt)
 {
-       size_t off, name_off, desc_off, seg_cnt = 0, lib_seg_cnt = 0, target_cnt = 0;
-       struct elf_seg *segs = NULL, *lib_segs = NULL;
+       size_t off, name_off, desc_off, seg_cnt = 0, vma_seg_cnt = 0, target_cnt = 0;
+       struct elf_seg *segs = NULL, *vma_segs = NULL;
        struct usdt_target *targets = NULL, *target;
        long base_addr = 0;
        Elf_Scn *notes_scn, *base_scn;
@@ -613,8 +618,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                struct elf_seg *seg = NULL;
                void *tmp;
 
-               err = parse_usdt_note(elf, path, base_addr, &nhdr,
-                                     data->d_buf, name_off, desc_off, &note);
+               err = parse_usdt_note(elf, path, &nhdr, data->d_buf, name_off, desc_off, &note);
                if (err)
                        goto err_out;
 
@@ -654,30 +658,29 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                        usdt_rel_ip += base_addr - note.base_addr;
                }
 
-               if (ehdr.e_type == ET_EXEC) {
-                       /* When attaching uprobes (which what USDTs basically
-                        * are) kernel expects a relative IP to be specified,
-                        * so if we are attaching to an executable ELF binary
-                        * (i.e., not a shared library), we need to calculate
-                        * proper relative IP based on ELF's load address
-                        */
-                       seg = find_elf_seg(segs, seg_cnt, usdt_abs_ip, false /* relative */);
-                       if (!seg) {
-                               err = -ESRCH;
-                               pr_warn("usdt: failed to find ELF program segment for '%s:%s' in '%s' at IP 0x%lx\n",
-                                       usdt_provider, usdt_name, path, usdt_abs_ip);
-                               goto err_out;
-                       }
-                       if (!seg->is_exec) {
-                               err = -ESRCH;
-                               pr_warn("usdt: matched ELF binary '%s' segment [0x%lx, 0x%lx) for '%s:%s' at IP 0x%lx is not executable\n",
-                                       path, seg->start, seg->end, usdt_provider, usdt_name,
-                                       usdt_abs_ip);
-                               goto err_out;
-                       }
+               /* When attaching uprobes (which is what USDTs basically are)
+                * kernel expects file offset to be specified, not a relative
+                * virtual address, so we need to translate virtual address to
+                * file offset, for both ET_EXEC and ET_DYN binaries.
+                */
+               seg = find_elf_seg(segs, seg_cnt, usdt_abs_ip);
+               if (!seg) {
+                       err = -ESRCH;
+                       pr_warn("usdt: failed to find ELF program segment for '%s:%s' in '%s' at IP 0x%lx\n",
+                               usdt_provider, usdt_name, path, usdt_abs_ip);
+                       goto err_out;
+               }
+               if (!seg->is_exec) {
+                       err = -ESRCH;
+                       pr_warn("usdt: matched ELF binary '%s' segment [0x%lx, 0x%lx) for '%s:%s' at IP 0x%lx is not executable\n",
+                               path, seg->start, seg->end, usdt_provider, usdt_name,
+                               usdt_abs_ip);
+                       goto err_out;
+               }
+               /* translate from virtual address to file offset */
+               usdt_rel_ip = usdt_abs_ip - seg->start + seg->offset;
 
-                       usdt_rel_ip = usdt_abs_ip - (seg->start - seg->offset);
-               } else if (!man->has_bpf_cookie) { /* ehdr.e_type == ET_DYN */
+               if (ehdr.e_type == ET_DYN && !man->has_bpf_cookie) {
                        /* If we don't have BPF cookie support but need to
                         * attach to a shared library, we'll need to know and
                         * record absolute addresses of attach points due to
@@ -697,9 +700,9 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                                goto err_out;
                        }
 
-                       /* lib_segs are lazily initialized only if necessary */
-                       if (lib_seg_cnt == 0) {
-                               err = parse_lib_segs(pid, path, &lib_segs, &lib_seg_cnt);
+                       /* vma_segs are lazily initialized only if necessary */
+                       if (vma_seg_cnt == 0) {
+                               err = parse_vma_segs(pid, path, &vma_segs, &vma_seg_cnt);
                                if (err) {
                                        pr_warn("usdt: failed to get memory segments in PID %d for shared library '%s': %d\n",
                                                pid, path, err);
@@ -707,7 +710,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                                }
                        }
 
-                       seg = find_elf_seg(lib_segs, lib_seg_cnt, usdt_rel_ip, true /* relative */);
+                       seg = find_vma_seg(vma_segs, vma_seg_cnt, usdt_rel_ip);
                        if (!seg) {
                                err = -ESRCH;
                                pr_warn("usdt: failed to find shared lib memory segment for '%s:%s' in '%s' at relative IP 0x%lx\n",
@@ -715,7 +718,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                                goto err_out;
                        }
 
-                       usdt_abs_ip = seg->start + (usdt_rel_ip - seg->offset);
+                       usdt_abs_ip = seg->start - seg->offset + usdt_rel_ip;
                }
 
                pr_debug("usdt: probe for '%s:%s' in %s '%s': addr 0x%lx base 0x%lx (resolved abs_ip 0x%lx rel_ip 0x%lx) args '%s' in segment [0x%lx, 0x%lx) at offset 0x%lx\n",
@@ -723,7 +726,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                         note.loc_addr, note.base_addr, usdt_abs_ip, usdt_rel_ip, note.args,
                         seg ? seg->start : 0, seg ? seg->end : 0, seg ? seg->offset : 0);
 
-               /* Adjust semaphore address to be a relative offset */
+               /* Adjust semaphore address to be a file offset */
                if (note.sema_addr) {
                        if (!man->has_sema_refcnt) {
                                pr_warn("usdt: kernel doesn't support USDT semaphore refcounting for '%s:%s' in '%s'\n",
@@ -732,7 +735,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                                goto err_out;
                        }
 
-                       seg = find_elf_seg(segs, seg_cnt, note.sema_addr, false /* relative */);
+                       seg = find_elf_seg(segs, seg_cnt, note.sema_addr);
                        if (!seg) {
                                err = -ESRCH;
                                pr_warn("usdt: failed to find ELF loadable segment with semaphore of '%s:%s' in '%s' at 0x%lx\n",
@@ -747,7 +750,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                                goto err_out;
                        }
 
-                       usdt_sema_off = note.sema_addr - (seg->start - seg->offset);
+                       usdt_sema_off = note.sema_addr - seg->start + seg->offset;
 
                        pr_debug("usdt: sema  for '%s:%s' in %s '%s': addr 0x%lx base 0x%lx (resolved 0x%lx) in segment [0x%lx, 0x%lx] at offset 0x%lx\n",
                                 usdt_provider, usdt_name, ehdr.e_type == ET_EXEC ? "exec" : "lib ",
@@ -770,7 +773,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
                target->rel_ip = usdt_rel_ip;
                target->sema_off = usdt_sema_off;
 
-               /* notes->args references strings from Elf itself, so they can
+               /* notes.args references strings from Elf itself, so they can
                 * be referenced safely until elf_end() call
                 */
                target->spec_str = note.args;
@@ -788,7 +791,7 @@ static int collect_usdt_targets(struct usdt_manager *man, Elf *elf, const char *
 
 err_out:
        free(segs);
-       free(lib_segs);
+       free(vma_segs);
        if (err < 0)
                free(targets);
        return err;
@@ -1089,8 +1092,8 @@ err_out:
 /* Parse out USDT ELF note from '.note.stapsdt' section.
  * Logic inspired by perf's code.
  */
-static int parse_usdt_note(Elf *elf, const char *path, long base_addr,
-                          GElf_Nhdr *nhdr, const char *data, size_t name_off, size_t desc_off,
+static int parse_usdt_note(Elf *elf, const char *path, GElf_Nhdr *nhdr,
+                          const char *data, size_t name_off, size_t desc_off,
                           struct usdt_note *note)
 {
        const char *provider, *name, *args;
index 595565e..ca2f47f 100644 (file)
@@ -43,3 +43,4 @@ test_cpp
 *.tmp
 xdpxceiver
 xdp_redirect_multi
+xdp_synproxy
index 2d3c8c8..cb8e552 100644 (file)
@@ -82,7 +82,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \
 TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \
        flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \
        test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \
-       xdpxceiver xdp_redirect_multi
+       xdpxceiver xdp_redirect_multi xdp_synproxy
 
 TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read
 
@@ -168,17 +168,26 @@ $(OUTPUT)/%:%.c
        $(call msg,BINARY,,$@)
        $(Q)$(LINK.c) $^ $(LDLIBS) -o $@
 
+# LLVM's ld.lld doesn't support all the architectures, so use it only on x86
+ifeq ($(SRCARCH),x86)
+LLD := lld
+else
+LLD := ld
+endif
+
 # Filter out -static for liburandom_read.so and its dependent targets so that static builds
 # do not fail. Static builds leave urandom_read relying on system-wide shared libraries.
 $(OUTPUT)/liburandom_read.so: urandom_read_lib1.c urandom_read_lib2.c
        $(call msg,LIB,,$@)
-       $(Q)$(CC) $(filter-out -static,$(CFLAGS) $(LDFLAGS)) $^ $(LDLIBS) -fPIC -shared -o $@
+       $(Q)$(CLANG) $(filter-out -static,$(CFLAGS) $(LDFLAGS)) $^ $(LDLIBS)   \
+                    -fuse-ld=$(LLD) -Wl,-znoseparate-code -fPIC -shared -o $@
 
 $(OUTPUT)/urandom_read: urandom_read.c urandom_read_aux.c $(OUTPUT)/liburandom_read.so
        $(call msg,BINARY,,$@)
-       $(Q)$(CC) $(filter-out -static,$(CFLAGS) $(LDFLAGS)) $(filter %.c,$^)  \
-                 liburandom_read.so $(LDLIBS)                                 \
-                 -Wl,-rpath=. -Wl,--build-id=sha1 -o $@
+       $(Q)$(CLANG) $(filter-out -static,$(CFLAGS) $(LDFLAGS)) $(filter %.c,$^) \
+                    liburandom_read.so $(LDLIBS)                              \
+                    -fuse-ld=$(LLD) -Wl,-znoseparate-code                     \
+                    -Wl,-rpath=. -Wl,--build-id=sha1 -o $@
 
 $(OUTPUT)/bpf_testmod.ko: $(VMLINUX_BTF) $(wildcard bpf_testmod/Makefile bpf_testmod/*.[ch])
        $(call msg,MOD,,$@)
@@ -502,6 +511,7 @@ TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c      \
                         cap_helpers.c
 TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \
                       $(OUTPUT)/liburandom_read.so                     \
+                      $(OUTPUT)/xdp_synproxy                           \
                       ima_setup.sh                                     \
                       $(wildcard progs/btf_dump_test_case_*.c)
 TRUNNER_BPF_BUILD_RULE := CLANG_BPF_BUILD_RULE
@@ -560,6 +570,7 @@ $(OUTPUT)/bench_ringbufs.o: $(OUTPUT)/ringbuf_bench.skel.h \
 $(OUTPUT)/bench_bloom_filter_map.o: $(OUTPUT)/bloom_filter_bench.skel.h
 $(OUTPUT)/bench_bpf_loop.o: $(OUTPUT)/bpf_loop_bench.skel.h
 $(OUTPUT)/bench_strncmp.o: $(OUTPUT)/strncmp_bench.skel.h
+$(OUTPUT)/bench_bpf_hashmap_full_update.o: $(OUTPUT)/bpf_hashmap_full_update_bench.skel.h
 $(OUTPUT)/bench.o: bench.h testing_helpers.h $(BPFOBJ)
 $(OUTPUT)/bench: LDLIBS += -lm
 $(OUTPUT)/bench: $(OUTPUT)/bench.o \
@@ -571,13 +582,16 @@ $(OUTPUT)/bench: $(OUTPUT)/bench.o \
                 $(OUTPUT)/bench_ringbufs.o \
                 $(OUTPUT)/bench_bloom_filter_map.o \
                 $(OUTPUT)/bench_bpf_loop.o \
-                $(OUTPUT)/bench_strncmp.o
+                $(OUTPUT)/bench_strncmp.o \
+                $(OUTPUT)/bench_bpf_hashmap_full_update.o
        $(call msg,BINARY,,$@)
        $(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(filter %.a %.o,$^) $(LDLIBS) -o $@
 
 EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(SCRATCH_DIR) $(HOST_SCRATCH_DIR) \
        prog_tests/tests.h map_tests/tests.h verifier/tests.h           \
        feature bpftool                                                 \
-       $(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h no_alu32 bpf_gcc bpf_testmod.ko)
+       $(addprefix $(OUTPUT)/,*.o *.skel.h *.lskel.h *.subskel.h       \
+                              no_alu32 bpf_gcc bpf_testmod.ko          \
+                              liburandom_read.so)
 
 .PHONY: docs docs-clean
index f061cc2..d8aa62b 100644 (file)
@@ -396,6 +396,7 @@ extern const struct bench bench_hashmap_with_bloom;
 extern const struct bench bench_bpf_loop;
 extern const struct bench bench_strncmp_no_helper;
 extern const struct bench bench_strncmp_helper;
+extern const struct bench bench_bpf_hashmap_full_update;
 
 static const struct bench *benchs[] = {
        &bench_count_global,
@@ -430,6 +431,7 @@ static const struct bench *benchs[] = {
        &bench_bpf_loop,
        &bench_strncmp_no_helper,
        &bench_strncmp_helper,
+       &bench_bpf_hashmap_full_update,
 };
 
 static void setup_benchmark()
diff --git a/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c b/tools/testing/selftests/bpf/benchs/bench_bpf_hashmap_full_update.c
new file mode 100644 (file)
index 0000000..cec51e0
--- /dev/null
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Bytedance */
+
+#include <argp.h>
+#include "bench.h"
+#include "bpf_hashmap_full_update_bench.skel.h"
+#include "bpf_util.h"
+
+/* BPF triggering benchmarks */
+static struct ctx {
+       struct bpf_hashmap_full_update_bench *skel;
+} ctx;
+
+#define MAX_LOOP_NUM 10000
+
+static void validate(void)
+{
+       if (env.consumer_cnt != 1) {
+               fprintf(stderr, "benchmark doesn't support multi-consumer!\n");
+               exit(1);
+       }
+}
+
+static void *producer(void *input)
+{
+       while (true) {
+               /* trigger the bpf program */
+               syscall(__NR_getpgid);
+       }
+
+       return NULL;
+}
+
+static void *consumer(void *input)
+{
+       return NULL;
+}
+
+static void measure(struct bench_res *res)
+{
+}
+
+static void setup(void)
+{
+       struct bpf_link *link;
+       int map_fd, i, max_entries;
+
+       setup_libbpf();
+
+       ctx.skel = bpf_hashmap_full_update_bench__open_and_load();
+       if (!ctx.skel) {
+               fprintf(stderr, "failed to open skeleton\n");
+               exit(1);
+       }
+
+       ctx.skel->bss->nr_loops = MAX_LOOP_NUM;
+
+       link = bpf_program__attach(ctx.skel->progs.benchmark);
+       if (!link) {
+               fprintf(stderr, "failed to attach program!\n");
+               exit(1);
+       }
+
+       /* fill hash_map */
+       map_fd = bpf_map__fd(ctx.skel->maps.hash_map_bench);
+       max_entries = bpf_map__max_entries(ctx.skel->maps.hash_map_bench);
+       for (i = 0; i < max_entries; i++)
+               bpf_map_update_elem(map_fd, &i, &i, BPF_ANY);
+}
+
+void hashmap_report_final(struct bench_res res[], int res_cnt)
+{
+       unsigned int nr_cpus = bpf_num_possible_cpus();
+       int i;
+
+       for (i = 0; i < nr_cpus; i++) {
+               u64 time = ctx.skel->bss->percpu_time[i];
+
+               if (!time)
+                       continue;
+
+               printf("%d:hash_map_full_perf %lld events per sec\n",
+                      i, ctx.skel->bss->nr_loops * 1000000000ll / time);
+       }
+}
+
+const struct bench bench_bpf_hashmap_full_update = {
+       .name = "bpf-hashmap-ful-update",
+       .validate = validate,
+       .setup = setup,
+       .producer_thread = producer,
+       .consumer_thread = consumer,
+       .measure = measure,
+       .report_progress = NULL,
+       .report_final = hashmap_report_final,
+};
diff --git a/tools/testing/selftests/bpf/benchs/run_bench_bpf_hashmap_full_update.sh b/tools/testing/selftests/bpf/benchs/run_bench_bpf_hashmap_full_update.sh
new file mode 100755 (executable)
index 0000000..1e2de83
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+source ./benchs/run_common.sh
+
+set -eufo pipefail
+
+nr_threads=`expr $(cat /proc/cpuinfo | grep "processor"| wc -l) - 1`
+summary=$($RUN_BENCH -p $nr_threads bpf-hashmap-ful-update)
+printf "$summary"
+printf "\n"
index b5941d5..1c1c2c2 100644 (file)
@@ -26,11 +26,12 @@ static const char * const btf_kind_str_mapping[] = {
        [BTF_KIND_FLOAT]        = "FLOAT",
        [BTF_KIND_DECL_TAG]     = "DECL_TAG",
        [BTF_KIND_TYPE_TAG]     = "TYPE_TAG",
+       [BTF_KIND_ENUM64]       = "ENUM64",
 };
 
 static const char *btf_kind_str(__u16 kind)
 {
-       if (kind > BTF_KIND_TYPE_TAG)
+       if (kind > BTF_KIND_ENUM64)
                return "UNKNOWN";
        return btf_kind_str_mapping[kind];
 }
@@ -139,14 +140,32 @@ int fprintf_btf_type_raw(FILE *out, const struct btf *btf, __u32 id)
        }
        case BTF_KIND_ENUM: {
                const struct btf_enum *v = btf_enum(t);
+               const char *fmt_str;
 
-               fprintf(out, " size=%u vlen=%u", t->size, vlen);
+               fmt_str = btf_kflag(t) ? "\n\t'%s' val=%d" : "\n\t'%s' val=%u";
+               fprintf(out, " encoding=%s size=%u vlen=%u",
+                       btf_kflag(t) ? "SIGNED" : "UNSIGNED", t->size, vlen);
                for (i = 0; i < vlen; i++, v++) {
-                       fprintf(out, "\n\t'%s' val=%u",
+                       fprintf(out, fmt_str,
                                btf_str(btf, v->name_off), v->val);
                }
                break;
        }
+       case BTF_KIND_ENUM64: {
+               const struct btf_enum64 *v = btf_enum64(t);
+               const char *fmt_str;
+
+               fmt_str = btf_kflag(t) ? "\n\t'%s' val=%lld" : "\n\t'%s' val=%llu";
+
+               fprintf(out, " encoding=%s size=%u vlen=%u",
+                       btf_kflag(t) ? "SIGNED" : "UNSIGNED", t->size, vlen);
+               for (i = 0; i < vlen; i++, v++) {
+                       fprintf(out, fmt_str,
+                               btf_str(btf, v->name_off),
+                               ((__u64)v->val_hi32 << 32) | v->val_lo32);
+               }
+               break;
+       }
        case BTF_KIND_FWD:
                fprintf(out, " fwd_kind=%s", btf_kflag(t) ? "union" : "struct");
                break;
index 08c0601..0b899d2 100644 (file)
@@ -17,6 +17,14 @@ static void trigger_func2(void)
        asm volatile ("");
 }
 
+/* attach point for byname sleepable uprobe */
+static void trigger_func3(void)
+{
+       asm volatile ("");
+}
+
+static char test_data[] = "test_data";
+
 void test_attach_probe(void)
 {
        DECLARE_LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts);
@@ -49,9 +57,17 @@ void test_attach_probe(void)
        if (!ASSERT_GE(ref_ctr_offset, 0, "ref_ctr_offset"))
                return;
 
-       skel = test_attach_probe__open_and_load();
+       skel = test_attach_probe__open();
        if (!ASSERT_OK_PTR(skel, "skel_open"))
                return;
+
+       /* sleepable kprobe test case needs flags set before loading */
+       if (!ASSERT_OK(bpf_program__set_flags(skel->progs.handle_kprobe_sleepable,
+               BPF_F_SLEEPABLE), "kprobe_sleepable_flags"))
+               goto cleanup;
+
+       if (!ASSERT_OK(test_attach_probe__load(skel), "skel_load"))
+               goto cleanup;
        if (!ASSERT_OK_PTR(skel->bss, "check_bss"))
                goto cleanup;
 
@@ -151,6 +167,30 @@ void test_attach_probe(void)
        if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname2, "attach_uretprobe_byname2"))
                goto cleanup;
 
+       /* sleepable kprobes should not attach successfully */
+       skel->links.handle_kprobe_sleepable = bpf_program__attach(skel->progs.handle_kprobe_sleepable);
+       if (!ASSERT_ERR_PTR(skel->links.handle_kprobe_sleepable, "attach_kprobe_sleepable"))
+               goto cleanup;
+
+       /* test sleepable uprobe and uretprobe variants */
+       skel->links.handle_uprobe_byname3_sleepable = bpf_program__attach(skel->progs.handle_uprobe_byname3_sleepable);
+       if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname3_sleepable, "attach_uprobe_byname3_sleepable"))
+               goto cleanup;
+
+       skel->links.handle_uprobe_byname3 = bpf_program__attach(skel->progs.handle_uprobe_byname3);
+       if (!ASSERT_OK_PTR(skel->links.handle_uprobe_byname3, "attach_uprobe_byname3"))
+               goto cleanup;
+
+       skel->links.handle_uretprobe_byname3_sleepable = bpf_program__attach(skel->progs.handle_uretprobe_byname3_sleepable);
+       if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname3_sleepable, "attach_uretprobe_byname3_sleepable"))
+               goto cleanup;
+
+       skel->links.handle_uretprobe_byname3 = bpf_program__attach(skel->progs.handle_uretprobe_byname3);
+       if (!ASSERT_OK_PTR(skel->links.handle_uretprobe_byname3, "attach_uretprobe_byname3"))
+               goto cleanup;
+
+       skel->bss->user_ptr = test_data;
+
        /* trigger & validate kprobe && kretprobe */
        usleep(1);
 
@@ -164,6 +204,9 @@ void test_attach_probe(void)
        /* trigger & validate uprobe attached by name */
        trigger_func2();
 
+       /* trigger & validate sleepable uprobe attached by name */
+       trigger_func3();
+
        ASSERT_EQ(skel->bss->kprobe_res, 1, "check_kprobe_res");
        ASSERT_EQ(skel->bss->kprobe2_res, 11, "check_kprobe_auto_res");
        ASSERT_EQ(skel->bss->kretprobe_res, 2, "check_kretprobe_res");
@@ -174,6 +217,10 @@ void test_attach_probe(void)
        ASSERT_EQ(skel->bss->uretprobe_byname_res, 6, "check_uretprobe_byname_res");
        ASSERT_EQ(skel->bss->uprobe_byname2_res, 7, "check_uprobe_byname2_res");
        ASSERT_EQ(skel->bss->uretprobe_byname2_res, 8, "check_uretprobe_byname2_res");
+       ASSERT_EQ(skel->bss->uprobe_byname3_sleepable_res, 9, "check_uprobe_byname3_sleepable_res");
+       ASSERT_EQ(skel->bss->uprobe_byname3_res, 10, "check_uprobe_byname3_res");
+       ASSERT_EQ(skel->bss->uretprobe_byname3_sleepable_res, 11, "check_uretprobe_byname3_sleepable_res");
+       ASSERT_EQ(skel->bss->uretprobe_byname3_res, 12, "check_uretprobe_byname3_res");
 
 cleanup:
        test_attach_probe__destroy(skel);
index ba5bde5..edb3871 100644 (file)
@@ -2897,26 +2897,6 @@ static struct btf_raw_test raw_tests[] = {
 },
 
 {
-       .descr = "invalid enum kind_flag",
-       .raw_types = {
-               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),          /* [1] */
-               BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 1, 1), 4),  /* [2] */
-               BTF_ENUM_ENC(NAME_TBD, 0),
-               BTF_END_RAW,
-       },
-       BTF_STR_SEC("\0A"),
-       .map_type = BPF_MAP_TYPE_ARRAY,
-       .map_name = "enum_type_check_btf",
-       .key_size = sizeof(int),
-       .value_size = sizeof(int),
-       .key_type_id = 1,
-       .value_type_id = 1,
-       .max_entries = 4,
-       .btf_load_err = true,
-       .err_str = "Invalid btf_info kind_flag",
-},
-
-{
        .descr = "valid fwd kind_flag",
        .raw_types = {
                BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),          /* [1] */
@@ -4072,6 +4052,42 @@ static struct btf_raw_test raw_tests[] = {
        .btf_load_err = true,
        .err_str = "Type tags don't precede modifiers",
 },
+{
+       .descr = "enum64 test #1, unsigned, size 8",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),                  /* [1] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 2), 8), /* [2] */
+               BTF_ENUM64_ENC(NAME_TBD, 0, 0),
+               BTF_ENUM64_ENC(NAME_TBD, 1, 1),
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0a\0b\0c"),
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "tag_type_check_btf",
+       .key_size = sizeof(int),
+       .value_size = 8,
+       .key_type_id = 1,
+       .value_type_id = 2,
+       .max_entries = 1,
+},
+{
+       .descr = "enum64 test #2, signed, size 4",
+       .raw_types = {
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),                  /* [1] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM64, 1, 2), 4), /* [2] */
+               BTF_ENUM64_ENC(NAME_TBD, -1, 0),
+               BTF_ENUM64_ENC(NAME_TBD, 1, 0),
+               BTF_END_RAW,
+       },
+       BTF_STR_SEC("\0a\0b\0c"),
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "tag_type_check_btf",
+       .key_size = sizeof(int),
+       .value_size = 4,
+       .key_type_id = 1,
+       .value_type_id = 2,
+       .max_entries = 1,
+},
 
 }; /* struct btf_raw_test raw_tests[] */
 
@@ -7000,9 +7016,12 @@ static struct btf_dedup_test dedup_tests[] = {
                        BTF_DECL_TAG_ENC(NAME_TBD, 13, 1),                              /* [16] decl_tag */
                        BTF_DECL_TAG_ENC(NAME_TBD, 7, -1),                              /* [17] decl_tag */
                        BTF_TYPE_TAG_ENC(NAME_TBD, 8),                                  /* [18] type_tag */
+                       BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 2), 8), /* [19] enum64 */
+                               BTF_ENUM64_ENC(NAME_TBD, 0, 0),
+                               BTF_ENUM64_ENC(NAME_TBD, 1, 1),
                        BTF_END_RAW,
                },
-               BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P\0Q\0R"),
+               BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P\0Q\0R\0S\0T\0U"),
        },
        .expect = {
                .raw_types = {
@@ -7030,9 +7049,12 @@ static struct btf_dedup_test dedup_tests[] = {
                        BTF_DECL_TAG_ENC(NAME_TBD, 13, 1),                              /* [16] decl_tag */
                        BTF_DECL_TAG_ENC(NAME_TBD, 7, -1),                              /* [17] decl_tag */
                        BTF_TYPE_TAG_ENC(NAME_TBD, 8),                                  /* [18] type_tag */
+                       BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 2), 8), /* [19] enum64 */
+                               BTF_ENUM64_ENC(NAME_TBD, 0, 0),
+                               BTF_ENUM64_ENC(NAME_TBD, 1, 1),
                        BTF_END_RAW,
                },
-               BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P\0Q\0R"),
+               BTF_STR_SEC("\0A\0B\0C\0D\0E\0F\0G\0H\0I\0J\0K\0L\0M\0N\0O\0P\0Q\0R\0S\0T\0U"),
        },
 },
 {
@@ -7493,6 +7515,91 @@ static struct btf_dedup_test dedup_tests[] = {
                BTF_STR_SEC("\0tag1\0t\0m"),
        },
 },
+{
+       .descr = "dedup: enum64, standalone",
+       .input = {
+               .raw_types = {
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 123),
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 123),
+                       BTF_END_RAW,
+               },
+               BTF_STR_SEC("\0e1\0e1_val"),
+       },
+       .expect = {
+               .raw_types = {
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 123),
+                       BTF_END_RAW,
+               },
+               BTF_STR_SEC("\0e1\0e1_val"),
+       },
+},
+{
+       .descr = "dedup: enum64, fwd resolution",
+       .input = {
+               .raw_types = {
+                       /* [1] fwd enum64 'e1' before full enum */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
+                       /* [2] full enum64 'e1' after fwd */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 123),
+                       /* [3] full enum64 'e2' before fwd */
+                       BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(4), 0, 456),
+                       /* [4] fwd enum64 'e2' after full enum */
+                       BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 0), 8),
+                       /* [5] incompatible full enum64 with different value */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 0, 321),
+                       BTF_END_RAW,
+               },
+               BTF_STR_SEC("\0e1\0e1_val\0e2\0e2_val"),
+       },
+       .expect = {
+               .raw_types = {
+                       /* [1] full enum64 'e1' */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 123),
+                       /* [2] full enum64 'e2' */
+                       BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(4), 0, 456),
+                       /* [3] incompatible full enum64 with different value */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 8),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 0, 321),
+                       BTF_END_RAW,
+               },
+               BTF_STR_SEC("\0e1\0e1_val\0e2\0e2_val"),
+       },
+},
+{
+       .descr = "dedup: enum and enum64, no dedup",
+       .input = {
+               .raw_types = {
+                       /* [1] enum 'e1' */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
+                               BTF_ENUM_ENC(NAME_NTH(2), 1),
+                       /* [2] enum64 'e1' */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 4),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 0),
+                       BTF_END_RAW,
+               },
+               BTF_STR_SEC("\0e1\0e1_val"),
+       },
+       .expect = {
+               .raw_types = {
+                       /* [1] enum 'e1' */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
+                               BTF_ENUM_ENC(NAME_NTH(2), 1),
+                       /* [2] enum64 'e1' */
+                       BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM64, 0, 1), 4),
+                               BTF_ENUM64_ENC(NAME_NTH(2), 1, 0),
+                       BTF_END_RAW,
+               },
+               BTF_STR_SEC("\0e1\0e1_val"),
+       },
+},
 
 };
 
@@ -7517,6 +7624,8 @@ static int btf_type_size(const struct btf_type *t)
                return base_size + sizeof(__u32);
        case BTF_KIND_ENUM:
                return base_size + vlen * sizeof(struct btf_enum);
+       case BTF_KIND_ENUM64:
+               return base_size + vlen * sizeof(struct btf_enum64);
        case BTF_KIND_ARRAY:
                return base_size + sizeof(struct btf_array);
        case BTF_KIND_STRUCT:
index addf99c..6e36de1 100644 (file)
@@ -9,6 +9,7 @@ static void gen_btf(struct btf *btf)
        const struct btf_var_secinfo *vi;
        const struct btf_type *t;
        const struct btf_member *m;
+       const struct btf_enum64 *v64;
        const struct btf_enum *v;
        const struct btf_param *p;
        int id, err, str_off;
@@ -171,7 +172,7 @@ static void gen_btf(struct btf *btf)
        ASSERT_STREQ(btf__str_by_offset(btf, v->name_off), "v2", "v2_name");
        ASSERT_EQ(v->val, 2, "v2_val");
        ASSERT_STREQ(btf_type_raw_dump(btf, 9),
-                    "[9] ENUM 'e1' size=4 vlen=2\n"
+                    "[9] ENUM 'e1' encoding=UNSIGNED size=4 vlen=2\n"
                     "\t'v1' val=1\n"
                     "\t'v2' val=2", "raw_dump");
 
@@ -202,7 +203,7 @@ static void gen_btf(struct btf *btf)
        ASSERT_EQ(btf_vlen(t), 0, "enum_fwd_kind");
        ASSERT_EQ(t->size, 4, "enum_fwd_sz");
        ASSERT_STREQ(btf_type_raw_dump(btf, 12),
-                    "[12] ENUM 'enum_fwd' size=4 vlen=0", "raw_dump");
+                    "[12] ENUM 'enum_fwd' encoding=UNSIGNED size=4 vlen=0", "raw_dump");
 
        /* TYPEDEF */
        id = btf__add_typedef(btf, "typedef1", 1);
@@ -307,6 +308,48 @@ static void gen_btf(struct btf *btf)
        ASSERT_EQ(t->type, 1, "tag_type");
        ASSERT_STREQ(btf_type_raw_dump(btf, 20),
                     "[20] TYPE_TAG 'tag1' type_id=1", "raw_dump");
+
+       /* ENUM64 */
+       id = btf__add_enum64(btf, "e1", 8, true);
+       ASSERT_EQ(id, 21, "enum64_id");
+       err = btf__add_enum64_value(btf, "v1", -1);
+       ASSERT_OK(err, "v1_res");
+       err = btf__add_enum64_value(btf, "v2", 0x123456789); /* 4886718345 */
+       ASSERT_OK(err, "v2_res");
+       t = btf__type_by_id(btf, 21);
+       ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "e1", "enum64_name");
+       ASSERT_EQ(btf_kind(t), BTF_KIND_ENUM64, "enum64_kind");
+       ASSERT_EQ(btf_vlen(t), 2, "enum64_vlen");
+       ASSERT_EQ(t->size, 8, "enum64_sz");
+       v64 = btf_enum64(t) + 0;
+       ASSERT_STREQ(btf__str_by_offset(btf, v64->name_off), "v1", "v1_name");
+       ASSERT_EQ(v64->val_hi32, 0xffffffff, "v1_val");
+       ASSERT_EQ(v64->val_lo32, 0xffffffff, "v1_val");
+       v64 = btf_enum64(t) + 1;
+       ASSERT_STREQ(btf__str_by_offset(btf, v64->name_off), "v2", "v2_name");
+       ASSERT_EQ(v64->val_hi32, 0x1, "v2_val");
+       ASSERT_EQ(v64->val_lo32, 0x23456789, "v2_val");
+       ASSERT_STREQ(btf_type_raw_dump(btf, 21),
+                    "[21] ENUM64 'e1' encoding=SIGNED size=8 vlen=2\n"
+                    "\t'v1' val=-1\n"
+                    "\t'v2' val=4886718345", "raw_dump");
+
+       id = btf__add_enum64(btf, "e1", 8, false);
+       ASSERT_EQ(id, 22, "enum64_id");
+       err = btf__add_enum64_value(btf, "v1", 0xffffffffFFFFFFFF); /* 18446744073709551615 */
+       ASSERT_OK(err, "v1_res");
+       t = btf__type_by_id(btf, 22);
+       ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "e1", "enum64_name");
+       ASSERT_EQ(btf_kind(t), BTF_KIND_ENUM64, "enum64_kind");
+       ASSERT_EQ(btf_vlen(t), 1, "enum64_vlen");
+       ASSERT_EQ(t->size, 8, "enum64_sz");
+       v64 = btf_enum64(t) + 0;
+       ASSERT_STREQ(btf__str_by_offset(btf, v64->name_off), "v1", "v1_name");
+       ASSERT_EQ(v64->val_hi32, 0xffffffff, "v1_val");
+       ASSERT_EQ(v64->val_lo32, 0xffffffff, "v1_val");
+       ASSERT_STREQ(btf_type_raw_dump(btf, 22),
+                    "[22] ENUM64 'e1' encoding=UNSIGNED size=8 vlen=1\n"
+                    "\t'v1' val=18446744073709551615", "raw_dump");
 }
 
 static void test_btf_add()
@@ -332,12 +375,12 @@ static void test_btf_add()
                "\t'f2' type_id=1 bits_offset=32 bitfield_size=16",
                "[8] UNION 'u1' size=8 vlen=1\n"
                "\t'f1' type_id=1 bits_offset=0 bitfield_size=16",
-               "[9] ENUM 'e1' size=4 vlen=2\n"
+               "[9] ENUM 'e1' encoding=UNSIGNED size=4 vlen=2\n"
                "\t'v1' val=1\n"
                "\t'v2' val=2",
                "[10] FWD 'struct_fwd' fwd_kind=struct",
                "[11] FWD 'union_fwd' fwd_kind=union",
-               "[12] ENUM 'enum_fwd' size=4 vlen=0",
+               "[12] ENUM 'enum_fwd' encoding=UNSIGNED size=4 vlen=0",
                "[13] TYPEDEF 'typedef1' type_id=1",
                "[14] FUNC 'func1' type_id=15 linkage=global",
                "[15] FUNC_PROTO '(anon)' ret_type_id=1 vlen=2\n"
@@ -348,7 +391,12 @@ static void test_btf_add()
                "\ttype_id=1 offset=4 size=8",
                "[18] DECL_TAG 'tag1' type_id=16 component_idx=-1",
                "[19] DECL_TAG 'tag2' type_id=14 component_idx=1",
-               "[20] TYPE_TAG 'tag1' type_id=1");
+               "[20] TYPE_TAG 'tag1' type_id=1",
+               "[21] ENUM64 'e1' encoding=SIGNED size=8 vlen=2\n"
+               "\t'v1' val=-1\n"
+               "\t'v2' val=4886718345",
+               "[22] ENUM64 'e1' encoding=UNSIGNED size=8 vlen=1\n"
+               "\t'v1' val=18446744073709551615");
 
        btf__free(btf);
 }
@@ -370,7 +418,7 @@ static void test_btf_add_btf()
        gen_btf(btf2);
 
        id = btf__add_btf(btf1, btf2);
-       if (!ASSERT_EQ(id, 21, "id"))
+       if (!ASSERT_EQ(id, 23, "id"))
                goto cleanup;
 
        VALIDATE_RAW_BTF(
@@ -386,12 +434,12 @@ static void test_btf_add_btf()
                "\t'f2' type_id=1 bits_offset=32 bitfield_size=16",
                "[8] UNION 'u1' size=8 vlen=1\n"
                "\t'f1' type_id=1 bits_offset=0 bitfield_size=16",
-               "[9] ENUM 'e1' size=4 vlen=2\n"
+               "[9] ENUM 'e1' encoding=UNSIGNED size=4 vlen=2\n"
                "\t'v1' val=1\n"
                "\t'v2' val=2",
                "[10] FWD 'struct_fwd' fwd_kind=struct",
                "[11] FWD 'union_fwd' fwd_kind=union",
-               "[12] ENUM 'enum_fwd' size=4 vlen=0",
+               "[12] ENUM 'enum_fwd' encoding=UNSIGNED size=4 vlen=0",
                "[13] TYPEDEF 'typedef1' type_id=1",
                "[14] FUNC 'func1' type_id=15 linkage=global",
                "[15] FUNC_PROTO '(anon)' ret_type_id=1 vlen=2\n"
@@ -403,36 +451,46 @@ static void test_btf_add_btf()
                "[18] DECL_TAG 'tag1' type_id=16 component_idx=-1",
                "[19] DECL_TAG 'tag2' type_id=14 component_idx=1",
                "[20] TYPE_TAG 'tag1' type_id=1",
+               "[21] ENUM64 'e1' encoding=SIGNED size=8 vlen=2\n"
+               "\t'v1' val=-1\n"
+               "\t'v2' val=4886718345",
+               "[22] ENUM64 'e1' encoding=UNSIGNED size=8 vlen=1\n"
+               "\t'v1' val=18446744073709551615",
 
                /* types appended from the second BTF */
-               "[21] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
-               "[22] PTR '(anon)' type_id=21",
-               "[23] CONST '(anon)' type_id=25",
-               "[24] VOLATILE '(anon)' type_id=23",
-               "[25] RESTRICT '(anon)' type_id=24",
-               "[26] ARRAY '(anon)' type_id=22 index_type_id=21 nr_elems=10",
-               "[27] STRUCT 's1' size=8 vlen=2\n"
-               "\t'f1' type_id=21 bits_offset=0\n"
-               "\t'f2' type_id=21 bits_offset=32 bitfield_size=16",
-               "[28] UNION 'u1' size=8 vlen=1\n"
-               "\t'f1' type_id=21 bits_offset=0 bitfield_size=16",
-               "[29] ENUM 'e1' size=4 vlen=2\n"
+               "[23] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED",
+               "[24] PTR '(anon)' type_id=23",
+               "[25] CONST '(anon)' type_id=27",
+               "[26] VOLATILE '(anon)' type_id=25",
+               "[27] RESTRICT '(anon)' type_id=26",
+               "[28] ARRAY '(anon)' type_id=24 index_type_id=23 nr_elems=10",
+               "[29] STRUCT 's1' size=8 vlen=2\n"
+               "\t'f1' type_id=23 bits_offset=0\n"
+               "\t'f2' type_id=23 bits_offset=32 bitfield_size=16",
+               "[30] UNION 'u1' size=8 vlen=1\n"
+               "\t'f1' type_id=23 bits_offset=0 bitfield_size=16",
+               "[31] ENUM 'e1' encoding=UNSIGNED size=4 vlen=2\n"
                "\t'v1' val=1\n"
                "\t'v2' val=2",
-               "[30] FWD 'struct_fwd' fwd_kind=struct",
-               "[31] FWD 'union_fwd' fwd_kind=union",
-               "[32] ENUM 'enum_fwd' size=4 vlen=0",
-               "[33] TYPEDEF 'typedef1' type_id=21",
-               "[34] FUNC 'func1' type_id=35 linkage=global",
-               "[35] FUNC_PROTO '(anon)' ret_type_id=21 vlen=2\n"
-               "\t'p1' type_id=21\n"
-               "\t'p2' type_id=22",
-               "[36] VAR 'var1' type_id=21, linkage=global-alloc",
-               "[37] DATASEC 'datasec1' size=12 vlen=1\n"
-               "\ttype_id=21 offset=4 size=8",
-               "[38] DECL_TAG 'tag1' type_id=36 component_idx=-1",
-               "[39] DECL_TAG 'tag2' type_id=34 component_idx=1",
-               "[40] TYPE_TAG 'tag1' type_id=21");
+               "[32] FWD 'struct_fwd' fwd_kind=struct",
+               "[33] FWD 'union_fwd' fwd_kind=union",
+               "[34] ENUM 'enum_fwd' encoding=UNSIGNED size=4 vlen=0",
+               "[35] TYPEDEF 'typedef1' type_id=23",
+               "[36] FUNC 'func1' type_id=37 linkage=global",
+               "[37] FUNC_PROTO '(anon)' ret_type_id=23 vlen=2\n"
+               "\t'p1' type_id=23\n"
+               "\t'p2' type_id=24",
+               "[38] VAR 'var1' type_id=23, linkage=global-alloc",
+               "[39] DATASEC 'datasec1' size=12 vlen=1\n"
+               "\ttype_id=23 offset=4 size=8",
+               "[40] DECL_TAG 'tag1' type_id=38 component_idx=-1",
+               "[41] DECL_TAG 'tag2' type_id=36 component_idx=1",
+               "[42] TYPE_TAG 'tag1' type_id=23",
+               "[43] ENUM64 'e1' encoding=SIGNED size=8 vlen=2\n"
+               "\t'v1' val=-1\n"
+               "\t'v2' val=4886718345",
+               "[44] ENUM64 'e1' encoding=UNSIGNED size=8 vlen=1\n"
+               "\t'v1' val=18446744073709551615");
 
 cleanup:
        btf__free(btf1);
index 3712dfe..2f92feb 100644 (file)
@@ -84,6 +84,7 @@ static int duration = 0;
 #define NESTING_ERR_CASE(name) {                                       \
        NESTING_CASE_COMMON(name),                                      \
        .fails = true,                                                  \
+       .run_btfgen_fails = true,                                                       \
 }
 
 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {     \
@@ -258,12 +259,14 @@ static int duration = 0;
        BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o",     \
                              "probed:", name),                         \
        .fails = true,                                                  \
+       .run_btfgen_fails = true,                                                       \
        .raw_tp_name = "sys_enter",                                     \
        .prog_name = "test_core_bitfields",                             \
 }, {                                                                   \
        BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o",     \
                              "direct:", name),                         \
        .fails = true,                                                  \
+       .run_btfgen_fails = true,                                                       \
        .prog_name = "test_core_bitfields_direct",                      \
 }
 
@@ -304,6 +307,7 @@ static int duration = 0;
 #define SIZE_ERR_CASE(name) {                                          \
        SIZE_CASE_COMMON(name),                                         \
        .fails = true,                                                  \
+       .run_btfgen_fails = true,                                                       \
 }
 
 #define TYPE_BASED_CASE_COMMON(name)                                   \
@@ -363,6 +367,25 @@ static int duration = 0;
        .fails = true,                                                  \
 }
 
+#define ENUM64VAL_CASE_COMMON(name)                                    \
+       .case_name = #name,                                             \
+       .bpf_obj_file = "test_core_reloc_enum64val.o",                  \
+       .btf_src_file = "btf__core_reloc_" #name ".o",                  \
+       .raw_tp_name = "sys_enter",                                     \
+       .prog_name = "test_core_enum64val"
+
+#define ENUM64VAL_CASE(name, ...) {                                    \
+       ENUM64VAL_CASE_COMMON(name),                                    \
+       .output = STRUCT_TO_CHAR_PTR(core_reloc_enum64val_output)       \
+                       __VA_ARGS__,                                    \
+       .output_len = sizeof(struct core_reloc_enum64val_output),       \
+}
+
+#define ENUM64VAL_ERR_CASE(name) {                                     \
+       ENUM64VAL_CASE_COMMON(name),                                    \
+       .fails = true,                                                  \
+}
+
 struct core_reloc_test_case;
 
 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
@@ -377,6 +400,7 @@ struct core_reloc_test_case {
        const char *output;
        int output_len;
        bool fails;
+       bool run_btfgen_fails;
        bool needs_testmod;
        bool relaxed_core_relocs;
        const char *prog_name;
@@ -831,6 +855,45 @@ static const struct core_reloc_test_case test_cases[] = {
                .anon_val2 = 0x222,
        }),
        ENUMVAL_ERR_CASE(enumval___err_missing),
+
+       /* 64bit enumerator value existence and value relocations */
+       ENUM64VAL_CASE(enum64val, {
+               .unsigned_val1_exists = true,
+               .unsigned_val2_exists = true,
+               .unsigned_val3_exists = true,
+               .signed_val1_exists = true,
+               .signed_val2_exists = true,
+               .signed_val3_exists = true,
+               .unsigned_val1 = 0x1ffffffffULL,
+               .unsigned_val2 = 0x2,
+               .signed_val1 = 0x1ffffffffLL,
+               .signed_val2 = -2,
+       }),
+       ENUM64VAL_CASE(enum64val___diff, {
+               .unsigned_val1_exists = true,
+               .unsigned_val2_exists = true,
+               .unsigned_val3_exists = true,
+               .signed_val1_exists = true,
+               .signed_val2_exists = true,
+               .signed_val3_exists = true,
+               .unsigned_val1 = 0x101ffffffffULL,
+               .unsigned_val2 = 0x202ffffffffULL,
+               .signed_val1 = -101,
+               .signed_val2 = -202,
+       }),
+       ENUM64VAL_CASE(enum64val___val3_missing, {
+               .unsigned_val1_exists = true,
+               .unsigned_val2_exists = true,
+               .unsigned_val3_exists = false,
+               .signed_val1_exists = true,
+               .signed_val2_exists = true,
+               .signed_val3_exists = false,
+               .unsigned_val1 = 0x111ffffffffULL,
+               .unsigned_val2 = 0x222,
+               .signed_val1 = 0x111ffffffffLL,
+               .signed_val2 = -222,
+       }),
+       ENUM64VAL_ERR_CASE(enum64val___err_missing),
 };
 
 struct data {
@@ -894,7 +957,7 @@ static void run_core_reloc_tests(bool use_btfgen)
                /* generate a "minimal" BTF file and use it as source */
                if (use_btfgen) {
 
-                       if (!test_case->btf_src_file || test_case->fails) {
+                       if (!test_case->btf_src_file || test_case->run_btfgen_fails) {
                                test__skip();
                                continue;
                        }
index a7e7429..5a7e601 100644 (file)
@@ -7,11 +7,9 @@
 
 void serial_test_fexit_stress(void)
 {
-       char test_skb[128] = {};
        int fexit_fd[CNT] = {};
        int link_fd[CNT] = {};
-       char error[4096];
-       int err, i, filter_fd;
+       int err, i;
 
        const struct bpf_insn trace_program[] = {
                BPF_MOV64_IMM(BPF_REG_0, 0),
@@ -20,25 +18,9 @@ void serial_test_fexit_stress(void)
 
        LIBBPF_OPTS(bpf_prog_load_opts, trace_opts,
                .expected_attach_type = BPF_TRACE_FEXIT,
-               .log_buf = error,
-               .log_size = sizeof(error),
        );
 
-       const struct bpf_insn skb_program[] = {
-               BPF_MOV64_IMM(BPF_REG_0, 0),
-               BPF_EXIT_INSN(),
-       };
-
-       LIBBPF_OPTS(bpf_prog_load_opts, skb_opts,
-               .log_buf = error,
-               .log_size = sizeof(error),
-       );
-
-       LIBBPF_OPTS(bpf_test_run_opts, topts,
-               .data_in = test_skb,
-               .data_size_in = sizeof(test_skb),
-               .repeat = 1,
-       );
+       LIBBPF_OPTS(bpf_test_run_opts, topts);
 
        err = libbpf_find_vmlinux_btf_id("bpf_fentry_test1",
                                         trace_opts.expected_attach_type);
@@ -58,15 +40,9 @@ void serial_test_fexit_stress(void)
                        goto out;
        }
 
-       filter_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
-                                 skb_program, sizeof(skb_program) / sizeof(struct bpf_insn),
-                                 &skb_opts);
-       if (!ASSERT_GE(filter_fd, 0, "test_program_loaded"))
-               goto out;
+       err = bpf_prog_test_run_opts(fexit_fd[0], &topts);
+       ASSERT_OK(err, "bpf_prog_test_run_opts");
 
-       err = bpf_prog_test_run_opts(filter_fd, &topts);
-       close(filter_fd);
-       CHECK_FAIL(err);
 out:
        for (i = 0; i < CNT; i++) {
                if (link_fd[i])
diff --git a/tools/testing/selftests/bpf/prog_tests/libbpf_str.c b/tools/testing/selftests/bpf/prog_tests/libbpf_str.c
new file mode 100644 (file)
index 0000000..93e9cdd
--- /dev/null
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include <ctype.h>
+#include <test_progs.h>
+#include <bpf/btf.h>
+
+/*
+ * Utility function uppercasing an entire string.
+ */
+static void uppercase(char *s)
+{
+       for (; *s != '\0'; s++)
+               *s = toupper(*s);
+}
+
+/*
+ * Test case to check that all bpf_attach_type variants are covered by
+ * libbpf_bpf_attach_type_str.
+ */
+static void test_libbpf_bpf_attach_type_str(void)
+{
+       struct btf *btf;
+       const struct btf_type *t;
+       const struct btf_enum *e;
+       int i, n, id;
+
+       btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
+       if (!ASSERT_OK_PTR(btf, "btf_parse"))
+               return;
+
+       /* find enum bpf_attach_type and enumerate each value */
+       id = btf__find_by_name_kind(btf, "bpf_attach_type", BTF_KIND_ENUM);
+       if (!ASSERT_GT(id, 0, "bpf_attach_type_id"))
+               goto cleanup;
+       t = btf__type_by_id(btf, id);
+       e = btf_enum(t);
+       n = btf_vlen(t);
+       for (i = 0; i < n; e++, i++) {
+               enum bpf_attach_type attach_type = (enum bpf_attach_type)e->val;
+               const char *attach_type_name;
+               const char *attach_type_str;
+               char buf[256];
+
+               if (attach_type == __MAX_BPF_ATTACH_TYPE)
+                       continue;
+
+               attach_type_name = btf__str_by_offset(btf, e->name_off);
+               attach_type_str = libbpf_bpf_attach_type_str(attach_type);
+               ASSERT_OK_PTR(attach_type_str, attach_type_name);
+
+               snprintf(buf, sizeof(buf), "BPF_%s", attach_type_str);
+               uppercase(buf);
+
+               ASSERT_STREQ(buf, attach_type_name, "exp_str_value");
+       }
+
+cleanup:
+       btf__free(btf);
+}
+
+/*
+ * Test case to check that all bpf_link_type variants are covered by
+ * libbpf_bpf_link_type_str.
+ */
+static void test_libbpf_bpf_link_type_str(void)
+{
+       struct btf *btf;
+       const struct btf_type *t;
+       const struct btf_enum *e;
+       int i, n, id;
+
+       btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
+       if (!ASSERT_OK_PTR(btf, "btf_parse"))
+               return;
+
+       /* find enum bpf_link_type and enumerate each value */
+       id = btf__find_by_name_kind(btf, "bpf_link_type", BTF_KIND_ENUM);
+       if (!ASSERT_GT(id, 0, "bpf_link_type_id"))
+               goto cleanup;
+       t = btf__type_by_id(btf, id);
+       e = btf_enum(t);
+       n = btf_vlen(t);
+       for (i = 0; i < n; e++, i++) {
+               enum bpf_link_type link_type = (enum bpf_link_type)e->val;
+               const char *link_type_name;
+               const char *link_type_str;
+               char buf[256];
+
+               if (link_type == MAX_BPF_LINK_TYPE)
+                       continue;
+
+               link_type_name = btf__str_by_offset(btf, e->name_off);
+               link_type_str = libbpf_bpf_link_type_str(link_type);
+               ASSERT_OK_PTR(link_type_str, link_type_name);
+
+               snprintf(buf, sizeof(buf), "BPF_LINK_TYPE_%s", link_type_str);
+               uppercase(buf);
+
+               ASSERT_STREQ(buf, link_type_name, "exp_str_value");
+       }
+
+cleanup:
+       btf__free(btf);
+}
+
+/*
+ * Test case to check that all bpf_map_type variants are covered by
+ * libbpf_bpf_map_type_str.
+ */
+static void test_libbpf_bpf_map_type_str(void)
+{
+       struct btf *btf;
+       const struct btf_type *t;
+       const struct btf_enum *e;
+       int i, n, id;
+
+       btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
+       if (!ASSERT_OK_PTR(btf, "btf_parse"))
+               return;
+
+       /* find enum bpf_map_type and enumerate each value */
+       id = btf__find_by_name_kind(btf, "bpf_map_type", BTF_KIND_ENUM);
+       if (!ASSERT_GT(id, 0, "bpf_map_type_id"))
+               goto cleanup;
+       t = btf__type_by_id(btf, id);
+       e = btf_enum(t);
+       n = btf_vlen(t);
+       for (i = 0; i < n; e++, i++) {
+               enum bpf_map_type map_type = (enum bpf_map_type)e->val;
+               const char *map_type_name;
+               const char *map_type_str;
+               char buf[256];
+
+               map_type_name = btf__str_by_offset(btf, e->name_off);
+               map_type_str = libbpf_bpf_map_type_str(map_type);
+               ASSERT_OK_PTR(map_type_str, map_type_name);
+
+               snprintf(buf, sizeof(buf), "BPF_MAP_TYPE_%s", map_type_str);
+               uppercase(buf);
+
+               ASSERT_STREQ(buf, map_type_name, "exp_str_value");
+       }
+
+cleanup:
+       btf__free(btf);
+}
+
+/*
+ * Test case to check that all bpf_prog_type variants are covered by
+ * libbpf_bpf_prog_type_str.
+ */
+static void test_libbpf_bpf_prog_type_str(void)
+{
+       struct btf *btf;
+       const struct btf_type *t;
+       const struct btf_enum *e;
+       int i, n, id;
+
+       btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
+       if (!ASSERT_OK_PTR(btf, "btf_parse"))
+               return;
+
+       /* find enum bpf_prog_type and enumerate each value */
+       id = btf__find_by_name_kind(btf, "bpf_prog_type", BTF_KIND_ENUM);
+       if (!ASSERT_GT(id, 0, "bpf_prog_type_id"))
+               goto cleanup;
+       t = btf__type_by_id(btf, id);
+       e = btf_enum(t);
+       n = btf_vlen(t);
+       for (i = 0; i < n; e++, i++) {
+               enum bpf_prog_type prog_type = (enum bpf_prog_type)e->val;
+               const char *prog_type_name;
+               const char *prog_type_str;
+               char buf[256];
+
+               prog_type_name = btf__str_by_offset(btf, e->name_off);
+               prog_type_str = libbpf_bpf_prog_type_str(prog_type);
+               ASSERT_OK_PTR(prog_type_str, prog_type_name);
+
+               snprintf(buf, sizeof(buf), "BPF_PROG_TYPE_%s", prog_type_str);
+               uppercase(buf);
+
+               ASSERT_STREQ(buf, prog_type_name, "exp_str_value");
+       }
+
+cleanup:
+       btf__free(btf);
+}
+
+/*
+ * Run all libbpf str conversion tests.
+ */
+void test_libbpf_str(void)
+{
+       if (test__start_subtest("bpf_attach_type_str"))
+               test_libbpf_bpf_attach_type_str();
+
+       if (test__start_subtest("bpf_link_type_str"))
+               test_libbpf_bpf_link_type_str();
+
+       if (test__start_subtest("bpf_map_type_str"))
+               test_libbpf_bpf_map_type_str();
+
+       if (test__start_subtest("bpf_prog_type_str"))
+               test_libbpf_bpf_prog_type_str();
+}
index 958dae7..cb6a53b 100644 (file)
@@ -646,7 +646,7 @@ static void test_tcp_clear_dtime(struct test_tc_dtime *skel)
        __u32 *errs = skel->bss->errs[t];
 
        skel->bss->test = t;
-       test_inet_dtime(AF_INET6, SOCK_STREAM, IP6_DST, 0);
+       test_inet_dtime(AF_INET6, SOCK_STREAM, IP6_DST, 50000 + t);
 
        ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
                  dtime_cnt_str(t, INGRESS_FWDNS_P100));
@@ -683,7 +683,7 @@ static void test_tcp_dtime(struct test_tc_dtime *skel, int family, bool bpf_fwd)
        errs = skel->bss->errs[t];
 
        skel->bss->test = t;
-       test_inet_dtime(family, SOCK_STREAM, addr, 0);
+       test_inet_dtime(family, SOCK_STREAM, addr, 50000 + t);
 
        /* fwdns_prio100 prog does not read delivery_time_type, so
         * kernel puts the (rcv) timetamp in __sk_buff->tstamp
@@ -715,13 +715,13 @@ static void test_udp_dtime(struct test_tc_dtime *skel, int family, bool bpf_fwd)
        errs = skel->bss->errs[t];
 
        skel->bss->test = t;
-       test_inet_dtime(family, SOCK_DGRAM, addr, 0);
+       test_inet_dtime(family, SOCK_DGRAM, addr, 50000 + t);
 
        ASSERT_EQ(dtimes[INGRESS_FWDNS_P100], 0,
                  dtime_cnt_str(t, INGRESS_FWDNS_P100));
        /* non mono delivery time is not forwarded */
        ASSERT_EQ(dtimes[INGRESS_FWDNS_P101], 0,
-                 dtime_cnt_str(t, INGRESS_FWDNS_P100));
+                 dtime_cnt_str(t, INGRESS_FWDNS_P101));
        for (i = EGRESS_FWDNS_P100; i < SET_DTIME; i++)
                ASSERT_GT(dtimes[i], 0, dtime_cnt_str(t, i));
 
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c b/tools/testing/selftests/bpf/prog_tests/xdp_synproxy.c
new file mode 100644 (file)
index 0000000..fb77a12
--- /dev/null
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#define _GNU_SOURCE
+#include <test_progs.h>
+#include <network_helpers.h>
+#include <ctype.h>
+
+#define CMD_OUT_BUF_SIZE 1023
+
+#define SYS(cmd) ({ \
+       if (!ASSERT_OK(system(cmd), (cmd))) \
+               goto out; \
+})
+
+#define SYS_OUT(cmd, ...) ({ \
+       char buf[1024]; \
+       snprintf(buf, sizeof(buf), (cmd), ##__VA_ARGS__); \
+       FILE *f = popen(buf, "r"); \
+       if (!ASSERT_OK_PTR(f, buf)) \
+               goto out; \
+       f; \
+})
+
+/* out must be at least `size * 4 + 1` bytes long */
+static void escape_str(char *out, const char *in, size_t size)
+{
+       static const char *hex = "0123456789ABCDEF";
+       size_t i;
+
+       for (i = 0; i < size; i++) {
+               if (isprint(in[i]) && in[i] != '\\' && in[i] != '\'') {
+                       *out++ = in[i];
+               } else {
+                       *out++ = '\\';
+                       *out++ = 'x';
+                       *out++ = hex[(in[i] >> 4) & 0xf];
+                       *out++ = hex[in[i] & 0xf];
+               }
+       }
+       *out++ = '\0';
+}
+
+static bool expect_str(char *buf, size_t size, const char *str, const char *name)
+{
+       static char escbuf_expected[CMD_OUT_BUF_SIZE * 4];
+       static char escbuf_actual[CMD_OUT_BUF_SIZE * 4];
+       static int duration = 0;
+       bool ok;
+
+       ok = size == strlen(str) && !memcmp(buf, str, size);
+
+       if (!ok) {
+               escape_str(escbuf_expected, str, strlen(str));
+               escape_str(escbuf_actual, buf, size);
+       }
+       CHECK(!ok, name, "unexpected %s: actual '%s' != expected '%s'\n",
+             name, escbuf_actual, escbuf_expected);
+
+       return ok;
+}
+
+static void test_synproxy(bool xdp)
+{
+       int server_fd = -1, client_fd = -1, accept_fd = -1;
+       char *prog_id, *prog_id_end;
+       struct nstoken *ns = NULL;
+       FILE *ctrl_file = NULL;
+       char buf[CMD_OUT_BUF_SIZE];
+       size_t size;
+
+       SYS("ip netns add synproxy");
+
+       SYS("ip link add tmp0 type veth peer name tmp1");
+       SYS("ip link set tmp1 netns synproxy");
+       SYS("ip link set tmp0 up");
+       SYS("ip addr replace 198.18.0.1/24 dev tmp0");
+
+       /* When checksum offload is enabled, the XDP program sees wrong
+        * checksums and drops packets.
+        */
+       SYS("ethtool -K tmp0 tx off");
+       if (xdp)
+               /* Workaround required for veth. */
+               SYS("ip link set tmp0 xdp object xdp_dummy.o section xdp 2> /dev/null");
+
+       ns = open_netns("synproxy");
+       if (!ASSERT_OK_PTR(ns, "setns"))
+               goto out;
+
+       SYS("ip link set lo up");
+       SYS("ip link set tmp1 up");
+       SYS("ip addr replace 198.18.0.2/24 dev tmp1");
+       SYS("sysctl -w net.ipv4.tcp_syncookies=2");
+       SYS("sysctl -w net.ipv4.tcp_timestamps=1");
+       SYS("sysctl -w net.netfilter.nf_conntrack_tcp_loose=0");
+       SYS("iptables -t raw -I PREROUTING \
+           -i tmp1 -p tcp -m tcp --syn --dport 8080 -j CT --notrack");
+       SYS("iptables -t filter -A INPUT \
+           -i tmp1 -p tcp -m tcp --dport 8080 -m state --state INVALID,UNTRACKED \
+           -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460");
+       SYS("iptables -t filter -A INPUT \
+           -i tmp1 -m state --state INVALID -j DROP");
+
+       ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --ports 8080 \
+                           --single --mss4 1460 --mss6 1440 \
+                           --wscale 7 --ttl 64%s", xdp ? "" : " --tc");
+       size = fread(buf, 1, sizeof(buf), ctrl_file);
+       pclose(ctrl_file);
+       if (!expect_str(buf, size, "Total SYNACKs generated: 0\n",
+                       "initial SYNACKs"))
+               goto out;
+
+       if (!xdp) {
+               ctrl_file = SYS_OUT("tc filter show dev tmp1 ingress");
+               size = fread(buf, 1, sizeof(buf), ctrl_file);
+               pclose(ctrl_file);
+               prog_id = memmem(buf, size, " id ", 4);
+               if (!ASSERT_OK_PTR(prog_id, "find prog id"))
+                       goto out;
+               prog_id += 4;
+               if (!ASSERT_LT(prog_id, buf + size, "find prog id begin"))
+                       goto out;
+               prog_id_end = prog_id;
+               while (prog_id_end < buf + size && *prog_id_end >= '0' &&
+                      *prog_id_end <= '9')
+                       prog_id_end++;
+               if (!ASSERT_LT(prog_id_end, buf + size, "find prog id end"))
+                       goto out;
+               *prog_id_end = '\0';
+       }
+
+       server_fd = start_server(AF_INET, SOCK_STREAM, "198.18.0.2", 8080, 0);
+       if (!ASSERT_GE(server_fd, 0, "start_server"))
+               goto out;
+
+       close_netns(ns);
+       ns = NULL;
+
+       client_fd = connect_to_fd(server_fd, 10000);
+       if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
+               goto out;
+
+       accept_fd = accept(server_fd, NULL, NULL);
+       if (!ASSERT_GE(accept_fd, 0, "accept"))
+               goto out;
+
+       ns = open_netns("synproxy");
+       if (!ASSERT_OK_PTR(ns, "setns"))
+               goto out;
+
+       if (xdp)
+               ctrl_file = SYS_OUT("./xdp_synproxy --iface tmp1 --single");
+       else
+               ctrl_file = SYS_OUT("./xdp_synproxy --prog %s --single",
+                                   prog_id);
+       size = fread(buf, 1, sizeof(buf), ctrl_file);
+       pclose(ctrl_file);
+       if (!expect_str(buf, size, "Total SYNACKs generated: 1\n",
+                       "SYNACKs after connection"))
+               goto out;
+
+out:
+       if (accept_fd >= 0)
+               close(accept_fd);
+       if (client_fd >= 0)
+               close(client_fd);
+       if (server_fd >= 0)
+               close(server_fd);
+       if (ns)
+               close_netns(ns);
+
+       system("ip link del tmp0");
+       system("ip netns del synproxy");
+}
+
+void test_xdp_synproxy(void)
+{
+       if (test__start_subtest("xdp"))
+               test_synproxy(true);
+       if (test__start_subtest("tc"))
+               test_synproxy(false);
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_hashmap_full_update_bench.c b/tools/testing/selftests/bpf/progs/bpf_hashmap_full_update_bench.c
new file mode 100644 (file)
index 0000000..5695755
--- /dev/null
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Bytedance */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+char _license[] SEC("license") = "GPL";
+
+#define MAX_ENTRIES 1000
+
+struct {
+       __uint(type, BPF_MAP_TYPE_HASH);
+       __type(key, u32);
+       __type(value, u64);
+       __uint(max_entries, MAX_ENTRIES);
+} hash_map_bench SEC(".maps");
+
+u64 __attribute__((__aligned__(256))) percpu_time[256];
+u64 nr_loops;
+
+static int loop_update_callback(__u32 index, u32 *key)
+{
+       u64 init_val = 1;
+
+       bpf_map_update_elem(&hash_map_bench, key, &init_val, BPF_ANY);
+       return 0;
+}
+
+SEC("fentry/" SYS_PREFIX "sys_getpgid")
+int benchmark(void *ctx)
+{
+       u32 cpu = bpf_get_smp_processor_id();
+       u32 key = cpu + MAX_ENTRIES;
+       u64 start_time = bpf_ktime_get_ns();
+
+       bpf_loop(nr_loops, loop_update_callback, &key, 0);
+       percpu_time[cpu & 255] = bpf_ktime_get_ns() - start_time;
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val.c
new file mode 100644 (file)
index 0000000..888e79d
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enum64val x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___diff.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___diff.c
new file mode 100644 (file)
index 0000000..1947491
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enum64val___diff x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___err_missing.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___err_missing.c
new file mode 100644 (file)
index 0000000..3d732d4
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enum64val___err_missing x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___val3_missing.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enum64val___val3_missing.c
new file mode 100644 (file)
index 0000000..17cf5d6
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enum64val___val3_missing x) {}
index f9dc976..26e1033 100644 (file)
@@ -1117,6 +1117,20 @@ struct core_reloc_enumval_output {
        int anon_val2;
 };
 
+struct core_reloc_enum64val_output {
+       bool unsigned_val1_exists;
+       bool unsigned_val2_exists;
+       bool unsigned_val3_exists;
+       bool signed_val1_exists;
+       bool signed_val2_exists;
+       bool signed_val3_exists;
+
+       long unsigned_val1;
+       long unsigned_val2;
+       long signed_val1;
+       long signed_val2;
+};
+
 enum named_enum {
        NAMED_ENUM_VAL1 = 1,
        NAMED_ENUM_VAL2 = 2,
@@ -1134,6 +1148,23 @@ struct core_reloc_enumval {
        anon_enum f2;
 };
 
+enum named_unsigned_enum64 {
+       UNSIGNED_ENUM64_VAL1 = 0x1ffffffffULL,
+       UNSIGNED_ENUM64_VAL2 = 0x2,
+       UNSIGNED_ENUM64_VAL3 = 0x3ffffffffULL,
+};
+
+enum named_signed_enum64 {
+       SIGNED_ENUM64_VAL1 = 0x1ffffffffLL,
+       SIGNED_ENUM64_VAL2 = -2,
+       SIGNED_ENUM64_VAL3 = 0x3ffffffffLL,
+};
+
+struct core_reloc_enum64val {
+       enum named_unsigned_enum64 f1;
+       enum named_signed_enum64 f2;
+};
+
 /* differing enumerator values */
 enum named_enum___diff {
        NAMED_ENUM_VAL1___diff = 101,
@@ -1152,6 +1183,23 @@ struct core_reloc_enumval___diff {
        anon_enum___diff f2;
 };
 
+enum named_unsigned_enum64___diff {
+       UNSIGNED_ENUM64_VAL1___diff = 0x101ffffffffULL,
+       UNSIGNED_ENUM64_VAL2___diff = 0x202ffffffffULL,
+       UNSIGNED_ENUM64_VAL3___diff = 0x303ffffffffULL,
+};
+
+enum named_signed_enum64___diff {
+       SIGNED_ENUM64_VAL1___diff = -101,
+       SIGNED_ENUM64_VAL2___diff = -202,
+       SIGNED_ENUM64_VAL3___diff = -303,
+};
+
+struct core_reloc_enum64val___diff {
+       enum named_unsigned_enum64___diff f1;
+       enum named_signed_enum64___diff f2;
+};
+
 /* missing (optional) third enum value */
 enum named_enum___val3_missing {
        NAMED_ENUM_VAL1___val3_missing = 111,
@@ -1168,6 +1216,21 @@ struct core_reloc_enumval___val3_missing {
        anon_enum___val3_missing f2;
 };
 
+enum named_unsigned_enum64___val3_missing {
+       UNSIGNED_ENUM64_VAL1___val3_missing = 0x111ffffffffULL,
+       UNSIGNED_ENUM64_VAL2___val3_missing = 0x222,
+};
+
+enum named_signed_enum64___val3_missing {
+       SIGNED_ENUM64_VAL1___val3_missing = 0x111ffffffffLL,
+       SIGNED_ENUM64_VAL2___val3_missing = -222,
+};
+
+struct core_reloc_enum64val___val3_missing {
+       enum named_unsigned_enum64___val3_missing f1;
+       enum named_signed_enum64___val3_missing f2;
+};
+
 /* missing (mandatory) second enum value, should fail */
 enum named_enum___err_missing {
        NAMED_ENUM_VAL1___err_missing = 1,
@@ -1183,3 +1246,18 @@ struct core_reloc_enumval___err_missing {
        enum named_enum___err_missing f1;
        anon_enum___err_missing f2;
 };
+
+enum named_unsigned_enum64___err_missing {
+       UNSIGNED_ENUM64_VAL1___err_missing = 0x1ffffffffULL,
+       UNSIGNED_ENUM64_VAL3___err_missing = 0x3ffffffffULL,
+};
+
+enum named_signed_enum64___err_missing {
+       SIGNED_ENUM64_VAL1___err_missing = 0x1ffffffffLL,
+       SIGNED_ENUM64_VAL3___err_missing = -3,
+};
+
+struct core_reloc_enum64val___err_missing {
+       enum named_unsigned_enum64___err_missing f1;
+       enum named_signed_enum64___err_missing f2;
+};
index ce9acf4..f1c88ad 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/bpf.h>
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_tracing.h>
+#include <stdbool.h>
 #include "bpf_misc.h"
 
 int kprobe_res = 0;
@@ -17,6 +18,11 @@ int uprobe_byname_res = 0;
 int uretprobe_byname_res = 0;
 int uprobe_byname2_res = 0;
 int uretprobe_byname2_res = 0;
+int uprobe_byname3_sleepable_res = 0;
+int uprobe_byname3_res = 0;
+int uretprobe_byname3_sleepable_res = 0;
+int uretprobe_byname3_res = 0;
+void *user_ptr = 0;
 
 SEC("kprobe")
 int handle_kprobe(struct pt_regs *ctx)
@@ -32,6 +38,17 @@ int BPF_KPROBE(handle_kprobe_auto)
        return 0;
 }
 
+/**
+ * This program will be manually made sleepable on the userspace side
+ * and should thus be unattachable.
+ */
+SEC("kprobe/" SYS_PREFIX "sys_nanosleep")
+int handle_kprobe_sleepable(struct pt_regs *ctx)
+{
+       kprobe_res = 2;
+       return 0;
+}
+
 SEC("kretprobe")
 int handle_kretprobe(struct pt_regs *ctx)
 {
@@ -93,4 +110,47 @@ int handle_uretprobe_byname2(struct pt_regs *ctx)
        return 0;
 }
 
+static __always_inline bool verify_sleepable_user_copy(void)
+{
+       char data[9];
+
+       bpf_copy_from_user(data, sizeof(data), user_ptr);
+       return bpf_strncmp(data, sizeof(data), "test_data") == 0;
+}
+
+SEC("uprobe.s//proc/self/exe:trigger_func3")
+int handle_uprobe_byname3_sleepable(struct pt_regs *ctx)
+{
+       if (verify_sleepable_user_copy())
+               uprobe_byname3_sleepable_res = 9;
+       return 0;
+}
+
+/**
+ * same target as the uprobe.s above to force sleepable and non-sleepable
+ * programs in the same bpf_prog_array
+ */
+SEC("uprobe//proc/self/exe:trigger_func3")
+int handle_uprobe_byname3(struct pt_regs *ctx)
+{
+       uprobe_byname3_res = 10;
+       return 0;
+}
+
+SEC("uretprobe.s//proc/self/exe:trigger_func3")
+int handle_uretprobe_byname3_sleepable(struct pt_regs *ctx)
+{
+       if (verify_sleepable_user_copy())
+               uretprobe_byname3_sleepable_res = 11;
+       return 0;
+}
+
+SEC("uretprobe//proc/self/exe:trigger_func3")
+int handle_uretprobe_byname3(struct pt_regs *ctx)
+{
+       uretprobe_byname3_res = 12;
+       return 0;
+}
+
+
 char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_enum64val.c b/tools/testing/selftests/bpf/progs/test_core_reloc_enum64val.c
new file mode 100644 (file)
index 0000000..63147fb
--- /dev/null
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+       char in[256];
+       char out[256];
+       bool skip;
+} data = {};
+
+enum named_unsigned_enum64 {
+       UNSIGNED_ENUM64_VAL1 = 0x1ffffffffULL,
+       UNSIGNED_ENUM64_VAL2 = 0x2ffffffffULL,
+       UNSIGNED_ENUM64_VAL3 = 0x3ffffffffULL,
+};
+
+enum named_signed_enum64 {
+       SIGNED_ENUM64_VAL1 = 0x1ffffffffLL,
+       SIGNED_ENUM64_VAL2 = -2,
+       SIGNED_ENUM64_VAL3 = 0x3ffffffffLL,
+};
+
+struct core_reloc_enum64val_output {
+       bool unsigned_val1_exists;
+       bool unsigned_val2_exists;
+       bool unsigned_val3_exists;
+       bool signed_val1_exists;
+       bool signed_val2_exists;
+       bool signed_val3_exists;
+
+       long unsigned_val1;
+       long unsigned_val2;
+       long signed_val1;
+       long signed_val2;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_enum64val(void *ctx)
+{
+#if __clang_major__ >= 15
+       struct core_reloc_enum64val_output *out = (void *)&data.out;
+       enum named_unsigned_enum64 named_unsigned = 0;
+       enum named_signed_enum64 named_signed = 0;
+
+       out->unsigned_val1_exists = bpf_core_enum_value_exists(named_unsigned, UNSIGNED_ENUM64_VAL1);
+       out->unsigned_val2_exists = bpf_core_enum_value_exists(enum named_unsigned_enum64, UNSIGNED_ENUM64_VAL2);
+       out->unsigned_val3_exists = bpf_core_enum_value_exists(enum named_unsigned_enum64, UNSIGNED_ENUM64_VAL3);
+       out->signed_val1_exists = bpf_core_enum_value_exists(named_signed, SIGNED_ENUM64_VAL1);
+       out->signed_val2_exists = bpf_core_enum_value_exists(enum named_signed_enum64, SIGNED_ENUM64_VAL2);
+       out->signed_val3_exists = bpf_core_enum_value_exists(enum named_signed_enum64, SIGNED_ENUM64_VAL3);
+
+       out->unsigned_val1 = bpf_core_enum_value(named_unsigned, UNSIGNED_ENUM64_VAL1);
+       out->unsigned_val2 = bpf_core_enum_value(named_unsigned, UNSIGNED_ENUM64_VAL2);
+       out->signed_val1 = bpf_core_enum_value(named_signed, SIGNED_ENUM64_VAL1);
+       out->signed_val2 = bpf_core_enum_value(named_signed, SIGNED_ENUM64_VAL2);
+       /* NAMED_ENUM64_VAL3 value is optional */
+
+#else
+       data.skip = true;
+#endif
+
+       return 0;
+}
index 06f300d..b596479 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 #include <bpf/bpf_helpers.h>
 #include <bpf/bpf_endian.h>
 #include <sys/socket.h>
@@ -115,6 +117,19 @@ static bool bpf_fwd(void)
        return test < TCP_IP4_RT_FWD;
 }
 
+static __u8 get_proto(void)
+{
+       switch (test) {
+       case UDP_IP4:
+       case UDP_IP6:
+       case UDP_IP4_RT_FWD:
+       case UDP_IP6_RT_FWD:
+               return IPPROTO_UDP;
+       default:
+               return IPPROTO_TCP;
+       }
+}
+
 /* -1: parse error: TC_ACT_SHOT
  *  0: not testing traffic: TC_ACT_OK
  * >0: first byte is the inet_proto, second byte has the netns
@@ -122,11 +137,16 @@ static bool bpf_fwd(void)
  */
 static int skb_get_type(struct __sk_buff *skb)
 {
+       __u16 dst_ns_port = __bpf_htons(50000 + test);
        void *data_end = ctx_ptr(skb->data_end);
        void *data = ctx_ptr(skb->data);
        __u8 inet_proto = 0, ns = 0;
        struct ipv6hdr *ip6h;
+       __u16 sport, dport;
        struct iphdr *iph;
+       struct tcphdr *th;
+       struct udphdr *uh;
+       void *trans;
 
        switch (skb->protocol) {
        case __bpf_htons(ETH_P_IP):
@@ -138,6 +158,7 @@ static int skb_get_type(struct __sk_buff *skb)
                else if (iph->saddr == ip4_dst)
                        ns = DST_NS;
                inet_proto = iph->protocol;
+               trans = iph + 1;
                break;
        case __bpf_htons(ETH_P_IPV6):
                ip6h = data + sizeof(struct ethhdr);
@@ -148,15 +169,43 @@ static int skb_get_type(struct __sk_buff *skb)
                else if (v6_equal(ip6h->saddr, (struct in6_addr)ip6_dst))
                        ns = DST_NS;
                inet_proto = ip6h->nexthdr;
+               trans = ip6h + 1;
                break;
        default:
                return 0;
        }
 
-       if ((inet_proto != IPPROTO_TCP && inet_proto != IPPROTO_UDP) || !ns)
+       /* skb is not from src_ns or dst_ns.
+        * skb is not the testing IPPROTO.
+        */
+       if (!ns || inet_proto != get_proto())
                return 0;
 
-       return (ns << 8 | inet_proto);
+       switch (inet_proto) {
+       case IPPROTO_TCP:
+               th = trans;
+               if (th + 1 > data_end)
+                       return -1;
+               sport = th->source;
+               dport = th->dest;
+               break;
+       case IPPROTO_UDP:
+               uh = trans;
+               if (uh + 1 > data_end)
+                       return -1;
+               sport = uh->source;
+               dport = uh->dest;
+               break;
+       default:
+               return 0;
+       }
+
+       /* The skb is the testing traffic */
+       if ((ns == SRC_NS && dport == dst_ns_port) ||
+           (ns == DST_NS && sport == dst_ns_port))
+               return (ns << 8 | inet_proto);
+
+       return 0;
 }
 
 /* format: direction@iface@netns
index 913acdf..3987ff1 100644 (file)
@@ -41,20 +41,20 @@ int handler64_unsigned(void *regs)
 {
        int pid = bpf_get_current_pid_tgid() >> 32;
        void *payload = payload1;
-       u64 len;
+       long len;
 
        /* ignore irrelevant invocations */
        if (test_pid != pid || !capture)
                return 0;
 
        len = bpf_probe_read_kernel_str(payload, MAX_LEN, &buf_in1[0]);
-       if (len <= MAX_LEN) {
+       if (len >= 0) {
                payload += len;
                payload1_len1 = len;
        }
 
        len = bpf_probe_read_kernel_str(payload, MAX_LEN, &buf_in2[0]);
-       if (len <= MAX_LEN) {
+       if (len >= 0) {
                payload += len;
                payload1_len2 = len;
        }
@@ -123,7 +123,7 @@ int handler32_signed(void *regs)
 {
        int pid = bpf_get_current_pid_tgid() >> 32;
        void *payload = payload4;
-       int len;
+       long len;
 
        /* ignore irrelevant invocations */
        if (test_pid != pid || !capture)
diff --git a/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c b/tools/testing/selftests/bpf/progs/xdp_synproxy_kern.c
new file mode 100644 (file)
index 0000000..9fd62e9
--- /dev/null
@@ -0,0 +1,833 @@
+// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include "vmlinux.h"
+
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+#include <asm/errno.h>
+
+#define TC_ACT_OK 0
+#define TC_ACT_SHOT 2
+
+#define NSEC_PER_SEC 1000000000L
+
+#define ETH_ALEN 6
+#define ETH_P_IP 0x0800
+#define ETH_P_IPV6 0x86DD
+
+#define tcp_flag_word(tp) (((union tcp_word_hdr *)(tp))->words[3])
+
+#define IP_DF 0x4000
+#define IP_MF 0x2000
+#define IP_OFFSET 0x1fff
+
+#define NEXTHDR_TCP 6
+
+#define TCPOPT_NOP 1
+#define TCPOPT_EOL 0
+#define TCPOPT_MSS 2
+#define TCPOPT_WINDOW 3
+#define TCPOPT_SACK_PERM 4
+#define TCPOPT_TIMESTAMP 8
+
+#define TCPOLEN_MSS 4
+#define TCPOLEN_WINDOW 3
+#define TCPOLEN_SACK_PERM 2
+#define TCPOLEN_TIMESTAMP 10
+
+#define TCP_TS_HZ 1000
+#define TS_OPT_WSCALE_MASK 0xf
+#define TS_OPT_SACK (1 << 4)
+#define TS_OPT_ECN (1 << 5)
+#define TSBITS 6
+#define TSMASK (((__u32)1 << TSBITS) - 1)
+#define TCP_MAX_WSCALE 14U
+
+#define IPV4_MAXLEN 60
+#define TCP_MAXLEN 60
+
+#define DEFAULT_MSS4 1460
+#define DEFAULT_MSS6 1440
+#define DEFAULT_WSCALE 7
+#define DEFAULT_TTL 64
+#define MAX_ALLOWED_PORTS 8
+
+#define swap(a, b) \
+       do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
+
+#define __get_unaligned_t(type, ptr) ({                                                \
+       const struct { type x; } __attribute__((__packed__)) *__pptr = (typeof(__pptr))(ptr); \
+       __pptr->x;                                                              \
+})
+
+#define get_unaligned(ptr) __get_unaligned_t(typeof(*(ptr)), (ptr))
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __type(key, __u32);
+       __type(value, __u64);
+       __uint(max_entries, 2);
+} values SEC(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __type(key, __u32);
+       __type(value, __u16);
+       __uint(max_entries, MAX_ALLOWED_PORTS);
+} allowed_ports SEC(".maps");
+
+extern struct nf_conn *bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx,
+                                        struct bpf_sock_tuple *bpf_tuple,
+                                        __u32 len_tuple,
+                                        struct bpf_ct_opts *opts,
+                                        __u32 len_opts) __ksym;
+
+extern struct nf_conn *bpf_skb_ct_lookup(struct __sk_buff *skb_ctx,
+                                        struct bpf_sock_tuple *bpf_tuple,
+                                        u32 len_tuple,
+                                        struct bpf_ct_opts *opts,
+                                        u32 len_opts) __ksym;
+
+extern void bpf_ct_release(struct nf_conn *ct) __ksym;
+
+static __always_inline void swap_eth_addr(__u8 *a, __u8 *b)
+{
+       __u8 tmp[ETH_ALEN];
+
+       __builtin_memcpy(tmp, a, ETH_ALEN);
+       __builtin_memcpy(a, b, ETH_ALEN);
+       __builtin_memcpy(b, tmp, ETH_ALEN);
+}
+
+static __always_inline __u16 csum_fold(__u32 csum)
+{
+       csum = (csum & 0xffff) + (csum >> 16);
+       csum = (csum & 0xffff) + (csum >> 16);
+       return (__u16)~csum;
+}
+
+static __always_inline __u16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+                                              __u32 len, __u8 proto,
+                                              __u32 csum)
+{
+       __u64 s = csum;
+
+       s += (__u32)saddr;
+       s += (__u32)daddr;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+       s += proto + len;
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+       s += (proto + len) << 8;
+#else
+#error Unknown endian
+#endif
+       s = (s & 0xffffffff) + (s >> 32);
+       s = (s & 0xffffffff) + (s >> 32);
+
+       return csum_fold((__u32)s);
+}
+
+static __always_inline __u16 csum_ipv6_magic(const struct in6_addr *saddr,
+                                            const struct in6_addr *daddr,
+                                            __u32 len, __u8 proto, __u32 csum)
+{
+       __u64 sum = csum;
+       int i;
+
+#pragma unroll
+       for (i = 0; i < 4; i++)
+               sum += (__u32)saddr->in6_u.u6_addr32[i];
+
+#pragma unroll
+       for (i = 0; i < 4; i++)
+               sum += (__u32)daddr->in6_u.u6_addr32[i];
+
+       /* Don't combine additions to avoid 32-bit overflow. */
+       sum += bpf_htonl(len);
+       sum += bpf_htonl(proto);
+
+       sum = (sum & 0xffffffff) + (sum >> 32);
+       sum = (sum & 0xffffffff) + (sum >> 32);
+
+       return csum_fold((__u32)sum);
+}
+
+static __always_inline __u64 tcp_clock_ns(void)
+{
+       return bpf_ktime_get_ns();
+}
+
+static __always_inline __u32 tcp_ns_to_ts(__u64 ns)
+{
+       return ns / (NSEC_PER_SEC / TCP_TS_HZ);
+}
+
+static __always_inline __u32 tcp_time_stamp_raw(void)
+{
+       return tcp_ns_to_ts(tcp_clock_ns());
+}
+
+struct tcpopt_context {
+       __u8 *ptr;
+       __u8 *end;
+       void *data_end;
+       __be32 *tsecr;
+       __u8 wscale;
+       bool option_timestamp;
+       bool option_sack;
+};
+
+static int tscookie_tcpopt_parse(struct tcpopt_context *ctx)
+{
+       __u8 opcode, opsize;
+
+       if (ctx->ptr >= ctx->end)
+               return 1;
+       if (ctx->ptr >= ctx->data_end)
+               return 1;
+
+       opcode = ctx->ptr[0];
+
+       if (opcode == TCPOPT_EOL)
+               return 1;
+       if (opcode == TCPOPT_NOP) {
+               ++ctx->ptr;
+               return 0;
+       }
+
+       if (ctx->ptr + 1 >= ctx->end)
+               return 1;
+       if (ctx->ptr + 1 >= ctx->data_end)
+               return 1;
+       opsize = ctx->ptr[1];
+       if (opsize < 2)
+               return 1;
+
+       if (ctx->ptr + opsize > ctx->end)
+               return 1;
+
+       switch (opcode) {
+       case TCPOPT_WINDOW:
+               if (opsize == TCPOLEN_WINDOW && ctx->ptr + TCPOLEN_WINDOW <= ctx->data_end)
+                       ctx->wscale = ctx->ptr[2] < TCP_MAX_WSCALE ? ctx->ptr[2] : TCP_MAX_WSCALE;
+               break;
+       case TCPOPT_TIMESTAMP:
+               if (opsize == TCPOLEN_TIMESTAMP && ctx->ptr + TCPOLEN_TIMESTAMP <= ctx->data_end) {
+                       ctx->option_timestamp = true;
+                       /* Client's tsval becomes our tsecr. */
+                       *ctx->tsecr = get_unaligned((__be32 *)(ctx->ptr + 2));
+               }
+               break;
+       case TCPOPT_SACK_PERM:
+               if (opsize == TCPOLEN_SACK_PERM)
+                       ctx->option_sack = true;
+               break;
+       }
+
+       ctx->ptr += opsize;
+
+       return 0;
+}
+
+static int tscookie_tcpopt_parse_batch(__u32 index, void *context)
+{
+       int i;
+
+       for (i = 0; i < 7; i++)
+               if (tscookie_tcpopt_parse(context))
+                       return 1;
+       return 0;
+}
+
+static __always_inline bool tscookie_init(struct tcphdr *tcp_header,
+                                         __u16 tcp_len, __be32 *tsval,
+                                         __be32 *tsecr, void *data_end)
+{
+       struct tcpopt_context loop_ctx = {
+               .ptr = (__u8 *)(tcp_header + 1),
+               .end = (__u8 *)tcp_header + tcp_len,
+               .data_end = data_end,
+               .tsecr = tsecr,
+               .wscale = TS_OPT_WSCALE_MASK,
+               .option_timestamp = false,
+               .option_sack = false,
+       };
+       u32 cookie;
+
+       bpf_loop(6, tscookie_tcpopt_parse_batch, &loop_ctx, 0);
+
+       if (!loop_ctx.option_timestamp)
+               return false;
+
+       cookie = tcp_time_stamp_raw() & ~TSMASK;
+       cookie |= loop_ctx.wscale & TS_OPT_WSCALE_MASK;
+       if (loop_ctx.option_sack)
+               cookie |= TS_OPT_SACK;
+       if (tcp_header->ece && tcp_header->cwr)
+               cookie |= TS_OPT_ECN;
+       *tsval = bpf_htonl(cookie);
+
+       return true;
+}
+
+static __always_inline void values_get_tcpipopts(__u16 *mss, __u8 *wscale,
+                                                __u8 *ttl, bool ipv6)
+{
+       __u32 key = 0;
+       __u64 *value;
+
+       value = bpf_map_lookup_elem(&values, &key);
+       if (value && *value != 0) {
+               if (ipv6)
+                       *mss = (*value >> 32) & 0xffff;
+               else
+                       *mss = *value & 0xffff;
+               *wscale = (*value >> 16) & 0xf;
+               *ttl = (*value >> 24) & 0xff;
+               return;
+       }
+
+       *mss = ipv6 ? DEFAULT_MSS6 : DEFAULT_MSS4;
+       *wscale = DEFAULT_WSCALE;
+       *ttl = DEFAULT_TTL;
+}
+
+static __always_inline void values_inc_synacks(void)
+{
+       __u32 key = 1;
+       __u32 *value;
+
+       value = bpf_map_lookup_elem(&values, &key);
+       if (value)
+               __sync_fetch_and_add(value, 1);
+}
+
+static __always_inline bool check_port_allowed(__u16 port)
+{
+       __u32 i;
+
+       for (i = 0; i < MAX_ALLOWED_PORTS; i++) {
+               __u32 key = i;
+               __u16 *value;
+
+               value = bpf_map_lookup_elem(&allowed_ports, &key);
+
+               if (!value)
+                       break;
+               /* 0 is a terminator value. Check it first to avoid matching on
+                * a forbidden port == 0 and returning true.
+                */
+               if (*value == 0)
+                       break;
+
+               if (*value == port)
+                       return true;
+       }
+
+       return false;
+}
+
+struct header_pointers {
+       struct ethhdr *eth;
+       struct iphdr *ipv4;
+       struct ipv6hdr *ipv6;
+       struct tcphdr *tcp;
+       __u16 tcp_len;
+};
+
+static __always_inline int tcp_dissect(void *data, void *data_end,
+                                      struct header_pointers *hdr)
+{
+       hdr->eth = data;
+       if (hdr->eth + 1 > data_end)
+               return XDP_DROP;
+
+       switch (bpf_ntohs(hdr->eth->h_proto)) {
+       case ETH_P_IP:
+               hdr->ipv6 = NULL;
+
+               hdr->ipv4 = (void *)hdr->eth + sizeof(*hdr->eth);
+               if (hdr->ipv4 + 1 > data_end)
+                       return XDP_DROP;
+               if (hdr->ipv4->ihl * 4 < sizeof(*hdr->ipv4))
+                       return XDP_DROP;
+               if (hdr->ipv4->version != 4)
+                       return XDP_DROP;
+
+               if (hdr->ipv4->protocol != IPPROTO_TCP)
+                       return XDP_PASS;
+
+               hdr->tcp = (void *)hdr->ipv4 + hdr->ipv4->ihl * 4;
+               break;
+       case ETH_P_IPV6:
+               hdr->ipv4 = NULL;
+
+               hdr->ipv6 = (void *)hdr->eth + sizeof(*hdr->eth);
+               if (hdr->ipv6 + 1 > data_end)
+                       return XDP_DROP;
+               if (hdr->ipv6->version != 6)
+                       return XDP_DROP;
+
+               /* XXX: Extension headers are not supported and could circumvent
+                * XDP SYN flood protection.
+                */
+               if (hdr->ipv6->nexthdr != NEXTHDR_TCP)
+                       return XDP_PASS;
+
+               hdr->tcp = (void *)hdr->ipv6 + sizeof(*hdr->ipv6);
+               break;
+       default:
+               /* XXX: VLANs will circumvent XDP SYN flood protection. */
+               return XDP_PASS;
+       }
+
+       if (hdr->tcp + 1 > data_end)
+               return XDP_DROP;
+       hdr->tcp_len = hdr->tcp->doff * 4;
+       if (hdr->tcp_len < sizeof(*hdr->tcp))
+               return XDP_DROP;
+
+       return XDP_TX;
+}
+
+static __always_inline int tcp_lookup(void *ctx, struct header_pointers *hdr, bool xdp)
+{
+       struct bpf_ct_opts ct_lookup_opts = {
+               .netns_id = BPF_F_CURRENT_NETNS,
+               .l4proto = IPPROTO_TCP,
+       };
+       struct bpf_sock_tuple tup = {};
+       struct nf_conn *ct;
+       __u32 tup_size;
+
+       if (hdr->ipv4) {
+               /* TCP doesn't normally use fragments, and XDP can't reassemble
+                * them.
+                */
+               if ((hdr->ipv4->frag_off & bpf_htons(IP_DF | IP_MF | IP_OFFSET)) != bpf_htons(IP_DF))
+                       return XDP_DROP;
+
+               tup.ipv4.saddr = hdr->ipv4->saddr;
+               tup.ipv4.daddr = hdr->ipv4->daddr;
+               tup.ipv4.sport = hdr->tcp->source;
+               tup.ipv4.dport = hdr->tcp->dest;
+               tup_size = sizeof(tup.ipv4);
+       } else if (hdr->ipv6) {
+               __builtin_memcpy(tup.ipv6.saddr, &hdr->ipv6->saddr, sizeof(tup.ipv6.saddr));
+               __builtin_memcpy(tup.ipv6.daddr, &hdr->ipv6->daddr, sizeof(tup.ipv6.daddr));
+               tup.ipv6.sport = hdr->tcp->source;
+               tup.ipv6.dport = hdr->tcp->dest;
+               tup_size = sizeof(tup.ipv6);
+       } else {
+               /* The verifier can't track that either ipv4 or ipv6 is not
+                * NULL.
+                */
+               return XDP_ABORTED;
+       }
+       if (xdp)
+               ct = bpf_xdp_ct_lookup(ctx, &tup, tup_size, &ct_lookup_opts, sizeof(ct_lookup_opts));
+       else
+               ct = bpf_skb_ct_lookup(ctx, &tup, tup_size, &ct_lookup_opts, sizeof(ct_lookup_opts));
+       if (ct) {
+               unsigned long status = ct->status;
+
+               bpf_ct_release(ct);
+               if (status & IPS_CONFIRMED_BIT)
+                       return XDP_PASS;
+       } else if (ct_lookup_opts.error != -ENOENT) {
+               return XDP_ABORTED;
+       }
+
+       /* error == -ENOENT || !(status & IPS_CONFIRMED_BIT) */
+       return XDP_TX;
+}
+
+static __always_inline __u8 tcp_mkoptions(__be32 *buf, __be32 *tsopt, __u16 mss,
+                                         __u8 wscale)
+{
+       __be32 *start = buf;
+
+       *buf++ = bpf_htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
+
+       if (!tsopt)
+               return buf - start;
+
+       if (tsopt[0] & bpf_htonl(1 << 4))
+               *buf++ = bpf_htonl((TCPOPT_SACK_PERM << 24) |
+                                  (TCPOLEN_SACK_PERM << 16) |
+                                  (TCPOPT_TIMESTAMP << 8) |
+                                  TCPOLEN_TIMESTAMP);
+       else
+               *buf++ = bpf_htonl((TCPOPT_NOP << 24) |
+                                  (TCPOPT_NOP << 16) |
+                                  (TCPOPT_TIMESTAMP << 8) |
+                                  TCPOLEN_TIMESTAMP);
+       *buf++ = tsopt[0];
+       *buf++ = tsopt[1];
+
+       if ((tsopt[0] & bpf_htonl(0xf)) != bpf_htonl(0xf))
+               *buf++ = bpf_htonl((TCPOPT_NOP << 24) |
+                                  (TCPOPT_WINDOW << 16) |
+                                  (TCPOLEN_WINDOW << 8) |
+                                  wscale);
+
+       return buf - start;
+}
+
+static __always_inline void tcp_gen_synack(struct tcphdr *tcp_header,
+                                          __u32 cookie, __be32 *tsopt,
+                                          __u16 mss, __u8 wscale)
+{
+       void *tcp_options;
+
+       tcp_flag_word(tcp_header) = TCP_FLAG_SYN | TCP_FLAG_ACK;
+       if (tsopt && (tsopt[0] & bpf_htonl(1 << 5)))
+               tcp_flag_word(tcp_header) |= TCP_FLAG_ECE;
+       tcp_header->doff = 5; /* doff is part of tcp_flag_word. */
+       swap(tcp_header->source, tcp_header->dest);
+       tcp_header->ack_seq = bpf_htonl(bpf_ntohl(tcp_header->seq) + 1);
+       tcp_header->seq = bpf_htonl(cookie);
+       tcp_header->window = 0;
+       tcp_header->urg_ptr = 0;
+       tcp_header->check = 0; /* Calculate checksum later. */
+
+       tcp_options = (void *)(tcp_header + 1);
+       tcp_header->doff += tcp_mkoptions(tcp_options, tsopt, mss, wscale);
+}
+
+static __always_inline void tcpv4_gen_synack(struct header_pointers *hdr,
+                                            __u32 cookie, __be32 *tsopt)
+{
+       __u8 wscale;
+       __u16 mss;
+       __u8 ttl;
+
+       values_get_tcpipopts(&mss, &wscale, &ttl, false);
+
+       swap_eth_addr(hdr->eth->h_source, hdr->eth->h_dest);
+
+       swap(hdr->ipv4->saddr, hdr->ipv4->daddr);
+       hdr->ipv4->check = 0; /* Calculate checksum later. */
+       hdr->ipv4->tos = 0;
+       hdr->ipv4->id = 0;
+       hdr->ipv4->ttl = ttl;
+
+       tcp_gen_synack(hdr->tcp, cookie, tsopt, mss, wscale);
+
+       hdr->tcp_len = hdr->tcp->doff * 4;
+       hdr->ipv4->tot_len = bpf_htons(sizeof(*hdr->ipv4) + hdr->tcp_len);
+}
+
+static __always_inline void tcpv6_gen_synack(struct header_pointers *hdr,
+                                            __u32 cookie, __be32 *tsopt)
+{
+       __u8 wscale;
+       __u16 mss;
+       __u8 ttl;
+
+       values_get_tcpipopts(&mss, &wscale, &ttl, true);
+
+       swap_eth_addr(hdr->eth->h_source, hdr->eth->h_dest);
+
+       swap(hdr->ipv6->saddr, hdr->ipv6->daddr);
+       *(__be32 *)hdr->ipv6 = bpf_htonl(0x60000000);
+       hdr->ipv6->hop_limit = ttl;
+
+       tcp_gen_synack(hdr->tcp, cookie, tsopt, mss, wscale);
+
+       hdr->tcp_len = hdr->tcp->doff * 4;
+       hdr->ipv6->payload_len = bpf_htons(hdr->tcp_len);
+}
+
+static __always_inline int syncookie_handle_syn(struct header_pointers *hdr,
+                                               void *ctx,
+                                               void *data, void *data_end,
+                                               bool xdp)
+{
+       __u32 old_pkt_size, new_pkt_size;
+       /* Unlike clang 10, clang 11 and 12 generate code that doesn't pass the
+        * BPF verifier if tsopt is not volatile. Volatile forces it to store
+        * the pointer value and use it directly, otherwise tcp_mkoptions is
+        * (mis)compiled like this:
+        *   if (!tsopt)
+        *       return buf - start;
+        *   reg = stored_return_value_of_tscookie_init;
+        *   if (reg)
+        *       tsopt = tsopt_buf;
+        *   else
+        *       tsopt = NULL;
+        *   ...
+        *   *buf++ = tsopt[1];
+        * It creates a dead branch where tsopt is assigned NULL, but the
+        * verifier can't prove it's dead and blocks the program.
+        */
+       __be32 * volatile tsopt = NULL;
+       __be32 tsopt_buf[2] = {};
+       __u16 ip_len;
+       __u32 cookie;
+       __s64 value;
+
+       /* Checksum is not yet verified, but both checksum failure and TCP
+        * header checks return XDP_DROP, so the order doesn't matter.
+        */
+       if (hdr->tcp->fin || hdr->tcp->rst)
+               return XDP_DROP;
+
+       /* Issue SYN cookies on allowed ports, drop SYN packets on blocked
+        * ports.
+        */
+       if (!check_port_allowed(bpf_ntohs(hdr->tcp->dest)))
+               return XDP_DROP;
+
+       if (hdr->ipv4) {
+               /* Check the IPv4 and TCP checksums before creating a SYNACK. */
+               value = bpf_csum_diff(0, 0, (void *)hdr->ipv4, hdr->ipv4->ihl * 4, 0);
+               if (value < 0)
+                       return XDP_ABORTED;
+               if (csum_fold(value) != 0)
+                       return XDP_DROP; /* Bad IPv4 checksum. */
+
+               value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0);
+               if (value < 0)
+                       return XDP_ABORTED;
+               if (csum_tcpudp_magic(hdr->ipv4->saddr, hdr->ipv4->daddr,
+                                     hdr->tcp_len, IPPROTO_TCP, value) != 0)
+                       return XDP_DROP; /* Bad TCP checksum. */
+
+               ip_len = sizeof(*hdr->ipv4);
+
+               value = bpf_tcp_raw_gen_syncookie_ipv4(hdr->ipv4, hdr->tcp,
+                                                      hdr->tcp_len);
+       } else if (hdr->ipv6) {
+               /* Check the TCP checksum before creating a SYNACK. */
+               value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0);
+               if (value < 0)
+                       return XDP_ABORTED;
+               if (csum_ipv6_magic(&hdr->ipv6->saddr, &hdr->ipv6->daddr,
+                                   hdr->tcp_len, IPPROTO_TCP, value) != 0)
+                       return XDP_DROP; /* Bad TCP checksum. */
+
+               ip_len = sizeof(*hdr->ipv6);
+
+               value = bpf_tcp_raw_gen_syncookie_ipv6(hdr->ipv6, hdr->tcp,
+                                                      hdr->tcp_len);
+       } else {
+               return XDP_ABORTED;
+       }
+
+       if (value < 0)
+               return XDP_ABORTED;
+       cookie = (__u32)value;
+
+       if (tscookie_init((void *)hdr->tcp, hdr->tcp_len,
+                         &tsopt_buf[0], &tsopt_buf[1], data_end))
+               tsopt = tsopt_buf;
+
+       /* Check that there is enough space for a SYNACK. It also covers
+        * the check that the destination of the __builtin_memmove below
+        * doesn't overflow.
+        */
+       if (data + sizeof(*hdr->eth) + ip_len + TCP_MAXLEN > data_end)
+               return XDP_ABORTED;
+
+       if (hdr->ipv4) {
+               if (hdr->ipv4->ihl * 4 > sizeof(*hdr->ipv4)) {
+                       struct tcphdr *new_tcp_header;
+
+                       new_tcp_header = data + sizeof(*hdr->eth) + sizeof(*hdr->ipv4);
+                       __builtin_memmove(new_tcp_header, hdr->tcp, sizeof(*hdr->tcp));
+                       hdr->tcp = new_tcp_header;
+
+                       hdr->ipv4->ihl = sizeof(*hdr->ipv4) / 4;
+               }
+
+               tcpv4_gen_synack(hdr, cookie, tsopt);
+       } else if (hdr->ipv6) {
+               tcpv6_gen_synack(hdr, cookie, tsopt);
+       } else {
+               return XDP_ABORTED;
+       }
+
+       /* Recalculate checksums. */
+       hdr->tcp->check = 0;
+       value = bpf_csum_diff(0, 0, (void *)hdr->tcp, hdr->tcp_len, 0);
+       if (value < 0)
+               return XDP_ABORTED;
+       if (hdr->ipv4) {
+               hdr->tcp->check = csum_tcpudp_magic(hdr->ipv4->saddr,
+                                                   hdr->ipv4->daddr,
+                                                   hdr->tcp_len,
+                                                   IPPROTO_TCP,
+                                                   value);
+
+               hdr->ipv4->check = 0;
+               value = bpf_csum_diff(0, 0, (void *)hdr->ipv4, sizeof(*hdr->ipv4), 0);
+               if (value < 0)
+                       return XDP_ABORTED;
+               hdr->ipv4->check = csum_fold(value);
+       } else if (hdr->ipv6) {
+               hdr->tcp->check = csum_ipv6_magic(&hdr->ipv6->saddr,
+                                                 &hdr->ipv6->daddr,
+                                                 hdr->tcp_len,
+                                                 IPPROTO_TCP,
+                                                 value);
+       } else {
+               return XDP_ABORTED;
+       }
+
+       /* Set the new packet size. */
+       old_pkt_size = data_end - data;
+       new_pkt_size = sizeof(*hdr->eth) + ip_len + hdr->tcp->doff * 4;
+       if (xdp) {
+               if (bpf_xdp_adjust_tail(ctx, new_pkt_size - old_pkt_size))
+                       return XDP_ABORTED;
+       } else {
+               if (bpf_skb_change_tail(ctx, new_pkt_size, 0))
+                       return XDP_ABORTED;
+       }
+
+       values_inc_synacks();
+
+       return XDP_TX;
+}
+
+static __always_inline int syncookie_handle_ack(struct header_pointers *hdr)
+{
+       int err;
+
+       if (hdr->tcp->rst)
+               return XDP_DROP;
+
+       if (hdr->ipv4)
+               err = bpf_tcp_raw_check_syncookie_ipv4(hdr->ipv4, hdr->tcp);
+       else if (hdr->ipv6)
+               err = bpf_tcp_raw_check_syncookie_ipv6(hdr->ipv6, hdr->tcp);
+       else
+               return XDP_ABORTED;
+       if (err)
+               return XDP_DROP;
+
+       return XDP_PASS;
+}
+
+static __always_inline int syncookie_part1(void *ctx, void *data, void *data_end,
+                                          struct header_pointers *hdr, bool xdp)
+{
+       struct bpf_ct_opts ct_lookup_opts = {
+               .netns_id = BPF_F_CURRENT_NETNS,
+               .l4proto = IPPROTO_TCP,
+       };
+       int ret;
+
+       ret = tcp_dissect(data, data_end, hdr);
+       if (ret != XDP_TX)
+               return ret;
+
+       ret = tcp_lookup(ctx, hdr, xdp);
+       if (ret != XDP_TX)
+               return ret;
+
+       /* Packet is TCP and doesn't belong to an established connection. */
+
+       if ((hdr->tcp->syn ^ hdr->tcp->ack) != 1)
+               return XDP_DROP;
+
+       /* Grow the TCP header to TCP_MAXLEN to be able to pass any hdr->tcp_len
+        * to bpf_tcp_raw_gen_syncookie_ipv{4,6} and pass the verifier.
+        */
+       if (xdp) {
+               if (bpf_xdp_adjust_tail(ctx, TCP_MAXLEN - hdr->tcp_len))
+                       return XDP_ABORTED;
+       } else {
+               /* Without volatile the verifier throws this error:
+                * R9 32-bit pointer arithmetic prohibited
+                */
+               volatile u64 old_len = data_end - data;
+
+               if (bpf_skb_change_tail(ctx, old_len + TCP_MAXLEN - hdr->tcp_len, 0))
+                       return XDP_ABORTED;
+       }
+
+       return XDP_TX;
+}
+
+static __always_inline int syncookie_part2(void *ctx, void *data, void *data_end,
+                                          struct header_pointers *hdr, bool xdp)
+{
+       if (hdr->ipv4) {
+               hdr->eth = data;
+               hdr->ipv4 = (void *)hdr->eth + sizeof(*hdr->eth);
+               /* IPV4_MAXLEN is needed when calculating checksum.
+                * At least sizeof(struct iphdr) is needed here to access ihl.
+                */
+               if ((void *)hdr->ipv4 + IPV4_MAXLEN > data_end)
+                       return XDP_ABORTED;
+               hdr->tcp = (void *)hdr->ipv4 + hdr->ipv4->ihl * 4;
+       } else if (hdr->ipv6) {
+               hdr->eth = data;
+               hdr->ipv6 = (void *)hdr->eth + sizeof(*hdr->eth);
+               hdr->tcp = (void *)hdr->ipv6 + sizeof(*hdr->ipv6);
+       } else {
+               return XDP_ABORTED;
+       }
+
+       if ((void *)hdr->tcp + TCP_MAXLEN > data_end)
+               return XDP_ABORTED;
+
+       /* We run out of registers, tcp_len gets spilled to the stack, and the
+        * verifier forgets its min and max values checked above in tcp_dissect.
+        */
+       hdr->tcp_len = hdr->tcp->doff * 4;
+       if (hdr->tcp_len < sizeof(*hdr->tcp))
+               return XDP_ABORTED;
+
+       return hdr->tcp->syn ? syncookie_handle_syn(hdr, ctx, data, data_end, xdp) :
+                              syncookie_handle_ack(hdr);
+}
+
+SEC("xdp")
+int syncookie_xdp(struct xdp_md *ctx)
+{
+       void *data_end = (void *)(long)ctx->data_end;
+       void *data = (void *)(long)ctx->data;
+       struct header_pointers hdr;
+       int ret;
+
+       ret = syncookie_part1(ctx, data, data_end, &hdr, true);
+       if (ret != XDP_TX)
+               return ret;
+
+       data_end = (void *)(long)ctx->data_end;
+       data = (void *)(long)ctx->data;
+
+       return syncookie_part2(ctx, data, data_end, &hdr, true);
+}
+
+SEC("tc")
+int syncookie_tc(struct __sk_buff *skb)
+{
+       void *data_end = (void *)(long)skb->data_end;
+       void *data = (void *)(long)skb->data;
+       struct header_pointers hdr;
+       int ret;
+
+       ret = syncookie_part1(skb, data, data_end, &hdr, false);
+       if (ret != XDP_TX)
+               return ret == XDP_PASS ? TC_ACT_OK : TC_ACT_SHOT;
+
+       data_end = (void *)(long)skb->data_end;
+       data = (void *)(long)skb->data;
+
+       ret = syncookie_part2(skb, data, data_end, &hdr, false);
+       switch (ret) {
+       case XDP_PASS:
+               return TC_ACT_OK;
+       case XDP_TX:
+               return bpf_redirect(skb->ifindex, 0);
+       default:
+               return TC_ACT_SHOT;
+       }
+}
+
+char _license[] SEC("license") = "GPL";
index c0e7acd..e443e65 100755 (executable)
@@ -58,7 +58,7 @@ class BlockParser(object):
 
 class ArrayParser(BlockParser):
     """
-    A parser for extracting dicionaries of values from some BPF-related arrays.
+    A parser for extracting a set of values from some BPF-related arrays.
     @reader: a pointer to the open file to parse
     @array_name: name of the array to parse
     """
@@ -66,7 +66,7 @@ class ArrayParser(BlockParser):
 
     def __init__(self, reader, array_name):
         self.array_name = array_name
-        self.start_marker = re.compile(f'(static )?const char \* const {self.array_name}\[.*\] = {{\n')
+        self.start_marker = re.compile(f'(static )?const bool {self.array_name}\[.*\] = {{\n')
         super().__init__(reader)
 
     def search_block(self):
@@ -80,15 +80,15 @@ class ArrayParser(BlockParser):
         Parse a block and return data as a dictionary. Items to extract must be
         on separate lines in the file.
         """
-        pattern = re.compile('\[(BPF_\w*)\]\s*= "(.*)",?$')
-        entries = {}
+        pattern = re.compile('\[(BPF_\w*)\]\s*= (true|false),?$')
+        entries = set()
         while True:
             line = self.reader.readline()
             if line == '' or re.match(self.end_marker, line):
                 break
             capture = pattern.search(line)
             if capture:
-                entries[capture.group(1)] = capture.group(2)
+                entries |= {capture.group(1)}
         return entries
 
 class InlineListParser(BlockParser):
@@ -115,7 +115,7 @@ class InlineListParser(BlockParser):
 class FileExtractor(object):
     """
     A generic reader for extracting data from a given file. This class contains
-    several helper methods that wrap arround parser objects to extract values
+    several helper methods that wrap around parser objects to extract values
     from different structures.
     This class does not offer a way to set a filename, which is expected to be
     defined in children classes.
@@ -139,21 +139,19 @@ class FileExtractor(object):
 
     def get_types_from_array(self, array_name):
         """
-        Search for and parse an array associating names to BPF_* enum members,
-        for example:
+        Search for and parse a list of allowed BPF_* enum members, for example:
 
-            const char * const prog_type_name[] = {
-                    [BPF_PROG_TYPE_UNSPEC]                  = "unspec",
-                    [BPF_PROG_TYPE_SOCKET_FILTER]           = "socket_filter",
-                    [BPF_PROG_TYPE_KPROBE]                  = "kprobe",
+            const bool prog_type_name[] = {
+                    [BPF_PROG_TYPE_UNSPEC]                  = true,
+                    [BPF_PROG_TYPE_SOCKET_FILTER]           = true,
+                    [BPF_PROG_TYPE_KPROBE]                  = true,
             };
 
-        Return a dictionary with the enum member names as keys and the
-        associated names as values, for example:
+        Return a set of the enum members, for example:
 
-            {'BPF_PROG_TYPE_UNSPEC': 'unspec',
-             'BPF_PROG_TYPE_SOCKET_FILTER': 'socket_filter',
-             'BPF_PROG_TYPE_KPROBE': 'kprobe'}
+            {'BPF_PROG_TYPE_UNSPEC',
+             'BPF_PROG_TYPE_SOCKET_FILTER',
+             'BPF_PROG_TYPE_KPROBE'}
 
         @array_name: name of the array to parse
         """
@@ -186,6 +184,27 @@ class FileExtractor(object):
         parser.search_block(start_marker)
         return parser.parse(pattern, end_marker)
 
+    def make_enum_map(self, names, enum_prefix):
+        """
+        Search for and parse an enum containing BPF_* members, just as get_enum
+        does. However, instead of just returning a set of the variant names,
+        also generate a textual representation from them by (assuming and)
+        removing a provided prefix and lowercasing the remainder. Then return a
+        dict mapping from name to textual representation.
+
+        @enum_values: a set of enum values; e.g., as retrieved by get_enum
+        @enum_prefix: the prefix to remove from each of the variants to infer
+        textual representation
+        """
+        mapping = {}
+        for name in names:
+            if not name.startswith(enum_prefix):
+                raise Exception(f"enum variant {name} does not start with {enum_prefix}")
+            text = name[len(enum_prefix):].lower()
+            mapping[name] = text
+
+        return mapping
+
     def __get_description_list(self, start_marker, pattern, end_marker):
         parser = InlineListParser(self.reader)
         parser.search_block(start_marker)
@@ -333,11 +352,9 @@ class ProgFileExtractor(SourceFileExtractor):
     """
     filename = os.path.join(BPFTOOL_DIR, 'prog.c')
 
-    def get_prog_types(self):
-        return self.get_types_from_array('prog_type_name')
-
     def get_attach_types(self):
-        return self.get_types_from_array('attach_type_strings')
+        types = self.get_types_from_array('attach_types')
+        return self.make_enum_map(types, 'BPF_')
 
     def get_prog_attach_help(self):
         return self.get_help_list('ATTACH_TYPE')
@@ -348,9 +365,6 @@ class MapFileExtractor(SourceFileExtractor):
     """
     filename = os.path.join(BPFTOOL_DIR, 'map.c')
 
-    def get_map_types(self):
-        return self.get_types_from_array('map_type_name')
-
     def get_map_help(self):
         return self.get_help_list('TYPE')
 
@@ -363,30 +377,6 @@ class CgroupFileExtractor(SourceFileExtractor):
     def get_prog_attach_help(self):
         return self.get_help_list('ATTACH_TYPE')
 
-class CommonFileExtractor(SourceFileExtractor):
-    """
-    An extractor for bpftool's common.c.
-    """
-    filename = os.path.join(BPFTOOL_DIR, 'common.c')
-
-    def __init__(self):
-        super().__init__()
-        self.attach_types = {}
-
-    def get_attach_types(self):
-        if not self.attach_types:
-            self.attach_types = self.get_types_from_array('attach_type_name')
-        return self.attach_types
-
-    def get_cgroup_attach_types(self):
-        if not self.attach_types:
-            self.get_attach_types()
-        cgroup_types = {}
-        for (key, value) in self.attach_types.items():
-            if key.find('BPF_CGROUP') != -1:
-                cgroup_types[key] = value
-        return cgroup_types
-
 class GenericSourceExtractor(SourceFileExtractor):
     """
     An extractor for generic source code files.
@@ -403,14 +393,28 @@ class BpfHeaderExtractor(FileExtractor):
     """
     filename = os.path.join(INCLUDE_DIR, 'uapi/linux/bpf.h')
 
+    def __init__(self):
+        super().__init__()
+        self.attach_types = {}
+
     def get_prog_types(self):
         return self.get_enum('bpf_prog_type')
 
-    def get_map_types(self):
-        return self.get_enum('bpf_map_type')
+    def get_map_type_map(self):
+        names = self.get_enum('bpf_map_type')
+        return self.make_enum_map(names, 'BPF_MAP_TYPE_')
 
-    def get_attach_types(self):
-        return self.get_enum('bpf_attach_type')
+    def get_attach_type_map(self):
+        if not self.attach_types:
+          names = self.get_enum('bpf_attach_type')
+          self.attach_types = self.make_enum_map(names, 'BPF_')
+        return self.attach_types
+
+    def get_cgroup_attach_type_map(self):
+        if not self.attach_types:
+            self.get_attach_type_map()
+        return {name: text for name, text in self.attach_types.items()
+            if name.startswith('BPF_CGROUP')}
 
 class ManPageExtractor(FileExtractor):
     """
@@ -495,21 +499,12 @@ def main():
     """)
     args = argParser.parse_args()
 
-    # Map types (enum)
-
     bpf_info = BpfHeaderExtractor()
-    ref = bpf_info.get_map_types()
-
-    map_info = MapFileExtractor()
-    source_map_items = map_info.get_map_types()
-    map_types_enum = set(source_map_items.keys())
-
-    verify(ref, map_types_enum,
-            f'Comparing BPF header (enum bpf_map_type) and {MapFileExtractor.filename} (map_type_name):')
 
     # Map types (names)
 
-    source_map_types = set(source_map_items.values())
+    map_info = MapFileExtractor()
+    source_map_types = set(bpf_info.get_map_type_map().values())
     source_map_types.discard('unspec')
 
     help_map_types = map_info.get_map_help()
@@ -525,37 +520,17 @@ def main():
     bashcomp_map_types = bashcomp_info.get_map_types()
 
     verify(source_map_types, help_map_types,
-            f'Comparing {MapFileExtractor.filename} (map_type_name) and {MapFileExtractor.filename} (do_help() TYPE):')
+            f'Comparing {BpfHeaderExtractor.filename} (bpf_map_type) and {MapFileExtractor.filename} (do_help() TYPE):')
     verify(source_map_types, man_map_types,
-            f'Comparing {MapFileExtractor.filename} (map_type_name) and {ManMapExtractor.filename} (TYPE):')
+            f'Comparing {BpfHeaderExtractor.filename} (bpf_map_type) and {ManMapExtractor.filename} (TYPE):')
     verify(help_map_options, man_map_options,
             f'Comparing {MapFileExtractor.filename} (do_help() OPTIONS) and {ManMapExtractor.filename} (OPTIONS):')
     verify(source_map_types, bashcomp_map_types,
-            f'Comparing {MapFileExtractor.filename} (map_type_name) and {BashcompExtractor.filename} (BPFTOOL_MAP_CREATE_TYPES):')
-
-    # Program types (enum)
-
-    ref = bpf_info.get_prog_types()
-
-    prog_info = ProgFileExtractor()
-    prog_types = set(prog_info.get_prog_types().keys())
-
-    verify(ref, prog_types,
-            f'Comparing BPF header (enum bpf_prog_type) and {ProgFileExtractor.filename} (prog_type_name):')
-
-    # Attach types (enum)
-
-    ref = bpf_info.get_attach_types()
-    bpf_info.close()
-
-    common_info = CommonFileExtractor()
-    attach_types = common_info.get_attach_types()
-
-    verify(ref, attach_types,
-            f'Comparing BPF header (enum bpf_attach_type) and {CommonFileExtractor.filename} (attach_type_name):')
+            f'Comparing {BpfHeaderExtractor.filename} (bpf_map_type) and {BashcompExtractor.filename} (BPFTOOL_MAP_CREATE_TYPES):')
 
     # Attach types (names)
 
+    prog_info = ProgFileExtractor()
     source_prog_attach_types = set(prog_info.get_attach_types().values())
 
     help_prog_attach_types = prog_info.get_prog_attach_help()
@@ -571,18 +546,17 @@ def main():
     bashcomp_prog_attach_types = bashcomp_info.get_prog_attach_types()
 
     verify(source_prog_attach_types, help_prog_attach_types,
-            f'Comparing {ProgFileExtractor.filename} (attach_type_strings) and {ProgFileExtractor.filename} (do_help() ATTACH_TYPE):')
+            f'Comparing {ProgFileExtractor.filename} (bpf_attach_type) and {ProgFileExtractor.filename} (do_help() ATTACH_TYPE):')
     verify(source_prog_attach_types, man_prog_attach_types,
-            f'Comparing {ProgFileExtractor.filename} (attach_type_strings) and {ManProgExtractor.filename} (ATTACH_TYPE):')
+            f'Comparing {ProgFileExtractor.filename} (bpf_attach_type) and {ManProgExtractor.filename} (ATTACH_TYPE):')
     verify(help_prog_options, man_prog_options,
             f'Comparing {ProgFileExtractor.filename} (do_help() OPTIONS) and {ManProgExtractor.filename} (OPTIONS):')
     verify(source_prog_attach_types, bashcomp_prog_attach_types,
-            f'Comparing {ProgFileExtractor.filename} (attach_type_strings) and {BashcompExtractor.filename} (BPFTOOL_PROG_ATTACH_TYPES):')
+            f'Comparing {ProgFileExtractor.filename} (bpf_attach_type) and {BashcompExtractor.filename} (BPFTOOL_PROG_ATTACH_TYPES):')
 
     # Cgroup attach types
-
-    source_cgroup_attach_types = set(common_info.get_cgroup_attach_types().values())
-    common_info.close()
+    source_cgroup_attach_types = set(bpf_info.get_cgroup_attach_type_map().values())
+    bpf_info.close()
 
     cgroup_info = CgroupFileExtractor()
     help_cgroup_attach_types = cgroup_info.get_prog_attach_help()
@@ -598,13 +572,13 @@ def main():
     bashcomp_info.close()
 
     verify(source_cgroup_attach_types, help_cgroup_attach_types,
-            f'Comparing {CommonFileExtractor.filename} (attach_type_strings) and {CgroupFileExtractor.filename} (do_help() ATTACH_TYPE):')
+            f'Comparing {BpfHeaderExtractor.filename} (bpf_attach_type) and {CgroupFileExtractor.filename} (do_help() ATTACH_TYPE):')
     verify(source_cgroup_attach_types, man_cgroup_attach_types,
-            f'Comparing {CommonFileExtractor.filename} (attach_type_strings) and {ManCgroupExtractor.filename} (ATTACH_TYPE):')
+            f'Comparing {BpfHeaderExtractor.filename} (bpf_attach_type) and {ManCgroupExtractor.filename} (ATTACH_TYPE):')
     verify(help_cgroup_options, man_cgroup_options,
             f'Comparing {CgroupFileExtractor.filename} (do_help() OPTIONS) and {ManCgroupExtractor.filename} (OPTIONS):')
     verify(source_cgroup_attach_types, bashcomp_cgroup_attach_types,
-            f'Comparing {CommonFileExtractor.filename} (attach_type_strings) and {BashcompExtractor.filename} (BPFTOOL_CGROUP_ATTACH_TYPES):')
+            f'Comparing {BpfHeaderExtractor.filename} (bpf_attach_type) and {BashcompExtractor.filename} (BPFTOOL_CGROUP_ATTACH_TYPES):')
 
     # Options for remaining commands
 
index 128989b..38782bd 100644 (file)
@@ -39,6 +39,7 @@
 #define BTF_MEMBER_ENC(name, type, bits_offset)        \
        (name), (type), (bits_offset)
 #define BTF_ENUM_ENC(name, val) (name), (val)
+#define BTF_ENUM64_ENC(name, val_lo32, val_hi32) (name), (val_lo32), (val_hi32)
 #define BTF_MEMBER_OFFSET(bitfield_size, bits_offset) \
        ((bitfield_size) << 24 | (bits_offset))
 
index c2f0ddb..c3d82e0 100755 (executable)
@@ -95,5 +95,9 @@ for server_args in "" "-I veth0 -s -S" ; do
        test "$client_args" "$server_args"
 done
 
+# Test drv mode
+test "-I veth1 -N" "-I veth0 -s -N"
+test "-I veth1 -N -c 10" "-I veth0 -s -N"
+
 echo "OK. All tests passed"
 exit 0
diff --git a/tools/testing/selftests/bpf/xdp_synproxy.c b/tools/testing/selftests/bpf/xdp_synproxy.c
new file mode 100644 (file)
index 0000000..d874ddf
--- /dev/null
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: LGPL-2.1 OR BSD-2-Clause
+/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
+
+#include <stdnoreturn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+#include <net/if.h>
+#include <linux/if_link.h>
+#include <linux/limits.h>
+
+static unsigned int ifindex;
+static __u32 attached_prog_id;
+static bool attached_tc;
+
+static void noreturn cleanup(int sig)
+{
+       LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
+       int prog_fd;
+       int err;
+
+       if (attached_prog_id == 0)
+               exit(0);
+
+       if (attached_tc) {
+               LIBBPF_OPTS(bpf_tc_hook, hook,
+                           .ifindex = ifindex,
+                           .attach_point = BPF_TC_INGRESS);
+
+               err = bpf_tc_hook_destroy(&hook);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_tc_hook_destroy: %s\n", strerror(-err));
+                       fprintf(stderr, "Failed to destroy the TC hook\n");
+                       exit(1);
+               }
+               exit(0);
+       }
+
+       prog_fd = bpf_prog_get_fd_by_id(attached_prog_id);
+       if (prog_fd < 0) {
+               fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
+               err = bpf_xdp_attach(ifindex, -1, 0, NULL);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n", strerror(-err));
+                       fprintf(stderr, "Failed to detach XDP program\n");
+                       exit(1);
+               }
+       } else {
+               opts.old_prog_fd = prog_fd;
+               err = bpf_xdp_attach(ifindex, -1, XDP_FLAGS_REPLACE, &opts);
+               close(prog_fd);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_set_link_xdp_fd_opts: %s\n", strerror(-err));
+                       /* Not an error if already replaced by someone else. */
+                       if (err != -EEXIST) {
+                               fprintf(stderr, "Failed to detach XDP program\n");
+                               exit(1);
+                       }
+               }
+       }
+       exit(0);
+}
+
+static noreturn void usage(const char *progname)
+{
+       fprintf(stderr, "Usage: %s [--iface <iface>|--prog <prog_id>] [--mss4 <mss ipv4> --mss6 <mss ipv6> --wscale <wscale> --ttl <ttl>] [--ports <port1>,<port2>,...] [--single] [--tc]\n",
+               progname);
+       exit(1);
+}
+
+static unsigned long parse_arg_ul(const char *progname, const char *arg, unsigned long limit)
+{
+       unsigned long res;
+       char *endptr;
+
+       errno = 0;
+       res = strtoul(arg, &endptr, 10);
+       if (errno != 0 || *endptr != '\0' || arg[0] == '\0' || res > limit)
+               usage(progname);
+
+       return res;
+}
+
+static void parse_options(int argc, char *argv[], unsigned int *ifindex, __u32 *prog_id,
+                         __u64 *tcpipopts, char **ports, bool *single, bool *tc)
+{
+       static struct option long_options[] = {
+               { "help", no_argument, NULL, 'h' },
+               { "iface", required_argument, NULL, 'i' },
+               { "prog", required_argument, NULL, 'x' },
+               { "mss4", required_argument, NULL, 4 },
+               { "mss6", required_argument, NULL, 6 },
+               { "wscale", required_argument, NULL, 'w' },
+               { "ttl", required_argument, NULL, 't' },
+               { "ports", required_argument, NULL, 'p' },
+               { "single", no_argument, NULL, 's' },
+               { "tc", no_argument, NULL, 'c' },
+               { NULL, 0, NULL, 0 },
+       };
+       unsigned long mss4, mss6, wscale, ttl;
+       unsigned int tcpipopts_mask = 0;
+
+       if (argc < 2)
+               usage(argv[0]);
+
+       *ifindex = 0;
+       *prog_id = 0;
+       *tcpipopts = 0;
+       *ports = NULL;
+       *single = false;
+
+       while (true) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "", long_options, NULL);
+               if (opt == -1)
+                       break;
+
+               switch (opt) {
+               case 'h':
+                       usage(argv[0]);
+                       break;
+               case 'i':
+                       *ifindex = if_nametoindex(optarg);
+                       if (*ifindex == 0)
+                               usage(argv[0]);
+                       break;
+               case 'x':
+                       *prog_id = parse_arg_ul(argv[0], optarg, UINT32_MAX);
+                       if (*prog_id == 0)
+                               usage(argv[0]);
+                       break;
+               case 4:
+                       mss4 = parse_arg_ul(argv[0], optarg, UINT16_MAX);
+                       tcpipopts_mask |= 1 << 0;
+                       break;
+               case 6:
+                       mss6 = parse_arg_ul(argv[0], optarg, UINT16_MAX);
+                       tcpipopts_mask |= 1 << 1;
+                       break;
+               case 'w':
+                       wscale = parse_arg_ul(argv[0], optarg, 14);
+                       tcpipopts_mask |= 1 << 2;
+                       break;
+               case 't':
+                       ttl = parse_arg_ul(argv[0], optarg, UINT8_MAX);
+                       tcpipopts_mask |= 1 << 3;
+                       break;
+               case 'p':
+                       *ports = optarg;
+                       break;
+               case 's':
+                       *single = true;
+                       break;
+               case 'c':
+                       *tc = true;
+                       break;
+               default:
+                       usage(argv[0]);
+               }
+       }
+       if (optind < argc)
+               usage(argv[0]);
+
+       if (tcpipopts_mask == 0xf) {
+               if (mss4 == 0 || mss6 == 0 || wscale == 0 || ttl == 0)
+                       usage(argv[0]);
+               *tcpipopts = (mss6 << 32) | (ttl << 24) | (wscale << 16) | mss4;
+       } else if (tcpipopts_mask != 0) {
+               usage(argv[0]);
+       }
+
+       if (*ifindex != 0 && *prog_id != 0)
+               usage(argv[0]);
+       if (*ifindex == 0 && *prog_id == 0)
+               usage(argv[0]);
+}
+
+static int syncookie_attach(const char *argv0, unsigned int ifindex, bool tc)
+{
+       struct bpf_prog_info info = {};
+       __u32 info_len = sizeof(info);
+       char xdp_filename[PATH_MAX];
+       struct bpf_program *prog;
+       struct bpf_object *obj;
+       int prog_fd;
+       int err;
+
+       snprintf(xdp_filename, sizeof(xdp_filename), "%s_kern.o", argv0);
+       obj = bpf_object__open_file(xdp_filename, NULL);
+       err = libbpf_get_error(obj);
+       if (err < 0) {
+               fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err));
+               return err;
+       }
+
+       err = bpf_object__load(obj);
+       if (err < 0) {
+               fprintf(stderr, "Error: bpf_object__open_file: %s\n", strerror(-err));
+               return err;
+       }
+
+       prog = bpf_object__find_program_by_name(obj, tc ? "syncookie_tc" : "syncookie_xdp");
+       if (!prog) {
+               fprintf(stderr, "Error: bpf_object__find_program_by_name: program was not found\n");
+               return -ENOENT;
+       }
+
+       prog_fd = bpf_program__fd(prog);
+
+       err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
+       if (err < 0) {
+               fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
+               goto out;
+       }
+       attached_tc = tc;
+       attached_prog_id = info.id;
+       signal(SIGINT, cleanup);
+       signal(SIGTERM, cleanup);
+       if (tc) {
+               LIBBPF_OPTS(bpf_tc_hook, hook,
+                           .ifindex = ifindex,
+                           .attach_point = BPF_TC_INGRESS);
+               LIBBPF_OPTS(bpf_tc_opts, opts,
+                           .handle = 1,
+                           .priority = 1,
+                           .prog_fd = prog_fd);
+
+               err = bpf_tc_hook_create(&hook);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_tc_hook_create: %s\n",
+                               strerror(-err));
+                       goto fail;
+               }
+               err = bpf_tc_attach(&hook, &opts);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_tc_attach: %s\n",
+                               strerror(-err));
+                       goto fail;
+               }
+
+       } else {
+               err = bpf_xdp_attach(ifindex, prog_fd,
+                                    XDP_FLAGS_UPDATE_IF_NOEXIST, NULL);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_set_link_xdp_fd: %s\n",
+                               strerror(-err));
+                       goto fail;
+               }
+       }
+       err = 0;
+out:
+       bpf_object__close(obj);
+       return err;
+fail:
+       signal(SIGINT, SIG_DFL);
+       signal(SIGTERM, SIG_DFL);
+       attached_prog_id = 0;
+       goto out;
+}
+
+static int syncookie_open_bpf_maps(__u32 prog_id, int *values_map_fd, int *ports_map_fd)
+{
+       struct bpf_prog_info prog_info;
+       __u32 map_ids[8];
+       __u32 info_len;
+       int prog_fd;
+       int err;
+       int i;
+
+       *values_map_fd = -1;
+       *ports_map_fd = -1;
+
+       prog_fd = bpf_prog_get_fd_by_id(prog_id);
+       if (prog_fd < 0) {
+               fprintf(stderr, "Error: bpf_prog_get_fd_by_id: %s\n", strerror(-prog_fd));
+               return prog_fd;
+       }
+
+       prog_info = (struct bpf_prog_info) {
+               .nr_map_ids = 8,
+               .map_ids = (__u64)map_ids,
+       };
+       info_len = sizeof(prog_info);
+
+       err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
+       if (err != 0) {
+               fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
+               goto out;
+       }
+
+       if (prog_info.nr_map_ids < 2) {
+               fprintf(stderr, "Error: Found %u BPF maps, expected at least 2\n",
+                       prog_info.nr_map_ids);
+               err = -ENOENT;
+               goto out;
+       }
+
+       for (i = 0; i < prog_info.nr_map_ids; i++) {
+               struct bpf_map_info map_info = {};
+               int map_fd;
+
+               err = bpf_map_get_fd_by_id(map_ids[i]);
+               if (err < 0) {
+                       fprintf(stderr, "Error: bpf_map_get_fd_by_id: %s\n", strerror(-err));
+                       goto err_close_map_fds;
+               }
+               map_fd = err;
+
+               info_len = sizeof(map_info);
+               err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
+               if (err != 0) {
+                       fprintf(stderr, "Error: bpf_obj_get_info_by_fd: %s\n", strerror(-err));
+                       close(map_fd);
+                       goto err_close_map_fds;
+               }
+               if (strcmp(map_info.name, "values") == 0) {
+                       *values_map_fd = map_fd;
+                       continue;
+               }
+               if (strcmp(map_info.name, "allowed_ports") == 0) {
+                       *ports_map_fd = map_fd;
+                       continue;
+               }
+               close(map_fd);
+       }
+
+       if (*values_map_fd != -1 && *ports_map_fd != -1) {
+               err = 0;
+               goto out;
+       }
+
+       err = -ENOENT;
+
+err_close_map_fds:
+       if (*values_map_fd != -1)
+               close(*values_map_fd);
+       if (*ports_map_fd != -1)
+               close(*ports_map_fd);
+       *values_map_fd = -1;
+       *ports_map_fd = -1;
+
+out:
+       close(prog_fd);
+       return err;
+}
+
+int main(int argc, char *argv[])
+{
+       int values_map_fd, ports_map_fd;
+       __u64 tcpipopts;
+       bool firstiter;
+       __u64 prevcnt;
+       __u32 prog_id;
+       char *ports;
+       bool single;
+       int err = 0;
+       bool tc;
+
+       parse_options(argc, argv, &ifindex, &prog_id, &tcpipopts, &ports,
+                     &single, &tc);
+
+       if (prog_id == 0) {
+               if (!tc) {
+                       err = bpf_xdp_query_id(ifindex, 0, &prog_id);
+                       if (err < 0) {
+                               fprintf(stderr, "Error: bpf_get_link_xdp_id: %s\n",
+                                       strerror(-err));
+                               goto out;
+                       }
+               }
+               if (prog_id == 0) {
+                       err = syncookie_attach(argv[0], ifindex, tc);
+                       if (err < 0)
+                               goto out;
+                       prog_id = attached_prog_id;
+               }
+       }
+
+       err = syncookie_open_bpf_maps(prog_id, &values_map_fd, &ports_map_fd);
+       if (err < 0)
+               goto out;
+
+       if (ports) {
+               __u16 port_last = 0;
+               __u32 port_idx = 0;
+               char *p = ports;
+
+               fprintf(stderr, "Replacing allowed ports\n");
+
+               while (p && *p != '\0') {
+                       char *token = strsep(&p, ",");
+                       __u16 port;
+
+                       port = parse_arg_ul(argv[0], token, UINT16_MAX);
+                       err = bpf_map_update_elem(ports_map_fd, &port_idx, &port, BPF_ANY);
+                       if (err != 0) {
+                               fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
+                               fprintf(stderr, "Failed to add port %u (index %u)\n",
+                                       port, port_idx);
+                               goto out_close_maps;
+                       }
+                       fprintf(stderr, "Added port %u\n", port);
+                       port_idx++;
+               }
+               err = bpf_map_update_elem(ports_map_fd, &port_idx, &port_last, BPF_ANY);
+               if (err != 0) {
+                       fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
+                       fprintf(stderr, "Failed to add the terminator value 0 (index %u)\n",
+                               port_idx);
+                       goto out_close_maps;
+               }
+       }
+
+       if (tcpipopts) {
+               __u32 key = 0;
+
+               fprintf(stderr, "Replacing TCP/IP options\n");
+
+               err = bpf_map_update_elem(values_map_fd, &key, &tcpipopts, BPF_ANY);
+               if (err != 0) {
+                       fprintf(stderr, "Error: bpf_map_update_elem: %s\n", strerror(-err));
+                       goto out_close_maps;
+               }
+       }
+
+       if ((ports || tcpipopts) && attached_prog_id == 0 && !single)
+               goto out_close_maps;
+
+       prevcnt = 0;
+       firstiter = true;
+       while (true) {
+               __u32 key = 1;
+               __u64 value;
+
+               err = bpf_map_lookup_elem(values_map_fd, &key, &value);
+               if (err != 0) {
+                       fprintf(stderr, "Error: bpf_map_lookup_elem: %s\n", strerror(-err));
+                       goto out_close_maps;
+               }
+               if (firstiter) {
+                       prevcnt = value;
+                       firstiter = false;
+               }
+               if (single) {
+                       printf("Total SYNACKs generated: %llu\n", value);
+                       break;
+               }
+               printf("SYNACKs generated: %llu (total %llu)\n", value - prevcnt, value);
+               prevcnt = value;
+               sleep(1);
+       }
+
+out_close_maps:
+       close(values_map_fd);
+       close(ports_map_fd);
+out:
+       return err == 0 ? 0 : 1;
+}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/rif_counter_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/rif_counter_scale.sh
new file mode 100644 (file)
index 0000000..a43a992
--- /dev/null
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0
+
+RIF_COUNTER_NUM_NETIFS=2
+
+rif_counter_addr4()
+{
+       local i=$1; shift
+       local p=$1; shift
+
+       printf 192.0.%d.%d $((i / 64)) $(((4 * i % 256) + p))
+}
+
+rif_counter_addr4pfx()
+{
+       rif_counter_addr4 $@
+       printf /30
+}
+
+rif_counter_h1_create()
+{
+       simple_if_init $h1
+}
+
+rif_counter_h1_destroy()
+{
+       simple_if_fini $h1
+}
+
+rif_counter_h2_create()
+{
+       simple_if_init $h2
+}
+
+rif_counter_h2_destroy()
+{
+       simple_if_fini $h2
+}
+
+rif_counter_setup_prepare()
+{
+       h1=${NETIFS[p1]}
+       h2=${NETIFS[p2]}
+
+       vrf_prepare
+
+       rif_counter_h1_create
+       rif_counter_h2_create
+}
+
+rif_counter_cleanup()
+{
+       local count=$1; shift
+
+       pre_cleanup
+
+       for ((i = 1; i <= count; i++)); do
+               vlan_destroy $h2 $i
+       done
+
+       rif_counter_h2_destroy
+       rif_counter_h1_destroy
+
+       vrf_cleanup
+
+       if [[ -v RIF_COUNTER_BATCH_FILE ]]; then
+               rm -f $RIF_COUNTER_BATCH_FILE
+       fi
+}
+
+
+rif_counter_test()
+{
+       local count=$1; shift
+       local should_fail=$1; shift
+
+       RIF_COUNTER_BATCH_FILE="$(mktemp)"
+
+       for ((i = 1; i <= count; i++)); do
+               vlan_create $h2 $i v$h2 $(rif_counter_addr4pfx $i 2)
+       done
+       for ((i = 1; i <= count; i++)); do
+               cat >> $RIF_COUNTER_BATCH_FILE <<-EOF
+                       stats set dev $h2.$i l3_stats on
+               EOF
+       done
+
+       ip -b $RIF_COUNTER_BATCH_FILE
+       check_err_fail $should_fail $? "RIF counter enablement"
+}
+
+rif_counter_traffic_test()
+{
+       local count=$1; shift
+       local i;
+
+       for ((i = count; i > 0; i /= 2)); do
+               $MZ $h1 -Q $i -c 1 -d 20msec -p 100 -a own -b $(mac_get $h2) \
+                   -A $(rif_counter_addr4 $i 1) \
+                   -B $(rif_counter_addr4 $i 2) \
+                   -q -t udp sp=54321,dp=12345
+       done
+       for ((i = count; i > 0; i /= 2)); do
+               busywait "$TC_HIT_TIMEOUT" until_counter_is "== 1" \
+                        hw_stats_get l3_stats $h2.$i rx packets > /dev/null
+               check_err $? "Traffic not seen at RIF $h2.$i"
+       done
+}
index e9f65bd..688338b 100755 (executable)
@@ -25,7 +25,16 @@ cleanup()
 
 trap cleanup EXIT
 
-ALL_TESTS="router tc_flower mirror_gre tc_police port rif_mac_profile"
+ALL_TESTS="
+       router
+       tc_flower
+       mirror_gre
+       tc_police
+       port
+       rif_mac_profile
+       rif_counter
+"
+
 for current_test in ${TESTS:-$ALL_TESTS}; do
        RET_FIN=0
        source ${current_test}_scale.sh
@@ -36,16 +45,32 @@ for current_test in ${TESTS:-$ALL_TESTS}; do
        for should_fail in 0 1; do
                RET=0
                target=$(${current_test}_get_target "$should_fail")
+               if ((target == 0)); then
+                       log_test_skip "'$current_test' should_fail=$should_fail test"
+                       continue
+               fi
+
                ${current_test}_setup_prepare
                setup_wait $num_netifs
+               # Update target in case occupancy of a certain resource changed
+               # following the test setup.
+               target=$(${current_test}_get_target "$should_fail")
                ${current_test}_test "$target" "$should_fail"
-               ${current_test}_cleanup
-               devlink_reload
                if [[ "$should_fail" -eq 0 ]]; then
                        log_test "'$current_test' $target"
+
+                       if ((!RET)); then
+                               tt=${current_test}_traffic_test
+                               if [[ $(type -t $tt) == "function" ]]; then
+                                       $tt "$target"
+                                       log_test "'$current_test' $target traffic test"
+                               fi
+                       fi
                else
                        log_test "'$current_test' overflow $target"
                fi
+               ${current_test}_cleanup $target
+               devlink_reload
                RET_FIN=$(( RET_FIN || RET ))
        done
 done
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/rif_counter_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/rif_counter_scale.sh
new file mode 120000 (symlink)
index 0000000..1f5752e
--- /dev/null
@@ -0,0 +1 @@
+../spectrum/rif_counter_scale.sh
\ No newline at end of file
index efd798a..4444bba 100644 (file)
@@ -4,17 +4,22 @@ source ../tc_flower_scale.sh
 tc_flower_get_target()
 {
        local should_fail=$1; shift
+       local max_cnts
 
        # The driver associates a counter with each tc filter, which means the
        # number of supported filters is bounded by the number of available
        # counters.
-       # Currently, the driver supports 30K (30,720) flow counters and six of
-       # these are used for multicast routing.
-       local target=30714
+       max_cnts=$(devlink_resource_size_get counters flow)
+
+       # Remove already allocated counters.
+       ((max_cnts -= $(devlink_resource_occ_get counters flow)))
+
+       # Each rule uses two counters, for packets and bytes.
+       ((max_cnts /= 2))
 
        if ((! should_fail)); then
-               echo $target
+               echo $max_cnts
        else
-               echo $((target + 1))
+               echo $((max_cnts + 1))
        fi
 }
index dea33dc..95d9f71 100755 (executable)
@@ -22,7 +22,16 @@ cleanup()
 devlink_sp_read_kvd_defaults
 trap cleanup EXIT
 
-ALL_TESTS="router tc_flower mirror_gre tc_police port rif_mac_profile"
+ALL_TESTS="
+       router
+       tc_flower
+       mirror_gre
+       tc_police
+       port
+       rif_mac_profile
+       rif_counter
+"
+
 for current_test in ${TESTS:-$ALL_TESTS}; do
        RET_FIN=0
        source ${current_test}_scale.sh
@@ -41,15 +50,31 @@ for current_test in ${TESTS:-$ALL_TESTS}; do
                for should_fail in 0 1; do
                        RET=0
                        target=$(${current_test}_get_target "$should_fail")
+                       if ((target == 0)); then
+                               log_test_skip "'$current_test' [$profile] should_fail=$should_fail test"
+                               continue
+                       fi
                        ${current_test}_setup_prepare
                        setup_wait $num_netifs
+                       # Update target in case occupancy of a certain resource
+                       # changed following the test setup.
+                       target=$(${current_test}_get_target "$should_fail")
                        ${current_test}_test "$target" "$should_fail"
-                       ${current_test}_cleanup
                        if [[ "$should_fail" -eq 0 ]]; then
                                log_test "'$current_test' [$profile] $target"
+
+                               if ((!RET)); then
+                                       tt=${current_test}_traffic_test
+                                       if [[ $(type -t $tt) == "function" ]]
+                                       then
+                                               $tt "$target"
+                                               log_test "'$current_test' [$profile] $target traffic test"
+                                       fi
+                               fi
                        else
                                log_test "'$current_test' [$profile] overflow $target"
                        fi
+                       ${current_test}_cleanup $target
                        RET_FIN=$(( RET_FIN || RET ))
                done
        done
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/rif_counter_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/rif_counter_scale.sh
new file mode 100644 (file)
index 0000000..d445362
--- /dev/null
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+source ../rif_counter_scale.sh
+
+rif_counter_get_target()
+{
+       local should_fail=$1; shift
+       local max_cnts
+       local max_rifs
+       local target
+
+       max_rifs=$(devlink_resource_size_get rifs)
+       max_cnts=$(devlink_resource_size_get counters rif)
+
+       # Remove already allocated RIFs.
+       ((max_rifs -= $(devlink_resource_occ_get rifs)))
+
+       # 10 KVD slots per counter, ingress+egress counters per RIF
+       ((max_cnts /= 20))
+
+       # Pointless to run the overflow test if we don't have enough RIFs to
+       # host all the counters.
+       if ((max_cnts > max_rifs && should_fail)); then
+               echo 0
+               return
+       fi
+
+       target=$((max_rifs < max_cnts ? max_rifs : max_cnts))
+
+       if ((! should_fail)); then
+               echo $target
+       else
+               echo $((target + 1))
+       fi
+}
index aa74be9..d3d9e60 100644 (file)
@@ -77,6 +77,7 @@ tc_flower_rules_create()
                        filter add dev $h2 ingress \
                                prot ipv6 \
                                pref 1000 \
+                               handle 42$i \
                                flower $tcflags dst_ip $(tc_flower_addr $i) \
                                action drop
                EOF
@@ -121,3 +122,19 @@ tc_flower_test()
        tcflags="skip_sw"
        __tc_flower_test $count $should_fail
 }
+
+tc_flower_traffic_test()
+{
+       local count=$1; shift
+       local i;
+
+       for ((i = count - 1; i > 0; i /= 2)); do
+               $MZ -6 $h1 -c 1 -d 20msec -p 100 -a own -b $(mac_get $h2) \
+                   -A $(tc_flower_addr 0) -B $(tc_flower_addr $i) \
+                   -q -t udp sp=54321,dp=12345
+       done
+       for ((i = count - 1; i > 0; i /= 2)); do
+               tc_check_packets "dev $h2 ingress" 42$i 1
+               check_err $? "Traffic not seen at rule #$i"
+       done
+}
index a29f796..1257baa 100644 (file)
@@ -37,3 +37,4 @@ gro
 ioam6_parser
 toeplitz
 cmsg_sender
+unix_connect
\ No newline at end of file
index df34164..969620a 100644 (file)
@@ -1,2 +1,3 @@
-TEST_GEN_PROGS := test_unix_oob
+TEST_GEN_PROGS := test_unix_oob unix_connect
+
 include ../../lib.mk
diff --git a/tools/testing/selftests/net/af_unix/unix_connect.c b/tools/testing/selftests/net/af_unix/unix_connect.c
new file mode 100644 (file)
index 0000000..157e44e
--- /dev/null
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <sched.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "../../kselftest_harness.h"
+
+FIXTURE(unix_connect)
+{
+       int server, client;
+       int family;
+};
+
+FIXTURE_VARIANT(unix_connect)
+{
+       int type;
+       char sun_path[8];
+       int len;
+       int flags;
+       int err;
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, stream_pathname)
+{
+       .type = SOCK_STREAM,
+       .sun_path = "test",
+       .len = 4 + 1,
+       .flags = 0,
+       .err = 0,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, stream_abstract)
+{
+       .type = SOCK_STREAM,
+       .sun_path = "\0test",
+       .len = 5,
+       .flags = 0,
+       .err = 0,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, stream_pathname_netns)
+{
+       .type = SOCK_STREAM,
+       .sun_path = "test",
+       .len = 4 + 1,
+       .flags = CLONE_NEWNET,
+       .err = 0,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, stream_abstract_netns)
+{
+       .type = SOCK_STREAM,
+       .sun_path = "\0test",
+       .len = 5,
+       .flags = CLONE_NEWNET,
+       .err = ECONNREFUSED,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, dgram_pathname)
+{
+       .type = SOCK_DGRAM,
+       .sun_path = "test",
+       .len = 4 + 1,
+       .flags = 0,
+       .err = 0,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, dgram_abstract)
+{
+       .type = SOCK_DGRAM,
+       .sun_path = "\0test",
+       .len = 5,
+       .flags = 0,
+       .err = 0,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, dgram_pathname_netns)
+{
+       .type = SOCK_DGRAM,
+       .sun_path = "test",
+       .len = 4 + 1,
+       .flags = CLONE_NEWNET,
+       .err = 0,
+};
+
+FIXTURE_VARIANT_ADD(unix_connect, dgram_abstract_netns)
+{
+       .type = SOCK_DGRAM,
+       .sun_path = "\0test",
+       .len = 5,
+       .flags = CLONE_NEWNET,
+       .err = ECONNREFUSED,
+};
+
+FIXTURE_SETUP(unix_connect)
+{
+       self->family = AF_UNIX;
+}
+
+FIXTURE_TEARDOWN(unix_connect)
+{
+       close(self->server);
+       close(self->client);
+
+       if (variant->sun_path[0])
+               remove("test");
+}
+
+#define offsetof(type, member) ((size_t)&((type *)0)->(member))
+
+TEST_F(unix_connect, test)
+{
+       socklen_t addrlen;
+       struct sockaddr_un addr = {
+               .sun_family = self->family,
+       };
+       int err;
+
+       self->server = socket(self->family, variant->type, 0);
+       ASSERT_NE(-1, self->server);
+
+       addrlen = offsetof(struct sockaddr_un, sun_path) + variant->len;
+       memcpy(&addr.sun_path, variant->sun_path, variant->len);
+
+       err = bind(self->server, (struct sockaddr *)&addr, addrlen);
+       ASSERT_EQ(0, err);
+
+       if (variant->type == SOCK_STREAM) {
+               err = listen(self->server, 32);
+               ASSERT_EQ(0, err);
+       }
+
+       err = unshare(variant->flags);
+       ASSERT_EQ(0, err);
+
+       self->client = socket(self->family, variant->type, 0);
+       ASSERT_LT(0, self->client);
+
+       err = connect(self->client, (struct sockaddr *)&addr, addrlen);
+       ASSERT_EQ(variant->err, err == -1 ? errno : 0);
+}
+
+TEST_HARNESS_MAIN
index bc21629..75dd83e 100644 (file)
@@ -456,7 +456,7 @@ int main(int argc, char *argv[])
                buf[1] = 0;
        } else if (opt.sock.type == SOCK_RAW) {
                struct udphdr hdr = { 1, 2, htons(opt.size), 0 };
-               struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;;
+               struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;
 
                memcpy(buf, &hdr, sizeof(hdr));
                sin6->sin6_port = htons(opt.sock.proto);
index bbe3b37..c245476 100755 (executable)
@@ -303,6 +303,29 @@ run_fibrule_tests()
        log_section "IPv6 fib rule"
        fib_rule6_test
 }
+################################################################################
+# usage
+
+usage()
+{
+       cat <<EOF
+usage: ${0##*/} OPTS
+
+        -t <test>   Test(s) to run (default: all)
+                    (options: $TESTS)
+EOF
+}
+
+################################################################################
+# main
+
+while getopts ":t:h" opt; do
+       case $opt in
+               t) TESTS=$OPTARG;;
+               h) usage; exit 0;;
+               *) usage; exit 1;;
+       esac
+done
 
 if [ "$(id -u)" -ne 0 ];then
        echo "SKIP: Need root privileges"
index 8f48121..669ffd6 100644 (file)
@@ -3,6 +3,7 @@
 TEST_PROGS = bridge_igmp.sh \
        bridge_locked_port.sh \
        bridge_mdb.sh \
+       bridge_mdb_port_down.sh \
        bridge_mld.sh \
        bridge_port_isolation.sh \
        bridge_sticky_fdb.sh \
diff --git a/tools/testing/selftests/net/forwarding/bridge_mdb_port_down.sh b/tools/testing/selftests/net/forwarding/bridge_mdb_port_down.sh
new file mode 100755 (executable)
index 0000000..1a0480e
--- /dev/null
@@ -0,0 +1,118 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Verify that permanent mdb entries can be added to and deleted from bridge
+# interfaces that are down, and works correctly when done so.
+
+ALL_TESTS="add_del_to_port_down"
+NUM_NETIFS=4
+
+TEST_GROUP="239.10.10.10"
+TEST_GROUP_MAC="01:00:5e:0a:0a:0a"
+
+source lib.sh
+
+
+add_del_to_port_down() {
+       RET=0
+
+       ip link set dev $swp2 down
+       bridge mdb add dev br0 port "$swp2" grp $TEST_GROUP permanent 2>/dev/null
+       check_err $? "Failed adding mdb entry"
+
+       ip link set dev $swp2 up
+       setup_wait_dev $swp2
+       mcast_packet_test $TEST_GROUP_MAC 192.0.2.1 $TEST_GROUP $h1 $h2
+       check_fail $? "Traffic to $TEST_GROUP wasn't forwarded"
+
+       ip link set dev $swp2 down
+       bridge mdb show dev br0 | grep -q "$TEST_GROUP permanent" 2>/dev/null
+       check_err $? "MDB entry did not persist after link up/down"
+
+       bridge mdb del dev br0 port "$swp2" grp $TEST_GROUP 2>/dev/null
+       check_err $? "Failed deleting mdb entry"
+
+       ip link set dev $swp2 up
+       setup_wait_dev $swp2
+       mcast_packet_test $TEST_GROUP_MAC 192.0.2.1 $TEST_GROUP $h1 $h2
+       check_err $? "Traffic to $TEST_GROUP was forwarded after entry removed"
+
+       log_test "MDB add/del entry to port with state down "
+}
+
+h1_create()
+{
+       simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
+}
+
+h1_destroy()
+{
+       simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
+}
+
+h2_create()
+{
+       simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
+}
+
+h2_destroy()
+{
+       simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
+}
+
+switch_create()
+{
+       # Enable multicast filtering
+       ip link add dev br0 type bridge mcast_snooping 1 mcast_querier 1
+
+       ip link set dev $swp1 master br0
+       ip link set dev $swp2 master br0
+
+       ip link set dev br0 up
+       ip link set dev $swp1 up
+
+       bridge link set dev $swp2 mcast_flood off
+       # Bridge currently has a "grace time" at creation time before it
+       # forwards multicast according to the mdb. Since we disable the
+       # mcast_flood setting per port
+       sleep 10
+}
+
+switch_destroy()
+{
+       ip link set dev $swp1 down
+       ip link set dev $swp2 down
+       ip link del dev br0
+}
+
+setup_prepare()
+{
+       h1=${NETIFS[p1]}
+       swp1=${NETIFS[p2]}
+
+       swp2=${NETIFS[p3]}
+       h2=${NETIFS[p4]}
+
+       vrf_prepare
+
+       h1_create
+       h2_create
+       switch_create
+}
+
+cleanup()
+{
+       pre_cleanup
+
+       switch_destroy
+       h1_destroy
+       h2_destroy
+
+       vrf_cleanup
+}
+
+trap cleanup EXIT
+
+setup_prepare
+tests_run
+exit $EXIT_STATUS
index 4b42dfd..072faa7 100755 (executable)
@@ -11,6 +11,8 @@ NUM_NETIFS=2
 source lib.sh
 source ethtool_lib.sh
 
+TIMEOUT=$((WAIT_TIMEOUT * 1000)) # ms
+
 setup_prepare()
 {
        swp1=${NETIFS[p1]}
@@ -18,7 +20,7 @@ setup_prepare()
        swp3=$NETIF_NO_CABLE
 }
 
-ethtool_extended_state_check()
+ethtool_ext_state()
 {
        local dev=$1; shift
        local expected_ext_state=$1; shift
@@ -30,21 +32,27 @@ ethtool_extended_state_check()
                | sed -e 's/^[[:space:]]*//')
        ext_state=$(echo $ext_state | cut -d "," -f1)
 
-       [[ $ext_state == $expected_ext_state ]]
-       check_err $? "Expected \"$expected_ext_state\", got \"$ext_state\""
-
-       [[ $ext_substate == $expected_ext_substate ]]
-       check_err $? "Expected \"$expected_ext_substate\", got \"$ext_substate\""
+       if [[ $ext_state != $expected_ext_state ]]; then
+               echo "Expected \"$expected_ext_state\", got \"$ext_state\""
+               return 1
+       fi
+       if [[ $ext_substate != $expected_ext_substate ]]; then
+               echo "Expected \"$expected_ext_substate\", got \"$ext_substate\""
+               return 1
+       fi
 }
 
 autoneg()
 {
+       local msg
+
        RET=0
 
        ip link set dev $swp1 up
 
-       sleep 4
-       ethtool_extended_state_check $swp1 "Autoneg" "No partner detected"
+       msg=$(busywait $TIMEOUT ethtool_ext_state $swp1 \
+                       "Autoneg" "No partner detected")
+       check_err $? "$msg"
 
        log_test "Autoneg, No partner detected"
 
@@ -53,6 +61,8 @@ autoneg()
 
 autoneg_force_mode()
 {
+       local msg
+
        RET=0
 
        ip link set dev $swp1 up
@@ -65,12 +75,13 @@ autoneg_force_mode()
        ethtool_set $swp1 speed $speed1 autoneg off
        ethtool_set $swp2 speed $speed2 autoneg off
 
-       sleep 4
-       ethtool_extended_state_check $swp1 "Autoneg" \
-               "No partner detected during force mode"
+       msg=$(busywait $TIMEOUT ethtool_ext_state $swp1 \
+                       "Autoneg" "No partner detected during force mode")
+       check_err $? "$msg"
 
-       ethtool_extended_state_check $swp2 "Autoneg" \
-               "No partner detected during force mode"
+       msg=$(busywait $TIMEOUT ethtool_ext_state $swp2 \
+                       "Autoneg" "No partner detected during force mode")
+       check_err $? "$msg"
 
        log_test "Autoneg, No partner detected during force mode"
 
@@ -83,12 +94,14 @@ autoneg_force_mode()
 
 no_cable()
 {
+       local msg
+
        RET=0
 
        ip link set dev $swp3 up
 
-       sleep 1
-       ethtool_extended_state_check $swp3 "No cable"
+       msg=$(busywait $TIMEOUT ethtool_ext_state $swp3 "No cable")
+       check_err $? "$msg"
 
        log_test "No cable"
 
index 28d568c..91e431c 100755 (executable)
@@ -141,12 +141,13 @@ switch_create()
        ip link set dev $swp4 up
 
        ip link add name br1 type bridge vlan_filtering 1
-       ip link set dev br1 up
-       __addr_add_del br1 add 192.0.2.129/32
-       ip -4 route add 192.0.2.130/32 dev br1
 
        team_create lag loadbalance $swp3 $swp4
        ip link set dev lag master br1
+
+       ip link set dev br1 up
+       __addr_add_del br1 add 192.0.2.129/32
+       ip -4 route add 192.0.2.130/32 dev br1
 }
 
 switch_destroy()
index 5d70b04..e71ec58 100644 (file)
@@ -235,6 +235,7 @@ FIXTURE_VARIANT(tls)
 {
        uint16_t tls_version;
        uint16_t cipher_type;
+       bool nopad;
 };
 
 FIXTURE_VARIANT_ADD(tls, 12_aes_gcm)
@@ -297,9 +298,17 @@ FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_256)
        .cipher_type = TLS_CIPHER_AES_GCM_256,
 };
 
+FIXTURE_VARIANT_ADD(tls, 13_nopad)
+{
+       .tls_version = TLS_1_3_VERSION,
+       .cipher_type = TLS_CIPHER_AES_GCM_128,
+       .nopad = true,
+};
+
 FIXTURE_SETUP(tls)
 {
        struct tls_crypto_info_keys tls12;
+       int one = 1;
        int ret;
 
        tls_crypto_info_init(variant->tls_version, variant->cipher_type,
@@ -315,6 +324,12 @@ FIXTURE_SETUP(tls)
 
        ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12, tls12.len);
        ASSERT_EQ(ret, 0);
+
+       if (variant->nopad) {
+               ret = setsockopt(self->cfd, SOL_TLS, TLS_RX_EXPECT_NO_PAD,
+                                (void *)&one, sizeof(one));
+               ASSERT_EQ(ret, 0);
+       }
 }
 
 FIXTURE_TEARDOWN(tls)
index d52f65d..9fe1cef 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 __pycache__/
 *.pyc
-plugins/
 *.xml
 *.tap
 tdc_config_local.py