aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/amt.c6
-rw-r--r--drivers/net/arcnet/arc-rawmode.c1
-rw-r--r--drivers/net/arcnet/arc-rimi.c1
-rw-r--r--drivers/net/arcnet/capmode.c1
-rw-r--r--drivers/net/arcnet/com20020-pci.c1
-rw-r--r--drivers/net/arcnet/com20020.c1
-rw-r--r--drivers/net/arcnet/com20020_cs.c1
-rw-r--r--drivers/net/arcnet/com90io.c1
-rw-r--r--drivers/net/arcnet/com90xx.c1
-rw-r--r--drivers/net/arcnet/rfc1051.c1
-rw-r--r--drivers/net/arcnet/rfc1201.c1
-rw-r--r--drivers/net/bonding/bond_alb.c3
-rw-r--r--drivers/net/bonding/bond_main.c36
-rw-r--r--drivers/net/can/c_can/c_can_platform.c13
-rw-r--r--drivers/net/can/dev/netlink.c2
-rw-r--r--drivers/net/can/flexcan/flexcan-core.c12
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c8
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c2
-rw-r--r--drivers/net/can/xilinx_can.c9
-rw-r--r--drivers/net/dsa/bcm_sf2.c7
-rw-r--r--drivers/net/dsa/bcm_sf2.h1
-rw-r--r--drivers/net/dsa/dsa_loop_bdinfo.c1
-rw-r--r--drivers/net/dsa/lantiq_gswip.c74
-rw-r--r--drivers/net/dsa/microchip/ksz8.h4
-rw-r--r--drivers/net/dsa/microchip/ksz8795.c156
-rw-r--r--drivers/net/dsa/microchip/ksz8795_reg.h3
-rw-r--r--drivers/net/dsa/microchip/ksz_common.c34
-rw-r--r--drivers/net/dsa/microchip/ksz_common.h21
-rw-r--r--drivers/net/dsa/mt7530.c5
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.c394
-rw-r--r--drivers/net/dsa/mv88e6xxx/chip.h31
-rw-r--r--drivers/net/dsa/mv88e6xxx/global1.c7
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.c10
-rw-r--r--drivers/net/dsa/mv88e6xxx/serdes.h8
-rw-r--r--drivers/net/dsa/qca/qca8k-8xxx.c50
-rw-r--r--drivers/net/dsa/qca/qca8k-common.c2
-rw-r--r--drivers/net/dsa/qca/qca8k-leds.c4
-rw-r--r--drivers/net/dsa/qca/qca8k.h1
-rw-r--r--drivers/net/dsa/realtek/rtl8365mb.c2
-rw-r--r--drivers/net/dsa/realtek/rtl8366-core.c2
-rw-r--r--drivers/net/dsa/realtek/rtl8366rb.c59
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c3
-rw-r--r--drivers/net/dsa/vitesse-vsc73xx-core.c10
-rw-r--r--drivers/net/ethernet/8390/8390.c1
-rw-r--r--drivers/net/ethernet/8390/8390p.c1
-rw-r--r--drivers/net/ethernet/8390/apne.c1
-rw-r--r--drivers/net/ethernet/8390/hydra.c1
-rw-r--r--drivers/net/ethernet/8390/stnic.c1
-rw-r--r--drivers/net/ethernet/8390/zorro8390.c1
-rw-r--r--drivers/net/ethernet/adi/Kconfig1
-rw-r--r--drivers/net/ethernet/amazon/ena/Makefile2
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_ethtool.c50
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.c693
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_netdev.h99
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_xdp.c468
-rw-r--r--drivers/net/ethernet/amazon/ena/ena_xdp.h151
-rw-r--r--drivers/net/ethernet/amd/pds_core/adminq.c64
-rw-r--r--drivers/net/ethernet/amd/pds_core/auxbus.c12
-rw-r--r--drivers/net/ethernet/amd/pds_core/core.c46
-rw-r--r--drivers/net/ethernet/amd/pds_core/core.h2
-rw-r--r--drivers/net/ethernet/amd/pds_core/debugfs.c4
-rw-r--r--drivers/net/ethernet/amd/pds_core/dev.c16
-rw-r--r--drivers/net/ethernet/amd/pds_core/devlink.c3
-rw-r--r--drivers/net/ethernet/amd/pds_core/fw.c3
-rw-r--r--drivers/net/ethernet/amd/pds_core/main.c32
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c33
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h2
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c31
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ptp.c32
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.c74
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_ring.h23
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/aq_vec.c23
-rw-r--r--drivers/net/ethernet/asix/ax88796c_main.c2
-rw-r--r--drivers/net/ethernet/asix/ax88796c_main.h8
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp.c6
-rw-r--r--drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c6
-rw-r--r--drivers/net/ethernet/broadcom/bcm4908_enet.c1
-rw-r--r--drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c1
-rw-r--r--drivers/net/ethernet/broadcom/bgmac-bcma.c1
-rw-r--r--drivers/net/ethernet/broadcom/bgmac-platform.c1
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c25
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c2682
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h503
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c10
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c740
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h521
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c38
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c8
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c10
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c39
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c22
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c12
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_ethtool.c2
-rw-r--r--drivers/net/ethernet/cadence/macb.h15
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c42
-rw-r--r--drivers/net/ethernet/cadence/macb_ptp.c28
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c2
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c2
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_core.c1
-rw-r--r--drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h5
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c31
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/adapter.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c9
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c24
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c1
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c25
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_vic.c3
-rw-r--r--drivers/net/ethernet/cortina/gemini.c15
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c3
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c28
-rw-r--r--drivers/net/ethernet/engleder/tsnep_main.c33
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c7
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c132
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c1
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_ethtool.c31
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc_pf.c3
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c7
-rw-r--r--drivers/net/ethernet/freescale/fman/fman_memac.c18
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c1
-rw-r--r--drivers/net/ethernet/fungible/funeth/funeth_ethtool.c48
-rw-r--r--drivers/net/ethernet/google/gve/gve.h8
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.c88
-rw-r--r--drivers/net/ethernet/google/gve/gve_adminq.h3
-rw-r--r--drivers/net/ethernet/google/gve/gve_dqo.h3
-rw-r--r--drivers/net/ethernet/google/gve/gve_ethtool.c2
-rw-r--r--drivers/net/ethernet/google/gve/gve_main.c17
-rw-r--r--drivers/net/ethernet/google/gve/gve_register.h9
-rw-r--r--drivers/net/ethernet/google/gve/gve_rx.c25
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx.c2
-rw-r--r--drivers/net/ethernet/google/gve/gve_tx_dqo.c37
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_ethtool.c82
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_enet.c2
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c23
-rw-r--r--drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c21
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_ethtool.c40
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h4
-rw-r--r--drivers/net/ethernet/intel/Kconfig11
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c46
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c23
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c3
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h3
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h20
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c7
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c18
-rw-r--r--drivers/net/ethernet/intel/e1000e/mac.c20
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c11
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c24
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c22
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c26
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pf.c7
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_vf.c10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h164
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.c229
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.h7
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c214
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_dcb.c287
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_dcb.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c32
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ddp.c4
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debug.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_diag.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c304
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c804
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_nvm.c24
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_prototype.h69
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c36
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_register.h11
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c139
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.h8
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h51
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c119
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_xsk.c7
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf.h5
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adminq.c86
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adminq.h7
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adv_rss.c8
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_adv_rss.h3
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_common.c42
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_ethtool.c101
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_fdir.c3
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c27
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_txrx.c21
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_virtchnl.c41
-rw-r--r--drivers/net/ethernet/intel/ice/Makefile5
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h30
-rw-r--r--drivers/net/ethernet/intel/ice/ice_adminq_cmd.h207
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c100
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c330
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb.c79
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_lib.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dcb_nl.c2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_debugfs.c667
-rw-r--r--drivers/net/ethernet/intel/ice/ice_devlink.c49
-rw-r--r--drivers/net/ethernet/intel/ice/ice_devlink.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_dpll.c123
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.c568
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch.h22
-rw-r--r--drivers/net/ethernet/intel/ice/ice_eswitch_br.c22
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c116
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c51
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fdir.c69
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flex_pipe.c52
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flex_pipe.h4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flex_type.h7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flow.c482
-rw-r--r--drivers/net/ethernet/intel/ice/ice_flow.h60
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fwlog.c470
-rw-r--r--drivers/net/ethernet/intel/ice/ice_fwlog.h79
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hw_autogen.h6
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hwmon.c126
-rw-r--r--drivers/net/ethernet/intel/ice/ice_hwmon.h15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lag.c32
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lag.h3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h412
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c372
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.h10
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c336
-rw-r--r--drivers/net/ethernet/intel/ice/ice_nvm.c15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_osdep.h2
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.c319
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp.h27
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_consts.h12
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.c444
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ptp_hw.h49
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.c195
-rw-r--r--drivers/net/ethernet/intel/ice/ice_repr.h9
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sched.c3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_sriov.c94
-rw-r--r--drivers/net/ethernet/intel/ice/ice_switch.c100
-rw-r--r--drivers/net/ethernet/intel/ice/ice_tc_lib.c45
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c44
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.h33
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx_lib.c207
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx_lib.h49
-rw-r--r--drivers/net/ethernet/intel/ice/ice_type.h44
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.c44
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib.h3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vf_lib_private.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl.c116
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c3
-rw-r--r--drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c48
-rw-r--r--drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c41
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.c30
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf.h7
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_ethtool.c53
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c67
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c7
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c70
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_virtchnl.c4
-rw-r--r--drivers/net/ethernet/intel/idpf/virtchnl2.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c29
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.c19
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c8
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_nvm.c18
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c17
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c44
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c48
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c5
-rw-r--r--drivers/net/ethernet/intel/igbvf/mbx.c1
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c33
-rw-r--r--drivers/net/ethernet/intel/igc/igc.h21
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.c6
-rw-r--r--drivers/net/ethernet/intel/igc/igc_base.h4
-rw-r--r--drivers/net/ethernet/intel/igc/igc_defines.h2
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ethtool.c33
-rw-r--r--drivers/net/ethernet/intel/igc/igc_i225.c6
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c88
-rw-r--r--drivers/net/ethernet/intel/igc/igc_phy.c11
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c50
-rw-r--r--drivers/net/ethernet/intel/igc/igc_regs.h5
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c38
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c61
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_common.c175
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c42
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c100
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c34
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c113
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c11
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h43
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c52
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c168
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ethtool.c27
-rw-r--r--drivers/net/ethernet/litex/litex_liteeth.c1
-rw-r--r--drivers/net/ethernet/marvell/mvmdio.c97
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c25
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c129
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/Makefile3
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c84
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c925
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_config.h48
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h4
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c86
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h173
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_main.c241
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_main.h65
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c449
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h167
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h13
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h416
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_rx.c12
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_rx.h34
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_tx.c5
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_tx.h99
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.c1
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/mbox.h74
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/npc.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rpm.c7
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.c9
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu.h42
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c9
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c25
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c82
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c726
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c137
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c96
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h2
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h17
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c14
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c81
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c3
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c127
-rw-r--r--drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c7
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c10
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed.c10
-rw-r--r--drivers/net/ethernet/mediatek/mtk_wed_wo.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c40
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/cmd.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/devlink.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/dpll.c109
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h37
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/params.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c30
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/qos.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c14
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/trap.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c87
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c82
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c26
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_common.c81
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c43
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c164
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rep.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_rx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_stats.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c29
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c46
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c36
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_core.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c54
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/health.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c21
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c78
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c38
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/port.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/vport.c21
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c26
-rw-r--r--drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/cmd.h11
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.h9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c119
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h103
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/resources.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h21
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c853
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c44
-rw-r--r--drivers/net/ethernet/micrel/ks8851_spi.c4
-rw-r--r--drivers/net/ethernet/microchip/lan743x_ethtool.c35
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.h2
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_lag.c9
-rw-r--r--drivers/net/ethernet/microchip/lan966x/lan966x_port.c5
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c2
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c4
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.c1
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_main.h1
-rw-r--r--drivers/net/ethernet/microchip/sparx5/sparx5_packet.c2
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c81
-rw-r--r--drivers/net/ethernet/microsoft/mana/hw_channel.c1
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c51
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c73
-rw-r--r--drivers/net/ethernet/neterion/s2io.c1
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/conntrack.c46
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/lag_conf.c13
-rw-r--r--drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfd3/dp.c9
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfdk/dp.c9
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_devlink.c8
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h40
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c200
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h16
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c537
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c6
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h6
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c90
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic.h2
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c50
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_debugfs.c3
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_dev.c74
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_dev.h8
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_ethtool.c33
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_fw.c5
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.c115
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_lif.h5
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_main.c47
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_stats.c4
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_txrx.c19
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_ethtool.c32
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c12
-rw-r--r--drivers/net/ethernet/qualcomm/qca_uart.c5
-rw-r--r--drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c2
-rw-r--r--drivers/net/ethernet/realtek/Kconfig7
-rw-r--r--drivers/net/ethernet/realtek/Makefile3
-rw-r--r--drivers/net/ethernet/realtek/r8169.h7
-rw-r--r--drivers/net/ethernet/realtek/r8169_firmware.c3
-rw-r--r--drivers/net/ethernet/realtek/r8169_leds.c157
-rw-r--r--drivers/net/ethernet/realtek/r8169_main.c216
-rw-r--r--drivers/net/ethernet/renesas/Kconfig12
-rw-r--r--drivers/net/ethernet/renesas/Makefile5
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c24
-rw-r--r--drivers/net/ethernet/renesas/rcar_gen4_ptp.c40
-rw-r--r--drivers/net/ethernet/renesas/rcar_gen4_ptp.h9
-rw-r--r--drivers/net/ethernet/renesas/rswitch.c381
-rw-r--r--drivers/net/ethernet/renesas/rswitch.h43
-rw-r--r--drivers/net/ethernet/sfc/ef10.c4
-rw-r--r--drivers/net/ethernet/sfc/ef100_ethtool.c3
-rw-r--r--drivers/net/ethernet/sfc/efx.c24
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c3
-rw-r--r--drivers/net/ethernet/sfc/ethtool_common.c126
-rw-r--r--drivers/net/ethernet/sfc/ethtool_common.h13
-rw-r--r--drivers/net/ethernet/sfc/falcon/ethtool.c26
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h2
-rw-r--r--drivers/net/ethernet/sfc/ptp.c30
-rw-r--r--drivers/net/ethernet/sfc/ptp.h7
-rw-r--r--drivers/net/ethernet/sfc/siena/efx.c24
-rw-r--r--drivers/net/ethernet/sfc/siena/ethtool.c3
-rw-r--r--drivers/net/ethernet/sfc/siena/ethtool_common.c126
-rw-r--r--drivers/net/ethernet/sfc/siena/ethtool_common.h13
-rw-r--r--drivers/net/ethernet/sfc/siena/net_driver.h2
-rw-r--r--drivers/net/ethernet/sfc/siena/ptp.c30
-rw-r--r--drivers/net/ethernet/sfc/siena/ptp.h7
-rw-r--r--drivers/net/ethernet/sfc/siena/siena.c2
-rw-r--r--drivers/net/ethernet/socionext/netsec.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h59
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.c137
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.h51
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c111
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c15
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.c21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h37
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc.h14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/mmc_core.c117
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h14
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_est.c165
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_est.h64
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c195
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c320
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c91
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c8
-rw-r--r--drivers/net/ethernet/ti/Kconfig15
-rw-r--r--drivers/net/ethernet/ti/Makefile3
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-ethtool.c272
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c283
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.h9
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-qos.c708
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-qos.h186
-rw-r--r--drivers/net/ethernet/ti/cpsw.c17
-rw-r--r--drivers/net/ethernet/ti/cpsw_new.c18
-rw-r--r--drivers/net/ethernet/ti/cpts.c17
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c16
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.c177
-rw-r--r--drivers/net/ethernet/toshiba/ps3_gelic_net.h30
-rw-r--r--drivers/net/ethernet/wangxun/Kconfig2
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_ethtool.c238
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_ethtool.h27
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_hw.c275
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_hw.h1
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_lib.c155
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_lib.h3
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_type.h94
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c82
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_main.c86
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c114
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.h1
-rw-r--r--drivers/net/ethernet/wangxun/ngbe/ngbe_type.h7
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c82
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_main.c63
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c57
-rw-r--r--drivers/net/ethernet/wangxun/txgbe/txgbe_type.h15
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig1
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet.h35
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c667
-rw-r--r--drivers/net/fddi/skfp/skfddi.c1
-rw-r--r--drivers/net/fjes/fjes_hw.c37
-rw-r--r--drivers/net/fjes/fjes_main.c6
-rw-r--r--drivers/net/geneve.c42
-rw-r--r--drivers/net/gtp.c14
-rw-r--r--drivers/net/hyperv/netvsc.c5
-rw-r--r--drivers/net/hyperv/netvsc_drv.c122
-rw-r--r--drivers/net/hyperv/rndis_filter.c1
-rw-r--r--drivers/net/ieee802154/fakelb.c6
-rw-r--r--drivers/net/ieee802154/mac802154_hwsim.c6
-rw-r--r--drivers/net/ipa/Makefile4
-rw-r--r--drivers/net/ipa/data/ipa_data-v5.5.c487
-rw-r--r--drivers/net/ipa/gsi_reg.c1
-rw-r--r--drivers/net/ipa/ipa_data.h1
-rw-r--r--drivers/net/ipa/ipa_interrupt.c2
-rw-r--r--drivers/net/ipa/ipa_main.c42
-rw-r--r--drivers/net/ipa/ipa_mem.c2
-rw-r--r--drivers/net/ipa/ipa_reg.c6
-rw-r--r--drivers/net/ipa/ipa_reg.h111
-rw-r--r--drivers/net/ipa/ipa_version.h1
-rw-r--r--drivers/net/ipa/reg/ipa_reg-v5.5.c565
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c15
-rw-r--r--drivers/net/ipvlan/ipvtap.c1
-rw-r--r--drivers/net/macsec.c126
-rw-r--r--drivers/net/macvlan.c15
-rw-r--r--drivers/net/mdio/mdio-bcm-unimac.c21
-rw-r--r--drivers/net/mdio/mdio-gpio.c4
-rw-r--r--drivers/net/mdio/mdio-mux-bcm-iproc.c6
-rw-r--r--drivers/net/mdio/mdio-mux.c14
-rw-r--r--drivers/net/netdevsim/dev.c8
-rw-r--r--drivers/net/netdevsim/macsec.c5
-rw-r--r--drivers/net/netdevsim/netdev.c9
-rw-r--r--drivers/net/pcs/pcs-rzn1-miic.c6
-rw-r--r--drivers/net/phy/Kconfig37
-rw-r--r--drivers/net/phy/Makefile19
-rw-r--r--drivers/net/phy/adin.c53
-rw-r--r--drivers/net/phy/aquantia.h16
-rw-r--r--drivers/net/phy/aquantia/Kconfig6
-rw-r--r--drivers/net/phy/aquantia/Makefile6
-rw-r--r--drivers/net/phy/aquantia/aquantia.h122
-rw-r--r--drivers/net/phy/aquantia/aquantia_firmware.c374
-rw-r--r--drivers/net/phy/aquantia/aquantia_hwmon.c (renamed from drivers/net/phy/aquantia_hwmon.c)14
-rw-r--r--drivers/net/phy/aquantia/aquantia_main.c (renamed from drivers/net/phy/aquantia_main.c)137
-rw-r--r--drivers/net/phy/at803x.c1092
-rw-r--r--drivers/net/phy/ax88796b_rust.rs135
-rw-r--r--drivers/net/phy/bcm-phy-ptp.c15
-rw-r--r--drivers/net/phy/bcm54140.c16
-rw-r--r--drivers/net/phy/bcm84881.c12
-rw-r--r--drivers/net/phy/broadcom.c2
-rw-r--r--drivers/net/phy/dp83640.c24
-rw-r--r--drivers/net/phy/dp83tg720.c188
-rw-r--r--drivers/net/phy/marvell10g.c203
-rw-r--r--drivers/net/phy/mdio_bus.c15
-rw-r--r--drivers/net/phy/mdio_device.c6
-rw-r--r--drivers/net/phy/mdio_devres.c1
-rw-r--r--drivers/net/phy/mediatek-ge-soc.c147
-rw-r--r--drivers/net/phy/micrel.c71
-rw-r--r--drivers/net/phy/mscc/mscc.h5
-rw-r--r--drivers/net/phy/mscc/mscc_main.c4
-rw-r--r--drivers/net/phy/mscc/mscc_ptp.c18
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx-macsec.c1729
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx.c94
-rw-r--r--drivers/net/phy/nxp-c45-tja11xx.h62
-rw-r--r--drivers/net/phy/nxp-tja11xx.c2
-rw-r--r--drivers/net/phy/phy-c45.c129
-rw-r--r--drivers/net/phy/phy-core.c204
-rw-r--r--drivers/net/phy/phy.c28
-rw-r--r--drivers/net/phy/phy_device.c47
-rw-r--r--drivers/net/phy/phylink.c324
-rw-r--r--drivers/net/phy/realtek.c4
-rw-r--r--drivers/net/phy/sfp-bus.c10
-rw-r--r--drivers/net/phy/sfp.c40
-rw-r--r--drivers/net/phy/smsc.c2
-rw-r--r--drivers/net/plip/plip.c1
-rw-r--r--drivers/net/ppp/bsd_comp.c1
-rw-r--r--drivers/net/ppp/ppp_async.c7
-rw-r--r--drivers/net/ppp/ppp_deflate.c1
-rw-r--r--drivers/net/ppp/ppp_generic.c1
-rw-r--r--drivers/net/ppp/ppp_synctty.c1
-rw-r--r--drivers/net/ppp/pppoe.c23
-rw-r--r--drivers/net/slip/slhc.c1
-rw-r--r--drivers/net/slip/slip.c1
-rw-r--r--drivers/net/tun.c11
-rw-r--r--drivers/net/usb/ax88179_178a.c2
-rw-r--r--drivers/net/usb/dm9601.c2
-rw-r--r--drivers/net/usb/hso.c11
-rw-r--r--drivers/net/usb/lan78xx.c10
-rw-r--r--drivers/net/usb/r8152.c16
-rw-r--r--drivers/net/usb/smsc95xx.c5
-rw-r--r--drivers/net/veth.c59
-rw-r--r--drivers/net/virtio_net.c335
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c32
-rw-r--r--drivers/net/vxlan/vxlan_core.c24
-rw-r--r--drivers/net/vxlan/vxlan_mdb.c174
-rw-r--r--drivers/net/vxlan/vxlan_private.h2
-rw-r--r--drivers/net/wan/Kconfig2
-rw-r--r--drivers/net/wan/Makefile2
-rw-r--r--drivers/net/wan/framer/Kconfig42
-rw-r--r--drivers/net/wan/framer/Makefile7
-rw-r--r--drivers/net/wan/framer/framer-core.c882
-rw-r--r--drivers/net/wan/framer/pef2256/Makefile8
-rw-r--r--drivers/net/wan/framer/pef2256/pef2256-regs.h250
-rw-r--r--drivers/net/wan/framer/pef2256/pef2256.c880
-rw-r--r--drivers/net/wan/fsl_ucc_hdlc.c6
-rw-r--r--drivers/net/wan/ixp4xx_hss.c5
-rw-r--r--drivers/net/wan/slic_ds26522.c1
-rw-r--r--drivers/net/wireless/Kconfig3
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/ath/ar5523/ar5523.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c17
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/coredump.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/coredump.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.h20
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c4
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h4
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c17
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/usb.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/wow.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.c10
-rw-r--r--drivers/net/wireless/ath/ath11k/ce.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/ce.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/core.h5
-rw-r--r--drivers/net/wireless/ath/ath11k/dbring.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/dbring.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/debug.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs.c26
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs.h13
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_sta.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_sta.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_tx.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_tx.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/fw.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/hal.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/hal.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/hal_desc.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/hal_rx.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/hal_rx.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/hif.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/htc.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/htc.h6
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c28
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/mhi.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/mhi.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/pcic.c6
-rw-r--r--drivers/net/wireless/ath/ath11k/peer.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/peer.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.h2
-rw-r--r--drivers/net/wireless/ath/ath11k/reg.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/reg.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/rx_desc.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/spectral.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/spectral.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/thermal.c1
-rw-r--r--drivers/net/wireless/ath/ath11k/thermal.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/trace.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.h63
-rw-r--r--drivers/net/wireless/ath/ath11k/wow.h1
-rw-r--r--drivers/net/wireless/ath/ath12k/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath12k/core.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/core.h5
-rw-r--r--drivers/net/wireless/ath/ath12k/dbring.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/dp.h13
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_mon.c15
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_mon.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.c151
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_rx.h8
-rw-r--r--drivers/net/wireless/ath/ath12k/dp_tx.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/hal.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/hal.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/hal_rx.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/hal_rx.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/hif.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.c5
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c190
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/mhi.c18
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.c174
-rw-r--r--drivers/net/wireless/ath/ath12k/pci.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/peer.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/qmi.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/qmi.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/reg.c21
-rw-r--r--drivers/net/wireless/ath/ath12k/reg.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/rx_desc.h2
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c2
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.h64
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c12
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c6
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c7
-rw-r--r--drivers/net/wireless/atmel/Kconfig35
-rw-r--r--drivers/net/wireless/atmel/Makefile4
-rw-r--r--drivers/net/wireless/atmel/atmel.c4452
-rw-r--r--drivers/net/wireless/atmel/atmel.h31
-rw-r--r--drivers/net/wireless/atmel/atmel_cs.c292
-rw-r--r--drivers/net/wireless/atmel/atmel_pci.c65
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c8
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c6
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c4
-rw-r--r--drivers/net/wireless/cisco/Kconfig59
-rw-r--r--drivers/net/wireless/cisco/Makefile3
-rw-r--r--drivers/net/wireless/cisco/airo.c8288
-rw-r--r--drivers/net/wireless/cisco/airo.h10
-rw-r--r--drivers/net/wireless/cisco/airo_cs.c218
-rw-r--r--drivers/net/wireless/intel/iwlegacy/4965-mac.c6
-rw-r--r--drivers/net/wireless/intel/iwlegacy/common.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/acpi.c15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/debug.h8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/api/txq.h12
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.c30
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/dbg.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/fw/file.h11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-config.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-csr.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c6
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h21
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-drv.c1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c23
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/iwl-trans.h31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/coex.c22
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/d3.c26
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c20
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c8
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c7
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c25
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c17
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mvm.h15
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/ops.c13
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c4
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/scan.c31
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c46
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/time-event.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c71
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/drv.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/rx.c3
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c10
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c47
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c34
-rw-r--r--drivers/net/wireless/intersil/Kconfig2
-rw-r--r--drivers/net/wireless/intersil/Makefile2
-rw-r--r--drivers/net/wireless/intersil/hostap/Kconfig95
-rw-r--r--drivers/net/wireless/intersil/hostap/Makefile8
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap.h98
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_80211.h97
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_80211_rx.c1116
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_80211_tx.c554
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_ap.c3277
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_ap.h264
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_common.h420
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_config.h49
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_cs.c710
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_download.c810
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_hw.c3387
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_info.c509
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_ioctl.c3847
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_main.c1123
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_pci.c445
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_plx.c617
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_proc.c411
-rw-r--r--drivers/net/wireless/intersil/hostap/hostap_wlan.h1051
-rw-r--r--drivers/net/wireless/intersil/orinoco/Kconfig143
-rw-r--r--drivers/net/wireless/intersil/orinoco/Makefile15
-rw-r--r--drivers/net/wireless/intersil/orinoco/airport.c268
-rw-r--r--drivers/net/wireless/intersil/orinoco/cfg.c291
-rw-r--r--drivers/net/wireless/intersil/orinoco/cfg.h15
-rw-r--r--drivers/net/wireless/intersil/orinoco/fw.c387
-rw-r--r--drivers/net/wireless/intersil/orinoco/fw.h21
-rw-r--r--drivers/net/wireless/intersil/orinoco/hermes.c778
-rw-r--r--drivers/net/wireless/intersil/orinoco/hermes.h534
-rw-r--r--drivers/net/wireless/intersil/orinoco/hermes_dld.c477
-rw-r--r--drivers/net/wireless/intersil/orinoco/hermes_dld.h52
-rw-r--r--drivers/net/wireless/intersil/orinoco/hermes_rid.h165
-rw-r--r--drivers/net/wireless/intersil/orinoco/hw.c1362
-rw-r--r--drivers/net/wireless/intersil/orinoco/hw.h60
-rw-r--r--drivers/net/wireless/intersil/orinoco/main.c2414
-rw-r--r--drivers/net/wireless/intersil/orinoco/main.h50
-rw-r--r--drivers/net/wireless/intersil/orinoco/mic.c89
-rw-r--r--drivers/net/wireless/intersil/orinoco/mic.h23
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco.h251
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_cs.c350
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_nortel.c314
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_pci.c257
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_pci.h54
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_plx.c362
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_tmd.c237
-rw-r--r--drivers/net/wireless/intersil/orinoco/orinoco_usb.c1787
-rw-r--r--drivers/net/wireless/intersil/orinoco/scan.c259
-rw-r--r--drivers/net/wireless/intersil/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/intersil/orinoco/spectrum_cs.c328
-rw-r--r--drivers/net/wireless/intersil/orinoco/wext.c1428
-rw-r--r--drivers/net/wireless/intersil/orinoco/wext.h13
-rw-r--r--drivers/net/wireless/intersil/p54/fwio.c2
-rw-r--r--drivers/net/wireless/intersil/p54/p54spi.c1
-rw-r--r--drivers/net/wireless/legacy/Kconfig55
-rw-r--r--drivers/net/wireless/legacy/Makefile6
-rw-r--r--drivers/net/wireless/legacy/ray_cs.c2824
-rw-r--r--drivers/net/wireless/legacy/ray_cs.h74
-rw-r--r--drivers/net/wireless/legacy/rayctl.h734
-rw-r--r--drivers/net/wireless/legacy/rndis_wlan.c3760
-rw-r--r--drivers/net/wireless/legacy/wl3501.h615
-rw-r--r--drivers/net/wireless/legacy/wl3501_cs.c2036
-rw-r--r--drivers/net/wireless/marvell/libertas/Kconfig9
-rw-r--r--drivers/net/wireless/marvell/libertas/Makefile1
-rw-r--r--drivers/net/wireless/marvell/libertas/if_cs.c957
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cfg80211.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/cmdevt.c8
-rw-r--r--drivers/net/wireless/marvell/mwifiex/fw.h1
-rw-r--r--drivers/net/wireless/marvell/mwifiex/ioctl.h1
-rw-r--r--drivers/net/wireless/marvell/mwifiex/join.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/main.h1
-rw-r--r--drivers/net/wireless/marvell/mwifiex/scan.c11
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sdio.c21
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sdio.h2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/sta_ioctl.c4
-rw-r--r--drivers/net/wireless/marvell/mwifiex/uap_cmd.c8
-rw-r--r--drivers/net/wireless/marvell/mwifiex/usb.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c258
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.h54
-rw-r--r--drivers/net/wireless/mediatek/mt76/eeprom.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c60
-rw-r--r--drivers/net/wireless/mediatek/mt76/mmio.c108
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h105
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/dma.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/main.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/soc.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mmio.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/soc.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac.h8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/pci.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_util.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/dma.c46
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c21
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mmio.c119
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/soc.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/init.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c39
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.c17
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/sdio.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/main.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mcu.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/pci.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x.h6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c53
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_core.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_mac.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/dma.c398
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c38
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/init.c520
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.c219
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/main.c89
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.c643
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.h253
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mmio.c296
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h160
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/pci.c79
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/regs.h182
-rw-r--r--drivers/net/wireless/mediatek/mt76/sdio.c19
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/util.c1
-rw-r--r--drivers/net/wireless/microchip/wilc1000/cfg80211.c24
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.c46
-rw-r--r--drivers/net/wireless/microchip/wilc1000/hif.h42
-rw-r--r--drivers/net/wireless/microchip/wilc1000/netdev.c1
-rw-r--r--drivers/net/wireless/microchip/wilc1000/sdio.c10
-rw-r--r--drivers/net/wireless/microchip/wilc1000/spi.c1
-rw-r--r--drivers/net/wireless/purelifi/plfxlc/usb.c5
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800.h4
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2800lib.c88
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00.h5
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00dev.c3
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00link.c2
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00mac.c11
-rw-r--r--drivers/net/wireless/ralink/rt2x00/rt2x00queue.c3
-rw-r--r--drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c12
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/base.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/pci.c99
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/pci.h25
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c14
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c16
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/phy.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c15
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c11
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c16
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c15
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c12
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c76
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c25
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/wifi.h24
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.c6
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.h6
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c4
-rw-r--r--drivers/net/wireless/realtek/rtw88/mac80211.c4
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c5
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h12
-rw-r--r--drivers/net/wireless/realtek/rtw88/sdio.c35
-rw-r--r--drivers/net/wireless/realtek/rtw88/tx.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/acpi.c81
-rw-r--r--drivers/net/wireless/realtek/rtw89/acpi.h32
-rw-r--r--drivers/net/wireless/realtek/rtw89/cam.c16
-rw-r--r--drivers/net/wireless/realtek/rtw89/coex.c652
-rw-r--r--drivers/net/wireless/realtek/rtw89/coex.h38
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.c107
-rw-r--r--drivers/net/wireless/realtek/rtw89/core.h149
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.c70
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.h19
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.c11
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse.h17
-rw-r--r--drivers/net/wireless/realtek/rtw89/efuse_be.c420
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.c175
-rw-r--r--drivers/net/wireless/realtek/rtw89/fw.h154
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.c853
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac.h150
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac80211.c21
-rw-r--r--drivers/net/wireless/realtek/rtw89/mac_be.c1841
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.c345
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci.h519
-rw-r--r--drivers/net/wireless/realtek/rtw89/pci_be.c509
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.c511
-rw-r--r--drivers/net/wireless/realtek/rtw89/phy.h49
-rw-r--r--drivers/net/wireless/realtek/rtw89/ps.h4
-rw-r--r--drivers/net/wireless/realtek/rtw89/reg.h3212
-rw-r--r--drivers/net/wireless/realtek/rtw89/regd.c175
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851b.c27
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8851be.c3
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852a.c27
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852ae.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852b.c27
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852be.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c.c51
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852c.h20
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8852ce.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a.c710
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922a.h73
-rw-r--r--drivers/net/wireless/realtek/rtw89/rtw8922ae.c88
-rw-r--r--drivers/net/wireless/realtek/rtw89/sar.c4
-rw-r--r--drivers/net/wireless/realtek/rtw89/ser.c16
-rw-r--r--drivers/net/wireless/realtek/rtw89/txrx.h4
-rw-r--r--drivers/net/wireless/realtek/rtw89/wow.c7
-rw-r--r--drivers/net/wireless/silabs/wfx/sta.c42
-rw-r--r--drivers/net/wireless/ti/wl1251/sdio.c1
-rw-r--r--drivers/net/wireless/ti/wl1251/spi.c1
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c1
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/sdio.c1
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c1
-rw-r--r--drivers/net/wireless/virtual/mac80211_hwsim.c25
-rw-r--r--drivers/net/wireless/zydas/Kconfig19
-rw-r--r--drivers/net/wireless/zydas/Makefile2
-rw-r--r--drivers/net/wireless/zydas/zd1201.c1909
-rw-r--r--drivers/net/wireless/zydas/zd1201.h144
-rw-r--r--drivers/net/wwan/qcom_bam_dmux.c6
-rw-r--r--drivers/net/xen-netback/netback.c107
1114 files changed, 48578 insertions, 73075 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index af0da4bb429b..8ca0bc223b30 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -434,6 +434,7 @@ config VIRTIO_NET
tristate "Virtio network driver"
depends on VIRTIO
select NET_FAILOVER
+ select DIMLIB
help
This is the virtual network driver for virtio. It can be used with
QEMU based VMMs (like KVM or Xen). Say Y or M.
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 53415e83821c..68e79b1272f6 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -11,7 +11,7 @@
#include <linux/net.h>
#include <linux/igmp.h>
#include <linux/workqueue.h>
-#include <net/sch_generic.h>
+#include <net/pkt_sched.h>
#include <net/net_namespace.h>
#include <net/ip.h>
#include <net/udp.h>
@@ -80,11 +80,11 @@ static struct mld2_grec mldv2_zero_grec;
static struct amt_skb_cb *amt_skb_cb(struct sk_buff *skb)
{
- BUILD_BUG_ON(sizeof(struct amt_skb_cb) + sizeof(struct qdisc_skb_cb) >
+ BUILD_BUG_ON(sizeof(struct amt_skb_cb) + sizeof(struct tc_skb_cb) >
sizeof_field(struct sk_buff, cb));
return (struct amt_skb_cb *)((void *)skb->cb +
- sizeof(struct qdisc_skb_cb));
+ sizeof(struct tc_skb_cb));
}
static void __amt_source_gc_work(void)
diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c
index 8c651fdee039..57f1729066f2 100644
--- a/drivers/net/arcnet/arc-rawmode.c
+++ b/drivers/net/arcnet/arc-rawmode.c
@@ -186,4 +186,5 @@ static void __exit arcnet_raw_exit(void)
module_init(arcnet_raw_init);
module_exit(arcnet_raw_exit);
+MODULE_DESCRIPTION("ARCnet raw mode packet interface module");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
index 8c3ccc7c83cd..53d10a04d1bd 100644
--- a/drivers/net/arcnet/arc-rimi.c
+++ b/drivers/net/arcnet/arc-rimi.c
@@ -312,6 +312,7 @@ module_param(node, int, 0);
module_param(io, int, 0);
module_param(irq, int, 0);
module_param_string(device, device, sizeof(device), 0);
+MODULE_DESCRIPTION("ARCnet COM90xx RIM I chipset driver");
MODULE_LICENSE("GPL");
static struct net_device *my_dev;
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
index c09b567845e1..7a0a79973769 100644
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -265,4 +265,5 @@ static void __exit capmode_module_exit(void)
module_init(capmode_module_init);
module_exit(capmode_module_exit);
+MODULE_DESCRIPTION("ARCnet CAP mode packet interface module");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 7b5c8bb02f11..c5e571ec94c9 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -61,6 +61,7 @@ module_param(timeout, int, 0);
module_param(backplane, int, 0);
module_param(clockp, int, 0);
module_param(clockm, int, 0);
+MODULE_DESCRIPTION("ARCnet COM20020 chipset PCI driver");
MODULE_LICENSE("GPL");
static void led_tx_set(struct led_classdev *led_cdev,
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c
index 06e1651b594b..a0053e3992a3 100644
--- a/drivers/net/arcnet/com20020.c
+++ b/drivers/net/arcnet/com20020.c
@@ -399,6 +399,7 @@ EXPORT_SYMBOL(com20020_found);
EXPORT_SYMBOL(com20020_netdev_ops);
#endif
+MODULE_DESCRIPTION("ARCnet COM20020 chipset core driver");
MODULE_LICENSE("GPL");
#ifdef MODULE
diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c
index dc3253b318da..75f08aa7528b 100644
--- a/drivers/net/arcnet/com20020_cs.c
+++ b/drivers/net/arcnet/com20020_cs.c
@@ -97,6 +97,7 @@ module_param(backplane, int, 0);
module_param(clockp, int, 0);
module_param(clockm, int, 0);
+MODULE_DESCRIPTION("ARCnet COM20020 chipset PCMCIA driver");
MODULE_LICENSE("GPL");
/*====================================================================*/
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 37b47749fc8b..3b463fbc6402 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -350,6 +350,7 @@ static char device[9]; /* use eg. device=arc1 to change name */
module_param_hw(io, int, ioport, 0);
module_param_hw(irq, int, irq, 0);
module_param_string(device, device, sizeof(device), 0);
+MODULE_DESCRIPTION("ARCnet COM90xx IO mapped chipset driver");
MODULE_LICENSE("GPL");
#ifndef MODULE
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index f49dae194284..b3b287c16561 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -645,6 +645,7 @@ static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count));
}
+MODULE_DESCRIPTION("ARCnet COM90xx normal chipset driver");
MODULE_LICENSE("GPL");
static int __init com90xx_init(void)
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
index a7752a5b647f..46519ca63a0a 100644
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -78,6 +78,7 @@ static void __exit arcnet_rfc1051_exit(void)
module_init(arcnet_rfc1051_init);
module_exit(arcnet_rfc1051_exit);
+MODULE_DESCRIPTION("ARCNet packet format (RFC 1051) module");
MODULE_LICENSE("GPL");
/* Determine a packet's protocol ID.
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index a4c856282674..0edf35d971c5 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -35,6 +35,7 @@
#include "arcdevice.h"
+MODULE_DESCRIPTION("ARCNet packet format (RFC 1201) module");
MODULE_LICENSE("GPL");
static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index dc2c7b979656..7edf0fd58c34 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -985,7 +985,8 @@ static int alb_upper_dev_walk(struct net_device *upper,
if (netif_is_macvlan(upper) && !strict_match) {
tags = bond_verify_device_path(bond->dev, upper, 0);
if (IS_ERR_OR_NULL(tags))
- BUG();
+ return -ENOMEM;
+
alb_send_lp_vid(slave, upper->dev_addr,
tags[0].vlan_proto, tags[0].vlan_id);
kfree(tags);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8e6cc0e133b7..cd0683bcca03 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1811,7 +1811,7 @@ void bond_xdp_set_features(struct net_device *bond_dev)
ASSERT_RTNL();
- if (!bond_xdp_check(bond)) {
+ if (!bond_xdp_check(bond) || !bond_has_slaves(bond)) {
xdp_clear_features_flag(bond_dev);
return;
}
@@ -1819,6 +1819,8 @@ void bond_xdp_set_features(struct net_device *bond_dev)
bond_for_each_slave(bond, slave, iter)
val &= slave->dev->xdp_features;
+ val &= ~NETDEV_XDP_ACT_XSK_ZEROCOPY;
+
xdp_set_features_flag(bond_dev, val);
}
@@ -5755,10 +5757,8 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
{
struct bonding *bond = netdev_priv(bond_dev);
struct ethtool_ts_info ts_info;
- const struct ethtool_ops *ops;
struct net_device *real_dev;
bool sw_tx_support = false;
- struct phy_device *phydev;
struct list_head *iter;
struct slave *slave;
int ret = 0;
@@ -5769,29 +5769,12 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
rcu_read_unlock();
if (real_dev) {
- ops = real_dev->ethtool_ops;
- phydev = real_dev->phydev;
-
- if (phy_has_tsinfo(phydev)) {
- ret = phy_ts_info(phydev, info);
- goto out;
- } else if (ops->get_ts_info) {
- ret = ops->get_ts_info(real_dev, info);
- goto out;
- }
+ ret = ethtool_get_ts_info_by_layer(real_dev, info);
} else {
/* Check if all slaves support software tx timestamping */
rcu_read_lock();
bond_for_each_slave_rcu(bond, slave, iter) {
- ret = -1;
- ops = slave->dev->ethtool_ops;
- phydev = slave->dev->phydev;
-
- if (phy_has_tsinfo(phydev))
- ret = phy_ts_info(phydev, &ts_info);
- else if (ops->get_ts_info)
- ret = ops->get_ts_info(slave->dev, &ts_info);
-
+ ret = ethtool_get_ts_info_by_layer(slave->dev, &ts_info);
if (!ret && (ts_info.so_timestamping & SOF_TIMESTAMPING_TX_SOFTWARE)) {
sw_tx_support = true;
continue;
@@ -5803,15 +5786,9 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
rcu_read_unlock();
}
- ret = 0;
- info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE;
if (sw_tx_support)
info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE;
- info->phc_index = -1;
-
-out:
dev_put(real_dev);
return ret;
}
@@ -5934,9 +5911,6 @@ void bond_setup(struct net_device *bond_dev)
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
bond_dev->features |= BOND_XFRM_FEATURES;
#endif /* CONFIG_XFRM_OFFLOAD */
-
- if (bond_xdp_check(bond))
- bond_dev->xdp_features = NETDEV_XDP_ACT_MASK;
}
/* Destroy a bonding device.
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index f44ba2600415..e2ec69aa46e5 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -30,9 +30,9 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/clk.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -259,22 +259,13 @@ static int c_can_plat_probe(struct platform_device *pdev)
void __iomem *addr;
struct net_device *dev;
struct c_can_priv *priv;
- const struct of_device_id *match;
struct resource *mem;
int irq;
struct clk *clk;
const struct c_can_driver_data *drvdata;
struct device_node *np = pdev->dev.of_node;
- match = of_match_device(c_can_of_table, &pdev->dev);
- if (match) {
- drvdata = match->data;
- } else if (pdev->id_entry->driver_data) {
- drvdata = (struct c_can_driver_data *)
- platform_get_device_id(pdev)->driver_data;
- } else {
- return -ENODEV;
- }
+ drvdata = device_get_match_data(&pdev->dev);
/* get the appropriate clk */
clk = devm_clk_get(&pdev->dev, NULL);
diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c
index 036d85ef07f5..dfdc039d92a6 100644
--- a/drivers/net/can/dev/netlink.c
+++ b/drivers/net/can/dev/netlink.c
@@ -346,7 +346,7 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
/* Neither of TDC parameters nor TDC flags are
* provided: do calculation
*/
- can_calc_tdco(&priv->tdc, priv->tdc_const, &priv->data_bittiming,
+ can_calc_tdco(&priv->tdc, priv->tdc_const, &dbt,
&priv->ctrlmode, priv->ctrlmode_supported);
} /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly
* turned off. TDC is disabled: do nothing
diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c
index d15f85a40c1e..8ea7f2795551 100644
--- a/drivers/net/can/flexcan/flexcan-core.c
+++ b/drivers/net/can/flexcan/flexcan-core.c
@@ -23,11 +23,11 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/can/platform/flexcan.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -2034,7 +2034,6 @@ MODULE_DEVICE_TABLE(platform, flexcan_id_table);
static int flexcan_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id;
const struct flexcan_devtype_data *devtype_data;
struct net_device *dev;
struct flexcan_priv *priv;
@@ -2090,14 +2089,7 @@ static int flexcan_probe(struct platform_device *pdev)
if (IS_ERR(regs))
return PTR_ERR(regs);
- of_id = of_match_device(flexcan_of_match, &pdev->dev);
- if (of_id)
- devtype_data = of_id->data;
- else if (platform_get_device_id(pdev)->driver_data)
- devtype_data = (struct flexcan_devtype_data *)
- platform_get_device_id(pdev)->driver_data;
- else
- return -ENODEV;
+ devtype_data = device_get_match_data(&pdev->dev);
if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) &&
!((devtype_data->quirks &
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 4837df6efa92..5b3d69c3b6b6 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -12,8 +12,10 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/netdevice.h>
#include <linux/can/dev.h>
+#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -290,7 +292,7 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
int irq, mscan_clksrc = 0;
int err = -ENOMEM;
- data = of_device_get_match_data(&ofdev->dev);
+ data = device_get_match_data(&ofdev->dev);
if (!data)
return -EINVAL;
@@ -351,13 +353,11 @@ exit_unmap_mem:
static void mpc5xxx_can_remove(struct platform_device *ofdev)
{
- const struct of_device_id *match;
const struct mpc5xxx_can_data *data;
struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
- match = of_match_device(mpc5xxx_can_table, &ofdev->dev);
- data = match ? match->data : NULL;
+ data = device_get_match_data(&ofdev->dev);
unregister_mscandev(dev);
if (data && data->put_clock)
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index 24ad9f593a77..1efa39e134f4 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -1143,7 +1143,7 @@ static void __exit peak_usb_exit(void)
int err;
/* last chance do send any synchronous commands here */
- err = driver_for_each_device(&peak_usb_driver.drvwrap.driver, NULL,
+ err = driver_for_each_device(&peak_usb_driver.driver, NULL,
NULL, peak_usb_do_device_exit);
if (err)
pr_err("%s: failed to stop all can devices (err %d)\n",
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index abe58f103043..3722eaa84234 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -20,8 +20,8 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -1726,8 +1726,7 @@ static int xcan_probe(struct platform_device *pdev)
struct net_device *ndev;
struct xcan_priv *priv;
struct phy *transceiver;
- const struct of_device_id *of_id;
- const struct xcan_devtype_data *devtype = &xcan_axi_data;
+ const struct xcan_devtype_data *devtype;
void __iomem *addr;
int ret;
int rx_max, tx_max;
@@ -1741,9 +1740,7 @@ static int xcan_probe(struct platform_device *pdev)
goto err;
}
- of_id = of_match_device(xcan_of_match, &pdev->dev);
- if (of_id && of_id->data)
- devtype = of_id->data;
+ devtype = device_get_match_data(&pdev->dev);
hw_tx_max_property = devtype->flags & XCAN_FLAG_TX_MAILBOXES ?
"tx-mailbox-count" : "tx-fifo-depth";
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index cadee5505c29..4a52ccbe393f 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -621,8 +621,6 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
goto err_of_node_put;
}
- priv->master_mii_dn = dn;
-
priv->user_mii_bus = mdiobus_alloc();
if (!priv->user_mii_bus) {
err = -ENOMEM;
@@ -635,7 +633,6 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
priv->user_mii_bus->write = bcm_sf2_sw_mdio_write;
snprintf(priv->user_mii_bus->id, MII_BUS_ID_SIZE, "sf2-%d",
index++);
- priv->user_mii_bus->dev.of_node = dn;
/* Include the pseudo-PHY address to divert reads towards our
* workaround. This is only required for 7445D0, since 7445E0
@@ -683,9 +680,11 @@ static int bcm_sf2_mdio_register(struct dsa_switch *ds)
}
err = mdiobus_register(priv->user_mii_bus);
- if (err && dn)
+ if (err)
goto err_free_user_mii_bus;
+ of_node_put(dn);
+
return 0;
err_free_user_mii_bus:
diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h
index 424f896b5a6f..f95f4880b69e 100644
--- a/drivers/net/dsa/bcm_sf2.h
+++ b/drivers/net/dsa/bcm_sf2.h
@@ -107,7 +107,6 @@ struct bcm_sf2_priv {
/* Master and slave MDIO bus controller */
unsigned int indir_phy_mask;
- struct device_node *master_mii_dn;
struct mii_bus *user_mii_bus;
struct mii_bus *master_mii_bus;
diff --git a/drivers/net/dsa/dsa_loop_bdinfo.c b/drivers/net/dsa/dsa_loop_bdinfo.c
index 237066d30704..14ca42491512 100644
--- a/drivers/net/dsa/dsa_loop_bdinfo.c
+++ b/drivers/net/dsa/dsa_loop_bdinfo.c
@@ -32,4 +32,5 @@ static int __init dsa_loop_bdinfo_init(void)
}
arch_initcall(dsa_loop_bdinfo_init)
+MODULE_DESCRIPTION("DSA mock-up switch driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c
index 9c185c9f0963..de48b194048f 100644
--- a/drivers/net/dsa/lantiq_gswip.c
+++ b/drivers/net/dsa/lantiq_gswip.c
@@ -505,27 +505,34 @@ static int gswip_mdio_rd(struct mii_bus *bus, int addr, int reg)
return gswip_mdio_r(priv, GSWIP_MDIO_READ);
}
-static int gswip_mdio(struct gswip_priv *priv, struct device_node *mdio_np)
+static int gswip_mdio(struct gswip_priv *priv)
{
- struct dsa_switch *ds = priv->ds;
- int err;
+ struct device_node *mdio_np, *switch_np = priv->dev->of_node;
+ struct device *dev = priv->dev;
+ struct mii_bus *bus;
+ int err = 0;
- ds->user_mii_bus = mdiobus_alloc();
- if (!ds->user_mii_bus)
- return -ENOMEM;
+ mdio_np = of_get_compatible_child(switch_np, "lantiq,xrx200-mdio");
+ if (!of_device_is_available(mdio_np))
+ goto out_put_node;
- ds->user_mii_bus->priv = priv;
- ds->user_mii_bus->read = gswip_mdio_rd;
- ds->user_mii_bus->write = gswip_mdio_wr;
- ds->user_mii_bus->name = "lantiq,xrx200-mdio";
- snprintf(ds->user_mii_bus->id, MII_BUS_ID_SIZE, "%s-mii",
- dev_name(priv->dev));
- ds->user_mii_bus->parent = priv->dev;
- ds->user_mii_bus->phy_mask = ~ds->phys_mii_mask;
+ bus = devm_mdiobus_alloc(dev);
+ if (!bus) {
+ err = -ENOMEM;
+ goto out_put_node;
+ }
- err = of_mdiobus_register(ds->user_mii_bus, mdio_np);
- if (err)
- mdiobus_free(ds->user_mii_bus);
+ bus->priv = priv;
+ bus->read = gswip_mdio_rd;
+ bus->write = gswip_mdio_wr;
+ bus->name = "lantiq,xrx200-mdio";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(priv->dev));
+ bus->parent = priv->dev;
+
+ err = devm_of_mdiobus_register(dev, bus, mdio_np);
+
+out_put_node:
+ of_node_put(mdio_np);
return err;
}
@@ -1759,7 +1766,7 @@ static void gswip_get_strings(struct dsa_switch *ds, int port, u32 stringset,
return;
for (i = 0; i < ARRAY_SIZE(gswip_rmon_cnt); i++)
- ethtool_sprintf(&data, "%s", gswip_rmon_cnt[i].name);
+ ethtool_puts(&data, gswip_rmon_cnt[i].name);
}
static u32 gswip_bcm_ram_entry_read(struct gswip_priv *priv, u32 table,
@@ -2094,9 +2101,9 @@ remove_gphy:
static int gswip_probe(struct platform_device *pdev)
{
- struct gswip_priv *priv;
- struct device_node *np, *mdio_np, *gphy_fw_np;
+ struct device_node *np, *gphy_fw_np;
struct device *dev = &pdev->dev;
+ struct gswip_priv *priv;
int err;
int i;
u32 version;
@@ -2163,19 +2170,16 @@ static int gswip_probe(struct platform_device *pdev)
}
/* bring up the mdio bus */
- mdio_np = of_get_compatible_child(dev->of_node, "lantiq,xrx200-mdio");
- if (mdio_np) {
- err = gswip_mdio(priv, mdio_np);
- if (err) {
- dev_err(dev, "mdio probe failed\n");
- goto put_mdio_node;
- }
+ err = gswip_mdio(priv);
+ if (err) {
+ dev_err(dev, "mdio probe failed\n");
+ goto gphy_fw_remove;
}
err = dsa_register_switch(priv->ds);
if (err) {
dev_err(dev, "dsa switch register failed: %i\n", err);
- goto mdio_bus;
+ goto gphy_fw_remove;
}
if (!dsa_is_cpu_port(priv->ds, priv->hw_info->cpu_port)) {
dev_err(dev, "wrong CPU port defined, HW only supports port: %i",
@@ -2194,13 +2198,7 @@ static int gswip_probe(struct platform_device *pdev)
disable_switch:
gswip_mdio_mask(priv, GSWIP_MDIO_GLOB_ENABLE, 0, GSWIP_MDIO_GLOB);
dsa_unregister_switch(priv->ds);
-mdio_bus:
- if (mdio_np) {
- mdiobus_unregister(priv->ds->user_mii_bus);
- mdiobus_free(priv->ds->user_mii_bus);
- }
-put_mdio_node:
- of_node_put(mdio_np);
+gphy_fw_remove:
for (i = 0; i < priv->num_gphy_fw; i++)
gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
return err;
@@ -2219,12 +2217,6 @@ static void gswip_remove(struct platform_device *pdev)
dsa_unregister_switch(priv->ds);
- if (priv->ds->user_mii_bus) {
- mdiobus_unregister(priv->ds->user_mii_bus);
- of_node_put(priv->ds->user_mii_bus->dev.of_node);
- mdiobus_free(priv->ds->user_mii_bus);
- }
-
for (i = 0; i < priv->num_gphy_fw; i++)
gswip_gphy_fw_remove(priv, &priv->gphy_fw[i]);
}
diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h
index 4cea811e73ac..1a5225264e6a 100644
--- a/drivers/net/dsa/microchip/ksz8.h
+++ b/drivers/net/dsa/microchip/ksz8.h
@@ -56,5 +56,9 @@ int ksz8_reset_switch(struct ksz_device *dev);
int ksz8_switch_init(struct ksz_device *dev);
void ksz8_switch_exit(struct ksz_device *dev);
int ksz8_change_mtu(struct ksz_device *dev, int port, int mtu);
+void ksz8_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);
#endif
diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c
index 4bf4d67557dc..c3da97abce20 100644
--- a/drivers/net/dsa/microchip/ksz8795.c
+++ b/drivers/net/dsa/microchip/ksz8795.c
@@ -49,9 +49,9 @@ static int ksz8_ind_write8(struct ksz_device *dev, u8 table, u16 addr, u8 data)
mutex_lock(&dev->alu_mutex);
ctrl_addr = IND_ACC_TABLE(table) | addr;
- ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
+ ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
if (!ret)
- ret = ksz_write16(dev, regs[REG_IND_CTRL_0], ctrl_addr);
+ ret = ksz_write8(dev, regs[REG_IND_BYTE], data);
mutex_unlock(&dev->alu_mutex);
@@ -1358,6 +1358,9 @@ static void ksz8795_cpu_interface_select(struct ksz_device *dev, int port)
{
struct ksz_port *p = &dev->ports[port];
+ if (!ksz_is_ksz87xx(dev))
+ return;
+
if (!p->interface && dev->compat_interface) {
dev_warn(dev->dev,
"Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
@@ -1391,18 +1394,29 @@ void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
/* enable 802.1p priority */
ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_ENABLE, true);
- if (cpu_port) {
- if (!ksz_is_ksz88x3(dev))
- ksz8795_cpu_interface_select(dev, port);
-
+ if (cpu_port)
member = dsa_user_ports(ds);
- } else {
+ else
member = BIT(dsa_upstream_port(ds, port));
- }
ksz8_cfg_port_member(dev, port, member);
}
+static void ksz88x3_config_rmii_clk(struct ksz_device *dev)
+{
+ struct dsa_port *cpu_dp = dsa_to_port(dev->ds, dev->cpu_port);
+ bool rmii_clk_internal;
+
+ if (!ksz_is_ksz88x3(dev))
+ return;
+
+ rmii_clk_internal = of_property_read_bool(cpu_dp->dn,
+ "microchip,rmii-clk-internal");
+
+ ksz_cfg(dev, KSZ88X3_REG_FVID_AND_HOST_MODE,
+ KSZ88X3_PORT3_RMII_CLK_INTERNAL, rmii_clk_internal);
+}
+
void ksz8_config_cpu_port(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
@@ -1419,6 +1433,9 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
ksz8_port_setup(dev, dev->cpu_port, true);
+ ksz8795_cpu_interface_select(dev, dev->cpu_port);
+ ksz88x3_config_rmii_clk(dev);
+
for (i = 0; i < dev->phy_port_cnt; i++) {
ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
}
@@ -1439,6 +1456,127 @@ void ksz8_config_cpu_port(struct dsa_switch *ds)
}
}
+/**
+ * ksz8_phy_port_link_up - Configures ports with integrated PHYs
+ * @dev: The KSZ device instance.
+ * @port: The port number to configure.
+ * @duplex: The desired duplex mode.
+ * @tx_pause: If true, enables transmit pause.
+ * @rx_pause: If true, enables receive pause.
+ *
+ * Description:
+ * The function configures flow control settings for a given port based on the
+ * desired settings and current duplex mode.
+ *
+ * According to the KSZ8873 datasheet, the PORT_FORCE_FLOW_CTRL bit in the
+ * Port Control 2 register (0x1A for Port 1, 0x22 for Port 2, 0x32 for Port 3)
+ * determines how flow control is handled on the port:
+ * "1 = will always enable full-duplex flow control on the port, regardless
+ * of AN result.
+ * 0 = full-duplex flow control is enabled based on AN result."
+ *
+ * This means that the flow control behavior depends on the state of this bit:
+ * - If PORT_FORCE_FLOW_CTRL is set to 1, the switch will ignore AN results and
+ * force flow control on the port.
+ * - If PORT_FORCE_FLOW_CTRL is set to 0, the switch will enable or disable
+ * flow control based on the AN results.
+ *
+ * However, there is a potential limitation in this configuration. It is
+ * currently not possible to force disable flow control on a port if we still
+ * advertise pause support. While such a configuration is not currently
+ * supported by Linux, and may not make practical sense, it's important to be
+ * aware of this limitation when working with the KSZ8873 and similar devices.
+ */
+static void ksz8_phy_port_link_up(struct ksz_device *dev, int port, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ const u16 *regs = dev->info->regs;
+ u8 sctrl = 0;
+
+ /* The KSZ8795 switch differs from the KSZ8873 by supporting
+ * asymmetric pause control. However, since a single bit is used to
+ * control both RX and TX pause, we can't enforce asymmetric pause
+ * control - both TX and RX pause will be either enabled or disabled
+ * together.
+ *
+ * If auto-negotiation is enabled, we usually allow the flow control to
+ * be determined by the auto-negotiation process based on the
+ * capabilities of both link partners. However, for KSZ8873, the
+ * PORT_FORCE_FLOW_CTRL bit may be set by the hardware bootstrap,
+ * ignoring the auto-negotiation result. Thus, even in auto-negotiation
+ * mode, we need to ensure that the PORT_FORCE_FLOW_CTRL bit is
+ * properly cleared.
+ *
+ * In the absence of pause auto-negotiation, we will enforce symmetric
+ * pause control for both variants of switches - KSZ8873 and KSZ8795.
+ *
+ * Autoneg Pause Autoneg rx,tx PORT_FORCE_FLOW_CTRL
+ * 1 1 x 0
+ * 0 1 x 0 (flow control probably disabled)
+ * x 0 1 1 (flow control force enabled)
+ * 1 0 0 0 (flow control still depends on
+ * aneg result due to hardware)
+ * 0 0 0 0 (flow control probably disabled)
+ */
+ if (dev->ports[port].manual_flow && tx_pause)
+ sctrl |= PORT_FORCE_FLOW_CTRL;
+
+ ksz_prmw8(dev, port, regs[P_STP_CTRL], PORT_FORCE_FLOW_CTRL, sctrl);
+}
+
+/**
+ * ksz8_cpu_port_link_up - Configures the CPU port of the switch.
+ * @dev: The KSZ device instance.
+ * @speed: The desired link speed.
+ * @duplex: The desired duplex mode.
+ * @tx_pause: If true, enables transmit pause.
+ * @rx_pause: If true, enables receive pause.
+ *
+ * Description:
+ * The function configures flow control and speed settings for the CPU
+ * port of the switch based on the desired settings, current duplex mode, and
+ * speed.
+ */
+static void ksz8_cpu_port_link_up(struct ksz_device *dev, int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ const u16 *regs = dev->info->regs;
+ u8 ctrl = 0;
+
+ /* SW_FLOW_CTRL, SW_HALF_DUPLEX, and SW_10_MBIT bits are bootstrappable
+ * at least on KSZ8873. They can have different values depending on your
+ * board setup.
+ */
+ if (tx_pause || rx_pause)
+ ctrl |= SW_FLOW_CTRL;
+
+ if (duplex == DUPLEX_HALF)
+ ctrl |= SW_HALF_DUPLEX;
+
+ /* This hardware only supports SPEED_10 and SPEED_100. For SPEED_10
+ * we need to set the SW_10_MBIT bit. Otherwise, we can leave it 0.
+ */
+ if (speed == SPEED_10)
+ ctrl |= SW_10_MBIT;
+
+ ksz_rmw8(dev, regs[S_BROADCAST_CTRL], SW_HALF_DUPLEX | SW_FLOW_CTRL |
+ SW_10_MBIT, ctrl);
+}
+
+void ksz8_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)
+{
+ /* If the port is the CPU port, apply special handling. Only the CPU
+ * port is configured via global registers.
+ */
+ if (dev->cpu_port == port)
+ ksz8_cpu_port_link_up(dev, speed, duplex, tx_pause, rx_pause);
+ else if (dev->info->internal_phy[port])
+ ksz8_phy_port_link_up(dev, port, duplex, tx_pause, rx_pause);
+}
+
static int ksz8_handle_global_errata(struct dsa_switch *ds)
{
struct ksz_device *dev = ds->priv;
@@ -1487,8 +1625,6 @@ int ksz8_setup(struct dsa_switch *ds)
*/
ds->vlan_filtering_is_global = true;
- ksz_cfg(dev, S_REPLACE_VID_CTRL, SW_FLOW_CTRL, true);
-
/* Enable automatic fast aging when link changed detected. */
ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);
diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h
index 3c9dae53e4d8..beca974e0171 100644
--- a/drivers/net/dsa/microchip/ksz8795_reg.h
+++ b/drivers/net/dsa/microchip/ksz8795_reg.h
@@ -22,6 +22,9 @@
#define KSZ8863_GLOBAL_SOFTWARE_RESET BIT(4)
#define KSZ8863_PCS_RESET BIT(0)
+#define KSZ88X3_REG_FVID_AND_HOST_MODE 0xC6
+#define KSZ88X3_PORT3_RMII_CLK_INTERNAL BIT(3)
+
#define REG_SW_CTRL_0 0x02
#define SW_NEW_BACKOFF BIT(7)
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index ff4b39601c93..245dfb7a7a31 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -277,6 +277,7 @@ static const struct ksz_dev_ops ksz8_dev_ops = {
.mirror_add = ksz8_port_mirror_add,
.mirror_del = ksz8_port_mirror_del,
.get_caps = ksz8_get_caps,
+ .phylink_mac_link_up = ksz8_phylink_mac_link_up,
.config_cpu_port = ksz8_config_cpu_port,
.enable_stp_addr = ksz8_enable_stp_addr,
.reset = ksz8_reset_switch,
@@ -1672,15 +1673,23 @@ static const struct ksz_chip_data *ksz_lookup_info(unsigned int prod_num)
static int ksz_check_device_id(struct ksz_device *dev)
{
- const struct ksz_chip_data *dt_chip_data;
+ const struct ksz_chip_data *expected_chip_data;
+ u32 expected_chip_id;
- dt_chip_data = of_device_get_match_data(dev->dev);
+ if (dev->pdata) {
+ expected_chip_id = dev->pdata->chip_id;
+ expected_chip_data = ksz_lookup_info(expected_chip_id);
+ if (WARN_ON(!expected_chip_data))
+ return -ENODEV;
+ } else {
+ expected_chip_data = of_device_get_match_data(dev->dev);
+ expected_chip_id = expected_chip_data->chip_id;
+ }
- /* Check for Device Tree and Chip ID */
- if (dt_chip_data->chip_id != dev->chip_id) {
+ if (expected_chip_id != dev->chip_id) {
dev_err(dev->dev,
"Device tree specifies chip %s but found %s, please fix it!\n",
- dt_chip_data->dev_name, dev->info->dev_name);
+ expected_chip_data->dev_name, dev->info->dev_name);
return -ENODEV;
}
@@ -2703,7 +2712,7 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
proto = DSA_TAG_PROTO_KSZ9477;
if (is_lan937x(dev))
- proto = DSA_TAG_PROTO_LAN937X_VALUE;
+ proto = DSA_TAG_PROTO_LAN937X;
return proto;
}
@@ -2974,8 +2983,10 @@ static void ksz_phylink_mac_config(struct dsa_switch *ds, int port,
{
struct ksz_device *dev = ds->priv;
- if (ksz_is_ksz88x3(dev))
+ if (ksz_is_ksz88x3(dev)) {
+ dev->ports[port].manual_flow = !(state->pause & MLO_PAUSE_AN);
return;
+ }
/* Internal PHYs */
if (dev->info->internal_phy[port])
@@ -3118,10 +3129,8 @@ static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
{
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);
+ 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)
@@ -4163,9 +4172,6 @@ int ksz_switch_register(struct ksz_device *dev)
int ret;
int i;
- if (dev->pdata)
- dev->chip_id = dev->pdata->chip_id;
-
dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(dev->reset_gpio))
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index b7e8a403a132..15612101a155 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -14,6 +14,7 @@
#include <linux/regmap.h>
#include <net/dsa.h>
#include <linux/irq.h>
+#include <linux/platform_data/microchip-ksz.h>
#include "ksz_ptp.h"
@@ -134,6 +135,7 @@ struct ksz_port {
ktime_t tstamp_msg;
struct completion tstamp_msg_comp;
#endif
+ bool manual_flow;
};
struct ksz_device {
@@ -202,25 +204,6 @@ enum ksz_model {
LAN9374,
};
-enum ksz_chip_id {
- KSZ8563_CHIP_ID = 0x8563,
- KSZ8795_CHIP_ID = 0x8795,
- KSZ8794_CHIP_ID = 0x8794,
- KSZ8765_CHIP_ID = 0x8765,
- KSZ8830_CHIP_ID = 0x8830,
- KSZ9477_CHIP_ID = 0x00947700,
- KSZ9896_CHIP_ID = 0x00989600,
- KSZ9897_CHIP_ID = 0x00989700,
- KSZ9893_CHIP_ID = 0x00989300,
- KSZ9563_CHIP_ID = 0x00956300,
- KSZ9567_CHIP_ID = 0x00956700,
- LAN9370_CHIP_ID = 0x00937000,
- LAN9371_CHIP_ID = 0x00937100,
- LAN9372_CHIP_ID = 0x00937200,
- LAN9373_CHIP_ID = 0x00937300,
- LAN9374_CHIP_ID = 0x00937400,
-};
-
enum ksz_regs {
REG_SW_MAC_ADDR,
REG_IND_CTRL_0,
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index d27c6b70a2f6..3c1f657593a8 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -836,7 +836,7 @@ mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
return;
for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++)
- ethtool_sprintf(&data, "%s", mt7530_mib[i].name);
+ ethtool_puts(&data, mt7530_mib[i].name);
}
static void
@@ -2838,8 +2838,7 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
/* MT753x MAC works in 1G full duplex mode for all up-clocked
* variants.
*/
- if (interface == PHY_INTERFACE_MODE_INTERNAL ||
- interface == PHY_INTERFACE_MODE_TRGMII ||
+ if (interface == PHY_INTERFACE_MODE_TRGMII ||
(phy_interface_mode_is_8023z(interface))) {
speed = SPEED_1000;
duplex = DUPLEX_FULL;
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 07a22c74fe81..614cabb5c1b0 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -943,76 +943,94 @@ error:
static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
{
+ int err;
+
if (!chip->info->ops->stats_snapshot)
return -EOPNOTSUPP;
- return chip->info->ops->stats_snapshot(chip, port);
-}
-
-static struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
- { "in_good_octets", 8, 0x00, STATS_TYPE_BANK0, },
- { "in_bad_octets", 4, 0x02, STATS_TYPE_BANK0, },
- { "in_unicast", 4, 0x04, STATS_TYPE_BANK0, },
- { "in_broadcasts", 4, 0x06, STATS_TYPE_BANK0, },
- { "in_multicasts", 4, 0x07, STATS_TYPE_BANK0, },
- { "in_pause", 4, 0x16, STATS_TYPE_BANK0, },
- { "in_undersize", 4, 0x18, STATS_TYPE_BANK0, },
- { "in_fragments", 4, 0x19, STATS_TYPE_BANK0, },
- { "in_oversize", 4, 0x1a, STATS_TYPE_BANK0, },
- { "in_jabber", 4, 0x1b, STATS_TYPE_BANK0, },
- { "in_rx_error", 4, 0x1c, STATS_TYPE_BANK0, },
- { "in_fcs_error", 4, 0x1d, STATS_TYPE_BANK0, },
- { "out_octets", 8, 0x0e, STATS_TYPE_BANK0, },
- { "out_unicast", 4, 0x10, STATS_TYPE_BANK0, },
- { "out_broadcasts", 4, 0x13, STATS_TYPE_BANK0, },
- { "out_multicasts", 4, 0x12, STATS_TYPE_BANK0, },
- { "out_pause", 4, 0x15, STATS_TYPE_BANK0, },
- { "excessive", 4, 0x11, STATS_TYPE_BANK0, },
- { "collisions", 4, 0x1e, STATS_TYPE_BANK0, },
- { "deferred", 4, 0x05, STATS_TYPE_BANK0, },
- { "single", 4, 0x14, STATS_TYPE_BANK0, },
- { "multiple", 4, 0x17, STATS_TYPE_BANK0, },
- { "out_fcs_error", 4, 0x03, STATS_TYPE_BANK0, },
- { "late", 4, 0x1f, STATS_TYPE_BANK0, },
- { "hist_64bytes", 4, 0x08, STATS_TYPE_BANK0, },
- { "hist_65_127bytes", 4, 0x09, STATS_TYPE_BANK0, },
- { "hist_128_255bytes", 4, 0x0a, STATS_TYPE_BANK0, },
- { "hist_256_511bytes", 4, 0x0b, STATS_TYPE_BANK0, },
- { "hist_512_1023bytes", 4, 0x0c, STATS_TYPE_BANK0, },
- { "hist_1024_max_bytes", 4, 0x0d, STATS_TYPE_BANK0, },
- { "sw_in_discards", 4, 0x10, STATS_TYPE_PORT, },
- { "sw_in_filtered", 2, 0x12, STATS_TYPE_PORT, },
- { "sw_out_filtered", 2, 0x13, STATS_TYPE_PORT, },
- { "in_discards", 4, 0x00, STATS_TYPE_BANK1, },
- { "in_filtered", 4, 0x01, STATS_TYPE_BANK1, },
- { "in_accepted", 4, 0x02, STATS_TYPE_BANK1, },
- { "in_bad_accepted", 4, 0x03, STATS_TYPE_BANK1, },
- { "in_good_avb_class_a", 4, 0x04, STATS_TYPE_BANK1, },
- { "in_good_avb_class_b", 4, 0x05, STATS_TYPE_BANK1, },
- { "in_bad_avb_class_a", 4, 0x06, STATS_TYPE_BANK1, },
- { "in_bad_avb_class_b", 4, 0x07, STATS_TYPE_BANK1, },
- { "tcam_counter_0", 4, 0x08, STATS_TYPE_BANK1, },
- { "tcam_counter_1", 4, 0x09, STATS_TYPE_BANK1, },
- { "tcam_counter_2", 4, 0x0a, STATS_TYPE_BANK1, },
- { "tcam_counter_3", 4, 0x0b, STATS_TYPE_BANK1, },
- { "in_da_unknown", 4, 0x0e, STATS_TYPE_BANK1, },
- { "in_management", 4, 0x0f, STATS_TYPE_BANK1, },
- { "out_queue_0", 4, 0x10, STATS_TYPE_BANK1, },
- { "out_queue_1", 4, 0x11, STATS_TYPE_BANK1, },
- { "out_queue_2", 4, 0x12, STATS_TYPE_BANK1, },
- { "out_queue_3", 4, 0x13, STATS_TYPE_BANK1, },
- { "out_queue_4", 4, 0x14, STATS_TYPE_BANK1, },
- { "out_queue_5", 4, 0x15, STATS_TYPE_BANK1, },
- { "out_queue_6", 4, 0x16, STATS_TYPE_BANK1, },
- { "out_queue_7", 4, 0x17, STATS_TYPE_BANK1, },
- { "out_cut_through", 4, 0x18, STATS_TYPE_BANK1, },
- { "out_octets_a", 4, 0x1a, STATS_TYPE_BANK1, },
- { "out_octets_b", 4, 0x1b, STATS_TYPE_BANK1, },
- { "out_management", 4, 0x1f, STATS_TYPE_BANK1, },
+ mv88e6xxx_reg_lock(chip);
+ err = chip->info->ops->stats_snapshot(chip, port);
+ mv88e6xxx_reg_unlock(chip);
+
+ return err;
+}
+
+#define MV88E6XXX_HW_STAT_MAPPER(_fn) \
+ _fn(in_good_octets, 8, 0x00, STATS_TYPE_BANK0), \
+ _fn(in_bad_octets, 4, 0x02, STATS_TYPE_BANK0), \
+ _fn(in_unicast, 4, 0x04, STATS_TYPE_BANK0), \
+ _fn(in_broadcasts, 4, 0x06, STATS_TYPE_BANK0), \
+ _fn(in_multicasts, 4, 0x07, STATS_TYPE_BANK0), \
+ _fn(in_pause, 4, 0x16, STATS_TYPE_BANK0), \
+ _fn(in_undersize, 4, 0x18, STATS_TYPE_BANK0), \
+ _fn(in_fragments, 4, 0x19, STATS_TYPE_BANK0), \
+ _fn(in_oversize, 4, 0x1a, STATS_TYPE_BANK0), \
+ _fn(in_jabber, 4, 0x1b, STATS_TYPE_BANK0), \
+ _fn(in_rx_error, 4, 0x1c, STATS_TYPE_BANK0), \
+ _fn(in_fcs_error, 4, 0x1d, STATS_TYPE_BANK0), \
+ _fn(out_octets, 8, 0x0e, STATS_TYPE_BANK0), \
+ _fn(out_unicast, 4, 0x10, STATS_TYPE_BANK0), \
+ _fn(out_broadcasts, 4, 0x13, STATS_TYPE_BANK0), \
+ _fn(out_multicasts, 4, 0x12, STATS_TYPE_BANK0), \
+ _fn(out_pause, 4, 0x15, STATS_TYPE_BANK0), \
+ _fn(excessive, 4, 0x11, STATS_TYPE_BANK0), \
+ _fn(collisions, 4, 0x1e, STATS_TYPE_BANK0), \
+ _fn(deferred, 4, 0x05, STATS_TYPE_BANK0), \
+ _fn(single, 4, 0x14, STATS_TYPE_BANK0), \
+ _fn(multiple, 4, 0x17, STATS_TYPE_BANK0), \
+ _fn(out_fcs_error, 4, 0x03, STATS_TYPE_BANK0), \
+ _fn(late, 4, 0x1f, STATS_TYPE_BANK0), \
+ _fn(hist_64bytes, 4, 0x08, STATS_TYPE_BANK0), \
+ _fn(hist_65_127bytes, 4, 0x09, STATS_TYPE_BANK0), \
+ _fn(hist_128_255bytes, 4, 0x0a, STATS_TYPE_BANK0), \
+ _fn(hist_256_511bytes, 4, 0x0b, STATS_TYPE_BANK0), \
+ _fn(hist_512_1023bytes, 4, 0x0c, STATS_TYPE_BANK0), \
+ _fn(hist_1024_max_bytes, 4, 0x0d, STATS_TYPE_BANK0), \
+ _fn(sw_in_discards, 4, 0x10, STATS_TYPE_PORT), \
+ _fn(sw_in_filtered, 2, 0x12, STATS_TYPE_PORT), \
+ _fn(sw_out_filtered, 2, 0x13, STATS_TYPE_PORT), \
+ _fn(in_discards, 4, 0x00, STATS_TYPE_BANK1), \
+ _fn(in_filtered, 4, 0x01, STATS_TYPE_BANK1), \
+ _fn(in_accepted, 4, 0x02, STATS_TYPE_BANK1), \
+ _fn(in_bad_accepted, 4, 0x03, STATS_TYPE_BANK1), \
+ _fn(in_good_avb_class_a, 4, 0x04, STATS_TYPE_BANK1), \
+ _fn(in_good_avb_class_b, 4, 0x05, STATS_TYPE_BANK1), \
+ _fn(in_bad_avb_class_a, 4, 0x06, STATS_TYPE_BANK1), \
+ _fn(in_bad_avb_class_b, 4, 0x07, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_0, 4, 0x08, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_1, 4, 0x09, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_2, 4, 0x0a, STATS_TYPE_BANK1), \
+ _fn(tcam_counter_3, 4, 0x0b, STATS_TYPE_BANK1), \
+ _fn(in_da_unknown, 4, 0x0e, STATS_TYPE_BANK1), \
+ _fn(in_management, 4, 0x0f, STATS_TYPE_BANK1), \
+ _fn(out_queue_0, 4, 0x10, STATS_TYPE_BANK1), \
+ _fn(out_queue_1, 4, 0x11, STATS_TYPE_BANK1), \
+ _fn(out_queue_2, 4, 0x12, STATS_TYPE_BANK1), \
+ _fn(out_queue_3, 4, 0x13, STATS_TYPE_BANK1), \
+ _fn(out_queue_4, 4, 0x14, STATS_TYPE_BANK1), \
+ _fn(out_queue_5, 4, 0x15, STATS_TYPE_BANK1), \
+ _fn(out_queue_6, 4, 0x16, STATS_TYPE_BANK1), \
+ _fn(out_queue_7, 4, 0x17, STATS_TYPE_BANK1), \
+ _fn(out_cut_through, 4, 0x18, STATS_TYPE_BANK1), \
+ _fn(out_octets_a, 4, 0x1a, STATS_TYPE_BANK1), \
+ _fn(out_octets_b, 4, 0x1b, STATS_TYPE_BANK1), \
+ _fn(out_management, 4, 0x1f, STATS_TYPE_BANK1), \
+ /* */
+
+#define MV88E6XXX_HW_STAT_ENTRY(_string, _size, _reg, _type) \
+ { #_string, _size, _reg, _type }
+static const struct mv88e6xxx_hw_stat mv88e6xxx_hw_stats[] = {
+ MV88E6XXX_HW_STAT_MAPPER(MV88E6XXX_HW_STAT_ENTRY)
+};
+
+#define MV88E6XXX_HW_STAT_ENUM(_string, _size, _reg, _type) \
+ MV88E6XXX_HW_STAT_ID_ ## _string
+enum mv88e6xxx_hw_stat_id {
+ MV88E6XXX_HW_STAT_MAPPER(MV88E6XXX_HW_STAT_ENUM)
};
static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
- struct mv88e6xxx_hw_stat *s,
+ const struct mv88e6xxx_hw_stat *s,
int port, u16 bank1_select,
u16 histogram)
{
@@ -1055,7 +1073,7 @@ static uint64_t _mv88e6xxx_get_ethtool_stat(struct mv88e6xxx_chip *chip,
static int mv88e6xxx_stats_get_strings(struct mv88e6xxx_chip *chip,
uint8_t *data, int types)
{
- struct mv88e6xxx_hw_stat *stat;
+ const struct mv88e6xxx_hw_stat *stat;
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
@@ -1136,7 +1154,7 @@ static void mv88e6xxx_get_strings(struct dsa_switch *ds, int port,
static int mv88e6xxx_stats_get_sset_count(struct mv88e6xxx_chip *chip,
int types)
{
- struct mv88e6xxx_hw_stat *stat;
+ const struct mv88e6xxx_hw_stat *stat;
int i, j;
for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
@@ -1195,59 +1213,82 @@ out:
return count;
}
-static int mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data, int types,
- u16 bank1_select, u16 histogram)
+static size_t mv88e6095_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- struct mv88e6xxx_hw_stat *stat;
- int i, j;
+ if (!(stat->type & (STATS_TYPE_BANK0 | STATS_TYPE_PORT)))
+ return 0;
- for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
- stat = &mv88e6xxx_hw_stats[i];
- if (stat->type & types) {
- mv88e6xxx_reg_lock(chip);
- data[j] = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
- bank1_select,
- histogram);
- mv88e6xxx_reg_unlock(chip);
+ *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
+ MV88E6XXX_G1_STATS_OP_HIST_RX);
+ return 1;
+}
- j++;
- }
- }
- return j;
+static size_t mv88e6250_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
+{
+ if (!(stat->type & STATS_TYPE_BANK0))
+ return 0;
+
+ *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port, 0,
+ MV88E6XXX_G1_STATS_OP_HIST_RX);
+ return 1;
}
-static int mv88e6095_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static size_t mv88e6320_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_PORT,
- 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+ if (!(stat->type & (STATS_TYPE_BANK0 | STATS_TYPE_BANK1)))
+ return 0;
+
+ *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
+ MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
+ MV88E6XXX_G1_STATS_OP_HIST_RX);
+ return 1;
}
-static int mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static size_t mv88e6390_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
- 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+ if (!(stat->type & (STATS_TYPE_BANK0 | STATS_TYPE_BANK1)))
+ return 0;
+
+ *data = _mv88e6xxx_get_ethtool_stat(chip, stat, port,
+ MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
+ 0);
+ return 1;
}
-static int mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static size_t mv88e6xxx_stats_get_stat(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
- MV88E6XXX_G1_STATS_OP_BANK_1_BIT_9,
- MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
+ int ret = 0;
+
+ if (chip->info->ops->stats_get_stat) {
+ mv88e6xxx_reg_lock(chip);
+ ret = chip->info->ops->stats_get_stat(chip, port, stat, data);
+ mv88e6xxx_reg_unlock(chip);
+ }
+
+ return ret;
}
-static int mv88e6390_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+static size_t mv88e6xxx_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
{
- return mv88e6xxx_stats_get_stats(chip, port, data,
- STATS_TYPE_BANK0 | STATS_TYPE_BANK1,
- MV88E6XXX_G1_STATS_OP_BANK_1_BIT_10,
- 0);
+ const struct mv88e6xxx_hw_stat *stat;
+ size_t i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(mv88e6xxx_hw_stats); i++) {
+ stat = &mv88e6xxx_hw_stats[i];
+ j += mv88e6xxx_stats_get_stat(chip, port, stat, &data[j]);
+ }
+ return j;
}
static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
@@ -1263,10 +1304,9 @@ static void mv88e6xxx_atu_vtu_get_stats(struct mv88e6xxx_chip *chip, int port,
static void mv88e6xxx_get_stats(struct mv88e6xxx_chip *chip, int port,
uint64_t *data)
{
- int count = 0;
+ size_t count;
- if (chip->info->ops->stats_get_stats)
- count = chip->info->ops->stats_get_stats(chip, port, data);
+ count = mv88e6xxx_stats_get_stats(chip, port, data);
mv88e6xxx_reg_lock(chip);
if (chip->info->ops->serdes_get_stats) {
@@ -1284,16 +1324,90 @@ static void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int ret;
- mv88e6xxx_reg_lock(chip);
+ ret = mv88e6xxx_stats_snapshot(chip, port);
+ if (ret < 0)
+ return;
+
+ mv88e6xxx_get_stats(chip, port, data);
+}
+
+static void mv88e6xxx_get_eth_mac_stats(struct dsa_switch *ds, int port,
+ struct ethtool_eth_mac_stats *mac_stats)
+{
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int ret;
ret = mv88e6xxx_stats_snapshot(chip, port);
- mv88e6xxx_reg_unlock(chip);
+ if (ret < 0)
+ return;
+
+#define MV88E6XXX_ETH_MAC_STAT_MAP(_id, _member) \
+ mv88e6xxx_stats_get_stat(chip, port, \
+ &mv88e6xxx_hw_stats[MV88E6XXX_HW_STAT_ID_ ## _id], \
+ &mac_stats->stats._member)
+
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_unicast, FramesTransmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(single, SingleCollisionFrames);
+ MV88E6XXX_ETH_MAC_STAT_MAP(multiple, MultipleCollisionFrames);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_unicast, FramesReceivedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_fcs_error, FrameCheckSequenceErrors);
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_octets, OctetsTransmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(deferred, FramesWithDeferredXmissions);
+ MV88E6XXX_ETH_MAC_STAT_MAP(late, LateCollisions);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_good_octets, OctetsReceivedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_multicasts, MulticastFramesXmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(out_broadcasts, BroadcastFramesXmittedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(excessive, FramesWithExcessiveDeferral);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_multicasts, MulticastFramesReceivedOK);
+ MV88E6XXX_ETH_MAC_STAT_MAP(in_broadcasts, BroadcastFramesReceivedOK);
+
+#undef MV88E6XXX_ETH_MAC_STAT_MAP
+
+ mac_stats->stats.FramesTransmittedOK += mac_stats->stats.MulticastFramesXmittedOK;
+ mac_stats->stats.FramesTransmittedOK += mac_stats->stats.BroadcastFramesXmittedOK;
+ mac_stats->stats.FramesReceivedOK += mac_stats->stats.MulticastFramesReceivedOK;
+ mac_stats->stats.FramesReceivedOK += mac_stats->stats.BroadcastFramesReceivedOK;
+}
+
+static void mv88e6xxx_get_rmon_stats(struct dsa_switch *ds, int port,
+ struct ethtool_rmon_stats *rmon_stats,
+ const struct ethtool_rmon_hist_range **ranges)
+{
+ static const struct ethtool_rmon_hist_range rmon_ranges[] = {
+ { 64, 64 },
+ { 65, 127 },
+ { 128, 255 },
+ { 256, 511 },
+ { 512, 1023 },
+ { 1024, 65535 },
+ {}
+ };
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int ret;
+ ret = mv88e6xxx_stats_snapshot(chip, port);
if (ret < 0)
return;
- mv88e6xxx_get_stats(chip, port, data);
+#define MV88E6XXX_RMON_STAT_MAP(_id, _member) \
+ mv88e6xxx_stats_get_stat(chip, port, \
+ &mv88e6xxx_hw_stats[MV88E6XXX_HW_STAT_ID_ ## _id], \
+ &rmon_stats->stats._member)
+
+ MV88E6XXX_RMON_STAT_MAP(in_undersize, undersize_pkts);
+ MV88E6XXX_RMON_STAT_MAP(in_oversize, oversize_pkts);
+ MV88E6XXX_RMON_STAT_MAP(in_fragments, fragments);
+ MV88E6XXX_RMON_STAT_MAP(in_jabber, jabbers);
+ MV88E6XXX_RMON_STAT_MAP(hist_64bytes, hist[0]);
+ MV88E6XXX_RMON_STAT_MAP(hist_65_127bytes, hist[1]);
+ MV88E6XXX_RMON_STAT_MAP(hist_128_255bytes, hist[2]);
+ MV88E6XXX_RMON_STAT_MAP(hist_256_511bytes, hist[3]);
+ MV88E6XXX_RMON_STAT_MAP(hist_512_1023bytes, hist[4]);
+ MV88E6XXX_RMON_STAT_MAP(hist_1024_max_bytes, hist[5]);
+#undef MV88E6XXX_RMON_STAT_MAP
+
+ *ranges = rmon_ranges;
}
static int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port)
@@ -3545,7 +3659,7 @@ static int mv88e6xxx_mdio_read_c45(struct mii_bus *bus, int phy, int devad,
int err;
if (!chip->info->ops->phy_read_c45)
- return -EOPNOTSUPP;
+ return 0xffff;
mv88e6xxx_reg_lock(chip);
err = chip->info->ops->phy_read_c45(chip, bus, phy, devad, reg, &val);
@@ -3987,7 +4101,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4025,7 +4139,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.mgmt_rsvd2cpu = mv88e6185_g2_mgmt_rsvd2cpu,
.ppu_enable = mv88e6185_g1_ppu_enable,
.ppu_disable = mv88e6185_g1_ppu_disable,
@@ -4066,7 +4180,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4108,7 +4222,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4151,7 +4265,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4200,7 +4314,7 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4255,7 +4369,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4293,7 +4407,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4341,7 +4455,7 @@ static const struct mv88e6xxx_ops mv88e6171_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4390,7 +4504,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4441,7 +4555,7 @@ static const struct mv88e6xxx_ops mv88e6175_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4490,7 +4604,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4535,7 +4649,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4584,7 +4698,7 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4642,7 +4756,7 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4698,7 +4812,7 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4757,7 +4871,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -4810,7 +4924,7 @@ static const struct mv88e6xxx_ops mv88e6250_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6250_stats_get_sset_count,
.stats_get_strings = mv88e6250_stats_get_strings,
- .stats_get_stats = mv88e6250_stats_get_stats,
+ .stats_get_stat = mv88e6250_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6250_watchdog_ops,
@@ -4857,7 +4971,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4916,7 +5030,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6320_stats_get_stats,
+ .stats_get_stat = mv88e6320_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -4963,7 +5077,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6320_stats_get_stats,
+ .stats_get_stat = mv88e6320_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5012,7 +5126,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5070,7 +5184,7 @@ static const struct mv88e6xxx_ops mv88e6350_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5116,7 +5230,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5167,7 +5281,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.stats_set_histogram = mv88e6095_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6095_stats_get_sset_count,
.stats_get_strings = mv88e6095_stats_get_strings,
- .stats_get_stats = mv88e6095_stats_get_stats,
+ .stats_get_stat = mv88e6095_stats_get_stat,
.set_cpu_port = mv88e6095_g1_set_cpu_port,
.set_egress_port = mv88e6095_g1_set_egress_port,
.watchdog_ops = &mv88e6097_watchdog_ops,
@@ -5229,7 +5343,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5291,7 +5405,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
.set_cpu_port = mv88e6390_g1_set_cpu_port,
.set_egress_port = mv88e6390_g1_set_egress_port,
.watchdog_ops = &mv88e6390_watchdog_ops,
@@ -5353,7 +5467,7 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
.stats_set_histogram = mv88e6390_g1_stats_set_histogram,
.stats_get_sset_count = mv88e6320_stats_get_sset_count,
.stats_get_strings = mv88e6320_stats_get_strings,
- .stats_get_stats = mv88e6390_stats_get_stats,
+ .stats_get_stat = mv88e6390_stats_get_stat,
/* .set_cpu_port is missing because this family does not support a global
* CPU port, only per port CPU port which is set via
* .port_set_upstream_port method.
@@ -6817,6 +6931,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
.phylink_mac_link_up = mv88e6xxx_mac_link_up,
.get_strings = mv88e6xxx_get_strings,
.get_ethtool_stats = mv88e6xxx_get_ethtool_stats,
+ .get_eth_mac_stats = mv88e6xxx_get_eth_mac_stats,
+ .get_rmon_stats = mv88e6xxx_get_rmon_stats,
.get_sset_count = mv88e6xxx_get_sset_count,
.port_max_mtu = mv88e6xxx_get_max_mtu,
.port_change_mtu = mv88e6xxx_change_mtu,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 44383a03ef2f..85eb293381a7 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -318,6 +318,17 @@ struct mv88e6xxx_mst {
struct mv88e6xxx_stu_entry stu;
};
+#define STATS_TYPE_PORT BIT(0)
+#define STATS_TYPE_BANK0 BIT(1)
+#define STATS_TYPE_BANK1 BIT(2)
+
+struct mv88e6xxx_hw_stat {
+ char string[ETH_GSTRING_LEN];
+ size_t size;
+ int reg;
+ int type;
+};
+
struct mv88e6xxx_chip {
const struct mv88e6xxx_info *info;
@@ -574,8 +585,9 @@ struct mv88e6xxx_ops {
/* Return the number of strings describing statistics */
int (*stats_get_sset_count)(struct mv88e6xxx_chip *chip);
int (*stats_get_strings)(struct mv88e6xxx_chip *chip, uint8_t *data);
- int (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data);
+ size_t (*stats_get_stat)(struct mv88e6xxx_chip *chip, int port,
+ const struct mv88e6xxx_hw_stat *stat,
+ uint64_t *data);
int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port);
int (*set_egress_port)(struct mv88e6xxx_chip *chip,
enum mv88e6xxx_egress_direction direction,
@@ -601,8 +613,8 @@ struct mv88e6xxx_ops {
int (*serdes_get_sset_count)(struct mv88e6xxx_chip *chip, int port);
int (*serdes_get_strings)(struct mv88e6xxx_chip *chip, int port,
uint8_t *data);
- int (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data);
+ size_t (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data);
/* SERDES registers for ethtool */
int (*serdes_get_regs_len)(struct mv88e6xxx_chip *chip, int port);
@@ -727,17 +739,6 @@ struct mv88e6xxx_pcs_ops {
};
-#define STATS_TYPE_PORT BIT(0)
-#define STATS_TYPE_BANK0 BIT(1)
-#define STATS_TYPE_BANK1 BIT(2)
-
-struct mv88e6xxx_hw_stat {
- char string[ETH_GSTRING_LEN];
- size_t size;
- int reg;
- int type;
-};
-
static inline bool mv88e6xxx_has_stu(struct mv88e6xxx_chip *chip)
{
return chip->info->max_sid > 0 &&
diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c
index 174c773b38c2..49444a72ff09 100644
--- a/drivers/net/dsa/mv88e6xxx/global1.c
+++ b/drivers/net/dsa/mv88e6xxx/global1.c
@@ -462,8 +462,7 @@ int mv88e6390_g1_rmu_disable(struct mv88e6xxx_chip *chip)
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
{
return mv88e6xxx_g1_ctl2_mask(chip, MV88E6390_G1_CTL2_HIST_MODE_MASK,
- MV88E6390_G1_CTL2_HIST_MODE_RX |
- MV88E6390_G1_CTL2_HIST_MODE_TX);
+ MV88E6390_G1_CTL2_HIST_MODE_RX);
}
int mv88e6xxx_g1_set_device_number(struct mv88e6xxx_chip *chip, int index)
@@ -491,7 +490,7 @@ int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
if (err)
return err;
- val |= MV88E6XXX_G1_STATS_OP_HIST_RX_TX;
+ val |= MV88E6XXX_G1_STATS_OP_HIST_RX;
err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val);
@@ -506,7 +505,7 @@ int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP,
MV88E6XXX_G1_STATS_OP_BUSY |
MV88E6XXX_G1_STATS_OP_CAPTURE_PORT |
- MV88E6XXX_G1_STATS_OP_HIST_RX_TX | port);
+ MV88E6XXX_G1_STATS_OP_HIST_RX | port);
if (err)
return err;
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 3b4b42651fa3..01ea53940786 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -177,8 +177,8 @@ static uint64_t mv88e6352_serdes_get_stat(struct mv88e6xxx_chip *chip,
return val;
}
-int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
{
struct mv88e6xxx_port *mv88e6xxx_port = &chip->ports[port];
struct mv88e6352_serdes_hw_stat *stat;
@@ -187,7 +187,7 @@ int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
err = mv88e6352_g2_scratch_port_has_serdes(chip, port);
if (err <= 0)
- return err;
+ return 0;
BUILD_BUG_ON(ARRAY_SIZE(mv88e6352_serdes_hw_stats) >
ARRAY_SIZE(mv88e6xxx_port->serdes_stats));
@@ -429,8 +429,8 @@ static uint64_t mv88e6390_serdes_get_stat(struct mv88e6xxx_chip *chip, int lane,
return reg[0] | ((u64)reg[1] << 16) | ((u64)reg[2] << 32);
}
-int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data)
+size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data)
{
struct mv88e6390_serdes_hw_stat *stat;
int lane;
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
index aac95cab46e3..ff5c3ab31e15 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.h
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -127,13 +127,13 @@ unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip,
int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data);
-int mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data);
+size_t mv88e6352_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data);
int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port);
int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip,
int port, uint8_t *data);
-int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
- uint64_t *data);
+size_t mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port,
+ uint64_t *data);
int mv88e6352_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port);
void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p);
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index ec57d9d52072..7a864329cb72 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -947,36 +947,49 @@ static int
qca8k_mdio_register(struct qca8k_priv *priv)
{
struct dsa_switch *ds = priv->ds;
+ struct device *dev = ds->dev;
struct device_node *mdio;
struct mii_bus *bus;
+ int err = 0;
- bus = devm_mdiobus_alloc(ds->dev);
- if (!bus)
- return -ENOMEM;
+ mdio = of_get_child_by_name(dev->of_node, "mdio");
+ if (mdio && !of_device_is_available(mdio))
+ goto out;
+
+ bus = devm_mdiobus_alloc(dev);
+ if (!bus) {
+ err = -ENOMEM;
+ goto out_put_node;
+ }
+ priv->internal_mdio_bus = bus;
bus->priv = (void *)priv;
snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d",
ds->dst->index, ds->index);
- bus->parent = ds->dev;
- bus->phy_mask = ~ds->phys_mii_mask;
- ds->user_mii_bus = bus;
+ bus->parent = dev;
- /* Check if the devicetree declare the port:phy mapping */
- mdio = of_get_child_by_name(priv->dev->of_node, "mdio");
- if (of_device_is_available(mdio)) {
+ if (mdio) {
+ /* Check if the device tree declares the port:phy mapping */
bus->name = "qca8k user mii";
bus->read = qca8k_internal_mdio_read;
bus->write = qca8k_internal_mdio_write;
- return devm_of_mdiobus_register(priv->dev, bus, mdio);
+ } else {
+ /* If a mapping can't be found, the legacy mapping is used,
+ * using qca8k_port_to_phy()
+ */
+ ds->user_mii_bus = bus;
+ bus->phy_mask = ~ds->phys_mii_mask;
+ bus->name = "qca8k-legacy user mii";
+ bus->read = qca8k_legacy_mdio_read;
+ bus->write = qca8k_legacy_mdio_write;
}
- /* If a mapping can't be found the legacy mapping is used,
- * using the qca8k_port_to_phy function
- */
- bus->name = "qca8k-legacy user mii";
- bus->read = qca8k_legacy_mdio_read;
- bus->write = qca8k_legacy_mdio_write;
- return devm_mdiobus_register(priv->dev, bus);
+ err = devm_of_mdiobus_register(dev, bus, mdio);
+
+out_put_node:
+ of_node_put(mdio);
+out:
+ return err;
}
static int
@@ -2038,12 +2051,11 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
priv->info = of_device_get_match_data(priv->dev);
priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
- GPIOD_ASIS);
+ GPIOD_OUT_HIGH);
if (IS_ERR(priv->reset_gpio))
return PTR_ERR(priv->reset_gpio);
if (priv->reset_gpio) {
- gpiod_set_value_cansleep(priv->reset_gpio, 1);
/* The active low duration must be greater than 10 ms
* and checkpatch.pl wants 20 ms.
*/
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 9243eff8918d..2358cd399c7e 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -487,7 +487,7 @@ void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset,
return;
for (i = 0; i < priv->info->mib_count; i++)
- ethtool_sprintf(&data, "%s", ar8327_mib[i].name);
+ ethtool_puts(&data, ar8327_mib[i].name);
}
void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/qca/qca8k-leds.c b/drivers/net/dsa/qca/qca8k-leds.c
index 90e30c2909e4..811ebeeff4ed 100644
--- a/drivers/net/dsa/qca/qca8k-leds.c
+++ b/drivers/net/dsa/qca/qca8k-leds.c
@@ -366,7 +366,6 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p
{
struct fwnode_handle *led = NULL, *leds = NULL;
struct led_init_data init_data = { };
- struct dsa_switch *ds = priv->ds;
enum led_default_state state;
struct qca8k_led *port_led;
int led_num, led_index;
@@ -429,7 +428,8 @@ qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int p
init_data.default_label = ":port";
init_data.fwnode = led;
init_data.devname_mandatory = true;
- init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d", ds->user_mii_bus->id,
+ init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d",
+ priv->internal_mdio_bus->id,
port_num);
if (!init_data.devicename)
return -ENOMEM;
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 2ac7e88f8da5..c8785c36c54e 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -454,6 +454,7 @@ struct qca8k_priv {
struct qca8k_ports_config ports_config;
struct regmap *regmap;
struct mii_bus *bus;
+ struct mii_bus *internal_mdio_bus;
struct dsa_switch *ds;
struct mutex reg_mutex;
struct device *dev;
diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
index 0875e4fc9f57..b072045eb154 100644
--- a/drivers/net/dsa/realtek/rtl8365mb.c
+++ b/drivers/net/dsa/realtek/rtl8365mb.c
@@ -1303,7 +1303,7 @@ static void rtl8365mb_get_strings(struct dsa_switch *ds, int port, u32 stringset
for (i = 0; i < RTL8365MB_MIB_END; i++) {
struct rtl8365mb_mib_counter *mib = &rtl8365mb_mib_counters[i];
- ethtool_sprintf(&data, "%s", mib->name);
+ ethtool_puts(&data, mib->name);
}
}
diff --git a/drivers/net/dsa/realtek/rtl8366-core.c b/drivers/net/dsa/realtek/rtl8366-core.c
index 82e267b8fddb..59f98d2c8769 100644
--- a/drivers/net/dsa/realtek/rtl8366-core.c
+++ b/drivers/net/dsa/realtek/rtl8366-core.c
@@ -401,7 +401,7 @@ void rtl8366_get_strings(struct dsa_switch *ds, int port, u32 stringset,
return;
for (i = 0; i < priv->num_mib_counters; i++)
- ethtool_sprintf(&data, "%s", priv->mib_counters[i].name);
+ ethtool_puts(&data, priv->mib_counters[i].name);
}
EXPORT_SYMBOL_GPL(rtl8366_get_strings);
diff --git a/drivers/net/dsa/realtek/rtl8366rb.c b/drivers/net/dsa/realtek/rtl8366rb.c
index b39b719a5b8f..e3b6a470ca67 100644
--- a/drivers/net/dsa/realtek/rtl8366rb.c
+++ b/drivers/net/dsa/realtek/rtl8366rb.c
@@ -15,6 +15,7 @@
#include <linux/bitops.h>
#include <linux/etherdevice.h>
#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
@@ -117,10 +118,11 @@
RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK)
/* CPU port control reg */
-#define RTL8368RB_CPU_CTRL_REG 0x0061
-#define RTL8368RB_CPU_PORTS_MSK 0x00FF
+#define RTL8366RB_CPU_CTRL_REG 0x0061
+#define RTL8366RB_CPU_PORTS_MSK 0x00FF
/* Disables inserting custom tag length/type 0x8899 */
-#define RTL8368RB_CPU_NO_TAG BIT(15)
+#define RTL8366RB_CPU_NO_TAG BIT(15)
+#define RTL8366RB_CPU_TAG_SIZE 4
#define RTL8366RB_SMAR0 0x0070 /* bits 0..15 */
#define RTL8366RB_SMAR1 0x0071 /* bits 16..31 */
@@ -912,10 +914,10 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
/* Enable CPU port with custom DSA tag 8899.
*
- * If you set RTL8368RB_CPU_NO_TAG (bit 15) in this registers
+ * If you set RTL8366RB_CPU_NO_TAG (bit 15) in this register
* the custom tag is turned off.
*/
- ret = regmap_update_bits(priv->map, RTL8368RB_CPU_CTRL_REG,
+ ret = regmap_update_bits(priv->map, RTL8366RB_CPU_CTRL_REG,
0xFFFF,
BIT(priv->cpu_port));
if (ret)
@@ -928,15 +930,19 @@ static int rtl8366rb_setup(struct dsa_switch *ds)
if (ret)
return ret;
- /* Set maximum packet length to 1536 bytes */
+ /* Set default maximum packet length to 1536 bytes */
ret = regmap_update_bits(priv->map, RTL8366RB_SGCR,
RTL8366RB_SGCR_MAX_LENGTH_MASK,
RTL8366RB_SGCR_MAX_LENGTH_1536);
if (ret)
return ret;
- for (i = 0; i < RTL8366RB_NUM_PORTS; i++)
- /* layer 2 size, see rtl8366rb_change_mtu() */
- rb->max_mtu[i] = 1532;
+ for (i = 0; i < RTL8366RB_NUM_PORTS; i++) {
+ if (i == priv->cpu_port)
+ /* CPU port need to also accept the tag */
+ rb->max_mtu[i] = ETH_DATA_LEN + RTL8366RB_CPU_TAG_SIZE;
+ else
+ rb->max_mtu[i] = ETH_DATA_LEN;
+ }
/* Disable learning for all ports */
ret = regmap_write(priv->map, RTL8366RB_PORT_LEARNDIS_CTRL,
@@ -1441,24 +1447,29 @@ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
/* Roof out the MTU for the entire switch to the greatest
* common denominator: the biggest set for any one port will
* be the biggest MTU for the switch.
- *
- * The first setting, 1522 bytes, is max IP packet 1500 bytes,
- * plus ethernet header, 1518 bytes, plus CPU tag, 4 bytes.
- * This function should consider the parameter an SDU, so the
- * MTU passed for this setting is 1518 bytes. The same logic
- * of subtracting the DSA tag of 4 bytes apply to the other
- * settings.
*/
- max_mtu = 1518;
+ max_mtu = ETH_DATA_LEN;
for (i = 0; i < RTL8366RB_NUM_PORTS; i++) {
if (rb->max_mtu[i] > max_mtu)
max_mtu = rb->max_mtu[i];
}
- if (max_mtu <= 1518)
+
+ /* Translate to layer 2 size.
+ * Add ethernet and (possible) VLAN headers, and checksum to the size.
+ * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes.
+ */
+ max_mtu += VLAN_ETH_HLEN;
+ max_mtu += ETH_FCS_LEN;
+
+ if (max_mtu <= 1522)
len = RTL8366RB_SGCR_MAX_LENGTH_1522;
- else if (max_mtu > 1518 && max_mtu <= 1532)
+ else if (max_mtu > 1522 && max_mtu <= 1536)
+ /* This will be the most common default if using VLAN and
+ * CPU tagging on a port as both VLAN and CPU tag will
+ * result in 1518 + 4 + 4 = 1526 bytes.
+ */
len = RTL8366RB_SGCR_MAX_LENGTH_1536;
- else if (max_mtu > 1532 && max_mtu <= 1548)
+ else if (max_mtu > 1536 && max_mtu <= 1552)
len = RTL8366RB_SGCR_MAX_LENGTH_1552;
else
len = RTL8366RB_SGCR_MAX_LENGTH_16000;
@@ -1470,10 +1481,12 @@ static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
static int rtl8366rb_max_mtu(struct dsa_switch *ds, int port)
{
- /* The max MTU is 16000 bytes, so we subtract the CPU tag
- * and the max presented to the system is 15996 bytes.
+ /* The max MTU is 16000 bytes, so we subtract the ethernet
+ * headers with VLAN and checksum and arrive at
+ * 16000 - 18 - 4 = 15978. This does not include the CPU tag
+ * since that is added to the requested MTU by the DSA framework.
*/
- return 15996;
+ return 16000 - VLAN_ETH_HLEN - ETH_FCS_LEN;
}
static int rtl8366rb_get_vlan_4k(struct realtek_priv *priv, u32 vid,
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 74cee39d73df..6646f7fb0f90 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -21,6 +21,8 @@
#include <linux/if_bridge.h>
#include <linux/if_ether.h>
#include <linux/dsa/8021q.h>
+#include <linux/units.h>
+
#include "sja1105.h"
#include "sja1105_tas.h"
@@ -2138,7 +2140,6 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
sja1105_bridge_member(ds, port, bridge, false);
}
-#define BYTES_PER_KBIT (1000LL / 8)
/* Port 0 (the uC port) does not have CBS shapers */
#define SJA1110_FIXED_CBS(port, prio) ((((port) - 1) * SJA1105_NUM_TC) + (prio))
diff --git a/drivers/net/dsa/vitesse-vsc73xx-core.c b/drivers/net/dsa/vitesse-vsc73xx-core.c
index e6f29e4e508c..ae70eac3be28 100644
--- a/drivers/net/dsa/vitesse-vsc73xx-core.c
+++ b/drivers/net/dsa/vitesse-vsc73xx-core.c
@@ -949,7 +949,7 @@ static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset,
indices[5] = ((val >> 26) & 0x1f); /* TX counter 2 */
/* The first counters is the RX octets */
- ethtool_sprintf(&buf, "RxEtherStatsOctets");
+ ethtool_puts(&buf, "RxEtherStatsOctets");
/* Each port supports recording 3 RX counters and 3 TX counters,
* figure out what counters we use in this set-up and return the
@@ -959,15 +959,15 @@ static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset,
*/
for (i = 0; i < 3; i++) {
cnt = vsc73xx_find_counter(vsc, indices[i], false);
- ethtool_sprintf(&buf, "%s", cnt ? cnt->name : "");
+ ethtool_puts(&buf, cnt ? cnt->name : "");
}
/* TX stats begins with the number of TX octets */
- ethtool_sprintf(&buf, "TxEtherStatsOctets");
+ ethtool_puts(&buf, "TxEtherStatsOctets");
for (i = 3; i < 6; i++) {
cnt = vsc73xx_find_counter(vsc, indices[i], true);
- ethtool_sprintf(&buf, "%s", cnt ? cnt->name : "");
+ ethtool_puts(&buf, cnt ? cnt->name : "");
}
}
@@ -1135,6 +1135,8 @@ static int vsc73xx_gpio_probe(struct vsc73xx *vsc)
vsc->gc.label = devm_kasprintf(vsc->dev, GFP_KERNEL, "VSC%04x",
vsc->chipid);
+ if (!vsc->gc.label)
+ return -ENOMEM;
vsc->gc.ngpio = 4;
vsc->gc.owner = THIS_MODULE;
vsc->gc.parent = vsc->dev;
diff --git a/drivers/net/ethernet/8390/8390.c b/drivers/net/ethernet/8390/8390.c
index 0e0aa4016858..c5636245f1ca 100644
--- a/drivers/net/ethernet/8390/8390.c
+++ b/drivers/net/ethernet/8390/8390.c
@@ -100,4 +100,5 @@ static void __exit ns8390_module_exit(void)
module_init(ns8390_module_init);
module_exit(ns8390_module_exit);
#endif /* MODULE */
+MODULE_DESCRIPTION("National Semiconductor 8390 core driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/8390/8390p.c b/drivers/net/ethernet/8390/8390p.c
index 6834742057b3..6d429b11e9c6 100644
--- a/drivers/net/ethernet/8390/8390p.c
+++ b/drivers/net/ethernet/8390/8390p.c
@@ -102,4 +102,5 @@ static void __exit NS8390p_cleanup_module(void)
module_init(NS8390p_init_module);
module_exit(NS8390p_cleanup_module);
+MODULE_DESCRIPTION("National Semiconductor 8390 core for ISA driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/8390/apne.c b/drivers/net/ethernet/8390/apne.c
index a09f383dd249..828edca8d30c 100644
--- a/drivers/net/ethernet/8390/apne.c
+++ b/drivers/net/ethernet/8390/apne.c
@@ -610,4 +610,5 @@ static int init_pcmcia(void)
return 1;
}
+MODULE_DESCRIPTION("National Semiconductor 8390 Amiga PCMCIA ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/8390/hydra.c b/drivers/net/ethernet/8390/hydra.c
index 24f49a8ff903..fd9dcdc356e6 100644
--- a/drivers/net/ethernet/8390/hydra.c
+++ b/drivers/net/ethernet/8390/hydra.c
@@ -270,4 +270,5 @@ static void __exit hydra_cleanup_module(void)
module_init(hydra_init_module);
module_exit(hydra_cleanup_module);
+MODULE_DESCRIPTION("Zorro-II Hydra 8390 ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/8390/stnic.c b/drivers/net/ethernet/8390/stnic.c
index 265976e3b64a..6cc0e190aa79 100644
--- a/drivers/net/ethernet/8390/stnic.c
+++ b/drivers/net/ethernet/8390/stnic.c
@@ -296,4 +296,5 @@ static void __exit stnic_cleanup(void)
module_init(stnic_probe);
module_exit(stnic_cleanup);
+MODULE_DESCRIPTION("National Semiconductor DP83902AV ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/8390/zorro8390.c b/drivers/net/ethernet/8390/zorro8390.c
index d70390e9d03d..c24dd4fe7a10 100644
--- a/drivers/net/ethernet/8390/zorro8390.c
+++ b/drivers/net/ethernet/8390/zorro8390.c
@@ -443,4 +443,5 @@ static void __exit zorro8390_cleanup_module(void)
module_init(zorro8390_init_module);
module_exit(zorro8390_cleanup_module);
+MODULE_DESCRIPTION("Zorro NS8390-based ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
index da3bdd302502..760a9a60bc15 100644
--- a/drivers/net/ethernet/adi/Kconfig
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -21,6 +21,7 @@ config ADIN1110
tristate "Analog Devices ADIN1110 MAC-PHY"
depends on SPI && NET_SWITCHDEV
select CRC8
+ select PHYLIB
help
Say yes here to build support for Analog Devices ADIN1110
Low Power 10BASE-T1L Ethernet MAC-PHY.
diff --git a/drivers/net/ethernet/amazon/ena/Makefile b/drivers/net/ethernet/amazon/ena/Makefile
index f1f752a8f7bb..6ab615365172 100644
--- a/drivers/net/ethernet/amazon/ena/Makefile
+++ b/drivers/net/ethernet/amazon/ena/Makefile
@@ -5,4 +5,4 @@
obj-$(CONFIG_ENA_ETHERNET) += ena.o
-ena-y := ena_netdev.o ena_com.o ena_eth_com.o ena_ethtool.o
+ena-y := ena_netdev.o ena_com.o ena_eth_com.o ena_ethtool.o ena_xdp.o
diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
index d671df4b76bc..0cb6cc1cef56 100644
--- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c
+++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c
@@ -7,6 +7,7 @@
#include <linux/pci.h>
#include "ena_netdev.h"
+#include "ena_xdp.h"
struct ena_stats {
char name[ETH_GSTRING_LEN];
@@ -262,17 +263,14 @@ static void ena_queue_strings(struct ena_adapter *adapter, u8 **data)
ena_stats->name);
}
- if (!is_xdp) {
- /* RX stats, in XDP there isn't a RX queue
- * counterpart
- */
- for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
- ena_stats = &ena_stats_rx_strings[j];
+ /* In XDP there isn't an RX queue counterpart */
+ if (is_xdp)
+ continue;
- ethtool_sprintf(data,
- "queue_%u_rx_%s", i,
- ena_stats->name);
- }
+ for (j = 0; j < ENA_STATS_ARRAY_RX; j++) {
+ ena_stats = &ena_stats_rx_strings[j];
+
+ ethtool_sprintf(data, "queue_%u_rx_%s", i, ena_stats->name);
}
}
}
@@ -299,13 +297,13 @@ static void ena_get_strings(struct ena_adapter *adapter,
for (i = 0; i < ENA_STATS_ARRAY_GLOBAL; i++) {
ena_stats = &ena_stats_global_strings[i];
- ethtool_sprintf(&data, ena_stats->name);
+ ethtool_puts(&data, ena_stats->name);
}
if (eni_stats_needed) {
for (i = 0; i < ENA_STATS_ARRAY_ENI(adapter); i++) {
ena_stats = &ena_stats_eni_strings[i];
- ethtool_sprintf(&data, ena_stats->name);
+ ethtool_puts(&data, ena_stats->name);
}
}
@@ -802,15 +800,15 @@ static int ena_indirection_table_get(struct ena_adapter *adapter, u32 *indir)
return rc;
}
-static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int ena_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct ena_adapter *adapter = netdev_priv(netdev);
enum ena_admin_hash_functions ena_func;
u8 func;
int rc;
- rc = ena_indirection_table_get(adapter, indir);
+ rc = ena_indirection_table_get(adapter, rxfh->indir);
if (rc)
return rc;
@@ -825,7 +823,7 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
return rc;
}
- rc = ena_com_get_hash_key(adapter->ena_dev, key);
+ rc = ena_com_get_hash_key(adapter->ena_dev, rxfh->key);
if (rc)
return rc;
@@ -842,27 +840,27 @@ static int ena_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
return -EOPNOTSUPP;
}
- if (hfunc)
- *hfunc = func;
+ rxfh->hfunc = func;
return 0;
}
-static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int ena_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct ena_adapter *adapter = netdev_priv(netdev);
struct ena_com_dev *ena_dev = adapter->ena_dev;
enum ena_admin_hash_functions func = 0;
int rc;
- if (indir) {
- rc = ena_indirection_table_set(adapter, indir);
+ if (rxfh->indir) {
+ rc = ena_indirection_table_set(adapter, rxfh->indir);
if (rc)
return rc;
}
- switch (hfunc) {
+ switch (rxfh->hfunc) {
case ETH_RSS_HASH_NO_CHANGE:
func = ena_com_get_current_hash_function(ena_dev);
break;
@@ -874,12 +872,12 @@ static int ena_set_rxfh(struct net_device *netdev, const u32 *indir,
break;
default:
netif_err(adapter, drv, netdev, "Unsupported hfunc %d\n",
- hfunc);
+ rxfh->hfunc);
return -EOPNOTSUPP;
}
- if (key || func) {
- rc = ena_com_fill_hash_function(ena_dev, func, key,
+ if (rxfh->key || func) {
+ rc = ena_com_fill_hash_function(ena_dev, func, rxfh->key,
ENA_HASH_KEY_SIZE,
0xFFFFFFFF);
if (unlikely(rc)) {
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index c44c44e26ddf..1c0a7828d397 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -19,8 +19,8 @@
#include <net/ip.h>
#include "ena_netdev.h"
-#include <linux/bpf_trace.h>
#include "ena_pci_id_tbl.h"
+#include "ena_xdp.h"
MODULE_AUTHOR("Amazon.com, Inc. or its affiliates");
MODULE_DESCRIPTION(DEVICE_NAME);
@@ -45,53 +45,6 @@ static void check_for_admin_com_state(struct ena_adapter *adapter);
static void ena_destroy_device(struct ena_adapter *adapter, bool graceful);
static int ena_restore_device(struct ena_adapter *adapter);
-static void ena_init_io_rings(struct ena_adapter *adapter,
- int first_index, int count);
-static void ena_init_napi_in_range(struct ena_adapter *adapter, int first_index,
- int count);
-static void ena_del_napi_in_range(struct ena_adapter *adapter, int first_index,
- int count);
-static int ena_setup_tx_resources(struct ena_adapter *adapter, int qid);
-static int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
- int first_index,
- int count);
-static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid);
-static void ena_free_tx_resources(struct ena_adapter *adapter, int qid);
-static int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget);
-static void ena_destroy_all_tx_queues(struct ena_adapter *adapter);
-static void ena_free_all_io_tx_resources(struct ena_adapter *adapter);
-static void ena_napi_disable_in_range(struct ena_adapter *adapter,
- int first_index, int count);
-static void ena_napi_enable_in_range(struct ena_adapter *adapter,
- int first_index, int count);
-static int ena_up(struct ena_adapter *adapter);
-static void ena_down(struct ena_adapter *adapter);
-static void ena_unmask_interrupt(struct ena_ring *tx_ring,
- struct ena_ring *rx_ring);
-static void ena_update_ring_numa_node(struct ena_ring *tx_ring,
- struct ena_ring *rx_ring);
-static void ena_unmap_tx_buff(struct ena_ring *tx_ring,
- struct ena_tx_buffer *tx_info);
-static int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
- int first_index, int count);
-static void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
- int first_index, int count);
-
-/* Increase a stat by cnt while holding syncp seqlock on 32bit machines */
-static void ena_increase_stat(u64 *statp, u64 cnt,
- struct u64_stats_sync *syncp)
-{
- u64_stats_update_begin(syncp);
- (*statp) += cnt;
- u64_stats_update_end(syncp);
-}
-
-static void ena_ring_tx_doorbell(struct ena_ring *tx_ring)
-{
- ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
- ena_increase_stat(&tx_ring->tx_stats.doorbells, 1, &tx_ring->syncp);
-}
-
static void ena_tx_timeout(struct net_device *dev, unsigned int txqueue)
{
struct ena_adapter *adapter = netdev_priv(dev);
@@ -135,19 +88,18 @@ static int ena_change_mtu(struct net_device *dev, int new_mtu)
return ret;
}
-static int ena_xmit_common(struct net_device *dev,
- struct ena_ring *ring,
- struct ena_tx_buffer *tx_info,
- struct ena_com_tx_ctx *ena_tx_ctx,
- u16 next_to_use,
- u32 bytes)
+int ena_xmit_common(struct ena_adapter *adapter,
+ struct ena_ring *ring,
+ struct ena_tx_buffer *tx_info,
+ struct ena_com_tx_ctx *ena_tx_ctx,
+ u16 next_to_use,
+ u32 bytes)
{
- struct ena_adapter *adapter = netdev_priv(dev);
int rc, nb_hw_desc;
if (unlikely(ena_com_is_doorbell_needed(ring->ena_com_io_sq,
ena_tx_ctx))) {
- netif_dbg(adapter, tx_queued, dev,
+ netif_dbg(adapter, tx_queued, adapter->netdev,
"llq tx max burst size of queue %d achieved, writing doorbell to send burst\n",
ring->qid);
ena_ring_tx_doorbell(ring);
@@ -162,7 +114,7 @@ static int ena_xmit_common(struct net_device *dev,
* ena_com_prepare_tx() are fatal and therefore require a device reset.
*/
if (unlikely(rc)) {
- netif_err(adapter, tx_queued, dev,
+ netif_err(adapter, tx_queued, adapter->netdev,
"Failed to prepare tx bufs\n");
ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1,
&ring->syncp);
@@ -178,6 +130,7 @@ static int ena_xmit_common(struct net_device *dev,
u64_stats_update_end(&ring->syncp);
tx_info->tx_descs = nb_hw_desc;
+ tx_info->total_tx_size = bytes;
tx_info->last_jiffies = jiffies;
tx_info->print_once = 0;
@@ -186,467 +139,6 @@ static int ena_xmit_common(struct net_device *dev,
return 0;
}
-/* This is the XDP napi callback. XDP queues use a separate napi callback
- * than Rx/Tx queues.
- */
-static int ena_xdp_io_poll(struct napi_struct *napi, int budget)
-{
- struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
- u32 xdp_work_done, xdp_budget;
- struct ena_ring *xdp_ring;
- int napi_comp_call = 0;
- int ret;
-
- xdp_ring = ena_napi->xdp_ring;
-
- xdp_budget = budget;
-
- if (!test_bit(ENA_FLAG_DEV_UP, &xdp_ring->adapter->flags) ||
- test_bit(ENA_FLAG_TRIGGER_RESET, &xdp_ring->adapter->flags)) {
- napi_complete_done(napi, 0);
- return 0;
- }
-
- xdp_work_done = ena_clean_xdp_irq(xdp_ring, xdp_budget);
-
- /* If the device is about to reset or down, avoid unmask
- * the interrupt and return 0 so NAPI won't reschedule
- */
- if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &xdp_ring->adapter->flags))) {
- napi_complete_done(napi, 0);
- ret = 0;
- } else if (xdp_budget > xdp_work_done) {
- napi_comp_call = 1;
- if (napi_complete_done(napi, xdp_work_done))
- ena_unmask_interrupt(xdp_ring, NULL);
- ena_update_ring_numa_node(xdp_ring, NULL);
- ret = xdp_work_done;
- } else {
- ret = xdp_budget;
- }
-
- u64_stats_update_begin(&xdp_ring->syncp);
- xdp_ring->tx_stats.napi_comp += napi_comp_call;
- xdp_ring->tx_stats.tx_poll++;
- u64_stats_update_end(&xdp_ring->syncp);
- xdp_ring->tx_stats.last_napi_jiffies = jiffies;
-
- return ret;
-}
-
-static int ena_xdp_tx_map_frame(struct ena_ring *xdp_ring,
- struct ena_tx_buffer *tx_info,
- struct xdp_frame *xdpf,
- struct ena_com_tx_ctx *ena_tx_ctx)
-{
- struct ena_adapter *adapter = xdp_ring->adapter;
- struct ena_com_buf *ena_buf;
- int push_len = 0;
- dma_addr_t dma;
- void *data;
- u32 size;
-
- tx_info->xdpf = xdpf;
- data = tx_info->xdpf->data;
- size = tx_info->xdpf->len;
-
- if (xdp_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
- /* Designate part of the packet for LLQ */
- push_len = min_t(u32, size, xdp_ring->tx_max_header_size);
-
- ena_tx_ctx->push_header = data;
-
- size -= push_len;
- data += push_len;
- }
-
- ena_tx_ctx->header_len = push_len;
-
- if (size > 0) {
- dma = dma_map_single(xdp_ring->dev,
- data,
- size,
- DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(xdp_ring->dev, dma)))
- goto error_report_dma_error;
-
- tx_info->map_linear_data = 0;
-
- ena_buf = tx_info->bufs;
- ena_buf->paddr = dma;
- ena_buf->len = size;
-
- ena_tx_ctx->ena_bufs = ena_buf;
- ena_tx_ctx->num_bufs = tx_info->num_of_bufs = 1;
- }
-
- return 0;
-
-error_report_dma_error:
- ena_increase_stat(&xdp_ring->tx_stats.dma_mapping_err, 1,
- &xdp_ring->syncp);
- netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map xdp buff\n");
-
- return -EINVAL;
-}
-
-static int ena_xdp_xmit_frame(struct ena_ring *xdp_ring,
- struct net_device *dev,
- struct xdp_frame *xdpf,
- int flags)
-{
- struct ena_com_tx_ctx ena_tx_ctx = {};
- struct ena_tx_buffer *tx_info;
- u16 next_to_use, req_id;
- int rc;
-
- next_to_use = xdp_ring->next_to_use;
- req_id = xdp_ring->free_ids[next_to_use];
- tx_info = &xdp_ring->tx_buffer_info[req_id];
- tx_info->num_of_bufs = 0;
-
- rc = ena_xdp_tx_map_frame(xdp_ring, tx_info, xdpf, &ena_tx_ctx);
- if (unlikely(rc))
- return rc;
-
- ena_tx_ctx.req_id = req_id;
-
- rc = ena_xmit_common(dev,
- xdp_ring,
- tx_info,
- &ena_tx_ctx,
- next_to_use,
- xdpf->len);
- if (rc)
- goto error_unmap_dma;
-
- /* trigger the dma engine. ena_ring_tx_doorbell()
- * calls a memory barrier inside it.
- */
- if (flags & XDP_XMIT_FLUSH)
- ena_ring_tx_doorbell(xdp_ring);
-
- return rc;
-
-error_unmap_dma:
- ena_unmap_tx_buff(xdp_ring, tx_info);
- tx_info->xdpf = NULL;
- return rc;
-}
-
-static int ena_xdp_xmit(struct net_device *dev, int n,
- struct xdp_frame **frames, u32 flags)
-{
- struct ena_adapter *adapter = netdev_priv(dev);
- struct ena_ring *xdp_ring;
- int qid, i, nxmit = 0;
-
- if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
- return -EINVAL;
-
- if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
- return -ENETDOWN;
-
- /* We assume that all rings have the same XDP program */
- if (!READ_ONCE(adapter->rx_ring->xdp_bpf_prog))
- return -ENXIO;
-
- qid = smp_processor_id() % adapter->xdp_num_queues;
- qid += adapter->xdp_first_ring;
- xdp_ring = &adapter->tx_ring[qid];
-
- /* Other CPU ids might try to send thorugh this queue */
- spin_lock(&xdp_ring->xdp_tx_lock);
-
- for (i = 0; i < n; i++) {
- if (ena_xdp_xmit_frame(xdp_ring, dev, frames[i], 0))
- break;
- nxmit++;
- }
-
- /* Ring doorbell to make device aware of the packets */
- if (flags & XDP_XMIT_FLUSH)
- ena_ring_tx_doorbell(xdp_ring);
-
- spin_unlock(&xdp_ring->xdp_tx_lock);
-
- /* Return number of packets sent */
- return nxmit;
-}
-
-static int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)
-{
- u32 verdict = ENA_XDP_PASS;
- struct bpf_prog *xdp_prog;
- struct ena_ring *xdp_ring;
- struct xdp_frame *xdpf;
- u64 *xdp_stat;
-
- xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
-
- if (!xdp_prog)
- goto out;
-
- verdict = bpf_prog_run_xdp(xdp_prog, xdp);
-
- switch (verdict) {
- case XDP_TX:
- xdpf = xdp_convert_buff_to_frame(xdp);
- if (unlikely(!xdpf)) {
- trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
- xdp_stat = &rx_ring->rx_stats.xdp_aborted;
- verdict = ENA_XDP_DROP;
- break;
- }
-
- /* Find xmit queue */
- xdp_ring = rx_ring->xdp_ring;
-
- /* The XDP queues are shared between XDP_TX and XDP_REDIRECT */
- spin_lock(&xdp_ring->xdp_tx_lock);
-
- if (ena_xdp_xmit_frame(xdp_ring, rx_ring->netdev, xdpf,
- XDP_XMIT_FLUSH))
- xdp_return_frame(xdpf);
-
- spin_unlock(&xdp_ring->xdp_tx_lock);
- xdp_stat = &rx_ring->rx_stats.xdp_tx;
- verdict = ENA_XDP_TX;
- break;
- case XDP_REDIRECT:
- if (likely(!xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog))) {
- xdp_stat = &rx_ring->rx_stats.xdp_redirect;
- verdict = ENA_XDP_REDIRECT;
- break;
- }
- trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
- xdp_stat = &rx_ring->rx_stats.xdp_aborted;
- verdict = ENA_XDP_DROP;
- break;
- case XDP_ABORTED:
- trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
- xdp_stat = &rx_ring->rx_stats.xdp_aborted;
- verdict = ENA_XDP_DROP;
- break;
- case XDP_DROP:
- xdp_stat = &rx_ring->rx_stats.xdp_drop;
- verdict = ENA_XDP_DROP;
- break;
- case XDP_PASS:
- xdp_stat = &rx_ring->rx_stats.xdp_pass;
- verdict = ENA_XDP_PASS;
- break;
- default:
- bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, verdict);
- xdp_stat = &rx_ring->rx_stats.xdp_invalid;
- verdict = ENA_XDP_DROP;
- }
-
- ena_increase_stat(xdp_stat, 1, &rx_ring->syncp);
-out:
- return verdict;
-}
-
-static void ena_init_all_xdp_queues(struct ena_adapter *adapter)
-{
- adapter->xdp_first_ring = adapter->num_io_queues;
- adapter->xdp_num_queues = adapter->num_io_queues;
-
- ena_init_io_rings(adapter,
- adapter->xdp_first_ring,
- adapter->xdp_num_queues);
-}
-
-static int ena_setup_and_create_all_xdp_queues(struct ena_adapter *adapter)
-{
- u32 xdp_first_ring = adapter->xdp_first_ring;
- u32 xdp_num_queues = adapter->xdp_num_queues;
- int rc = 0;
-
- rc = ena_setup_tx_resources_in_range(adapter, xdp_first_ring, xdp_num_queues);
- if (rc)
- goto setup_err;
-
- rc = ena_create_io_tx_queues_in_range(adapter, xdp_first_ring, xdp_num_queues);
- if (rc)
- goto create_err;
-
- return 0;
-
-create_err:
- ena_free_all_io_tx_resources_in_range(adapter, xdp_first_ring, xdp_num_queues);
-setup_err:
- return rc;
-}
-
-/* Provides a way for both kernel and bpf-prog to know
- * more about the RX-queue a given XDP frame arrived on.
- */
-static int ena_xdp_register_rxq_info(struct ena_ring *rx_ring)
-{
- int rc;
-
- rc = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, rx_ring->qid, 0);
-
- if (rc) {
- netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
- "Failed to register xdp rx queue info. RX queue num %d rc: %d\n",
- rx_ring->qid, rc);
- goto err;
- }
-
- rc = xdp_rxq_info_reg_mem_model(&rx_ring->xdp_rxq, MEM_TYPE_PAGE_SHARED,
- NULL);
-
- if (rc) {
- netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
- "Failed to register xdp rx queue info memory model. RX queue num %d rc: %d\n",
- rx_ring->qid, rc);
- xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
- }
-
-err:
- return rc;
-}
-
-static void ena_xdp_unregister_rxq_info(struct ena_ring *rx_ring)
-{
- xdp_rxq_info_unreg_mem_model(&rx_ring->xdp_rxq);
- xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
-}
-
-static void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,
- struct bpf_prog *prog,
- int first, int count)
-{
- struct bpf_prog *old_bpf_prog;
- struct ena_ring *rx_ring;
- int i = 0;
-
- for (i = first; i < count; i++) {
- rx_ring = &adapter->rx_ring[i];
- old_bpf_prog = xchg(&rx_ring->xdp_bpf_prog, prog);
-
- if (!old_bpf_prog && prog) {
- ena_xdp_register_rxq_info(rx_ring);
- rx_ring->rx_headroom = XDP_PACKET_HEADROOM;
- } else if (old_bpf_prog && !prog) {
- ena_xdp_unregister_rxq_info(rx_ring);
- rx_ring->rx_headroom = NET_SKB_PAD;
- }
- }
-}
-
-static void ena_xdp_exchange_program(struct ena_adapter *adapter,
- struct bpf_prog *prog)
-{
- struct bpf_prog *old_bpf_prog = xchg(&adapter->xdp_bpf_prog, prog);
-
- ena_xdp_exchange_program_rx_in_range(adapter,
- prog,
- 0,
- adapter->num_io_queues);
-
- if (old_bpf_prog)
- bpf_prog_put(old_bpf_prog);
-}
-
-static int ena_destroy_and_free_all_xdp_queues(struct ena_adapter *adapter)
-{
- bool was_up;
- int rc;
-
- was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
-
- if (was_up)
- ena_down(adapter);
-
- adapter->xdp_first_ring = 0;
- adapter->xdp_num_queues = 0;
- ena_xdp_exchange_program(adapter, NULL);
- if (was_up) {
- rc = ena_up(adapter);
- if (rc)
- return rc;
- }
- return 0;
-}
-
-static int ena_xdp_set(struct net_device *netdev, struct netdev_bpf *bpf)
-{
- struct ena_adapter *adapter = netdev_priv(netdev);
- struct bpf_prog *prog = bpf->prog;
- struct bpf_prog *old_bpf_prog;
- int rc, prev_mtu;
- bool is_up;
-
- is_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
- rc = ena_xdp_allowed(adapter);
- if (rc == ENA_XDP_ALLOWED) {
- old_bpf_prog = adapter->xdp_bpf_prog;
- if (prog) {
- if (!is_up) {
- ena_init_all_xdp_queues(adapter);
- } else if (!old_bpf_prog) {
- ena_down(adapter);
- ena_init_all_xdp_queues(adapter);
- }
- ena_xdp_exchange_program(adapter, prog);
-
- if (is_up && !old_bpf_prog) {
- rc = ena_up(adapter);
- if (rc)
- return rc;
- }
- xdp_features_set_redirect_target(netdev, false);
- } else if (old_bpf_prog) {
- xdp_features_clear_redirect_target(netdev);
- rc = ena_destroy_and_free_all_xdp_queues(adapter);
- if (rc)
- return rc;
- }
-
- prev_mtu = netdev->max_mtu;
- netdev->max_mtu = prog ? ENA_XDP_MAX_MTU : adapter->max_mtu;
-
- if (!old_bpf_prog)
- netif_info(adapter, drv, adapter->netdev,
- "XDP program is set, changing the max_mtu from %d to %d",
- prev_mtu, netdev->max_mtu);
-
- } else if (rc == ENA_XDP_CURRENT_MTU_TOO_LARGE) {
- netif_err(adapter, drv, adapter->netdev,
- "Failed to set xdp program, the current MTU (%d) is larger than the maximum allowed MTU (%lu) while xdp is on",
- netdev->mtu, ENA_XDP_MAX_MTU);
- NL_SET_ERR_MSG_MOD(bpf->extack,
- "Failed to set xdp program, the current MTU is larger than the maximum allowed MTU. Check the dmesg for more info");
- return -EINVAL;
- } else if (rc == ENA_XDP_NO_ENOUGH_QUEUES) {
- netif_err(adapter, drv, adapter->netdev,
- "Failed to set xdp program, the Rx/Tx channel count should be at most half of the maximum allowed channel count. The current queue count (%d), the maximal queue count (%d)\n",
- adapter->num_io_queues, adapter->max_num_io_queues);
- NL_SET_ERR_MSG_MOD(bpf->extack,
- "Failed to set xdp program, there is no enough space for allocating XDP queues, Check the dmesg for more info");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* This is the main xdp callback, it's used by the kernel to set/unset the xdp
- * program as well as to query the current xdp program id.
- */
-static int ena_xdp(struct net_device *netdev, struct netdev_bpf *bpf)
-{
- switch (bpf->command) {
- case XDP_SETUP_PROG:
- return ena_xdp_set(netdev, bpf);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static int ena_init_rx_cpu_rmap(struct ena_adapter *adapter)
{
#ifdef CONFIG_RFS_ACCEL
@@ -688,8 +180,8 @@ static void ena_init_io_rings_common(struct ena_adapter *adapter,
u64_stats_init(&ring->syncp);
}
-static void ena_init_io_rings(struct ena_adapter *adapter,
- int first_index, int count)
+void ena_init_io_rings(struct ena_adapter *adapter,
+ int first_index, int count)
{
struct ena_com_dev *ena_dev;
struct ena_ring *txr, *rxr;
@@ -820,9 +312,8 @@ static void ena_free_tx_resources(struct ena_adapter *adapter, int qid)
tx_ring->push_buf_intermediate_buf = NULL;
}
-static int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
- int first_index,
- int count)
+int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
+ int first_index, int count)
{
int i, rc = 0;
@@ -845,8 +336,8 @@ err_setup_tx:
return rc;
}
-static void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
- int first_index, int count)
+void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
+ int first_index, int count)
{
int i;
@@ -859,7 +350,7 @@ static void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
*
* Free all transmit software resources
*/
-static void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
+void ena_free_all_io_tx_resources(struct ena_adapter *adapter)
{
ena_free_all_io_tx_resources_in_range(adapter,
0,
@@ -1169,8 +660,8 @@ static void ena_free_all_rx_bufs(struct ena_adapter *adapter)
ena_free_rx_bufs(adapter, i);
}
-static void ena_unmap_tx_buff(struct ena_ring *tx_ring,
- struct ena_tx_buffer *tx_info)
+void ena_unmap_tx_buff(struct ena_ring *tx_ring,
+ struct ena_tx_buffer *tx_info)
{
struct ena_com_buf *ena_buf;
u32 cnt;
@@ -1262,6 +753,7 @@ static void ena_destroy_all_rx_queues(struct ena_adapter *adapter)
for (i = 0; i < adapter->num_io_queues; i++) {
ena_qid = ENA_IO_RXQ_IDX(i);
cancel_work_sync(&adapter->ena_napi[i].dim.work);
+ ena_xdp_unregister_rxq_info(&adapter->rx_ring[i]);
ena_com_destroy_io_queue(adapter->ena_dev, ena_qid);
}
}
@@ -1272,8 +764,8 @@ static void ena_destroy_all_io_queues(struct ena_adapter *adapter)
ena_destroy_all_rx_queues(adapter);
}
-static int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
- struct ena_tx_buffer *tx_info, bool is_xdp)
+int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
+ struct ena_tx_buffer *tx_info, bool is_xdp)
{
if (tx_info)
netif_err(ring->adapter,
@@ -1305,17 +797,6 @@ static int validate_tx_req_id(struct ena_ring *tx_ring, u16 req_id)
return handle_invalid_req_id(tx_ring, req_id, tx_info, false);
}
-static int validate_xdp_req_id(struct ena_ring *xdp_ring, u16 req_id)
-{
- struct ena_tx_buffer *tx_info;
-
- tx_info = &xdp_ring->tx_buffer_info[req_id];
- if (likely(tx_info->xdpf))
- return 0;
-
- return handle_invalid_req_id(xdp_ring, req_id, tx_info, true);
-}
-
static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
{
struct netdev_queue *txq;
@@ -1363,7 +844,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget)
"tx_poll: q %d skb %p completed\n", tx_ring->qid,
skb);
- tx_bytes += skb->len;
+ tx_bytes += tx_info->total_tx_size;
dev_kfree_skb(skb);
tx_pkts++;
total_done += tx_info->tx_descs;
@@ -1688,6 +1169,7 @@ static int ena_xdp_handle_buff(struct ena_ring *rx_ring, struct xdp_buff *xdp, u
return ret;
}
+
/* ena_clean_rx_irq - Cleanup RX irq
* @rx_ring: RX ring to clean
* @napi: napi handler
@@ -1880,8 +1362,8 @@ static void ena_adjust_adaptive_rx_intr_moderation(struct ena_napi *ena_napi)
rx_ring->per_napi_packets = 0;
}
-static void ena_unmask_interrupt(struct ena_ring *tx_ring,
- struct ena_ring *rx_ring)
+void ena_unmask_interrupt(struct ena_ring *tx_ring,
+ struct ena_ring *rx_ring)
{
u32 rx_interval = tx_ring->smoothed_interval;
struct ena_eth_io_intr_reg intr_reg;
@@ -1913,8 +1395,8 @@ static void ena_unmask_interrupt(struct ena_ring *tx_ring,
ena_com_unmask_intr(tx_ring->ena_com_io_cq, &intr_reg);
}
-static void ena_update_ring_numa_node(struct ena_ring *tx_ring,
- struct ena_ring *rx_ring)
+void ena_update_ring_numa_node(struct ena_ring *tx_ring,
+ struct ena_ring *rx_ring)
{
int cpu = get_cpu();
int numa_node;
@@ -1949,67 +1431,6 @@ out:
put_cpu();
}
-static int ena_clean_xdp_irq(struct ena_ring *xdp_ring, u32 budget)
-{
- u32 total_done = 0;
- u16 next_to_clean;
- int tx_pkts = 0;
- u16 req_id;
- int rc;
-
- if (unlikely(!xdp_ring))
- return 0;
- next_to_clean = xdp_ring->next_to_clean;
-
- while (tx_pkts < budget) {
- struct ena_tx_buffer *tx_info;
- struct xdp_frame *xdpf;
-
- rc = ena_com_tx_comp_req_id_get(xdp_ring->ena_com_io_cq,
- &req_id);
- if (rc) {
- if (unlikely(rc == -EINVAL))
- handle_invalid_req_id(xdp_ring, req_id, NULL,
- true);
- break;
- }
-
- /* validate that the request id points to a valid xdp_frame */
- rc = validate_xdp_req_id(xdp_ring, req_id);
- if (rc)
- break;
-
- tx_info = &xdp_ring->tx_buffer_info[req_id];
- xdpf = tx_info->xdpf;
-
- tx_info->xdpf = NULL;
- tx_info->last_jiffies = 0;
- ena_unmap_tx_buff(xdp_ring, tx_info);
-
- netif_dbg(xdp_ring->adapter, tx_done, xdp_ring->netdev,
- "tx_poll: q %d skb %p completed\n", xdp_ring->qid,
- xdpf);
-
- tx_pkts++;
- total_done += tx_info->tx_descs;
-
- xdp_return_frame(xdpf);
- xdp_ring->free_ids[next_to_clean] = req_id;
- next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
- xdp_ring->ring_size);
- }
-
- xdp_ring->next_to_clean = next_to_clean;
- ena_com_comp_ack(xdp_ring->ena_com_io_sq, total_done);
- ena_com_update_dev_comp_head(xdp_ring->ena_com_io_cq);
-
- netif_dbg(xdp_ring->adapter, tx_done, xdp_ring->netdev,
- "tx_poll: q %d done. total pkts: %d\n",
- xdp_ring->qid, tx_pkts);
-
- return tx_pkts;
-}
-
static int ena_io_poll(struct napi_struct *napi, int budget)
{
struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
@@ -2326,28 +1747,36 @@ static void ena_del_napi_in_range(struct ena_adapter *adapter,
for (i = first_index; i < first_index + count; i++) {
netif_napi_del(&adapter->ena_napi[i].napi);
- WARN_ON(!ENA_IS_XDP_INDEX(adapter, i) &&
- adapter->ena_napi[i].xdp_ring);
+ WARN_ON(ENA_IS_XDP_INDEX(adapter, i) &&
+ adapter->ena_napi[i].rx_ring);
}
}
static void ena_init_napi_in_range(struct ena_adapter *adapter,
int first_index, int count)
{
+ int (*napi_handler)(struct napi_struct *napi, int budget);
int i;
for (i = first_index; i < first_index + count; i++) {
struct ena_napi *napi = &adapter->ena_napi[i];
+ struct ena_ring *rx_ring, *tx_ring;
- netif_napi_add(adapter->netdev, &napi->napi,
- ENA_IS_XDP_INDEX(adapter, i) ? ena_xdp_io_poll : ena_io_poll);
+ memset(napi, 0, sizeof(*napi));
- if (!ENA_IS_XDP_INDEX(adapter, i)) {
- napi->rx_ring = &adapter->rx_ring[i];
- napi->tx_ring = &adapter->tx_ring[i];
- } else {
- napi->xdp_ring = &adapter->tx_ring[i];
- }
+ rx_ring = &adapter->rx_ring[i];
+ tx_ring = &adapter->tx_ring[i];
+
+ napi_handler = ena_io_poll;
+ if (ENA_IS_XDP_INDEX(adapter, i))
+ napi_handler = ena_xdp_io_poll;
+
+ netif_napi_add(adapter->netdev, &napi->napi, napi_handler);
+
+ if (!ENA_IS_XDP_INDEX(adapter, i))
+ napi->rx_ring = rx_ring;
+
+ napi->tx_ring = tx_ring;
napi->qid = i;
}
}
@@ -2475,8 +1904,8 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid)
return rc;
}
-static int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
- int first_index, int count)
+int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
+ int first_index, int count)
{
struct ena_com_dev *ena_dev = adapter->ena_dev;
int rc, i;
@@ -2556,12 +1985,15 @@ static int ena_create_all_io_rx_queues(struct ena_adapter *adapter)
if (rc)
goto create_err;
INIT_WORK(&adapter->ena_napi[i].dim.work, ena_dim_work);
+
+ ena_xdp_register_rxq_info(&adapter->rx_ring[i]);
}
return 0;
create_err:
while (i--) {
+ ena_xdp_unregister_rxq_info(&adapter->rx_ring[i]);
cancel_work_sync(&adapter->ena_napi[i].dim.work);
ena_com_destroy_io_queue(ena_dev, ENA_IO_RXQ_IDX(i));
}
@@ -2686,7 +2118,7 @@ err_setup_tx:
}
}
-static int ena_up(struct ena_adapter *adapter)
+int ena_up(struct ena_adapter *adapter)
{
int io_queue_count, rc, i;
@@ -2748,7 +2180,7 @@ err_req_irq:
return rc;
}
-static void ena_down(struct ena_adapter *adapter)
+void ena_down(struct ena_adapter *adapter)
{
int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
@@ -3179,7 +2611,7 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set flags and meta data */
ena_tx_csum(&ena_tx_ctx, skb, tx_ring->disable_meta_caching);
- rc = ena_xmit_common(dev,
+ rc = ena_xmit_common(adapter,
tx_ring,
tx_info,
&ena_tx_ctx,
@@ -3275,8 +2707,8 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pd
strscpy(host_info->kernel_ver_str, utsname()->version,
sizeof(host_info->kernel_ver_str) - 1);
host_info->os_dist = 0;
- strncpy(host_info->os_dist_str, utsname()->release,
- sizeof(host_info->os_dist_str) - 1);
+ strscpy(host_info->os_dist_str, utsname()->release,
+ sizeof(host_info->os_dist_str));
host_info->driver_version =
(DRV_MODULE_GEN_MAJOR) |
(DRV_MODULE_GEN_MINOR << ENA_ADMIN_HOST_INFO_MINOR_SHIFT) |
@@ -3363,6 +2795,7 @@ static void ena_get_stats64(struct net_device *netdev,
{
struct ena_adapter *adapter = netdev_priv(netdev);
struct ena_ring *rx_ring, *tx_ring;
+ u64 total_xdp_rx_drops = 0;
unsigned int start;
u64 rx_drops;
u64 tx_drops;
@@ -3371,8 +2804,8 @@ static void ena_get_stats64(struct net_device *netdev,
if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
return;
- for (i = 0; i < adapter->num_io_queues; i++) {
- u64 bytes, packets;
+ for (i = 0; i < adapter->num_io_queues + adapter->xdp_num_queues; i++) {
+ u64 bytes, packets, xdp_rx_drops;
tx_ring = &adapter->tx_ring[i];
@@ -3385,16 +2818,22 @@ static void ena_get_stats64(struct net_device *netdev,
stats->tx_packets += packets;
stats->tx_bytes += bytes;
+ /* In XDP there isn't an RX queue counterpart */
+ if (ENA_IS_XDP_INDEX(adapter, i))
+ continue;
+
rx_ring = &adapter->rx_ring[i];
do {
start = u64_stats_fetch_begin(&rx_ring->syncp);
packets = rx_ring->rx_stats.cnt;
bytes = rx_ring->rx_stats.bytes;
+ xdp_rx_drops = rx_ring->rx_stats.xdp_drop;
} while (u64_stats_fetch_retry(&rx_ring->syncp, start));
stats->rx_packets += packets;
stats->rx_bytes += bytes;
+ total_xdp_rx_drops += xdp_rx_drops;
}
do {
@@ -3403,7 +2842,7 @@ static void ena_get_stats64(struct net_device *netdev,
tx_drops = adapter->dev_stats.tx_drops;
} while (u64_stats_fetch_retry(&adapter->syncp, start));
- stats->rx_dropped = rx_drops;
+ stats->rx_dropped = rx_drops + total_xdp_rx_drops;
stats->tx_dropped = tx_drops;
stats->multicast = 0;
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h
index 33c923e1261a..6d2cc20210cc 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.h
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h
@@ -110,19 +110,6 @@
#define ENA_MMIO_DISABLE_REG_READ BIT(0)
-/* The max MTU size is configured to be the ethernet frame size without
- * the overhead of the ethernet header, which can have a VLAN header, and
- * a frame check sequence (FCS).
- * The buffer size we share with the device is defined to be ENA_PAGE_SIZE
- */
-
-#define ENA_XDP_MAX_MTU (ENA_PAGE_SIZE - ETH_HLEN - ETH_FCS_LEN - \
- VLAN_HLEN - XDP_PACKET_HEADROOM - \
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
-
-#define ENA_IS_XDP_INDEX(adapter, index) (((index) >= (adapter)->xdp_first_ring) && \
- ((index) < (adapter)->xdp_first_ring + (adapter)->xdp_num_queues))
-
struct ena_irq {
irq_handler_t handler;
void *data;
@@ -138,13 +125,18 @@ struct ena_napi {
struct napi_struct napi;
struct ena_ring *tx_ring;
struct ena_ring *rx_ring;
- struct ena_ring *xdp_ring;
u32 qid;
struct dim dim;
};
struct ena_tx_buffer {
- struct sk_buff *skb;
+ union {
+ struct sk_buff *skb;
+ /* XDP buffer structure which is used for sending packets in
+ * the xdp queues
+ */
+ struct xdp_frame *xdpf;
+ };
/* num of ena desc for this specific skb
* (includes data desc and metadata desc)
*/
@@ -152,16 +144,14 @@ struct ena_tx_buffer {
/* num of buffers used by this skb */
u32 num_of_bufs;
- /* XDP buffer structure which is used for sending packets in
- * the xdp queues
- */
- struct xdp_frame *xdpf;
+ /* Total size of all buffers in bytes */
+ u32 total_tx_size;
/* Indicate if bufs[0] map the linear data of the skb. */
u8 map_linear_data;
/* Used for detect missing tx packets to limit the number of prints */
- u32 print_once;
+ u8 print_once;
/* Save the last jiffies to detect missing tx packets
*
* sets to non zero value on ena_start_xmit and set to zero on
@@ -421,47 +411,44 @@ static inline void ena_reset_device(struct ena_adapter *adapter,
set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags);
}
-enum ena_xdp_errors_t {
- ENA_XDP_ALLOWED = 0,
- ENA_XDP_CURRENT_MTU_TOO_LARGE,
- ENA_XDP_NO_ENOUGH_QUEUES,
-};
+int handle_invalid_req_id(struct ena_ring *ring, u16 req_id,
+ struct ena_tx_buffer *tx_info, bool is_xdp);
-enum ENA_XDP_ACTIONS {
- ENA_XDP_PASS = 0,
- ENA_XDP_TX = BIT(0),
- ENA_XDP_REDIRECT = BIT(1),
- ENA_XDP_DROP = BIT(2)
-};
-
-#define ENA_XDP_FORWARDED (ENA_XDP_TX | ENA_XDP_REDIRECT)
-
-static inline bool ena_xdp_present(struct ena_adapter *adapter)
-{
- return !!adapter->xdp_bpf_prog;
-}
-
-static inline bool ena_xdp_present_ring(struct ena_ring *ring)
+/* Increase a stat by cnt while holding syncp seqlock on 32bit machines */
+static inline void ena_increase_stat(u64 *statp, u64 cnt,
+ struct u64_stats_sync *syncp)
{
- return !!ring->xdp_bpf_prog;
+ u64_stats_update_begin(syncp);
+ (*statp) += cnt;
+ u64_stats_update_end(syncp);
}
-static inline bool ena_xdp_legal_queue_count(struct ena_adapter *adapter,
- u32 queues)
+static inline void ena_ring_tx_doorbell(struct ena_ring *tx_ring)
{
- return 2 * queues <= adapter->max_num_io_queues;
-}
-
-static inline enum ena_xdp_errors_t ena_xdp_allowed(struct ena_adapter *adapter)
-{
- enum ena_xdp_errors_t rc = ENA_XDP_ALLOWED;
-
- if (adapter->netdev->mtu > ENA_XDP_MAX_MTU)
- rc = ENA_XDP_CURRENT_MTU_TOO_LARGE;
- else if (!ena_xdp_legal_queue_count(adapter, adapter->num_io_queues))
- rc = ENA_XDP_NO_ENOUGH_QUEUES;
-
- return rc;
+ ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq);
+ ena_increase_stat(&tx_ring->tx_stats.doorbells, 1, &tx_ring->syncp);
}
+int ena_xmit_common(struct ena_adapter *adapter,
+ struct ena_ring *ring,
+ struct ena_tx_buffer *tx_info,
+ struct ena_com_tx_ctx *ena_tx_ctx,
+ u16 next_to_use,
+ u32 bytes);
+void ena_unmap_tx_buff(struct ena_ring *tx_ring,
+ struct ena_tx_buffer *tx_info);
+void ena_init_io_rings(struct ena_adapter *adapter,
+ int first_index, int count);
+int ena_create_io_tx_queues_in_range(struct ena_adapter *adapter,
+ int first_index, int count);
+int ena_setup_tx_resources_in_range(struct ena_adapter *adapter,
+ int first_index, int count);
+void ena_free_all_io_tx_resources_in_range(struct ena_adapter *adapter,
+ int first_index, int count);
+void ena_free_all_io_tx_resources(struct ena_adapter *adapter);
+void ena_down(struct ena_adapter *adapter);
+int ena_up(struct ena_adapter *adapter);
+void ena_unmask_interrupt(struct ena_ring *tx_ring, struct ena_ring *rx_ring);
+void ena_update_ring_numa_node(struct ena_ring *tx_ring,
+ struct ena_ring *rx_ring);
#endif /* !(ENA_H) */
diff --git a/drivers/net/ethernet/amazon/ena/ena_xdp.c b/drivers/net/ethernet/amazon/ena/ena_xdp.c
new file mode 100644
index 000000000000..fc1c4ef73ba3
--- /dev/null
+++ b/drivers/net/ethernet/amazon/ena/ena_xdp.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright 2015-2021 Amazon.com, Inc. or its affiliates. All rights reserved.
+ */
+
+#include "ena_xdp.h"
+
+static int validate_xdp_req_id(struct ena_ring *tx_ring, u16 req_id)
+{
+ struct ena_tx_buffer *tx_info;
+
+ tx_info = &tx_ring->tx_buffer_info[req_id];
+ if (likely(tx_info->xdpf))
+ return 0;
+
+ return handle_invalid_req_id(tx_ring, req_id, tx_info, true);
+}
+
+static int ena_xdp_tx_map_frame(struct ena_ring *tx_ring,
+ struct ena_tx_buffer *tx_info,
+ struct xdp_frame *xdpf,
+ struct ena_com_tx_ctx *ena_tx_ctx)
+{
+ struct ena_adapter *adapter = tx_ring->adapter;
+ struct ena_com_buf *ena_buf;
+ int push_len = 0;
+ dma_addr_t dma;
+ void *data;
+ u32 size;
+
+ tx_info->xdpf = xdpf;
+ data = tx_info->xdpf->data;
+ size = tx_info->xdpf->len;
+
+ if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
+ /* Designate part of the packet for LLQ */
+ push_len = min_t(u32, size, tx_ring->tx_max_header_size);
+
+ ena_tx_ctx->push_header = data;
+
+ size -= push_len;
+ data += push_len;
+ }
+
+ ena_tx_ctx->header_len = push_len;
+
+ if (size > 0) {
+ dma = dma_map_single(tx_ring->dev,
+ data,
+ size,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
+ goto error_report_dma_error;
+
+ tx_info->map_linear_data = 0;
+
+ ena_buf = tx_info->bufs;
+ ena_buf->paddr = dma;
+ ena_buf->len = size;
+
+ ena_tx_ctx->ena_bufs = ena_buf;
+ ena_tx_ctx->num_bufs = tx_info->num_of_bufs = 1;
+ }
+
+ return 0;
+
+error_report_dma_error:
+ ena_increase_stat(&tx_ring->tx_stats.dma_mapping_err, 1,
+ &tx_ring->syncp);
+ netif_warn(adapter, tx_queued, adapter->netdev, "Failed to map xdp buff\n");
+
+ return -EINVAL;
+}
+
+int ena_xdp_xmit_frame(struct ena_ring *tx_ring,
+ struct ena_adapter *adapter,
+ struct xdp_frame *xdpf,
+ int flags)
+{
+ struct ena_com_tx_ctx ena_tx_ctx = {};
+ struct ena_tx_buffer *tx_info;
+ u16 next_to_use, req_id;
+ int rc;
+
+ next_to_use = tx_ring->next_to_use;
+ req_id = tx_ring->free_ids[next_to_use];
+ tx_info = &tx_ring->tx_buffer_info[req_id];
+ tx_info->num_of_bufs = 0;
+
+ rc = ena_xdp_tx_map_frame(tx_ring, tx_info, xdpf, &ena_tx_ctx);
+ if (unlikely(rc))
+ return rc;
+
+ ena_tx_ctx.req_id = req_id;
+
+ rc = ena_xmit_common(adapter,
+ tx_ring,
+ tx_info,
+ &ena_tx_ctx,
+ next_to_use,
+ xdpf->len);
+ if (rc)
+ goto error_unmap_dma;
+
+ /* trigger the dma engine. ena_ring_tx_doorbell()
+ * calls a memory barrier inside it.
+ */
+ if (flags & XDP_XMIT_FLUSH)
+ ena_ring_tx_doorbell(tx_ring);
+
+ return rc;
+
+error_unmap_dma:
+ ena_unmap_tx_buff(tx_ring, tx_info);
+ tx_info->xdpf = NULL;
+ return rc;
+}
+
+int ena_xdp_xmit(struct net_device *dev, int n,
+ struct xdp_frame **frames, u32 flags)
+{
+ struct ena_adapter *adapter = netdev_priv(dev);
+ struct ena_ring *tx_ring;
+ int qid, i, nxmit = 0;
+
+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
+ return -EINVAL;
+
+ if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags))
+ return -ENETDOWN;
+
+ /* We assume that all rings have the same XDP program */
+ if (!READ_ONCE(adapter->rx_ring->xdp_bpf_prog))
+ return -ENXIO;
+
+ qid = smp_processor_id() % adapter->xdp_num_queues;
+ qid += adapter->xdp_first_ring;
+ tx_ring = &adapter->tx_ring[qid];
+
+ /* Other CPU ids might try to send thorugh this queue */
+ spin_lock(&tx_ring->xdp_tx_lock);
+
+ for (i = 0; i < n; i++) {
+ if (ena_xdp_xmit_frame(tx_ring, adapter, frames[i], 0))
+ break;
+ nxmit++;
+ }
+
+ /* Ring doorbell to make device aware of the packets */
+ if (flags & XDP_XMIT_FLUSH)
+ ena_ring_tx_doorbell(tx_ring);
+
+ spin_unlock(&tx_ring->xdp_tx_lock);
+
+ /* Return number of packets sent */
+ return nxmit;
+}
+
+static void ena_init_all_xdp_queues(struct ena_adapter *adapter)
+{
+ adapter->xdp_first_ring = adapter->num_io_queues;
+ adapter->xdp_num_queues = adapter->num_io_queues;
+
+ ena_init_io_rings(adapter,
+ adapter->xdp_first_ring,
+ adapter->xdp_num_queues);
+}
+
+int ena_setup_and_create_all_xdp_queues(struct ena_adapter *adapter)
+{
+ u32 xdp_first_ring = adapter->xdp_first_ring;
+ u32 xdp_num_queues = adapter->xdp_num_queues;
+ int rc = 0;
+
+ rc = ena_setup_tx_resources_in_range(adapter, xdp_first_ring, xdp_num_queues);
+ if (rc)
+ goto setup_err;
+
+ rc = ena_create_io_tx_queues_in_range(adapter, xdp_first_ring, xdp_num_queues);
+ if (rc)
+ goto create_err;
+
+ return 0;
+
+create_err:
+ ena_free_all_io_tx_resources_in_range(adapter, xdp_first_ring, xdp_num_queues);
+setup_err:
+ return rc;
+}
+
+/* Provides a way for both kernel and bpf-prog to know
+ * more about the RX-queue a given XDP frame arrived on.
+ */
+int ena_xdp_register_rxq_info(struct ena_ring *rx_ring)
+{
+ int rc;
+
+ rc = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, rx_ring->qid, 0);
+
+ netif_dbg(rx_ring->adapter, ifup, rx_ring->netdev, "Registering RX info for queue %d",
+ rx_ring->qid);
+ if (rc) {
+ netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
+ "Failed to register xdp rx queue info. RX queue num %d rc: %d\n",
+ rx_ring->qid, rc);
+ goto err;
+ }
+
+ rc = xdp_rxq_info_reg_mem_model(&rx_ring->xdp_rxq, MEM_TYPE_PAGE_SHARED, NULL);
+
+ if (rc) {
+ netif_err(rx_ring->adapter, ifup, rx_ring->netdev,
+ "Failed to register xdp rx queue info memory model. RX queue num %d rc: %d\n",
+ rx_ring->qid, rc);
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+ }
+
+err:
+ return rc;
+}
+
+void ena_xdp_unregister_rxq_info(struct ena_ring *rx_ring)
+{
+ netif_dbg(rx_ring->adapter, ifdown, rx_ring->netdev,
+ "Unregistering RX info for queue %d",
+ rx_ring->qid);
+ xdp_rxq_info_unreg_mem_model(&rx_ring->xdp_rxq);
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+}
+
+void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,
+ struct bpf_prog *prog,
+ int first, int count)
+{
+ struct bpf_prog *old_bpf_prog;
+ struct ena_ring *rx_ring;
+ int i = 0;
+
+ for (i = first; i < count; i++) {
+ rx_ring = &adapter->rx_ring[i];
+ old_bpf_prog = xchg(&rx_ring->xdp_bpf_prog, prog);
+
+ if (!old_bpf_prog && prog) {
+ rx_ring->rx_headroom = XDP_PACKET_HEADROOM;
+ } else if (old_bpf_prog && !prog) {
+ rx_ring->rx_headroom = NET_SKB_PAD;
+ }
+ }
+}
+
+static void ena_xdp_exchange_program(struct ena_adapter *adapter,
+ struct bpf_prog *prog)
+{
+ struct bpf_prog *old_bpf_prog = xchg(&adapter->xdp_bpf_prog, prog);
+
+ ena_xdp_exchange_program_rx_in_range(adapter,
+ prog,
+ 0,
+ adapter->num_io_queues);
+
+ if (old_bpf_prog)
+ bpf_prog_put(old_bpf_prog);
+}
+
+static int ena_destroy_and_free_all_xdp_queues(struct ena_adapter *adapter)
+{
+ bool was_up;
+ int rc;
+
+ was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+
+ if (was_up)
+ ena_down(adapter);
+
+ adapter->xdp_first_ring = 0;
+ adapter->xdp_num_queues = 0;
+ ena_xdp_exchange_program(adapter, NULL);
+ if (was_up) {
+ rc = ena_up(adapter);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+static int ena_xdp_set(struct net_device *netdev, struct netdev_bpf *bpf)
+{
+ struct ena_adapter *adapter = netdev_priv(netdev);
+ struct bpf_prog *prog = bpf->prog;
+ struct bpf_prog *old_bpf_prog;
+ int rc, prev_mtu;
+ bool is_up;
+
+ is_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags);
+ rc = ena_xdp_allowed(adapter);
+ if (rc == ENA_XDP_ALLOWED) {
+ old_bpf_prog = adapter->xdp_bpf_prog;
+ if (prog) {
+ if (!is_up) {
+ ena_init_all_xdp_queues(adapter);
+ } else if (!old_bpf_prog) {
+ ena_down(adapter);
+ ena_init_all_xdp_queues(adapter);
+ }
+ ena_xdp_exchange_program(adapter, prog);
+
+ netif_dbg(adapter, drv, adapter->netdev, "Set a new XDP program\n");
+
+ if (is_up && !old_bpf_prog) {
+ rc = ena_up(adapter);
+ if (rc)
+ return rc;
+ }
+ xdp_features_set_redirect_target(netdev, false);
+ } else if (old_bpf_prog) {
+ xdp_features_clear_redirect_target(netdev);
+ netif_dbg(adapter, drv, adapter->netdev, "Removing XDP program\n");
+
+ rc = ena_destroy_and_free_all_xdp_queues(adapter);
+ if (rc)
+ return rc;
+ }
+
+ prev_mtu = netdev->max_mtu;
+ netdev->max_mtu = prog ? ENA_XDP_MAX_MTU : adapter->max_mtu;
+
+ if (!old_bpf_prog)
+ netif_info(adapter, drv, adapter->netdev,
+ "XDP program is set, changing the max_mtu from %d to %d",
+ prev_mtu, netdev->max_mtu);
+
+ } else if (rc == ENA_XDP_CURRENT_MTU_TOO_LARGE) {
+ netif_err(adapter, drv, adapter->netdev,
+ "Failed to set xdp program, the current MTU (%d) is larger than the maximum allowed MTU (%lu) while xdp is on",
+ netdev->mtu, ENA_XDP_MAX_MTU);
+ NL_SET_ERR_MSG_MOD(bpf->extack,
+ "Failed to set xdp program, the current MTU is larger than the maximum allowed MTU. Check the dmesg for more info");
+ return -EINVAL;
+ } else if (rc == ENA_XDP_NO_ENOUGH_QUEUES) {
+ netif_err(adapter, drv, adapter->netdev,
+ "Failed to set xdp program, the Rx/Tx channel count should be at most half of the maximum allowed channel count. The current queue count (%d), the maximal queue count (%d)\n",
+ adapter->num_io_queues, adapter->max_num_io_queues);
+ NL_SET_ERR_MSG_MOD(bpf->extack,
+ "Failed to set xdp program, there is no enough space for allocating XDP queues, Check the dmesg for more info");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* This is the main xdp callback, it's used by the kernel to set/unset the xdp
+ * program as well as to query the current xdp program id.
+ */
+int ena_xdp(struct net_device *netdev, struct netdev_bpf *bpf)
+{
+ switch (bpf->command) {
+ case XDP_SETUP_PROG:
+ return ena_xdp_set(netdev, bpf);
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ena_clean_xdp_irq(struct ena_ring *tx_ring, u32 budget)
+{
+ u32 total_done = 0;
+ u16 next_to_clean;
+ int tx_pkts = 0;
+ u16 req_id;
+ int rc;
+
+ if (unlikely(!tx_ring))
+ return 0;
+ next_to_clean = tx_ring->next_to_clean;
+
+ while (tx_pkts < budget) {
+ struct ena_tx_buffer *tx_info;
+ struct xdp_frame *xdpf;
+
+ rc = ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq,
+ &req_id);
+ if (rc) {
+ if (unlikely(rc == -EINVAL))
+ handle_invalid_req_id(tx_ring, req_id, NULL, true);
+ break;
+ }
+
+ /* validate that the request id points to a valid xdp_frame */
+ rc = validate_xdp_req_id(tx_ring, req_id);
+ if (rc)
+ break;
+
+ tx_info = &tx_ring->tx_buffer_info[req_id];
+
+ tx_info->last_jiffies = 0;
+
+ xdpf = tx_info->xdpf;
+ tx_info->xdpf = NULL;
+ ena_unmap_tx_buff(tx_ring, tx_info);
+ xdp_return_frame(xdpf);
+
+ tx_pkts++;
+ total_done += tx_info->tx_descs;
+ tx_ring->free_ids[next_to_clean] = req_id;
+ next_to_clean = ENA_TX_RING_IDX_NEXT(next_to_clean,
+ tx_ring->ring_size);
+
+ netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
+ "tx_poll: q %d pkt #%d req_id %d\n", tx_ring->qid, tx_pkts, req_id);
+ }
+
+ tx_ring->next_to_clean = next_to_clean;
+ ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done);
+ ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq);
+
+ netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev,
+ "tx_poll: q %d done. total pkts: %d\n",
+ tx_ring->qid, tx_pkts);
+
+ return tx_pkts;
+}
+
+/* This is the XDP napi callback. XDP queues use a separate napi callback
+ * than Rx/Tx queues.
+ */
+int ena_xdp_io_poll(struct napi_struct *napi, int budget)
+{
+ struct ena_napi *ena_napi = container_of(napi, struct ena_napi, napi);
+ struct ena_ring *tx_ring;
+ u32 work_done;
+ int ret;
+
+ tx_ring = ena_napi->tx_ring;
+
+ if (!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags) ||
+ test_bit(ENA_FLAG_TRIGGER_RESET, &tx_ring->adapter->flags)) {
+ napi_complete_done(napi, 0);
+ return 0;
+ }
+
+ work_done = ena_clean_xdp_irq(tx_ring, budget);
+
+ /* If the device is about to reset or down, avoid unmask
+ * the interrupt and return 0 so NAPI won't reschedule
+ */
+ if (unlikely(!test_bit(ENA_FLAG_DEV_UP, &tx_ring->adapter->flags))) {
+ napi_complete_done(napi, 0);
+ ret = 0;
+ } else if (budget > work_done) {
+ ena_increase_stat(&tx_ring->tx_stats.napi_comp, 1,
+ &tx_ring->syncp);
+ if (napi_complete_done(napi, work_done))
+ ena_unmask_interrupt(tx_ring, NULL);
+
+ ena_update_ring_numa_node(tx_ring, NULL);
+ ret = work_done;
+ } else {
+ ret = budget;
+ }
+
+ u64_stats_update_begin(&tx_ring->syncp);
+ tx_ring->tx_stats.tx_poll++;
+ u64_stats_update_end(&tx_ring->syncp);
+ tx_ring->tx_stats.last_napi_jiffies = jiffies;
+
+ return ret;
+}
diff --git a/drivers/net/ethernet/amazon/ena/ena_xdp.h b/drivers/net/ethernet/amazon/ena/ena_xdp.h
new file mode 100644
index 000000000000..cfd82728486a
--- /dev/null
+++ b/drivers/net/ethernet/amazon/ena/ena_xdp.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/*
+ * Copyright 2015-2021 Amazon.com, Inc. or its affiliates. All rights reserved.
+ */
+
+#ifndef ENA_XDP_H
+#define ENA_XDP_H
+
+#include "ena_netdev.h"
+#include <linux/bpf_trace.h>
+
+/* The max MTU size is configured to be the ethernet frame size without
+ * the overhead of the ethernet header, which can have a VLAN header, and
+ * a frame check sequence (FCS).
+ * The buffer size we share with the device is defined to be ENA_PAGE_SIZE
+ */
+#define ENA_XDP_MAX_MTU (ENA_PAGE_SIZE - ETH_HLEN - ETH_FCS_LEN - \
+ VLAN_HLEN - XDP_PACKET_HEADROOM - \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
+#define ENA_IS_XDP_INDEX(adapter, index) (((index) >= (adapter)->xdp_first_ring) && \
+ ((index) < (adapter)->xdp_first_ring + (adapter)->xdp_num_queues))
+
+enum ENA_XDP_ACTIONS {
+ ENA_XDP_PASS = 0,
+ ENA_XDP_TX = BIT(0),
+ ENA_XDP_REDIRECT = BIT(1),
+ ENA_XDP_DROP = BIT(2)
+};
+
+#define ENA_XDP_FORWARDED (ENA_XDP_TX | ENA_XDP_REDIRECT)
+
+int ena_setup_and_create_all_xdp_queues(struct ena_adapter *adapter);
+void ena_xdp_exchange_program_rx_in_range(struct ena_adapter *adapter,
+ struct bpf_prog *prog,
+ int first, int count);
+int ena_xdp_io_poll(struct napi_struct *napi, int budget);
+int ena_xdp_xmit_frame(struct ena_ring *tx_ring,
+ struct ena_adapter *adapter,
+ struct xdp_frame *xdpf,
+ int flags);
+int ena_xdp_xmit(struct net_device *dev, int n,
+ struct xdp_frame **frames, u32 flags);
+int ena_xdp(struct net_device *netdev, struct netdev_bpf *bpf);
+int ena_xdp_register_rxq_info(struct ena_ring *rx_ring);
+void ena_xdp_unregister_rxq_info(struct ena_ring *rx_ring);
+
+enum ena_xdp_errors_t {
+ ENA_XDP_ALLOWED = 0,
+ ENA_XDP_CURRENT_MTU_TOO_LARGE,
+ ENA_XDP_NO_ENOUGH_QUEUES,
+};
+
+static inline bool ena_xdp_present(struct ena_adapter *adapter)
+{
+ return !!adapter->xdp_bpf_prog;
+}
+
+static inline bool ena_xdp_present_ring(struct ena_ring *ring)
+{
+ return !!ring->xdp_bpf_prog;
+}
+
+static inline bool ena_xdp_legal_queue_count(struct ena_adapter *adapter,
+ u32 queues)
+{
+ return 2 * queues <= adapter->max_num_io_queues;
+}
+
+static inline enum ena_xdp_errors_t ena_xdp_allowed(struct ena_adapter *adapter)
+{
+ enum ena_xdp_errors_t rc = ENA_XDP_ALLOWED;
+
+ if (adapter->netdev->mtu > ENA_XDP_MAX_MTU)
+ rc = ENA_XDP_CURRENT_MTU_TOO_LARGE;
+ else if (!ena_xdp_legal_queue_count(adapter, adapter->num_io_queues))
+ rc = ENA_XDP_NO_ENOUGH_QUEUES;
+
+ return rc;
+}
+
+static inline int ena_xdp_execute(struct ena_ring *rx_ring, struct xdp_buff *xdp)
+{
+ u32 verdict = ENA_XDP_PASS;
+ struct bpf_prog *xdp_prog;
+ struct ena_ring *xdp_ring;
+ struct xdp_frame *xdpf;
+ u64 *xdp_stat;
+
+ xdp_prog = READ_ONCE(rx_ring->xdp_bpf_prog);
+
+ verdict = bpf_prog_run_xdp(xdp_prog, xdp);
+
+ switch (verdict) {
+ case XDP_TX:
+ xdpf = xdp_convert_buff_to_frame(xdp);
+ if (unlikely(!xdpf)) {
+ trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
+ xdp_stat = &rx_ring->rx_stats.xdp_aborted;
+ verdict = ENA_XDP_DROP;
+ break;
+ }
+
+ /* Find xmit queue */
+ xdp_ring = rx_ring->xdp_ring;
+
+ /* The XDP queues are shared between XDP_TX and XDP_REDIRECT */
+ spin_lock(&xdp_ring->xdp_tx_lock);
+
+ if (ena_xdp_xmit_frame(xdp_ring, rx_ring->adapter, xdpf,
+ XDP_XMIT_FLUSH))
+ xdp_return_frame(xdpf);
+
+ spin_unlock(&xdp_ring->xdp_tx_lock);
+ xdp_stat = &rx_ring->rx_stats.xdp_tx;
+ verdict = ENA_XDP_TX;
+ break;
+ case XDP_REDIRECT:
+ if (likely(!xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog))) {
+ xdp_stat = &rx_ring->rx_stats.xdp_redirect;
+ verdict = ENA_XDP_REDIRECT;
+ break;
+ }
+ trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
+ xdp_stat = &rx_ring->rx_stats.xdp_aborted;
+ verdict = ENA_XDP_DROP;
+ break;
+ case XDP_ABORTED:
+ trace_xdp_exception(rx_ring->netdev, xdp_prog, verdict);
+ xdp_stat = &rx_ring->rx_stats.xdp_aborted;
+ verdict = ENA_XDP_DROP;
+ break;
+ case XDP_DROP:
+ xdp_stat = &rx_ring->rx_stats.xdp_drop;
+ verdict = ENA_XDP_DROP;
+ break;
+ case XDP_PASS:
+ xdp_stat = &rx_ring->rx_stats.xdp_pass;
+ verdict = ENA_XDP_PASS;
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(rx_ring->netdev, xdp_prog, verdict);
+ xdp_stat = &rx_ring->rx_stats.xdp_invalid;
+ verdict = ENA_XDP_DROP;
+ }
+
+ ena_increase_stat(xdp_stat, 1, &rx_ring->syncp);
+
+ return verdict;
+}
+#endif /* ENA_XDP_H */
diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c
index 5beadabc2136..ea773cfa0af6 100644
--- a/drivers/net/ethernet/amd/pds_core/adminq.c
+++ b/drivers/net/ethernet/amd/pds_core/adminq.c
@@ -63,6 +63,15 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq)
return nq_work;
}
+static bool pdsc_adminq_inc_if_up(struct pdsc *pdsc)
+{
+ if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER) ||
+ pdsc->state & BIT_ULL(PDSC_S_FW_DEAD))
+ return false;
+
+ return refcount_inc_not_zero(&pdsc->adminq_refcnt);
+}
+
void pdsc_process_adminq(struct pdsc_qcq *qcq)
{
union pds_core_adminq_comp *comp;
@@ -75,9 +84,9 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq)
int aq_work = 0;
int credits;
- /* Don't process AdminQ when shutting down */
- if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) {
- dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n",
+ /* Don't process AdminQ when it's not up */
+ if (!pdsc_adminq_inc_if_up(pdsc)) {
+ dev_err(pdsc->dev, "%s: called while adminq is unavailable\n",
__func__);
return;
}
@@ -124,6 +133,7 @@ credits:
pds_core_intr_credits(&pdsc->intr_ctrl[qcq->intx],
credits,
PDS_CORE_INTR_CRED_REARM);
+ refcount_dec(&pdsc->adminq_refcnt);
}
void pdsc_work_thread(struct work_struct *work)
@@ -135,18 +145,20 @@ void pdsc_work_thread(struct work_struct *work)
irqreturn_t pdsc_adminq_isr(int irq, void *data)
{
- struct pdsc_qcq *qcq = data;
- struct pdsc *pdsc = qcq->pdsc;
+ struct pdsc *pdsc = data;
+ struct pdsc_qcq *qcq;
- /* Don't process AdminQ when shutting down */
- if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) {
- dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n",
+ /* Don't process AdminQ when it's not up */
+ if (!pdsc_adminq_inc_if_up(pdsc)) {
+ dev_err(pdsc->dev, "%s: called while adminq is unavailable\n",
__func__);
return IRQ_HANDLED;
}
+ qcq = &pdsc->adminqcq;
queue_work(pdsc->wq, &qcq->work);
pds_core_intr_mask(&pdsc->intr_ctrl[qcq->intx], PDS_CORE_INTR_MASK_CLEAR);
+ refcount_dec(&pdsc->adminq_refcnt);
return IRQ_HANDLED;
}
@@ -179,10 +191,16 @@ static int __pdsc_adminq_post(struct pdsc *pdsc,
/* Check that the FW is running */
if (!pdsc_is_fw_running(pdsc)) {
- u8 fw_status = ioread8(&pdsc->info_regs->fw_status);
-
- dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n",
- __func__, fw_status);
+ if (pdsc->info_regs) {
+ u8 fw_status =
+ ioread8(&pdsc->info_regs->fw_status);
+
+ dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n",
+ __func__, fw_status);
+ } else {
+ dev_info(pdsc->dev, "%s: post failed - BARs not setup\n",
+ __func__);
+ }
ret = -ENXIO;
goto err_out_unlock;
@@ -230,6 +248,12 @@ int pdsc_adminq_post(struct pdsc *pdsc,
int err = 0;
int index;
+ if (!pdsc_adminq_inc_if_up(pdsc)) {
+ dev_dbg(pdsc->dev, "%s: preventing adminq cmd %u\n",
+ __func__, cmd->opcode);
+ return -ENXIO;
+ }
+
wc.qcq = &pdsc->adminqcq;
index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp, &wc);
if (index < 0) {
@@ -248,10 +272,16 @@ int pdsc_adminq_post(struct pdsc *pdsc,
break;
if (!pdsc_is_fw_running(pdsc)) {
- u8 fw_status = ioread8(&pdsc->info_regs->fw_status);
-
- dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n",
- __func__, fw_status);
+ if (pdsc->info_regs) {
+ u8 fw_status =
+ ioread8(&pdsc->info_regs->fw_status);
+
+ dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n",
+ __func__, fw_status);
+ } else {
+ dev_dbg(pdsc->dev, "%s: post wait failed - BARs not setup\n",
+ __func__);
+ }
err = -ENXIO;
break;
}
@@ -285,6 +315,8 @@ err_out:
queue_work(pdsc->wq, &pdsc->health_work);
}
+ refcount_dec(&pdsc->adminq_refcnt);
+
return err;
}
EXPORT_SYMBOL_GPL(pdsc_adminq_post);
diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c
index 11c23a7f3172..fd1a5149c003 100644
--- a/drivers/net/ethernet/amd/pds_core/auxbus.c
+++ b/drivers/net/ethernet/amd/pds_core/auxbus.c
@@ -160,23 +160,19 @@ static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf,
if (err < 0) {
dev_warn(cf->dev, "auxiliary_device_init of %s failed: %pe\n",
name, ERR_PTR(err));
- goto err_out;
+ kfree(padev);
+ return ERR_PTR(err);
}
err = auxiliary_device_add(aux_dev);
if (err) {
dev_warn(cf->dev, "auxiliary_device_add of %s failed: %pe\n",
name, ERR_PTR(err));
- goto err_out_uninit;
+ auxiliary_device_uninit(aux_dev);
+ return ERR_PTR(err);
}
return padev;
-
-err_out_uninit:
- auxiliary_device_uninit(aux_dev);
-err_out:
- kfree(padev);
- return ERR_PTR(err);
}
int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf)
diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c
index 0d2091e9eb28..7658a7286767 100644
--- a/drivers/net/ethernet/amd/pds_core/core.c
+++ b/drivers/net/ethernet/amd/pds_core/core.c
@@ -125,7 +125,7 @@ static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq)
snprintf(name, sizeof(name), "%s-%d-%s",
PDS_CORE_DRV_NAME, pdsc->pdev->bus->number, qcq->q.name);
- index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, qcq);
+ index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, pdsc);
if (index < 0)
return index;
qcq->intx = index;
@@ -404,10 +404,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init)
int numdescs;
int err;
- if (init)
- err = pdsc_dev_init(pdsc);
- else
- err = pdsc_dev_reinit(pdsc);
+ err = pdsc_dev_init(pdsc);
if (err)
return err;
@@ -450,6 +447,7 @@ int pdsc_setup(struct pdsc *pdsc, bool init)
pdsc_debugfs_add_viftype(pdsc);
}
+ refcount_set(&pdsc->adminq_refcnt, 1);
clear_bit(PDSC_S_FW_DEAD, &pdsc->state);
return 0;
@@ -464,6 +462,8 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
if (!pdsc->pdev->is_virtfn)
pdsc_devcmd_reset(pdsc);
+ if (pdsc->adminqcq.work.func)
+ cancel_work_sync(&pdsc->adminqcq.work);
pdsc_qcq_free(pdsc, &pdsc->notifyqcq);
pdsc_qcq_free(pdsc, &pdsc->adminqcq);
@@ -476,10 +476,9 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
for (i = 0; i < pdsc->nintrs; i++)
pdsc_intr_free(pdsc, i);
- if (removing) {
- kfree(pdsc->intr_info);
- pdsc->intr_info = NULL;
- }
+ kfree(pdsc->intr_info);
+ pdsc->intr_info = NULL;
+ pdsc->nintrs = 0;
}
if (pdsc->kern_dbpage) {
@@ -487,6 +486,7 @@ void pdsc_teardown(struct pdsc *pdsc, bool removing)
pdsc->kern_dbpage = NULL;
}
+ pci_free_irq_vectors(pdsc->pdev);
set_bit(PDSC_S_FW_DEAD, &pdsc->state);
}
@@ -512,6 +512,24 @@ void pdsc_stop(struct pdsc *pdsc)
PDS_CORE_INTR_MASK_SET);
}
+static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc)
+{
+ /* The driver initializes the adminq_refcnt to 1 when the adminq is
+ * allocated and ready for use. Other users/requesters will increment
+ * the refcnt while in use. If the refcnt is down to 1 then the adminq
+ * is not in use and the refcnt can be cleared and adminq freed. Before
+ * calling this function the driver will set PDSC_S_FW_DEAD, which
+ * prevent subsequent attempts to use the adminq and increment the
+ * refcnt to fail. This guarantees that this function will eventually
+ * exit.
+ */
+ while (!refcount_dec_if_one(&pdsc->adminq_refcnt)) {
+ dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n",
+ __func__);
+ cpu_relax();
+ }
+}
+
void pdsc_fw_down(struct pdsc *pdsc)
{
union pds_core_notifyq_comp reset_event = {
@@ -527,6 +545,8 @@ void pdsc_fw_down(struct pdsc *pdsc)
if (pdsc->pdev->is_virtfn)
return;
+ pdsc_adminq_wait_and_dec_once_unused(pdsc);
+
/* Notify clients of fw_down */
if (pdsc->fw_reporter)
devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc);
@@ -577,7 +597,13 @@ err_out:
static void pdsc_check_pci_health(struct pdsc *pdsc)
{
- u8 fw_status = ioread8(&pdsc->info_regs->fw_status);
+ u8 fw_status;
+
+ /* some sort of teardown already in progress */
+ if (!pdsc->info_regs)
+ return;
+
+ fw_status = ioread8(&pdsc->info_regs->fw_status);
/* is PCI broken? */
if (fw_status != PDS_RC_BAD_PCI)
diff --git a/drivers/net/ethernet/amd/pds_core/core.h b/drivers/net/ethernet/amd/pds_core/core.h
index e35d3e7006bf..110c4b826b22 100644
--- a/drivers/net/ethernet/amd/pds_core/core.h
+++ b/drivers/net/ethernet/amd/pds_core/core.h
@@ -184,6 +184,7 @@ struct pdsc {
struct mutex devcmd_lock; /* lock for dev_cmd operations */
struct mutex config_lock; /* lock for configuration operations */
spinlock_t adminq_lock; /* lock for adminq operations */
+ refcount_t adminq_refcnt;
struct pds_core_dev_info_regs __iomem *info_regs;
struct pds_core_dev_cmd_regs __iomem *cmd_regs;
struct pds_core_intr __iomem *intr_ctrl;
@@ -280,7 +281,6 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
union pds_core_dev_comp *comp, int max_seconds);
int pdsc_devcmd_init(struct pdsc *pdsc);
int pdsc_devcmd_reset(struct pdsc *pdsc);
-int pdsc_dev_reinit(struct pdsc *pdsc);
int pdsc_dev_init(struct pdsc *pdsc);
void pdsc_reset_prepare(struct pci_dev *pdev);
diff --git a/drivers/net/ethernet/amd/pds_core/debugfs.c b/drivers/net/ethernet/amd/pds_core/debugfs.c
index 8ec392299b7d..4e8579ca1c8c 100644
--- a/drivers/net/ethernet/amd/pds_core/debugfs.c
+++ b/drivers/net/ethernet/amd/pds_core/debugfs.c
@@ -64,6 +64,10 @@ DEFINE_SHOW_ATTRIBUTE(identity);
void pdsc_debugfs_add_ident(struct pdsc *pdsc)
{
+ /* This file will already exist in the reset flow */
+ if (debugfs_lookup("identity", pdsc->dentry))
+ return;
+
debugfs_create_file("identity", 0400, pdsc->dentry,
pdsc, &identity_fops);
}
diff --git a/drivers/net/ethernet/amd/pds_core/dev.c b/drivers/net/ethernet/amd/pds_core/dev.c
index 31940b857e0e..e65a1632df50 100644
--- a/drivers/net/ethernet/amd/pds_core/dev.c
+++ b/drivers/net/ethernet/amd/pds_core/dev.c
@@ -57,6 +57,9 @@ int pdsc_err_to_errno(enum pds_core_status_code code)
bool pdsc_is_fw_running(struct pdsc *pdsc)
{
+ if (!pdsc->info_regs)
+ return false;
+
pdsc->fw_status = ioread8(&pdsc->info_regs->fw_status);
pdsc->last_fw_time = jiffies;
pdsc->last_hb = ioread32(&pdsc->info_regs->fw_heartbeat);
@@ -182,13 +185,17 @@ int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd,
{
int err;
+ if (!pdsc->cmd_regs)
+ return -ENXIO;
+
memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd));
pdsc_devcmd_dbell(pdsc);
err = pdsc_devcmd_wait(pdsc, cmd->opcode, max_seconds);
- memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
if ((err == -ENXIO || err == -ETIMEDOUT) && pdsc->wq)
queue_work(pdsc->wq, &pdsc->health_work);
+ else
+ memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp));
return err;
}
@@ -309,13 +316,6 @@ static int pdsc_identify(struct pdsc *pdsc)
return 0;
}
-int pdsc_dev_reinit(struct pdsc *pdsc)
-{
- pdsc_init_devinfo(pdsc);
-
- return pdsc_identify(pdsc);
-}
-
int pdsc_dev_init(struct pdsc *pdsc)
{
unsigned int nintrs;
diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c
index e9948ea5bbcd..54864f27c87a 100644
--- a/drivers/net/ethernet/amd/pds_core/devlink.c
+++ b/drivers/net/ethernet/amd/pds_core/devlink.c
@@ -111,7 +111,8 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
mutex_lock(&pdsc->devcmd_lock);
err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2);
- memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
+ if (!err)
+ memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list));
mutex_unlock(&pdsc->devcmd_lock);
if (err && err != -EIO)
return err;
diff --git a/drivers/net/ethernet/amd/pds_core/fw.c b/drivers/net/ethernet/amd/pds_core/fw.c
index 90a811f3878a..fa626719e68d 100644
--- a/drivers/net/ethernet/amd/pds_core/fw.c
+++ b/drivers/net/ethernet/amd/pds_core/fw.c
@@ -107,6 +107,9 @@ int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,
dev_info(pdsc->dev, "Installing firmware\n");
+ if (!pdsc->cmd_regs)
+ return -ENXIO;
+
dl = priv_to_devlink(pdsc);
devlink_flash_update_status_notify(dl, "Preparing to flash",
NULL, 0, 0);
diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
index 3080898d7b95..0050c5894563 100644
--- a/drivers/net/ethernet/amd/pds_core/main.c
+++ b/drivers/net/ethernet/amd/pds_core/main.c
@@ -37,6 +37,11 @@ static void pdsc_unmap_bars(struct pdsc *pdsc)
struct pdsc_dev_bar *bars = pdsc->bars;
unsigned int i;
+ pdsc->info_regs = NULL;
+ pdsc->cmd_regs = NULL;
+ pdsc->intr_status = NULL;
+ pdsc->intr_ctrl = NULL;
+
for (i = 0; i < PDS_CORE_BARS_MAX; i++) {
if (bars[i].vaddr)
pci_iounmap(pdsc->pdev, bars[i].vaddr);
@@ -293,7 +298,7 @@ err_out_stop:
err_out_teardown:
pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING);
err_out_unmap_bars:
- del_timer_sync(&pdsc->wdtimer);
+ timer_shutdown_sync(&pdsc->wdtimer);
if (pdsc->wq)
destroy_workqueue(pdsc->wq);
mutex_destroy(&pdsc->config_lock);
@@ -420,7 +425,7 @@ static void pdsc_remove(struct pci_dev *pdev)
*/
pdsc_sriov_configure(pdev, 0);
- del_timer_sync(&pdsc->wdtimer);
+ timer_shutdown_sync(&pdsc->wdtimer);
if (pdsc->wq)
destroy_workqueue(pdsc->wq);
@@ -433,7 +438,6 @@ static void pdsc_remove(struct pci_dev *pdev)
mutex_destroy(&pdsc->config_lock);
mutex_destroy(&pdsc->devcmd_lock);
- pci_free_irq_vectors(pdev);
pdsc_unmap_bars(pdsc);
pci_release_regions(pdev);
}
@@ -445,13 +449,32 @@ static void pdsc_remove(struct pci_dev *pdev)
devlink_free(dl);
}
+static void pdsc_stop_health_thread(struct pdsc *pdsc)
+{
+ if (pdsc->pdev->is_virtfn)
+ return;
+
+ timer_shutdown_sync(&pdsc->wdtimer);
+ if (pdsc->health_work.func)
+ cancel_work_sync(&pdsc->health_work);
+}
+
+static void pdsc_restart_health_thread(struct pdsc *pdsc)
+{
+ if (pdsc->pdev->is_virtfn)
+ return;
+
+ timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
+ mod_timer(&pdsc->wdtimer, jiffies + 1);
+}
+
void pdsc_reset_prepare(struct pci_dev *pdev)
{
struct pdsc *pdsc = pci_get_drvdata(pdev);
+ pdsc_stop_health_thread(pdsc);
pdsc_fw_down(pdsc);
- pci_free_irq_vectors(pdev);
pdsc_unmap_bars(pdsc);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -486,6 +509,7 @@ void pdsc_reset_done(struct pci_dev *pdev)
}
pdsc_fw_up(pdsc);
+ pdsc_restart_health_thread(pdsc);
}
static const struct pci_error_handlers pdsc_err_handler = {
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
index 32fab5e77246..58e7e88aae5b 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c
@@ -527,47 +527,48 @@ static u32 xgbe_get_rxfh_indir_size(struct net_device *netdev)
return ARRAY_SIZE(pdata->rss_table);
}
-static int xgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int xgbe_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
unsigned int i;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < ARRAY_SIZE(pdata->rss_table); i++)
- indir[i] = XGMAC_GET_BITS(pdata->rss_table[i],
- MAC_RSSDR, DMCH);
+ rxfh->indir[i] = XGMAC_GET_BITS(pdata->rss_table[i],
+ MAC_RSSDR, DMCH);
}
- if (key)
- memcpy(key, pdata->rss_key, sizeof(pdata->rss_key));
+ if (rxfh->key)
+ memcpy(rxfh->key, pdata->rss_key, sizeof(pdata->rss_key));
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int xgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int xgbe_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
unsigned int ret;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) {
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP) {
netdev_err(netdev, "unsupported hash function\n");
return -EOPNOTSUPP;
}
- if (indir) {
- ret = hw_if->set_rss_lookup_table(pdata, indir);
+ if (rxfh->indir) {
+ ret = hw_if->set_rss_lookup_table(pdata, rxfh->indir);
if (ret)
return ret;
}
- if (key) {
- ret = hw_if->set_rss_hash_key(pdata, key);
+ if (rxfh->key) {
+ ret = hw_if->set_rss_hash_key(pdata, rxfh->key);
if (ret)
return ret;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index ad136ed493ed..f01a1e566da6 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -495,7 +495,7 @@ struct xgbe_ring {
* a DMA channel.
*/
struct xgbe_channel {
- char name[16];
+ char name[20];
/* Address of private data area for device */
struct xgbe_prv_data *pdata;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
index ac4ea93bd8dd..18a6c8d99fa0 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
@@ -447,8 +447,8 @@ static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev)
return sizeof(cfg->aq_rss.hash_secret_key);
}
-static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int aq_ethtool_get_rss(struct net_device *ndev,
+ struct ethtool_rxfh_param *rxfh)
{
struct aq_nic_s *aq_nic = netdev_priv(ndev);
struct aq_nic_cfg_s *cfg;
@@ -456,21 +456,21 @@ static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key,
cfg = aq_nic_get_cfg(aq_nic);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
- if (indir) {
+ rxfh->hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
+ if (rxfh->indir) {
for (i = 0; i < AQ_CFG_RSS_INDIRECTION_TABLE_MAX; i++)
- indir[i] = cfg->aq_rss.indirection_table[i];
+ rxfh->indir[i] = cfg->aq_rss.indirection_table[i];
}
- if (key)
- memcpy(key, cfg->aq_rss.hash_secret_key,
+ if (rxfh->key)
+ memcpy(rxfh->key, cfg->aq_rss.hash_secret_key,
sizeof(cfg->aq_rss.hash_secret_key));
return 0;
}
-static int aq_ethtool_set_rss(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int aq_ethtool_set_rss(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct aq_nic_s *aq_nic = netdev_priv(netdev);
struct aq_nic_cfg_s *cfg;
@@ -482,16 +482,17 @@ static int aq_ethtool_set_rss(struct net_device *netdev, const u32 *indir,
rss_entries = cfg->aq_rss.indirection_table_size;
/* We do not allow change in unsupported parameters */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
- if (indir)
+ if (rxfh->indir)
for (i = 0; i < rss_entries; i++)
- cfg->aq_rss.indirection_table[i] = indir[i];
+ cfg->aq_rss.indirection_table[i] = rxfh->indir[i];
/* Fill out the rss hash key */
- if (key) {
- memcpy(cfg->aq_rss.hash_secret_key, key,
+ if (rxfh->key) {
+ memcpy(cfg->aq_rss.hash_secret_key, rxfh->key,
sizeof(cfg->aq_rss.hash_secret_key));
err = aq_nic->aq_hw_ops->hw_rss_hash_set(aq_nic->aq_hw,
&cfg->aq_rss);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
index 28c9b6f1a54f..5acb3e16b567 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
@@ -953,8 +953,6 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
unsigned int tx_ring_idx, rx_ring_idx;
- struct aq_ring_s *hwts;
- struct aq_ring_s *ring;
int err;
if (!aq_ptp)
@@ -962,29 +960,23 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
tx_ring_idx = aq_ptp_ring_idx(aq_nic->aq_nic_cfg.tc_mode);
- ring = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
- tx_ring_idx, &aq_nic->aq_nic_cfg);
- if (!ring) {
- err = -ENOMEM;
+ err = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
+ tx_ring_idx, &aq_nic->aq_nic_cfg);
+ if (err)
goto err_exit;
- }
rx_ring_idx = aq_ptp_ring_idx(aq_nic->aq_nic_cfg.tc_mode);
- ring = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
- rx_ring_idx, &aq_nic->aq_nic_cfg);
- if (!ring) {
- err = -ENOMEM;
+ err = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
+ rx_ring_idx, &aq_nic->aq_nic_cfg);
+ if (err)
goto err_exit_ptp_tx;
- }
- hwts = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
- aq_nic->aq_nic_cfg.rxds,
- aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
- if (!hwts) {
- err = -ENOMEM;
+ err = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
+ aq_nic->aq_nic_cfg.rxds,
+ aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
+ if (err)
goto err_exit_ptp_rx;
- }
err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
if (err != 0) {
@@ -1001,7 +993,7 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
return 0;
err_exit_hwts_rx:
- aq_ring_free(&aq_ptp->hwts_rx);
+ aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
err_exit_ptp_rx:
aq_ring_free(&aq_ptp->ptp_rx);
err_exit_ptp_tx:
@@ -1019,7 +1011,7 @@ void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
aq_ring_free(&aq_ptp->ptp_tx);
aq_ring_free(&aq_ptp->ptp_rx);
- aq_ring_free(&aq_ptp->hwts_rx);
+ aq_ring_hwts_rx_free(&aq_ptp->hwts_rx);
aq_ptp_skb_ring_release(&aq_ptp->skb_ring);
}
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
index e1885c1eb100..f7433abd6591 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c
@@ -132,8 +132,8 @@ static int aq_get_rxpages(struct aq_ring_s *self, struct aq_ring_buff_s *rxbuf)
return 0;
}
-static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
- struct aq_nic_s *aq_nic)
+static int aq_ring_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic)
{
int err = 0;
@@ -156,46 +156,29 @@ static struct aq_ring_s *aq_ring_alloc(struct aq_ring_s *self,
err_exit:
if (err < 0) {
aq_ring_free(self);
- self = NULL;
}
- return self;
+ return err;
}
-struct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
- struct aq_nic_s *aq_nic,
- unsigned int idx,
- struct aq_nic_cfg_s *aq_nic_cfg)
+int aq_ring_tx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg)
{
- int err = 0;
-
self->aq_nic = aq_nic;
self->idx = idx;
self->size = aq_nic_cfg->txds;
self->dx_size = aq_nic_cfg->aq_hw_caps->txd_size;
- self = aq_ring_alloc(self, aq_nic);
- if (!self) {
- err = -ENOMEM;
- goto err_exit;
- }
-
-err_exit:
- if (err < 0) {
- aq_ring_free(self);
- self = NULL;
- }
-
- return self;
+ return aq_ring_alloc(self, aq_nic);
}
-struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
- struct aq_nic_s *aq_nic,
- unsigned int idx,
- struct aq_nic_cfg_s *aq_nic_cfg)
+int aq_ring_rx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg)
{
- int err = 0;
-
self->aq_nic = aq_nic;
self->idx = idx;
self->size = aq_nic_cfg->rxds;
@@ -217,22 +200,10 @@ struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
self->tail_size = 0;
}
- self = aq_ring_alloc(self, aq_nic);
- if (!self) {
- err = -ENOMEM;
- goto err_exit;
- }
-
-err_exit:
- if (err < 0) {
- aq_ring_free(self);
- self = NULL;
- }
-
- return self;
+ return aq_ring_alloc(self, aq_nic);
}
-struct aq_ring_s *
+int
aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
unsigned int idx, unsigned int size, unsigned int dx_size)
{
@@ -250,10 +221,10 @@ aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
GFP_KERNEL);
if (!self->dx_ring) {
aq_ring_free(self);
- return NULL;
+ return -ENOMEM;
}
- return self;
+ return 0;
}
int aq_ring_init(struct aq_ring_s *self, const enum atl_ring_type ring_type)
@@ -948,6 +919,19 @@ void aq_ring_free(struct aq_ring_s *self)
}
}
+void aq_ring_hwts_rx_free(struct aq_ring_s *self)
+{
+ if (!self)
+ return;
+
+ if (self->dx_ring) {
+ dma_free_coherent(aq_nic_get_dev(self->aq_nic),
+ self->size * self->dx_size + AQ_CFG_RXDS_DEF,
+ self->dx_ring, self->dx_ring_pa);
+ self->dx_ring = NULL;
+ }
+}
+
unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data)
{
unsigned int count;
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
index 0a6c34438c1d..d627ace850ff 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h
@@ -183,14 +183,14 @@ static inline unsigned int aq_ring_avail_dx(struct aq_ring_s *self)
self->sw_head - self->sw_tail - 1);
}
-struct aq_ring_s *aq_ring_tx_alloc(struct aq_ring_s *self,
- struct aq_nic_s *aq_nic,
- unsigned int idx,
- struct aq_nic_cfg_s *aq_nic_cfg);
-struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
- struct aq_nic_s *aq_nic,
- unsigned int idx,
- struct aq_nic_cfg_s *aq_nic_cfg);
+int aq_ring_tx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg);
+int aq_ring_rx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic,
+ unsigned int idx,
+ struct aq_nic_cfg_s *aq_nic_cfg);
int aq_ring_init(struct aq_ring_s *self, const enum atl_ring_type ring_type);
void aq_ring_rx_deinit(struct aq_ring_s *self);
@@ -207,9 +207,10 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
int budget);
int aq_ring_rx_fill(struct aq_ring_s *self);
-struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
- struct aq_nic_s *aq_nic, unsigned int idx,
- unsigned int size, unsigned int dx_size);
+int aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
+ struct aq_nic_s *aq_nic, unsigned int idx,
+ unsigned int size, unsigned int dx_size);
+void aq_ring_hwts_rx_free(struct aq_ring_s *self);
void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic);
unsigned int aq_ring_fill_stats_data(struct aq_ring_s *self, u64 *data);
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
index f5db1c44e9b9..9769ab4f9bef 100644
--- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
+++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c
@@ -136,35 +136,32 @@ int aq_vec_ring_alloc(struct aq_vec_s *self, struct aq_nic_s *aq_nic,
const unsigned int idx_ring = AQ_NIC_CFG_TCVEC2RING(aq_nic_cfg,
i, idx);
- ring = aq_ring_tx_alloc(&self->ring[i][AQ_VEC_TX_ID], aq_nic,
- idx_ring, aq_nic_cfg);
- if (!ring) {
- err = -ENOMEM;
+ ring = &self->ring[i][AQ_VEC_TX_ID];
+ err = aq_ring_tx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
+ if (err)
goto err_exit;
- }
++self->tx_rings;
aq_nic_set_tx_ring(aq_nic, idx_ring, ring);
- if (xdp_rxq_info_reg(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq,
+ ring = &self->ring[i][AQ_VEC_RX_ID];
+ if (xdp_rxq_info_reg(&ring->xdp_rxq,
aq_nic->ndev, idx,
self->napi.napi_id) < 0) {
err = -ENOMEM;
goto err_exit;
}
- if (xdp_rxq_info_reg_mem_model(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq,
+ if (xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED, NULL) < 0) {
- xdp_rxq_info_unreg(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq);
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
err = -ENOMEM;
goto err_exit;
}
- ring = aq_ring_rx_alloc(&self->ring[i][AQ_VEC_RX_ID], aq_nic,
- idx_ring, aq_nic_cfg);
- if (!ring) {
- xdp_rxq_info_unreg(&self->ring[i][AQ_VEC_RX_ID].xdp_rxq);
- err = -ENOMEM;
+ err = aq_ring_rx_alloc(ring, aq_nic, idx_ring, aq_nic_cfg);
+ if (err) {
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
goto err_exit;
}
diff --git a/drivers/net/ethernet/asix/ax88796c_main.c b/drivers/net/ethernet/asix/ax88796c_main.c
index e551ffaed20d..11e8996b33d7 100644
--- a/drivers/net/ethernet/asix/ax88796c_main.c
+++ b/drivers/net/ethernet/asix/ax88796c_main.c
@@ -284,7 +284,7 @@ ax88796c_tx_fixup(struct net_device *ndev, struct sk_buff_head *q)
ax88796c_proc_tx_hdr(&info, skb->ip_summed);
/* SOP and SEG header */
- memcpy(skb_push(skb, TX_OVERHEAD), &info.sop, TX_OVERHEAD);
+ memcpy(skb_push(skb, TX_OVERHEAD), &info.tx_overhead, TX_OVERHEAD);
/* Write SPI TXQ header */
memcpy(skb_push(skb, spi_len), ax88796c_tx_cmd_buf, spi_len);
diff --git a/drivers/net/ethernet/asix/ax88796c_main.h b/drivers/net/ethernet/asix/ax88796c_main.h
index 4a83c991dcbe..68a09edecab8 100644
--- a/drivers/net/ethernet/asix/ax88796c_main.h
+++ b/drivers/net/ethernet/asix/ax88796c_main.h
@@ -25,7 +25,7 @@
#define AX88796C_PHY_REGDUMP_LEN 14
#define AX88796C_PHY_ID 0x10
-#define TX_OVERHEAD 8
+#define TX_OVERHEAD sizeof_field(struct tx_pkt_info, tx_overhead)
#define TX_EOP_SIZE 4
#define AX_MCAST_FILTER_SIZE 8
@@ -549,8 +549,10 @@ struct tx_eop_header {
};
struct tx_pkt_info {
- struct tx_sop_header sop;
- struct tx_segment_header seg;
+ struct_group(tx_overhead,
+ struct tx_sop_header sop;
+ struct tx_segment_header seg;
+ );
struct tx_eop_header eop;
u16 pkt_len;
u16 seq_num;
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
index 29b04a274d07..80245c65cc90 100644
--- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c
@@ -535,9 +535,6 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
int j = 0, i;
for (i = 0; i < NUM_NET_FILTERS; i++) {
- if (j == *rule_cnt)
- return -EMSGSIZE;
-
if (!priv->net_filters[i].claimed ||
priv->net_filters[i].port != intf->port)
continue;
@@ -547,6 +544,9 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs,
priv->net_filters[i - 1].wake_filter)
continue;
+ if (j == *rule_cnt)
+ return -EMSGSIZE;
+
rule_locs[j++] = priv->net_filters[i].fs.location;
}
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
index 53e542881255..6ad1366270f7 100644
--- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
+++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c
@@ -684,6 +684,8 @@ static int bcmasp_init_rx(struct bcmasp_intf *intf)
intf->rx_buf_order = get_order(RING_BUFFER_SIZE);
buffer_pg = alloc_pages(GFP_KERNEL, intf->rx_buf_order);
+ if (!buffer_pg)
+ return -ENOMEM;
dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE,
DMA_FROM_DEVICE);
@@ -1048,6 +1050,9 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect)
netdev_err(dev, "could not attach to PHY\n");
goto err_phy_disable;
}
+
+ /* Indicate that the MAC is responsible for PHY PM */
+ phydev->mac_managed_pm = true;
} else if (!intf->wolopts) {
ret = phy_resume(dev->phydev);
if (ret)
@@ -1092,6 +1097,7 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect)
return 0;
err_reclaim_tx:
+ netif_napi_del(&intf->tx_napi);
bcmasp_reclaim_free_all_tx(intf);
err_phy_disconnect:
if (phydev)
diff --git a/drivers/net/ethernet/broadcom/bcm4908_enet.c b/drivers/net/ethernet/broadcom/bcm4908_enet.c
index 3e7c8671cd11..72df1bb10172 100644
--- a/drivers/net/ethernet/broadcom/bcm4908_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm4908_enet.c
@@ -793,5 +793,6 @@ static struct platform_driver bcm4908_enet_driver = {
};
module_platform_driver(bcm4908_enet_driver);
+MODULE_DESCRIPTION("Broadcom BCM4908 Gigabit Ethernet driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(of, bcm4908_enet_of_match);
diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
index 9b83d5361699..50b8e97a811d 100644
--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
@@ -260,4 +260,5 @@ void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister);
MODULE_AUTHOR("Rafał Miłecki");
+MODULE_DESCRIPTION("Broadcom iProc GBit BCMA MDIO helpers");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c
index 6e4f36aaf5db..36f9bad28e6a 100644
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
@@ -362,4 +362,5 @@ module_init(bgmac_init)
module_exit(bgmac_exit)
MODULE_AUTHOR("Rafał Miłecki");
+MODULE_DESCRIPTION("Broadcom iProc GBit BCMA interface driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bgmac-platform.c b/drivers/net/ethernet/broadcom/bgmac-platform.c
index 0b21fd5bd457..77425c7a32db 100644
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
@@ -298,4 +298,5 @@ static struct platform_driver bgmac_enet_driver = {
};
module_platform_driver(bgmac_enet_driver);
+MODULE_DESCRIPTION("Broadcom iProc GBit platform interface driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 448a1b90de5e..6ffdc4229407 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -1626,4 +1626,5 @@ int bgmac_enet_resume(struct bgmac *bgmac)
EXPORT_SYMBOL_GPL(bgmac_enet_resume);
MODULE_AUTHOR("Rafał Miłecki");
+MODULE_DESCRIPTION("Broadcom iProc GBit driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index bda3ccc28eca..81d232e6d05f 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -3486,16 +3486,15 @@ static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev)
return T_ETH_INDIRECTION_TABLE_SIZE;
}
-static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int bnx2x_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct bnx2x *bp = netdev_priv(dev);
u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0};
size_t i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (!rxfh->indir)
return 0;
/* Get the current configuration of the RSS indirection table */
@@ -3511,13 +3510,14 @@ static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
* queue.
*/
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++)
- indir[i] = ind_table[i] - bp->fp->cl_id;
+ rxfh->indir[i] = ind_table[i] - bp->fp->cl_id;
return 0;
}
-static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int bnx2x_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct bnx2x *bp = netdev_priv(dev);
size_t i;
@@ -3525,11 +3525,12 @@ static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir,
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) {
@@ -3542,7 +3543,7 @@ static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir,
* align the received table to the Client ID of the leading RSS
* queue
*/
- bp->rss_conf_obj.ind_table[i] = indir[i] + bp->fp->cl_id;
+ bp->rss_conf_obj.ind_table[i] = rxfh->indir[i] + bp->fp->cl_id;
}
if (bp->state == BNX2X_STATE_OPEN)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index e1f1e646cf48..39845d556baf 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -120,6 +120,10 @@ static const struct {
[BCM57508] = { "Broadcom BCM57508 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" },
[BCM57504] = { "Broadcom BCM57504 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" },
[BCM57502] = { "Broadcom BCM57502 NetXtreme-E 10Gb/25Gb/50Gb Ethernet" },
+ [BCM57608] = { "Broadcom BCM57608 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb/400Gb Ethernet" },
+ [BCM57604] = { "Broadcom BCM57604 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb Ethernet" },
+ [BCM57602] = { "Broadcom BCM57602 NetXtreme-E 10Gb/25Gb/50Gb/100Gb Ethernet" },
+ [BCM57601] = { "Broadcom BCM57601 NetXtreme-E 10Gb/25Gb/50Gb/100Gb/200Gb/400Gb Ethernet" },
[BCM57508_NPAR] = { "Broadcom BCM57508 NetXtreme-E Ethernet Partition" },
[BCM57504_NPAR] = { "Broadcom BCM57504 NetXtreme-E Ethernet Partition" },
[BCM57502_NPAR] = { "Broadcom BCM57502 NetXtreme-E Ethernet Partition" },
@@ -174,6 +178,10 @@ static const struct pci_device_id bnxt_pci_tbl[] = {
{ PCI_VDEVICE(BROADCOM, 0x1750), .driver_data = BCM57508 },
{ PCI_VDEVICE(BROADCOM, 0x1751), .driver_data = BCM57504 },
{ PCI_VDEVICE(BROADCOM, 0x1752), .driver_data = BCM57502 },
+ { PCI_VDEVICE(BROADCOM, 0x1760), .driver_data = BCM57608 },
+ { PCI_VDEVICE(BROADCOM, 0x1761), .driver_data = BCM57604 },
+ { PCI_VDEVICE(BROADCOM, 0x1762), .driver_data = BCM57602 },
+ { PCI_VDEVICE(BROADCOM, 0x1763), .driver_data = BCM57601 },
{ PCI_VDEVICE(BROADCOM, 0x1800), .driver_data = BCM57502_NPAR },
{ PCI_VDEVICE(BROADCOM, 0x1801), .driver_data = BCM57504_NPAR },
{ PCI_VDEVICE(BROADCOM, 0x1802), .driver_data = BCM57508_NPAR },
@@ -254,22 +262,28 @@ static bool bnxt_vf_pciid(enum board_idx idx)
writel(DB_CP_IRQ_DIS_FLAGS, db)
#define BNXT_DB_CQ(db, idx) \
- writel(DB_CP_FLAGS | RING_CMP(idx), (db)->doorbell)
+ writel(DB_CP_FLAGS | DB_RING_IDX(db, idx), (db)->doorbell)
#define BNXT_DB_NQ_P5(db, idx) \
- bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ | RING_CMP(idx), \
+ bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ | DB_RING_IDX(db, idx),\
(db)->doorbell)
+#define BNXT_DB_NQ_P7(db, idx) \
+ bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ_MASK | \
+ DB_RING_IDX(db, idx), (db)->doorbell)
+
#define BNXT_DB_CQ_ARM(db, idx) \
- writel(DB_CP_REARM_FLAGS | RING_CMP(idx), (db)->doorbell)
+ writel(DB_CP_REARM_FLAGS | DB_RING_IDX(db, idx), (db)->doorbell)
#define BNXT_DB_NQ_ARM_P5(db, idx) \
- bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ_ARM | RING_CMP(idx),\
- (db)->doorbell)
+ bnxt_writeq(bp, (db)->db_key64 | DBR_TYPE_NQ_ARM | \
+ DB_RING_IDX(db, idx), (db)->doorbell)
static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P7)
+ BNXT_DB_NQ_P7(db, idx);
+ else if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
BNXT_DB_NQ_P5(db, idx);
else
BNXT_DB_CQ(db, idx);
@@ -277,7 +291,7 @@ static void bnxt_db_nq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
static void bnxt_db_nq_arm(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
BNXT_DB_NQ_ARM_P5(db, idx);
else
BNXT_DB_CQ_ARM(db, idx);
@@ -285,9 +299,9 @@ static void bnxt_db_nq_arm(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
static void bnxt_db_cq(struct bnxt *bp, struct bnxt_db_info *db, u32 idx)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
bnxt_writeq(bp, db->db_key64 | DBR_TYPE_CQ_ARMALL |
- RING_CMP(idx), db->doorbell);
+ DB_RING_IDX(db, idx), db->doorbell);
else
BNXT_DB_CQ(db, idx);
}
@@ -321,7 +335,7 @@ static void bnxt_sched_reset_rxr(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
{
if (!rxr->bnapi->in_reset) {
rxr->bnapi->in_reset = true;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
set_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event);
else
set_bit(BNXT_RST_RING_SP_EVENT, &bp->sp_event);
@@ -331,16 +345,16 @@ static void bnxt_sched_reset_rxr(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
}
void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
- int idx)
+ u16 curr)
{
struct bnxt_napi *bnapi = txr->bnapi;
if (bnapi->tx_fault)
return;
- netdev_err(bp->dev, "Invalid Tx completion (ring:%d tx_pkts:%d cons:%u prod:%u i:%d)",
- txr->txq_index, bnapi->tx_pkts,
- txr->tx_cons, txr->tx_prod, idx);
+ netdev_err(bp->dev, "Invalid Tx completion (ring:%d tx_hw_cons:%u cons:%u prod:%u curr:%u)",
+ txr->txq_index, txr->tx_hw_cons,
+ txr->tx_cons, txr->tx_prod, curr);
WARN_ON_ONCE(1);
bnapi->tx_fault = 1;
bnxt_queue_sp_work(bp, BNXT_RESET_TASK_SP_EVENT);
@@ -381,6 +395,8 @@ static u16 bnxt_xmit_get_cfa_action(struct sk_buff *skb)
static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
u16 prod)
{
+ /* Sync BD data before updating doorbell */
+ wmb();
bnxt_db_write(bp, &txr->tx_db, prod);
txr->kick_pending = 0;
}
@@ -388,7 +404,7 @@ static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
- struct tx_bd *txbd;
+ struct tx_bd *txbd, *txbd0;
struct tx_bd_ext *txbd1;
struct netdev_queue *txq;
int i;
@@ -430,11 +446,9 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
last_frag = skb_shinfo(skb)->nr_frags;
- txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
+ txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
- txbd->tx_bd_opaque = prod;
-
- tx_buf = &txr->tx_buf_ring[prod];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
tx_buf->skb = skb;
tx_buf->nr_frags = last_frag;
@@ -519,12 +533,15 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbd->tx_bd_len_flags_type = tx_push->tx_bd_len_flags_type;
txbd->tx_bd_haddr = txr->data_mapping;
+ txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 2);
prod = NEXT_TX(prod);
- txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
+ tx_push->tx_bd_opaque = txbd->tx_bd_opaque;
+ txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
memcpy(txbd, tx_push1, sizeof(*txbd));
prod = NEXT_TX(prod);
tx_push->doorbell =
- cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH | prod);
+ cpu_to_le32(DB_KEY_TX_PUSH | DB_LONG_TX_PUSH |
+ DB_RING_IDX(&txr->tx_db, prod));
WRITE_ONCE(txr->tx_prod, prod);
tx_buf->is_push = 1;
@@ -562,19 +579,29 @@ normal_tx:
((last_frag + 2) << TX_BD_FLAGS_BD_CNT_SHIFT);
txbd->tx_bd_haddr = cpu_to_le64(mapping);
+ txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 2 + last_frag);
prod = NEXT_TX(prod);
txbd1 = (struct tx_bd_ext *)
- &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
+ &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
txbd1->tx_bd_hsize_lflags = lflags;
if (skb_is_gso(skb)) {
+ bool udp_gso = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4);
u32 hdr_len;
- if (skb->encapsulation)
- hdr_len = skb_inner_tcp_all_headers(skb);
- else
+ if (skb->encapsulation) {
+ if (udp_gso)
+ hdr_len = skb_inner_transport_offset(skb) +
+ sizeof(struct udphdr);
+ else
+ hdr_len = skb_inner_tcp_all_headers(skb);
+ } else if (udp_gso) {
+ hdr_len = skb_transport_offset(skb) +
+ sizeof(struct udphdr);
+ } else {
hdr_len = skb_tcp_all_headers(skb);
+ }
txbd1->tx_bd_hsize_lflags |= cpu_to_le32(TX_BD_FLAGS_LSO |
TX_BD_FLAGS_T_IPID |
@@ -601,11 +628,12 @@ normal_tx:
txbd1->tx_bd_cfa_meta = cpu_to_le32(vlan_tag_flags);
txbd1->tx_bd_cfa_action =
cpu_to_le32(cfa_action << TX_BD_CFA_ACTION_SHIFT);
+ txbd0 = txbd;
for (i = 0; i < last_frag; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
prod = NEXT_TX(prod);
- txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
+ txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
len = skb_frag_size(frag);
mapping = skb_frag_dma_map(&pdev->dev, frag, 0, len,
@@ -614,7 +642,7 @@ normal_tx:
if (unlikely(dma_mapping_error(&pdev->dev, mapping)))
goto tx_dma_error;
- tx_buf = &txr->tx_buf_ring[prod];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
dma_unmap_addr_set(tx_buf, mapping, mapping);
txbd->tx_bd_haddr = cpu_to_le64(mapping);
@@ -632,22 +660,26 @@ normal_tx:
skb_tx_timestamp(skb);
- /* Sync BD data before updating doorbell */
- wmb();
-
prod = NEXT_TX(prod);
WRITE_ONCE(txr->tx_prod, prod);
- if (!netdev_xmit_more() || netif_xmit_stopped(txq))
+ if (!netdev_xmit_more() || netif_xmit_stopped(txq)) {
bnxt_txr_db_kick(bp, txr, prod);
- else
+ } else {
+ if (free_size >= bp->tx_wake_thresh)
+ txbd0->tx_bd_len_flags_type |=
+ cpu_to_le32(TX_BD_FLAGS_NO_CMPL);
txr->kick_pending = 1;
+ }
tx_done:
if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) {
- if (netdev_xmit_more() && !tx_buf->is_push)
+ if (netdev_xmit_more() && !tx_buf->is_push) {
+ txbd0->tx_bd_len_flags_type &=
+ cpu_to_le32(~TX_BD_FLAGS_NO_CMPL);
bnxt_txr_db_kick(bp, txr, prod);
+ }
netif_txq_try_stop(txq, bnxt_tx_avail(bp, txr),
bp->tx_wake_thresh);
@@ -662,7 +694,7 @@ tx_dma_error:
/* start back at beginning and unmap skb */
prod = txr->tx_prod;
- tx_buf = &txr->tx_buf_ring[prod];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
dma_unmap_single(&pdev->dev, dma_unmap_addr(tx_buf, mapping),
skb_headlen(skb), DMA_TO_DEVICE);
prod = NEXT_TX(prod);
@@ -670,7 +702,7 @@ tx_dma_error:
/* unmap remaining mapped pages */
for (i = 0; i < last_frag; i++) {
prod = NEXT_TX(prod);
- tx_buf = &txr->tx_buf_ring[prod];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
dma_unmap_page(&pdev->dev, dma_unmap_addr(tx_buf, mapping),
skb_frag_size(&skb_shinfo(skb)->frags[i]),
DMA_TO_DEVICE);
@@ -686,31 +718,32 @@ tx_kick_pending:
return NETDEV_TX_OK;
}
-static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
+static void __bnxt_tx_int(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
+ int budget)
{
- struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
struct netdev_queue *txq = netdev_get_tx_queue(bp->dev, txr->txq_index);
- u16 cons = txr->tx_cons;
struct pci_dev *pdev = bp->pdev;
- int nr_pkts = bnapi->tx_pkts;
- int i;
+ u16 hw_cons = txr->tx_hw_cons;
unsigned int tx_bytes = 0;
+ u16 cons = txr->tx_cons;
+ int tx_pkts = 0;
- for (i = 0; i < nr_pkts; i++) {
+ while (RING_TX(bp, cons) != hw_cons) {
struct bnxt_sw_tx_bd *tx_buf;
struct sk_buff *skb;
int j, last;
- tx_buf = &txr->tx_buf_ring[cons];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, cons)];
cons = NEXT_TX(cons);
skb = tx_buf->skb;
tx_buf->skb = NULL;
if (unlikely(!skb)) {
- bnxt_sched_reset_txr(bp, txr, i);
+ bnxt_sched_reset_txr(bp, txr, cons);
return;
}
+ tx_pkts++;
tx_bytes += skb->len;
if (tx_buf->is_push) {
@@ -724,7 +757,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
for (j = 0; j < last; j++) {
cons = NEXT_TX(cons);
- tx_buf = &txr->tx_buf_ring[cons];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, cons)];
dma_unmap_page(
&pdev->dev,
dma_unmap_addr(tx_buf, mapping),
@@ -732,7 +765,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
DMA_TO_DEVICE);
}
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (BNXT_CHIP_P5(bp)) {
/* PTP worker takes ownership of the skb */
if (!bnxt_get_tx_ts_p5(bp, skb))
skb = NULL;
@@ -747,14 +780,25 @@ next_tx_int:
dev_consume_skb_any(skb);
}
- bnapi->tx_pkts = 0;
WRITE_ONCE(txr->tx_cons, cons);
- __netif_txq_completed_wake(txq, nr_pkts, tx_bytes,
+ __netif_txq_completed_wake(txq, tx_pkts, tx_bytes,
bnxt_tx_avail(bp, txr), bp->tx_wake_thresh,
READ_ONCE(txr->dev_state) == BNXT_DEV_STATE_CLOSING);
}
+static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
+{
+ struct bnxt_tx_ring_info *txr;
+ int i;
+
+ bnxt_for_each_napi_tx(i, bnapi, txr) {
+ if (txr->tx_hw_cons != RING_TX(bp, txr->tx_cons))
+ __bnxt_tx_int(bp, txr, budget);
+ }
+ bnapi->events &= ~BNXT_TX_CMP_EVENT;
+}
+
static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
struct bnxt_rx_ring_info *rxr,
unsigned int *offset,
@@ -803,8 +847,8 @@ static inline u8 *__bnxt_alloc_rx_frag(struct bnxt *bp, dma_addr_t *mapping,
int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
u16 prod, gfp_t gfp)
{
- struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
- struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[prod];
+ struct rx_bd *rxbd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)];
+ struct bnxt_sw_rx_bd *rx_buf = &rxr->rx_buf_ring[RING_RX(bp, prod)];
dma_addr_t mapping;
if (BNXT_RX_PAGE_MODE(bp)) {
@@ -837,9 +881,10 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data)
{
u16 prod = rxr->rx_prod;
struct bnxt_sw_rx_bd *cons_rx_buf, *prod_rx_buf;
+ struct bnxt *bp = rxr->bnapi->bp;
struct rx_bd *cons_bd, *prod_bd;
- prod_rx_buf = &rxr->rx_buf_ring[prod];
+ prod_rx_buf = &rxr->rx_buf_ring[RING_RX(bp, prod)];
cons_rx_buf = &rxr->rx_buf_ring[cons];
prod_rx_buf->data = data;
@@ -847,8 +892,8 @@ void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data)
prod_rx_buf->mapping = cons_rx_buf->mapping;
- prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
- cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
+ prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)];
+ cons_bd = &rxr->rx_desc_ring[RX_RING(bp, cons)][RX_IDX(cons)];
prod_bd->rx_bd_haddr = cons_bd->rx_bd_haddr;
}
@@ -868,7 +913,7 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp,
u16 prod, gfp_t gfp)
{
struct rx_bd *rxbd =
- &rxr->rx_agg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+ &rxr->rx_agg_desc_ring[RX_AGG_RING(bp, prod)][RX_IDX(prod)];
struct bnxt_sw_rx_agg_bd *rx_agg_buf;
struct page *page;
dma_addr_t mapping;
@@ -885,7 +930,7 @@ static inline int bnxt_alloc_rx_page(struct bnxt *bp,
__set_bit(sw_prod, rxr->rx_agg_bmap);
rx_agg_buf = &rxr->rx_agg_ring[sw_prod];
- rxr->rx_sw_agg_prod = NEXT_RX_AGG(sw_prod);
+ rxr->rx_sw_agg_prod = RING_RX_AGG(bp, NEXT_RX_AGG(sw_prod));
rx_agg_buf->page = page;
rx_agg_buf->offset = offset;
@@ -927,7 +972,7 @@ static void bnxt_reuse_rx_agg_bufs(struct bnxt_cp_ring_info *cpr, u16 idx,
bool p5_tpa = false;
u32 i;
- if ((bp->flags & BNXT_FLAG_CHIP_P5) && tpa)
+ if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && tpa)
p5_tpa = true;
for (i = 0; i < agg_bufs; i++) {
@@ -961,13 +1006,13 @@ static void bnxt_reuse_rx_agg_bufs(struct bnxt_cp_ring_info *cpr, u16 idx,
prod_rx_buf->mapping = cons_rx_buf->mapping;
- prod_bd = &rxr->rx_agg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+ prod_bd = &rxr->rx_agg_desc_ring[RX_AGG_RING(bp, prod)][RX_IDX(prod)];
prod_bd->rx_bd_haddr = cpu_to_le64(cons_rx_buf->mapping);
prod_bd->rx_bd_opaque = sw_prod;
prod = NEXT_RX_AGG(prod);
- sw_prod = NEXT_RX_AGG(sw_prod);
+ sw_prod = RING_RX_AGG(bp, NEXT_RX_AGG(sw_prod));
}
rxr->rx_agg_prod = prod;
rxr->rx_sw_agg_prod = sw_prod;
@@ -1094,7 +1139,7 @@ static u32 __bnxt_rx_agg_pages(struct bnxt *bp,
u32 i, total_frag_len = 0;
bool p5_tpa = false;
- if ((bp->flags & BNXT_FLAG_CHIP_P5) && tpa)
+ if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && tpa)
p5_tpa = true;
for (i = 0; i < agg_bufs; i++) {
@@ -1249,7 +1294,7 @@ static int bnxt_discard_rx(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
} else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) {
struct rx_tpa_end_cmp *tpa_end = cmp;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return 0;
agg_bufs = TPA_END_AGG_BUFS(tpa_end);
@@ -1290,8 +1335,39 @@ static u16 bnxt_lookup_agg_idx(struct bnxt_rx_ring_info *rxr, u16 agg_id)
return map->agg_id_tbl[agg_id];
}
+static void bnxt_tpa_metadata(struct bnxt_tpa_info *tpa_info,
+ struct rx_tpa_start_cmp *tpa_start,
+ struct rx_tpa_start_cmp_ext *tpa_start1)
+{
+ tpa_info->cfa_code_valid = 1;
+ tpa_info->cfa_code = TPA_START_CFA_CODE(tpa_start1);
+ tpa_info->vlan_valid = 0;
+ if (tpa_info->flags2 & RX_CMP_FLAGS2_META_FORMAT_VLAN) {
+ tpa_info->vlan_valid = 1;
+ tpa_info->metadata =
+ le32_to_cpu(tpa_start1->rx_tpa_start_cmp_metadata);
+ }
+}
+
+static void bnxt_tpa_metadata_v2(struct bnxt_tpa_info *tpa_info,
+ struct rx_tpa_start_cmp *tpa_start,
+ struct rx_tpa_start_cmp_ext *tpa_start1)
+{
+ tpa_info->vlan_valid = 0;
+ if (TPA_START_VLAN_VALID(tpa_start)) {
+ u32 tpid_sel = TPA_START_VLAN_TPID_SEL(tpa_start);
+ u32 vlan_proto = ETH_P_8021Q;
+
+ tpa_info->vlan_valid = 1;
+ if (tpid_sel == RX_TPA_START_METADATA1_TPID_8021AD)
+ vlan_proto = ETH_P_8021AD;
+ tpa_info->metadata = vlan_proto << 16 |
+ TPA_START_METADATA0_TCI(tpa_start1);
+ }
+}
+
static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
- struct rx_tpa_start_cmp *tpa_start,
+ u8 cmp_type, struct rx_tpa_start_cmp *tpa_start,
struct rx_tpa_start_cmp_ext *tpa_start1)
{
struct bnxt_sw_rx_bd *cons_rx_buf, *prod_rx_buf;
@@ -1300,7 +1376,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
struct rx_bd *prod_bd;
dma_addr_t mapping;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
agg_id = TPA_START_AGG_ID_P5(tpa_start);
agg_id = bnxt_alloc_agg_idx(rxr, agg_id);
} else {
@@ -1309,7 +1385,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
cons = tpa_start->rx_tpa_start_cmp_opaque;
prod = rxr->rx_prod;
cons_rx_buf = &rxr->rx_buf_ring[cons];
- prod_rx_buf = &rxr->rx_buf_ring[prod];
+ prod_rx_buf = &rxr->rx_buf_ring[RING_RX(bp, prod)];
tpa_info = &rxr->rx_tpa[agg_id];
if (unlikely(cons != rxr->rx_next_cons ||
@@ -1320,17 +1396,13 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
bnxt_sched_reset_rxr(bp, rxr);
return;
}
- /* Store cfa_code in tpa_info to use in tpa_end
- * completion processing.
- */
- tpa_info->cfa_code = TPA_START_CFA_CODE(tpa_start1);
prod_rx_buf->data = tpa_info->data;
prod_rx_buf->data_ptr = tpa_info->data_ptr;
mapping = tpa_info->mapping;
prod_rx_buf->mapping = mapping;
- prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
+ prod_bd = &rxr->rx_desc_ring[RX_RING(bp, prod)][RX_IDX(prod)];
prod_bd->rx_bd_haddr = cpu_to_le64(mapping);
@@ -1343,12 +1415,13 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
le32_to_cpu(tpa_start->rx_tpa_start_cmp_len_flags_type) >>
RX_TPA_START_CMP_LEN_SHIFT;
if (likely(TPA_START_HASH_VALID(tpa_start))) {
- u32 hash_type = TPA_START_HASH_TYPE(tpa_start);
-
tpa_info->hash_type = PKT_HASH_TYPE_L4;
tpa_info->gso_type = SKB_GSO_TCPV4;
+ if (TPA_START_IS_IPV6(tpa_start1))
+ tpa_info->gso_type = SKB_GSO_TCPV6;
/* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */
- if (hash_type == 3 || TPA_START_IS_IPV6(tpa_start1))
+ else if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP &&
+ TPA_START_HASH_TYPE(tpa_start) == 3)
tpa_info->gso_type = SKB_GSO_TCPV6;
tpa_info->rss_hash =
le32_to_cpu(tpa_start->rx_tpa_start_cmp_rss_hash);
@@ -1358,13 +1431,16 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
netif_warn(bp, rx_err, bp->dev, "TPA packet without valid hash\n");
}
tpa_info->flags2 = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_flags2);
- tpa_info->metadata = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_metadata);
tpa_info->hdr_info = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_hdr_info);
+ if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP)
+ bnxt_tpa_metadata(tpa_info, tpa_start, tpa_start1);
+ else
+ bnxt_tpa_metadata_v2(tpa_info, tpa_start, tpa_start1);
tpa_info->agg_count = 0;
rxr->rx_prod = NEXT_RX(prod);
- cons = NEXT_RX(cons);
- rxr->rx_next_cons = NEXT_RX(cons);
+ cons = RING_RX(bp, NEXT_RX(cons));
+ rxr->rx_next_cons = RING_RX(bp, NEXT_RX(cons));
cons_rx_buf = &rxr->rx_buf_ring[cons];
bnxt_reuse_rx_data(rxr, cons, cons_rx_buf->data);
@@ -1563,7 +1639,7 @@ static inline struct sk_buff *bnxt_gro_skb(struct bnxt *bp,
skb_shinfo(skb)->gso_size =
le32_to_cpu(tpa_end1->rx_tpa_end_cmp_seg_len);
skb_shinfo(skb)->gso_type = tpa_info->gso_type;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
payload_off = TPA_END_PAYLOAD_OFF_P5(tpa_end1);
else
payload_off = TPA_END_PAYLOAD_OFF(tpa_end);
@@ -1594,6 +1670,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
{
struct bnxt_napi *bnapi = cpr->bnapi;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
+ struct net_device *dev = bp->dev;
u8 *data_ptr, agg_bufs;
unsigned int len;
struct bnxt_tpa_info *tpa_info;
@@ -1611,7 +1688,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
return NULL;
}
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
agg_id = TPA_END_AGG_ID_P5(tpa_end);
agg_id = bnxt_lookup_agg_idx(rxr, agg_id);
agg_bufs = TPA_END_AGG_BUFS_P5(tpa_end1);
@@ -1700,14 +1777,15 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
}
}
- skb->protocol =
- eth_type_trans(skb, bnxt_get_pkt_dev(bp, tpa_info->cfa_code));
+ if (tpa_info->cfa_code_valid)
+ dev = bnxt_get_pkt_dev(bp, tpa_info->cfa_code);
+ skb->protocol = eth_type_trans(skb, dev);
if (tpa_info->hash_type != PKT_HASH_TYPE_NONE)
skb_set_hash(skb, tpa_info->rss_hash, tpa_info->hash_type);
- if ((tpa_info->flags2 & RX_CMP_FLAGS2_META_FORMAT_VLAN) &&
- (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) {
+ if (tpa_info->vlan_valid &&
+ (dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) {
__be16 vlan_proto = htons(tpa_info->metadata >>
RX_CMP_FLAGS2_METADATA_TPID_SFT);
u16 vtag = tpa_info->metadata & RX_CMP_FLAGS2_METADATA_TCI_MASK;
@@ -1774,6 +1852,64 @@ ts_valid:
return true;
}
+static struct sk_buff *bnxt_rx_vlan(struct sk_buff *skb, u8 cmp_type,
+ struct rx_cmp *rxcmp,
+ struct rx_cmp_ext *rxcmp1)
+{
+ __be16 vlan_proto;
+ u16 vtag;
+
+ if (cmp_type == CMP_TYPE_RX_L2_CMP) {
+ __le32 flags2 = rxcmp1->rx_cmp_flags2;
+ u32 meta_data;
+
+ if (!(flags2 & cpu_to_le32(RX_CMP_FLAGS2_META_FORMAT_VLAN)))
+ return skb;
+
+ meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data);
+ vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK;
+ vlan_proto = htons(meta_data >> RX_CMP_FLAGS2_METADATA_TPID_SFT);
+ if (eth_type_vlan(vlan_proto))
+ __vlan_hwaccel_put_tag(skb, vlan_proto, vtag);
+ else
+ goto vlan_err;
+ } else if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) {
+ if (RX_CMP_VLAN_VALID(rxcmp)) {
+ u32 tpid_sel = RX_CMP_VLAN_TPID_SEL(rxcmp);
+
+ if (tpid_sel == RX_CMP_METADATA1_TPID_8021Q)
+ vlan_proto = htons(ETH_P_8021Q);
+ else if (tpid_sel == RX_CMP_METADATA1_TPID_8021AD)
+ vlan_proto = htons(ETH_P_8021AD);
+ else
+ goto vlan_err;
+ vtag = RX_CMP_METADATA0_TCI(rxcmp1);
+ __vlan_hwaccel_put_tag(skb, vlan_proto, vtag);
+ }
+ }
+ return skb;
+vlan_err:
+ dev_kfree_skb(skb);
+ return NULL;
+}
+
+static enum pkt_hash_types bnxt_rss_ext_op(struct bnxt *bp,
+ struct rx_cmp *rxcmp)
+{
+ u8 ext_op;
+
+ ext_op = RX_CMP_V3_HASH_TYPE(bp, rxcmp);
+ switch (ext_op) {
+ case EXT_OP_INNER_4:
+ case EXT_OP_OUTER_4:
+ case EXT_OP_INNFL_3:
+ case EXT_OP_OUTFL_3:
+ return PKT_HASH_TYPE_L4;
+ default:
+ return PKT_HASH_TYPE_L3;
+ }
+}
+
/* returns the following:
* 1 - 1 packet successfully received
* 0 - successful TPA_START, packet not completed yet
@@ -1790,7 +1926,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
struct rx_cmp *rxcmp;
struct rx_cmp_ext *rxcmp1;
u32 tmp_raw_cons = *raw_cons;
- u16 cfa_code, cons, prod, cp_cons = RING_CMP(tmp_raw_cons);
+ u16 cons, prod, cp_cons = RING_CMP(tmp_raw_cons);
struct bnxt_sw_rx_bd *rx_buf;
unsigned int len;
u8 *data_ptr, agg_bufs, cmp_type;
@@ -1827,8 +1963,10 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
dma_rmb();
prod = rxr->rx_prod;
- if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) {
- bnxt_tpa_start(bp, rxr, (struct rx_tpa_start_cmp *)rxcmp,
+ if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP ||
+ cmp_type == CMP_TYPE_RX_L2_TPA_START_V3_CMP) {
+ bnxt_tpa_start(bp, rxr, cmp_type,
+ (struct rx_tpa_start_cmp *)rxcmp,
(struct rx_tpa_start_cmp_ext *)rxcmp1);
*event |= BNXT_RX_EVENT;
@@ -1893,7 +2031,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
rc = -EIO;
if (rx_err & RX_CMPL_ERRORS_BUFFER_ERROR_MASK) {
bnapi->cp_ring.sw_stats.rx.rx_buf_errors++;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5) &&
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
!(bp->fw_cap & BNXT_FW_CAP_RING_MONITOR)) {
netdev_warn_once(bp->dev, "RX buffer error %x\n",
rx_err);
@@ -1981,32 +2119,32 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
}
if (RX_CMP_HASH_VALID(rxcmp)) {
- u32 hash_type = RX_CMP_HASH_TYPE(rxcmp);
- enum pkt_hash_types type = PKT_HASH_TYPE_L4;
+ enum pkt_hash_types type;
- /* RSS profiles 1 and 3 with extract code 0 for inner 4-tuple */
- if (hash_type != 1 && hash_type != 3)
- type = PKT_HASH_TYPE_L3;
+ if (cmp_type == CMP_TYPE_RX_L2_V3_CMP) {
+ type = bnxt_rss_ext_op(bp, rxcmp);
+ } else {
+ u32 hash_type = RX_CMP_HASH_TYPE(rxcmp);
+
+ /* RSS profiles 1 and 3 with extract code 0 for inner
+ * 4-tuple
+ */
+ if (hash_type != 1 && hash_type != 3)
+ type = PKT_HASH_TYPE_L3;
+ else
+ type = PKT_HASH_TYPE_L4;
+ }
skb_set_hash(skb, le32_to_cpu(rxcmp->rx_cmp_rss_hash), type);
}
- cfa_code = RX_CMP_CFA_CODE(rxcmp1);
- skb->protocol = eth_type_trans(skb, bnxt_get_pkt_dev(bp, cfa_code));
+ if (cmp_type == CMP_TYPE_RX_L2_CMP)
+ dev = bnxt_get_pkt_dev(bp, RX_CMP_CFA_CODE(rxcmp1));
+ skb->protocol = eth_type_trans(skb, dev);
- if ((rxcmp1->rx_cmp_flags2 &
- cpu_to_le32(RX_CMP_FLAGS2_META_FORMAT_VLAN)) &&
- (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX)) {
- u32 meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data);
- u16 vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK;
- __be16 vlan_proto = htons(meta_data >>
- RX_CMP_FLAGS2_METADATA_TPID_SFT);
-
- if (eth_type_vlan(vlan_proto)) {
- __vlan_hwaccel_put_tag(skb, vlan_proto, vtag);
- } else {
- dev_kfree_skb(skb);
+ if (skb->dev->features & BNXT_HW_FEATURE_VLAN_ALL_RX) {
+ skb = bnxt_rx_vlan(skb, cmp_type, rxcmp, rxcmp1);
+ if (!skb)
goto next_rx;
- }
}
skb_checksum_none_assert(skb);
@@ -2023,7 +2161,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
}
if (bnxt_rx_ts_valid(bp, flags, rxcmp1, &cmpl_ts)) {
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
u64 ns, ts;
if (!bnxt_get_rx_ts_p5(bp, &ts, cmpl_ts)) {
@@ -2047,7 +2185,7 @@ next_rx:
next_rx_no_len:
rxr->rx_prod = NEXT_RX(prod);
- rxr->rx_next_cons = NEXT_RX(cons);
+ rxr->rx_next_cons = RING_RX(bp, NEXT_RX(cons));
next_rx_no_prod_no_len:
*raw_cons = tmp_raw_cons;
@@ -2086,7 +2224,8 @@ static int bnxt_force_rx_discard(struct bnxt *bp,
*/
dma_rmb();
cmp_type = RX_CMP_TYPE(rxcmp);
- if (cmp_type == CMP_TYPE_RX_L2_CMP) {
+ if (cmp_type == CMP_TYPE_RX_L2_CMP ||
+ cmp_type == CMP_TYPE_RX_L2_V3_CMP) {
rxcmp1->rx_cmp_cfa_code_errors_v2 |=
cpu_to_le32(RX_CMPL_ERRORS_CRC_ERROR);
} else if (cmp_type == CMP_TYPE_RX_L2_TPA_END_CMP) {
@@ -2146,6 +2285,10 @@ static u16 bnxt_agg_ring_id_to_grp_idx(struct bnxt *bp, u16 ring_id)
static u16 bnxt_get_force_speed(struct bnxt_link_info *link_info)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2)
+ return link_info->force_link_speed2;
if (link_info->req_signal_mode == BNXT_SIG_MODE_PAM4)
return link_info->force_pam4_link_speed;
return link_info->force_link_speed;
@@ -2153,6 +2296,28 @@ static u16 bnxt_get_force_speed(struct bnxt_link_info *link_info)
static void bnxt_set_force_speed(struct bnxt_link_info *link_info)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ link_info->req_link_speed = link_info->force_link_speed2;
+ link_info->req_signal_mode = BNXT_SIG_MODE_NRZ;
+ switch (link_info->req_link_speed) {
+ case BNXT_LINK_SPEED_50GB_PAM4:
+ case BNXT_LINK_SPEED_100GB_PAM4:
+ case BNXT_LINK_SPEED_200GB_PAM4:
+ case BNXT_LINK_SPEED_400GB_PAM4:
+ link_info->req_signal_mode = BNXT_SIG_MODE_PAM4;
+ break;
+ case BNXT_LINK_SPEED_100GB_PAM4_112:
+ case BNXT_LINK_SPEED_200GB_PAM4_112:
+ case BNXT_LINK_SPEED_400GB_PAM4_112:
+ link_info->req_signal_mode = BNXT_SIG_MODE_PAM4_112;
+ break;
+ default:
+ link_info->req_signal_mode = BNXT_SIG_MODE_NRZ;
+ }
+ return;
+ }
link_info->req_link_speed = link_info->force_link_speed;
link_info->req_signal_mode = BNXT_SIG_MODE_NRZ;
if (link_info->force_pam4_link_speed) {
@@ -2163,12 +2328,25 @@ static void bnxt_set_force_speed(struct bnxt_link_info *link_info)
static void bnxt_set_auto_speed(struct bnxt_link_info *link_info)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ link_info->advertising = link_info->auto_link_speeds2;
+ return;
+ }
link_info->advertising = link_info->auto_link_speeds;
link_info->advertising_pam4 = link_info->auto_pam4_link_speeds;
}
static bool bnxt_force_speed_updated(struct bnxt_link_info *link_info)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ if (link_info->req_link_speed != link_info->force_link_speed2)
+ return true;
+ return false;
+ }
if (link_info->req_signal_mode == BNXT_SIG_MODE_NRZ &&
link_info->req_link_speed != link_info->force_link_speed)
return true;
@@ -2180,6 +2358,13 @@ static bool bnxt_force_speed_updated(struct bnxt_link_info *link_info)
static bool bnxt_auto_speed_updated(struct bnxt_link_info *link_info)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ if (link_info->advertising != link_info->auto_link_speeds2)
+ return true;
+ return false;
+ }
if (link_info->advertising != link_info->auto_link_speeds ||
link_info->advertising_pam4 != link_info->auto_pam4_link_speeds)
return true;
@@ -2430,7 +2615,7 @@ static int bnxt_async_event_process(struct bnxt *bp,
struct bnxt_rx_ring_info *rxr;
u16 grp_idx;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
goto async_event_process_exit;
netdev_warn(bp->dev, "Ring monitor event, ring type %lu id 0x%x\n",
@@ -2603,7 +2788,6 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
struct bnxt_napi *bnapi = cpr->bnapi;
u32 raw_cons = cpr->cp_raw_cons;
u32 cons;
- int tx_pkts = 0;
int rx_pkts = 0;
u8 event = 0;
struct tx_cmp *txcmp;
@@ -2611,6 +2795,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
cpr->has_more_work = 0;
cpr->had_work_done = 1;
while (1) {
+ u8 cmp_type;
int rc;
cons = RING_CMP(raw_cons);
@@ -2623,17 +2808,31 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
* reading any further.
*/
dma_rmb();
- if (TX_CMP_TYPE(txcmp) == CMP_TYPE_TX_L2_CMP) {
- tx_pkts++;
+ cmp_type = TX_CMP_TYPE(txcmp);
+ if (cmp_type == CMP_TYPE_TX_L2_CMP ||
+ cmp_type == CMP_TYPE_TX_L2_COAL_CMP) {
+ u32 opaque = txcmp->tx_cmp_opaque;
+ struct bnxt_tx_ring_info *txr;
+ u16 tx_freed;
+
+ txr = bnapi->tx_ring[TX_OPAQUE_RING(opaque)];
+ event |= BNXT_TX_CMP_EVENT;
+ if (cmp_type == CMP_TYPE_TX_L2_COAL_CMP)
+ txr->tx_hw_cons = TX_CMP_SQ_CONS_IDX(txcmp);
+ else
+ txr->tx_hw_cons = TX_OPAQUE_PROD(bp, opaque);
+ tx_freed = (txr->tx_hw_cons - txr->tx_cons) &
+ bp->tx_ring_mask;
/* return full budget so NAPI will complete. */
- if (unlikely(tx_pkts >= bp->tx_wake_thresh)) {
+ if (unlikely(tx_freed >= bp->tx_wake_thresh)) {
rx_pkts = budget;
raw_cons = NEXT_RAW_CMP(raw_cons);
if (budget)
cpr->has_more_work = 1;
break;
}
- } else if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) {
+ } else if (cmp_type >= CMP_TYPE_RX_L2_CMP &&
+ cmp_type <= CMP_TYPE_RX_L2_TPA_START_V3_CMP) {
if (likely(budget))
rc = bnxt_rx_pkt(bp, cpr, &raw_cons, &event);
else
@@ -2650,12 +2849,9 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
rx_pkts++;
else if (rc == -EBUSY) /* partial completion */
break;
- } else if (unlikely((TX_CMP_TYPE(txcmp) ==
- CMPL_BASE_TYPE_HWRM_DONE) ||
- (TX_CMP_TYPE(txcmp) ==
- CMPL_BASE_TYPE_HWRM_FWD_REQ) ||
- (TX_CMP_TYPE(txcmp) ==
- CMPL_BASE_TYPE_HWRM_ASYNC_EVENT))) {
+ } else if (unlikely(cmp_type == CMPL_BASE_TYPE_HWRM_DONE ||
+ cmp_type == CMPL_BASE_TYPE_HWRM_FWD_REQ ||
+ cmp_type == CMPL_BASE_TYPE_HWRM_ASYNC_EVENT)) {
bnxt_hwrm_handler(bp, txcmp);
}
raw_cons = NEXT_RAW_CMP(raw_cons);
@@ -2670,7 +2866,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
xdp_do_flush();
if (event & BNXT_TX_EVENT) {
- struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
+ struct bnxt_tx_ring_info *txr = bnapi->tx_ring[0];
u16 prod = txr->tx_prod;
/* Sync BD data before updating doorbell */
@@ -2680,7 +2876,6 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
}
cpr->cp_raw_cons = raw_cons;
- bnapi->tx_pkts += tx_pkts;
bnapi->events |= event;
return rx_pkts;
}
@@ -2688,7 +2883,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi,
int budget)
{
- if (bnapi->tx_pkts && !bnapi->tx_fault)
+ if ((bnapi->events & BNXT_TX_CMP_EVENT) && !bnapi->tx_fault)
bnapi->tx_int(bp, bnapi, budget);
if ((bnapi->events & BNXT_RX_EVENT) && !(bnapi->in_reset)) {
@@ -2701,7 +2896,7 @@ static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi,
bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod);
}
- bnapi->events = 0;
+ bnapi->events &= BNXT_TX_CMP_EVENT;
}
static int bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
@@ -2841,10 +3036,10 @@ static int __bnxt_poll_cqs(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
int i, work_done = 0;
- for (i = 0; i < 2; i++) {
- struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i];
+ for (i = 0; i < cpr->cp_ring_count; i++) {
+ struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[i];
- if (cpr2) {
+ if (cpr2->had_nqe_notify) {
work_done += __bnxt_poll_work(bp, cpr2,
budget - work_done);
cpr->has_more_work |= cpr2->has_more_work;
@@ -2859,14 +3054,22 @@ static void __bnxt_poll_cqs_done(struct bnxt *bp, struct bnxt_napi *bnapi,
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
int i;
- for (i = 0; i < 2; i++) {
- struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[i];
+ for (i = 0; i < cpr->cp_ring_count; i++) {
+ struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[i];
struct bnxt_db_info *db;
- if (cpr2 && cpr2->had_work_done) {
+ if (cpr2->had_work_done) {
+ u32 tgl = 0;
+
+ if (dbr_type == DBR_TYPE_CQ_ARMALL) {
+ cpr2->had_nqe_notify = 0;
+ tgl = cpr2->toggle;
+ }
db = &cpr2->cp_db;
- bnxt_writeq(bp, db->db_key64 | dbr_type |
- RING_CMP(cpr2->cp_raw_cons), db->doorbell);
+ bnxt_writeq(bp,
+ db->db_key64 | dbr_type | DB_TOGGLE(tgl) |
+ DB_RING_IDX(db, cpr2->cp_raw_cons),
+ db->doorbell);
cpr2->had_work_done = 0;
}
}
@@ -2893,6 +3096,8 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget)
work_done = __bnxt_poll_cqs(bp, bnapi, budget);
}
while (1) {
+ u16 type;
+
cons = RING_CMP(raw_cons);
nqcmp = &cpr->nq_desc_ring[CP_RING(cons)][CP_IDX(cons)];
@@ -2914,15 +3119,21 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget)
*/
dma_rmb();
- if (nqcmp->type == cpu_to_le16(NQ_CN_TYPE_CQ_NOTIFICATION)) {
+ type = le16_to_cpu(nqcmp->type);
+ if (NQE_CN_TYPE(type) == NQ_CN_TYPE_CQ_NOTIFICATION) {
u32 idx = le32_to_cpu(nqcmp->cq_handle_low);
+ u32 cq_type = BNXT_NQ_HDL_TYPE(idx);
struct bnxt_cp_ring_info *cpr2;
/* No more budget for RX work */
- if (budget && work_done >= budget && idx == BNXT_RX_HDL)
+ if (budget && work_done >= budget &&
+ cq_type == BNXT_NQ_HDL_TYPE_RX)
break;
- cpr2 = cpr->cp_ring_arr[idx];
+ idx = BNXT_NQ_HDL_IDX(idx);
+ cpr2 = &cpr->cp_ring_arr[idx];
+ cpr2->had_nqe_notify = 1;
+ cpr2->toggle = NQE_CN_TOGGLE(type);
work_done += __bnxt_poll_work(bp, cpr2,
budget - work_done);
cpr->has_more_work |= cpr2->has_more_work;
@@ -2937,8 +3148,9 @@ static int bnxt_poll_p5(struct napi_struct *napi, int budget)
BNXT_DB_NQ_P5(&cpr->cp_db, raw_cons);
}
poll_done:
- cpr_rx = cpr->cp_ring_arr[BNXT_RX_HDL];
- if (cpr_rx && (bp->flags & BNXT_FLAG_DIM)) {
+ cpr_rx = &cpr->cp_ring_arr[0];
+ if (cpr_rx->cp_ring_type == BNXT_NQ_HDL_TYPE_RX &&
+ (bp->flags & BNXT_FLAG_DIM)) {
struct dim_sample dim_sample = {};
dim_update_sample(cpr->event_ctr,
@@ -3112,20 +3324,20 @@ static void bnxt_free_skbs(struct bnxt *bp)
bnxt_free_rx_skbs(bp);
}
-static void bnxt_init_ctx_mem(struct bnxt_mem_init *mem_init, void *p, int len)
+static void bnxt_init_ctx_mem(struct bnxt_ctx_mem_type *ctxm, void *p, int len)
{
- u8 init_val = mem_init->init_val;
- u16 offset = mem_init->offset;
+ u8 init_val = ctxm->init_value;
+ u16 offset = ctxm->init_offset;
u8 *p2 = p;
int i;
if (!init_val)
return;
- if (offset == BNXT_MEM_INVALID_OFFSET) {
+ if (offset == BNXT_CTX_INIT_INVALID_OFFSET) {
memset(p, init_val, len);
return;
}
- for (i = 0; i < len; i += mem_init->size)
+ for (i = 0; i < len; i += ctxm->entry_size)
*(p2 + i + offset) = init_val;
}
@@ -3192,8 +3404,8 @@ static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem)
if (!rmem->pg_arr[i])
return -ENOMEM;
- if (rmem->mem_init)
- bnxt_init_ctx_mem(rmem->mem_init, rmem->pg_arr[i],
+ if (rmem->ctx_mem)
+ bnxt_init_ctx_mem(rmem->ctx_mem, rmem->pg_arr[i],
rmem->page_size);
if (rmem->nr_pages > 1 || rmem->depth > 0) {
if (i == rmem->nr_pages - 2 &&
@@ -3240,7 +3452,7 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp)
int i, j;
bp->max_tpa = MAX_TPA;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
if (!bp->max_tpa_v2)
return 0;
bp->max_tpa = max_t(u16, bp->max_tpa_v2, MAX_TPA_P5);
@@ -3255,7 +3467,7 @@ static int bnxt_alloc_tpa_info(struct bnxt *bp)
if (!rxr->rx_tpa)
return -ENOMEM;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
continue;
for (j = 0; j < bp->max_tpa; j++) {
agg = kcalloc(MAX_SKB_FRAGS, sizeof(*agg), GFP_KERNEL);
@@ -3313,6 +3525,7 @@ static int bnxt_alloc_rx_page_pool(struct bnxt *bp,
pp.pool_size += bp->rx_ring_size;
pp.nid = dev_to_node(&bp->pdev->dev);
pp.napi = &rxr->bnapi->napi;
+ pp.netdev = bp->dev;
pp.dev = &bp->pdev->dev;
pp.dma_dir = bp->rx_dir;
pp.max_len = PAGE_SIZE;
@@ -3410,6 +3623,15 @@ static void bnxt_free_tx_rings(struct bnxt *bp)
}
}
+#define BNXT_TC_TO_RING_BASE(bp, tc) \
+ ((tc) * (bp)->tx_nr_rings_per_tc)
+
+#define BNXT_RING_TO_TC_OFF(bp, tx) \
+ ((tx) % (bp)->tx_nr_rings_per_tc)
+
+#define BNXT_RING_TO_TC(bp, tx) \
+ ((tx) / (bp)->tx_nr_rings_per_tc)
+
static int bnxt_alloc_tx_rings(struct bnxt *bp)
{
int i, j, rc;
@@ -3465,7 +3687,7 @@ static int bnxt_alloc_tx_rings(struct bnxt *bp)
spin_lock_init(&txr->xdp_tx_lock);
if (i < bp->tx_nr_rings_xdp)
continue;
- if (i % bp->tx_nr_rings_per_tc == (bp->tx_nr_rings_per_tc - 1))
+ if (BNXT_RING_TO_TC_OFF(bp, i) == (bp->tx_nr_rings_per_tc - 1))
j++;
}
return 0;
@@ -3548,36 +3770,33 @@ static void bnxt_free_cp_rings(struct bnxt *bp)
bnxt_free_ring(bp, &ring->ring_mem);
- for (j = 0; j < 2; j++) {
- struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
+ if (!cpr->cp_ring_arr)
+ continue;
+
+ for (j = 0; j < cpr->cp_ring_count; j++) {
+ struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j];
- if (cpr2) {
- ring = &cpr2->cp_ring_struct;
- bnxt_free_ring(bp, &ring->ring_mem);
- bnxt_free_cp_arrays(cpr2);
- kfree(cpr2);
- cpr->cp_ring_arr[j] = NULL;
- }
+ ring = &cpr2->cp_ring_struct;
+ bnxt_free_ring(bp, &ring->ring_mem);
+ bnxt_free_cp_arrays(cpr2);
}
+ kfree(cpr->cp_ring_arr);
+ cpr->cp_ring_arr = NULL;
+ cpr->cp_ring_count = 0;
}
}
-static struct bnxt_cp_ring_info *bnxt_alloc_cp_sub_ring(struct bnxt *bp)
+static int bnxt_alloc_cp_sub_ring(struct bnxt *bp,
+ struct bnxt_cp_ring_info *cpr)
{
struct bnxt_ring_mem_info *rmem;
struct bnxt_ring_struct *ring;
- struct bnxt_cp_ring_info *cpr;
int rc;
- cpr = kzalloc(sizeof(*cpr), GFP_KERNEL);
- if (!cpr)
- return NULL;
-
rc = bnxt_alloc_cp_arrays(cpr, bp->cp_nr_pages);
if (rc) {
bnxt_free_cp_arrays(cpr);
- kfree(cpr);
- return NULL;
+ return -ENOMEM;
}
ring = &cpr->cp_ring_struct;
rmem = &ring->ring_mem;
@@ -3590,23 +3809,26 @@ static struct bnxt_cp_ring_info *bnxt_alloc_cp_sub_ring(struct bnxt *bp)
if (rc) {
bnxt_free_ring(bp, rmem);
bnxt_free_cp_arrays(cpr);
- kfree(cpr);
- cpr = NULL;
}
- return cpr;
+ return rc;
}
static int bnxt_alloc_cp_rings(struct bnxt *bp)
{
bool sh = !!(bp->flags & BNXT_FLAG_SHARED_RINGS);
- int i, rc, ulp_base_vec, ulp_msix;
+ int i, j, rc, ulp_base_vec, ulp_msix;
+ int tcs = bp->num_tc;
+ if (!tcs)
+ tcs = 1;
ulp_msix = bnxt_get_ulp_msix_num(bp);
ulp_base_vec = bnxt_get_ulp_msix_base(bp);
- for (i = 0; i < bp->cp_nr_rings; i++) {
+ for (i = 0, j = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
- struct bnxt_cp_ring_info *cpr;
+ struct bnxt_cp_ring_info *cpr, *cpr2;
struct bnxt_ring_struct *ring;
+ int cp_count = 0, k;
+ int rx = 0, tx = 0;
if (!bnapi)
continue;
@@ -3624,35 +3846,55 @@ static int bnxt_alloc_cp_rings(struct bnxt *bp)
else
ring->map_idx = i;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
continue;
if (i < bp->rx_nr_rings) {
- struct bnxt_cp_ring_info *cpr2 =
- bnxt_alloc_cp_sub_ring(bp);
-
- cpr->cp_ring_arr[BNXT_RX_HDL] = cpr2;
- if (!cpr2)
- return -ENOMEM;
- cpr2->bnapi = bnapi;
+ cp_count++;
+ rx = 1;
+ }
+ if (i < bp->tx_nr_rings_xdp) {
+ cp_count++;
+ tx = 1;
+ } else if ((sh && i < bp->tx_nr_rings) ||
+ (!sh && i >= bp->rx_nr_rings)) {
+ cp_count += tcs;
+ tx = 1;
}
- if ((sh && i < bp->tx_nr_rings) ||
- (!sh && i >= bp->rx_nr_rings)) {
- struct bnxt_cp_ring_info *cpr2 =
- bnxt_alloc_cp_sub_ring(bp);
- cpr->cp_ring_arr[BNXT_TX_HDL] = cpr2;
- if (!cpr2)
- return -ENOMEM;
+ cpr->cp_ring_arr = kcalloc(cp_count, sizeof(*cpr),
+ GFP_KERNEL);
+ if (!cpr->cp_ring_arr)
+ return -ENOMEM;
+ cpr->cp_ring_count = cp_count;
+
+ for (k = 0; k < cp_count; k++) {
+ cpr2 = &cpr->cp_ring_arr[k];
+ rc = bnxt_alloc_cp_sub_ring(bp, cpr2);
+ if (rc)
+ return rc;
cpr2->bnapi = bnapi;
+ cpr2->cp_idx = k;
+ if (!k && rx) {
+ bp->rx_ring[i].rx_cpr = cpr2;
+ cpr2->cp_ring_type = BNXT_NQ_HDL_TYPE_RX;
+ } else {
+ int n, tc = k - rx;
+
+ n = BNXT_TC_TO_RING_BASE(bp, tc) + j;
+ bp->tx_ring[n].tx_cpr = cpr2;
+ cpr2->cp_ring_type = BNXT_NQ_HDL_TYPE_TX;
+ }
}
+ if (tx)
+ j++;
}
return 0;
}
static void bnxt_init_ring_struct(struct bnxt *bp)
{
- int i;
+ int i, j;
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
@@ -3697,18 +3939,16 @@ static void bnxt_init_ring_struct(struct bnxt *bp)
rmem->vmem = (void **)&rxr->rx_agg_ring;
skip_rx:
- txr = bnapi->tx_ring;
- if (!txr)
- continue;
-
- ring = &txr->tx_ring_struct;
- rmem = &ring->ring_mem;
- rmem->nr_pages = bp->tx_nr_pages;
- rmem->page_size = HW_RXBD_RING_SIZE;
- rmem->pg_arr = (void **)txr->tx_desc_ring;
- rmem->dma_arr = txr->tx_desc_mapping;
- rmem->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages;
- rmem->vmem = (void **)&txr->tx_buf_ring;
+ bnxt_for_each_napi_tx(j, bnapi, txr) {
+ ring = &txr->tx_ring_struct;
+ rmem = &ring->ring_mem;
+ rmem->nr_pages = bp->tx_nr_pages;
+ rmem->page_size = HW_TXBD_RING_SIZE;
+ rmem->pg_arr = (void **)txr->tx_desc_ring;
+ rmem->dma_arr = txr->tx_desc_mapping;
+ rmem->vmem_size = SW_TXBD_RING_SIZE * bp->tx_nr_pages;
+ rmem->vmem = (void **)&txr->tx_buf_ring;
+ }
}
}
@@ -3799,6 +4039,9 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr)
ring = &rxr->rx_ring_struct;
bnxt_init_rxbd_pages(ring, type);
+ netif_queue_set_napi(bp->dev, ring_nr, NETDEV_QUEUE_TYPE_RX,
+ &rxr->bnapi->napi);
+
if (BNXT_RX_PAGE_MODE(bp) && bp->xdp_prog) {
bpf_prog_add(bp->xdp_prog, 1);
rxr->xdp_prog = bp->xdp_prog;
@@ -3829,11 +4072,10 @@ static void bnxt_init_cp_rings(struct bnxt *bp)
ring->fw_ring_id = INVALID_HW_RING_ID;
cpr->rx_ring_coal.coal_ticks = bp->rx_coal.coal_ticks;
cpr->rx_ring_coal.coal_bufs = bp->rx_coal.coal_bufs;
- for (j = 0; j < 2; j++) {
- struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
-
- if (!cpr2)
- continue;
+ if (!cpr->cp_ring_arr)
+ continue;
+ for (j = 0; j < cpr->cp_ring_count; j++) {
+ struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j];
ring = &cpr2->cp_ring_struct;
ring->fw_ring_id = INVALID_HW_RING_ID;
@@ -3876,6 +4118,11 @@ static int bnxt_init_tx_rings(struct bnxt *bp)
struct bnxt_ring_struct *ring = &txr->tx_ring_struct;
ring->fw_ring_id = INVALID_HW_RING_ID;
+
+ if (i >= bp->tx_nr_rings_xdp)
+ netif_queue_set_napi(bp->dev, i - bp->tx_nr_rings_xdp,
+ NETDEV_QUEUE_TYPE_TX,
+ &txr->bnapi->napi);
}
return 0;
@@ -3921,7 +4168,7 @@ static int bnxt_alloc_vnics(struct bnxt *bp)
int num_vnics = 1;
#ifdef CONFIG_RFS_ACCEL
- if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS)
+ if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) == BNXT_FLAG_RFS)
num_vnics += bp->rx_nr_rings;
#endif
@@ -3952,13 +4199,22 @@ static void bnxt_init_vnics(struct bnxt *bp)
vnic->fw_l2_ctx_id = INVALID_HW_RING_ID;
if (bp->vnic_info[i].rss_hash_key) {
- if (i == 0)
+ if (!i) {
+ u8 *key = (void *)vnic->rss_hash_key;
+ int k;
+
+ bp->toeplitz_prefix = 0;
get_random_bytes(vnic->rss_hash_key,
HW_HASH_KEY_SIZE);
- else
+ for (k = 0; k < 8; k++) {
+ bp->toeplitz_prefix <<= 8;
+ bp->toeplitz_prefix |= key[k];
+ }
+ } else {
memcpy(vnic->rss_hash_key,
bp->vnic_info[0].rss_hash_key,
HW_HASH_KEY_SIZE);
+ }
}
}
}
@@ -4194,7 +4450,7 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp)
}
}
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
goto vnic_skip_grps;
if (vnic->flags & BNXT_VNIC_RSS_FLAG)
@@ -4208,13 +4464,13 @@ static int bnxt_alloc_vnic_attributes(struct bnxt *bp)
goto out;
}
vnic_skip_grps:
- if ((bp->flags & BNXT_FLAG_NEW_RSS_CAP) &&
+ if ((bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) &&
!(vnic->flags & BNXT_VNIC_RSS_FLAG))
continue;
/* Allocate rss table and hash key */
size = L1_CACHE_ALIGN(HW_HASH_INDEX_SIZE * sizeof(u16));
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
size = L1_CACHE_ALIGN(BNXT_MAX_RSS_TABLE_SIZE_P5);
vnic->rss_table_size = size + HW_HASH_KEY_SIZE;
@@ -4324,7 +4580,7 @@ static int bnxt_hwrm_func_qstat_ext(struct bnxt *bp,
int rc;
if (!(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED) ||
- !(bp->flags & BNXT_FLAG_CHIP_P5))
+ !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
return -EOPNOTSUPP;
rc = hwrm_req_init(bp, req, HWRM_FUNC_QSTATS_EXT);
@@ -4362,7 +4618,7 @@ static void bnxt_init_stats(struct bnxt *bp)
stats = &cpr->stats;
rc = bnxt_hwrm_func_qstat_ext(bp, stats);
if (rc) {
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
mask = (1ULL << 48) - 1;
else
mask = -1ULL;
@@ -4508,7 +4764,7 @@ alloc_tx_ext_stats:
static void bnxt_clear_ring_indices(struct bnxt *bp)
{
- int i;
+ int i, j;
if (!bp->bnapi)
return;
@@ -4525,10 +4781,10 @@ static void bnxt_clear_ring_indices(struct bnxt *bp)
cpr = &bnapi->cp_ring;
cpr->cp_raw_cons = 0;
- txr = bnapi->tx_ring;
- if (txr) {
+ bnxt_for_each_napi_tx(j, bnapi, txr) {
txr->tx_prod = 0;
txr->tx_cons = 0;
+ txr->tx_hw_cons = 0;
}
rxr = bnapi->rx_ring;
@@ -4538,12 +4794,12 @@ static void bnxt_clear_ring_indices(struct bnxt *bp)
rxr->rx_sw_agg_prod = 0;
rxr->rx_next_cons = 0;
}
+ bnapi->events = 0;
}
}
-static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool irq_reinit)
+static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all)
{
-#ifdef CONFIG_RFS_ACCEL
int i;
/* Under rtnl_lock and all our NAPIs have been disabled. It's
@@ -4555,40 +4811,73 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool irq_reinit)
struct bnxt_ntuple_filter *fltr;
head = &bp->ntp_fltr_hash_tbl[i];
- hlist_for_each_entry_safe(fltr, tmp, head, hash) {
- hlist_del(&fltr->hash);
+ hlist_for_each_entry_safe(fltr, tmp, head, base.hash) {
+ bnxt_del_l2_filter(bp, fltr->l2_fltr);
+ if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST))
+ continue;
+ hlist_del(&fltr->base.hash);
+ clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap);
+ bp->ntp_fltr_count--;
kfree(fltr);
}
}
- if (irq_reinit) {
- bitmap_free(bp->ntp_fltr_bmap);
- bp->ntp_fltr_bmap = NULL;
- }
+ if (!all)
+ return;
+
+ bitmap_free(bp->ntp_fltr_bmap);
+ bp->ntp_fltr_bmap = NULL;
bp->ntp_fltr_count = 0;
-#endif
}
static int bnxt_alloc_ntp_fltrs(struct bnxt *bp)
{
-#ifdef CONFIG_RFS_ACCEL
int i, rc = 0;
- if (!(bp->flags & BNXT_FLAG_RFS))
+ if (!(bp->flags & BNXT_FLAG_RFS) || bp->ntp_fltr_bmap)
return 0;
for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++)
INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]);
bp->ntp_fltr_count = 0;
- bp->ntp_fltr_bmap = bitmap_zalloc(BNXT_NTP_FLTR_MAX_FLTR, GFP_KERNEL);
+ bp->ntp_fltr_bmap = bitmap_zalloc(BNXT_MAX_FLTR, GFP_KERNEL);
if (!bp->ntp_fltr_bmap)
rc = -ENOMEM;
return rc;
-#else
- return 0;
-#endif
+}
+
+static void bnxt_free_l2_filters(struct bnxt *bp, bool all)
+{
+ int i;
+
+ for (i = 0; i < BNXT_L2_FLTR_HASH_SIZE; i++) {
+ struct hlist_head *head;
+ struct hlist_node *tmp;
+ struct bnxt_l2_filter *fltr;
+
+ head = &bp->l2_fltr_hash_tbl[i];
+ hlist_for_each_entry_safe(fltr, tmp, head, base.hash) {
+ if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST))
+ continue;
+ hlist_del(&fltr->base.hash);
+ if (fltr->base.flags) {
+ clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap);
+ bp->ntp_fltr_count--;
+ }
+ kfree(fltr);
+ }
+ }
+}
+
+static void bnxt_init_l2_fltr_tbl(struct bnxt *bp)
+{
+ int i;
+
+ for (i = 0; i < BNXT_L2_FLTR_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&bp->l2_fltr_hash_tbl[i]);
+ get_random_bytes(&bp->hash_seed, sizeof(bp->hash_seed));
}
static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init)
@@ -4598,7 +4887,8 @@ static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init)
bnxt_free_rx_rings(bp);
bnxt_free_cp_rings(bp);
bnxt_free_all_cp_arrays(bp);
- bnxt_free_ntp_fltrs(bp, irq_re_init);
+ bnxt_free_ntp_fltrs(bp, false);
+ bnxt_free_l2_filters(bp, false);
if (irq_re_init) {
bnxt_free_ring_stats(bp);
if (!(bp->phy_flags & BNXT_PHY_FL_PORT_STATS_NO_RESET) ||
@@ -4641,7 +4931,7 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init)
bp->bnapi[i] = bnapi;
bp->bnapi[i]->index = i;
bp->bnapi[i]->bp = bp;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
struct bnxt_cp_ring_info *cpr =
&bp->bnapi[i]->cp_ring;
@@ -4659,11 +4949,13 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init)
for (i = 0; i < bp->rx_nr_rings; i++) {
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[i];
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
rxr->rx_ring_struct.ring_mem.flags =
BNXT_RMEM_RING_PTE_FLAG;
rxr->rx_agg_ring_struct.ring_mem.flags =
BNXT_RMEM_RING_PTE_FLAG;
+ } else {
+ rxr->rx_cpr = &bp->bnapi[i]->cp_ring;
}
rxr->bnapi = bp->bnapi[i];
bp->bnapi[i]->rx_ring = &bp->rx_ring[i];
@@ -4686,22 +4978,33 @@ static int bnxt_alloc_mem(struct bnxt *bp, bool irq_re_init)
else
j = bp->rx_nr_rings;
- for (i = 0; i < bp->tx_nr_rings; i++, j++) {
+ for (i = 0; i < bp->tx_nr_rings; i++) {
struct bnxt_tx_ring_info *txr = &bp->tx_ring[i];
+ struct bnxt_napi *bnapi2;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
txr->tx_ring_struct.ring_mem.flags =
BNXT_RMEM_RING_PTE_FLAG;
- txr->bnapi = bp->bnapi[j];
- bp->bnapi[j]->tx_ring = txr;
bp->tx_ring_map[i] = bp->tx_nr_rings_xdp + i;
if (i >= bp->tx_nr_rings_xdp) {
+ int k = j + BNXT_RING_TO_TC_OFF(bp, i);
+
+ bnapi2 = bp->bnapi[k];
txr->txq_index = i - bp->tx_nr_rings_xdp;
- bp->bnapi[j]->tx_int = bnxt_tx_int;
+ txr->tx_napi_idx =
+ BNXT_RING_TO_TC(bp, txr->txq_index);
+ bnapi2->tx_ring[txr->tx_napi_idx] = txr;
+ bnapi2->tx_int = bnxt_tx_int;
} else {
- bp->bnapi[j]->flags |= BNXT_NAPI_FLAG_XDP;
- bp->bnapi[j]->tx_int = bnxt_tx_int_xdp;
+ bnapi2 = bp->bnapi[j];
+ bnapi2->flags |= BNXT_NAPI_FLAG_XDP;
+ bnapi2->tx_ring[0] = txr;
+ bnapi2->tx_int = bnxt_tx_int_xdp;
+ j++;
}
+ txr->bnapi = bnapi2;
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
+ txr->tx_cpr = &bnapi2->cp_ring;
}
rc = bnxt_alloc_stats(bp);
@@ -4913,6 +5216,8 @@ int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp)
return hwrm_req_send(bp, req);
}
+static int bnxt_set_tpa(struct bnxt *bp, bool set_tpa);
+
static int bnxt_hwrm_tunnel_dst_port_free(struct bnxt *bp, u8 tunnel_type)
{
struct hwrm_tunnel_dst_port_free_input *req;
@@ -4942,6 +5247,11 @@ static int bnxt_hwrm_tunnel_dst_port_free(struct bnxt *bp, u8 tunnel_type)
bp->nge_port = 0;
bp->nge_fw_dst_port_id = INVALID_HW_RING_ID;
break;
+ case TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE:
+ req->tunnel_dst_port_id = cpu_to_le16(bp->vxlan_gpe_fw_dst_port_id);
+ bp->vxlan_gpe_port = 0;
+ bp->vxlan_gpe_fw_dst_port_id = INVALID_HW_RING_ID;
+ break;
default:
break;
}
@@ -4950,6 +5260,8 @@ static int bnxt_hwrm_tunnel_dst_port_free(struct bnxt *bp, u8 tunnel_type)
if (rc)
netdev_err(bp->dev, "hwrm_tunnel_dst_port_free failed. rc:%d\n",
rc);
+ if (bp->flags & BNXT_FLAG_TPA)
+ bnxt_set_tpa(bp, true);
return rc;
}
@@ -4985,9 +5297,16 @@ static int bnxt_hwrm_tunnel_dst_port_alloc(struct bnxt *bp, __be16 port,
bp->nge_port = port;
bp->nge_fw_dst_port_id = le16_to_cpu(resp->tunnel_dst_port_id);
break;
+ case TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE:
+ bp->vxlan_gpe_port = port;
+ bp->vxlan_gpe_fw_dst_port_id =
+ le16_to_cpu(resp->tunnel_dst_port_id);
+ break;
default:
break;
}
+ if (bp->flags & BNXT_FLAG_TPA)
+ bnxt_set_tpa(bp, true);
err_out:
hwrm_req_drop(bp, req);
@@ -5013,25 +5332,301 @@ static int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt *bp, u16 vnic_id)
return hwrm_req_send_silent(bp, req);
}
+void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr)
+{
+ if (!atomic_dec_and_test(&fltr->refcnt))
+ return;
+ spin_lock_bh(&bp->ntp_fltr_lock);
+ if (!test_and_clear_bit(BNXT_FLTR_INSERTED, &fltr->base.state)) {
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ return;
+ }
+ hlist_del_rcu(&fltr->base.hash);
+ if (fltr->base.flags) {
+ clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap);
+ bp->ntp_fltr_count--;
+ }
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ kfree_rcu(fltr, base.rcu);
+}
+
+static struct bnxt_l2_filter *__bnxt_lookup_l2_filter(struct bnxt *bp,
+ struct bnxt_l2_key *key,
+ u32 idx)
+{
+ struct hlist_head *head = &bp->l2_fltr_hash_tbl[idx];
+ struct bnxt_l2_filter *fltr;
+
+ hlist_for_each_entry_rcu(fltr, head, base.hash) {
+ struct bnxt_l2_key *l2_key = &fltr->l2_key;
+
+ if (ether_addr_equal(l2_key->dst_mac_addr, key->dst_mac_addr) &&
+ l2_key->vlan == key->vlan)
+ return fltr;
+ }
+ return NULL;
+}
+
+static struct bnxt_l2_filter *bnxt_lookup_l2_filter(struct bnxt *bp,
+ struct bnxt_l2_key *key,
+ u32 idx)
+{
+ struct bnxt_l2_filter *fltr = NULL;
+
+ rcu_read_lock();
+ fltr = __bnxt_lookup_l2_filter(bp, key, idx);
+ if (fltr)
+ atomic_inc(&fltr->refcnt);
+ rcu_read_unlock();
+ return fltr;
+}
+
+#define BNXT_IPV4_4TUPLE(bp, fkeys) \
+ (((fkeys)->basic.ip_proto == IPPROTO_TCP && \
+ (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) || \
+ ((fkeys)->basic.ip_proto == IPPROTO_UDP && \
+ (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4))
+
+#define BNXT_IPV6_4TUPLE(bp, fkeys) \
+ (((fkeys)->basic.ip_proto == IPPROTO_TCP && \
+ (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) || \
+ ((fkeys)->basic.ip_proto == IPPROTO_UDP && \
+ (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6))
+
+static u32 bnxt_get_rss_flow_tuple_len(struct bnxt *bp, struct flow_keys *fkeys)
+{
+ if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
+ if (BNXT_IPV4_4TUPLE(bp, fkeys))
+ return sizeof(fkeys->addrs.v4addrs) +
+ sizeof(fkeys->ports);
+
+ if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
+ return sizeof(fkeys->addrs.v4addrs);
+ }
+
+ if (fkeys->basic.n_proto == htons(ETH_P_IPV6)) {
+ if (BNXT_IPV6_4TUPLE(bp, fkeys))
+ return sizeof(fkeys->addrs.v6addrs) +
+ sizeof(fkeys->ports);
+
+ if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
+ return sizeof(fkeys->addrs.v6addrs);
+ }
+
+ return 0;
+}
+
+static u32 bnxt_toeplitz(struct bnxt *bp, struct flow_keys *fkeys,
+ const unsigned char *key)
+{
+ u64 prefix = bp->toeplitz_prefix, hash = 0;
+ struct bnxt_ipv4_tuple tuple4;
+ struct bnxt_ipv6_tuple tuple6;
+ int i, j, len = 0;
+ u8 *four_tuple;
+
+ len = bnxt_get_rss_flow_tuple_len(bp, fkeys);
+ if (!len)
+ return 0;
+
+ if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
+ tuple4.v4addrs = fkeys->addrs.v4addrs;
+ tuple4.ports = fkeys->ports;
+ four_tuple = (unsigned char *)&tuple4;
+ } else {
+ tuple6.v6addrs = fkeys->addrs.v6addrs;
+ tuple6.ports = fkeys->ports;
+ four_tuple = (unsigned char *)&tuple6;
+ }
+
+ for (i = 0, j = 8; i < len; i++, j++) {
+ u8 byte = four_tuple[i];
+ int bit;
+
+ for (bit = 0; bit < 8; bit++, prefix <<= 1, byte <<= 1) {
+ if (byte & 0x80)
+ hash ^= prefix;
+ }
+ prefix |= (j < HW_HASH_KEY_SIZE) ? key[j] : 0;
+ }
+
+ /* The valid part of the hash is in the upper 32 bits. */
+ return (hash >> 32) & BNXT_NTP_FLTR_HASH_MASK;
+}
+
#ifdef CONFIG_RFS_ACCEL
-static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp,
- struct bnxt_ntuple_filter *fltr)
+static struct bnxt_l2_filter *
+bnxt_lookup_l2_filter_from_key(struct bnxt *bp, struct bnxt_l2_key *key)
+{
+ struct bnxt_l2_filter *fltr;
+ u32 idx;
+
+ idx = jhash2(&key->filter_key, BNXT_L2_KEY_SIZE, bp->hash_seed) &
+ BNXT_L2_FLTR_HASH_MASK;
+ fltr = bnxt_lookup_l2_filter(bp, key, idx);
+ return fltr;
+}
+#endif
+
+static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr,
+ struct bnxt_l2_key *key, u32 idx)
+{
+ struct hlist_head *head;
+
+ ether_addr_copy(fltr->l2_key.dst_mac_addr, key->dst_mac_addr);
+ fltr->l2_key.vlan = key->vlan;
+ fltr->base.type = BNXT_FLTR_TYPE_L2;
+ if (fltr->base.flags) {
+ int bit_id;
+
+ bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap,
+ BNXT_MAX_FLTR, 0);
+ if (bit_id < 0)
+ return -ENOMEM;
+ fltr->base.sw_id = (u16)bit_id;
+ }
+ head = &bp->l2_fltr_hash_tbl[idx];
+ hlist_add_head_rcu(&fltr->base.hash, head);
+ set_bit(BNXT_FLTR_INSERTED, &fltr->base.state);
+ atomic_set(&fltr->refcnt, 1);
+ return 0;
+}
+
+static struct bnxt_l2_filter *bnxt_alloc_l2_filter(struct bnxt *bp,
+ struct bnxt_l2_key *key,
+ gfp_t gfp)
+{
+ struct bnxt_l2_filter *fltr;
+ u32 idx;
+ int rc;
+
+ idx = jhash2(&key->filter_key, BNXT_L2_KEY_SIZE, bp->hash_seed) &
+ BNXT_L2_FLTR_HASH_MASK;
+ fltr = bnxt_lookup_l2_filter(bp, key, idx);
+ if (fltr)
+ return fltr;
+
+ fltr = kzalloc(sizeof(*fltr), gfp);
+ if (!fltr)
+ return ERR_PTR(-ENOMEM);
+ spin_lock_bh(&bp->ntp_fltr_lock);
+ rc = bnxt_init_l2_filter(bp, fltr, key, idx);
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ if (rc) {
+ bnxt_del_l2_filter(bp, fltr);
+ fltr = ERR_PTR(rc);
+ }
+ return fltr;
+}
+
+static u16 bnxt_vf_target_id(struct bnxt_pf_info *pf, u16 vf_idx)
+{
+#ifdef CONFIG_BNXT_SRIOV
+ struct bnxt_vf_info *vf = &pf->vf[vf_idx];
+
+ return vf->fw_fid;
+#else
+ return INVALID_HW_RING_ID;
+#endif
+}
+
+int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr)
+{
+ struct hwrm_cfa_l2_filter_free_input *req;
+ u16 target_id = 0xffff;
+ int rc;
+
+ if (fltr->base.flags & BNXT_ACT_FUNC_DST) {
+ struct bnxt_pf_info *pf = &bp->pf;
+
+ if (fltr->base.vf_idx >= pf->active_vfs)
+ return -EINVAL;
+
+ target_id = bnxt_vf_target_id(pf, fltr->base.vf_idx);
+ if (target_id == INVALID_HW_RING_ID)
+ return -EINVAL;
+ }
+
+ rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_FREE);
+ if (rc)
+ return rc;
+
+ req->target_id = cpu_to_le16(target_id);
+ req->l2_filter_id = fltr->base.filter_id;
+ return hwrm_req_send(bp, req);
+}
+
+int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr)
+{
+ struct hwrm_cfa_l2_filter_alloc_output *resp;
+ struct hwrm_cfa_l2_filter_alloc_input *req;
+ u16 target_id = 0xffff;
+ int rc;
+
+ if (fltr->base.flags & BNXT_ACT_FUNC_DST) {
+ struct bnxt_pf_info *pf = &bp->pf;
+
+ if (fltr->base.vf_idx >= pf->active_vfs)
+ return -EINVAL;
+
+ target_id = bnxt_vf_target_id(pf, fltr->base.vf_idx);
+ }
+ rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_ALLOC);
+ if (rc)
+ return rc;
+
+ req->target_id = cpu_to_le16(target_id);
+ req->flags = cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX);
+
+ if (!BNXT_CHIP_TYPE_NITRO_A0(bp))
+ req->flags |=
+ cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST);
+ req->dst_id = cpu_to_le16(fltr->base.fw_vnic_id);
+ req->enables =
+ cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR |
+ CFA_L2_FILTER_ALLOC_REQ_ENABLES_DST_ID |
+ CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK);
+ ether_addr_copy(req->l2_addr, fltr->l2_key.dst_mac_addr);
+ eth_broadcast_addr(req->l2_addr_mask);
+
+ if (fltr->l2_key.vlan) {
+ req->enables |=
+ cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_IVLAN |
+ CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_IVLAN_MASK |
+ CFA_L2_FILTER_ALLOC_REQ_ENABLES_NUM_VLANS);
+ req->num_vlans = 1;
+ req->l2_ivlan = cpu_to_le16(fltr->l2_key.vlan);
+ req->l2_ivlan_mask = cpu_to_le16(0xfff);
+ }
+
+ resp = hwrm_req_hold(bp, req);
+ rc = hwrm_req_send(bp, req);
+ if (!rc) {
+ fltr->base.filter_id = resp->l2_filter_id;
+ set_bit(BNXT_FLTR_VALID, &fltr->base.state);
+ }
+ hwrm_req_drop(bp, req);
+ return rc;
+}
+
+int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr)
{
struct hwrm_cfa_ntuple_filter_free_input *req;
int rc;
+ set_bit(BNXT_FLTR_FW_DELETED, &fltr->base.state);
rc = hwrm_req_init(bp, req, HWRM_CFA_NTUPLE_FILTER_FREE);
if (rc)
return rc;
- req->ntuple_filter_id = fltr->filter_id;
+ req->ntuple_filter_id = fltr->base.filter_id;
return hwrm_req_send(bp, req);
}
#define BNXT_NTP_FLTR_FLAGS \
(CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_L2_FILTER_ID | \
CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_ETHERTYPE | \
- CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_SRC_MACADDR | \
CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_IPADDR_TYPE | \
CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_SRC_IPADDR | \
CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_SRC_IPADDR_MASK | \
@@ -5047,12 +5642,21 @@ static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp,
#define BNXT_NTP_TUNNEL_FLTR_FLAG \
CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_TUNNEL_TYPE
-static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
- struct bnxt_ntuple_filter *fltr)
+void bnxt_fill_ipv6_mask(__be32 mask[4])
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ mask[i] = cpu_to_be32(~0);
+}
+
+int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr)
{
struct hwrm_cfa_ntuple_filter_alloc_output *resp;
struct hwrm_cfa_ntuple_filter_alloc_input *req;
struct flow_keys *keys = &fltr->fkeys;
+ struct bnxt_l2_filter *l2_fltr;
struct bnxt_vnic_info *vnic;
u32 flags = 0;
int rc;
@@ -5061,42 +5665,47 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
if (rc)
return rc;
- req->l2_filter_id = bp->vnic_info[0].fw_l2_filter_id[fltr->l2_fltr_idx];
+ l2_fltr = fltr->l2_fltr;
+ req->l2_filter_id = l2_fltr->base.filter_id;
+
if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) {
flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX;
- req->dst_id = cpu_to_le16(fltr->rxq);
+ req->dst_id = cpu_to_le16(fltr->base.rxq);
} else {
- vnic = &bp->vnic_info[fltr->rxq + 1];
+ vnic = &bp->vnic_info[fltr->base.rxq + 1];
req->dst_id = cpu_to_le16(vnic->fw_vnic_id);
}
req->flags = cpu_to_le32(flags);
req->enables = cpu_to_le32(BNXT_NTP_FLTR_FLAGS);
req->ethertype = htons(ETH_P_IP);
- memcpy(req->src_macaddr, fltr->src_mac_addr, ETH_ALEN);
req->ip_addr_type = CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV4;
req->ip_protocol = keys->basic.ip_proto;
if (keys->basic.n_proto == htons(ETH_P_IPV6)) {
- int i;
-
req->ethertype = htons(ETH_P_IPV6);
req->ip_addr_type =
CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV6;
- *(struct in6_addr *)&req->src_ipaddr[0] =
- keys->addrs.v6addrs.src;
- *(struct in6_addr *)&req->dst_ipaddr[0] =
- keys->addrs.v6addrs.dst;
- for (i = 0; i < 4; i++) {
- req->src_ipaddr_mask[i] = cpu_to_be32(0xffffffff);
- req->dst_ipaddr_mask[i] = cpu_to_be32(0xffffffff);
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) {
+ *(struct in6_addr *)&req->src_ipaddr[0] =
+ keys->addrs.v6addrs.src;
+ bnxt_fill_ipv6_mask(req->src_ipaddr_mask);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) {
+ *(struct in6_addr *)&req->dst_ipaddr[0] =
+ keys->addrs.v6addrs.dst;
+ bnxt_fill_ipv6_mask(req->dst_ipaddr_mask);
}
} else {
- req->src_ipaddr[0] = keys->addrs.v4addrs.src;
- req->src_ipaddr_mask[0] = cpu_to_be32(0xffffffff);
- req->dst_ipaddr[0] = keys->addrs.v4addrs.dst;
- req->dst_ipaddr_mask[0] = cpu_to_be32(0xffffffff);
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) {
+ req->src_ipaddr[0] = keys->addrs.v4addrs.src;
+ req->src_ipaddr_mask[0] = cpu_to_be32(0xffffffff);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) {
+ req->dst_ipaddr[0] = keys->addrs.v4addrs.dst;
+ req->dst_ipaddr_mask[0] = cpu_to_be32(0xffffffff);
+ }
}
if (keys->control.flags & FLOW_DIS_ENCAPSULATION) {
req->enables |= cpu_to_le32(BNXT_NTP_TUNNEL_FLTR_FLAG);
@@ -5104,80 +5713,85 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL;
}
- req->src_port = keys->ports.src;
- req->src_port_mask = cpu_to_be16(0xffff);
- req->dst_port = keys->ports.dst;
- req->dst_port_mask = cpu_to_be16(0xffff);
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) {
+ req->src_port = keys->ports.src;
+ req->src_port_mask = cpu_to_be16(0xffff);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) {
+ req->dst_port = keys->ports.dst;
+ req->dst_port_mask = cpu_to_be16(0xffff);
+ }
resp = hwrm_req_hold(bp, req);
rc = hwrm_req_send(bp, req);
if (!rc)
- fltr->filter_id = resp->ntuple_filter_id;
+ fltr->base.filter_id = resp->ntuple_filter_id;
hwrm_req_drop(bp, req);
return rc;
}
-#endif
static int bnxt_hwrm_set_vnic_filter(struct bnxt *bp, u16 vnic_id, u16 idx,
const u8 *mac_addr)
{
- struct hwrm_cfa_l2_filter_alloc_output *resp;
- struct hwrm_cfa_l2_filter_alloc_input *req;
+ struct bnxt_l2_filter *fltr;
+ struct bnxt_l2_key key;
int rc;
- rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_ALLOC);
- if (rc)
- return rc;
-
- req->flags = cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX);
- if (!BNXT_CHIP_TYPE_NITRO_A0(bp))
- req->flags |=
- cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST);
- req->dst_id = cpu_to_le16(bp->vnic_info[vnic_id].fw_vnic_id);
- req->enables =
- cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR |
- CFA_L2_FILTER_ALLOC_REQ_ENABLES_DST_ID |
- CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK);
- memcpy(req->l2_addr, mac_addr, ETH_ALEN);
- req->l2_addr_mask[0] = 0xff;
- req->l2_addr_mask[1] = 0xff;
- req->l2_addr_mask[2] = 0xff;
- req->l2_addr_mask[3] = 0xff;
- req->l2_addr_mask[4] = 0xff;
- req->l2_addr_mask[5] = 0xff;
+ ether_addr_copy(key.dst_mac_addr, mac_addr);
+ key.vlan = 0;
+ fltr = bnxt_alloc_l2_filter(bp, &key, GFP_KERNEL);
+ if (IS_ERR(fltr))
+ return PTR_ERR(fltr);
- resp = hwrm_req_hold(bp, req);
- rc = hwrm_req_send(bp, req);
- if (!rc)
- bp->vnic_info[vnic_id].fw_l2_filter_id[idx] =
- resp->l2_filter_id;
- hwrm_req_drop(bp, req);
+ fltr->base.fw_vnic_id = bp->vnic_info[vnic_id].fw_vnic_id;
+ rc = bnxt_hwrm_l2_filter_alloc(bp, fltr);
+ if (rc)
+ bnxt_del_l2_filter(bp, fltr);
+ else
+ bp->vnic_info[vnic_id].l2_filters[idx] = fltr;
return rc;
}
-static int bnxt_hwrm_clear_vnic_filter(struct bnxt *bp)
+static void bnxt_hwrm_clear_vnic_filter(struct bnxt *bp)
{
- struct hwrm_cfa_l2_filter_free_input *req;
u16 i, j, num_of_vnics = 1; /* only vnic 0 supported */
- int rc;
/* Any associated ntuple filters will also be cleared by firmware. */
- rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_FREE);
- if (rc)
- return rc;
- hwrm_req_hold(bp, req);
for (i = 0; i < num_of_vnics; i++) {
struct bnxt_vnic_info *vnic = &bp->vnic_info[i];
for (j = 0; j < vnic->uc_filter_count; j++) {
- req->l2_filter_id = vnic->fw_l2_filter_id[j];
+ struct bnxt_l2_filter *fltr = vnic->l2_filters[j];
- rc = hwrm_req_send(bp, req);
+ bnxt_hwrm_l2_filter_free(bp, fltr);
+ bnxt_del_l2_filter(bp, fltr);
}
vnic->uc_filter_count = 0;
}
- hwrm_req_drop(bp, req);
- return rc;
+}
+
+#define BNXT_DFLT_TUNL_TPA_BMAP \
+ (VNIC_TPA_CFG_REQ_TNL_TPA_EN_BITMAP_GRE | \
+ VNIC_TPA_CFG_REQ_TNL_TPA_EN_BITMAP_IPV4 | \
+ VNIC_TPA_CFG_REQ_TNL_TPA_EN_BITMAP_IPV6)
+
+static void bnxt_hwrm_vnic_update_tunl_tpa(struct bnxt *bp,
+ struct hwrm_vnic_tpa_cfg_input *req)
+{
+ u32 tunl_tpa_bmap = BNXT_DFLT_TUNL_TPA_BMAP;
+
+ if (!(bp->fw_cap & BNXT_FW_CAP_VNIC_TUNNEL_TPA))
+ return;
+
+ if (bp->vxlan_port)
+ tunl_tpa_bmap |= VNIC_TPA_CFG_REQ_TNL_TPA_EN_BITMAP_VXLAN;
+ if (bp->vxlan_gpe_port)
+ tunl_tpa_bmap |= VNIC_TPA_CFG_REQ_TNL_TPA_EN_BITMAP_VXLAN_GPE;
+ if (bp->nge_port)
+ tunl_tpa_bmap |= VNIC_TPA_CFG_REQ_TNL_TPA_EN_BITMAP_GENEVE;
+
+ req->enables |= cpu_to_le32(VNIC_TPA_CFG_REQ_ENABLES_TNL_TPA_EN);
+ req->tnl_tpa_en_bitmap = cpu_to_le32(tunl_tpa_bmap);
}
static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags)
@@ -5226,7 +5840,7 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags)
nsegs = (MAX_SKB_FRAGS - n) / n;
}
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
segs = MAX_TPA_SEGS_P5;
max_aggs = bp->max_tpa;
} else {
@@ -5236,6 +5850,7 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags)
req->max_aggs = cpu_to_le16(max_aggs);
req->min_agg_len = cpu_to_le32(512);
+ bnxt_hwrm_vnic_update_tunl_tpa(bp, req);
}
req->vnic_id = cpu_to_le16(vnic->fw_vnic_id);
@@ -5252,35 +5867,25 @@ static u16 bnxt_cp_ring_from_grp(struct bnxt *bp, struct bnxt_ring_struct *ring)
static u16 bnxt_cp_ring_for_rx(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- struct bnxt_napi *bnapi = rxr->bnapi;
- struct bnxt_cp_ring_info *cpr;
-
- cpr = bnapi->cp_ring.cp_ring_arr[BNXT_RX_HDL];
- return cpr->cp_ring_struct.fw_ring_id;
- } else {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
+ return rxr->rx_cpr->cp_ring_struct.fw_ring_id;
+ else
return bnxt_cp_ring_from_grp(bp, &rxr->rx_ring_struct);
- }
}
static u16 bnxt_cp_ring_for_tx(struct bnxt *bp, struct bnxt_tx_ring_info *txr)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- struct bnxt_napi *bnapi = txr->bnapi;
- struct bnxt_cp_ring_info *cpr;
-
- cpr = bnapi->cp_ring.cp_ring_arr[BNXT_TX_HDL];
- return cpr->cp_ring_struct.fw_ring_id;
- } else {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
+ return txr->tx_cpr->cp_ring_struct.fw_ring_id;
+ else
return bnxt_cp_ring_from_grp(bp, &txr->tx_ring_struct);
- }
}
static int bnxt_alloc_rss_indir_tbl(struct bnxt *bp)
{
int entries;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
entries = BNXT_MAX_RSS_TABLE_ENTRIES_P5;
else
entries = HW_HASH_INDEX_SIZE;
@@ -5330,8 +5935,12 @@ static u16 bnxt_get_max_rss_ring(struct bnxt *bp)
int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5)
- return DIV_ROUND_UP(rx_rings, BNXT_RSS_TABLE_ENTRIES_P5);
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ if (!rx_rings)
+ return 0;
+ return bnxt_calc_nr_ring_pages(rx_rings - 1,
+ BNXT_RSS_TABLE_ENTRIES_P5);
+ }
if (BNXT_CHIP_TYPE_NITRO_A0(bp))
return 2;
return 1;
@@ -5376,7 +5985,7 @@ static void
__bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req,
struct bnxt_vnic_info *vnic)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
bnxt_fill_hw_rss_tbl_p5(bp, vnic);
else
bnxt_fill_hw_rss_tbl(bp, vnic);
@@ -5401,7 +6010,7 @@ static int bnxt_hwrm_vnic_set_rss(struct bnxt *bp, u16 vnic_id, bool set_rss)
struct hwrm_vnic_rss_cfg_input *req;
int rc;
- if ((bp->flags & BNXT_FLAG_CHIP_P5) ||
+ if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) ||
vnic->fw_rss_cos_lb_ctx[0] == INVALID_HW_RING_ID)
return 0;
@@ -5566,7 +6175,7 @@ int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id)
if (rc)
return rc;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
struct bnxt_rx_ring_info *rxr = &bp->rx_ring[0];
req->default_rx_ring_id =
@@ -5666,7 +6275,7 @@ static int bnxt_hwrm_vnic_alloc(struct bnxt *bp, u16 vnic_id,
if (rc)
return rc;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
goto vnic_no_ring_grps;
/* map ring groups to this vnic */
@@ -5701,7 +6310,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp)
int rc;
bp->hw_ring_stats_size = sizeof(struct ctx_hw_stats);
- bp->flags &= ~(BNXT_FLAG_NEW_RSS_CAP | BNXT_FLAG_ROCE_MIRROR_CAP);
+ bp->flags &= ~BNXT_FLAG_ROCE_MIRROR_CAP;
+ bp->rss_cap &= ~BNXT_RSS_CAP_NEW_RSS_CAP;
if (bp->hwrm_spec_code < 0x10600)
return 0;
@@ -5714,9 +6324,9 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp)
if (!rc) {
u32 flags = le32_to_cpu(resp->flags);
- if (!(bp->flags & BNXT_FLAG_CHIP_P5) &&
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
(flags & VNIC_QCAPS_RESP_FLAGS_RSS_DFLT_CR_CAP))
- bp->flags |= BNXT_FLAG_NEW_RSS_CAP;
+ bp->rss_cap |= BNXT_RSS_CAP_NEW_RSS_CAP;
if (flags &
VNIC_QCAPS_RESP_FLAGS_ROCE_MIRRORING_CAPABLE_VNIC_CAP)
bp->flags |= BNXT_FLAG_ROCE_MIRROR_CAP;
@@ -5725,18 +6335,22 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp)
* VLAN_STRIP_CAP properly.
*/
if ((flags & VNIC_QCAPS_RESP_FLAGS_VLAN_STRIP_CAP) ||
- (BNXT_CHIP_P5_THOR(bp) &&
+ (BNXT_CHIP_P5(bp) &&
!(bp->fw_cap & BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED)))
bp->fw_cap |= BNXT_FW_CAP_VLAN_RX_STRIP;
if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_HASH_TYPE_DELTA_CAP)
- bp->fw_cap |= BNXT_FW_CAP_RSS_HASH_TYPE_DELTA;
+ bp->rss_cap |= BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA;
+ if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_PROF_TCAM_MODE_ENABLED)
+ bp->rss_cap |= BNXT_RSS_CAP_RSS_TCAM;
bp->max_tpa_v2 = le16_to_cpu(resp->max_aggs_supported);
if (bp->max_tpa_v2) {
- if (BNXT_CHIP_P5_THOR(bp))
+ if (BNXT_CHIP_P5(bp))
bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P5;
else
- bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P5_SR2;
+ bp->hw_ring_stats_size = BNXT_RING_STATS_SIZE_P7;
}
+ if (flags & VNIC_QCAPS_RESP_FLAGS_HW_TUNNEL_TPA_CAP)
+ bp->fw_cap |= BNXT_FW_CAP_VNIC_TUNNEL_TPA;
}
hwrm_req_drop(bp, req);
return rc;
@@ -5749,7 +6363,7 @@ static int bnxt_hwrm_ring_grp_alloc(struct bnxt *bp)
int rc;
u16 i;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return 0;
rc = hwrm_req_init(bp, req, HWRM_RING_GRP_ALLOC);
@@ -5782,7 +6396,7 @@ static void bnxt_hwrm_ring_grp_free(struct bnxt *bp)
struct hwrm_ring_grp_free_input *req;
u16 i;
- if (!bp->grp_info || (bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!bp->grp_info || (bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
return;
if (hwrm_req_init(bp, req, HWRM_RING_GRP_FREE))
@@ -5842,12 +6456,15 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
req->length = cpu_to_le32(bp->tx_ring_mask + 1);
req->stat_ctx_id = cpu_to_le32(grp_info->fw_stats_ctx);
req->queue_id = cpu_to_le16(ring->queue_id);
+ if (bp->flags & BNXT_FLAG_TX_COAL_CMPL)
+ req->cmpl_coal_cnt =
+ RING_ALLOC_REQ_CMPL_COAL_CNT_COAL_64;
break;
}
case HWRM_RING_ALLOC_RX:
req->ring_type = RING_ALLOC_REQ_RING_TYPE_RX;
req->length = cpu_to_le32(bp->rx_ring_mask + 1);
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
u16 flags = 0;
/* Association of rx ring with stats context */
@@ -5862,7 +6479,7 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
}
break;
case HWRM_RING_ALLOC_AGG:
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
req->ring_type = RING_ALLOC_REQ_RING_TYPE_RX_AGG;
/* Association of agg ring with rx ring */
grp_info = &bp->grp_info[ring->grp_idx];
@@ -5880,7 +6497,7 @@ static int hwrm_ring_alloc_send_msg(struct bnxt *bp,
case HWRM_RING_ALLOC_CMPL:
req->ring_type = RING_ALLOC_REQ_RING_TYPE_L2_CMPL;
req->length = cpu_to_le32(bp->cp_ring_mask + 1);
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
/* Association of cp ring with nq */
grp_info = &bp->grp_info[map_index];
req->nq_ring_id = cpu_to_le16(grp_info->cp_fw_ring_id);
@@ -5948,14 +6565,34 @@ static int bnxt_hwrm_set_async_event_cr(struct bnxt *bp, int idx)
}
}
+static void bnxt_set_db_mask(struct bnxt *bp, struct bnxt_db_info *db,
+ u32 ring_type)
+{
+ switch (ring_type) {
+ case HWRM_RING_ALLOC_TX:
+ db->db_ring_mask = bp->tx_ring_mask;
+ break;
+ case HWRM_RING_ALLOC_RX:
+ db->db_ring_mask = bp->rx_ring_mask;
+ break;
+ case HWRM_RING_ALLOC_AGG:
+ db->db_ring_mask = bp->rx_agg_ring_mask;
+ break;
+ case HWRM_RING_ALLOC_CMPL:
+ case HWRM_RING_ALLOC_NQ:
+ db->db_ring_mask = bp->cp_ring_mask;
+ break;
+ }
+ if (bp->flags & BNXT_FLAG_CHIP_P7) {
+ db->db_epoch_mask = db->db_ring_mask + 1;
+ db->db_epoch_shift = DBR_EPOCH_SFT - ilog2(db->db_epoch_mask);
+ }
+}
+
static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type,
u32 map_idx, u32 xid)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- if (BNXT_PF(bp))
- db->doorbell = bp->bar1 + DB_PF_OFFSET_P5;
- else
- db->doorbell = bp->bar1 + DB_VF_OFFSET_P5;
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
switch (ring_type) {
case HWRM_RING_ALLOC_TX:
db->db_key64 = DBR_PATH_L2 | DBR_TYPE_SQ;
@@ -5972,6 +6609,11 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type,
break;
}
db->db_key64 |= (u64)xid << DBR_XID_SFT;
+
+ if (bp->flags & BNXT_FLAG_CHIP_P7)
+ db->db_key64 |= DBR_VALID;
+
+ db->doorbell = bp->bar1 + bp->db_offset;
} else {
db->doorbell = bp->bar1 + map_idx * 0x80;
switch (ring_type) {
@@ -5987,6 +6629,7 @@ static void bnxt_set_db(struct bnxt *bp, struct bnxt_db_info *db, u32 ring_type,
break;
}
}
+ bnxt_set_db_mask(bp, db, ring_type);
}
static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
@@ -5995,7 +6638,7 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
int i, rc = 0;
u32 type;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
type = HWRM_RING_ALLOC_NQ;
else
type = HWRM_RING_ALLOC_CMPL;
@@ -6031,15 +6674,13 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
struct bnxt_ring_struct *ring;
u32 map_idx;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ struct bnxt_cp_ring_info *cpr2 = txr->tx_cpr;
struct bnxt_napi *bnapi = txr->bnapi;
- struct bnxt_cp_ring_info *cpr, *cpr2;
u32 type2 = HWRM_RING_ALLOC_CMPL;
- cpr = &bnapi->cp_ring;
- cpr2 = cpr->cp_ring_arr[BNXT_TX_HDL];
ring = &cpr2->cp_ring_struct;
- ring->handle = BNXT_TX_HDL;
+ ring->handle = BNXT_SET_NQ_HDL(cpr2);
map_idx = bnapi->index;
rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx);
if (rc)
@@ -6071,14 +6712,12 @@ static int bnxt_hwrm_ring_alloc(struct bnxt *bp)
if (!agg_rings)
bnxt_db_write(bp, &rxr->rx_db, rxr->rx_prod);
bp->grp_info[map_idx].rx_fw_ring_id = ring->fw_ring_id;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ struct bnxt_cp_ring_info *cpr2 = rxr->rx_cpr;
u32 type2 = HWRM_RING_ALLOC_CMPL;
- struct bnxt_cp_ring_info *cpr2;
- cpr2 = cpr->cp_ring_arr[BNXT_RX_HDL];
ring = &cpr2->cp_ring_struct;
- ring->handle = BNXT_RX_HDL;
+ ring->handle = BNXT_SET_NQ_HDL(cpr2);
rc = hwrm_ring_alloc_send_msg(bp, ring, type2, map_idx);
if (rc)
goto err_out;
@@ -6186,7 +6825,7 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
}
}
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
type = RING_FREE_REQ_RING_TYPE_RX_AGG;
else
type = RING_FREE_REQ_RING_TYPE_RX;
@@ -6213,7 +6852,7 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
*/
bnxt_disable_int_sync(bp);
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
type = RING_FREE_REQ_RING_TYPE_NQ;
else
type = RING_FREE_REQ_RING_TYPE_L2_CMPL;
@@ -6223,18 +6862,16 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
struct bnxt_ring_struct *ring;
int j;
- for (j = 0; j < 2; j++) {
- struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
+ for (j = 0; j < cpr->cp_ring_count && cpr->cp_ring_arr; j++) {
+ struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j];
- if (cpr2) {
- ring = &cpr2->cp_ring_struct;
- if (ring->fw_ring_id == INVALID_HW_RING_ID)
- continue;
- hwrm_ring_free_send_msg(bp, ring,
- RING_FREE_REQ_RING_TYPE_L2_CMPL,
- INVALID_HW_RING_ID);
- ring->fw_ring_id = INVALID_HW_RING_ID;
- }
+ ring = &cpr2->cp_ring_struct;
+ if (ring->fw_ring_id == INVALID_HW_RING_ID)
+ continue;
+ hwrm_ring_free_send_msg(bp, ring,
+ RING_FREE_REQ_RING_TYPE_L2_CMPL,
+ INVALID_HW_RING_ID);
+ ring->fw_ring_id = INVALID_HW_RING_ID;
}
ring = &cpr->cp_ring_struct;
if (ring->fw_ring_id != INVALID_HW_RING_ID) {
@@ -6246,6 +6883,8 @@ static void bnxt_hwrm_ring_free(struct bnxt *bp, bool close_path)
}
}
+static int __bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
+ bool shared);
static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
bool shared);
@@ -6282,14 +6921,16 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp)
cp = le16_to_cpu(resp->alloc_cmpl_rings);
stats = le16_to_cpu(resp->alloc_stat_ctx);
hw_resc->resv_irqs = cp;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
int rx = hw_resc->resv_rx_rings;
int tx = hw_resc->resv_tx_rings;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx >>= 1;
if (cp < (rx + tx)) {
- bnxt_trim_rings(bp, &rx, &tx, cp, false);
+ rc = __bnxt_trim_rings(bp, &rx, &tx, cp, false);
+ if (rc)
+ goto get_rings_exit;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
hw_resc->resv_rx_rings = rx;
@@ -6301,8 +6942,9 @@ static int bnxt_hwrm_get_rings(struct bnxt *bp)
hw_resc->resv_cp_rings = cp;
hw_resc->resv_stat_ctxs = stats;
}
+get_rings_exit:
hwrm_req_drop(bp, req);
- return 0;
+ return rc;
}
int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
@@ -6346,7 +6988,7 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
if (BNXT_NEW_RM(bp)) {
enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
enables |= stats ? FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_MSIX : 0;
enables |= tx_rings + ring_grps ?
FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0;
@@ -6362,16 +7004,17 @@ __bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
enables |= vnics ? FUNC_CFG_REQ_ENABLES_NUM_VNICS : 0;
req->num_rx_rings = cpu_to_le16(rx_rings);
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, ring_grps);
+
req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps);
req->num_msix = cpu_to_le16(cp_rings);
- req->num_rsscos_ctxs =
- cpu_to_le16(DIV_ROUND_UP(ring_grps, 64));
+ req->num_rsscos_ctxs = cpu_to_le16(rss_ctx);
} else {
req->num_cmpl_rings = cpu_to_le16(cp_rings);
req->num_hw_ring_grps = cpu_to_le16(ring_grps);
req->num_rsscos_ctxs = cpu_to_le16(1);
- if (!(bp->flags & BNXT_FLAG_NEW_RSS_CAP) &&
+ if (!(bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP) &&
bnxt_rfs_supported(bp))
req->num_rsscos_ctxs =
cpu_to_le16(ring_grps + 1);
@@ -6397,7 +7040,7 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS |
FUNC_VF_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS : 0;
enables |= stats ? FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
enables |= tx_rings + ring_grps ?
FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS : 0;
} else {
@@ -6412,9 +7055,11 @@ __bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
req->num_l2_ctxs = cpu_to_le16(BNXT_VF_MAX_L2_CTX);
req->num_tx_rings = cpu_to_le16(tx_rings);
req->num_rx_rings = cpu_to_le16(rx_rings);
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ u16 rss_ctx = bnxt_get_nr_rss_ctxs(bp, ring_grps);
+
req->num_cmpl_rings = cpu_to_le16(tx_rings + ring_grps);
- req->num_rsscos_ctxs = cpu_to_le16(DIV_ROUND_UP(ring_grps, 64));
+ req->num_rsscos_ctxs = cpu_to_le16(rss_ctx);
} else {
req->num_cmpl_rings = cpu_to_le16(cp_rings);
req->num_hw_ring_grps = cpu_to_le16(ring_grps);
@@ -6508,7 +7153,7 @@ static int bnxt_cp_rings_in_use(struct bnxt *bp)
{
int cp;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
return bnxt_nq_rings_in_use(bp);
cp = bp->tx_nr_rings + bp->rx_nr_rings;
@@ -6565,7 +7210,8 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp)
bnxt_check_rss_tbl_no_rmgr(bp);
return false;
}
- if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5))
+ if ((bp->flags & BNXT_FLAG_RFS) &&
+ !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
vnic = rx + 1;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
@@ -6573,9 +7219,9 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp)
if (hw_resc->resv_rx_rings != rx || hw_resc->resv_cp_rings != cp ||
hw_resc->resv_vnics != vnic || hw_resc->resv_stat_ctxs != stat ||
(hw_resc->resv_hw_ring_grps != grp &&
- !(bp->flags & BNXT_FLAG_CHIP_P5)))
+ !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)))
return true;
- if ((bp->flags & BNXT_FLAG_CHIP_P5) && BNXT_PF(bp) &&
+ if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) && BNXT_PF(bp) &&
hw_resc->resv_irqs != nq)
return true;
return false;
@@ -6590,13 +7236,15 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
int grp, rx_rings, rc;
int vnic = 1, stat;
bool sh = false;
+ int tx_cp;
if (!bnxt_need_reserve_rings(bp))
return 0;
if (bp->flags & BNXT_FLAG_SHARED_RINGS)
sh = true;
- if ((bp->flags & BNXT_FLAG_RFS) && !(bp->flags & BNXT_FLAG_CHIP_P5))
+ if ((bp->flags & BNXT_FLAG_RFS) &&
+ !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
vnic = rx + 1;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx <<= 1;
@@ -6639,7 +7287,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
rc = bnxt_trim_rings(bp, &rx_rings, &tx, cp, sh);
if (bp->flags & BNXT_FLAG_AGG_RINGS)
rx = rx_rings << 1;
- cp = sh ? max_t(int, tx, rx_rings) : tx + rx_rings;
+ tx_cp = bnxt_num_tx_to_cp(bp, tx);
+ cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings;
bp->tx_nr_rings = tx;
/* If we cannot reserve all the RX rings, reset the RSS map only
@@ -6686,7 +7335,7 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
FUNC_VF_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST |
FUNC_VF_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
flags |= FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST;
req->flags = cpu_to_le32(flags);
@@ -6708,7 +7357,7 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
FUNC_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
flags |= FUNC_CFG_REQ_FLAGS_RSSCOS_CTX_ASSETS_TEST |
FUNC_CFG_REQ_FLAGS_NQ_ASSETS_TEST;
else
@@ -6902,10 +7551,40 @@ int bnxt_hwrm_set_ring_coal(struct bnxt *bp, struct bnxt_napi *bnapi)
return hwrm_req_send(bp, req_rx);
}
+static int
+bnxt_hwrm_set_rx_coal(struct bnxt *bp, struct bnxt_napi *bnapi,
+ struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
+{
+ u16 ring_id = bnxt_cp_ring_for_rx(bp, bnapi->rx_ring);
+
+ req->ring_id = cpu_to_le16(ring_id);
+ return hwrm_req_send(bp, req);
+}
+
+static int
+bnxt_hwrm_set_tx_coal(struct bnxt *bp, struct bnxt_napi *bnapi,
+ struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req)
+{
+ struct bnxt_tx_ring_info *txr;
+ int i, rc;
+
+ bnxt_for_each_napi_tx(i, bnapi, txr) {
+ u16 ring_id;
+
+ ring_id = bnxt_cp_ring_for_tx(bp, txr);
+ req->ring_id = cpu_to_le16(ring_id);
+ rc = hwrm_req_send(bp, req);
+ if (rc)
+ return rc;
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
+ return 0;
+ }
+ return 0;
+}
+
int bnxt_hwrm_set_coal(struct bnxt *bp)
{
- struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req_rx, *req_tx,
- *req;
+ struct hwrm_ring_cmpl_ring_cfg_aggint_params_input *req_rx, *req_tx;
int i, rc;
rc = hwrm_req_init(bp, req_rx, HWRM_RING_CMPL_RING_CFG_AGGINT_PARAMS);
@@ -6926,29 +7605,19 @@ int bnxt_hwrm_set_coal(struct bnxt *bp)
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_coal *hw_coal;
- u16 ring_id;
-
- req = req_rx;
- if (!bnapi->rx_ring) {
- ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring);
- req = req_tx;
- } else {
- ring_id = bnxt_cp_ring_for_rx(bp, bnapi->rx_ring);
- }
- req->ring_id = cpu_to_le16(ring_id);
- rc = hwrm_req_send(bp, req);
+ if (!bnapi->rx_ring)
+ rc = bnxt_hwrm_set_tx_coal(bp, bnapi, req_tx);
+ else
+ rc = bnxt_hwrm_set_rx_coal(bp, bnapi, req_rx);
if (rc)
break;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
continue;
- if (bnapi->rx_ring && bnapi->tx_ring) {
- req = req_tx;
- ring_id = bnxt_cp_ring_for_tx(bp, bnapi->tx_ring);
- req->ring_id = cpu_to_le16(ring_id);
- rc = hwrm_req_send(bp, req);
+ if (bnapi->rx_ring && bnapi->tx_ring[0]) {
+ rc = bnxt_hwrm_set_tx_coal(bp, bnapi, req_tx);
if (rc)
break;
}
@@ -7044,7 +7713,6 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
{
struct hwrm_func_qcfg_output *resp;
struct hwrm_func_qcfg_input *req;
- u32 min_db_offset = 0;
u16 flags;
int rc;
@@ -7102,16 +7770,17 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
if (bp->db_size)
goto func_qcfg_exit;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ bp->db_offset = le16_to_cpu(resp->legacy_l2_db_size_kb) * 1024;
+ if (BNXT_CHIP_P5(bp)) {
if (BNXT_PF(bp))
- min_db_offset = DB_PF_OFFSET_P5;
+ bp->db_offset = DB_PF_OFFSET_P5;
else
- min_db_offset = DB_VF_OFFSET_P5;
+ bp->db_offset = DB_VF_OFFSET_P5;
}
bp->db_size = PAGE_ALIGN(le16_to_cpu(resp->l2_doorbell_bar_size_kb) *
1024);
if (!bp->db_size || bp->db_size > pci_resource_len(bp->pdev, 2) ||
- bp->db_size <= min_db_offset)
+ bp->db_size <= bp->db_offset)
bp->db_size = pci_resource_len(bp->pdev, 2);
func_qcfg_exit:
@@ -7119,37 +7788,99 @@ func_qcfg_exit:
return rc;
}
-static void bnxt_init_ctx_initializer(struct bnxt_ctx_mem_info *ctx,
- struct hwrm_func_backing_store_qcaps_output *resp)
+static void bnxt_init_ctx_initializer(struct bnxt_ctx_mem_type *ctxm,
+ u8 init_val, u8 init_offset,
+ bool init_mask_set)
{
- struct bnxt_mem_init *mem_init;
- u16 init_mask;
- u8 init_val;
- u8 *offset;
- int i;
+ ctxm->init_value = init_val;
+ ctxm->init_offset = BNXT_CTX_INIT_INVALID_OFFSET;
+ if (init_mask_set)
+ ctxm->init_offset = init_offset * 4;
+ else
+ ctxm->init_value = 0;
+}
+
+static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp, int ctx_max)
+{
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+ u16 type;
+
+ for (type = 0; type < ctx_max; type++) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ int n = 1;
- init_val = resp->ctx_kind_initializer;
- init_mask = le16_to_cpu(resp->ctx_init_mask);
- offset = &resp->qp_init_offset;
- mem_init = &ctx->mem_init[BNXT_CTX_MEM_INIT_QP];
- for (i = 0; i < BNXT_CTX_MEM_INIT_MAX; i++, mem_init++, offset++) {
- mem_init->init_val = init_val;
- mem_init->offset = BNXT_MEM_INVALID_OFFSET;
- if (!init_mask)
+ if (!ctxm->max_entries)
continue;
- if (i == BNXT_CTX_MEM_INIT_STAT)
- offset = &resp->stat_init_offset;
- if (init_mask & (1 << i))
- mem_init->offset = *offset * 4;
- else
- mem_init->init_val = 0;
+
+ if (ctxm->instance_bmap)
+ n = hweight32(ctxm->instance_bmap);
+ ctxm->pg_info = kcalloc(n, sizeof(*ctxm->pg_info), GFP_KERNEL);
+ if (!ctxm->pg_info)
+ return -ENOMEM;
}
- ctx->mem_init[BNXT_CTX_MEM_INIT_QP].size = ctx->qp_entry_size;
- ctx->mem_init[BNXT_CTX_MEM_INIT_SRQ].size = ctx->srq_entry_size;
- ctx->mem_init[BNXT_CTX_MEM_INIT_CQ].size = ctx->cq_entry_size;
- ctx->mem_init[BNXT_CTX_MEM_INIT_VNIC].size = ctx->vnic_entry_size;
- ctx->mem_init[BNXT_CTX_MEM_INIT_STAT].size = ctx->stat_entry_size;
- ctx->mem_init[BNXT_CTX_MEM_INIT_MRAV].size = ctx->mrav_entry_size;
+ return 0;
+}
+
+#define BNXT_CTX_INIT_VALID(flags) \
+ (!!((flags) & \
+ FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_ENABLE_CTX_KIND_INIT))
+
+static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp)
+{
+ struct hwrm_func_backing_store_qcaps_v2_output *resp;
+ struct hwrm_func_backing_store_qcaps_v2_input *req;
+ struct bnxt_ctx_mem_info *ctx;
+ u16 type;
+ int rc;
+
+ rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2);
+ if (rc)
+ return rc;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ bp->ctx = ctx;
+
+ resp = hwrm_req_hold(bp, req);
+
+ for (type = 0; type < BNXT_CTX_V2_MAX; ) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ u8 init_val, init_off, i;
+ __le32 *p;
+ u32 flags;
+
+ req->type = cpu_to_le16(type);
+ rc = hwrm_req_send(bp, req);
+ if (rc)
+ goto ctx_done;
+ flags = le32_to_cpu(resp->flags);
+ type = le16_to_cpu(resp->next_valid_type);
+ if (!(flags & FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID))
+ continue;
+
+ ctxm->type = le16_to_cpu(resp->type);
+ ctxm->entry_size = le16_to_cpu(resp->entry_size);
+ ctxm->flags = flags;
+ ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map);
+ ctxm->entry_multiple = resp->entry_multiple;
+ ctxm->max_entries = le32_to_cpu(resp->max_num_entries);
+ ctxm->min_entries = le32_to_cpu(resp->min_num_entries);
+ init_val = resp->ctx_init_value;
+ init_off = resp->ctx_init_offset;
+ bnxt_init_ctx_initializer(ctxm, init_val, init_off,
+ BNXT_CTX_INIT_VALID(flags));
+ ctxm->split_entry_cnt = min_t(u8, resp->subtype_valid_cnt,
+ BNXT_MAX_SPLIT_ENTRY);
+ for (i = 0, p = &resp->split_entry_0; i < ctxm->split_entry_cnt;
+ i++, p++)
+ ctxm->split[i] = le32_to_cpu(*p);
+ }
+ rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_V2_MAX);
+
+ctx_done:
+ hwrm_req_drop(bp, req);
+ return rc;
}
static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp)
@@ -7161,6 +7892,9 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp)
if (bp->hwrm_spec_code < 0x10902 || BNXT_VF(bp) || bp->ctx)
return 0;
+ if (bp->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2)
+ return bnxt_hwrm_func_backing_store_qcaps_v2(bp);
+
rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS);
if (rc)
return rc;
@@ -7168,48 +7902,84 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp)
resp = hwrm_req_hold(bp, req);
rc = hwrm_req_send_silent(bp, req);
if (!rc) {
- struct bnxt_ctx_pg_info *ctx_pg;
+ struct bnxt_ctx_mem_type *ctxm;
struct bnxt_ctx_mem_info *ctx;
- int i, tqm_rings;
+ u8 init_val, init_idx = 0;
+ u16 init_mask;
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = bp->ctx;
if (!ctx) {
- rc = -ENOMEM;
- goto ctx_err;
- }
- ctx->qp_max_entries = le32_to_cpu(resp->qp_max_entries);
- ctx->qp_min_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries);
- ctx->qp_max_l2_entries = le16_to_cpu(resp->qp_max_l2_entries);
- ctx->qp_entry_size = le16_to_cpu(resp->qp_entry_size);
- ctx->srq_max_l2_entries = le16_to_cpu(resp->srq_max_l2_entries);
- ctx->srq_max_entries = le32_to_cpu(resp->srq_max_entries);
- ctx->srq_entry_size = le16_to_cpu(resp->srq_entry_size);
- ctx->cq_max_l2_entries = le16_to_cpu(resp->cq_max_l2_entries);
- ctx->cq_max_entries = le32_to_cpu(resp->cq_max_entries);
- ctx->cq_entry_size = le16_to_cpu(resp->cq_entry_size);
- ctx->vnic_max_vnic_entries =
- le16_to_cpu(resp->vnic_max_vnic_entries);
- ctx->vnic_max_ring_table_entries =
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto ctx_err;
+ }
+ bp->ctx = ctx;
+ }
+ init_val = resp->ctx_kind_initializer;
+ init_mask = le16_to_cpu(resp->ctx_init_mask);
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_QP];
+ ctxm->max_entries = le32_to_cpu(resp->qp_max_entries);
+ ctxm->qp_qp1_entries = le16_to_cpu(resp->qp_min_qp1_entries);
+ ctxm->qp_l2_entries = le16_to_cpu(resp->qp_max_l2_entries);
+ ctxm->qp_fast_qpmd_entries = le16_to_cpu(resp->fast_qpmd_qp_num_entries);
+ ctxm->entry_size = le16_to_cpu(resp->qp_entry_size);
+ bnxt_init_ctx_initializer(ctxm, init_val, resp->qp_init_offset,
+ (init_mask & (1 << init_idx++)) != 0);
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ];
+ ctxm->srq_l2_entries = le16_to_cpu(resp->srq_max_l2_entries);
+ ctxm->max_entries = le32_to_cpu(resp->srq_max_entries);
+ ctxm->entry_size = le16_to_cpu(resp->srq_entry_size);
+ bnxt_init_ctx_initializer(ctxm, init_val, resp->srq_init_offset,
+ (init_mask & (1 << init_idx++)) != 0);
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_CQ];
+ ctxm->cq_l2_entries = le16_to_cpu(resp->cq_max_l2_entries);
+ ctxm->max_entries = le32_to_cpu(resp->cq_max_entries);
+ ctxm->entry_size = le16_to_cpu(resp->cq_entry_size);
+ bnxt_init_ctx_initializer(ctxm, init_val, resp->cq_init_offset,
+ (init_mask & (1 << init_idx++)) != 0);
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC];
+ ctxm->vnic_entries = le16_to_cpu(resp->vnic_max_vnic_entries);
+ ctxm->max_entries = ctxm->vnic_entries +
le16_to_cpu(resp->vnic_max_ring_table_entries);
- ctx->vnic_entry_size = le16_to_cpu(resp->vnic_entry_size);
- ctx->stat_max_entries = le32_to_cpu(resp->stat_max_entries);
- ctx->stat_entry_size = le16_to_cpu(resp->stat_entry_size);
- ctx->tqm_entry_size = le16_to_cpu(resp->tqm_entry_size);
- ctx->tqm_min_entries_per_ring =
- le32_to_cpu(resp->tqm_min_entries_per_ring);
- ctx->tqm_max_entries_per_ring =
- le32_to_cpu(resp->tqm_max_entries_per_ring);
- ctx->tqm_entries_multiple = resp->tqm_entries_multiple;
- if (!ctx->tqm_entries_multiple)
- ctx->tqm_entries_multiple = 1;
- ctx->mrav_max_entries = le32_to_cpu(resp->mrav_max_entries);
- ctx->mrav_entry_size = le16_to_cpu(resp->mrav_entry_size);
- ctx->mrav_num_entries_units =
+ ctxm->entry_size = le16_to_cpu(resp->vnic_entry_size);
+ bnxt_init_ctx_initializer(ctxm, init_val,
+ resp->vnic_init_offset,
+ (init_mask & (1 << init_idx++)) != 0);
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_STAT];
+ ctxm->max_entries = le32_to_cpu(resp->stat_max_entries);
+ ctxm->entry_size = le16_to_cpu(resp->stat_entry_size);
+ bnxt_init_ctx_initializer(ctxm, init_val,
+ resp->stat_init_offset,
+ (init_mask & (1 << init_idx++)) != 0);
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_STQM];
+ ctxm->entry_size = le16_to_cpu(resp->tqm_entry_size);
+ ctxm->min_entries = le32_to_cpu(resp->tqm_min_entries_per_ring);
+ ctxm->max_entries = le32_to_cpu(resp->tqm_max_entries_per_ring);
+ ctxm->entry_multiple = resp->tqm_entries_multiple;
+ if (!ctxm->entry_multiple)
+ ctxm->entry_multiple = 1;
+
+ memcpy(&ctx->ctx_arr[BNXT_CTX_FTQM], ctxm, sizeof(*ctxm));
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV];
+ ctxm->max_entries = le32_to_cpu(resp->mrav_max_entries);
+ ctxm->entry_size = le16_to_cpu(resp->mrav_entry_size);
+ ctxm->mrav_num_entries_units =
le16_to_cpu(resp->mrav_num_entries_units);
- ctx->tim_entry_size = le16_to_cpu(resp->tim_entry_size);
- ctx->tim_max_entries = le32_to_cpu(resp->tim_max_entries);
+ bnxt_init_ctx_initializer(ctxm, init_val,
+ resp->mrav_init_offset,
+ (init_mask & (1 << init_idx++)) != 0);
- bnxt_init_ctx_initializer(ctx, resp);
+ ctxm = &ctx->ctx_arr[BNXT_CTX_TIM];
+ ctxm->entry_size = le16_to_cpu(resp->tim_entry_size);
+ ctxm->max_entries = le32_to_cpu(resp->tim_max_entries);
ctx->tqm_fp_rings_count = resp->tqm_fp_rings_count;
if (!ctx->tqm_fp_rings_count)
@@ -7217,16 +7987,11 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp)
else if (ctx->tqm_fp_rings_count > BNXT_MAX_TQM_FP_RINGS)
ctx->tqm_fp_rings_count = BNXT_MAX_TQM_FP_RINGS;
- tqm_rings = ctx->tqm_fp_rings_count + BNXT_MAX_TQM_SP_RINGS;
- ctx_pg = kcalloc(tqm_rings, sizeof(*ctx_pg), GFP_KERNEL);
- if (!ctx_pg) {
- kfree(ctx);
- rc = -ENOMEM;
- goto ctx_err;
- }
- for (i = 0; i < tqm_rings; i++, ctx_pg++)
- ctx->tqm_mem[i] = ctx_pg;
- bp->ctx = ctx;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_FTQM];
+ memcpy(ctxm, &ctx->ctx_arr[BNXT_CTX_STQM], sizeof(*ctxm));
+ ctxm->instance_bmap = (1 << ctx->tqm_fp_rings_count) - 1;
+
+ rc = bnxt_alloc_all_ctx_pg_info(bp, BNXT_CTX_MAX);
} else {
rc = 0;
}
@@ -7265,6 +8030,7 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables)
struct hwrm_func_backing_store_cfg_input *req;
struct bnxt_ctx_mem_info *ctx = bp->ctx;
struct bnxt_ctx_pg_info *ctx_pg;
+ struct bnxt_ctx_mem_type *ctxm;
void **__req = (void **)&req;
u32 req_len = sizeof(*req);
__le32 *num_entries;
@@ -7286,82 +8052,102 @@ static int bnxt_hwrm_func_backing_store_cfg(struct bnxt *bp, u32 enables)
req->enables = cpu_to_le32(enables);
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP) {
- ctx_pg = &ctx->qp_mem;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_QP];
+ ctx_pg = ctxm->pg_info;
req->qp_num_entries = cpu_to_le32(ctx_pg->entries);
- req->qp_num_qp1_entries = cpu_to_le16(ctx->qp_min_qp1_entries);
- req->qp_num_l2_entries = cpu_to_le16(ctx->qp_max_l2_entries);
- req->qp_entry_size = cpu_to_le16(ctx->qp_entry_size);
+ req->qp_num_qp1_entries = cpu_to_le16(ctxm->qp_qp1_entries);
+ req->qp_num_l2_entries = cpu_to_le16(ctxm->qp_l2_entries);
+ req->qp_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->qpc_pg_size_qpc_lvl,
&req->qpc_page_dir);
+
+ if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP_FAST_QPMD)
+ req->qp_num_fast_qpmd_entries = cpu_to_le16(ctxm->qp_fast_qpmd_entries);
}
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_SRQ) {
- ctx_pg = &ctx->srq_mem;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ];
+ ctx_pg = ctxm->pg_info;
req->srq_num_entries = cpu_to_le32(ctx_pg->entries);
- req->srq_num_l2_entries = cpu_to_le16(ctx->srq_max_l2_entries);
- req->srq_entry_size = cpu_to_le16(ctx->srq_entry_size);
+ req->srq_num_l2_entries = cpu_to_le16(ctxm->srq_l2_entries);
+ req->srq_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->srq_pg_size_srq_lvl,
&req->srq_page_dir);
}
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_CQ) {
- ctx_pg = &ctx->cq_mem;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_CQ];
+ ctx_pg = ctxm->pg_info;
req->cq_num_entries = cpu_to_le32(ctx_pg->entries);
- req->cq_num_l2_entries = cpu_to_le16(ctx->cq_max_l2_entries);
- req->cq_entry_size = cpu_to_le16(ctx->cq_entry_size);
+ req->cq_num_l2_entries = cpu_to_le16(ctxm->cq_l2_entries);
+ req->cq_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->cq_pg_size_cq_lvl,
&req->cq_page_dir);
}
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_VNIC) {
- ctx_pg = &ctx->vnic_mem;
- req->vnic_num_vnic_entries =
- cpu_to_le16(ctx->vnic_max_vnic_entries);
+ ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC];
+ ctx_pg = ctxm->pg_info;
+ req->vnic_num_vnic_entries = cpu_to_le16(ctxm->vnic_entries);
req->vnic_num_ring_table_entries =
- cpu_to_le16(ctx->vnic_max_ring_table_entries);
- req->vnic_entry_size = cpu_to_le16(ctx->vnic_entry_size);
+ cpu_to_le16(ctxm->max_entries - ctxm->vnic_entries);
+ req->vnic_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->vnic_pg_size_vnic_lvl,
&req->vnic_page_dir);
}
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_STAT) {
- ctx_pg = &ctx->stat_mem;
- req->stat_num_entries = cpu_to_le32(ctx->stat_max_entries);
- req->stat_entry_size = cpu_to_le16(ctx->stat_entry_size);
+ ctxm = &ctx->ctx_arr[BNXT_CTX_STAT];
+ ctx_pg = ctxm->pg_info;
+ req->stat_num_entries = cpu_to_le32(ctxm->max_entries);
+ req->stat_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->stat_pg_size_stat_lvl,
&req->stat_page_dir);
}
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV) {
- ctx_pg = &ctx->mrav_mem;
+ u32 units;
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV];
+ ctx_pg = ctxm->pg_info;
req->mrav_num_entries = cpu_to_le32(ctx_pg->entries);
- if (ctx->mrav_num_entries_units)
- flags |=
- FUNC_BACKING_STORE_CFG_REQ_FLAGS_MRAV_RESERVATION_SPLIT;
- req->mrav_entry_size = cpu_to_le16(ctx->mrav_entry_size);
+ units = ctxm->mrav_num_entries_units;
+ if (units) {
+ u32 num_mr, num_ah = ctxm->mrav_av_entries;
+ u32 entries;
+
+ num_mr = ctx_pg->entries - num_ah;
+ entries = ((num_mr / units) << 16) | (num_ah / units);
+ req->mrav_num_entries = cpu_to_le32(entries);
+ flags |= FUNC_BACKING_STORE_CFG_REQ_FLAGS_MRAV_RESERVATION_SPLIT;
+ }
+ req->mrav_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->mrav_pg_size_mrav_lvl,
&req->mrav_page_dir);
}
if (enables & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM) {
- ctx_pg = &ctx->tim_mem;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_TIM];
+ ctx_pg = ctxm->pg_info;
req->tim_num_entries = cpu_to_le32(ctx_pg->entries);
- req->tim_entry_size = cpu_to_le16(ctx->tim_entry_size);
+ req->tim_entry_size = cpu_to_le16(ctxm->entry_size);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
&req->tim_pg_size_tim_lvl,
&req->tim_page_dir);
}
+ ctxm = &ctx->ctx_arr[BNXT_CTX_STQM];
for (i = 0, num_entries = &req->tqm_sp_num_entries,
pg_attr = &req->tqm_sp_pg_size_tqm_sp_lvl,
pg_dir = &req->tqm_sp_page_dir,
- ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP;
+ ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP,
+ ctx_pg = ctxm->pg_info;
i < BNXT_MAX_TQM_RINGS;
+ ctx_pg = &ctx->ctx_arr[BNXT_CTX_FTQM].pg_info[i],
i++, num_entries++, pg_attr++, pg_dir++, ena <<= 1) {
if (!(enables & ena))
continue;
- req->tqm_entry_size = cpu_to_le16(ctx->tqm_entry_size);
- ctx_pg = ctx->tqm_mem[i];
+ req->tqm_entry_size = cpu_to_le16(ctxm->entry_size);
*num_entries = cpu_to_le32(ctx_pg->entries);
bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem, pg_attr, pg_dir);
}
@@ -7385,7 +8171,7 @@ static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp,
static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp,
struct bnxt_ctx_pg_info *ctx_pg, u32 mem_size,
- u8 depth, struct bnxt_mem_init *mem_init)
+ u8 depth, struct bnxt_ctx_mem_type *ctxm)
{
struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem;
int rc;
@@ -7423,7 +8209,7 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp,
rmem->pg_tbl_map = ctx_pg->ctx_dma_arr[i];
rmem->depth = 1;
rmem->nr_pages = MAX_CTX_PAGES;
- rmem->mem_init = mem_init;
+ rmem->ctx_mem = ctxm;
if (i == (nr_tbls - 1)) {
int rem = ctx_pg->nr_pages % MAX_CTX_PAGES;
@@ -7438,7 +8224,7 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp,
rmem->nr_pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE);
if (rmem->nr_pages > 1 || depth)
rmem->depth = 1;
- rmem->mem_init = mem_init;
+ rmem->ctx_mem = ctxm;
rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg);
}
return rc;
@@ -7473,41 +8259,144 @@ static void bnxt_free_ctx_pg_tbls(struct bnxt *bp,
ctx_pg->nr_pages = 0;
}
+static int bnxt_setup_ctxm_pg_tbls(struct bnxt *bp,
+ struct bnxt_ctx_mem_type *ctxm, u32 entries,
+ u8 pg_lvl)
+{
+ struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
+ int i, rc = 0, n = 1;
+ u32 mem_size;
+
+ if (!ctxm->entry_size || !ctx_pg)
+ return -EINVAL;
+ if (ctxm->instance_bmap)
+ n = hweight32(ctxm->instance_bmap);
+ if (ctxm->entry_multiple)
+ entries = roundup(entries, ctxm->entry_multiple);
+ entries = clamp_t(u32, entries, ctxm->min_entries, ctxm->max_entries);
+ mem_size = entries * ctxm->entry_size;
+ for (i = 0; i < n && !rc; i++) {
+ ctx_pg[i].entries = entries;
+ rc = bnxt_alloc_ctx_pg_tbls(bp, &ctx_pg[i], mem_size, pg_lvl,
+ ctxm->init_value ? ctxm : NULL);
+ }
+ return rc;
+}
+
+static int bnxt_hwrm_func_backing_store_cfg_v2(struct bnxt *bp,
+ struct bnxt_ctx_mem_type *ctxm,
+ bool last)
+{
+ struct hwrm_func_backing_store_cfg_v2_input *req;
+ u32 instance_bmap = ctxm->instance_bmap;
+ int i, j, rc = 0, n = 1;
+ __le32 *p;
+
+ if (!(ctxm->flags & BNXT_CTX_MEM_TYPE_VALID) || !ctxm->pg_info)
+ return 0;
+
+ if (instance_bmap)
+ n = hweight32(ctxm->instance_bmap);
+ else
+ instance_bmap = 1;
+
+ rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_CFG_V2);
+ if (rc)
+ return rc;
+ hwrm_req_hold(bp, req);
+ req->type = cpu_to_le16(ctxm->type);
+ req->entry_size = cpu_to_le16(ctxm->entry_size);
+ req->subtype_valid_cnt = ctxm->split_entry_cnt;
+ for (i = 0, p = &req->split_entry_0; i < ctxm->split_entry_cnt; i++)
+ p[i] = cpu_to_le32(ctxm->split[i]);
+ for (i = 0, j = 0; j < n && !rc; i++) {
+ struct bnxt_ctx_pg_info *ctx_pg;
+
+ if (!(instance_bmap & (1 << i)))
+ continue;
+ req->instance = cpu_to_le16(i);
+ ctx_pg = &ctxm->pg_info[j++];
+ if (!ctx_pg->entries)
+ continue;
+ req->num_entries = cpu_to_le32(ctx_pg->entries);
+ bnxt_hwrm_set_pg_attr(&ctx_pg->ring_mem,
+ &req->page_size_pbl_level,
+ &req->page_dir);
+ if (last && j == n)
+ req->flags =
+ cpu_to_le32(FUNC_BACKING_STORE_CFG_V2_REQ_FLAGS_BS_CFG_ALL_DONE);
+ rc = hwrm_req_send(bp, req);
+ }
+ hwrm_req_drop(bp, req);
+ return rc;
+}
+
+static int bnxt_backing_store_cfg_v2(struct bnxt *bp, u32 ena)
+{
+ struct bnxt_ctx_mem_info *ctx = bp->ctx;
+ struct bnxt_ctx_mem_type *ctxm;
+ u16 last_type;
+ int rc = 0;
+ u16 type;
+
+ if (!ena)
+ return 0;
+ else if (ena & FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM)
+ last_type = BNXT_CTX_MAX - 1;
+ else
+ last_type = BNXT_CTX_L2_MAX - 1;
+ ctx->ctx_arr[last_type].last = 1;
+
+ for (type = 0 ; type < BNXT_CTX_V2_MAX; type++) {
+ ctxm = &ctx->ctx_arr[type];
+
+ rc = bnxt_hwrm_func_backing_store_cfg_v2(bp, ctxm, ctxm->last);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
void bnxt_free_ctx_mem(struct bnxt *bp)
{
struct bnxt_ctx_mem_info *ctx = bp->ctx;
- int i;
+ u16 type;
if (!ctx)
return;
- if (ctx->tqm_mem[0]) {
- for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++)
- bnxt_free_ctx_pg_tbls(bp, ctx->tqm_mem[i]);
- kfree(ctx->tqm_mem[0]);
- ctx->tqm_mem[0] = NULL;
+ for (type = 0; type < BNXT_CTX_V2_MAX; type++) {
+ struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type];
+ struct bnxt_ctx_pg_info *ctx_pg = ctxm->pg_info;
+ int i, n = 1;
+
+ if (!ctx_pg)
+ continue;
+ if (ctxm->instance_bmap)
+ n = hweight32(ctxm->instance_bmap);
+ for (i = 0; i < n; i++)
+ bnxt_free_ctx_pg_tbls(bp, &ctx_pg[i]);
+
+ kfree(ctx_pg);
+ ctxm->pg_info = NULL;
}
- bnxt_free_ctx_pg_tbls(bp, &ctx->tim_mem);
- bnxt_free_ctx_pg_tbls(bp, &ctx->mrav_mem);
- bnxt_free_ctx_pg_tbls(bp, &ctx->stat_mem);
- bnxt_free_ctx_pg_tbls(bp, &ctx->vnic_mem);
- bnxt_free_ctx_pg_tbls(bp, &ctx->cq_mem);
- bnxt_free_ctx_pg_tbls(bp, &ctx->srq_mem);
- bnxt_free_ctx_pg_tbls(bp, &ctx->qp_mem);
ctx->flags &= ~BNXT_CTX_FLAG_INITED;
+ kfree(ctx);
+ bp->ctx = NULL;
}
static int bnxt_alloc_ctx_mem(struct bnxt *bp)
{
- struct bnxt_ctx_pg_info *ctx_pg;
+ struct bnxt_ctx_mem_type *ctxm;
struct bnxt_ctx_mem_info *ctx;
- struct bnxt_mem_init *init;
- u32 mem_size, ena, entries;
- u32 entries_sp, min;
+ u32 l2_qps, qp1_qps, max_qps;
+ u32 ena, entries_sp, entries;
+ u32 srqs, max_srqs, min;
u32 num_mr, num_ah;
u32 extra_srqs = 0;
u32 extra_qps = 0;
+ u32 fast_qpmd_qps;
u8 pg_lvl = 1;
int i, rc;
@@ -7521,120 +8410,98 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp)
if (!ctx || (ctx->flags & BNXT_CTX_FLAG_INITED))
return 0;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_QP];
+ l2_qps = ctxm->qp_l2_entries;
+ qp1_qps = ctxm->qp_qp1_entries;
+ fast_qpmd_qps = ctxm->qp_fast_qpmd_entries;
+ max_qps = ctxm->max_entries;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ];
+ srqs = ctxm->srq_l2_entries;
+ max_srqs = ctxm->max_entries;
+ ena = 0;
if ((bp->flags & BNXT_FLAG_ROCE_CAP) && !is_kdump_kernel()) {
pg_lvl = 2;
- extra_qps = 65536;
- extra_srqs = 8192;
+ extra_qps = min_t(u32, 65536, max_qps - l2_qps - qp1_qps);
+ /* allocate extra qps if fw supports RoCE fast qp destroy feature */
+ extra_qps += fast_qpmd_qps;
+ extra_srqs = min_t(u32, 8192, max_srqs - srqs);
+ if (fast_qpmd_qps)
+ ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_QP_FAST_QPMD;
}
- ctx_pg = &ctx->qp_mem;
- ctx_pg->entries = ctx->qp_min_qp1_entries + ctx->qp_max_l2_entries +
- extra_qps;
- if (ctx->qp_entry_size) {
- mem_size = ctx->qp_entry_size * ctx_pg->entries;
- init = &ctx->mem_init[BNXT_CTX_MEM_INIT_QP];
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, init);
- if (rc)
- return rc;
- }
+ ctxm = &ctx->ctx_arr[BNXT_CTX_QP];
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, l2_qps + qp1_qps + extra_qps,
+ pg_lvl);
+ if (rc)
+ return rc;
- ctx_pg = &ctx->srq_mem;
- ctx_pg->entries = ctx->srq_max_l2_entries + extra_srqs;
- if (ctx->srq_entry_size) {
- mem_size = ctx->srq_entry_size * ctx_pg->entries;
- init = &ctx->mem_init[BNXT_CTX_MEM_INIT_SRQ];
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, init);
- if (rc)
- return rc;
- }
+ ctxm = &ctx->ctx_arr[BNXT_CTX_SRQ];
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, srqs + extra_srqs, pg_lvl);
+ if (rc)
+ return rc;
- ctx_pg = &ctx->cq_mem;
- ctx_pg->entries = ctx->cq_max_l2_entries + extra_qps * 2;
- if (ctx->cq_entry_size) {
- mem_size = ctx->cq_entry_size * ctx_pg->entries;
- init = &ctx->mem_init[BNXT_CTX_MEM_INIT_CQ];
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, init);
- if (rc)
- return rc;
- }
+ ctxm = &ctx->ctx_arr[BNXT_CTX_CQ];
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, ctxm->cq_l2_entries +
+ extra_qps * 2, pg_lvl);
+ if (rc)
+ return rc;
- ctx_pg = &ctx->vnic_mem;
- ctx_pg->entries = ctx->vnic_max_vnic_entries +
- ctx->vnic_max_ring_table_entries;
- if (ctx->vnic_entry_size) {
- mem_size = ctx->vnic_entry_size * ctx_pg->entries;
- init = &ctx->mem_init[BNXT_CTX_MEM_INIT_VNIC];
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, init);
- if (rc)
- return rc;
- }
+ ctxm = &ctx->ctx_arr[BNXT_CTX_VNIC];
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, ctxm->max_entries, 1);
+ if (rc)
+ return rc;
- ctx_pg = &ctx->stat_mem;
- ctx_pg->entries = ctx->stat_max_entries;
- if (ctx->stat_entry_size) {
- mem_size = ctx->stat_entry_size * ctx_pg->entries;
- init = &ctx->mem_init[BNXT_CTX_MEM_INIT_STAT];
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, init);
- if (rc)
- return rc;
- }
+ ctxm = &ctx->ctx_arr[BNXT_CTX_STAT];
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, ctxm->max_entries, 1);
+ if (rc)
+ return rc;
- ena = 0;
if (!(bp->flags & BNXT_FLAG_ROCE_CAP))
goto skip_rdma;
- ctx_pg = &ctx->mrav_mem;
+ ctxm = &ctx->ctx_arr[BNXT_CTX_MRAV];
/* 128K extra is needed to accommodate static AH context
* allocation by f/w.
*/
- num_mr = 1024 * 256;
- num_ah = 1024 * 128;
- ctx_pg->entries = num_mr + num_ah;
- if (ctx->mrav_entry_size) {
- mem_size = ctx->mrav_entry_size * ctx_pg->entries;
- init = &ctx->mem_init[BNXT_CTX_MEM_INIT_MRAV];
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 2, init);
- if (rc)
- return rc;
- }
- ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV;
- if (ctx->mrav_num_entries_units)
- ctx_pg->entries =
- ((num_mr / ctx->mrav_num_entries_units) << 16) |
- (num_ah / ctx->mrav_num_entries_units);
-
- ctx_pg = &ctx->tim_mem;
- ctx_pg->entries = ctx->qp_mem.entries;
- if (ctx->tim_entry_size) {
- mem_size = ctx->tim_entry_size * ctx_pg->entries;
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, NULL);
- if (rc)
- return rc;
- }
+ num_mr = min_t(u32, ctxm->max_entries / 2, 1024 * 256);
+ num_ah = min_t(u32, num_mr, 1024 * 128);
+ ctxm->split_entry_cnt = BNXT_CTX_MRAV_AV_SPLIT_ENTRY + 1;
+ if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah)
+ ctxm->mrav_av_entries = num_ah;
+
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, num_mr + num_ah, 2);
+ if (rc)
+ return rc;
+ ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV;
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_TIM];
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, l2_qps + qp1_qps + extra_qps, 1);
+ if (rc)
+ return rc;
ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM;
skip_rdma:
- min = ctx->tqm_min_entries_per_ring;
- entries_sp = ctx->vnic_max_vnic_entries + ctx->qp_max_l2_entries +
- 2 * (extra_qps + ctx->qp_min_qp1_entries) + min;
- entries_sp = roundup(entries_sp, ctx->tqm_entries_multiple);
- entries = ctx->qp_max_l2_entries + 2 * (extra_qps + ctx->qp_min_qp1_entries);
- entries = roundup(entries, ctx->tqm_entries_multiple);
- entries = clamp_t(u32, entries, min, ctx->tqm_max_entries_per_ring);
- for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++) {
- ctx_pg = ctx->tqm_mem[i];
- ctx_pg->entries = i ? entries : entries_sp;
- if (ctx->tqm_entry_size) {
- mem_size = ctx->tqm_entry_size * ctx_pg->entries;
- rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1,
- NULL);
- if (rc)
- return rc;
- }
+ ctxm = &ctx->ctx_arr[BNXT_CTX_STQM];
+ min = ctxm->min_entries;
+ entries_sp = ctx->ctx_arr[BNXT_CTX_VNIC].vnic_entries + l2_qps +
+ 2 * (extra_qps + qp1_qps) + min;
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, entries_sp, 2);
+ if (rc)
+ return rc;
+
+ ctxm = &ctx->ctx_arr[BNXT_CTX_FTQM];
+ entries = l2_qps + 2 * (extra_qps + qp1_qps);
+ rc = bnxt_setup_ctxm_pg_tbls(bp, ctxm, entries, 2);
+ if (rc)
+ return rc;
+ for (i = 0; i < ctx->tqm_fp_rings_count + 1; i++)
ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP << i;
- }
ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES;
- rc = bnxt_hwrm_func_backing_store_cfg(bp, ena);
+
+ if (bp->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2)
+ rc = bnxt_backing_store_cfg_v2(bp, ena);
+ else
+ rc = bnxt_hwrm_func_backing_store_cfg(bp, ena);
if (rc) {
netdev_err(bp->dev, "Failed configuring context mem, rc = %d.\n",
rc);
@@ -7682,7 +8549,7 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all)
hw_resc->min_stat_ctxs = le16_to_cpu(resp->min_stat_ctx);
hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
u16 max_msix = le16_to_cpu(resp->max_msix);
hw_resc->max_nqs = max_msix;
@@ -7711,7 +8578,7 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp)
u8 flags;
int rc;
- if (bp->hwrm_spec_code < 0x10801 || !BNXT_CHIP_P5_THOR(bp)) {
+ if (bp->hwrm_spec_code < 0x10801 || !BNXT_CHIP_P5(bp)) {
rc = -ENODEV;
goto no_ptp;
}
@@ -7743,7 +8610,7 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp)
if (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK) {
ptp->refclk_regs[0] = le32_to_cpu(resp->ts_ref_clock_reg_lower);
ptp->refclk_regs[1] = le32_to_cpu(resp->ts_ref_clock_reg_upper);
- } else if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ } else if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
ptp->refclk_regs[0] = BNXT_TS_REG_TIMESYNC_TS0_LOWER;
ptp->refclk_regs[1] = BNXT_TS_REG_TIMESYNC_TS0_UPPER;
} else {
@@ -7815,10 +8682,16 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF;
if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_FW_LIVEPATCH_SUPPORTED))
bp->fw_cap |= BNXT_FW_CAP_LIVEPATCH;
+ if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_BS_V2_SUPPORTED)
+ bp->fw_cap |= BNXT_FW_CAP_BACKING_STORE_V2;
+ if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_TX_COAL_CMPL_CAP)
+ bp->flags |= BNXT_FLAG_TX_COAL_CMPL;
flags_ext2 = le32_to_cpu(resp->flags_ext2);
if (flags_ext2 & FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED)
bp->fw_cap |= BNXT_FW_CAP_RX_ALL_PKT_TS;
+ if (flags_ext2 & FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED)
+ bp->flags |= BNXT_FLAG_UDP_GSO_CAP;
bp->tx_push_thresh = 0;
if ((flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED) &&
@@ -8450,7 +9323,7 @@ static void bnxt_accumulate_all_stats(struct bnxt *bp)
int i;
/* Chip bug. Counter intermittently becomes 0. */
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
ignore_zero = true;
for (i = 0; i < bp->cp_nr_rings; i++) {
@@ -8644,7 +9517,7 @@ static void bnxt_clear_vnic(struct bnxt *bp)
return;
bnxt_hwrm_clear_vnic_filter(bp);
- if (!(bp->flags & BNXT_FLAG_CHIP_P5)) {
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)) {
/* clear all RSS setting before free vnic ctx */
bnxt_hwrm_clear_vnic_rss(bp);
bnxt_hwrm_vnic_ctx_free(bp);
@@ -8653,7 +9526,7 @@ static void bnxt_clear_vnic(struct bnxt *bp)
if (bp->flags & BNXT_FLAG_TPA)
bnxt_set_tpa(bp, false);
bnxt_hwrm_vnic_free(bp);
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
bnxt_hwrm_vnic_ctx_free(bp);
}
@@ -8810,7 +9683,7 @@ static int __bnxt_setup_vnic_p5(struct bnxt *bp, u16 vnic_id)
static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return __bnxt_setup_vnic_p5(bp, vnic_id);
else
return __bnxt_setup_vnic(bp, vnic_id);
@@ -8818,10 +9691,9 @@ static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
{
-#ifdef CONFIG_RFS_ACCEL
int i, rc = 0;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return 0;
for (i = 0; i < bp->rx_nr_rings; i++) {
@@ -8834,7 +9706,7 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
vnic = &bp->vnic_info[vnic_id];
vnic->flags |= BNXT_VNIC_RFS_FLAG;
- if (bp->flags & BNXT_FLAG_NEW_RSS_CAP)
+ if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP)
vnic->flags |= BNXT_VNIC_RFS_NEW_RSS_FLAG;
rc = bnxt_hwrm_vnic_alloc(bp, vnic_id, ring_id, 1);
if (rc) {
@@ -8847,9 +9719,6 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
break;
}
return rc;
-#else
- return 0;
-#endif
}
/* Allow PF, trusted VFs and VFs with default VLAN to be in promiscuous mode */
@@ -8928,7 +9797,7 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
rc = bnxt_setup_vnic(bp, 0);
if (rc)
goto err_out;
- if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA)
+ if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA)
bnxt_hwrm_update_rss_hash_cfg(bp);
if (bp->flags & BNXT_FLAG_RFS) {
@@ -9046,8 +9915,8 @@ static int bnxt_set_real_num_queues(struct bnxt *bp)
return rc;
}
-static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
- bool shared)
+static int __bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
+ bool shared)
{
int _rx = *rx, _tx = *tx;
@@ -9070,19 +9939,59 @@ static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
return 0;
}
+static int __bnxt_num_tx_to_cp(struct bnxt *bp, int tx, int tx_sets, int tx_xdp)
+{
+ return (tx - tx_xdp) / tx_sets + tx_xdp;
+}
+
+int bnxt_num_tx_to_cp(struct bnxt *bp, int tx)
+{
+ int tcs = bp->num_tc;
+
+ if (!tcs)
+ tcs = 1;
+ return __bnxt_num_tx_to_cp(bp, tx, tcs, bp->tx_nr_rings_xdp);
+}
+
+static int bnxt_num_cp_to_tx(struct bnxt *bp, int tx_cp)
+{
+ int tcs = bp->num_tc;
+
+ return (tx_cp - bp->tx_nr_rings_xdp) * tcs +
+ bp->tx_nr_rings_xdp;
+}
+
+static int bnxt_trim_rings(struct bnxt *bp, int *rx, int *tx, int max,
+ bool sh)
+{
+ int tx_cp = bnxt_num_tx_to_cp(bp, *tx);
+
+ if (tx_cp != *tx) {
+ int tx_saved = tx_cp, rc;
+
+ rc = __bnxt_trim_rings(bp, rx, &tx_cp, max, sh);
+ if (rc)
+ return rc;
+ if (tx_cp != tx_saved)
+ *tx = bnxt_num_cp_to_tx(bp, tx_cp);
+ return 0;
+ }
+ return __bnxt_trim_rings(bp, rx, tx, max, sh);
+}
+
static void bnxt_setup_msix(struct bnxt *bp)
{
const int len = sizeof(bp->irq_tbl[0].name);
struct net_device *dev = bp->dev;
int tcs, i;
- tcs = netdev_get_num_tc(dev);
+ tcs = bp->num_tc;
if (tcs) {
int i, off, count;
for (i = 0; i < tcs; i++) {
count = bp->tx_nr_rings_per_tc;
- off = i * count;
+ off = BNXT_TC_TO_RING_BASE(bp, i);
netdev_set_tc_queue(dev, i, count, off);
}
}
@@ -9108,8 +10017,10 @@ static void bnxt_setup_inta(struct bnxt *bp)
{
const int len = sizeof(bp->irq_tbl[0].name);
- if (netdev_get_num_tc(bp->dev))
+ if (bp->num_tc) {
netdev_reset_tc(bp->dev);
+ bp->num_tc = 0;
+ }
snprintf(bp->irq_tbl[0].name, len, "%s-%s-%d", bp->dev->name, "TxRx",
0);
@@ -9137,7 +10048,6 @@ static int bnxt_setup_int_mode(struct bnxt *bp)
return rc;
}
-#ifdef CONFIG_RFS_ACCEL
static unsigned int bnxt_get_max_func_rss_ctxs(struct bnxt *bp)
{
return bp->hw_resc.max_rsscos_ctxs;
@@ -9147,7 +10057,6 @@ static unsigned int bnxt_get_max_func_vnics(struct bnxt *bp)
{
return bp->hw_resc.max_vnics;
}
-#endif
unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp)
{
@@ -9163,7 +10072,7 @@ static unsigned int bnxt_get_max_func_cp_rings_for_en(struct bnxt *bp)
{
unsigned int cp = bp->hw_resc.max_cp_rings;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
cp -= bnxt_get_ulp_msix_num(bp);
return cp;
@@ -9173,7 +10082,7 @@ static unsigned int bnxt_get_max_func_irqs(struct bnxt *bp)
{
struct bnxt_hw_resc *hw_resc = &bp->hw_resc;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return min_t(unsigned int, hw_resc->max_irqs, hw_resc->max_nqs);
return min_t(unsigned int, hw_resc->max_irqs, hw_resc->max_cp_rings);
@@ -9189,7 +10098,7 @@ unsigned int bnxt_get_avail_cp_rings_for_en(struct bnxt *bp)
unsigned int cp;
cp = bnxt_get_max_func_cp_rings_for_en(bp);
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return cp - bp->rx_nr_rings - bp->tx_nr_rings;
else
return cp - bp->cp_nr_rings;
@@ -9208,7 +10117,7 @@ int bnxt_get_avail_msix(struct bnxt *bp, int num)
int max_idx, avail_msix;
max_idx = bp->total_irqs;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
max_idx = min_t(int, bp->total_irqs, max_cp);
avail_msix = max_idx - bp->cp_nr_rings;
if (!BNXT_NEW_RM(bp) || avail_msix >= num)
@@ -9232,7 +10141,7 @@ static int bnxt_get_num_msix(struct bnxt *bp)
static int bnxt_init_msix(struct bnxt *bp)
{
- int i, total_vecs, max, rc = 0, min = 1, ulp_msix;
+ int i, total_vecs, max, rc = 0, min = 1, ulp_msix, tx_cp;
struct msix_entry *msix_ent;
total_vecs = bnxt_get_num_msix(bp);
@@ -9274,9 +10183,10 @@ static int bnxt_init_msix(struct bnxt *bp)
if (rc)
goto msix_setup_exit;
+ tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
bp->cp_nr_rings = (min == 1) ?
- max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
- bp->tx_nr_rings + bp->rx_nr_rings;
+ max_t(int, tx_cp, bp->rx_nr_rings) :
+ tx_cp + bp->rx_nr_rings;
} else {
rc = -ENOMEM;
@@ -9336,8 +10246,8 @@ static void bnxt_clear_int_mode(struct bnxt *bp)
int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
{
- int tcs = netdev_get_num_tc(bp->dev);
bool irq_cleared = false;
+ int tcs = bp->num_tc;
int rc;
if (!bnxt_need_reserve_rings(bp))
@@ -9363,6 +10273,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
bp->tx_nr_rings - bp->tx_nr_rings_xdp)) {
netdev_err(bp->dev, "tx ring reservation failure\n");
netdev_reset_tc(bp->dev);
+ bp->num_tc = 0;
if (bp->tx_nr_rings_xdp)
bp->tx_nr_rings_per_tc = bp->tx_nr_rings_xdp;
else
@@ -9439,6 +10350,7 @@ static int bnxt_request_irq(struct bnxt *bp)
if (rc)
break;
+ netif_napi_set_irq(&bp->bnapi[i]->napi, irq->vector);
irq->requested = 1;
if (zalloc_cpumask_var(&irq->cpu_mask, GFP_KERNEL)) {
@@ -9466,6 +10378,11 @@ static void bnxt_del_napi(struct bnxt *bp)
if (!bp->bnapi)
return;
+ for (i = 0; i < bp->rx_nr_rings; i++)
+ netif_queue_set_napi(bp->dev, i, NETDEV_QUEUE_TYPE_RX, NULL);
+ for (i = 0; i < bp->tx_nr_rings - bp->tx_nr_rings_xdp; i++)
+ netif_queue_set_napi(bp->dev, i, NETDEV_QUEUE_TYPE_TX, NULL);
+
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
@@ -9486,7 +10403,7 @@ static void bnxt_init_napi(struct bnxt *bp)
if (bp->flags & BNXT_FLAG_USING_MSIX) {
int (*poll_fn)(struct napi_struct *, int) = bnxt_poll;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
poll_fn = bnxt_poll_p5;
else if (BNXT_CHIP_TYPE_NITRO_A0(bp))
cp_nr_rings--;
@@ -9542,8 +10459,6 @@ static void bnxt_enable_napi(struct bnxt *bp)
cpr = &bnapi->cp_ring;
bnapi->in_reset = false;
- bnapi->tx_pkts = 0;
-
if (bnapi->rx_ring) {
INIT_WORK(&cpr->dim.work, bnxt_dim_work);
cpr->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
@@ -9647,7 +10562,10 @@ void bnxt_report_link(struct bnxt *bp)
signal = "(NRZ) ";
break;
case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4:
- signal = "(PAM4) ";
+ signal = "(PAM4 56Gbps) ";
+ break;
+ case PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112:
+ signal = "(PAM4 112Gbps) ";
break;
default:
break;
@@ -9675,7 +10593,9 @@ static bool bnxt_phy_qcaps_no_speed(struct hwrm_port_phy_qcaps_output *resp)
if (!resp->supported_speeds_auto_mode &&
!resp->supported_speeds_force_mode &&
!resp->supported_pam4_speeds_auto_mode &&
- !resp->supported_pam4_speeds_force_mode)
+ !resp->supported_pam4_speeds_force_mode &&
+ !resp->supported_speeds2_auto_mode &&
+ !resp->supported_speeds2_force_mode)
return true;
return false;
}
@@ -9721,6 +10641,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp)
/* Phy re-enabled, reprobe the speeds */
link_info->support_auto_speeds = 0;
link_info->support_pam4_auto_speeds = 0;
+ link_info->support_auto_speeds2 = 0;
}
}
if (resp->supported_speeds_auto_mode)
@@ -9729,6 +10650,9 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp)
if (resp->supported_pam4_speeds_auto_mode)
link_info->support_pam4_auto_speeds =
le16_to_cpu(resp->supported_pam4_speeds_auto_mode);
+ if (resp->supported_speeds2_auto_mode)
+ link_info->support_auto_speeds2 =
+ le16_to_cpu(resp->supported_speeds2_auto_mode);
bp->port_count = resp->port_cnt;
@@ -9746,9 +10670,19 @@ static bool bnxt_support_dropped(u16 advertising, u16 supported)
static bool bnxt_support_speed_dropped(struct bnxt_link_info *link_info)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+
/* Check if any advertised speeds are no longer supported. The caller
* holds the link_lock mutex, so we can modify link_info settings.
*/
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ if (bnxt_support_dropped(link_info->advertising,
+ link_info->support_auto_speeds2)) {
+ link_info->advertising = link_info->support_auto_speeds2;
+ return true;
+ }
+ return false;
+ }
if (bnxt_support_dropped(link_info->advertising,
link_info->support_auto_speeds)) {
link_info->advertising = link_info->support_auto_speeds;
@@ -9797,18 +10731,25 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
link_info->lp_pause = resp->link_partner_adv_pause;
link_info->force_pause_setting = resp->force_pause;
link_info->duplex_setting = resp->duplex_cfg;
- if (link_info->phy_link_status == BNXT_LINK_LINK)
+ if (link_info->phy_link_status == BNXT_LINK_LINK) {
link_info->link_speed = le16_to_cpu(resp->link_speed);
- else
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2)
+ link_info->active_lanes = resp->active_lanes;
+ } else {
link_info->link_speed = 0;
+ link_info->active_lanes = 0;
+ }
link_info->force_link_speed = le16_to_cpu(resp->force_link_speed);
link_info->force_pam4_link_speed =
le16_to_cpu(resp->force_pam4_link_speed);
+ link_info->force_link_speed2 = le16_to_cpu(resp->force_link_speeds2);
link_info->support_speeds = le16_to_cpu(resp->support_speeds);
link_info->support_pam4_speeds = le16_to_cpu(resp->support_pam4_speeds);
+ link_info->support_speeds2 = le16_to_cpu(resp->support_speeds2);
link_info->auto_link_speeds = le16_to_cpu(resp->auto_link_speed_mask);
link_info->auto_pam4_link_speeds =
le16_to_cpu(resp->auto_pam4_link_speed_mask);
+ link_info->auto_link_speeds2 = le16_to_cpu(resp->auto_link_speeds2);
link_info->lp_auto_link_speeds =
le16_to_cpu(resp->link_partner_adv_speeds);
link_info->lp_auto_pam4_link_speeds =
@@ -9947,7 +10888,11 @@ static void bnxt_hwrm_set_link_common(struct bnxt *bp, struct hwrm_port_phy_cfg_
{
if (bp->link_info.autoneg & BNXT_AUTONEG_SPEED) {
req->auto_mode |= PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK;
- if (bp->link_info.advertising) {
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ req->enables |=
+ cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK);
+ req->auto_link_speeds2_mask = cpu_to_le16(bp->link_info.advertising);
+ } else if (bp->link_info.advertising) {
req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK);
req->auto_link_speed_mask = cpu_to_le16(bp->link_info.advertising);
}
@@ -9961,7 +10906,12 @@ static void bnxt_hwrm_set_link_common(struct bnxt *bp, struct hwrm_port_phy_cfg_
req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_RESTART_AUTONEG);
} else {
req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE);
- if (bp->link_info.req_signal_mode == BNXT_SIG_MODE_PAM4) {
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ req->force_link_speeds2 = cpu_to_le16(bp->link_info.req_link_speed);
+ req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2);
+ netif_info(bp, link, bp->dev, "Forcing FW speed2: %d\n",
+ (u32)bp->link_info.req_link_speed);
+ } else if (bp->link_info.req_signal_mode == BNXT_SIG_MODE_PAM4) {
req->force_pam4_link_speed = cpu_to_le16(bp->link_info.req_link_speed);
req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED);
} else {
@@ -10226,8 +11176,6 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
bnxt_ulp_stop(bp);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
bnxt_dcb_free(bp);
rc = bnxt_fw_init_one(bp);
if (rc) {
@@ -10627,10 +11575,12 @@ int bnxt_half_open_nic(struct bnxt *bp)
netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc);
goto half_open_err;
}
+ bnxt_init_napi(bp);
set_bit(BNXT_STATE_HALF_OPEN, &bp->state);
rc = bnxt_init_nic(bp, true);
if (rc) {
clear_bit(BNXT_STATE_HALF_OPEN, &bp->state);
+ bnxt_del_napi(bp);
netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
goto half_open_err;
}
@@ -10649,6 +11599,7 @@ half_open_err:
void bnxt_half_close_nic(struct bnxt *bp)
{
bnxt_hwrm_resource_free(bp, false, true);
+ bnxt_del_napi(bp);
bnxt_free_skbs(bp);
bnxt_free_mem(bp, true);
clear_bit(BNXT_STATE_HALF_OPEN, &bp->state);
@@ -11112,7 +12063,6 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp)
{
struct net_device *dev = bp->dev;
struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
- struct hwrm_cfa_l2_filter_free_input *req;
struct netdev_hw_addr *ha;
int i, off = 0, rc;
bool uc_update;
@@ -11124,16 +12074,12 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp)
if (!uc_update)
goto skip_uc;
- rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_FREE);
- if (rc)
- return rc;
- hwrm_req_hold(bp, req);
for (i = 1; i < vnic->uc_filter_count; i++) {
- req->l2_filter_id = vnic->fw_l2_filter_id[i];
+ struct bnxt_l2_filter *fltr = vnic->l2_filters[i];
- rc = hwrm_req_send(bp, req);
+ bnxt_hwrm_l2_filter_free(bp, fltr);
+ bnxt_del_l2_filter(bp, fltr);
}
- hwrm_req_drop(bp, req);
vnic->uc_filter_count = 1;
@@ -11210,7 +12156,7 @@ static bool bnxt_can_reserve_rings(struct bnxt *bp)
/* If the chip and firmware supports RFS */
static bool bnxt_rfs_supported(struct bnxt *bp)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2)
return true;
return false;
@@ -11220,7 +12166,7 @@ static bool bnxt_rfs_supported(struct bnxt *bp)
return false;
if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp))
return true;
- if (bp->flags & BNXT_FLAG_NEW_RSS_CAP)
+ if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP)
return true;
return false;
}
@@ -11228,10 +12174,9 @@ static bool bnxt_rfs_supported(struct bnxt *bp)
/* If runtime conditions support RFS */
static bool bnxt_rfs_capable(struct bnxt *bp)
{
-#ifdef CONFIG_RFS_ACCEL
int vnics, max_vnics, max_rss_ctxs;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
return bnxt_rfs_supported(bp);
if (!(bp->flags & BNXT_FLAG_MSIX_CAP) || !bnxt_can_reserve_rings(bp) || !bp->rx_nr_rings)
return false;
@@ -11241,7 +12186,7 @@ static bool bnxt_rfs_capable(struct bnxt *bp)
max_rss_ctxs = bnxt_get_max_func_rss_ctxs(bp);
/* RSS contexts not a limiting factor */
- if (bp->flags & BNXT_FLAG_NEW_RSS_CAP)
+ if (bp->rss_cap & BNXT_RSS_CAP_NEW_RSS_CAP)
max_rss_ctxs = max_vnics;
if (vnics > max_vnics || vnics > max_rss_ctxs) {
if (bp->rx_nr_rings > 1)
@@ -11264,9 +12209,6 @@ static bool bnxt_rfs_capable(struct bnxt *bp)
netdev_warn(bp->dev, "Unable to reserve resources to support NTUPLE filters.\n");
bnxt_hwrm_reserve_rings(bp, 0, 0, 0, 0, 0, 1);
return false;
-#else
- return false;
-#endif
}
static netdev_features_t bnxt_fix_features(struct net_device *dev,
@@ -11333,7 +12275,7 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
update_tpa = true;
if ((bp->flags & BNXT_FLAG_TPA) == 0 ||
(flags & BNXT_FLAG_TPA) == 0 ||
- (bp->flags & BNXT_FLAG_CHIP_P5))
+ (bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
re_init = true;
}
@@ -11442,9 +12384,10 @@ static bool bnxt_udp_tunl_check(struct bnxt *bp, struct sk_buff *skb)
struct udphdr *uh = udp_hdr(skb);
__be16 udp_port = uh->dest;
- if (udp_port != bp->vxlan_port && udp_port != bp->nge_port)
+ if (udp_port != bp->vxlan_port && udp_port != bp->nge_port &&
+ udp_port != bp->vxlan_gpe_port)
return false;
- if (skb->inner_protocol_type == ENCAP_TYPE_ETHER) {
+ if (skb->inner_protocol == htons(ETH_P_TEB)) {
struct ethhdr *eh = inner_eth_hdr(skb);
switch (eh->h_proto) {
@@ -11455,6 +12398,11 @@ static bool bnxt_udp_tunl_check(struct bnxt *bp, struct sk_buff *skb)
skb_inner_network_offset(skb),
NULL);
}
+ } else if (skb->inner_protocol == htons(ETH_P_IP)) {
+ return true;
+ } else if (skb->inner_protocol == htons(ETH_P_IPV6)) {
+ return bnxt_exthdr_check(bp, skb, skb_inner_network_offset(skb),
+ NULL);
}
return false;
}
@@ -11575,15 +12523,13 @@ static int bnxt_dbg_hwrm_ring_info_get(struct bnxt *bp, u8 ring_type,
static void bnxt_dump_tx_sw_state(struct bnxt_napi *bnapi)
{
- struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
- int i = bnapi->index;
-
- if (!txr)
- return;
+ struct bnxt_tx_ring_info *txr;
+ int i = bnapi->index, j;
- netdev_info(bnapi->bp->dev, "[%d]: tx{fw_ring: %d prod: %x cons: %x}\n",
- i, txr->tx_ring_struct.fw_ring_id, txr->tx_prod,
- txr->tx_cons);
+ bnxt_for_each_napi_tx(j, bnapi, txr)
+ netdev_info(bnapi->bp->dev, "[%d.%d]: tx{fw_ring: %d prod: %x cons: %x}\n",
+ i, j, txr->tx_ring_struct.fw_ring_id, txr->tx_prod,
+ txr->tx_cons);
}
static void bnxt_dump_rx_sw_state(struct bnxt_napi *bnapi)
@@ -11746,8 +12692,7 @@ static void bnxt_timer(struct timer_list *t)
if (test_bit(BNXT_STATE_L2_FILTER_RETRY, &bp->state))
bnxt_queue_sp_work(bp, BNXT_RX_MASK_SP_EVENT);
- if ((bp->flags & BNXT_FLAG_CHIP_P5) && !bp->chip_rev &&
- netif_carrier_ok(dev))
+ if ((BNXT_CHIP_P5(bp)) && !bp->chip_rev && netif_carrier_ok(dev))
bnxt_queue_sp_work(bp, BNXT_RING_COAL_NOW_SP_EVENT);
bnxt_restart_timer:
@@ -11856,8 +12801,6 @@ static void bnxt_fw_reset_close(struct bnxt *bp)
if (pci_is_enabled(bp->pdev))
pci_disable_device(bp->pdev);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
}
static bool is_bnxt_fw_ok(struct bnxt *bp)
@@ -12000,7 +12943,7 @@ static void bnxt_chk_missed_irq(struct bnxt *bp)
{
int i;
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
return;
for (i = 0; i < bp->cp_nr_rings; i++) {
@@ -12013,12 +12956,11 @@ static void bnxt_chk_missed_irq(struct bnxt *bp)
continue;
cpr = &bnapi->cp_ring;
- for (j = 0; j < 2; j++) {
- struct bnxt_cp_ring_info *cpr2 = cpr->cp_ring_arr[j];
+ for (j = 0; j < cpr->cp_ring_count; j++) {
+ struct bnxt_cp_ring_info *cpr2 = &cpr->cp_ring_arr[j];
u32 val[2];
- if (!cpr2 || cpr2->has_more_work ||
- !bnxt_has_work(bp, cpr2))
+ if (cpr2->has_more_work || !bnxt_has_work(bp, cpr2))
continue;
if (cpr2->cp_raw_cons != cpr2->last_cp_raw_cons) {
@@ -12179,36 +13121,42 @@ static void bnxt_sp_task(struct work_struct *work)
clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
}
+static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx,
+ int *max_cp);
+
/* Under rtnl_lock */
int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
int tx_xdp)
{
- int max_rx, max_tx, tx_sets = 1;
+ int max_rx, max_tx, max_cp, tx_sets = 1, tx_cp;
int tx_rings_needed, stats;
int rx_rings = rx;
- int cp, vnics, rc;
+ int cp, vnics;
if (tcs)
tx_sets = tcs;
- rc = bnxt_get_max_rings(bp, &max_rx, &max_tx, sh);
- if (rc)
- return rc;
+ _bnxt_get_max_rings(bp, &max_rx, &max_tx, &max_cp);
- if (max_rx < rx)
+ if (max_rx < rx_rings)
return -ENOMEM;
+ if (bp->flags & BNXT_FLAG_AGG_RINGS)
+ rx_rings <<= 1;
+
tx_rings_needed = tx * tx_sets + tx_xdp;
if (max_tx < tx_rings_needed)
return -ENOMEM;
vnics = 1;
- if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5)) == BNXT_FLAG_RFS)
- vnics += rx_rings;
+ if ((bp->flags & (BNXT_FLAG_RFS | BNXT_FLAG_CHIP_P5_PLUS)) ==
+ BNXT_FLAG_RFS)
+ vnics += rx;
- if (bp->flags & BNXT_FLAG_AGG_RINGS)
- rx_rings <<= 1;
- cp = sh ? max_t(int, tx_rings_needed, rx) : tx_rings_needed + rx;
+ tx_cp = __bnxt_num_tx_to_cp(bp, tx_rings_needed, tx_sets, tx_xdp);
+ cp = sh ? max_t(int, tx_cp, rx) : tx_cp + rx;
+ if (max_cp < cp)
+ return -ENOMEM;
stats = cp;
if (BNXT_NEW_RM(bp)) {
cp += bnxt_get_ulp_msix_num(bp);
@@ -12283,10 +13231,10 @@ static bool bnxt_fw_pre_resv_vnics(struct bnxt *bp)
{
u16 fw_maj = BNXT_FW_MAJ(bp), fw_bld = BNXT_FW_BLD(bp);
- if (!(bp->flags & BNXT_FLAG_CHIP_P5) &&
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
(fw_maj > 218 || (fw_maj == 218 && fw_bld >= 18)))
return true;
- if ((bp->flags & BNXT_FLAG_CHIP_P5) &&
+ if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
(fw_maj > 216 || (fw_maj == 216 && fw_bld >= 172)))
return true;
return false;
@@ -12298,6 +13246,11 @@ static int bnxt_fw_init_one_p1(struct bnxt *bp)
bp->fw_cap = 0;
rc = bnxt_hwrm_ver_get(bp);
+ /* FW may be unresponsive after FLR. FLR must complete within 100 msec
+ * so wait before continuing with recovery.
+ */
+ if (rc)
+ msleep(100);
bnxt_try_map_fw_health_reg(bp);
if (rc) {
rc = bnxt_try_recover_fw(bp);
@@ -12364,15 +13317,15 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp)
static void bnxt_set_dflt_rss_hash_type(struct bnxt *bp)
{
- bp->flags &= ~BNXT_FLAG_UDP_RSS_CAP;
+ bp->rss_cap &= ~BNXT_RSS_CAP_UDP_RSS_CAP;
bp->rss_hash_cfg = VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
- if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA)
+ if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA)
bp->rss_hash_delta = bp->rss_hash_cfg;
if (BNXT_CHIP_P4_PLUS(bp) && bp->hwrm_spec_code >= 0x10501) {
- bp->flags |= BNXT_FLAG_UDP_RSS_CAP;
+ bp->rss_cap |= BNXT_RSS_CAP_UDP_RSS_CAP;
bp->rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
}
@@ -12842,7 +13795,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
{
struct bnxt *bp = netdev_priv(dev);
bool sh = false;
- int rc;
+ int rc, tx_cp;
if (tc > bp->max_tc) {
netdev_err(dev, "Too many traffic classes requested: %d. Max supported is %d.\n",
@@ -12850,7 +13803,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
return -EINVAL;
}
- if (netdev_get_num_tc(dev) == tc)
+ if (bp->num_tc == tc)
return 0;
if (bp->flags & BNXT_FLAG_SHARED_RINGS)
@@ -12868,13 +13821,16 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc)
if (tc) {
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc;
netdev_set_num_tc(dev, tc);
+ bp->num_tc = tc;
} else {
bp->tx_nr_rings = bp->tx_nr_rings_per_tc;
netdev_reset_tc(dev);
+ bp->num_tc = 0;
}
bp->tx_nr_rings += bp->tx_nr_rings_xdp;
- bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
- bp->tx_nr_rings + bp->rx_nr_rings;
+ tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+ bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
+ tx_cp + bp->rx_nr_rings;
if (netif_running(bp->dev))
return bnxt_open_nic(bp, true, false);
@@ -12924,38 +13880,102 @@ static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
}
}
-#ifdef CONFIG_RFS_ACCEL
+u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys,
+ const struct sk_buff *skb)
+{
+ struct bnxt_vnic_info *vnic;
+
+ if (skb)
+ return skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK;
+
+ vnic = &bp->vnic_info[0];
+ return bnxt_toeplitz(bp, fkeys, (void *)vnic->rss_hash_key);
+}
+
+int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr,
+ u32 idx)
+{
+ struct hlist_head *head;
+ int bit_id;
+
+ spin_lock_bh(&bp->ntp_fltr_lock);
+ bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, BNXT_MAX_FLTR, 0);
+ if (bit_id < 0) {
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ return -ENOMEM;
+ }
+
+ fltr->base.sw_id = (u16)bit_id;
+ fltr->base.type = BNXT_FLTR_TYPE_NTUPLE;
+ fltr->base.flags |= BNXT_ACT_RING_DST;
+ head = &bp->ntp_fltr_hash_tbl[idx];
+ hlist_add_head_rcu(&fltr->base.hash, head);
+ set_bit(BNXT_FLTR_INSERTED, &fltr->base.state);
+ bp->ntp_fltr_count++;
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ return 0;
+}
+
static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1,
struct bnxt_ntuple_filter *f2)
{
struct flow_keys *keys1 = &f1->fkeys;
struct flow_keys *keys2 = &f2->fkeys;
+ if (f1->ntuple_flags != f2->ntuple_flags)
+ return false;
+
if (keys1->basic.n_proto != keys2->basic.n_proto ||
keys1->basic.ip_proto != keys2->basic.ip_proto)
return false;
if (keys1->basic.n_proto == htons(ETH_P_IP)) {
- if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src ||
- keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst)
+ if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) &&
+ keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src) ||
+ ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) &&
+ keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst))
return false;
} else {
- if (memcmp(&keys1->addrs.v6addrs.src, &keys2->addrs.v6addrs.src,
- sizeof(keys1->addrs.v6addrs.src)) ||
- memcmp(&keys1->addrs.v6addrs.dst, &keys2->addrs.v6addrs.dst,
- sizeof(keys1->addrs.v6addrs.dst)))
+ if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) &&
+ memcmp(&keys1->addrs.v6addrs.src,
+ &keys2->addrs.v6addrs.src,
+ sizeof(keys1->addrs.v6addrs.src))) ||
+ ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) &&
+ memcmp(&keys1->addrs.v6addrs.dst,
+ &keys2->addrs.v6addrs.dst,
+ sizeof(keys1->addrs.v6addrs.dst))))
return false;
}
- if (keys1->ports.ports == keys2->ports.ports &&
- keys1->control.flags == keys2->control.flags &&
- ether_addr_equal(f1->src_mac_addr, f2->src_mac_addr) &&
- ether_addr_equal(f1->dst_mac_addr, f2->dst_mac_addr))
+ if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) &&
+ keys1->ports.src != keys2->ports.src) ||
+ ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) &&
+ keys1->ports.dst != keys2->ports.dst))
+ return false;
+
+ if (keys1->control.flags == keys2->control.flags &&
+ f1->l2_fltr == f2->l2_fltr)
return true;
return false;
}
+struct bnxt_ntuple_filter *
+bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr, u32 idx)
+{
+ struct bnxt_ntuple_filter *f;
+ struct hlist_head *head;
+
+ head = &bp->ntp_fltr_hash_tbl[idx];
+ hlist_for_each_entry_rcu(f, head, base.hash) {
+ if (bnxt_fltr_match(f, fltr))
+ return f;
+ }
+ return NULL;
+}
+
+#ifdef CONFIG_RFS_ACCEL
static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
u16 rxq_index, u32 flow_id)
{
@@ -12963,29 +13983,31 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
struct bnxt_ntuple_filter *fltr, *new_fltr;
struct flow_keys *fkeys;
struct ethhdr *eth = (struct ethhdr *)skb_mac_header(skb);
- int rc = 0, idx, bit_id, l2_idx = 0;
- struct hlist_head *head;
+ struct bnxt_l2_filter *l2_fltr;
+ int rc = 0, idx;
u32 flags;
- if (!ether_addr_equal(dev->dev_addr, eth->h_dest)) {
- struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
- int off = 0, j;
+ if (ether_addr_equal(dev->dev_addr, eth->h_dest)) {
+ l2_fltr = bp->vnic_info[0].l2_filters[0];
+ atomic_inc(&l2_fltr->refcnt);
+ } else {
+ struct bnxt_l2_key key;
- netif_addr_lock_bh(dev);
- for (j = 0; j < vnic->uc_filter_count; j++, off += ETH_ALEN) {
- if (ether_addr_equal(eth->h_dest,
- vnic->uc_list + off)) {
- l2_idx = j + 1;
- break;
- }
- }
- netif_addr_unlock_bh(dev);
- if (!l2_idx)
+ ether_addr_copy(key.dst_mac_addr, eth->h_dest);
+ key.vlan = 0;
+ l2_fltr = bnxt_lookup_l2_filter_from_key(bp, &key);
+ if (!l2_fltr)
return -EINVAL;
+ if (l2_fltr->base.flags & BNXT_ACT_FUNC_DST) {
+ bnxt_del_l2_filter(bp, l2_fltr);
+ return -EINVAL;
+ }
}
new_fltr = kzalloc(sizeof(*new_fltr), GFP_ATOMIC);
- if (!new_fltr)
+ if (!new_fltr) {
+ bnxt_del_l2_filter(bp, l2_fltr);
return -ENOMEM;
+ }
fkeys = &new_fltr->fkeys;
if (!skb_flow_dissect_flow_keys(skb, fkeys, 0)) {
@@ -13012,49 +14034,52 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
goto err_free;
}
- memcpy(new_fltr->dst_mac_addr, eth->h_dest, ETH_ALEN);
- memcpy(new_fltr->src_mac_addr, eth->h_source, ETH_ALEN);
+ new_fltr->l2_fltr = l2_fltr;
+ new_fltr->ntuple_flags = BNXT_NTUPLE_MATCH_ALL;
- idx = skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK;
- head = &bp->ntp_fltr_hash_tbl[idx];
+ idx = bnxt_get_ntp_filter_idx(bp, fkeys, skb);
rcu_read_lock();
- hlist_for_each_entry_rcu(fltr, head, hash) {
- if (bnxt_fltr_match(fltr, new_fltr)) {
- rc = fltr->sw_id;
- rcu_read_unlock();
- goto err_free;
- }
- }
- rcu_read_unlock();
-
- spin_lock_bh(&bp->ntp_fltr_lock);
- bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap,
- BNXT_NTP_FLTR_MAX_FLTR, 0);
- if (bit_id < 0) {
- spin_unlock_bh(&bp->ntp_fltr_lock);
- rc = -ENOMEM;
+ fltr = bnxt_lookup_ntp_filter_from_idx(bp, new_fltr, idx);
+ if (fltr) {
+ rc = fltr->base.sw_id;
+ rcu_read_unlock();
goto err_free;
}
+ rcu_read_unlock();
- new_fltr->sw_id = (u16)bit_id;
new_fltr->flow_id = flow_id;
- new_fltr->l2_fltr_idx = l2_idx;
- new_fltr->rxq = rxq_index;
- hlist_add_head_rcu(&new_fltr->hash, head);
- bp->ntp_fltr_count++;
- spin_unlock_bh(&bp->ntp_fltr_lock);
-
- bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT);
-
- return new_fltr->sw_id;
+ new_fltr->base.rxq = rxq_index;
+ rc = bnxt_insert_ntp_filter(bp, new_fltr, idx);
+ if (!rc) {
+ bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT);
+ return new_fltr->base.sw_id;
+ }
err_free:
+ bnxt_del_l2_filter(bp, l2_fltr);
kfree(new_fltr);
return rc;
}
+#endif
+
+void bnxt_del_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr)
+{
+ spin_lock_bh(&bp->ntp_fltr_lock);
+ if (!test_and_clear_bit(BNXT_FLTR_INSERTED, &fltr->base.state)) {
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ return;
+ }
+ hlist_del_rcu(&fltr->base.hash);
+ bp->ntp_fltr_count--;
+ spin_unlock_bh(&bp->ntp_fltr_lock);
+ bnxt_del_l2_filter(bp, fltr->l2_fltr);
+ clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap);
+ kfree_rcu(fltr, base.rcu);
+}
static void bnxt_cfg_ntp_filters(struct bnxt *bp)
{
+#ifdef CONFIG_RFS_ACCEL
int i;
for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
@@ -13064,13 +14089,15 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp)
int rc;
head = &bp->ntp_fltr_hash_tbl[i];
- hlist_for_each_entry_safe(fltr, tmp, head, hash) {
+ hlist_for_each_entry_safe(fltr, tmp, head, base.hash) {
bool del = false;
- if (test_bit(BNXT_FLTR_VALID, &fltr->state)) {
- if (rps_may_expire_flow(bp->dev, fltr->rxq,
+ if (test_bit(BNXT_FLTR_VALID, &fltr->base.state)) {
+ if (fltr->base.flags & BNXT_ACT_NO_AGING)
+ continue;
+ if (rps_may_expire_flow(bp->dev, fltr->base.rxq,
fltr->flow_id,
- fltr->sw_id)) {
+ fltr->base.sw_id)) {
bnxt_hwrm_cfa_ntuple_filter_free(bp,
fltr);
del = true;
@@ -13081,30 +14108,16 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp)
if (rc)
del = true;
else
- set_bit(BNXT_FLTR_VALID, &fltr->state);
+ set_bit(BNXT_FLTR_VALID, &fltr->base.state);
}
- if (del) {
- spin_lock_bh(&bp->ntp_fltr_lock);
- hlist_del_rcu(&fltr->hash);
- bp->ntp_fltr_count--;
- spin_unlock_bh(&bp->ntp_fltr_lock);
- synchronize_rcu();
- clear_bit(fltr->sw_id, bp->ntp_fltr_bmap);
- kfree(fltr);
- }
+ if (del)
+ bnxt_del_ntp_filter(bp, fltr);
}
}
+#endif
}
-#else
-
-static void bnxt_cfg_ntp_filters(struct bnxt *bp)
-{
-}
-
-#endif /* CONFIG_RFS_ACCEL */
-
static int bnxt_udp_tunnel_set_port(struct net_device *netdev, unsigned int table,
unsigned int entry, struct udp_tunnel_info *ti)
{
@@ -13112,9 +14125,11 @@ static int bnxt_udp_tunnel_set_port(struct net_device *netdev, unsigned int tabl
unsigned int cmd;
if (ti->type == UDP_TUNNEL_TYPE_VXLAN)
- cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN;
+ cmd = TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN;
+ else if (ti->type == UDP_TUNNEL_TYPE_GENEVE)
+ cmd = TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GENEVE;
else
- cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE;
+ cmd = TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE;
return bnxt_hwrm_tunnel_dst_port_alloc(bp, ti->port, cmd);
}
@@ -13127,8 +14142,10 @@ static int bnxt_udp_tunnel_unset_port(struct net_device *netdev, unsigned int ta
if (ti->type == UDP_TUNNEL_TYPE_VXLAN)
cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN;
- else
+ else if (ti->type == UDP_TUNNEL_TYPE_GENEVE)
cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE;
+ else
+ cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE;
return bnxt_hwrm_tunnel_dst_port_free(bp, cmd);
}
@@ -13142,6 +14159,16 @@ static const struct udp_tunnel_nic_info bnxt_udp_tunnels = {
{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, },
{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, },
},
+}, bnxt_udp_tunnels_p7 = {
+ .set_port = bnxt_udp_tunnel_set_port,
+ .unset_port = bnxt_udp_tunnel_unset_port,
+ .flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP |
+ UDP_TUNNEL_NIC_INFO_OPEN_ONLY,
+ .tables = {
+ { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, },
+ { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_GENEVE, },
+ { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN_GPE, },
+ },
};
static int bnxt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
@@ -13249,6 +14276,8 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bnxt_ptp_clear(bp);
unregister_netdev(dev);
+ bnxt_free_l2_filters(bp, true);
+ bnxt_free_ntp_fltrs(bp, true);
clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
/* Flush any pending tasks */
cancel_work_sync(&bp->sp_task);
@@ -13271,8 +14300,6 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bp->fw_health = NULL;
bnxt_cleanup_pci(bp);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
kfree(bp->rss_indir_tbl);
bp->rss_indir_tbl = NULL;
bnxt_free_port_stats(bp);
@@ -13341,7 +14368,7 @@ static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx,
max_irq = min_t(int, bnxt_get_max_func_irqs(bp) -
bnxt_get_ulp_msix_num(bp),
hw_resc->max_stat_ctxs - bnxt_get_ulp_stat_ctxs(bp));
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
*max_cp = min_t(int, *max_cp, max_irq);
max_ring_grps = hw_resc->max_hw_ring_grps;
if (BNXT_CHIP_TYPE_NITRO_A0(bp) && BNXT_PF(bp)) {
@@ -13350,8 +14377,14 @@ static void _bnxt_get_max_rings(struct bnxt *bp, int *max_rx, int *max_tx,
}
if (bp->flags & BNXT_FLAG_AGG_RINGS)
*max_rx >>= 1;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- bnxt_trim_rings(bp, max_rx, max_tx, *max_cp, false);
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ int rc;
+
+ rc = __bnxt_trim_rings(bp, max_rx, max_tx, *max_cp, false);
+ if (rc) {
+ *max_rx = 0;
+ *max_tx = 0;
+ }
/* On P5 chips, max_cp output param should be available NQs */
*max_cp = max_irq;
}
@@ -13652,7 +14685,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
max_irqs = bnxt_get_max_irq(pdev);
- dev = alloc_etherdev_mq(sizeof(*bp), max_irqs);
+ dev = alloc_etherdev_mqs(sizeof(*bp), max_irqs * BNXT_MAX_QUEUE,
+ max_irqs);
if (!dev)
return -ENOMEM;
@@ -13694,10 +14728,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (BNXT_PF(bp))
bnxt_vpd_read_info(bp);
- if (BNXT_CHIP_P5(bp)) {
- bp->flags |= BNXT_FLAG_CHIP_P5;
- if (BNXT_CHIP_SR2(bp))
- bp->flags |= BNXT_FLAG_CHIP_SR2;
+ if (BNXT_CHIP_P5_PLUS(bp)) {
+ bp->flags |= BNXT_FLAG_CHIP_P5_PLUS;
+ if (BNXT_CHIP_P7(bp))
+ bp->flags |= BNXT_FLAG_CHIP_P7;
}
rc = bnxt_alloc_rss_indir_tbl(bp);
@@ -13722,6 +14756,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM |
NETIF_F_GSO_PARTIAL | NETIF_F_RXHASH |
NETIF_F_RXCSUM | NETIF_F_GRO;
+ if (bp->flags & BNXT_FLAG_UDP_GSO_CAP)
+ dev->hw_features |= NETIF_F_GSO_UDP_L4;
if (BNXT_SUPPORTS_TPA(bp))
dev->hw_features |= NETIF_F_LRO;
@@ -13732,7 +14768,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_GRE |
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_GRE_CSUM |
NETIF_F_GSO_IPXIP4 | NETIF_F_GSO_PARTIAL;
- dev->udp_tunnel_nic_info = &bnxt_udp_tunnels;
+ if (bp->flags & BNXT_FLAG_UDP_GSO_CAP)
+ dev->hw_enc_features |= NETIF_F_GSO_UDP_L4;
+ if (bp->flags & BNXT_FLAG_CHIP_P7)
+ dev->udp_tunnel_nic_info = &bnxt_udp_tunnels_p7;
+ else
+ dev->udp_tunnel_nic_info = &bnxt_udp_tunnels;
dev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_GSO_GRE_CSUM;
@@ -13760,7 +14801,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bp->gro_func = bnxt_gro_func_5730x;
if (BNXT_CHIP_P4(bp))
bp->gro_func = bnxt_gro_func_5731x;
- else if (BNXT_CHIP_P5(bp))
+ else if (BNXT_CHIP_P5_PLUS(bp))
bp->gro_func = bnxt_gro_func_5750x;
}
if (!BNXT_CHIP_P4_PLUS(bp))
@@ -13786,6 +14827,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto init_err_pci_clean;
+ bnxt_init_l2_fltr_tbl(bp);
bnxt_set_rx_skb_mode(bp, false);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
@@ -13868,8 +14910,6 @@ init_err_pci_clean:
bp->fw_health = NULL;
bnxt_cleanup_pci(bp);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
kfree(bp->rss_indir_tbl);
bp->rss_indir_tbl = NULL;
@@ -13922,8 +14962,6 @@ static int bnxt_suspend(struct device *device)
bnxt_hwrm_func_drv_unrgtr(bp);
pci_disable_device(bp->pdev);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
rtnl_unlock();
return rc;
}
@@ -14022,8 +15060,6 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
if (pci_is_enabled(pdev))
pci_disable_device(pdev);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
rtnl_unlock();
/* Request a slot slot reset. */
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index a7d7b09ea162..47338b48ca20 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -18,7 +18,7 @@
*/
#define DRV_VER_MAJ 1
#define DRV_VER_MIN 10
-#define DRV_VER_UPD 2
+#define DRV_VER_UPD 3
#include <linux/ethtool.h>
#include <linux/interrupt.h>
@@ -61,6 +61,24 @@ struct tx_bd {
__le64 tx_bd_haddr;
} __packed;
+#define TX_OPAQUE_IDX_MASK 0x0000ffff
+#define TX_OPAQUE_BDS_MASK 0x00ff0000
+#define TX_OPAQUE_BDS_SHIFT 16
+#define TX_OPAQUE_RING_MASK 0xff000000
+#define TX_OPAQUE_RING_SHIFT 24
+
+#define SET_TX_OPAQUE(bp, txr, idx, bds) \
+ (((txr)->tx_napi_idx << TX_OPAQUE_RING_SHIFT) | \
+ ((bds) << TX_OPAQUE_BDS_SHIFT) | ((idx) & (bp)->tx_ring_mask))
+
+#define TX_OPAQUE_IDX(opq) ((opq) & TX_OPAQUE_IDX_MASK)
+#define TX_OPAQUE_RING(opq) (((opq) & TX_OPAQUE_RING_MASK) >> \
+ TX_OPAQUE_RING_SHIFT)
+#define TX_OPAQUE_BDS(opq) (((opq) & TX_OPAQUE_BDS_MASK) >> \
+ TX_OPAQUE_BDS_SHIFT)
+#define TX_OPAQUE_PROD(bp, opq) ((TX_OPAQUE_IDX(opq) + TX_OPAQUE_BDS(opq)) &\
+ (bp)->tx_ring_mask)
+
struct tx_bd_ext {
__le32 tx_bd_hsize_lflags;
#define TX_BD_FLAGS_TCP_UDP_CHKSUM (1 << 0)
@@ -121,11 +139,15 @@ struct tx_cmp {
__le32 tx_cmp_flags_type;
#define CMP_TYPE (0x3f << 0)
#define CMP_TYPE_TX_L2_CMP 0
+ #define CMP_TYPE_TX_L2_COAL_CMP 2
+ #define CMP_TYPE_TX_L2_PKT_TS_CMP 4
#define CMP_TYPE_RX_L2_CMP 17
#define CMP_TYPE_RX_AGG_CMP 18
#define CMP_TYPE_RX_L2_TPA_START_CMP 19
#define CMP_TYPE_RX_L2_TPA_END_CMP 21
#define CMP_TYPE_RX_TPA_AGG_CMP 22
+ #define CMP_TYPE_RX_L2_V3_CMP 23
+ #define CMP_TYPE_RX_L2_TPA_START_V3_CMP 25
#define CMP_TYPE_STATUS_CMP 32
#define CMP_TYPE_REMOTE_DRIVER_REQ 34
#define CMP_TYPE_REMOTE_DRIVER_RESP 36
@@ -152,9 +174,13 @@ struct tx_cmp {
#define TX_CMP_ERRORS_DMA_ERROR (1 << 6)
#define TX_CMP_ERRORS_HINT_TOO_SHORT (1 << 7)
- __le32 tx_cmp_unsed_3;
+ __le32 sq_cons_idx;
+ #define TX_CMP_SQ_CONS_IDX_MASK 0x00ffffff
};
+#define TX_CMP_SQ_CONS_IDX(txcmp) \
+ (le32_to_cpu((txcmp)->sq_cons_idx) & TX_CMP_SQ_CONS_IDX_MASK)
+
struct rx_cmp {
__le32 rx_cmp_len_flags_type;
#define RX_CMP_CMP_TYPE (0x3f << 0)
@@ -182,8 +208,20 @@ struct rx_cmp {
#define RX_CMP_AGG_BUFS_SHIFT 1
#define RX_CMP_RSS_HASH_TYPE (0x7f << 9)
#define RX_CMP_RSS_HASH_TYPE_SHIFT 9
+ #define RX_CMP_V3_RSS_EXT_OP_LEGACY (0xf << 12)
+ #define RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT 12
+ #define RX_CMP_V3_RSS_EXT_OP_NEW (0xf << 8)
+ #define RX_CMP_V3_RSS_EXT_OP_NEW_SHIFT 8
#define RX_CMP_PAYLOAD_OFFSET (0xff << 16)
#define RX_CMP_PAYLOAD_OFFSET_SHIFT 16
+ #define RX_CMP_SUB_NS_TS (0xf << 16)
+ #define RX_CMP_SUB_NS_TS_SHIFT 16
+ #define RX_CMP_METADATA1 (0xf << 28)
+ #define RX_CMP_METADATA1_SHIFT 28
+ #define RX_CMP_METADATA1_TPID_SEL (0x7 << 28)
+ #define RX_CMP_METADATA1_TPID_8021Q (0x1 << 28)
+ #define RX_CMP_METADATA1_TPID_8021AD (0x0 << 28)
+ #define RX_CMP_METADATA1_VALID (0x8 << 28)
__le32 rx_cmp_rss_hash;
};
@@ -203,6 +241,30 @@ struct rx_cmp {
(((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\
RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
+#define RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp) \
+ ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_LEGACY) >>\
+ RX_CMP_V3_RSS_EXT_OP_LEGACY_SHIFT)
+
+#define RX_CMP_V3_HASH_TYPE_NEW(rxcmp) \
+ ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_V3_RSS_EXT_OP_NEW) >>\
+ RX_CMP_V3_RSS_EXT_OP_NEW_SHIFT)
+
+#define RX_CMP_V3_HASH_TYPE(bp, rxcmp) \
+ (((bp)->rss_cap & BNXT_RSS_CAP_RSS_TCAM) ? \
+ RX_CMP_V3_HASH_TYPE_NEW(rxcmp) : \
+ RX_CMP_V3_HASH_TYPE_LEGACY(rxcmp))
+
+#define EXT_OP_INNER_4 0x0
+#define EXT_OP_OUTER_4 0x2
+#define EXT_OP_INNFL_3 0x8
+#define EXT_OP_OUTFL_3 0xa
+
+#define RX_CMP_VLAN_VALID(rxcmp) \
+ ((rxcmp)->rx_cmp_misc_v1 & cpu_to_le32(RX_CMP_METADATA1_VALID))
+
+#define RX_CMP_VLAN_TPID_SEL(rxcmp) \
+ (le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_METADATA1_TPID_SEL)
+
struct rx_cmp_ext {
__le32 rx_cmp_flags2;
#define RX_CMP_FLAGS2_IP_CS_CALC 0x1
@@ -250,6 +312,9 @@ struct rx_cmp_ext {
#define RX_CMPL_CFA_CODE_MASK (0xffff << 16)
#define RX_CMPL_CFA_CODE_SFT 16
+ #define RX_CMPL_METADATA0_TCI_MASK (0xffff << 16)
+ #define RX_CMPL_METADATA0_VID_MASK (0x0fff << 16)
+ #define RX_CMPL_METADATA0_SFT 16
__le32 rx_cmp_timestamp;
};
@@ -275,6 +340,10 @@ struct rx_cmp_ext {
((le32_to_cpu((rxcmpl1)->rx_cmp_cfa_code_errors_v2) & \
RX_CMPL_CFA_CODE_MASK) >> RX_CMPL_CFA_CODE_SFT)
+#define RX_CMP_METADATA0_TCI(rxcmp1) \
+ ((le32_to_cpu((rxcmp1)->rx_cmp_cfa_code_errors_v2) & \
+ RX_CMPL_METADATA0_TCI_MASK) >> RX_CMPL_METADATA0_SFT)
+
struct rx_agg_cmp {
__le32 rx_agg_cmp_len_flags_type;
#define RX_AGG_CMP_TYPE (0x3f << 0)
@@ -317,10 +386,18 @@ struct rx_tpa_start_cmp {
#define RX_TPA_START_CMP_V1 (0x1 << 0)
#define RX_TPA_START_CMP_RSS_HASH_TYPE (0x7f << 9)
#define RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT 9
+ #define RX_TPA_START_CMP_V3_RSS_HASH_TYPE (0x1ff << 7)
+ #define RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT 7
#define RX_TPA_START_CMP_AGG_ID (0x7f << 25)
#define RX_TPA_START_CMP_AGG_ID_SHIFT 25
#define RX_TPA_START_CMP_AGG_ID_P5 (0xffff << 16)
#define RX_TPA_START_CMP_AGG_ID_SHIFT_P5 16
+ #define RX_TPA_START_CMP_METADATA1 (0xf << 28)
+ #define RX_TPA_START_CMP_METADATA1_SHIFT 28
+ #define RX_TPA_START_METADATA1_TPID_SEL (0x7 << 28)
+ #define RX_TPA_START_METADATA1_TPID_8021Q (0x1 << 28)
+ #define RX_TPA_START_METADATA1_TPID_8021AD (0x0 << 28)
+ #define RX_TPA_START_METADATA1_VALID (0x8 << 28)
__le32 rx_tpa_start_cmp_rss_hash;
};
@@ -334,6 +411,11 @@ struct rx_tpa_start_cmp {
RX_TPA_START_CMP_RSS_HASH_TYPE) >> \
RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
+#define TPA_START_V3_HASH_TYPE(rx_tpa_start) \
+ (((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
+ RX_TPA_START_CMP_V3_RSS_HASH_TYPE) >> \
+ RX_TPA_START_CMP_V3_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
+
#define TPA_START_AGG_ID(rx_tpa_start) \
((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
RX_TPA_START_CMP_AGG_ID) >> RX_TPA_START_CMP_AGG_ID_SHIFT)
@@ -346,6 +428,14 @@ struct rx_tpa_start_cmp {
((rx_tpa_start)->rx_tpa_start_cmp_len_flags_type & \
cpu_to_le32(RX_TPA_START_CMP_FLAGS_ERROR))
+#define TPA_START_VLAN_VALID(rx_tpa_start) \
+ ((rx_tpa_start)->rx_tpa_start_cmp_misc_v1 & \
+ cpu_to_le32(RX_TPA_START_METADATA1_VALID))
+
+#define TPA_START_VLAN_TPID_SEL(rx_tpa_start) \
+ (le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
+ RX_TPA_START_METADATA1_TPID_SEL)
+
struct rx_tpa_start_cmp_ext {
__le32 rx_tpa_start_cmp_flags2;
#define RX_TPA_START_CMP_FLAGS2_IP_CS_CALC (0x1 << 0)
@@ -356,6 +446,8 @@ struct rx_tpa_start_cmp_ext {
#define RX_TPA_START_CMP_FLAGS2_CSUM_CMPL_VALID (0x1 << 9)
#define RX_TPA_START_CMP_FLAGS2_EXT_META_FORMAT (0x3 << 10)
#define RX_TPA_START_CMP_FLAGS2_EXT_META_FORMAT_SHIFT 10
+ #define RX_TPA_START_CMP_V3_FLAGS2_T_IP_TYPE (0x1 << 10)
+ #define RX_TPA_START_CMP_V3_FLAGS2_AGG_GRO (0x1 << 11)
#define RX_TPA_START_CMP_FLAGS2_CSUM_CMPL (0xffff << 16)
#define RX_TPA_START_CMP_FLAGS2_CSUM_CMPL_SHIFT 16
@@ -369,6 +461,9 @@ struct rx_tpa_start_cmp_ext {
#define RX_TPA_START_CMP_ERRORS_BUFFER_ERROR_FLUSH (0x5 << 1)
#define RX_TPA_START_CMP_CFA_CODE (0xffff << 16)
#define RX_TPA_START_CMPL_CFA_CODE_SHIFT 16
+ #define RX_TPA_START_CMP_METADATA0_TCI_MASK (0xffff << 16)
+ #define RX_TPA_START_CMP_METADATA0_VID_MASK (0x0fff << 16)
+ #define RX_TPA_START_CMP_METADATA0_SFT 16
__le32 rx_tpa_start_cmp_hdr_info;
};
@@ -385,6 +480,11 @@ struct rx_tpa_start_cmp_ext {
RX_TPA_START_CMP_ERRORS_BUFFER_ERROR_MASK) >> \
RX_TPA_START_CMP_ERRORS_BUFFER_ERROR_SHIFT)
+#define TPA_START_METADATA0_TCI(rx_tpa_start) \
+ ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_cfa_code_v2) & \
+ RX_TPA_START_CMP_METADATA0_TCI_MASK) >> \
+ RX_TPA_START_CMP_METADATA0_SFT)
+
struct rx_tpa_end_cmp {
__le32 rx_tpa_end_cmp_len_flags_type;
#define RX_TPA_END_CMP_TYPE (0x3f << 0)
@@ -529,6 +629,8 @@ struct nqe_cn {
#define NQ_CN_TYPE_SFT 0
#define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL
#define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION
+ #define NQ_CN_TOGGLE_MASK 0xc0UL
+ #define NQ_CN_TOGGLE_SFT 6
__le16 reserved16;
__le32 cq_handle_low;
__le32 v;
@@ -536,6 +638,23 @@ struct nqe_cn {
__le32 cq_handle_high;
};
+#define BNXT_NQ_HDL_IDX_MASK 0x00ffffff
+#define BNXT_NQ_HDL_TYPE_MASK 0xff000000
+#define BNXT_NQ_HDL_TYPE_SHIFT 24
+#define BNXT_NQ_HDL_TYPE_RX 0x00
+#define BNXT_NQ_HDL_TYPE_TX 0x01
+
+#define BNXT_NQ_HDL_IDX(hdl) ((hdl) & BNXT_NQ_HDL_IDX_MASK)
+#define BNXT_NQ_HDL_TYPE(hdl) (((hdl) & BNXT_NQ_HDL_TYPE_MASK) >> \
+ BNXT_NQ_HDL_TYPE_SHIFT)
+
+#define BNXT_SET_NQ_HDL(cpr) \
+ (((cpr)->cp_ring_type << BNXT_NQ_HDL_TYPE_SHIFT) | (cpr)->cp_idx)
+
+#define NQE_CN_TYPE(type) ((type) & NQ_CN_TYPE_MASK)
+#define NQE_CN_TOGGLE(type) (((type) & NQ_CN_TOGGLE_MASK) >> \
+ NQ_CN_TOGGLE_SFT)
+
#define DB_IDX_MASK 0xffffff
#define DB_IDX_VALID (0x1 << 26)
#define DB_IRQ_DIS (0x1 << 27)
@@ -551,9 +670,14 @@ struct nqe_cn {
/* 64-bit doorbell */
#define DBR_INDEX_MASK 0x0000000000ffffffULL
+#define DBR_EPOCH_MASK 0x01000000UL
+#define DBR_EPOCH_SFT 24
+#define DBR_TOGGLE_MASK 0x06000000UL
+#define DBR_TOGGLE_SFT 25
#define DBR_XID_MASK 0x000fffff00000000ULL
#define DBR_XID_SFT 32
#define DBR_PATH_L2 (0x1ULL << 56)
+#define DBR_VALID (0x1ULL << 58)
#define DBR_TYPE_SQ (0x0ULL << 60)
#define DBR_TYPE_RQ (0x1ULL << 60)
#define DBR_TYPE_SRQ (0x2ULL << 60)
@@ -566,6 +690,7 @@ struct nqe_cn {
#define DBR_TYPE_CQ_CUTOFF_ACK (0x9ULL << 60)
#define DBR_TYPE_NQ (0xaULL << 60)
#define DBR_TYPE_NQ_ARM (0xbULL << 60)
+#define DBR_TYPE_NQ_MASK (0xeULL << 60)
#define DBR_TYPE_NULL (0xfULL << 60)
#define DB_PF_OFFSET_P5 0x10000
@@ -661,10 +786,12 @@ struct nqe_cn {
*/
#define BNXT_MIN_TX_DESC_CNT (MAX_SKB_FRAGS + 2)
-#define RX_RING(x) (((x) & ~(RX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
+#define RX_RING(bp, x) (((x) & (bp)->rx_ring_mask) >> (BNXT_PAGE_SHIFT - 4))
+#define RX_AGG_RING(bp, x) (((x) & (bp)->rx_agg_ring_mask) >> \
+ (BNXT_PAGE_SHIFT - 4))
#define RX_IDX(x) ((x) & (RX_DESC_CNT - 1))
-#define TX_RING(x) (((x) & ~(TX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
+#define TX_RING(bp, x) (((x) & (bp)->tx_ring_mask) >> (BNXT_PAGE_SHIFT - 4))
#define TX_IDX(x) ((x) & (TX_DESC_CNT - 1))
#define CP_RING(x) (((x) & ~(CP_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
@@ -691,11 +818,14 @@ struct nqe_cn {
#define RX_CMP_TYPE(rxcmp) \
(le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_CMP_TYPE)
-#define NEXT_RX(idx) (((idx) + 1) & bp->rx_ring_mask)
+#define RING_RX(bp, idx) ((idx) & (bp)->rx_ring_mask)
+#define NEXT_RX(idx) ((idx) + 1)
-#define NEXT_RX_AGG(idx) (((idx) + 1) & bp->rx_agg_ring_mask)
+#define RING_RX_AGG(bp, idx) ((idx) & (bp)->rx_agg_ring_mask)
+#define NEXT_RX_AGG(idx) ((idx) + 1)
-#define NEXT_TX(idx) (((idx) + 1) & bp->tx_ring_mask)
+#define RING_TX(bp, idx) ((idx) & (bp)->tx_ring_mask)
+#define NEXT_TX(idx) ((idx) + 1)
#define ADV_RAW_CMP(idx, n) ((idx) + (n))
#define NEXT_RAW_CMP(idx) ADV_RAW_CMP(idx, 1)
@@ -708,6 +838,7 @@ struct nqe_cn {
#define BNXT_AGG_EVENT 2
#define BNXT_TX_EVENT 4
#define BNXT_REDIRECT_EVENT 8
+#define BNXT_TX_CMP_EVENT 0x10
struct bnxt_sw_tx_bd {
union {
@@ -736,13 +867,6 @@ struct bnxt_sw_rx_agg_bd {
dma_addr_t mapping;
};
-struct bnxt_mem_init {
- u8 init_val;
- u16 offset;
-#define BNXT_MEM_INVALID_OFFSET 0xffff
- u16 size;
-};
-
struct bnxt_ring_mem_info {
int nr_pages;
int page_size;
@@ -752,7 +876,7 @@ struct bnxt_ring_mem_info {
#define BNXT_RMEM_USE_FULL_PAGE_FLAG 4
u16 depth;
- struct bnxt_mem_init *mem_init;
+ struct bnxt_ctx_mem_type *ctx_mem;
void **pg_arr;
dma_addr_t *dma_arr;
@@ -794,13 +918,27 @@ struct bnxt_db_info {
u64 db_key64;
u32 db_key32;
};
+ u32 db_ring_mask;
+ u32 db_epoch_mask;
+ u8 db_epoch_shift;
};
+#define DB_EPOCH(db, idx) (((idx) & (db)->db_epoch_mask) << \
+ ((db)->db_epoch_shift))
+
+#define DB_TOGGLE(tgl) ((tgl) << DBR_TOGGLE_SFT)
+
+#define DB_RING_IDX(db, idx) (((idx) & (db)->db_ring_mask) | \
+ DB_EPOCH(db, idx))
+
struct bnxt_tx_ring_info {
struct bnxt_napi *bnapi;
+ struct bnxt_cp_ring_info *tx_cpr;
u16 tx_prod;
u16 tx_cons;
+ u16 tx_hw_cons;
u16 txq_index;
+ u8 tx_napi_idx;
u8 kick_pending;
struct bnxt_db_info tx_db;
@@ -895,6 +1033,8 @@ struct bnxt_tpa_info {
u16 cfa_code; /* cfa_code in TPA start compl */
u8 agg_count;
+ u8 vlan_valid:1;
+ u8 cfa_code_valid:1;
struct rx_agg_cmp *agg_arr;
};
@@ -907,6 +1047,7 @@ struct bnxt_tpa_idx_map {
struct bnxt_rx_ring_info {
struct bnxt_napi *bnapi;
+ struct bnxt_cp_ring_info *rx_cpr;
u16 rx_prod;
u16 rx_agg_prod;
u16 rx_sw_agg_prod;
@@ -986,6 +1127,11 @@ struct bnxt_cp_ring_info {
u8 had_work_done:1;
u8 has_more_work:1;
+ u8 had_nqe_notify:1;
+ u8 toggle;
+
+ u8 cp_ring_type;
+ u8 cp_idx;
u32 last_cp_raw_cons;
@@ -1010,11 +1156,18 @@ struct bnxt_cp_ring_info {
struct bnxt_ring_struct cp_ring_struct;
- struct bnxt_cp_ring_info *cp_ring_arr[2];
-#define BNXT_RX_HDL 0
-#define BNXT_TX_HDL 1
+ int cp_ring_count;
+ struct bnxt_cp_ring_info *cp_ring_arr;
};
+#define BNXT_MAX_QUEUE 8
+#define BNXT_MAX_TXR_PER_NAPI BNXT_MAX_QUEUE
+
+#define bnxt_for_each_napi_tx(iter, bnapi, txr) \
+ for (iter = 0, txr = (bnapi)->tx_ring[0]; txr; \
+ txr = (iter < BNXT_MAX_TXR_PER_NAPI - 1) ? \
+ (bnapi)->tx_ring[++iter] : NULL)
+
struct bnxt_napi {
struct napi_struct napi;
struct bnxt *bp;
@@ -1022,11 +1175,10 @@ struct bnxt_napi {
int index;
struct bnxt_cp_ring_info cp_ring;
struct bnxt_rx_ring_info *rx_ring;
- struct bnxt_tx_ring_info *tx_ring;
+ struct bnxt_tx_ring_info *tx_ring[BNXT_MAX_TXR_PER_NAPI];
void (*tx_int)(struct bnxt *, struct bnxt_napi *,
int budget);
- int tx_pkts;
u8 events;
u8 tx_fault:1;
@@ -1067,7 +1219,7 @@ struct bnxt_vnic_info {
u16 fw_rss_cos_lb_ctx[BNXT_MAX_CTX_PER_VNIC];
u16 fw_l2_ctx_id;
#define BNXT_MAX_UC_ADDRS 4
- __le64 fw_l2_filter_id[BNXT_MAX_UC_ADDRS];
+ struct bnxt_l2_filter *l2_filters[BNXT_MAX_UC_ADDRS];
/* index 0 always dev_addr */
u16 uc_filter_count;
u8 *uc_list;
@@ -1180,19 +1332,71 @@ struct bnxt_pf_info {
struct bnxt_vf_info *vf;
};
-struct bnxt_ntuple_filter {
+struct bnxt_filter_base {
struct hlist_node hash;
- u8 dst_mac_addr[ETH_ALEN];
- u8 src_mac_addr[ETH_ALEN];
- struct flow_keys fkeys;
__le64 filter_id;
+ u8 type;
+#define BNXT_FLTR_TYPE_NTUPLE 1
+#define BNXT_FLTR_TYPE_L2 2
+ u8 flags;
+#define BNXT_ACT_DROP 1
+#define BNXT_ACT_RING_DST 2
+#define BNXT_ACT_FUNC_DST 4
+#define BNXT_ACT_NO_AGING 8
u16 sw_id;
- u8 l2_fltr_idx;
u16 rxq;
- u32 flow_id;
+ u16 fw_vnic_id;
+ u16 vf_idx;
unsigned long state;
#define BNXT_FLTR_VALID 0
-#define BNXT_FLTR_UPDATE 1
+#define BNXT_FLTR_INSERTED 1
+#define BNXT_FLTR_FW_DELETED 2
+
+ struct rcu_head rcu;
+};
+
+struct bnxt_ntuple_filter {
+ struct bnxt_filter_base base;
+ struct flow_keys fkeys;
+ struct bnxt_l2_filter *l2_fltr;
+ u32 ntuple_flags;
+#define BNXT_NTUPLE_MATCH_SRC_IP 1
+#define BNXT_NTUPLE_MATCH_DST_IP 2
+#define BNXT_NTUPLE_MATCH_SRC_PORT 4
+#define BNXT_NTUPLE_MATCH_DST_PORT 8
+#define BNXT_NTUPLE_MATCH_ALL (BNXT_NTUPLE_MATCH_SRC_IP | \
+ BNXT_NTUPLE_MATCH_DST_IP | \
+ BNXT_NTUPLE_MATCH_SRC_PORT | \
+ BNXT_NTUPLE_MATCH_DST_PORT)
+ u32 flow_id;
+};
+
+struct bnxt_l2_key {
+ union {
+ struct {
+ u8 dst_mac_addr[ETH_ALEN];
+ u16 vlan;
+ };
+ u32 filter_key;
+ };
+};
+
+struct bnxt_ipv4_tuple {
+ struct flow_dissector_key_ipv4_addrs v4addrs;
+ struct flow_dissector_key_ports ports;
+};
+
+struct bnxt_ipv6_tuple {
+ struct flow_dissector_key_ipv6_addrs v6addrs;
+ struct flow_dissector_key_ports ports;
+};
+
+#define BNXT_L2_KEY_SIZE (sizeof(struct bnxt_l2_key) / 4)
+
+struct bnxt_l2_filter {
+ struct bnxt_filter_base base;
+ struct bnxt_l2_key l2_key;
+ atomic_t refcnt;
};
struct bnxt_link_info {
@@ -1214,6 +1418,7 @@ struct bnxt_link_info {
#define BNXT_LINK_STATE_DOWN 1
#define BNXT_LINK_STATE_UP 2
#define BNXT_LINK_IS_UP(bp) ((bp)->link_info.link_state == BNXT_LINK_STATE_UP)
+ u8 active_lanes;
u8 duplex;
#define BNXT_LINK_DUPLEX_HALF PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF
#define BNXT_LINK_DUPLEX_FULL PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL
@@ -1248,8 +1453,11 @@ struct bnxt_link_info {
#define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
#define BNXT_LINK_SPEED_100GB PORT_PHY_QCFG_RESP_LINK_SPEED_100GB
#define BNXT_LINK_SPEED_200GB PORT_PHY_QCFG_RESP_LINK_SPEED_200GB
+#define BNXT_LINK_SPEED_400GB PORT_PHY_QCFG_RESP_LINK_SPEED_400GB
u16 support_speeds;
u16 support_pam4_speeds;
+ u16 support_speeds2;
+
u16 auto_link_speeds; /* fw adv setting */
#define BNXT_LINK_SPEED_MSK_100MB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100MB
#define BNXT_LINK_SPEED_MSK_1GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_1GB
@@ -1265,12 +1473,52 @@ struct bnxt_link_info {
#define BNXT_LINK_PAM4_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_50G
#define BNXT_LINK_PAM4_SPEED_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_100G
#define BNXT_LINK_PAM4_SPEED_MSK_200GB PORT_PHY_QCFG_RESP_SUPPORT_PAM4_SPEEDS_200G
+ u16 auto_link_speeds2;
+#define BNXT_LINK_SPEEDS2_MSK_1GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB
+#define BNXT_LINK_SPEEDS2_MSK_10GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB
+#define BNXT_LINK_SPEEDS2_MSK_25GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_25GB
+#define BNXT_LINK_SPEEDS2_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_40GB
+#define BNXT_LINK_SPEEDS2_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB
+#define BNXT_LINK_SPEEDS2_MSK_100GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB
+#define BNXT_LINK_SPEEDS2_MSK_50GB_PAM4 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56
+#define BNXT_LINK_SPEEDS2_MSK_100GB_PAM4 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56
+#define BNXT_LINK_SPEEDS2_MSK_200GB_PAM4 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56
+#define BNXT_LINK_SPEEDS2_MSK_400GB_PAM4 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56
+#define BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112
+#define BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112
+#define BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112 \
+ PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112
+
u16 support_auto_speeds;
u16 support_pam4_auto_speeds;
+ u16 support_auto_speeds2;
+
u16 lp_auto_link_speeds;
u16 lp_auto_pam4_link_speeds;
u16 force_link_speed;
u16 force_pam4_link_speed;
+ u16 force_link_speed2;
+#define BNXT_LINK_SPEED_50GB_PAM4 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56
+#define BNXT_LINK_SPEED_100GB_PAM4 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56
+#define BNXT_LINK_SPEED_200GB_PAM4 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56
+#define BNXT_LINK_SPEED_400GB_PAM4 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56
+#define BNXT_LINK_SPEED_100GB_PAM4_112 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112
+#define BNXT_LINK_SPEED_200GB_PAM4_112 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112
+#define BNXT_LINK_SPEED_400GB_PAM4_112 \
+ PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112
+
u32 preemphasis;
u8 module_status;
u8 active_fec_sig_mode;
@@ -1301,6 +1549,7 @@ struct bnxt_link_info {
u8 req_signal_mode;
#define BNXT_SIG_MODE_NRZ PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ
#define BNXT_SIG_MODE_PAM4 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4
+#define BNXT_SIG_MODE_PAM4_112 PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112
#define BNXT_SIG_MODE_MAX (PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST + 1)
u8 req_duplex;
u8 req_flow_ctrl;
@@ -1361,8 +1610,6 @@ struct bnxt_link_info {
(PORT_PHY_CFG_REQ_FLAGS_FEC_CLAUSE74_DISABLE | \
BNXT_FEC_RS_OFF(link_info))
-#define BNXT_MAX_QUEUE 8
-
struct bnxt_queue_info {
u8 queue_id;
u8 queue_profile;
@@ -1391,7 +1638,7 @@ struct bnxt_test_info {
};
#define CHIMP_REG_VIEW_ADDR \
- ((bp->flags & BNXT_FLAG_CHIP_P5) ? 0x80000000 : 0xb1000000)
+ ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) ? 0x80000000 : 0xb1000000)
#define BNXT_GRCPF_REG_CHIMP_COMM 0x0
#define BNXT_GRCPF_REG_CHIMP_COMM_TRIGGER 0x100
@@ -1515,53 +1762,73 @@ do { \
attr = FUNC_BACKING_STORE_CFG_REQ_QPC_PG_SIZE_PG_4K; \
} while (0)
+struct bnxt_ctx_mem_type {
+ u16 type;
+ u16 entry_size;
+ u32 flags;
+#define BNXT_CTX_MEM_TYPE_VALID FUNC_BACKING_STORE_QCAPS_V2_RESP_FLAGS_TYPE_VALID
+ u32 instance_bmap;
+ u8 init_value;
+ u8 entry_multiple;
+ u16 init_offset;
+#define BNXT_CTX_INIT_INVALID_OFFSET 0xffff
+ u32 max_entries;
+ u32 min_entries;
+ u8 last:1;
+ u8 split_entry_cnt;
+#define BNXT_MAX_SPLIT_ENTRY 4
+ union {
+ struct {
+ u32 qp_l2_entries;
+ u32 qp_qp1_entries;
+ u32 qp_fast_qpmd_entries;
+ };
+ u32 srq_l2_entries;
+ u32 cq_l2_entries;
+ u32 vnic_entries;
+ struct {
+ u32 mrav_av_entries;
+ u32 mrav_num_entries_units;
+ };
+ u32 split[BNXT_MAX_SPLIT_ENTRY];
+ };
+ struct bnxt_ctx_pg_info *pg_info;
+};
+
+#define BNXT_CTX_MRAV_AV_SPLIT_ENTRY 0
+
+#define BNXT_CTX_QP FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QP
+#define BNXT_CTX_SRQ FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRQ
+#define BNXT_CTX_CQ FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CQ
+#define BNXT_CTX_VNIC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_VNIC
+#define BNXT_CTX_STAT FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_STAT
+#define BNXT_CTX_STQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SP_TQM_RING
+#define BNXT_CTX_FTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_FP_TQM_RING
+#define BNXT_CTX_MRAV FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MRAV
+#define BNXT_CTX_TIM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TIM
+#define BNXT_CTX_TKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TKC
+#define BNXT_CTX_RKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RKC
+#define BNXT_CTX_MTQM FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MP_TQM_RING
+#define BNXT_CTX_SQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SQ_DB_SHADOW
+#define BNXT_CTX_RQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RQ_DB_SHADOW
+#define BNXT_CTX_SRQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SRQ_DB_SHADOW
+#define BNXT_CTX_CQDBS FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_CQ_DB_SHADOW
+#define BNXT_CTX_QTKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_TKC
+#define BNXT_CTX_QRKC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_QUIC_RKC
+#define BNXT_CTX_TBLSC FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TBL_SCOPE
+#define BNXT_CTX_XPAR FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_XID_PARTITION
+
+#define BNXT_CTX_MAX (BNXT_CTX_TIM + 1)
+#define BNXT_CTX_L2_MAX (BNXT_CTX_FTQM + 1)
+#define BNXT_CTX_V2_MAX (BNXT_CTX_XPAR + 1)
+#define BNXT_CTX_INV ((u16)-1)
+
struct bnxt_ctx_mem_info {
- u32 qp_max_entries;
- u16 qp_min_qp1_entries;
- u16 qp_max_l2_entries;
- u16 qp_entry_size;
- u16 srq_max_l2_entries;
- u32 srq_max_entries;
- u16 srq_entry_size;
- u16 cq_max_l2_entries;
- u32 cq_max_entries;
- u16 cq_entry_size;
- u16 vnic_max_vnic_entries;
- u16 vnic_max_ring_table_entries;
- u16 vnic_entry_size;
- u32 stat_max_entries;
- u16 stat_entry_size;
- u16 tqm_entry_size;
- u32 tqm_min_entries_per_ring;
- u32 tqm_max_entries_per_ring;
- u32 mrav_max_entries;
- u16 mrav_entry_size;
- u16 tim_entry_size;
- u32 tim_max_entries;
- u16 mrav_num_entries_units;
- u8 tqm_entries_multiple;
u8 tqm_fp_rings_count;
u32 flags;
#define BNXT_CTX_FLAG_INITED 0x01
-
- struct bnxt_ctx_pg_info qp_mem;
- struct bnxt_ctx_pg_info srq_mem;
- struct bnxt_ctx_pg_info cq_mem;
- struct bnxt_ctx_pg_info vnic_mem;
- struct bnxt_ctx_pg_info stat_mem;
- struct bnxt_ctx_pg_info mrav_mem;
- struct bnxt_ctx_pg_info tim_mem;
- struct bnxt_ctx_pg_info *tqm_mem[BNXT_MAX_TQM_RINGS];
-
-#define BNXT_CTX_MEM_INIT_QP 0
-#define BNXT_CTX_MEM_INIT_SRQ 1
-#define BNXT_CTX_MEM_INIT_CQ 2
-#define BNXT_CTX_MEM_INIT_VNIC 3
-#define BNXT_CTX_MEM_INIT_STAT 4
-#define BNXT_CTX_MEM_INIT_MRAV 5
-#define BNXT_CTX_MEM_INIT_MAX 6
- struct bnxt_mem_init mem_init[BNXT_CTX_MEM_INIT_MAX];
+ struct bnxt_ctx_mem_type ctx_arr[BNXT_CTX_V2_MAX];
};
enum bnxt_health_severity {
@@ -1697,6 +1964,10 @@ enum board_idx {
BCM57508_NPAR,
BCM57504_NPAR,
BCM57502_NPAR,
+ BCM57608,
+ BCM57604,
+ BCM57602,
+ BCM57601,
BCM58802,
BCM58804,
BCM58808,
@@ -1744,14 +2015,14 @@ struct bnxt {
#define CHIP_NUM_57504 0x1751
#define CHIP_NUM_57502 0x1752
+#define CHIP_NUM_57608 0x1760
+
#define CHIP_NUM_58802 0xd802
#define CHIP_NUM_58804 0xd804
#define CHIP_NUM_58808 0xd808
u8 chip_rev;
-#define CHIP_NUM_58818 0xd818
-
#define BNXT_CHIP_NUM_5730X(chip_num) \
((chip_num) >= CHIP_NUM_57301 && \
(chip_num) <= CHIP_NUM_57304)
@@ -1801,7 +2072,7 @@ struct bnxt {
atomic_t intr_sem;
u32 flags;
- #define BNXT_FLAG_CHIP_P5 0x1
+ #define BNXT_FLAG_CHIP_P5_PLUS 0x1
#define BNXT_FLAG_VF 0x2
#define BNXT_FLAG_LRO 0x4
#ifdef CONFIG_INET
@@ -1820,8 +2091,6 @@ struct bnxt {
#define BNXT_FLAG_RFS 0x100
#define BNXT_FLAG_SHARED_RINGS 0x200
#define BNXT_FLAG_PORT_STATS 0x400
- #define BNXT_FLAG_UDP_RSS_CAP 0x800
- #define BNXT_FLAG_NEW_RSS_CAP 0x2000
#define BNXT_FLAG_WOL_CAP 0x4000
#define BNXT_FLAG_ROCEV1_CAP 0x8000
#define BNXT_FLAG_ROCEV2_CAP 0x10000
@@ -1829,13 +2098,15 @@ struct bnxt {
BNXT_FLAG_ROCEV2_CAP)
#define BNXT_FLAG_NO_AGG_RINGS 0x20000
#define BNXT_FLAG_RX_PAGE_MODE 0x40000
- #define BNXT_FLAG_CHIP_SR2 0x80000
+ #define BNXT_FLAG_CHIP_P7 0x80000
#define BNXT_FLAG_MULTI_HOST 0x100000
#define BNXT_FLAG_DSN_VALID 0x200000
#define BNXT_FLAG_DOUBLE_DB 0x400000
+ #define BNXT_FLAG_UDP_GSO_CAP 0x800000
#define BNXT_FLAG_CHIP_NITRO_A0 0x1000000
#define BNXT_FLAG_DIM 0x2000000
#define BNXT_FLAG_ROCE_MIRROR_CAP 0x4000000
+ #define BNXT_FLAG_TX_COAL_CMPL 0x8000000
#define BNXT_FLAG_PORT_STATS_EXT 0x10000000
#define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \
@@ -1855,21 +2126,21 @@ struct bnxt {
#define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0)
#define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE)
#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_TYPE_NITRO_A0(bp) && \
- (!((bp)->flags & BNXT_FLAG_CHIP_P5) || \
+ (!((bp)->flags & BNXT_FLAG_CHIP_P5_PLUS) ||\
(bp)->max_tpa_v2) && !is_kdump_kernel())
#define BNXT_RX_JUMBO_MODE(bp) ((bp)->flags & BNXT_FLAG_JUMBO)
-#define BNXT_CHIP_SR2(bp) \
- ((bp)->chip_num == CHIP_NUM_58818)
+#define BNXT_CHIP_P7(bp) \
+ ((bp)->chip_num == CHIP_NUM_57608)
-#define BNXT_CHIP_P5_THOR(bp) \
+#define BNXT_CHIP_P5(bp) \
((bp)->chip_num == CHIP_NUM_57508 || \
(bp)->chip_num == CHIP_NUM_57504 || \
(bp)->chip_num == CHIP_NUM_57502)
/* Chip class phase 5 */
-#define BNXT_CHIP_P5(bp) \
- (BNXT_CHIP_P5_THOR(bp) || BNXT_CHIP_SR2(bp))
+#define BNXT_CHIP_P5_PLUS(bp) \
+ (BNXT_CHIP_P5(bp) || BNXT_CHIP_P7(bp))
/* Chip class phase 4.x */
#define BNXT_CHIP_P4(bp) \
@@ -1880,7 +2151,7 @@ struct bnxt {
!BNXT_CHIP_TYPE_NITRO_A0(bp)))
#define BNXT_CHIP_P4_PLUS(bp) \
- (BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp))
+ (BNXT_CHIP_P4(bp) || BNXT_CHIP_P5_PLUS(bp))
struct bnxt_aux_priv *aux_priv;
struct bnxt_en_dev *edev;
@@ -1941,6 +2212,11 @@ struct bnxt {
u16 rss_indir_tbl_entries;
u32 rss_hash_cfg;
u32 rss_hash_delta;
+ u32 rss_cap;
+#define BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA BIT(0)
+#define BNXT_RSS_CAP_UDP_RSS_CAP BIT(1)
+#define BNXT_RSS_CAP_NEW_RSS_CAP BIT(2)
+#define BNXT_RSS_CAP_RSS_TCAM BIT(3)
u16 max_mtu;
u8 max_tc;
@@ -1949,6 +2225,7 @@ struct bnxt {
u8 tc_to_qidx[BNXT_MAX_QUEUE];
u8 q_ids[BNXT_MAX_QUEUE];
u8 max_q;
+ u8 num_tc;
unsigned int current_interval;
#define BNXT_TIMER_INTERVAL HZ
@@ -2006,7 +2283,6 @@ struct bnxt {
#define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 BIT_ULL(16)
#define BNXT_FW_CAP_PCIE_STATS_SUPPORTED BIT_ULL(17)
#define BNXT_FW_CAP_EXT_STATS_SUPPORTED BIT_ULL(18)
- #define BNXT_FW_CAP_RSS_HASH_TYPE_DELTA BIT_ULL(19)
#define BNXT_FW_CAP_ERR_RECOVER_RELOAD BIT_ULL(20)
#define BNXT_FW_CAP_HOT_RESET BIT_ULL(21)
#define BNXT_FW_CAP_PTP_RTC BIT_ULL(22)
@@ -2023,6 +2299,8 @@ struct bnxt {
#define BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED BIT_ULL(33)
#define BNXT_FW_CAP_DFLT_VLAN_TPID_PCP BIT_ULL(34)
#define BNXT_FW_CAP_PRE_RESV_VNICS BIT_ULL(35)
+ #define BNXT_FW_CAP_BACKING_STORE_V2 BIT_ULL(36)
+ #define BNXT_FW_CAP_VNIC_TUNNEL_TPA BIT_ULL(37)
u32 fw_dbg_cap;
@@ -2067,8 +2345,10 @@ struct bnxt {
u16 vxlan_fw_dst_port_id;
u16 nge_fw_dst_port_id;
+ u16 vxlan_gpe_fw_dst_port_id;
__be16 vxlan_port;
__be16 nge_port;
+ __be16 vxlan_gpe_port;
u8 port_partition_type;
u8 port_count;
u16 br_mode;
@@ -2136,9 +2416,11 @@ struct bnxt {
/* ensure atomic 64-bit doorbell writes on 32-bit systems. */
spinlock_t db_lock;
#endif
+ int db_offset; /* db_offset within db_size */
int db_size;
#define BNXT_NTP_FLTR_MAX_FLTR 4096
+#define BNXT_MAX_FLTR (BNXT_NTP_FLTR_MAX_FLTR + BNXT_L2_FLTR_MAX_FLTR)
#define BNXT_NTP_FLTR_HASH_SIZE 512
#define BNXT_NTP_FLTR_HASH_MASK (BNXT_NTP_FLTR_HASH_SIZE - 1)
struct hlist_head ntp_fltr_hash_tbl[BNXT_NTP_FLTR_HASH_SIZE];
@@ -2147,6 +2429,14 @@ struct bnxt {
unsigned long *ntp_fltr_bmap;
int ntp_fltr_count;
+#define BNXT_L2_FLTR_MAX_FLTR 1024
+#define BNXT_L2_FLTR_HASH_SIZE 32
+#define BNXT_L2_FLTR_HASH_MASK (BNXT_L2_FLTR_HASH_SIZE - 1)
+ struct hlist_head l2_fltr_hash_tbl[BNXT_L2_FLTR_HASH_SIZE];
+
+ u32 hash_seed;
+ u64 toeplitz_prefix;
+
/* To protect link related settings during link changes and
* ethtool settings changes.
*/
@@ -2169,6 +2459,7 @@ struct bnxt {
#define BNXT_PHY_FL_NO_PAUSE (PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED << 8)
#define BNXT_PHY_FL_NO_PFC (PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED << 8)
#define BNXT_PHY_FL_BANK_SEL (PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED << 8)
+#define BNXT_PHY_FL_SPEEDS2 (PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED << 8)
u8 num_tests;
struct bnxt_test_info *test_info;
@@ -2212,15 +2503,15 @@ struct bnxt {
#define BNXT_NUM_TX_RING_STATS 8
#define BNXT_NUM_TPA_RING_STATS 4
#define BNXT_NUM_TPA_RING_STATS_P5 5
-#define BNXT_NUM_TPA_RING_STATS_P5_SR2 6
+#define BNXT_NUM_TPA_RING_STATS_P7 6
#define BNXT_RING_STATS_SIZE_P5 \
((BNXT_NUM_RX_RING_STATS + BNXT_NUM_TX_RING_STATS + \
BNXT_NUM_TPA_RING_STATS_P5) * 8)
-#define BNXT_RING_STATS_SIZE_P5_SR2 \
+#define BNXT_RING_STATS_SIZE_P7 \
((BNXT_NUM_RX_RING_STATS + BNXT_NUM_TX_RING_STATS + \
- BNXT_NUM_TPA_RING_STATS_P5_SR2) * 8)
+ BNXT_NUM_TPA_RING_STATS_P7) * 8)
#define BNXT_GET_RING_STATS64(sw, counter) \
(*((sw) + offsetof(struct ctx_hw_stats, counter) / 8))
@@ -2303,10 +2594,11 @@ static inline void bnxt_writeq_relaxed(struct bnxt *bp, u64 val,
static inline void bnxt_db_write_relaxed(struct bnxt *bp,
struct bnxt_db_info *db, u32 idx)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- bnxt_writeq_relaxed(bp, db->db_key64 | idx, db->doorbell);
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ bnxt_writeq_relaxed(bp, db->db_key64 | DB_RING_IDX(db, idx),
+ db->doorbell);
} else {
- u32 db_val = db->db_key32 | idx;
+ u32 db_val = db->db_key32 | DB_RING_IDX(db, idx);
writel_relaxed(db_val, db->doorbell);
if (bp->flags & BNXT_FLAG_DOUBLE_DB)
@@ -2318,10 +2610,11 @@ static inline void bnxt_db_write_relaxed(struct bnxt *bp,
static inline void bnxt_db_write(struct bnxt *bp, struct bnxt_db_info *db,
u32 idx)
{
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- bnxt_writeq(bp, db->db_key64 | idx, db->doorbell);
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
+ bnxt_writeq(bp, db->db_key64 | DB_RING_IDX(db, idx),
+ db->doorbell);
} else {
- u32 db_val = db->db_key32 | idx;
+ u32 db_val = db->db_key32 | DB_RING_IDX(db, idx);
writel(db_val, db->doorbell);
if (bp->flags & BNXT_FLAG_DOUBLE_DB)
@@ -2351,12 +2644,21 @@ int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode);
int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap,
int bmap_size, bool async_only);
int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp);
+void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr);
+int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr);
+int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr);
+int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr);
+int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr);
+void bnxt_fill_ipv6_mask(__be32 mask[4]);
int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings);
int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id);
int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings);
int bnxt_nq_rings_in_use(struct bnxt *bp);
int bnxt_hwrm_set_coal(struct bnxt *);
void bnxt_free_ctx_mem(struct bnxt *bp);
+int bnxt_num_tx_to_cp(struct bnxt *bp, int tx);
unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp);
unsigned int bnxt_get_avail_stat_ctxs_for_en(struct bnxt *bp);
unsigned int bnxt_get_max_func_cp_rings(struct bnxt *bp);
@@ -2366,7 +2668,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init);
void bnxt_tx_disable(struct bnxt *bp);
void bnxt_tx_enable(struct bnxt *bp);
void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
- int idx);
+ u16 curr);
void bnxt_report_link(struct bnxt *bp);
int bnxt_update_link(struct bnxt *bp, bool chng_link_state);
int bnxt_hwrm_set_pause(struct bnxt *);
@@ -2393,6 +2695,13 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
int bnxt_fw_init_one(struct bnxt *bp);
bool bnxt_hwrm_reset_permitted(struct bnxt *bp);
int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
+struct bnxt_ntuple_filter *bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp,
+ struct bnxt_ntuple_filter *fltr, u32 idx);
+u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys,
+ const struct sk_buff *skb);
+int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr,
+ u32 idx);
+void bnxt_del_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr);
int bnxt_get_max_rings(struct bnxt *, int *, int *, bool);
int bnxt_restore_pf_fw_resources(struct bnxt *bp);
int bnxt_get_port_parent_id(struct net_device *dev,
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
index 63e067038385..0dbb880a7aa0 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
@@ -228,7 +228,7 @@ static int bnxt_queue_remap(struct bnxt *bp, unsigned int lltc_mask)
}
}
if (bp->ieee_ets) {
- int tc = netdev_get_num_tc(bp->dev);
+ int tc = bp->num_tc;
if (!tc)
tc = 1;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
index 89809f1b129c..ae4529c043f0 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
@@ -462,8 +462,6 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
}
bnxt_cancel_reservations(bp, false);
bnxt_free_ctx_mem(bp);
- kfree(bp->ctx);
- bp->ctx = NULL;
break;
}
case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: {
@@ -734,7 +732,7 @@ static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver)
}
/* earlier devices present as an array of raw bytes */
- if (!BNXT_CHIP_P5(bp)) {
+ if (!BNXT_CHIP_P5_PLUS(bp)) {
dim = 0;
i = 0;
bits *= 3; /* array of 3 version components */
@@ -754,7 +752,7 @@ static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver)
goto exit;
bnxt_copy_from_nvm_data(&ver, data, bits, bytes);
- if (BNXT_CHIP_P5(bp)) {
+ if (BNXT_CHIP_P5_PLUS(bp)) {
*nvm_cfg_ver <<= 8;
*nvm_cfg_ver |= ver.vu8;
} else {
@@ -774,7 +772,7 @@ static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req,
if (!strlen(buf))
return 0;
- if ((bp->flags & BNXT_FLAG_CHIP_P5) &&
+ if ((bp->flags & BNXT_FLAG_CHIP_P5_PLUS) &&
(!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) ||
!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE)))
return 0;
@@ -1000,7 +998,7 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
if (rc)
return rc;
- if (BNXT_CHIP_P5(bp)) {
+ if (BNXT_CHIP_P5_PLUS(bp)) {
rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
if (rc)
return rc;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index 5f67a7f94e7d..dc4ca706b0e2 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -460,6 +460,7 @@ static const struct {
BNXT_RX_STATS_EXT_DISCARD_COS_ENTRIES,
BNXT_RX_STATS_EXT_ENTRY(rx_fec_corrected_blocks),
BNXT_RX_STATS_EXT_ENTRY(rx_fec_uncorrectable_blocks),
+ BNXT_RX_STATS_EXT_ENTRY(rx_filter_miss),
};
static const struct {
@@ -510,9 +511,9 @@ static int bnxt_get_num_tpa_ring_stats(struct bnxt *bp)
{
if (BNXT_SUPPORTS_TPA(bp)) {
if (bp->max_tpa_v2) {
- if (BNXT_CHIP_P5_THOR(bp))
+ if (BNXT_CHIP_P5(bp))
return BNXT_NUM_TPA_RING_STATS_P5;
- return BNXT_NUM_TPA_RING_STATS_P5_SR2;
+ return BNXT_NUM_TPA_RING_STATS_P7;
}
return BNXT_NUM_TPA_RING_STATS;
}
@@ -527,7 +528,8 @@ static int bnxt_get_num_ring_stats(struct bnxt *bp)
bnxt_get_num_tpa_ring_stats(bp);
tx = NUM_RING_TX_HW_STATS;
cmn = NUM_RING_CMN_SW_STATS;
- return rx * bp->rx_nr_rings + tx * bp->tx_nr_rings +
+ return rx * bp->rx_nr_rings +
+ tx * (bp->tx_nr_rings_xdp + bp->tx_nr_rings_per_tc) +
cmn * bp->cp_nr_rings;
}
@@ -882,7 +884,7 @@ static void bnxt_get_channels(struct net_device *dev,
if (max_tx_sch_inputs)
max_tx_rings = min_t(int, max_tx_rings, max_tx_sch_inputs);
- tcs = netdev_get_num_tc(dev);
+ tcs = bp->num_tc;
tx_grps = max(tcs, 1);
if (bp->tx_nr_rings_xdp)
tx_grps++;
@@ -922,6 +924,7 @@ static int bnxt_set_channels(struct net_device *dev,
bool sh = false;
int tx_xdp = 0;
int rc = 0;
+ int tx_cp;
if (channel->other_count)
return -EINVAL;
@@ -941,7 +944,7 @@ static int bnxt_set_channels(struct net_device *dev,
if (channel->combined_count)
sh = true;
- tcs = netdev_get_num_tc(dev);
+ tcs = bp->num_tc;
req_tx_rings = sh ? channel->combined_count : channel->tx_count;
req_rx_rings = sh ? channel->combined_count : channel->rx_count;
@@ -988,8 +991,9 @@ static int bnxt_set_channels(struct net_device *dev,
if (tcs > 1)
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
- bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
- bp->tx_nr_rings + bp->rx_nr_rings;
+ tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+ bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) :
+ tx_cp + bp->rx_nr_rings;
/* After changing number of rx channels, update NTUPLE feature. */
netdev_update_features(dev);
@@ -1007,29 +1011,60 @@ static int bnxt_set_channels(struct net_device *dev,
return rc;
}
-#ifdef CONFIG_RFS_ACCEL
-static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
- u32 *rule_locs)
+static u32 bnxt_get_all_fltr_ids_rcu(struct bnxt *bp, struct hlist_head tbl[],
+ int tbl_size, u32 *ids, u32 start,
+ u32 id_cnt)
{
- int i, j = 0;
+ int i, j = start;
- cmd->data = bp->ntp_fltr_count;
- for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
+ if (j >= id_cnt)
+ return j;
+ for (i = 0; i < tbl_size; i++) {
struct hlist_head *head;
- struct bnxt_ntuple_filter *fltr;
+ struct bnxt_filter_base *fltr;
- head = &bp->ntp_fltr_hash_tbl[i];
- rcu_read_lock();
+ head = &tbl[i];
hlist_for_each_entry_rcu(fltr, head, hash) {
- if (j == cmd->rule_cnt)
- break;
- rule_locs[j++] = fltr->sw_id;
+ if (!fltr->flags ||
+ test_bit(BNXT_FLTR_FW_DELETED, &fltr->state))
+ continue;
+ ids[j++] = fltr->sw_id;
+ if (j == id_cnt)
+ return j;
+ }
+ }
+ return j;
+}
+
+static struct bnxt_filter_base *bnxt_get_one_fltr_rcu(struct bnxt *bp,
+ struct hlist_head tbl[],
+ int tbl_size, u32 id)
+{
+ int i;
+
+ for (i = 0; i < tbl_size; i++) {
+ struct hlist_head *head;
+ struct bnxt_filter_base *fltr;
+
+ head = &tbl[i];
+ hlist_for_each_entry_rcu(fltr, head, hash) {
+ if (fltr->flags && fltr->sw_id == id)
+ return fltr;
}
- rcu_read_unlock();
- if (j == cmd->rule_cnt)
- break;
}
- cmd->rule_cnt = j;
+ return NULL;
+}
+
+static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
+ u32 *rule_locs)
+{
+ cmd->data = bp->ntp_fltr_count;
+ rcu_read_lock();
+ cmd->rule_cnt = bnxt_get_all_fltr_ids_rcu(bp, bp->ntp_fltr_hash_tbl,
+ BNXT_NTP_FLTR_HASH_SIZE,
+ rule_locs, 0, cmd->rule_cnt);
+ rcu_read_unlock();
+
return 0;
}
@@ -1037,27 +1072,24 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fs =
(struct ethtool_rx_flow_spec *)&cmd->fs;
+ struct bnxt_filter_base *fltr_base;
struct bnxt_ntuple_filter *fltr;
struct flow_keys *fkeys;
- int i, rc = -EINVAL;
+ int rc = -EINVAL;
if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
return rc;
- for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
- struct hlist_head *head;
-
- head = &bp->ntp_fltr_hash_tbl[i];
- rcu_read_lock();
- hlist_for_each_entry_rcu(fltr, head, hash) {
- if (fltr->sw_id == fs->location)
- goto fltr_found;
- }
+ rcu_read_lock();
+ fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl,
+ BNXT_NTP_FLTR_HASH_SIZE,
+ fs->location);
+ if (!fltr_base) {
rcu_read_unlock();
+ return rc;
}
- return rc;
+ fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base);
-fltr_found:
fkeys = &fltr->fkeys;
if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
if (fkeys->basic.ip_proto == IPPROTO_TCP)
@@ -1067,20 +1099,23 @@ fltr_found:
else
goto fltr_err;
- fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
- fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
-
- fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
- fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
-
- fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
- fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
-
- fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
- fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) {
+ fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
+ fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) {
+ fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
+ fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) {
+ fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
+ fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) {
+ fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
+ fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
+ }
} else {
- int i;
-
if (fkeys->basic.ip_proto == IPPROTO_TCP)
fs->flow_type = TCP_V6_FLOW;
else if (fkeys->basic.ip_proto == IPPROTO_UDP)
@@ -1088,22 +1123,27 @@ fltr_found:
else
goto fltr_err;
- *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
- fkeys->addrs.v6addrs.src;
- *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
- fkeys->addrs.v6addrs.dst;
- for (i = 0; i < 4; i++) {
- fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0);
- fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0);
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) {
+ *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
+ fkeys->addrs.v6addrs.src;
+ bnxt_fill_ipv6_mask(fs->m_u.tcp_ip6_spec.ip6src);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) {
+ *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
+ fkeys->addrs.v6addrs.dst;
+ bnxt_fill_ipv6_mask(fs->m_u.tcp_ip6_spec.ip6dst);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) {
+ fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
+ fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0);
+ }
+ if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) {
+ fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
+ fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0);
}
- fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
- fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0);
-
- fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
- fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0);
}
- fs->ring_cookie = fltr->rxq;
+ fs->ring_cookie = fltr->base.rxq;
rc = 0;
fltr_err:
@@ -1111,7 +1151,221 @@ fltr_err:
return rc;
}
-#endif
+
+#define IPV4_ALL_MASK ((__force __be32)~0)
+#define L4_PORT_ALL_MASK ((__force __be16)~0)
+
+static bool ipv6_mask_is_full(__be32 mask[4])
+{
+ return (mask[0] & mask[1] & mask[2] & mask[3]) == IPV4_ALL_MASK;
+}
+
+static bool ipv6_mask_is_zero(__be32 mask[4])
+{
+ return !(mask[0] | mask[1] | mask[2] | mask[3]);
+}
+
+static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
+ struct ethtool_rx_flow_spec *fs)
+{
+ u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
+ u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
+ struct bnxt_ntuple_filter *new_fltr, *fltr;
+ struct bnxt_l2_filter *l2_fltr;
+ u32 flow_type = fs->flow_type;
+ struct flow_keys *fkeys;
+ u32 idx;
+ int rc;
+
+ if (!bp->vnic_info)
+ return -EAGAIN;
+
+ if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf)
+ return -EOPNOTSUPP;
+
+ new_fltr = kzalloc(sizeof(*new_fltr), GFP_KERNEL);
+ if (!new_fltr)
+ return -ENOMEM;
+
+ l2_fltr = bp->vnic_info[0].l2_filters[0];
+ atomic_inc(&l2_fltr->refcnt);
+ new_fltr->l2_fltr = l2_fltr;
+ fkeys = &new_fltr->fkeys;
+
+ rc = -EOPNOTSUPP;
+ switch (flow_type) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW: {
+ struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec;
+ struct ethtool_tcpip4_spec *ip_mask = &fs->m_u.tcp_ip4_spec;
+
+ fkeys->basic.ip_proto = IPPROTO_TCP;
+ if (flow_type == UDP_V4_FLOW)
+ fkeys->basic.ip_proto = IPPROTO_UDP;
+ fkeys->basic.n_proto = htons(ETH_P_IP);
+
+ if (ip_mask->ip4src == IPV4_ALL_MASK) {
+ fkeys->addrs.v4addrs.src = ip_spec->ip4src;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_IP;
+ } else if (ip_mask->ip4src) {
+ goto ntuple_err;
+ }
+ if (ip_mask->ip4dst == IPV4_ALL_MASK) {
+ fkeys->addrs.v4addrs.dst = ip_spec->ip4dst;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_IP;
+ } else if (ip_mask->ip4dst) {
+ goto ntuple_err;
+ }
+
+ if (ip_mask->psrc == L4_PORT_ALL_MASK) {
+ fkeys->ports.src = ip_spec->psrc;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_PORT;
+ } else if (ip_mask->psrc) {
+ goto ntuple_err;
+ }
+ if (ip_mask->pdst == L4_PORT_ALL_MASK) {
+ fkeys->ports.dst = ip_spec->pdst;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_PORT;
+ } else if (ip_mask->pdst) {
+ goto ntuple_err;
+ }
+ break;
+ }
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW: {
+ struct ethtool_tcpip6_spec *ip_spec = &fs->h_u.tcp_ip6_spec;
+ struct ethtool_tcpip6_spec *ip_mask = &fs->m_u.tcp_ip6_spec;
+
+ fkeys->basic.ip_proto = IPPROTO_TCP;
+ if (flow_type == UDP_V6_FLOW)
+ fkeys->basic.ip_proto = IPPROTO_UDP;
+ fkeys->basic.n_proto = htons(ETH_P_IPV6);
+
+ if (ipv6_mask_is_full(ip_mask->ip6src)) {
+ fkeys->addrs.v6addrs.src =
+ *(struct in6_addr *)&ip_spec->ip6src;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_IP;
+ } else if (!ipv6_mask_is_zero(ip_mask->ip6src)) {
+ goto ntuple_err;
+ }
+ if (ipv6_mask_is_full(ip_mask->ip6dst)) {
+ fkeys->addrs.v6addrs.dst =
+ *(struct in6_addr *)&ip_spec->ip6dst;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_IP;
+ } else if (!ipv6_mask_is_zero(ip_mask->ip6dst)) {
+ goto ntuple_err;
+ }
+
+ if (ip_mask->psrc == L4_PORT_ALL_MASK) {
+ fkeys->ports.src = ip_spec->psrc;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_PORT;
+ } else if (ip_mask->psrc) {
+ goto ntuple_err;
+ }
+ if (ip_mask->pdst == L4_PORT_ALL_MASK) {
+ fkeys->ports.dst = ip_spec->pdst;
+ new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_PORT;
+ } else if (ip_mask->pdst) {
+ goto ntuple_err;
+ }
+ break;
+ }
+ default:
+ rc = -EOPNOTSUPP;
+ goto ntuple_err;
+ }
+ if (!new_fltr->ntuple_flags)
+ goto ntuple_err;
+
+ idx = bnxt_get_ntp_filter_idx(bp, fkeys, NULL);
+ rcu_read_lock();
+ fltr = bnxt_lookup_ntp_filter_from_idx(bp, new_fltr, idx);
+ if (fltr) {
+ rcu_read_unlock();
+ rc = -EEXIST;
+ goto ntuple_err;
+ }
+ rcu_read_unlock();
+
+ new_fltr->base.rxq = ring;
+ new_fltr->base.flags = BNXT_ACT_NO_AGING;
+ __set_bit(BNXT_FLTR_VALID, &new_fltr->base.state);
+ rc = bnxt_insert_ntp_filter(bp, new_fltr, idx);
+ if (!rc) {
+ rc = bnxt_hwrm_cfa_ntuple_filter_alloc(bp, new_fltr);
+ if (rc) {
+ bnxt_del_ntp_filter(bp, new_fltr);
+ return rc;
+ }
+ fs->location = new_fltr->base.sw_id;
+ return 0;
+ }
+
+ntuple_err:
+ atomic_dec(&l2_fltr->refcnt);
+ kfree(new_fltr);
+ return rc;
+}
+
+static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd)
+{
+ struct ethtool_rx_flow_spec *fs = &cmd->fs;
+ u32 ring, flow_type;
+ int rc;
+ u8 vf;
+
+ if (!netif_running(bp->dev))
+ return -EAGAIN;
+ if (!(bp->flags & BNXT_FLAG_RFS))
+ return -EPERM;
+ if (fs->location != RX_CLS_LOC_ANY)
+ return -EINVAL;
+
+ ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
+ vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
+ if (BNXT_VF(bp) && vf)
+ return -EINVAL;
+ if (BNXT_PF(bp) && vf > bp->pf.active_vfs)
+ return -EINVAL;
+ if (!vf && ring >= bp->rx_nr_rings)
+ return -EINVAL;
+
+ flow_type = fs->flow_type;
+ if (flow_type & (FLOW_MAC_EXT | FLOW_RSS))
+ return -EINVAL;
+ flow_type &= ~FLOW_EXT;
+ if (flow_type == ETHER_FLOW)
+ rc = -EOPNOTSUPP;
+ else
+ rc = bnxt_add_ntuple_cls_rule(bp, fs);
+ return rc;
+}
+
+static int bnxt_srxclsrldel(struct bnxt *bp, struct ethtool_rxnfc *cmd)
+{
+ struct ethtool_rx_flow_spec *fs = &cmd->fs;
+ struct bnxt_filter_base *fltr_base;
+ struct bnxt_ntuple_filter *fltr;
+
+ rcu_read_lock();
+ fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl,
+ BNXT_NTP_FLTR_HASH_SIZE,
+ fs->location);
+ if (!fltr_base) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+
+ fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base);
+ if (!(fltr->base.flags & BNXT_ACT_NO_AGING)) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ rcu_read_unlock();
+ bnxt_hwrm_cfa_ntuple_filter_free(bp, fltr);
+ bnxt_del_ntp_filter(bp, fltr);
+ return 0;
+}
static u64 get_ethtool_ipv4_rss(struct bnxt *bp)
{
@@ -1194,7 +1448,7 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
} else if (cmd->flow_type == UDP_V4_FLOW) {
- if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
+ if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP))
return -EINVAL;
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
if (tuple == 4)
@@ -1204,7 +1458,7 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
} else if (cmd->flow_type == UDP_V6_FLOW) {
- if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
+ if (tuple == 4 && !(bp->rss_cap & BNXT_RSS_CAP_UDP_RSS_CAP))
return -EINVAL;
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
if (tuple == 4)
@@ -1244,7 +1498,7 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
if (bp->rss_hash_cfg == rss_hash_cfg)
return 0;
- if (bp->fw_cap & BNXT_FW_CAP_RSS_HASH_TYPE_DELTA)
+ if (bp->rss_cap & BNXT_RSS_CAP_RSS_HASH_TYPE_DELTA)
bp->rss_hash_delta = bp->rss_hash_cfg ^ rss_hash_cfg;
bp->rss_hash_cfg = rss_hash_cfg;
if (netif_running(bp->dev)) {
@@ -1261,14 +1515,13 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
int rc = 0;
switch (cmd->cmd) {
-#ifdef CONFIG_RFS_ACCEL
case ETHTOOL_GRXRINGS:
cmd->data = bp->rx_nr_rings;
break;
case ETHTOOL_GRXCLSRLCNT:
cmd->rule_cnt = bp->ntp_fltr_count;
- cmd->data = BNXT_NTP_FLTR_MAX_FLTR;
+ cmd->data = BNXT_NTP_FLTR_MAX_FLTR | RX_CLS_LOC_SPECIAL;
break;
case ETHTOOL_GRXCLSRLALL:
@@ -1278,7 +1531,6 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
case ETHTOOL_GRXCLSRULE:
rc = bnxt_grxclsrule(bp, cmd);
break;
-#endif
case ETHTOOL_GRXFH:
rc = bnxt_grxfh(bp, cmd);
@@ -1302,6 +1554,14 @@ static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
rc = bnxt_srxfh(bp, cmd);
break;
+ case ETHTOOL_SRXCLSRLINS:
+ rc = bnxt_srxclsrlins(bp, cmd);
+ break;
+
+ case ETHTOOL_SRXCLSRLDEL:
+ rc = bnxt_srxclsrldel(bp, cmd);
+ break;
+
default:
rc = -EOPNOTSUPP;
break;
@@ -1313,8 +1573,9 @@ u32 bnxt_get_rxfh_indir_size(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
- if (bp->flags & BNXT_FLAG_CHIP_P5)
- return ALIGN(bp->rx_nr_rings, BNXT_RSS_TABLE_ENTRIES_P5);
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
+ return bnxt_get_nr_rss_ctxs(bp, bp->rx_nr_rings) *
+ BNXT_RSS_TABLE_ENTRIES_P5;
return HW_HASH_INDEX_SIZE;
}
@@ -1323,49 +1584,49 @@ static u32 bnxt_get_rxfh_key_size(struct net_device *dev)
return HW_HASH_KEY_SIZE;
}
-static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int bnxt_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vnic_info *vnic;
u32 i, tbl_size;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
if (!bp->vnic_info)
return 0;
vnic = &bp->vnic_info[0];
- if (indir && bp->rss_indir_tbl) {
+ if (rxfh->indir && bp->rss_indir_tbl) {
tbl_size = bnxt_get_rxfh_indir_size(dev);
for (i = 0; i < tbl_size; i++)
- indir[i] = bp->rss_indir_tbl[i];
+ rxfh->indir[i] = bp->rss_indir_tbl[i];
}
- if (key && vnic->rss_hash_key)
- memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
+ if (rxfh->key && vnic->rss_hash_key)
+ memcpy(rxfh->key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
return 0;
}
-static int bnxt_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int bnxt_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct bnxt *bp = netdev_priv(dev);
int rc = 0;
- if (hfunc && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (key)
+ if (rxfh->key)
return -EOPNOTSUPP;
- if (indir) {
+ if (rxfh->indir) {
u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev);
for (i = 0; i < tbl_size; i++)
- bp->rss_indir_tbl[i] = indir[i];
+ bp->rss_indir_tbl[i] = rxfh->indir[i];
pad = bp->rss_indir_tbl_entries - tbl_size;
if (pad)
memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16));
@@ -1568,6 +1829,22 @@ static const enum bnxt_media_type bnxt_phy_types[] = {
[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2] = BNXT_MEDIA_SR,
[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2] = BNXT_MEDIA_LR_ER_FR,
[PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR] = BNXT_MEDIA_CR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR] = BNXT_MEDIA_SR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2] = BNXT_MEDIA_CR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2] = BNXT_MEDIA_SR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8] = BNXT_MEDIA_CR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8] = BNXT_MEDIA_SR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4] = BNXT_MEDIA_CR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4] = BNXT_MEDIA_SR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4] = BNXT_MEDIA_LR_ER_FR,
+ [PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4] = BNXT_MEDIA_LR_ER_FR,
};
static enum bnxt_media_type
@@ -1595,6 +1872,7 @@ enum bnxt_link_speed_indices {
BNXT_LINK_SPEED_50GB_IDX,
BNXT_LINK_SPEED_100GB_IDX,
BNXT_LINK_SPEED_200GB_IDX,
+ BNXT_LINK_SPEED_400GB_IDX,
__BNXT_LINK_SPEED_END
};
@@ -1606,9 +1884,21 @@ static enum bnxt_link_speed_indices bnxt_fw_speed_idx(u16 speed)
case BNXT_LINK_SPEED_10GB: return BNXT_LINK_SPEED_10GB_IDX;
case BNXT_LINK_SPEED_25GB: return BNXT_LINK_SPEED_25GB_IDX;
case BNXT_LINK_SPEED_40GB: return BNXT_LINK_SPEED_40GB_IDX;
- case BNXT_LINK_SPEED_50GB: return BNXT_LINK_SPEED_50GB_IDX;
- case BNXT_LINK_SPEED_100GB: return BNXT_LINK_SPEED_100GB_IDX;
- case BNXT_LINK_SPEED_200GB: return BNXT_LINK_SPEED_200GB_IDX;
+ case BNXT_LINK_SPEED_50GB:
+ case BNXT_LINK_SPEED_50GB_PAM4:
+ return BNXT_LINK_SPEED_50GB_IDX;
+ case BNXT_LINK_SPEED_100GB:
+ case BNXT_LINK_SPEED_100GB_PAM4:
+ case BNXT_LINK_SPEED_100GB_PAM4_112:
+ return BNXT_LINK_SPEED_100GB_IDX;
+ case BNXT_LINK_SPEED_200GB:
+ case BNXT_LINK_SPEED_200GB_PAM4:
+ case BNXT_LINK_SPEED_200GB_PAM4_112:
+ return BNXT_LINK_SPEED_200GB_IDX;
+ case BNXT_LINK_SPEED_400GB:
+ case BNXT_LINK_SPEED_400GB_PAM4:
+ case BNXT_LINK_SPEED_400GB_PAM4_112:
+ return BNXT_LINK_SPEED_400GB_IDX;
default: return BNXT_LINK_SPEED_UNKNOWN;
}
}
@@ -1681,6 +1971,12 @@ bnxt_link_modes[__BNXT_LINK_SPEED_END][BNXT_SIG_MODE_MAX][__BNXT_MEDIA_END] = {
[BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
[BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
},
+ [BNXT_SIG_MODE_PAM4_112] = {
+ [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
+ [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
+ [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
+ [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
+ },
},
[BNXT_LINK_SPEED_200GB_IDX] = {
[BNXT_SIG_MODE_PAM4] = {
@@ -1689,6 +1985,26 @@ bnxt_link_modes[__BNXT_LINK_SPEED_END][BNXT_SIG_MODE_MAX][__BNXT_MEDIA_END] = {
[BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
[BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
},
+ [BNXT_SIG_MODE_PAM4_112] = {
+ [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
+ [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
+ [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
+ [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
+ },
+ },
+ [BNXT_LINK_SPEED_400GB_IDX] = {
+ [BNXT_SIG_MODE_PAM4] = {
+ [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
+ [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
+ [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
+ [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
+ },
+ [BNXT_SIG_MODE_PAM4_112] = {
+ [BNXT_MEDIA_CR] = ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,
+ [BNXT_MEDIA_KR] = ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,
+ [BNXT_MEDIA_SR] = ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
+ [BNXT_MEDIA_LR_ER_FR] = ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
+ },
},
};
@@ -1753,7 +2069,8 @@ static void bnxt_get_ethtool_modes(struct bnxt_link_info *link_info,
lk_ksettings->link_modes.supported);
}
- if (link_info->support_auto_speeds || link_info->support_pam4_auto_speeds)
+ if (link_info->support_auto_speeds || link_info->support_auto_speeds2 ||
+ link_info->support_pam4_auto_speeds)
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
lk_ksettings->link_modes.supported);
@@ -1789,22 +2106,60 @@ static const u16 bnxt_pam4_speed_masks[] = {
[BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_50GB,
[BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_100GB,
[BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_PAM4_SPEED_MSK_200GB,
+ [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */
+};
+
+static const u16 bnxt_nrz_speeds2_masks[] = {
+ [BNXT_LINK_SPEED_1GB_IDX] = BNXT_LINK_SPEEDS2_MSK_1GB,
+ [BNXT_LINK_SPEED_10GB_IDX] = BNXT_LINK_SPEEDS2_MSK_10GB,
+ [BNXT_LINK_SPEED_25GB_IDX] = BNXT_LINK_SPEEDS2_MSK_25GB,
+ [BNXT_LINK_SPEED_40GB_IDX] = BNXT_LINK_SPEEDS2_MSK_40GB,
+ [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEEDS2_MSK_50GB,
+ [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB,
+ [__BNXT_LINK_SPEED_END - 1] = 0 /* make any legal speed a valid index */
+};
+
+static const u16 bnxt_pam4_speeds2_masks[] = {
+ [BNXT_LINK_SPEED_50GB_IDX] = BNXT_LINK_SPEEDS2_MSK_50GB_PAM4,
+ [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB_PAM4,
+ [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_SPEEDS2_MSK_200GB_PAM4,
+ [BNXT_LINK_SPEED_400GB_IDX] = BNXT_LINK_SPEEDS2_MSK_400GB_PAM4,
+};
+
+static const u16 bnxt_pam4_112_speeds2_masks[] = {
+ [BNXT_LINK_SPEED_100GB_IDX] = BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112,
+ [BNXT_LINK_SPEED_200GB_IDX] = BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112,
+ [BNXT_LINK_SPEED_400GB_IDX] = BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112,
};
static enum bnxt_link_speed_indices
-bnxt_encoding_speed_idx(u8 sig_mode, u16 speed_msk)
+bnxt_encoding_speed_idx(u8 sig_mode, u16 phy_flags, u16 speed_msk)
{
const u16 *speeds;
int idx, len;
switch (sig_mode) {
case BNXT_SIG_MODE_NRZ:
- speeds = bnxt_nrz_speed_masks;
- len = ARRAY_SIZE(bnxt_nrz_speed_masks);
+ if (phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ speeds = bnxt_nrz_speeds2_masks;
+ len = ARRAY_SIZE(bnxt_nrz_speeds2_masks);
+ } else {
+ speeds = bnxt_nrz_speed_masks;
+ len = ARRAY_SIZE(bnxt_nrz_speed_masks);
+ }
break;
case BNXT_SIG_MODE_PAM4:
- speeds = bnxt_pam4_speed_masks;
- len = ARRAY_SIZE(bnxt_pam4_speed_masks);
+ if (phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ speeds = bnxt_pam4_speeds2_masks;
+ len = ARRAY_SIZE(bnxt_pam4_speeds2_masks);
+ } else {
+ speeds = bnxt_pam4_speed_masks;
+ len = ARRAY_SIZE(bnxt_pam4_speed_masks);
+ }
+ break;
+ case BNXT_SIG_MODE_PAM4_112:
+ speeds = bnxt_pam4_112_speeds2_masks;
+ len = ARRAY_SIZE(bnxt_pam4_112_speeds2_masks);
break;
default:
return BNXT_LINK_SPEED_UNKNOWN;
@@ -1822,14 +2177,14 @@ bnxt_encoding_speed_idx(u8 sig_mode, u16 speed_msk)
static void
__bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media,
- u8 sig_mode, unsigned long *et_mask)
+ u8 sig_mode, u16 phy_flags, unsigned long *et_mask)
{
enum ethtool_link_mode_bit_indices link_mode;
enum bnxt_link_speed_indices speed;
u8 bit;
for_each_set_bit(bit, &fw_mask, BNXT_FW_SPEED_MSK_BITS) {
- speed = bnxt_encoding_speed_idx(sig_mode, 1 << bit);
+ speed = bnxt_encoding_speed_idx(sig_mode, phy_flags, 1 << bit);
if (!speed)
continue;
@@ -1843,16 +2198,83 @@ __bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media,
static void
bnxt_get_ethtool_speeds(unsigned long fw_mask, enum bnxt_media_type media,
- u8 sig_mode, unsigned long *et_mask)
+ u8 sig_mode, u16 phy_flags, unsigned long *et_mask)
{
if (media) {
- __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, et_mask);
+ __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags,
+ et_mask);
return;
}
/* list speeds for all media if unknown */
for (media = 1; media < __BNXT_MEDIA_END; media++)
- __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, et_mask);
+ __bnxt_get_ethtool_speeds(fw_mask, media, sig_mode, phy_flags,
+ et_mask);
+}
+
+static void
+bnxt_get_all_ethtool_support_speeds(struct bnxt_link_info *link_info,
+ enum bnxt_media_type media,
+ struct ethtool_link_ksettings *lk_ksettings)
+{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+ u16 sp_nrz, sp_pam4, sp_pam4_112 = 0;
+ u16 phy_flags = bp->phy_flags;
+
+ if (phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ sp_nrz = link_info->support_speeds2;
+ sp_pam4 = link_info->support_speeds2;
+ sp_pam4_112 = link_info->support_speeds2;
+ } else {
+ sp_nrz = link_info->support_speeds;
+ sp_pam4 = link_info->support_pam4_speeds;
+ }
+ bnxt_get_ethtool_speeds(sp_nrz, media, BNXT_SIG_MODE_NRZ, phy_flags,
+ lk_ksettings->link_modes.supported);
+ bnxt_get_ethtool_speeds(sp_pam4, media, BNXT_SIG_MODE_PAM4, phy_flags,
+ lk_ksettings->link_modes.supported);
+ bnxt_get_ethtool_speeds(sp_pam4_112, media, BNXT_SIG_MODE_PAM4_112,
+ phy_flags, lk_ksettings->link_modes.supported);
+}
+
+static void
+bnxt_get_all_ethtool_adv_speeds(struct bnxt_link_info *link_info,
+ enum bnxt_media_type media,
+ struct ethtool_link_ksettings *lk_ksettings)
+{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+ u16 sp_nrz, sp_pam4, sp_pam4_112 = 0;
+ u16 phy_flags = bp->phy_flags;
+
+ sp_nrz = link_info->advertising;
+ if (phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ sp_pam4 = link_info->advertising;
+ sp_pam4_112 = link_info->advertising;
+ } else {
+ sp_pam4 = link_info->advertising_pam4;
+ }
+ bnxt_get_ethtool_speeds(sp_nrz, media, BNXT_SIG_MODE_NRZ, phy_flags,
+ lk_ksettings->link_modes.advertising);
+ bnxt_get_ethtool_speeds(sp_pam4, media, BNXT_SIG_MODE_PAM4, phy_flags,
+ lk_ksettings->link_modes.advertising);
+ bnxt_get_ethtool_speeds(sp_pam4_112, media, BNXT_SIG_MODE_PAM4_112,
+ phy_flags, lk_ksettings->link_modes.advertising);
+}
+
+static void
+bnxt_get_all_ethtool_lp_speeds(struct bnxt_link_info *link_info,
+ enum bnxt_media_type media,
+ struct ethtool_link_ksettings *lk_ksettings)
+{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+ u16 phy_flags = bp->phy_flags;
+
+ bnxt_get_ethtool_speeds(link_info->lp_auto_link_speeds, media,
+ BNXT_SIG_MODE_NRZ, phy_flags,
+ lk_ksettings->link_modes.lp_advertising);
+ bnxt_get_ethtool_speeds(link_info->lp_auto_pam4_link_speeds, media,
+ BNXT_SIG_MODE_PAM4, phy_flags,
+ lk_ksettings->link_modes.lp_advertising);
}
static void bnxt_update_speed(u32 *delta, bool installed_media, u16 *speeds,
@@ -1881,22 +2303,42 @@ static void bnxt_update_speed(u32 *delta, bool installed_media, u16 *speeds,
static void bnxt_set_ethtool_speeds(struct bnxt_link_info *link_info,
const unsigned long *et_mask)
{
+ struct bnxt *bp = container_of(link_info, struct bnxt, link_info);
+ u16 const *sp_msks, *sp_pam4_msks, *sp_pam4_112_msks;
enum bnxt_media_type media = bnxt_get_media(link_info);
+ u16 *adv, *adv_pam4, *adv_pam4_112 = NULL;
+ u32 delta_pam4_112 = 0;
u32 delta_pam4 = 0;
u32 delta_nrz = 0;
int i, m;
+ adv = &link_info->advertising;
+ if (bp->phy_flags & BNXT_PHY_FL_SPEEDS2) {
+ adv_pam4 = &link_info->advertising;
+ adv_pam4_112 = &link_info->advertising;
+ sp_msks = bnxt_nrz_speeds2_masks;
+ sp_pam4_msks = bnxt_pam4_speeds2_masks;
+ sp_pam4_112_msks = bnxt_pam4_112_speeds2_masks;
+ } else {
+ adv_pam4 = &link_info->advertising_pam4;
+ sp_msks = bnxt_nrz_speed_masks;
+ sp_pam4_msks = bnxt_pam4_speed_masks;
+ }
for (i = 1; i < __BNXT_LINK_SPEED_END; i++) {
/* accept any legal media from user */
for (m = 1; m < __BNXT_MEDIA_END; m++) {
bnxt_update_speed(&delta_nrz, m == media,
- &link_info->advertising,
- bnxt_nrz_speed_masks[i], et_mask,
+ adv, sp_msks[i], et_mask,
bnxt_link_modes[i][BNXT_SIG_MODE_NRZ][m]);
bnxt_update_speed(&delta_pam4, m == media,
- &link_info->advertising_pam4,
- bnxt_pam4_speed_masks[i], et_mask,
+ adv_pam4, sp_pam4_msks[i], et_mask,
bnxt_link_modes[i][BNXT_SIG_MODE_PAM4][m]);
+ if (!adv_pam4_112)
+ continue;
+
+ bnxt_update_speed(&delta_pam4_112, m == media,
+ adv_pam4_112, sp_pam4_112_msks[i], et_mask,
+ bnxt_link_modes[i][BNXT_SIG_MODE_PAM4_112][m]);
}
}
}
@@ -1961,11 +2403,20 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
case BNXT_LINK_SPEED_40GB:
return SPEED_40000;
case BNXT_LINK_SPEED_50GB:
+ case BNXT_LINK_SPEED_50GB_PAM4:
return SPEED_50000;
case BNXT_LINK_SPEED_100GB:
+ case BNXT_LINK_SPEED_100GB_PAM4:
+ case BNXT_LINK_SPEED_100GB_PAM4_112:
return SPEED_100000;
case BNXT_LINK_SPEED_200GB:
+ case BNXT_LINK_SPEED_200GB_PAM4:
+ case BNXT_LINK_SPEED_200GB_PAM4_112:
return SPEED_200000;
+ case BNXT_LINK_SPEED_400GB:
+ case BNXT_LINK_SPEED_400GB_PAM4:
+ case BNXT_LINK_SPEED_400GB_PAM4_112:
+ return SPEED_400000;
default:
return SPEED_UNKNOWN;
}
@@ -1981,6 +2432,7 @@ static void bnxt_get_default_speeds(struct ethtool_link_ksettings *lk_ksettings,
base->duplex = DUPLEX_HALF;
if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
base->duplex = DUPLEX_FULL;
+ lk_ksettings->lanes = link_info->active_lanes;
} else if (!link_info->autoneg) {
base->speed = bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
base->duplex = DUPLEX_HALF;
@@ -2008,12 +2460,7 @@ static int bnxt_get_link_ksettings(struct net_device *dev,
mutex_lock(&bp->link_lock);
bnxt_get_ethtool_modes(link_info, lk_ksettings);
media = bnxt_get_media(link_info);
- bnxt_get_ethtool_speeds(link_info->support_speeds,
- media, BNXT_SIG_MODE_NRZ,
- lk_ksettings->link_modes.supported);
- bnxt_get_ethtool_speeds(link_info->support_pam4_speeds,
- media, BNXT_SIG_MODE_PAM4,
- lk_ksettings->link_modes.supported);
+ bnxt_get_all_ethtool_support_speeds(link_info, media, lk_ksettings);
bnxt_fw_to_ethtool_support_fec(link_info, lk_ksettings);
link_mode = bnxt_get_link_mode(link_info);
if (link_mode != BNXT_LINK_MODE_UNKNOWN)
@@ -2026,20 +2473,10 @@ static int bnxt_get_link_ksettings(struct net_device *dev,
linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
lk_ksettings->link_modes.advertising);
base->autoneg = AUTONEG_ENABLE;
- bnxt_get_ethtool_speeds(link_info->advertising,
- media, BNXT_SIG_MODE_NRZ,
- lk_ksettings->link_modes.advertising);
- bnxt_get_ethtool_speeds(link_info->advertising_pam4,
- media, BNXT_SIG_MODE_PAM4,
- lk_ksettings->link_modes.advertising);
- if (link_info->phy_link_status == BNXT_LINK_LINK) {
- bnxt_get_ethtool_speeds(link_info->lp_auto_link_speeds,
- media, BNXT_SIG_MODE_NRZ,
- lk_ksettings->link_modes.lp_advertising);
- bnxt_get_ethtool_speeds(link_info->lp_auto_pam4_link_speeds,
- media, BNXT_SIG_MODE_PAM4,
- lk_ksettings->link_modes.lp_advertising);
- }
+ bnxt_get_all_ethtool_adv_speeds(link_info, media, lk_ksettings);
+ if (link_info->phy_link_status == BNXT_LINK_LINK)
+ bnxt_get_all_ethtool_lp_speeds(link_info, media,
+ lk_ksettings);
} else {
base->autoneg = AUTONEG_DISABLE;
}
@@ -2074,6 +2511,7 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes)
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
u16 support_pam4_spds = link_info->support_pam4_speeds;
+ u16 support_spds2 = link_info->support_speeds2;
u16 support_spds = link_info->support_speeds;
u8 sig_mode = BNXT_SIG_MODE_NRZ;
u32 lanes_needed = 1;
@@ -2085,7 +2523,8 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes)
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB;
break;
case SPEED_1000:
- if (support_spds & BNXT_LINK_SPEED_MSK_1GB)
+ if ((support_spds & BNXT_LINK_SPEED_MSK_1GB) ||
+ (support_spds2 & BNXT_LINK_SPEEDS2_MSK_1GB))
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
break;
case SPEED_2500:
@@ -2093,7 +2532,8 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes)
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_2_5GB;
break;
case SPEED_10000:
- if (support_spds & BNXT_LINK_SPEED_MSK_10GB)
+ if ((support_spds & BNXT_LINK_SPEED_MSK_10GB) ||
+ (support_spds2 & BNXT_LINK_SPEEDS2_MSK_10GB))
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
break;
case SPEED_20000:
@@ -2103,26 +2543,34 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes)
}
break;
case SPEED_25000:
- if (support_spds & BNXT_LINK_SPEED_MSK_25GB)
+ if ((support_spds & BNXT_LINK_SPEED_MSK_25GB) ||
+ (support_spds2 & BNXT_LINK_SPEEDS2_MSK_25GB))
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
break;
case SPEED_40000:
- if (support_spds & BNXT_LINK_SPEED_MSK_40GB) {
+ if ((support_spds & BNXT_LINK_SPEED_MSK_40GB) ||
+ (support_spds2 & BNXT_LINK_SPEEDS2_MSK_40GB)) {
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
lanes_needed = 4;
}
break;
case SPEED_50000:
- if ((support_spds & BNXT_LINK_SPEED_MSK_50GB) && lanes != 1) {
+ if (((support_spds & BNXT_LINK_SPEED_MSK_50GB) ||
+ (support_spds2 & BNXT_LINK_SPEEDS2_MSK_50GB)) &&
+ lanes != 1) {
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
lanes_needed = 2;
} else if (support_pam4_spds & BNXT_LINK_PAM4_SPEED_MSK_50GB) {
fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_50GB;
sig_mode = BNXT_SIG_MODE_PAM4;
+ } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_50GB_PAM4) {
+ fw_speed = BNXT_LINK_SPEED_50GB_PAM4;
+ sig_mode = BNXT_SIG_MODE_PAM4;
}
break;
case SPEED_100000:
- if ((support_spds & BNXT_LINK_SPEED_MSK_100GB) &&
+ if (((support_spds & BNXT_LINK_SPEED_MSK_100GB) ||
+ (support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB)) &&
lanes != 2 && lanes != 1) {
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100GB;
lanes_needed = 4;
@@ -2130,6 +2578,14 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes)
fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_100GB;
sig_mode = BNXT_SIG_MODE_PAM4;
lanes_needed = 2;
+ } else if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB_PAM4) &&
+ lanes != 1) {
+ fw_speed = BNXT_LINK_SPEED_100GB_PAM4;
+ sig_mode = BNXT_SIG_MODE_PAM4;
+ lanes_needed = 2;
+ } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_100GB_PAM4_112) {
+ fw_speed = BNXT_LINK_SPEED_100GB_PAM4_112;
+ sig_mode = BNXT_SIG_MODE_PAM4_112;
}
break;
case SPEED_200000:
@@ -2137,6 +2593,27 @@ bnxt_force_link_speed(struct net_device *dev, u32 ethtool_speed, u32 lanes)
fw_speed = PORT_PHY_CFG_REQ_FORCE_PAM4_LINK_SPEED_200GB;
sig_mode = BNXT_SIG_MODE_PAM4;
lanes_needed = 4;
+ } else if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_200GB_PAM4) &&
+ lanes != 2) {
+ fw_speed = BNXT_LINK_SPEED_200GB_PAM4;
+ sig_mode = BNXT_SIG_MODE_PAM4;
+ lanes_needed = 4;
+ } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_200GB_PAM4_112) {
+ fw_speed = BNXT_LINK_SPEED_200GB_PAM4_112;
+ sig_mode = BNXT_SIG_MODE_PAM4_112;
+ lanes_needed = 2;
+ }
+ break;
+ case SPEED_400000:
+ if ((support_spds2 & BNXT_LINK_SPEEDS2_MSK_400GB_PAM4) &&
+ lanes != 4) {
+ fw_speed = BNXT_LINK_SPEED_400GB_PAM4;
+ sig_mode = BNXT_SIG_MODE_PAM4;
+ lanes_needed = 8;
+ } else if (support_spds2 & BNXT_LINK_SPEEDS2_MSK_400GB_PAM4_112) {
+ fw_speed = BNXT_LINK_SPEED_400GB_PAM4_112;
+ sig_mode = BNXT_SIG_MODE_PAM4_112;
+ lanes_needed = 4;
}
break;
}
@@ -3910,7 +4387,8 @@ static int bnxt_poll_loopback(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
* reading any further.
*/
dma_rmb();
- if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) {
+ if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP ||
+ TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_V3_CMP) {
rc = bnxt_rx_loopback(bp, cpr, raw_cons, pkt_size);
raw_cons = NEXT_RAW_CMP(raw_cons);
raw_cons = NEXT_RAW_CMP(raw_cons);
@@ -3934,8 +4412,8 @@ static int bnxt_run_loopback(struct bnxt *bp)
int rc;
cpr = &rxr->bnapi->cp_ring;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
- cpr = cpr->cp_ring_arr[BNXT_RX_HDL];
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
+ cpr = rxr->rx_cpr;
pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh);
skb = netdev_alloc_skb(bp->dev, pkt_size);
if (!skb)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
index d5fad5a3cdd1..e957abd704db 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h
@@ -40,6 +40,8 @@ struct hwrm_resp_hdr {
#define TLV_TYPE_ROCE_SP_COMMAND 0x3UL
#define TLV_TYPE_QUERY_ROCE_CC_GEN1 0x4UL
#define TLV_TYPE_MODIFY_ROCE_CC_GEN1 0x5UL
+#define TLV_TYPE_QUERY_ROCE_CC_GEN2 0x6UL
+#define TLV_TYPE_MODIFY_ROCE_CC_GEN2 0x7UL
#define TLV_TYPE_ENGINE_CKV_ALIAS_ECC_PUBLIC_KEY 0x8001UL
#define TLV_TYPE_ENGINE_CKV_IV 0x8003UL
#define TLV_TYPE_ENGINE_CKV_AUTH_TAG 0x8004UL
@@ -196,6 +198,9 @@ struct cmd_nums {
#define HWRM_QUEUE_ADPTV_QOS_TX_FEATURE_QCFG 0x8aUL
#define HWRM_QUEUE_ADPTV_QOS_TX_FEATURE_CFG 0x8bUL
#define HWRM_QUEUE_QCAPS 0x8cUL
+ #define HWRM_QUEUE_ADPTV_QOS_RX_TUNING_QCFG 0x8dUL
+ #define HWRM_QUEUE_ADPTV_QOS_RX_TUNING_CFG 0x8eUL
+ #define HWRM_QUEUE_ADPTV_QOS_TX_TUNING_QCFG 0x8fUL
#define HWRM_CFA_L2_FILTER_ALLOC 0x90UL
#define HWRM_CFA_L2_FILTER_FREE 0x91UL
#define HWRM_CFA_L2_FILTER_CFG 0x92UL
@@ -214,6 +219,7 @@ struct cmd_nums {
#define HWRM_TUNNEL_DST_PORT_QUERY 0xa0UL
#define HWRM_TUNNEL_DST_PORT_ALLOC 0xa1UL
#define HWRM_TUNNEL_DST_PORT_FREE 0xa2UL
+ #define HWRM_QUEUE_ADPTV_QOS_TX_TUNING_CFG 0xa3UL
#define HWRM_STAT_CTX_ENG_QUERY 0xafUL
#define HWRM_STAT_CTX_ALLOC 0xb0UL
#define HWRM_STAT_CTX_FREE 0xb1UL
@@ -261,6 +267,7 @@ struct cmd_nums {
#define HWRM_PORT_EP_TX_CFG 0xdbUL
#define HWRM_PORT_CFG 0xdcUL
#define HWRM_PORT_QCFG 0xddUL
+ #define HWRM_PORT_MAC_QCAPS 0xdfUL
#define HWRM_TEMP_MONITOR_QUERY 0xe0UL
#define HWRM_REG_POWER_QUERY 0xe1UL
#define HWRM_CORE_FREQUENCY_QUERY 0xe2UL
@@ -392,6 +399,10 @@ struct cmd_nums {
#define HWRM_FUNC_KEY_CTX_FREE 0x1adUL
#define HWRM_FUNC_LAG_MODE_CFG 0x1aeUL
#define HWRM_FUNC_LAG_MODE_QCFG 0x1afUL
+ #define HWRM_FUNC_LAG_CREATE 0x1b0UL
+ #define HWRM_FUNC_LAG_UPDATE 0x1b1UL
+ #define HWRM_FUNC_LAG_FREE 0x1b2UL
+ #define HWRM_FUNC_LAG_QCFG 0x1b3UL
#define HWRM_SELFTEST_QLIST 0x200UL
#define HWRM_SELFTEST_EXEC 0x201UL
#define HWRM_SELFTEST_IRQ 0x202UL
@@ -406,9 +417,9 @@ struct cmd_nums {
#define HWRM_MFG_FRU_EEPROM_READ 0x20bUL
#define HWRM_MFG_SOC_IMAGE 0x20cUL
#define HWRM_MFG_SOC_QSTATUS 0x20dUL
- #define HWRM_MFG_PARAM_SEEPROM_SYNC 0x20eUL
- #define HWRM_MFG_PARAM_SEEPROM_READ 0x20fUL
- #define HWRM_MFG_PARAM_SEEPROM_HEALTH 0x210UL
+ #define HWRM_MFG_PARAM_CRITICAL_DATA_FINALIZE 0x20eUL
+ #define HWRM_MFG_PARAM_CRITICAL_DATA_READ 0x20fUL
+ #define HWRM_MFG_PARAM_CRITICAL_DATA_HEALTH 0x210UL
#define HWRM_MFG_PRVSN_EXPORT_CSR 0x211UL
#define HWRM_MFG_PRVSN_IMPORT_CERT 0x212UL
#define HWRM_MFG_PRVSN_GET_STATE 0x213UL
@@ -418,6 +429,16 @@ struct cmd_nums {
#define HWRM_MFG_SELFTEST_EXEC 0x217UL
#define HWRM_STAT_GENERIC_QSTATS 0x218UL
#define HWRM_MFG_PRVSN_EXPORT_CERT 0x219UL
+ #define HWRM_STAT_DB_ERROR_QSTATS 0x21aUL
+ #define HWRM_UDCC_QCAPS 0x258UL
+ #define HWRM_UDCC_CFG 0x259UL
+ #define HWRM_UDCC_QCFG 0x25aUL
+ #define HWRM_UDCC_SESSION_CFG 0x25bUL
+ #define HWRM_UDCC_SESSION_QCFG 0x25cUL
+ #define HWRM_UDCC_SESSION_QUERY 0x25dUL
+ #define HWRM_UDCC_COMP_CFG 0x25eUL
+ #define HWRM_UDCC_COMP_QCFG 0x25fUL
+ #define HWRM_UDCC_COMP_QUERY 0x260UL
#define HWRM_TF 0x2bcUL
#define HWRM_TF_VERSION_GET 0x2bdUL
#define HWRM_TF_SESSION_OPEN 0x2c6UL
@@ -582,9 +603,9 @@ struct hwrm_err_output {
#define HWRM_TARGET_ID_TOOLS 0xFFFD
#define HWRM_VERSION_MAJOR 1
#define HWRM_VERSION_MINOR 10
-#define HWRM_VERSION_UPDATE 2
-#define HWRM_VERSION_RSVD 171
-#define HWRM_VERSION_STR "1.10.2.171"
+#define HWRM_VERSION_UPDATE 3
+#define HWRM_VERSION_RSVD 15
+#define HWRM_VERSION_STR "1.10.3.15"
/* hwrm_ver_get_input (size:192b/24B) */
struct hwrm_ver_get_input {
@@ -816,7 +837,8 @@ struct hwrm_async_event_cmpl {
#define ASYNC_EVENT_CMPL_EVENT_ID_DOORBELL_PACING_NQ_UPDATE 0x48UL
#define ASYNC_EVENT_CMPL_EVENT_ID_HW_DOORBELL_RECOVERY_READ_ERROR 0x49UL
#define ASYNC_EVENT_CMPL_EVENT_ID_CTX_ERROR 0x4aUL
- #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x4bUL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_UDCC_SESSION_CHANGE 0x4bUL
+ #define ASYNC_EVENT_CMPL_EVENT_ID_MAX_RGTR_EVENT_ID 0x4cUL
#define ASYNC_EVENT_CMPL_EVENT_ID_FW_TRACE_MSG 0xfeUL
#define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL
#define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR
@@ -1632,7 +1654,7 @@ struct hwrm_func_qcaps_input {
u8 unused_0[6];
};
-/* hwrm_func_qcaps_output (size:896b/112B) */
+/* hwrm_func_qcaps_output (size:1088b/136B) */
struct hwrm_func_qcaps_output {
__le16 error_code;
__le16 req_type;
@@ -1736,21 +1758,29 @@ struct hwrm_func_qcaps_output {
#define FUNC_QCAPS_RESP_MPC_CHNLS_CAP_PRIMATE 0x10UL
__le16 max_key_ctxs_alloc;
__le32 flags_ext2;
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED 0x1UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_QUIC_SUPPORTED 0x2UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_KDNET_SUPPORTED 0x4UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED 0x40UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_SYNCE_SUPPORTED 0x80UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_V0_SUPPORTED 0x100UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED 0x200UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_HW_LAG_SUPPORTED 0x400UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_ON_CHIP_CTX_SUPPORTED 0x800UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_STEERING_TAG_SUPPORTED 0x1000UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_ENHANCED_VF_SCALE_SUPPORTED 0x2000UL
- #define FUNC_QCAPS_RESP_FLAGS_EXT2_KEY_XID_PARTITION_SUPPORTED 0x4000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED 0x1UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_QUIC_SUPPORTED 0x2UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_KDNET_SUPPORTED 0x4UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_EXT_SUPPORTED 0x8UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_SW_DBR_DROP_RECOVERY_SUPPORTED 0x10UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_GENERIC_STATS_SUPPORTED 0x20UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDP_GSO_SUPPORTED 0x40UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_SYNCE_SUPPORTED 0x80UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_DBR_PACING_V0_SUPPORTED 0x100UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED 0x200UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_HW_LAG_SUPPORTED 0x400UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_ON_CHIP_CTX_SUPPORTED 0x800UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_STEERING_TAG_SUPPORTED 0x1000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_ENHANCED_VF_SCALE_SUPPORTED 0x2000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_KEY_XID_PARTITION_SUPPORTED 0x4000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_CONCURRENT_KTLS_QUIC_SUPPORTED 0x8000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_SCHQ_CROSS_TC_CAP_SUPPORTED 0x10000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_SCHQ_PER_TC_CAP_SUPPORTED 0x20000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_SCHQ_PER_TC_RESERVATION_SUPPORTED 0x40000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_DB_ERROR_STATS_SUPPORTED 0x80000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_ROCE_VF_RESOURCE_MGMT_SUPPORTED 0x100000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_UDCC_SUPPORTED 0x200000UL
+ #define FUNC_QCAPS_RESP_FLAGS_EXT2_TIMED_TX_SO_TXTIME_SUPPORTED 0x400000UL
__le16 tunnel_disable_flag;
#define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_VXLAN 0x1UL
#define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_NGE 0x2UL
@@ -1760,15 +1790,21 @@ struct hwrm_func_qcaps_output {
#define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_IPINIP 0x20UL
#define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_MPLS 0x40UL
#define FUNC_QCAPS_RESP_TUNNEL_DISABLE_FLAG_DISABLE_PPPOE 0x80UL
- u8 key_xid_partition_cap;
- #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_TKC 0x1UL
- #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_RKC 0x2UL
- #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_QUIC_TKC 0x4UL
- #define FUNC_QCAPS_RESP_KEY_XID_PARTITION_CAP_QUIC_RKC 0x8UL
- u8 unused_1;
+ __le16 xid_partition_cap;
+ #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_KTLS_TKC 0x1UL
+ #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_KTLS_RKC 0x2UL
+ #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_QUIC_TKC 0x4UL
+ #define FUNC_QCAPS_RESP_XID_PARTITION_CAP_QUIC_RKC 0x8UL
u8 device_serial_number[8];
__le16 ctxs_per_partition;
- u8 unused_2[5];
+ u8 unused_2[2];
+ __le32 roce_vf_max_av;
+ __le32 roce_vf_max_cq;
+ __le32 roce_vf_max_mrw;
+ __le32 roce_vf_max_qp;
+ __le32 roce_vf_max_srq;
+ __le32 roce_vf_max_gid;
+ u8 unused_3[3];
u8 valid;
};
@@ -1783,7 +1819,7 @@ struct hwrm_func_qcfg_input {
u8 unused_0[6];
};
-/* hwrm_func_qcfg_output (size:1024b/128B) */
+/* hwrm_func_qcfg_output (size:1280b/160B) */
struct hwrm_func_qcfg_output {
__le16 error_code;
__le16 req_type;
@@ -1892,7 +1928,7 @@ struct hwrm_func_qcfg_output {
__le16 alloc_msix;
__le16 registered_vfs;
__le16 l2_doorbell_bar_size_kb;
- u8 unused_1;
+ u8 active_endpoints;
u8 always_1;
__le32 reset_addr_poll;
__le16 legacy_l2_db_size_kb;
@@ -1952,15 +1988,26 @@ struct hwrm_func_qcfg_output {
u8 kdnet_pcie_function;
__le16 port_kdnet_fid;
u8 unused_5[2];
- __le32 alloc_tx_key_ctxs;
- __le32 alloc_rx_key_ctxs;
+ __le32 num_ktls_tx_key_ctxs;
+ __le32 num_ktls_rx_key_ctxs;
u8 lag_id;
u8 parif;
- u8 unused_6[5];
+ u8 fw_lag_id;
+ u8 unused_6;
+ __le32 num_quic_tx_key_ctxs;
+ __le32 num_quic_rx_key_ctxs;
+ __le32 roce_max_av_per_vf;
+ __le32 roce_max_cq_per_vf;
+ __le32 roce_max_mrw_per_vf;
+ __le32 roce_max_qp_per_vf;
+ __le32 roce_max_srq_per_vf;
+ __le32 roce_max_gid_per_vf;
+ __le16 xid_partition_cfg;
+ u8 unused_7;
u8 valid;
};
-/* hwrm_func_cfg_input (size:1088b/136B) */
+/* hwrm_func_cfg_input (size:1280b/160B) */
struct hwrm_func_cfg_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -1996,7 +2043,6 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_FLAGS_PPP_PUSH_MODE_DISABLE 0x10000000UL
#define FUNC_CFG_REQ_FLAGS_BD_METADATA_ENABLE 0x20000000UL
#define FUNC_CFG_REQ_FLAGS_BD_METADATA_DISABLE 0x40000000UL
- #define FUNC_CFG_REQ_FLAGS_KEY_CTX_ASSETS_TEST 0x80000000UL
__le32 enables;
#define FUNC_CFG_REQ_ENABLES_ADMIN_MTU 0x1UL
#define FUNC_CFG_REQ_ENABLES_MRU 0x2UL
@@ -2028,8 +2074,8 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_ENABLES_PARTITION_MAX_BW 0x8000000UL
#define FUNC_CFG_REQ_ENABLES_TPID 0x10000000UL
#define FUNC_CFG_REQ_ENABLES_HOST_MTU 0x20000000UL
- #define FUNC_CFG_REQ_ENABLES_TX_KEY_CTXS 0x40000000UL
- #define FUNC_CFG_REQ_ENABLES_RX_KEY_CTXS 0x80000000UL
+ #define FUNC_CFG_REQ_ENABLES_KTLS_TX_KEY_CTXS 0x40000000UL
+ #define FUNC_CFG_REQ_ENABLES_KTLS_RX_KEY_CTXS 0x80000000UL
__le16 admin_mtu;
__le16 mru;
__le16 num_rsscos_ctxs;
@@ -2139,10 +2185,21 @@ struct hwrm_func_cfg_input {
#define FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_LAST FUNC_CFG_REQ_PARTITION_MAX_BW_BW_VALUE_UNIT_PERCENT1_100
__be16 tpid;
__le16 host_mtu;
- u8 unused_0[4];
+ __le32 flags2;
+ #define FUNC_CFG_REQ_FLAGS2_KTLS_KEY_CTX_ASSETS_TEST 0x1UL
+ #define FUNC_CFG_REQ_FLAGS2_QUIC_KEY_CTX_ASSETS_TEST 0x2UL
__le32 enables2;
- #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL
- #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL
+ #define FUNC_CFG_REQ_ENABLES2_KDNET 0x1UL
+ #define FUNC_CFG_REQ_ENABLES2_DB_PAGE_SIZE 0x2UL
+ #define FUNC_CFG_REQ_ENABLES2_QUIC_TX_KEY_CTXS 0x4UL
+ #define FUNC_CFG_REQ_ENABLES2_QUIC_RX_KEY_CTXS 0x8UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_AV_PER_VF 0x10UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_CQ_PER_VF 0x20UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_MRW_PER_VF 0x40UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_QP_PER_VF 0x80UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_SRQ_PER_VF 0x100UL
+ #define FUNC_CFG_REQ_ENABLES2_ROCE_MAX_GID_PER_VF 0x200UL
+ #define FUNC_CFG_REQ_ENABLES2_XID_PARTITION_CFG 0x400UL
u8 port_kdnet_mode;
#define FUNC_CFG_REQ_PORT_KDNET_MODE_DISABLED 0x0UL
#define FUNC_CFG_REQ_PORT_KDNET_MODE_ENABLED 0x1UL
@@ -2165,7 +2222,18 @@ struct hwrm_func_cfg_input {
__le32 num_ktls_rx_key_ctxs;
__le32 num_quic_tx_key_ctxs;
__le32 num_quic_rx_key_ctxs;
- __le32 unused_2;
+ __le32 roce_max_av_per_vf;
+ __le32 roce_max_cq_per_vf;
+ __le32 roce_max_mrw_per_vf;
+ __le32 roce_max_qp_per_vf;
+ __le32 roce_max_srq_per_vf;
+ __le32 roce_max_gid_per_vf;
+ __le16 xid_partition_cfg;
+ #define FUNC_CFG_REQ_XID_PARTITION_CFG_KTLS_TKC 0x1UL
+ #define FUNC_CFG_REQ_XID_PARTITION_CFG_KTLS_RKC 0x2UL
+ #define FUNC_CFG_REQ_XID_PARTITION_CFG_QUIC_TKC 0x4UL
+ #define FUNC_CFG_REQ_XID_PARTITION_CFG_QUIC_RKC 0x8UL
+ __le16 unused_2;
};
/* hwrm_func_cfg_output (size:128b/16B) */
@@ -2604,7 +2672,7 @@ struct hwrm_func_vf_resource_cfg_input {
__le32 max_quic_rx_key_ctxs;
};
-/* hwrm_func_vf_resource_cfg_output (size:320b/40B) */
+/* hwrm_func_vf_resource_cfg_output (size:384b/48B) */
struct hwrm_func_vf_resource_cfg_output {
__le16 error_code;
__le16 req_type;
@@ -2618,8 +2686,10 @@ struct hwrm_func_vf_resource_cfg_output {
__le16 reserved_vnics;
__le16 reserved_stat_ctx;
__le16 reserved_hw_ring_grps;
- __le32 reserved_tx_key_ctxs;
- __le32 reserved_rx_key_ctxs;
+ __le32 reserved_ktls_tx_key_ctxs;
+ __le32 reserved_ktls_rx_key_ctxs;
+ __le32 reserved_quic_tx_key_ctxs;
+ __le32 reserved_quic_rx_key_ctxs;
u8 unused_0[7];
u8 valid;
};
@@ -3441,7 +3511,8 @@ struct hwrm_func_ptp_cfg_input {
#define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_4K 0x1UL
#define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_8K 0x2UL
#define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_10M 0x3UL
- #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_LAST FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_10M
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_25M 0x4UL
+ #define FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_LAST FUNC_PTP_CFG_REQ_PTP_FREQ_ADJ_DLL_PHASE_25M
u8 unused_0[3];
__le32 ptp_freq_adj_ext_period;
__le32 ptp_freq_adj_ext_up;
@@ -3627,28 +3698,28 @@ struct hwrm_func_backing_store_qcfg_v2_input {
__le16 target_id;
__le64 resp_addr;
__le16 type;
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QP 0x0UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ 0x1UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ 0x2UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_VNIC 0x3UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_STAT 0x4UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SP_TQM_RING 0x5UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_FP_TQM_RING 0x6UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MRAV 0xeUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TIM 0xfUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TKC 0x13UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RKC 0x14UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MP_TQM_RING 0x15UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SQ_DB_SHADOW 0x16UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RQ_DB_SHADOW 0x17UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ_DB_SHADOW 0x18UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ_DB_SHADOW 0x19UL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_TKC 0x1aUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_RKC 0x1bUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TBL_SCOPE 0x1cUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_XID_PARTITION 0x1dUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL
- #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QP 0x0UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ 0x1UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ 0x2UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_VNIC 0x3UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_STAT 0x4UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SP_TQM_RING 0x5UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_FP_TQM_RING 0x6UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MRAV 0xeUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TIM 0xfUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TKC 0x13UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RKC 0x14UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_MP_TQM_RING 0x15UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SQ_DB_SHADOW 0x16UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_RQ_DB_SHADOW 0x17UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_SRQ_DB_SHADOW 0x18UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_CQ_DB_SHADOW 0x19UL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_TKC 0x1aUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_QUIC_RKC 0x1bUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_TBL_SCOPE 0x1cUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_XID_PARTITION_TABLE 0x1dUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID 0xffffUL
+ #define FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_LAST FUNC_BACKING_STORE_QCFG_V2_REQ_TYPE_INVALID
__le16 instance;
u8 rsvd[4];
};
@@ -3744,6 +3815,15 @@ struct mrav_split_entries {
__le32 rsvd2[2];
};
+/* ts_split_entries (size:128b/16B) */
+struct ts_split_entries {
+ __le32 region_num_entries;
+ u8 tsid;
+ u8 lkup_static_bkt_cnt_exp[2];
+ u8 rsvd;
+ __le32 rsvd2[2];
+};
+
/* hwrm_func_backing_store_qcaps_v2_input (size:192b/24B) */
struct hwrm_func_backing_store_qcaps_v2_input {
__le16 req_type;
@@ -3761,8 +3841,8 @@ struct hwrm_func_backing_store_qcaps_v2_input {
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_FP_TQM_RING 0x6UL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MRAV 0xeUL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TIM 0xfUL
- #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_TKC 0x13UL
- #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RKC 0x14UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_KTLS_TKC 0x13UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_KTLS_RKC 0x14UL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_MP_TQM_RING 0x15UL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_SQ_DB_SHADOW 0x16UL
#define FUNC_BACKING_STORE_QCAPS_V2_REQ_TYPE_RQ_DB_SHADOW 0x17UL
@@ -3793,8 +3873,8 @@ struct hwrm_func_backing_store_qcaps_v2_output {
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_FP_TQM_RING 0x6UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_MRAV 0xeUL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_TIM 0xfUL
- #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_TKC 0x13UL
- #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RKC 0x14UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_KTLS_TKC 0x13UL
+ #define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_KTLS_RKC 0x14UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_MP_TQM_RING 0x15UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_SQ_DB_SHADOW 0x16UL
#define FUNC_BACKING_STORE_QCAPS_V2_RESP_TYPE_RQ_DB_SHADOW 0x17UL
@@ -3838,56 +3918,55 @@ struct hwrm_func_backing_store_qcaps_v2_output {
/* hwrm_func_dbr_pacing_qcfg_input (size:128b/16B) */
struct hwrm_func_dbr_pacing_qcfg_input {
- __le16 req_type;
- __le16 cmpl_ring;
- __le16 seq_id;
- __le16 target_id;
- __le64 resp_addr;
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
};
/* hwrm_func_dbr_pacing_qcfg_output (size:512b/64B) */
struct hwrm_func_dbr_pacing_qcfg_output {
- __le16 error_code;
- __le16 req_type;
- __le16 seq_id;
- __le16 resp_len;
- u8 flags;
-#define FUNC_DBR_PACING_QCFG_RESP_FLAGS_DBR_NQ_EVENT_ENABLED 0x1UL
- u8 unused_0[7];
- __le32 dbr_stat_db_fifo_reg;
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK 0x3UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_SFT 0
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_PCIE_CFG 0x0UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_GRC 0x1UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR0 0x2UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 0x3UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_LAST \
- FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_MASK 0xfffffffcUL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SFT 2
- __le32 dbr_stat_db_fifo_reg_watermark_mask;
- u8 dbr_stat_db_fifo_reg_watermark_shift;
- u8 unused_1[3];
- __le32 dbr_stat_db_fifo_reg_fifo_room_mask;
- u8 dbr_stat_db_fifo_reg_fifo_room_shift;
- u8 unused_2[3];
- __le32 dbr_throttling_aeq_arm_reg;
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_MASK 0x3UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_SFT 0
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_PCIE_CFG 0x0UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_GRC 0x1UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR0 0x2UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 0x3UL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_LAST \
- FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_MASK 0xfffffffcUL
-#define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SFT 2
- u8 dbr_throttling_aeq_arm_reg_val;
- u8 unused_3[7];
- __le32 primary_nq_id;
- __le32 pacing_threshold;
- u8 unused_4[7];
- u8 valid;
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 flags;
+ #define FUNC_DBR_PACING_QCFG_RESP_FLAGS_DBR_NQ_EVENT_ENABLED 0x1UL
+ u8 unused_0[7];
+ __le32 dbr_stat_db_fifo_reg;
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_MASK 0x3UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_SFT 0
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_PCIE_CFG 0x0UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_GRC 0x1UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR0 0x2UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1 0x3UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_LAST FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SPACE_BAR1
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_MASK 0xfffffffcUL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_STAT_DB_FIFO_REG_ADDR_SFT 2
+ __le32 dbr_stat_db_fifo_reg_watermark_mask;
+ u8 dbr_stat_db_fifo_reg_watermark_shift;
+ u8 unused_1[3];
+ __le32 dbr_stat_db_fifo_reg_fifo_room_mask;
+ u8 dbr_stat_db_fifo_reg_fifo_room_shift;
+ u8 unused_2[3];
+ __le32 dbr_throttling_aeq_arm_reg;
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_MASK 0x3UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_SFT 0
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_PCIE_CFG 0x0UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_GRC 0x1UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR0 0x2UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1 0x3UL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_LAST FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SPACE_BAR1
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_MASK 0xfffffffcUL
+ #define FUNC_DBR_PACING_QCFG_RESP_DBR_THROTTLING_AEQ_ARM_REG_ADDR_SFT 2
+ u8 dbr_throttling_aeq_arm_reg_val;
+ u8 unused_3[3];
+ __le32 dbr_stat_db_max_fifo_depth;
+ __le32 primary_nq_id;
+ __le32 pacing_threshold;
+ u8 unused_4[7];
+ u8 valid;
};
/* hwrm_func_drv_if_change_input (size:192b/24B) */
@@ -3915,7 +3994,7 @@ struct hwrm_func_drv_if_change_output {
u8 valid;
};
-/* hwrm_port_phy_cfg_input (size:448b/56B) */
+/* hwrm_port_phy_cfg_input (size:512b/64B) */
struct hwrm_port_phy_cfg_input {
__le16 req_type;
__le16 cmpl_ring;
@@ -3960,6 +4039,8 @@ struct hwrm_port_phy_cfg_input {
#define PORT_PHY_CFG_REQ_ENABLES_TX_LPI_TIMER 0x400UL
#define PORT_PHY_CFG_REQ_ENABLES_FORCE_PAM4_LINK_SPEED 0x800UL
#define PORT_PHY_CFG_REQ_ENABLES_AUTO_PAM4_LINK_SPEED_MASK 0x1000UL
+ #define PORT_PHY_CFG_REQ_ENABLES_FORCE_LINK_SPEEDS2 0x2000UL
+ #define PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEEDS2_MASK 0x4000UL
__le16 port_id;
__le16 force_link_speed;
#define PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_100MB 0x1UL
@@ -3990,7 +4071,9 @@ struct hwrm_port_phy_cfg_input {
#define PORT_PHY_CFG_REQ_AUTO_PAUSE_TX 0x1UL
#define PORT_PHY_CFG_REQ_AUTO_PAUSE_RX 0x2UL
#define PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE 0x4UL
- u8 unused_0;
+ u8 mgmt_flag;
+ #define PORT_PHY_CFG_REQ_MGMT_FLAG_LINK_RELEASE 0x1UL
+ #define PORT_PHY_CFG_REQ_MGMT_FLAG_MGMT_VALID 0x80UL
__le16 auto_link_speed;
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100MB 0x1UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_1GB 0xaUL
@@ -4054,7 +4137,36 @@ struct hwrm_port_phy_cfg_input {
#define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_50G 0x1UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_100G 0x2UL
#define PORT_PHY_CFG_REQ_AUTO_LINK_PAM4_SPEED_MASK_200G 0x4UL
- u8 unused_2[2];
+ __le16 force_link_speeds2;
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_1GB 0xaUL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_10GB 0x64UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_25GB 0xfaUL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_40GB 0x190UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB 0x1f4UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB 0x3e8UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_50GB_PAM4_56 0x1f5UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_56 0x3e9UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_56 0x7d1UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_56 0xfa1UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_100GB_PAM4_112 0x3eaUL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_200GB_PAM4_112 0x7d2UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112 0xfa2UL
+ #define PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_LAST PORT_PHY_CFG_REQ_FORCE_LINK_SPEEDS2_400GB_PAM4_112
+ __le16 auto_link_speeds2_mask;
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_1GB 0x1UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_10GB 0x2UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_25GB 0x4UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_40GB 0x8UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_50GB 0x10UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB 0x20UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_50GB_PAM4_56 0x40UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB_PAM4_56 0x80UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_200GB_PAM4_56 0x100UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_400GB_PAM4_56 0x200UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_100GB_PAM4_112 0x400UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_200GB_PAM4_112 0x800UL
+ #define PORT_PHY_CFG_REQ_AUTO_LINK_SPEEDS2_MASK_400GB_PAM4_112 0x1000UL
+ u8 unused_2[6];
};
/* hwrm_port_phy_cfg_output (size:128b/16B) */
@@ -4104,7 +4216,8 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_SIGNAL_MODE_SFT 0
#define PORT_PHY_QCFG_RESP_SIGNAL_MODE_NRZ 0x0UL
#define PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4 0x1UL
- #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4
+ #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112 0x2UL
+ #define PORT_PHY_QCFG_RESP_SIGNAL_MODE_LAST PORT_PHY_QCFG_RESP_SIGNAL_MODE_PAM4_112
#define PORT_PHY_QCFG_RESP_ACTIVE_FEC_MASK 0xf0UL
#define PORT_PHY_QCFG_RESP_ACTIVE_FEC_SFT 4
#define PORT_PHY_QCFG_RESP_ACTIVE_FEC_FEC_NONE_ACTIVE (0x0UL << 4)
@@ -4127,6 +4240,7 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_LINK_SPEED_50GB 0x1f4UL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_100GB 0x3e8UL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_200GB 0x7d0UL
+ #define PORT_PHY_QCFG_RESP_LINK_SPEED_400GB 0xfa0UL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_10MB 0xffffUL
#define PORT_PHY_QCFG_RESP_LINK_SPEED_LAST PORT_PHY_QCFG_RESP_LINK_SPEED_10MB
u8 duplex_cfg;
@@ -4270,7 +4384,23 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR2 0x25UL
#define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR2 0x26UL
#define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2 0x27UL
- #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER2
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASECR 0x28UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASESR 0x29UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASELR 0x2aUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_100G_BASEER 0x2bUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASECR2 0x2cUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASESR2 0x2dUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASELR2 0x2eUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_200G_BASEER2 0x2fUL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR8 0x30UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR8 0x31UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR8 0x32UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER8 0x33UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASECR4 0x34UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASESR4 0x35UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASELR4 0x36UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4 0x37UL
+ #define PORT_PHY_QCFG_RESP_PHY_TYPE_LAST PORT_PHY_QCFG_RESP_PHY_TYPE_400G_BASEER4
u8 media_type;
#define PORT_PHY_QCFG_RESP_MEDIA_TYPE_UNKNOWN 0x0UL
#define PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP 0x1UL
@@ -4366,6 +4496,7 @@ struct hwrm_port_phy_qcfg_output {
u8 option_flags;
#define PORT_PHY_QCFG_RESP_OPTION_FLAGS_MEDIA_AUTO_DETECT 0x1UL
#define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SIGNAL_MODE_KNOWN 0x2UL
+ #define PORT_PHY_QCFG_RESP_OPTION_FLAGS_SPEEDS2_SUPPORTED 0x4UL
char phy_vendor_name[16];
char phy_vendor_partnumber[16];
__le16 support_pam4_speeds;
@@ -4387,7 +4518,53 @@ struct hwrm_port_phy_qcfg_output {
#define PORT_PHY_QCFG_RESP_LINK_PARTNER_PAM4_ADV_SPEEDS_200GB 0x4UL
u8 link_down_reason;
#define PORT_PHY_QCFG_RESP_LINK_DOWN_REASON_RF 0x1UL
- u8 unused_0[7];
+ __le16 support_speeds2;
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_1GB 0x1UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_10GB 0x2UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_25GB 0x4UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_40GB 0x8UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB 0x10UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB 0x20UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_50GB_PAM4_56 0x40UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_56 0x80UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_56 0x100UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_56 0x200UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_100GB_PAM4_112 0x400UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_200GB_PAM4_112 0x800UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_400GB_PAM4_112 0x1000UL
+ #define PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS2_800GB_PAM4_112 0x2000UL
+ __le16 force_link_speeds2;
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_1GB 0xaUL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_10GB 0x64UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_25GB 0xfaUL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_40GB 0x190UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_50GB 0x1f4UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB 0x3e8UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_50GB_PAM4_56 0x1f5UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB_PAM4_56 0x3e9UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_200GB_PAM4_56 0x7d1UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_400GB_PAM4_56 0xfa1UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_100GB_PAM4_112 0x3eaUL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_200GB_PAM4_112 0x7d2UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_400GB_PAM4_112 0xfa2UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_800GB_PAM4_112 0x1f42UL
+ #define PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_LAST PORT_PHY_QCFG_RESP_FORCE_LINK_SPEEDS2_800GB_PAM4_112
+ __le16 auto_link_speeds2;
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_1GB 0x1UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_10GB 0x2UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_25GB 0x4UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_40GB 0x8UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_50GB 0x10UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB 0x20UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_50GB_PAM4_56 0x40UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB_PAM4_56 0x80UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_200GB_PAM4_56 0x100UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_400GB_PAM4_56 0x200UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_100GB_PAM4_112 0x400UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_200GB_PAM4_112 0x800UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_400GB_PAM4_112 0x1000UL
+ #define PORT_PHY_QCFG_RESP_AUTO_LINK_SPEEDS2_800GB_PAM4_112 0x2000UL
+ u8 active_lanes;
u8 valid;
};
@@ -4426,6 +4603,7 @@ struct hwrm_port_mac_cfg_input {
#define PORT_MAC_CFG_REQ_ENABLES_COS_FIELD_CFG 0x100UL
#define PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB 0x200UL
#define PORT_MAC_CFG_REQ_ENABLES_PTP_ADJ_PHASE 0x400UL
+ #define PORT_MAC_CFG_REQ_ENABLES_PTP_LOAD_CONTROL 0x800UL
__le16 port_id;
u8 ipg;
u8 lpbk;
@@ -4459,7 +4637,12 @@ struct hwrm_port_mac_cfg_input {
#define PORT_MAC_CFG_REQ_COS_FIELD_CFG_DEFAULT_COS_SFT 5
u8 unused_0[3];
__le32 ptp_freq_adj_ppb;
- u8 unused_1[4];
+ u8 unused_1[3];
+ u8 ptp_load_control;
+ #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_NONE 0x0UL
+ #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_IMMEDIATE 0x1UL
+ #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_PPS_EVENT 0x2UL
+ #define PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_LAST PORT_MAC_CFG_REQ_PTP_LOAD_CONTROL_PPS_EVENT
__le64 ptp_adj_phase;
};
@@ -4504,6 +4687,7 @@ struct hwrm_port_mac_ptp_qcfg_output {
#define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS 0x8UL
#define PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK 0x10UL
#define PORT_MAC_PTP_QCFG_RESP_FLAGS_RTC_CONFIGURED 0x20UL
+ #define PORT_MAC_PTP_QCFG_RESP_FLAGS_64B_PHC_TIME 0x40UL
u8 unused_0[3];
__le32 rx_ts_reg_off_lower;
__le32 rx_ts_reg_off_upper;
@@ -4968,7 +5152,7 @@ struct hwrm_port_phy_qcaps_input {
u8 unused_0[6];
};
-/* hwrm_port_phy_qcaps_output (size:256b/32B) */
+/* hwrm_port_phy_qcaps_output (size:320b/40B) */
struct hwrm_port_phy_qcaps_output {
__le16 error_code;
__le16 req_type;
@@ -5051,7 +5235,40 @@ struct hwrm_port_phy_qcaps_output {
#define PORT_PHY_QCAPS_RESP_FLAGS2_PAUSE_UNSUPPORTED 0x1UL
#define PORT_PHY_QCAPS_RESP_FLAGS2_PFC_UNSUPPORTED 0x2UL
#define PORT_PHY_QCAPS_RESP_FLAGS2_BANK_ADDR_SUPPORTED 0x4UL
+ #define PORT_PHY_QCAPS_RESP_FLAGS2_SPEEDS2_SUPPORTED 0x8UL
u8 internal_port_cnt;
+ u8 unused_0;
+ __le16 supported_speeds2_force_mode;
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_1GB 0x1UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_10GB 0x2UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_25GB 0x4UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_40GB 0x8UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_50GB 0x10UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB 0x20UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_50GB_PAM4_56 0x40UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB_PAM4_56 0x80UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_200GB_PAM4_56 0x100UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_400GB_PAM4_56 0x200UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_100GB_PAM4_112 0x400UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_200GB_PAM4_112 0x800UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_400GB_PAM4_112 0x1000UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_FORCE_MODE_800GB_PAM4_112 0x2000UL
+ __le16 supported_speeds2_auto_mode;
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_1GB 0x1UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_10GB 0x2UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_25GB 0x4UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_40GB 0x8UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_50GB 0x10UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB 0x20UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_50GB_PAM4_56 0x40UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB_PAM4_56 0x80UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_200GB_PAM4_56 0x100UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_400GB_PAM4_56 0x200UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_100GB_PAM4_112 0x400UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_200GB_PAM4_112 0x800UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_400GB_PAM4_112 0x1000UL
+ #define PORT_PHY_QCAPS_RESP_SUPPORTED_SPEEDS2_AUTO_MODE_800GB_PAM4_112 0x2000UL
+ u8 unused_1[3];
u8 valid;
};
@@ -5472,6 +5689,30 @@ struct hwrm_port_led_qcaps_output {
u8 valid;
};
+/* hwrm_port_mac_qcaps_input (size:192b/24B) */
+struct hwrm_port_mac_qcaps_input {
+ __le16 req_type;
+ __le16 cmpl_ring;
+ __le16 seq_id;
+ __le16 target_id;
+ __le64 resp_addr;
+ __le16 port_id;
+ u8 unused_0[6];
+};
+
+/* hwrm_port_mac_qcaps_output (size:128b/16B) */
+struct hwrm_port_mac_qcaps_output {
+ __le16 error_code;
+ __le16 req_type;
+ __le16 seq_id;
+ __le16 resp_len;
+ u8 flags;
+ #define PORT_MAC_QCAPS_RESP_FLAGS_LOCAL_LPBK_NOT_SUPPORTED 0x1UL
+ #define PORT_MAC_QCAPS_RESP_FLAGS_REMOTE_LPBK_SUPPORTED 0x2UL
+ u8 unused_0[6];
+ u8 valid;
+};
+
/* hwrm_queue_qportcfg_input (size:192b/24B) */
struct hwrm_queue_qportcfg_input {
__le16 req_type;
@@ -7488,7 +7729,7 @@ struct hwrm_cfa_ntuple_filter_alloc_input {
#define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD 0xffUL
#define CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_LAST CFA_NTUPLE_FILTER_ALLOC_REQ_IP_PROTOCOL_RSVD
__le16 dst_id;
- __le16 mirror_vnic_id;
+ __le16 rfs_ring_tbl_idx;
u8 tunnel_type;
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_NONTUNNEL 0x0UL
#define CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_VXLAN 0x1UL
@@ -8201,6 +8442,7 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output {
#define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_NO_L2CTX_SUPPORTED 0x40000UL
#define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NIC_FLOW_STATS_SUPPORTED 0x80000UL
#define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED 0x100000UL
+ #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V3_SUPPORTED 0x200000UL
u8 unused_0[3];
u8 valid;
};
@@ -8223,7 +8465,8 @@ struct hwrm_tunnel_dst_port_query_input {
#define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_ECPRI 0xeUL
#define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_SRV6 0xfUL
#define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE 0x10UL
- #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_VXLAN_GPE
+ #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_GRE 0x11UL
+ #define TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_QUERY_REQ_TUNNEL_TYPE_GRE
u8 tunnel_next_proto;
u8 unused_0[6];
};
@@ -8245,7 +8488,10 @@ struct hwrm_tunnel_dst_port_query_output {
#define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR5 0x20UL
#define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR6 0x40UL
#define TUNNEL_DST_PORT_QUERY_RESP_UPAR_IN_USE_UPAR7 0x80UL
- u8 unused_0[2];
+ u8 status;
+ #define TUNNEL_DST_PORT_QUERY_RESP_STATUS_CHIP_LEVEL 0x1UL
+ #define TUNNEL_DST_PORT_QUERY_RESP_STATUS_FUNC_LEVEL 0x2UL
+ u8 unused_0;
u8 valid;
};
@@ -8267,7 +8513,8 @@ struct hwrm_tunnel_dst_port_alloc_input {
#define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_ECPRI 0xeUL
#define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_SRV6 0xfUL
#define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE 0x10UL
- #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_VXLAN_GPE
+ #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GRE 0x11UL
+ #define TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_ALLOC_REQ_TUNNEL_TYPE_GRE
u8 tunnel_next_proto;
__be16 tunnel_dst_port_val;
u8 unused_0[4];
@@ -8284,7 +8531,8 @@ struct hwrm_tunnel_dst_port_alloc_output {
#define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_SUCCESS 0x0UL
#define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ALLOCATED 0x1UL
#define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE 0x2UL
- #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_NO_RESOURCE
+ #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ENABLED 0x3UL
+ #define TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_LAST TUNNEL_DST_PORT_ALLOC_RESP_ERROR_INFO_ERR_ENABLED
u8 upar_in_use;
#define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR0 0x1UL
#define TUNNEL_DST_PORT_ALLOC_RESP_UPAR_IN_USE_UPAR1 0x2UL
@@ -8316,7 +8564,8 @@ struct hwrm_tunnel_dst_port_free_input {
#define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_ECPRI 0xeUL
#define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_SRV6 0xfUL
#define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE 0x10UL
- #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN_GPE
+ #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GRE 0x11UL
+ #define TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_LAST TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GRE
u8 tunnel_next_proto;
__le16 tunnel_dst_port_id;
u8 unused_0[4];
@@ -9717,7 +9966,7 @@ struct hwrm_nvm_get_dev_info_input {
__le64 resp_addr;
};
-/* hwrm_nvm_get_dev_info_output (size:640b/80B) */
+/* hwrm_nvm_get_dev_info_output (size:704b/88B) */
struct hwrm_nvm_get_dev_info_output {
__le16 error_code;
__le16 req_type;
@@ -9747,6 +9996,10 @@ struct hwrm_nvm_get_dev_info_output {
__le16 roce_fw_minor;
__le16 roce_fw_build;
__le16 roce_fw_patch;
+ __le16 netctrl_fw_major;
+ __le16 netctrl_fw_minor;
+ __le16 netctrl_fw_build;
+ __le16 netctrl_fw_patch;
u8 unused_0[7];
u8 valid;
};
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
index 6e3da3362bd6..cc07660330f5 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
@@ -129,7 +129,7 @@ static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts)
}
resp = hwrm_req_hold(bp, req);
- rc = hwrm_req_send(bp, req);
+ rc = hwrm_req_send_silent(bp, req);
if (!rc)
*ts = le64_to_cpu(resp->ptp_msg_ts);
hwrm_req_drop(bp, req);
@@ -319,15 +319,17 @@ static int bnxt_ptp_cfg_event(struct bnxt *bp, u8 event)
return hwrm_req_send(bp, req);
}
-void bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp)
+int bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
struct hwrm_port_mac_cfg_input *req;
+ int rc;
if (!ptp || !ptp->tstamp_filters)
- return;
+ return -EIO;
- if (hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG))
+ rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG);
+ if (rc)
goto out;
if (!(bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) && (ptp->tstamp_filters &
@@ -342,15 +344,17 @@ void bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp)
req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_RX_TS_CAPTURE_PTP_MSG_TYPE);
req->rx_ts_capture_ptp_msg_type = cpu_to_le16(ptp->rxctl);
- if (!hwrm_req_send(bp, req)) {
+ rc = hwrm_req_send(bp, req);
+ if (!rc) {
bp->ptp_all_rx_tstamp = !!(ptp->tstamp_filters &
PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_ENABLE);
- return;
+ return 0;
}
ptp->tstamp_filters = 0;
out:
bp->ptp_all_rx_tstamp = 0;
netdev_warn(bp->dev, "Failed to configure HW packet timestamp filters\n");
+ return rc;
}
void bnxt_ptp_reapply_pps(struct bnxt *bp)
@@ -494,7 +498,6 @@ static int bnxt_hwrm_ptp_cfg(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
u32 flags = 0;
- int rc = 0;
switch (ptp->rx_filter) {
case HWTSTAMP_FILTER_ALL:
@@ -519,18 +522,7 @@ static int bnxt_hwrm_ptp_cfg(struct bnxt *bp)
ptp->tstamp_filters = flags;
- if (netif_running(bp->dev)) {
- if (ptp->rx_filter == HWTSTAMP_FILTER_ALL) {
- bnxt_close_nic(bp, false, false);
- rc = bnxt_open_nic(bp, false, false);
- } else {
- bnxt_ptp_cfg_tstamp_filters(bp);
- }
- if (!rc && !ptp->tstamp_filters)
- rc = -EIO;
- }
-
- return rc;
+ return bnxt_ptp_cfg_tstamp_filters(bp);
}
int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
@@ -649,7 +641,7 @@ static int bnxt_map_ptp_regs(struct bnxt *bp)
int rc, i;
reg_arr = ptp->refclk_regs;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (BNXT_CHIP_P5(bp)) {
rc = bnxt_map_regs(bp, reg_arr, 2, BNXT_PTP_GRC_WIN);
if (rc)
return rc;
@@ -692,8 +684,8 @@ static void bnxt_stamp_tx_skb(struct bnxt *bp, struct sk_buff *skb)
timestamp.hwtstamp = ns_to_ktime(ns);
skb_tstamp_tx(ptp->tx_skb, &timestamp);
} else {
- netdev_err(bp->dev, "TS query for TX timer failed rc = %x\n",
- rc);
+ netdev_warn_once(bp->dev,
+ "TS query for TX timer failed rc = %x\n", rc);
}
dev_kfree_skb_any(ptp->tx_skb);
@@ -966,7 +958,7 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
rc = err;
goto out;
}
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (BNXT_CHIP_P5(bp)) {
spin_lock_bh(&ptp->ptp_lock);
bnxt_refclk_read(bp, NULL, &ptp->current_time);
WRITE_ONCE(ptp->old_time, ptp->current_time);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
index 34162e07a119..fce8dc39a7d0 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h
@@ -137,7 +137,7 @@ do { \
int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id, u16 *hdr_off);
void bnxt_ptp_update_current_time(struct bnxt *bp);
void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2);
-void bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp);
+int bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp);
void bnxt_ptp_reapply_pps(struct bnxt *bp);
int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr);
int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
index c722b3b41730..175192ebaa77 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -536,7 +536,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset)
if (rc)
return rc;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
vf_msix = hw_resc->max_nqs - bnxt_nq_rings_in_use(bp);
vf_ring_grps = 0;
} else {
@@ -565,7 +565,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset)
req->min_l2_ctxs = cpu_to_le16(min);
req->min_vnics = cpu_to_le16(min);
req->min_stat_ctx = cpu_to_le16(min);
- if (!(bp->flags & BNXT_FLAG_CHIP_P5))
+ if (!(bp->flags & BNXT_FLAG_CHIP_P5_PLUS))
req->min_hw_ring_grps = cpu_to_le16(min);
} else {
vf_cp_rings /= num_vfs;
@@ -602,7 +602,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset)
req->max_stat_ctx = cpu_to_le16(vf_stat_ctx);
req->max_hw_ring_grps = cpu_to_le16(vf_ring_grps);
req->max_rsscos_ctx = cpu_to_le16(vf_rss);
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
req->max_msix = cpu_to_le16(vf_msix / num_vfs);
hwrm_req_hold(bp, req);
@@ -630,7 +630,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset)
le16_to_cpu(req->min_rsscos_ctx) * n;
hw_resc->max_stat_ctxs -= le16_to_cpu(req->min_stat_ctx) * n;
hw_resc->max_vnics -= le16_to_cpu(req->min_vnics) * n;
- if (bp->flags & BNXT_FLAG_CHIP_P5)
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
hw_resc->max_nqs -= vf_msix;
rc = pf->active_vfs;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
index 6ba2b9398633..93f9bd55020f 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
@@ -42,13 +42,10 @@ static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
for (i = 0; i < num_msix; i++) {
ent[i].vector = bp->irq_tbl[idx + i].vector;
ent[i].ring_idx = idx + i;
- if (bp->flags & BNXT_FLAG_CHIP_P5) {
- ent[i].db_offset = DB_PF_OFFSET_P5;
- if (BNXT_VF(bp))
- ent[i].db_offset = DB_VF_OFFSET_P5;
- } else {
+ if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
+ ent[i].db_offset = bp->db_offset;
+ else
ent[i].db_offset = (idx + i) * 0x80;
- }
}
}
@@ -333,6 +330,7 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp)
edev->pdev = bp->pdev;
edev->l2_db_size = bp->db_size;
edev->l2_db_size_nc = bp->db_size;
+ edev->l2_db_offset = bp->db_offset;
if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
index 6ff77f082e6c..b9e73de14b57 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
@@ -73,6 +73,10 @@ struct bnxt_en_dev {
* bytes mapped as non-
* cacheable.
*/
+ int l2_db_offset; /* Doorbell offset in
+ * bytes within
+ * l2_db_size_nc.
+ */
u16 chip_num;
u16 hw_ring_stats_size;
u16 pf_port_id;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
index 8cb9a99154aa..4079538bc310 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
@@ -42,17 +42,17 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
/* fill up the first buffer */
prod = txr->tx_prod;
- tx_buf = &txr->tx_buf_ring[prod];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
tx_buf->nr_frags = num_frags;
if (xdp)
tx_buf->page = virt_to_head_page(xdp->data);
- txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
+ txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
flags = (len << TX_BD_LEN_SHIFT) |
((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) |
bnxt_lhint_arr[len >> 9];
txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
- txbd->tx_bd_opaque = prod;
+ txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, 1 + num_frags);
txbd->tx_bd_haddr = cpu_to_le64(mapping);
/* now let us fill up the frags into the next buffers */
@@ -66,10 +66,10 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
WRITE_ONCE(txr->tx_prod, prod);
/* first fill up the first buffer */
- frag_tx_buf = &txr->tx_buf_ring[prod];
+ frag_tx_buf = &txr->tx_buf_ring[RING_TX(bp, prod)];
frag_tx_buf->page = skb_frag_page(frag);
- txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
+ txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)];
frag_len = skb_frag_size(frag);
flags = frag_len << TX_BD_LEN_SHIFT;
@@ -120,20 +120,20 @@ static void __bnxt_xmit_xdp_redirect(struct bnxt *bp,
void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
{
- struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
+ struct bnxt_tx_ring_info *txr = bnapi->tx_ring[0];
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
+ u16 tx_hw_cons = txr->tx_hw_cons;
bool rx_doorbell_needed = false;
- int nr_pkts = bnapi->tx_pkts;
struct bnxt_sw_tx_bd *tx_buf;
u16 tx_cons = txr->tx_cons;
u16 last_tx_cons = tx_cons;
- int i, j, frags;
+ int j, frags;
if (!budget)
return;
- for (i = 0; i < nr_pkts; i++) {
- tx_buf = &txr->tx_buf_ring[tx_cons];
+ while (RING_TX(bp, tx_cons) != tx_hw_cons) {
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, tx_cons)];
if (tx_buf->action == XDP_REDIRECT) {
struct pci_dev *pdev = bp->pdev;
@@ -153,20 +153,20 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int budget)
frags = tx_buf->nr_frags;
for (j = 0; j < frags; j++) {
tx_cons = NEXT_TX(tx_cons);
- tx_buf = &txr->tx_buf_ring[tx_cons];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, tx_cons)];
page_pool_recycle_direct(rxr->page_pool, tx_buf->page);
}
} else {
- bnxt_sched_reset_txr(bp, txr, i);
+ bnxt_sched_reset_txr(bp, txr, tx_cons);
return;
}
tx_cons = NEXT_TX(tx_cons);
}
- bnapi->tx_pkts = 0;
+ bnapi->events &= ~BNXT_TX_CMP_EVENT;
WRITE_ONCE(txr->tx_cons, tx_cons);
if (rx_doorbell_needed) {
- tx_buf = &txr->tx_buf_ring[last_tx_cons];
+ tx_buf = &txr->tx_buf_ring[RING_TX(bp, last_tx_cons)];
bnxt_db_write(bp, &rxr->rx_db, tx_buf->rx_prod);
}
@@ -242,7 +242,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
pdev = bp->pdev;
offset = bp->rx_offset;
- txr = rxr->bnapi->tx_ring;
+ txr = rxr->bnapi->tx_ring[0];
/* BNXT_RX_PAGE_MODE(bp) when XDP enabled */
orig_data = xdp.data;
@@ -268,7 +268,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
case XDP_TX:
rx_buf = &rxr->rx_buf_ring[cons];
mapping = rx_buf->mapping - bp->rx_dma_offset;
- *event = 0;
+ *event &= BNXT_TX_CMP_EVENT;
if (unlikely(xdp_buff_has_frags(&xdp))) {
struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(&xdp);
@@ -391,7 +391,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
struct net_device *dev = bp->dev;
- int tx_xdp = 0, rc, tc;
+ int tx_xdp = 0, tx_cp, rc, tc;
struct bpf_prog *old;
if (prog && !prog->aux->xdp_has_frags &&
@@ -407,7 +407,7 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
if (prog)
tx_xdp = bp->rx_nr_rings;
- tc = netdev_get_num_tc(dev);
+ tc = bp->num_tc;
if (!tc)
tc = 1;
rc = bnxt_check_rings(bp, bp->tx_nr_rings_per_tc, bp->rx_nr_rings,
@@ -439,7 +439,8 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
- bp->cp_nr_rings = max_t(int, bp->tx_nr_rings, bp->rx_nr_rings);
+ tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings);
+ bp->cp_nr_rings = max_t(int, tx_cp, bp->rx_nr_rings);
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index f52830dfb26a..04964bbe08cf 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -12745,24 +12745,23 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev)
return size;
}
-static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+static int tg3_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
{
struct tg3 *tp = netdev_priv(dev);
int i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (!rxfh->indir)
return 0;
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
- indir[i] = tp->rss_ind_tbl[i];
+ rxfh->indir[i] = tp->rss_ind_tbl[i];
return 0;
}
-static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
- const u8 hfunc)
+static int tg3_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct tg3 *tp = netdev_priv(dev);
size_t i;
@@ -12770,15 +12769,16 @@ static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++)
- tp->rss_ind_tbl[i] = indir[i];
+ tp->rss_ind_tbl[i] = rxfh->indir[i];
if (!netif_running(dev) || !tg3_flag(tp, ENABLE_RSS))
return 0;
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 31191b520b58..c32174484a96 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -1091,10 +1091,10 @@ bnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx)
* Free all TxQs buffers and then notify TX_E_CLEANUP_DONE to Tx fsm.
*/
static void
-bnad_tx_cleanup(struct delayed_work *work)
+bnad_tx_cleanup(struct work_struct *work)
{
struct bnad_tx_info *tx_info =
- container_of(work, struct bnad_tx_info, tx_cleanup_work);
+ container_of(work, struct bnad_tx_info, tx_cleanup_work.work);
struct bnad *bnad = NULL;
struct bna_tcb *tcb;
unsigned long flags;
@@ -1170,7 +1170,7 @@ bnad_cb_rx_stall(struct bnad *bnad, struct bna_rx *rx)
* Free all RxQs buffers and then notify RX_E_CLEANUP_DONE to Rx fsm.
*/
static void
-bnad_rx_cleanup(void *work)
+bnad_rx_cleanup(struct work_struct *work)
{
struct bnad_rx_info *rx_info =
container_of(work, struct bnad_rx_info, rx_cleanup_work);
@@ -1991,8 +1991,7 @@ bnad_setup_tx(struct bnad *bnad, u32 tx_id)
}
tx_info->tx = tx;
- INIT_DELAYED_WORK(&tx_info->tx_cleanup_work,
- (work_func_t)bnad_tx_cleanup);
+ INIT_DELAYED_WORK(&tx_info->tx_cleanup_work, bnad_tx_cleanup);
/* Register ISR for the Tx object */
if (intr_info->intr_type == BNA_INTR_T_MSIX) {
@@ -2248,8 +2247,7 @@ bnad_setup_rx(struct bnad *bnad, u32 rx_id)
rx_info->rx = rx;
spin_unlock_irqrestore(&bnad->bna_lock, flags);
- INIT_WORK(&rx_info->rx_cleanup_work,
- (work_func_t)(bnad_rx_cleanup));
+ INIT_WORK(&rx_info->rx_cleanup_work, bnad_rx_cleanup);
/*
* Init NAPI, so that state is set to NAPI_STATE_SCHED,
diff --git a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
index df10edff5603..d1ad6c9f8140 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_ethtool.c
@@ -608,7 +608,7 @@ bnad_get_strings(struct net_device *netdev, u32 stringset, u8 *string)
for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
BUG_ON(!(strlen(bnad_net_stats_strings[i]) < ETH_GSTRING_LEN));
- ethtool_sprintf(&string, bnad_net_stats_strings[i]);
+ ethtool_puts(&string, bnad_net_stats_strings[i]);
}
bmap = bna_tx_rid_mask(&bnad->bna);
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 78c972bb1d96..aa5700ac9c00 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -1165,9 +1165,10 @@ struct macb_ptp_info {
int (*get_ts_info)(struct net_device *dev,
struct ethtool_ts_info *info);
int (*get_hwtst)(struct net_device *netdev,
- struct ifreq *ifr);
+ struct kernel_hwtstamp_config *tstamp_config);
int (*set_hwtst)(struct net_device *netdev,
- struct ifreq *ifr, int cmd);
+ struct kernel_hwtstamp_config *tstamp_config,
+ struct netlink_ext_ack *extack);
};
struct macb_pm_data {
@@ -1314,7 +1315,7 @@ struct macb {
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
struct tsu_incr tsu_incr;
- struct hwtstamp_config tstamp_config;
+ struct kernel_hwtstamp_config tstamp_config;
/* RX queue filer rule set*/
struct ethtool_rx_fs_list rx_fs_list;
@@ -1363,8 +1364,12 @@ static inline void gem_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb, stru
gem_ptp_rxstamp(bp, skb, desc);
}
-int gem_get_hwtst(struct net_device *dev, struct ifreq *rq);
-int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+int gem_get_hwtst(struct net_device *dev,
+ struct kernel_hwtstamp_config *tstamp_config);
+int gem_set_hwtst(struct net_device *dev,
+ struct kernel_hwtstamp_config *tstamp_config,
+ struct netlink_ext_ack *extack);
#else
static inline void gem_ptp_init(struct net_device *ndev) { }
static inline void gem_ptp_remove(struct net_device *ndev) { }
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index cebae0f418f2..898debfd4db3 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -3773,18 +3773,38 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!netif_running(dev))
return -EINVAL;
- if (bp->ptp_info) {
- switch (cmd) {
- case SIOCSHWTSTAMP:
- return bp->ptp_info->set_hwtst(dev, rq, cmd);
- case SIOCGHWTSTAMP:
- return bp->ptp_info->get_hwtst(dev, rq);
- }
- }
-
return phylink_mii_ioctl(bp->phylink, rq, cmd);
}
+static int macb_hwtstamp_get(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg)
+{
+ struct macb *bp = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!bp->ptp_info)
+ return -EOPNOTSUPP;
+
+ return bp->ptp_info->get_hwtst(dev, cfg);
+}
+
+static int macb_hwtstamp_set(struct net_device *dev,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct macb *bp = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!bp->ptp_info)
+ return -EOPNOTSUPP;
+
+ return bp->ptp_info->set_hwtst(dev, cfg, extack);
+}
+
static inline void macb_set_txcsum_feature(struct macb *bp,
netdev_features_t features)
{
@@ -3884,6 +3904,8 @@ static const struct net_device_ops macb_netdev_ops = {
#endif
.ndo_set_features = macb_set_features,
.ndo_features_check = macb_features_check,
+ .ndo_hwtstamp_set = macb_hwtstamp_set,
+ .ndo_hwtstamp_get = macb_hwtstamp_get,
};
/* Configure peripheral capabilities according to device tree
@@ -4539,6 +4561,8 @@ static const struct net_device_ops at91ether_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = at91ether_poll_controller,
#endif
+ .ndo_hwtstamp_set = macb_hwtstamp_set,
+ .ndo_hwtstamp_get = macb_hwtstamp_get,
};
static int at91ether_clk_init(struct platform_device *pdev, struct clk **pclk,
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 51d26fa190d7..a63bf29c4fa8 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -374,19 +374,16 @@ static int gem_ptp_set_ts_mode(struct macb *bp,
return 0;
}
-int gem_get_hwtst(struct net_device *dev, struct ifreq *rq)
+int gem_get_hwtst(struct net_device *dev,
+ struct kernel_hwtstamp_config *tstamp_config)
{
- struct hwtstamp_config *tstamp_config;
struct macb *bp = netdev_priv(dev);
- tstamp_config = &bp->tstamp_config;
+ *tstamp_config = bp->tstamp_config;
if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0)
return -EOPNOTSUPP;
- if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config)))
- return -EFAULT;
- else
- return 0;
+ return 0;
}
static void gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
@@ -401,22 +398,18 @@ static void gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
macb_writel(bp, NCR, reg_val & ~MACB_BIT(OSSMODE));
}
-int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
+int gem_set_hwtst(struct net_device *dev,
+ struct kernel_hwtstamp_config *tstamp_config,
+ struct netlink_ext_ack *extack)
{
enum macb_bd_control tx_bd_control = TSTAMP_DISABLED;
enum macb_bd_control rx_bd_control = TSTAMP_DISABLED;
- struct hwtstamp_config *tstamp_config;
struct macb *bp = netdev_priv(dev);
u32 regval;
- tstamp_config = &bp->tstamp_config;
if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0)
return -EOPNOTSUPP;
- if (copy_from_user(tstamp_config, ifr->ifr_data,
- sizeof(*tstamp_config)))
- return -EFAULT;
-
switch (tstamp_config->tx_type) {
case HWTSTAMP_TX_OFF:
break;
@@ -463,12 +456,11 @@ int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
return -ERANGE;
}
+ bp->tstamp_config = *tstamp_config;
+
if (gem_ptp_set_ts_mode(bp, tx_bd_control, rx_bd_control) != 0)
return -ERANGE;
- if (copy_to_user(ifr->ifr_data, tstamp_config, sizeof(*tstamp_config)))
- return -EFAULT;
- else
- return 0;
+ return 0;
}
diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
index 068ed52b66c9..b3c81a2e9d46 100644
--- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
@@ -1490,7 +1490,7 @@ int cn23xx_get_vf_stats(struct octeon_device *oct, int vfidx,
mbox_cmd.q_no = vfidx * oct->sriov_info.rings_per_vf;
mbox_cmd.recv_len = 0;
mbox_cmd.recv_status = 0;
- mbox_cmd.fn = (octeon_mbox_callback_t)cn23xx_get_vf_stats_callback;
+ mbox_cmd.fn = cn23xx_get_vf_stats_callback;
ctx.stats = stats;
atomic_set(&ctx.status, 0);
mbox_cmd.fn_arg = (void *)&ctx;
diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c
index dd5d80fee24f..d2fcb3da484e 100644
--- a/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_vf_device.c
@@ -429,7 +429,7 @@ int cn23xx_octeon_pfvf_handshake(struct octeon_device *oct)
mbox_cmd.q_no = 0;
mbox_cmd.recv_len = 0;
mbox_cmd.recv_status = 0;
- mbox_cmd.fn = (octeon_mbox_callback_t)octeon_pfvf_hs_callback;
+ mbox_cmd.fn = octeon_pfvf_hs_callback;
mbox_cmd.fn_arg = &status;
octeon_mbox_write(oct, &mbox_cmd);
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c
index 9cc6303c82ff..f38d31bfab1b 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_core.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c
@@ -27,6 +27,7 @@
#include "octeon_network.h"
MODULE_AUTHOR("Cavium Networks, <support@cavium.com>");
+MODULE_DESCRIPTION("Cavium LiquidIO Intelligent Server Adapter Core");
MODULE_LICENSE("GPL");
/* OOM task polling interval */
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h
index d92bd7e16477..9ac85d22c615 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.h
@@ -57,7 +57,10 @@ union octeon_mbox_message {
} s;
};
-typedef void (*octeon_mbox_callback_t)(void *, void *, void *);
+struct octeon_mbox_cmd;
+
+typedef void (*octeon_mbox_callback_t)(struct octeon_device *,
+ struct octeon_mbox_cmd *, void *);
struct octeon_mbox_cmd {
union octeon_mbox_message msg;
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
index d8d71bf97983..34125b8cd935 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
@@ -653,35 +653,36 @@ static u32 nicvf_get_rxfh_indir_size(struct net_device *dev)
return nic->rss_info.rss_size;
}
-static int nicvf_get_rxfh(struct net_device *dev, u32 *indir, u8 *hkey,
- u8 *hfunc)
+static int nicvf_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct nicvf *nic = netdev_priv(dev);
struct nicvf_rss_info *rss = &nic->rss_info;
int idx;
- if (indir) {
+ if (rxfh->indir) {
for (idx = 0; idx < rss->rss_size; idx++)
- indir[idx] = rss->ind_tbl[idx];
+ rxfh->indir[idx] = rss->ind_tbl[idx];
}
- if (hkey)
- memcpy(hkey, rss->key, RSS_HASH_KEY_SIZE * sizeof(u64));
+ if (rxfh->key)
+ memcpy(rxfh->key, rss->key, RSS_HASH_KEY_SIZE * sizeof(u64));
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int nicvf_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *hkey, const u8 hfunc)
+static int nicvf_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct nicvf *nic = netdev_priv(dev);
struct nicvf_rss_info *rss = &nic->rss_info;
int idx;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
if (!rss->enable) {
@@ -690,13 +691,13 @@ static int nicvf_set_rxfh(struct net_device *dev, const u32 *indir,
return -EIO;
}
- if (indir) {
+ if (rxfh->indir) {
for (idx = 0; idx < rss->rss_size; idx++)
- rss->ind_tbl[idx] = indir[idx];
+ rss->ind_tbl[idx] = rxfh->indir[idx];
}
- if (hkey) {
- memcpy(rss->key, hkey, RSS_HASH_KEY_SIZE * sizeof(u64));
+ if (rxfh->key) {
+ memcpy(rss->key, rxfh->key, RSS_HASH_KEY_SIZE * sizeof(u64));
nicvf_set_rss_key(nic);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb3/adapter.h b/drivers/net/ethernet/chelsio/cxgb3/adapter.h
index 6d682b7c7aac..9d11e55981a0 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb3/adapter.h
@@ -237,7 +237,7 @@ struct adapter {
int msix_nvectors;
struct {
unsigned short vec;
- char desc[22];
+ char desc[IFNAMSIZ + 1 + 12]; /* Needs space for "%s-%d" */
} msix_info[SGE_QSETS + 1];
/* T3 modules */
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
index d117022d15d7..2236f1d35f2b 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
@@ -380,19 +380,18 @@ static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
*/
static void name_msix_vecs(struct adapter *adap)
{
- int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
+ int i, j, msi_idx = 1;
- snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
- adap->msix_info[0].desc[n] = 0;
+ strscpy(adap->msix_info[0].desc, adap->name, sizeof(adap->msix_info[0].desc));
for_each_port(adap, j) {
struct net_device *d = adap->port[j];
const struct port_info *pi = netdev_priv(d);
for (i = 0; i < pi->nqsets; i++, msi_idx++) {
- snprintf(adap->msix_info[msi_idx].desc, n,
+ snprintf(adap->msix_info[msi_idx].desc,
+ sizeof(adap->msix_info[0].desc),
"%s-%d", d->name, pi->first_qset + i);
- adap->msix_info[msi_idx].desc[n] = 0;
}
}
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
index 8477a93cee6b..47eecde36285 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
@@ -1588,22 +1588,23 @@ static u32 get_rss_table_size(struct net_device *dev)
return pi->rss_size;
}
-static int get_rss_table(struct net_device *dev, u32 *p, u8 *key, u8 *hfunc)
+static int get_rss_table(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
const struct port_info *pi = netdev_priv(dev);
unsigned int n = pi->rss_size;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!p)
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (!rxfh->indir)
return 0;
while (n--)
- p[n] = pi->rss[n];
+ rxfh->indir[n] = pi->rss[n];
return 0;
}
-static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key,
- const u8 hfunc)
+static int set_rss_table(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
unsigned int i;
struct port_info *pi = netdev_priv(dev);
@@ -1611,16 +1612,17 @@ static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key,
/* We require at least one supported parameter to be changed and no
* change in any of the unsupported parameters
*/
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!p)
+ if (!rxfh->indir)
return 0;
/* Interface must be brought up atleast once */
if (pi->adapter->flags & CXGB4_FULL_INIT_DONE) {
for (i = 0; i < pi->rss_size; i++)
- pi->rss[i] = p[i];
+ pi->rss[i] = rxfh->indir[i];
return cxgb4_write_rss(pi, pi->rss);
}
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 1c2a540db13d..1f495cfd7959 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -868,5 +868,6 @@ static struct platform_driver ep93xx_eth_driver = {
module_platform_driver(ep93xx_eth_driver);
+MODULE_DESCRIPTION("Cirrus EP93xx Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ep93xx-eth");
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index 08b7cc0a1809..241906697019 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -568,31 +568,32 @@ static u32 enic_get_rxfh_key_size(struct net_device *netdev)
return ENIC_RSS_LEN;
}
-static int enic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey,
- u8 *hfunc)
+static int enic_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct enic *enic = netdev_priv(netdev);
- if (hkey)
- memcpy(hkey, enic->rss_key, ENIC_RSS_LEN);
+ if (rxfh->key)
+ memcpy(rxfh->key, enic->rss_key, ENIC_RSS_LEN);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int enic_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *hkey, const u8 hfunc)
+static int enic_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct enic *enic = netdev_priv(netdev);
- if ((hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) ||
- indir)
+ if (rxfh->indir ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EINVAL;
- if (hkey)
- memcpy(enic->rss_key, hkey, ENIC_RSS_LEN);
+ if (rxfh->key)
+ memcpy(enic->rss_key, rxfh->key, ENIC_RSS_LEN);
return __enic_set_rsskey(enic);
}
diff --git a/drivers/net/ethernet/cisco/enic/vnic_vic.c b/drivers/net/ethernet/cisco/enic/vnic_vic.c
index 20fcb20b42ed..66b577835338 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_vic.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_vic.c
@@ -49,7 +49,8 @@ int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
tlv->type = htons(type);
tlv->length = htons(length);
- memcpy(tlv->value, value, length);
+ unsafe_memcpy(tlv->value, value, length,
+ /* Flexible array of flexible arrays */);
vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
vp->length = htonl(ntohl(vp->length) +
diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c
index 78287cfcbf63..705c3eb19cd3 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -79,8 +79,7 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
#define GMAC0_IRQ4_8 (GMAC0_MIB_INT_BIT | GMAC0_RX_OVERRUN_INT_BIT)
#define GMAC_OFFLOAD_FEATURES (NETIF_F_SG | NETIF_F_IP_CSUM | \
- NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | \
- NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM)
/**
* struct gmac_queue_page - page buffer per-page info
@@ -1143,23 +1142,13 @@ static int gmac_map_tx_bufs(struct net_device *netdev, struct sk_buff *skb,
struct gmac_txdesc *txd;
skb_frag_t *skb_frag;
dma_addr_t mapping;
- unsigned short mtu;
void *buffer;
int ret;
- mtu = ETH_HLEN;
- mtu += netdev->mtu;
- if (skb->protocol == htons(ETH_P_8021Q))
- mtu += VLAN_HLEN;
-
+ /* TODO: implement proper TSO using MTU in word3 */
word1 = skb->len;
word3 = SOF_BIT;
- if (word1 > mtu) {
- word1 |= TSS_MTU_ENABLE_BIT;
- word3 |= mtu;
- }
-
if (skb->len >= ETH_FRAME_LEN) {
/* Hardware offloaded checksumming isn't working on frames
* bigger than 1514 bytes. A hypothesis about this is that the
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index db6615aa921b..7bfeae04b52b 100644
--- a/drivers/net/ethernet/dlink/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -565,8 +565,7 @@ static void rio_hw_init(struct net_device *dev)
* too. However, it doesn't work on IP1000A so we use 16-bit access.
*/
for (i = 0; i < 3; i++)
- dw16(StationAddr0 + 2 * i,
- cpu_to_le16(((const u16 *)dev->dev_addr)[i]));
+ dw16(StationAddr0 + 2 * i, get_unaligned_le16(&dev->dev_addr[2 * i]));
set_multicast (dev);
if (np->coalesce) {
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index a29de29bdf23..f001a649f58f 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1271,43 +1271,45 @@ static u32 be_get_rxfh_key_size(struct net_device *netdev)
return RSS_HASH_KEY_LEN;
}
-static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey,
- u8 *hfunc)
+static int be_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct be_adapter *adapter = netdev_priv(netdev);
int i;
struct rss_info *rss = &adapter->rss_info;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < RSS_INDIR_TABLE_LEN; i++)
- indir[i] = rss->rss_queue[i];
+ rxfh->indir[i] = rss->rss_queue[i];
}
- if (hkey)
- memcpy(hkey, rss->rss_hkey, RSS_HASH_KEY_LEN);
+ if (rxfh->key)
+ memcpy(rxfh->key, rss->rss_hkey, RSS_HASH_KEY_LEN);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int be_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *hkey, const u8 hfunc)
+static int be_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
int rc = 0, i, j;
struct be_adapter *adapter = netdev_priv(netdev);
+ u8 *hkey = rxfh->key;
u8 rsstable[RSS_INDIR_TABLE_LEN];
/* We do not allow change in unsupported parameters */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (indir) {
+ if (rxfh->indir) {
struct be_rx_obj *rxo;
for (i = 0; i < RSS_INDIR_TABLE_LEN; i++) {
- j = indir[i];
+ j = rxfh->indir[i];
rxo = &adapter->rx_obj[j];
rsstable[i] = rxo->rss_id;
adapter->rss_info.rss_queue[i] = j;
diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c
index df40c720e7b2..64eadd320798 100644
--- a/drivers/net/ethernet/engleder/tsnep_main.c
+++ b/drivers/net/ethernet/engleder/tsnep_main.c
@@ -719,17 +719,25 @@ static void tsnep_xdp_xmit_flush(struct tsnep_tx *tx)
static bool tsnep_xdp_xmit_back(struct tsnep_adapter *adapter,
struct xdp_buff *xdp,
- struct netdev_queue *tx_nq, struct tsnep_tx *tx)
+ struct netdev_queue *tx_nq, struct tsnep_tx *tx,
+ bool zc)
{
struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp);
bool xmit;
+ u32 type;
if (unlikely(!xdpf))
return false;
+ /* no page pool for zero copy */
+ if (zc)
+ type = TSNEP_TX_TYPE_XDP_NDO;
+ else
+ type = TSNEP_TX_TYPE_XDP_TX;
+
__netif_tx_lock(tx_nq, smp_processor_id());
- xmit = tsnep_xdp_xmit_frame_ring(xdpf, tx, TSNEP_TX_TYPE_XDP_TX);
+ xmit = tsnep_xdp_xmit_frame_ring(xdpf, tx, type);
/* Avoid transmit queue timeout since we share it with the slow path */
if (xmit)
@@ -1273,7 +1281,7 @@ static bool tsnep_xdp_run_prog(struct tsnep_rx *rx, struct bpf_prog *prog,
case XDP_PASS:
return false;
case XDP_TX:
- if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx))
+ if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx, false))
goto out_failure;
*status |= TSNEP_XDP_TX;
return true;
@@ -1323,7 +1331,7 @@ static bool tsnep_xdp_run_prog_zc(struct tsnep_rx *rx, struct bpf_prog *prog,
case XDP_PASS:
return false;
case XDP_TX:
- if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx))
+ if (!tsnep_xdp_xmit_back(rx->adapter, xdp, tx_nq, tx, true))
goto out_failure;
*status |= TSNEP_XDP_TX;
return true;
@@ -1485,7 +1493,7 @@ static int tsnep_rx_poll(struct tsnep_rx *rx, struct napi_struct *napi,
xdp_prepare_buff(&xdp, page_address(entry->page),
XDP_PACKET_HEADROOM + TSNEP_RX_INLINE_METADATA_SIZE,
- length, false);
+ length - ETH_FCS_LEN, false);
consume = tsnep_xdp_run_prog(rx, prog, &xdp,
&xdp_status, tx_nq, tx);
@@ -1568,7 +1576,7 @@ static int tsnep_rx_poll_zc(struct tsnep_rx *rx, struct napi_struct *napi,
prefetch(entry->xdp->data);
length = __le32_to_cpu(entry->desc_wb->properties) &
TSNEP_DESC_LENGTH_MASK;
- xsk_buff_set_size(entry->xdp, length);
+ xsk_buff_set_size(entry->xdp, length - ETH_FCS_LEN);
xsk_buff_dma_sync_for_cpu(entry->xdp, rx->xsk_pool);
/* RX metadata with timestamps is in front of actual data,
@@ -1762,6 +1770,19 @@ static void tsnep_rx_reopen_xsk(struct tsnep_rx *rx)
allocated--;
}
}
+
+ /* set need wakeup flag immediately if ring is not filled completely,
+ * first polling would be too late as need wakeup signalisation would
+ * be delayed for an indefinite time
+ */
+ if (xsk_uses_need_wakeup(rx->xsk_pool)) {
+ int desc_available = tsnep_rx_desc_available(rx);
+
+ if (desc_available)
+ xsk_set_rx_need_wakeup(rx->xsk_pool);
+ else
+ xsk_clear_rx_need_wakeup(rx->xsk_pool);
+ }
}
static bool tsnep_pending(struct tsnep_queue *queue)
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c
index 4d7184d46824..9ebe751c1df0 100644
--- a/drivers/net/ethernet/ezchip/nps_enet.c
+++ b/drivers/net/ethernet/ezchip/nps_enet.c
@@ -633,7 +633,7 @@ out_netdev:
return err;
}
-static s32 nps_enet_remove(struct platform_device *pdev)
+static void nps_enet_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct nps_enet_priv *priv = netdev_priv(ndev);
@@ -641,8 +641,6 @@ static s32 nps_enet_remove(struct platform_device *pdev)
unregister_netdev(ndev);
netif_napi_del(&priv->napi);
free_netdev(ndev);
-
- return 0;
}
static const struct of_device_id nps_enet_dt_ids[] = {
@@ -653,7 +651,7 @@ MODULE_DEVICE_TABLE(of, nps_enet_dt_ids);
static struct platform_driver nps_enet_driver = {
.probe = nps_enet_probe,
- .remove = nps_enet_remove,
+ .remove_new = nps_enet_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = nps_enet_dt_ids,
@@ -663,4 +661,5 @@ static struct platform_driver nps_enet_driver = {
module_platform_driver(nps_enet_driver);
MODULE_AUTHOR("EZchip Semiconductor");
+MODULE_DESCRIPTION("EZchip NPS Ethernet driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index e01a246124ac..f3543a2df68d 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -289,7 +289,7 @@ static int dpaa2_switch_port_add_vlan(struct ethsw_port_priv *port_priv,
int err;
if (port_priv->vlans[vid]) {
- netdev_warn(netdev, "VLAN %d already configured\n", vid);
+ netdev_err(netdev, "VLAN %d already configured\n", vid);
return -EEXIST;
}
@@ -1509,9 +1509,9 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
struct device *dev = (struct device *)arg;
struct ethsw_core *ethsw = dev_get_drvdata(dev);
struct ethsw_port_priv *port_priv;
- u32 status = ~0;
int err, if_id;
bool had_mac;
+ u32 status;
err = dpsw_get_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, &status);
@@ -1523,12 +1523,11 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
if_id = (status & 0xFFFF0000) >> 16;
port_priv = ethsw->ports[if_id];
- if (status & DPSW_IRQ_EVENT_LINK_CHANGED) {
+ if (status & DPSW_IRQ_EVENT_LINK_CHANGED)
dpaa2_switch_port_link_state_update(port_priv->netdev);
- dpaa2_switch_port_set_mac_addr(port_priv);
- }
if (status & DPSW_IRQ_EVENT_ENDPOINT_CHANGED) {
+ dpaa2_switch_port_set_mac_addr(port_priv);
/* We can avoid locking because the "endpoint changed" IRQ
* handler is the only one who changes priv->mac at runtime,
* so we are not racing with anyone.
@@ -1540,20 +1539,20 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
dpaa2_switch_port_connect_mac(port_priv);
}
-out:
err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, status);
if (err)
dev_err(dev, "Can't clear irq status (err %d)\n", err);
+out:
return IRQ_HANDLED;
}
static int dpaa2_switch_setup_irqs(struct fsl_mc_device *sw_dev)
{
+ u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED | DPSW_IRQ_EVENT_ENDPOINT_CHANGED;
struct device *dev = &sw_dev->dev;
struct ethsw_core *ethsw = dev_get_drvdata(dev);
- u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED;
struct fsl_mc_device_irq *irq;
int err;
@@ -1775,8 +1774,10 @@ int dpaa2_switch_port_vlans_add(struct net_device *netdev,
/* Make sure that the VLAN is not already configured
* on the switch port
*/
- if (port_priv->vlans[vlan->vid] & ETHSW_VLAN_MEMBER)
+ if (port_priv->vlans[vlan->vid] & ETHSW_VLAN_MEMBER) {
+ netdev_err(netdev, "VLAN %d already configured\n", vlan->vid);
return -EEXIST;
+ }
/* Check if there is space for a new VLAN */
err = dpsw_get_attributes(ethsw->mc_io, 0, ethsw->dpsw_handle,
@@ -2003,25 +2004,11 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
struct netlink_ext_ack *extack)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct dpaa2_switch_fdb *old_fdb = port_priv->fdb;
struct ethsw_core *ethsw = port_priv->ethsw_data;
- struct ethsw_port_priv *other_port_priv;
- struct net_device *other_dev;
- struct list_head *iter;
bool learn_ena;
int err;
- netdev_for_each_lower_dev(upper_dev, other_dev, iter) {
- if (!dpaa2_switch_port_dev_check(other_dev))
- continue;
-
- other_port_priv = netdev_priv(other_dev);
- if (other_port_priv->ethsw_data != port_priv->ethsw_data) {
- NL_SET_ERR_MSG_MOD(extack,
- "Interface from a different DPSW is in the bridge already");
- return -EINVAL;
- }
- }
-
/* Delete the previously manually installed VLAN 1 */
err = dpaa2_switch_port_del_vlan(port_priv, 1);
if (err)
@@ -2039,6 +2026,11 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
if (err)
goto err_egress_flood;
+ /* Recreate the egress flood domain of the FDB that we just left. */
+ err = dpaa2_switch_fdb_set_egress_flood(ethsw, old_fdb->fdb_id);
+ if (err)
+ goto err_egress_flood;
+
err = switchdev_bridge_port_offload(netdev, netdev, NULL,
NULL, NULL, false, extack);
if (err)
@@ -2155,6 +2147,10 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev,
struct net_device *upper_dev,
struct netlink_ext_ack *extack)
{
+ struct ethsw_port_priv *port_priv = netdev_priv(netdev);
+ struct ethsw_port_priv *other_port_priv;
+ struct net_device *other_dev;
+ struct list_head *iter;
int err;
if (!br_vlan_enabled(upper_dev)) {
@@ -2169,54 +2165,93 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev,
return 0;
}
+ netdev_for_each_lower_dev(upper_dev, other_dev, iter) {
+ if (!dpaa2_switch_port_dev_check(other_dev))
+ continue;
+
+ other_port_priv = netdev_priv(other_dev);
+ if (other_port_priv->ethsw_data != port_priv->ethsw_data) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Interface from a different DPSW is in the bridge already");
+ return -EINVAL;
+ }
+ }
+
return 0;
}
-static int dpaa2_switch_port_netdevice_event(struct notifier_block *nb,
- unsigned long event, void *ptr)
+static int dpaa2_switch_port_prechangeupper(struct net_device *netdev,
+ struct netdev_notifier_changeupper_info *info)
{
- struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
- struct netdev_notifier_changeupper_info *info = ptr;
struct netlink_ext_ack *extack;
struct net_device *upper_dev;
- int err = 0;
+ int err;
if (!dpaa2_switch_port_dev_check(netdev))
- return NOTIFY_DONE;
+ return 0;
extack = netdev_notifier_info_to_extack(&info->info);
-
- switch (event) {
- case NETDEV_PRECHANGEUPPER:
- upper_dev = info->upper_dev;
- if (!netif_is_bridge_master(upper_dev))
- break;
-
+ upper_dev = info->upper_dev;
+ if (netif_is_bridge_master(upper_dev)) {
err = dpaa2_switch_prechangeupper_sanity_checks(netdev,
upper_dev,
extack);
if (err)
- goto out;
+ return err;
if (!info->linking)
dpaa2_switch_port_pre_bridge_leave(netdev);
+ }
+
+ return 0;
+}
+
+static int dpaa2_switch_port_changeupper(struct net_device *netdev,
+ struct netdev_notifier_changeupper_info *info)
+{
+ struct netlink_ext_ack *extack;
+ struct net_device *upper_dev;
+
+ if (!dpaa2_switch_port_dev_check(netdev))
+ return 0;
+
+ extack = netdev_notifier_info_to_extack(&info->info);
+
+ upper_dev = info->upper_dev;
+ if (netif_is_bridge_master(upper_dev)) {
+ if (info->linking)
+ return dpaa2_switch_port_bridge_join(netdev,
+ upper_dev,
+ extack);
+ else
+ return dpaa2_switch_port_bridge_leave(netdev);
+ }
+
+ return 0;
+}
+
+static int dpaa2_switch_port_netdevice_event(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ int err = 0;
+
+ switch (event) {
+ case NETDEV_PRECHANGEUPPER:
+ err = dpaa2_switch_port_prechangeupper(netdev, ptr);
+ if (err)
+ return notifier_from_errno(err);
break;
case NETDEV_CHANGEUPPER:
- upper_dev = info->upper_dev;
- if (netif_is_bridge_master(upper_dev)) {
- if (info->linking)
- err = dpaa2_switch_port_bridge_join(netdev,
- upper_dev,
- extack);
- else
- err = dpaa2_switch_port_bridge_leave(netdev);
- }
+ err = dpaa2_switch_port_changeupper(netdev, ptr);
+ if (err)
+ return notifier_from_errno(err);
+
break;
}
-out:
- return notifier_from_errno(err);
+ return NOTIFY_DONE;
}
struct ethsw_switchdev_event_work {
@@ -3294,6 +3329,7 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
port_netdev->features = NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_HW_VLAN_STAG_FILTER |
NETIF_F_HW_TC;
+ port_netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
err = dpaa2_switch_port_init(port_priv, port_idx);
if (err)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index cffbf27c4656..bfdbdab443ae 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -3216,4 +3216,5 @@ void enetc_pci_remove(struct pci_dev *pdev)
}
EXPORT_SYMBOL_GPL(enetc_pci_remove);
+MODULE_DESCRIPTION("NXP ENETC Ethernet driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index e993ed04ab57..f7753ea5b57e 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -690,25 +690,26 @@ static u32 enetc_get_rxfh_indir_size(struct net_device *ndev)
return priv->si->num_rss;
}
-static int enetc_get_rxfh(struct net_device *ndev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int enetc_get_rxfh(struct net_device *ndev,
+ struct ethtool_rxfh_param *rxfh)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_hw *hw = &priv->si->hw;
int err = 0, i;
/* return hash function */
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
/* return hash key */
- if (key && hw->port)
+ if (rxfh->key && hw->port)
for (i = 0; i < ENETC_RSSHASH_KEY_SIZE / 4; i++)
- ((u32 *)key)[i] = enetc_port_rd(hw, ENETC_PRSSK(i));
+ ((u32 *)rxfh->key)[i] = enetc_port_rd(hw,
+ ENETC_PRSSK(i));
/* return RSS table */
- if (indir)
- err = enetc_get_rss_table(priv->si, indir, priv->si->num_rss);
+ if (rxfh->indir)
+ err = enetc_get_rss_table(priv->si, rxfh->indir,
+ priv->si->num_rss);
return err;
}
@@ -722,20 +723,22 @@ void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes)
}
EXPORT_SYMBOL_GPL(enetc_set_rss_key);
-static int enetc_set_rxfh(struct net_device *ndev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int enetc_set_rxfh(struct net_device *ndev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_hw *hw = &priv->si->hw;
int err = 0;
/* set hash key, if PF */
- if (key && hw->port)
- enetc_set_rss_key(hw, key);
+ if (rxfh->key && hw->port)
+ enetc_set_rss_key(hw, rxfh->key);
/* set RSS table */
- if (indir)
- err = enetc_set_rss_table(priv->si, indir, priv->si->num_rss);
+ if (rxfh->indir)
+ err = enetc_set_rss_table(priv->si, rxfh->indir,
+ priv->si->num_rss);
return err;
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index c153dc083aff..11b14555802c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -920,6 +920,7 @@ static void enetc_imdio_remove(struct enetc_pf *pf)
static bool enetc_port_has_pcs(struct enetc_pf *pf)
{
return (pf->if_mode == PHY_INTERFACE_MODE_SGMII ||
+ pf->if_mode == PHY_INTERFACE_MODE_1000BASEX ||
pf->if_mode == PHY_INTERFACE_MODE_2500BASEX ||
pf->if_mode == PHY_INTERFACE_MODE_USXGMII);
}
@@ -1116,6 +1117,8 @@ static int enetc_phylink_create(struct enetc_ndev_priv *priv,
pf->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII,
pf->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ pf->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_2500BASEX,
pf->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_USXGMII,
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index e08c7b572497..432523b2c789 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2036,6 +2036,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
/* if any of the above changed restart the FEC */
if (status_change) {
+ netif_stop_queue(ndev);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_restart(ndev);
@@ -2045,6 +2046,7 @@ static void fec_enet_adjust_link(struct net_device *ndev)
}
} else {
if (fep->link) {
+ netif_stop_queue(ndev);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
fec_stop(ndev);
@@ -2932,10 +2934,10 @@ static void fec_enet_get_strings(struct net_device *netdev,
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(fec_stats); i++) {
- ethtool_sprintf(&data, "%s", fec_stats[i].name);
+ ethtool_puts(&data, fec_stats[i].name);
}
for (i = 0; i < ARRAY_SIZE(fec_xdp_stat_strs); i++) {
- ethtool_sprintf(&data, "%s", fec_xdp_stat_strs[i]);
+ ethtool_puts(&data, fec_xdp_stat_strs[i]);
}
page_pool_ethtool_stats_get_strings(data);
@@ -4769,4 +4771,5 @@ static struct platform_driver fec_driver = {
module_platform_driver(fec_driver);
+MODULE_DESCRIPTION("NXP Fast Ethernet Controller (FEC) driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c
index 9ba15d3183d7..758535adc9ff 100644
--- a/drivers/net/ethernet/freescale/fman/fman_memac.c
+++ b/drivers/net/ethernet/freescale/fman/fman_memac.c
@@ -1073,6 +1073,14 @@ int memac_initialization(struct mac_device *mac_dev,
unsigned long capabilities;
unsigned long *supported;
+ /* The internal connection to the serdes is XGMII, but this isn't
+ * really correct for the phy mode (which is the external connection).
+ * However, this is how all older device trees say that they want
+ * 10GBASE-R (aka XFI), so just convert it for them.
+ */
+ if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
+ mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER;
+
mac_dev->phylink_ops = &memac_mac_ops;
mac_dev->set_promisc = memac_set_promiscuous;
mac_dev->change_addr = memac_modify_mac_address;
@@ -1139,7 +1147,7 @@ int memac_initialization(struct mac_device *mac_dev,
* (and therefore that xfi_pcs cannot be set). If we are defaulting to
* XGMII, assume this is for XFI. Otherwise, assume it is for SGMII.
*/
- if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
+ if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_10GBASER)
memac->xfi_pcs = pcs;
else
memac->sgmii_pcs = pcs;
@@ -1153,14 +1161,6 @@ int memac_initialization(struct mac_device *mac_dev,
goto _return_fm_mac_free;
}
- /* The internal connection to the serdes is XGMII, but this isn't
- * really correct for the phy mode (which is the external connection).
- * However, this is how all older device trees say that they want
- * 10GBASE-R (aka XFI), so just convert it for them.
- */
- if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
- mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER;
-
/* TODO: The following interface modes are supported by (some) hardware
* but not by this driver:
* - 1000BASE-KX
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 70dd982a5edc..026f7270a54d 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -531,4 +531,5 @@ static struct platform_driver fsl_pq_mdio_driver = {
module_platform_driver(fsl_pq_mdio_driver);
+MODULE_DESCRIPTION("Freescale PQ MDIO helpers");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c b/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c
index 31aa185f4d17..4edd0adfc6c7 100644
--- a/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c
+++ b/drivers/net/ethernet/fungible/funeth/funeth_ethtool.c
@@ -655,7 +655,7 @@ static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data)
i);
}
for (j = 0; j < ARRAY_SIZE(txq_stat_names); j++)
- ethtool_sprintf(&p, txq_stat_names[j]);
+ ethtool_puts(&p, txq_stat_names[j]);
for (i = 0; i < fp->num_xdpqs; i++) {
for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)
@@ -663,7 +663,7 @@ static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data)
xdpq_stat_names[j], i);
}
for (j = 0; j < ARRAY_SIZE(xdpq_stat_names); j++)
- ethtool_sprintf(&p, xdpq_stat_names[j]);
+ ethtool_puts(&p, xdpq_stat_names[j]);
for (i = 0; i < netdev->real_num_rx_queues; i++) {
for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)
@@ -671,10 +671,10 @@ static void fun_get_strings(struct net_device *netdev, u32 sset, u8 *data)
i);
}
for (j = 0; j < ARRAY_SIZE(rxq_stat_names); j++)
- ethtool_sprintf(&p, rxq_stat_names[j]);
+ ethtool_puts(&p, rxq_stat_names[j]);
for (j = 0; j < ARRAY_SIZE(tls_stat_names); j++)
- ethtool_sprintf(&p, tls_stat_names[j]);
+ ethtool_puts(&p, tls_stat_names[j]);
break;
default:
break;
@@ -977,44 +977,44 @@ static u32 fun_get_rxfh_key_size(struct net_device *netdev)
return sizeof(fp->rss_key);
}
-static int fun_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int fun_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
const struct funeth_priv *fp = netdev_priv(netdev);
if (!fp->rss_cfg)
return -EOPNOTSUPP;
- if (indir)
- memcpy(indir, fp->indir_table,
+ if (rxfh->indir)
+ memcpy(rxfh->indir, fp->indir_table,
sizeof(u32) * fp->indir_table_nentries);
- if (key)
- memcpy(key, fp->rss_key, sizeof(fp->rss_key));
+ if (rxfh->key)
+ memcpy(rxfh->key, fp->rss_key, sizeof(fp->rss_key));
- if (hfunc)
- *hfunc = fp->hash_algo == FUN_ETH_RSS_ALG_TOEPLITZ ?
- ETH_RSS_HASH_TOP : ETH_RSS_HASH_CRC32;
+ rxfh->hfunc = fp->hash_algo == FUN_ETH_RSS_ALG_TOEPLITZ ?
+ ETH_RSS_HASH_TOP : ETH_RSS_HASH_CRC32;
return 0;
}
-static int fun_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int fun_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct funeth_priv *fp = netdev_priv(netdev);
- const u32 *rss_indir = indir ? indir : fp->indir_table;
- const u8 *rss_key = key ? key : fp->rss_key;
+ const u32 *rss_indir = rxfh->indir ? rxfh->indir : fp->indir_table;
+ const u8 *rss_key = rxfh->key ? rxfh->key : fp->rss_key;
enum fun_eth_hash_alg algo;
if (!fp->rss_cfg)
return -EOPNOTSUPP;
- if (hfunc == ETH_RSS_HASH_NO_CHANGE)
+ if (rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE)
algo = fp->hash_algo;
- else if (hfunc == ETH_RSS_HASH_CRC32)
+ else if (rxfh->hfunc == ETH_RSS_HASH_CRC32)
algo = FUN_ETH_RSS_ALG_CRC32;
- else if (hfunc == ETH_RSS_HASH_TOP)
+ else if (rxfh->hfunc == ETH_RSS_HASH_TOP)
algo = FUN_ETH_RSS_ALG_TOEPLITZ;
else
return -EINVAL;
@@ -1031,10 +1031,10 @@ static int fun_set_rxfh(struct net_device *netdev, const u32 *indir,
}
fp->hash_algo = algo;
- if (key)
- memcpy(fp->rss_key, key, sizeof(fp->rss_key));
- if (indir)
- memcpy(fp->indir_table, indir,
+ if (rxfh->key)
+ memcpy(fp->rss_key, rxfh->key, sizeof(fp->rss_key));
+ if (rxfh->indir)
+ memcpy(fp->indir_table, rxfh->indir,
sizeof(u32) * fp->indir_table_nentries);
return 0;
}
diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h
index 0d1e681be250..b80349154604 100644
--- a/drivers/net/ethernet/google/gve/gve.h
+++ b/drivers/net/ethernet/google/gve/gve.h
@@ -8,6 +8,7 @@
#define _GVE_H_
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/u64_stats_sync.h>
@@ -41,12 +42,16 @@
#define NIC_TX_STATS_REPORT_NUM 0
#define NIC_RX_STATS_REPORT_NUM 4
+#define GVE_ADMINQ_BUFFER_SIZE 4096
+
#define GVE_DATA_SLOT_ADDR_PAGE_MASK (~(PAGE_SIZE - 1))
/* PTYPEs are always 10 bits. */
#define GVE_NUM_PTYPES 1024
-#define GVE_RX_BUFFER_SIZE_DQO 2048
+#define GVE_DEFAULT_RX_BUFFER_SIZE 2048
+
+#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
#define GVE_XDP_ACTIONS 5
@@ -672,6 +677,7 @@ struct gve_priv {
/* Admin queue - see gve_adminq.h*/
union gve_adminq_command *adminq;
dma_addr_t adminq_bus_addr;
+ struct dma_pool *adminq_pool;
u32 adminq_mask; /* masks prod_cnt to adminq size */
u32 adminq_prod_cnt; /* free-running count of AQ cmds executed */
u32 adminq_cmd_fail; /* free-running count of AQ cmds failed */
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.c b/drivers/net/ethernet/google/gve/gve_adminq.c
index 79db7a6d42bc..12fbd723ecc6 100644
--- a/drivers/net/ethernet/google/gve/gve_adminq.c
+++ b/drivers/net/ethernet/google/gve/gve_adminq.c
@@ -194,12 +194,19 @@ gve_process_device_options(struct gve_priv *priv,
int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
{
- priv->adminq = dma_alloc_coherent(dev, PAGE_SIZE,
- &priv->adminq_bus_addr, GFP_KERNEL);
- if (unlikely(!priv->adminq))
+ priv->adminq_pool = dma_pool_create("adminq_pool", dev,
+ GVE_ADMINQ_BUFFER_SIZE, 0, 0);
+ if (unlikely(!priv->adminq_pool))
return -ENOMEM;
+ priv->adminq = dma_pool_alloc(priv->adminq_pool, GFP_KERNEL,
+ &priv->adminq_bus_addr);
+ if (unlikely(!priv->adminq)) {
+ dma_pool_destroy(priv->adminq_pool);
+ return -ENOMEM;
+ }
- priv->adminq_mask = (PAGE_SIZE / sizeof(union gve_adminq_command)) - 1;
+ priv->adminq_mask =
+ (GVE_ADMINQ_BUFFER_SIZE / sizeof(union gve_adminq_command)) - 1;
priv->adminq_prod_cnt = 0;
priv->adminq_cmd_fail = 0;
priv->adminq_timeouts = 0;
@@ -218,9 +225,20 @@ int gve_adminq_alloc(struct device *dev, struct gve_priv *priv)
priv->adminq_get_ptype_map_cnt = 0;
/* Setup Admin queue with the device */
- iowrite32be(priv->adminq_bus_addr / PAGE_SIZE,
- &priv->reg_bar0->adminq_pfn);
-
+ if (priv->pdev->revision < 0x1) {
+ iowrite32be(priv->adminq_bus_addr / PAGE_SIZE,
+ &priv->reg_bar0->adminq_pfn);
+ } else {
+ iowrite16be(GVE_ADMINQ_BUFFER_SIZE,
+ &priv->reg_bar0->adminq_length);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ iowrite32be(priv->adminq_bus_addr >> 32,
+ &priv->reg_bar0->adminq_base_address_hi);
+#endif
+ iowrite32be(priv->adminq_bus_addr,
+ &priv->reg_bar0->adminq_base_address_lo);
+ iowrite32be(GVE_DRIVER_STATUS_RUN_MASK, &priv->reg_bar0->driver_status);
+ }
gve_set_admin_queue_ok(priv);
return 0;
}
@@ -230,16 +248,27 @@ void gve_adminq_release(struct gve_priv *priv)
int i = 0;
/* Tell the device the adminq is leaving */
- iowrite32be(0x0, &priv->reg_bar0->adminq_pfn);
- while (ioread32be(&priv->reg_bar0->adminq_pfn)) {
- /* If this is reached the device is unrecoverable and still
- * holding memory. Continue looping to avoid memory corruption,
- * but WARN so it is visible what is going on.
- */
- if (i == GVE_MAX_ADMINQ_RELEASE_CHECK)
- WARN(1, "Unrecoverable platform error!");
- i++;
- msleep(GVE_ADMINQ_SLEEP_LEN);
+ if (priv->pdev->revision < 0x1) {
+ iowrite32be(0x0, &priv->reg_bar0->adminq_pfn);
+ while (ioread32be(&priv->reg_bar0->adminq_pfn)) {
+ /* If this is reached the device is unrecoverable and still
+ * holding memory. Continue looping to avoid memory corruption,
+ * but WARN so it is visible what is going on.
+ */
+ if (i == GVE_MAX_ADMINQ_RELEASE_CHECK)
+ WARN(1, "Unrecoverable platform error!");
+ i++;
+ msleep(GVE_ADMINQ_SLEEP_LEN);
+ }
+ } else {
+ iowrite32be(GVE_DRIVER_STATUS_RESET_MASK, &priv->reg_bar0->driver_status);
+ while (!(ioread32be(&priv->reg_bar0->device_status)
+ & GVE_DEVICE_STATUS_DEVICE_IS_RESET)) {
+ if (i == GVE_MAX_ADMINQ_RELEASE_CHECK)
+ WARN(1, "Unrecoverable platform error!");
+ i++;
+ msleep(GVE_ADMINQ_SLEEP_LEN);
+ }
}
gve_clear_device_rings_ok(priv);
gve_clear_device_resources_ok(priv);
@@ -251,7 +280,8 @@ void gve_adminq_free(struct device *dev, struct gve_priv *priv)
if (!gve_get_admin_queue_ok(priv))
return;
gve_adminq_release(priv);
- dma_free_coherent(dev, PAGE_SIZE, priv->adminq, priv->adminq_bus_addr);
+ dma_pool_free(priv->adminq_pool, priv->adminq, priv->adminq_bus_addr);
+ dma_pool_destroy(priv->adminq_pool);
gve_clear_admin_queue_ok(priv);
}
@@ -697,18 +727,7 @@ static int gve_set_desc_cnt(struct gve_priv *priv,
struct gve_device_descriptor *descriptor)
{
priv->tx_desc_cnt = be16_to_cpu(descriptor->tx_queue_entries);
- if (priv->tx_desc_cnt * sizeof(priv->tx->desc[0]) < PAGE_SIZE) {
- dev_err(&priv->pdev->dev, "Tx desc count %d too low\n",
- priv->tx_desc_cnt);
- return -EINVAL;
- }
priv->rx_desc_cnt = be16_to_cpu(descriptor->rx_queue_entries);
- if (priv->rx_desc_cnt * sizeof(priv->rx->desc.desc_ring[0])
- < PAGE_SIZE) {
- dev_err(&priv->pdev->dev, "Rx desc count %d too low\n",
- priv->rx_desc_cnt);
- return -EINVAL;
- }
return 0;
}
@@ -778,8 +797,8 @@ int gve_adminq_describe_device(struct gve_priv *priv)
u16 mtu;
memset(&cmd, 0, sizeof(cmd));
- descriptor = dma_alloc_coherent(&priv->pdev->dev, PAGE_SIZE,
- &descriptor_bus, GFP_KERNEL);
+ descriptor = dma_pool_alloc(priv->adminq_pool, GFP_KERNEL,
+ &descriptor_bus);
if (!descriptor)
return -ENOMEM;
cmd.opcode = cpu_to_be32(GVE_ADMINQ_DESCRIBE_DEVICE);
@@ -787,7 +806,8 @@ int gve_adminq_describe_device(struct gve_priv *priv)
cpu_to_be64(descriptor_bus);
cmd.describe_device.device_descriptor_version =
cpu_to_be32(GVE_ADMINQ_DEVICE_DESCRIPTOR_VERSION);
- cmd.describe_device.available_length = cpu_to_be32(PAGE_SIZE);
+ cmd.describe_device.available_length =
+ cpu_to_be32(GVE_ADMINQ_BUFFER_SIZE);
err = gve_adminq_execute_cmd(priv, &cmd);
if (err)
@@ -868,8 +888,7 @@ int gve_adminq_describe_device(struct gve_priv *priv)
dev_op_jumbo_frames, dev_op_dqo_qpl);
free_device_descriptor:
- dma_free_coherent(&priv->pdev->dev, PAGE_SIZE, descriptor,
- descriptor_bus);
+ dma_pool_free(priv->adminq_pool, descriptor, descriptor_bus);
return err;
}
@@ -898,6 +917,7 @@ int gve_adminq_register_page_list(struct gve_priv *priv,
.page_list_id = cpu_to_be32(qpl->id),
.num_pages = cpu_to_be32(num_entries),
.page_address_list_addr = cpu_to_be64(page_list_bus),
+ .page_size = cpu_to_be64(PAGE_SIZE),
};
err = gve_adminq_execute_cmd(priv, &cmd);
diff --git a/drivers/net/ethernet/google/gve/gve_adminq.h b/drivers/net/ethernet/google/gve/gve_adminq.h
index 38a22279e863..5865ccdccbd0 100644
--- a/drivers/net/ethernet/google/gve/gve_adminq.h
+++ b/drivers/net/ethernet/google/gve/gve_adminq.h
@@ -219,9 +219,10 @@ struct gve_adminq_register_page_list {
__be32 page_list_id;
__be32 num_pages;
__be64 page_address_list_addr;
+ __be64 page_size;
};
-static_assert(sizeof(struct gve_adminq_register_page_list) == 16);
+static_assert(sizeof(struct gve_adminq_register_page_list) == 24);
struct gve_adminq_unregister_page_list {
__be32 page_list_id;
diff --git a/drivers/net/ethernet/google/gve/gve_dqo.h b/drivers/net/ethernet/google/gve/gve_dqo.h
index 1eb4d5fd8561..c36b93f0de15 100644
--- a/drivers/net/ethernet/google/gve/gve_dqo.h
+++ b/drivers/net/ethernet/google/gve/gve_dqo.h
@@ -33,6 +33,9 @@
#define GVE_DEALLOCATE_COMPL_TIMEOUT 60
netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev);
+netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features);
bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
int gve_tx_alloc_rings_dqo(struct gve_priv *priv);
diff --git a/drivers/net/ethernet/google/gve/gve_ethtool.c b/drivers/net/ethernet/google/gve/gve_ethtool.c
index 233e5946905e..e5397aa1e48f 100644
--- a/drivers/net/ethernet/google/gve/gve_ethtool.c
+++ b/drivers/net/ethernet/google/gve/gve_ethtool.c
@@ -519,7 +519,7 @@ static int gve_set_tunable(struct net_device *netdev,
case ETHTOOL_RX_COPYBREAK:
{
u32 max_copybreak = gve_is_gqi(priv) ?
- (PAGE_SIZE / 2) : priv->data_buffer_size_dqo;
+ GVE_DEFAULT_RX_BUFFER_SIZE : priv->data_buffer_size_dqo;
len = *(u32 *)value;
if (len > max_copybreak)
diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c
index 2d42e733837b..619bf63ec935 100644
--- a/drivers/net/ethernet/google/gve/gve_main.c
+++ b/drivers/net/ethernet/google/gve/gve_main.c
@@ -79,6 +79,18 @@ static int gve_verify_driver_compatibility(struct gve_priv *priv)
return err;
}
+static netdev_features_t gve_features_check(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ struct gve_priv *priv = netdev_priv(dev);
+
+ if (!gve_is_gqi(priv))
+ return gve_features_check_dqo(skb, dev, features);
+
+ return features;
+}
+
static netdev_tx_t gve_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gve_priv *priv = netdev_priv(dev);
@@ -1316,7 +1328,7 @@ static int gve_open(struct net_device *dev)
/* Hard code this for now. This may be tuned in the future for
* performance.
*/
- priv->data_buffer_size_dqo = GVE_RX_BUFFER_SIZE_DQO;
+ priv->data_buffer_size_dqo = GVE_DEFAULT_RX_BUFFER_SIZE;
}
err = gve_create_rings(priv);
if (err)
@@ -1652,7 +1664,7 @@ static int verify_xdp_configuration(struct net_device *dev)
return -EOPNOTSUPP;
}
- if (dev->mtu > (PAGE_SIZE / 2) - sizeof(struct ethhdr) - GVE_RX_PAD) {
+ if (dev->mtu > GVE_DEFAULT_RX_BUFFER_SIZE - sizeof(struct ethhdr) - GVE_RX_PAD) {
netdev_warn(dev, "XDP is not supported for mtu %d.\n",
dev->mtu);
return -EOPNOTSUPP;
@@ -1879,6 +1891,7 @@ err:
static const struct net_device_ops gve_netdev_ops = {
.ndo_start_xmit = gve_start_xmit,
+ .ndo_features_check = gve_features_check,
.ndo_open = gve_open,
.ndo_stop = gve_close,
.ndo_get_stats64 = gve_get_stats,
diff --git a/drivers/net/ethernet/google/gve/gve_register.h b/drivers/net/ethernet/google/gve/gve_register.h
index fb655463c357..8e72b97008d6 100644
--- a/drivers/net/ethernet/google/gve/gve_register.h
+++ b/drivers/net/ethernet/google/gve/gve_register.h
@@ -18,11 +18,20 @@ struct gve_registers {
__be32 adminq_event_counter;
u8 reserved[3];
u8 driver_version;
+ __be32 adminq_base_address_hi;
+ __be32 adminq_base_address_lo;
+ __be16 adminq_length;
};
enum gve_device_status_flags {
GVE_DEVICE_STATUS_RESET_MASK = BIT(1),
GVE_DEVICE_STATUS_LINK_STATUS_MASK = BIT(2),
GVE_DEVICE_STATUS_REPORT_STATS_MASK = BIT(3),
+ GVE_DEVICE_STATUS_DEVICE_IS_RESET = BIT(4),
+};
+
+enum gve_driver_status_flags {
+ GVE_DRIVER_STATUS_RUN_MASK = BIT(0),
+ GVE_DRIVER_STATUS_RESET_MASK = BIT(1),
};
#endif /* _GVE_REGISTER_H_ */
diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c
index 73655347902d..76615d47e055 100644
--- a/drivers/net/ethernet/google/gve/gve_rx.c
+++ b/drivers/net/ethernet/google/gve/gve_rx.c
@@ -211,9 +211,9 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
{
struct gve_rx_ring *rx = &priv->rx[idx];
struct device *hdev = &priv->pdev->dev;
- u32 slots, npages;
int filled_pages;
size_t bytes;
+ u32 slots;
int err;
netif_dbg(priv, drv, priv->dev, "allocating rx ring\n");
@@ -270,12 +270,6 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
/* alloc rx desc ring */
bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt;
- npages = bytes / PAGE_SIZE;
- if (npages * PAGE_SIZE != bytes) {
- err = -EIO;
- goto abort_with_q_resources;
- }
-
rx->desc.desc_ring = dma_alloc_coherent(hdev, bytes, &rx->desc.bus,
GFP_KERNEL);
if (!rx->desc.desc_ring) {
@@ -289,7 +283,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
/* Allocating half-page buffers allows page-flipping which is faster
* than copying or allocating new pages.
*/
- rx->packet_buffer_size = PAGE_SIZE / 2;
+ rx->packet_buffer_size = GVE_DEFAULT_RX_BUFFER_SIZE;
gve_rx_ctx_clear(&rx->ctx);
gve_rx_add_to_block(priv, idx);
@@ -362,7 +356,7 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info,
- u16 packet_buffer_size, u16 len,
+ unsigned int truesize, u16 len,
struct gve_rx_ctx *ctx)
{
u32 offset = page_info->page_offset + page_info->pad;
@@ -395,20 +389,20 @@ static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
if (skb != ctx->skb_head) {
ctx->skb_head->len += len;
ctx->skb_head->data_len += len;
- ctx->skb_head->truesize += packet_buffer_size;
+ ctx->skb_head->truesize += truesize;
}
skb_add_rx_frag(skb, num_frags, page_info->page,
- offset, len, packet_buffer_size);
+ offset, len, truesize);
return ctx->skb_head;
}
static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info, __be64 *slot_addr)
{
- const __be64 offset = cpu_to_be64(PAGE_SIZE / 2);
+ const __be64 offset = cpu_to_be64(GVE_DEFAULT_RX_BUFFER_OFFSET);
/* "flip" to other packet buffer on this page */
- page_info->page_offset ^= PAGE_SIZE / 2;
+ page_info->page_offset ^= GVE_DEFAULT_RX_BUFFER_OFFSET;
*(slot_addr) ^= offset;
}
@@ -492,7 +486,7 @@ static struct sk_buff *gve_rx_copy_to_pool(struct gve_rx_ring *rx,
memcpy(alloc_page_info.page_address, src, page_info->pad + len);
skb = gve_rx_add_frags(napi, &alloc_page_info,
- rx->packet_buffer_size,
+ PAGE_SIZE,
len, ctx);
u64_stats_update_begin(&rx->statss);
@@ -513,8 +507,7 @@ static struct sk_buff *gve_rx_copy_to_pool(struct gve_rx_ring *rx,
return NULL;
gve_dec_pagecnt_bias(copy_page_info);
- copy_page_info->page_offset += rx->packet_buffer_size;
- copy_page_info->page_offset &= (PAGE_SIZE - 1);
+ copy_page_info->page_offset ^= GVE_DEFAULT_RX_BUFFER_OFFSET;
if (copy_page_info->can_flip) {
/* We have used both halves of this copy page, it
diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c
index 9f6ffc4a54f0..07ba124780df 100644
--- a/drivers/net/ethernet/google/gve/gve_tx.c
+++ b/drivers/net/ethernet/google/gve/gve_tx.c
@@ -819,7 +819,7 @@ int gve_xdp_xmit_one(struct gve_priv *priv, struct gve_tx_ring *tx,
return 0;
}
-#define GVE_TX_START_THRESH PAGE_SIZE
+#define GVE_TX_START_THRESH 4096
static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx,
u32 to_do, bool try_to_wake)
diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
index 1e19b834a613..f59c4710f118 100644
--- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c
+++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c
@@ -843,6 +843,16 @@ static bool gve_can_send_tso(const struct sk_buff *skb)
return true;
}
+netdev_features_t gve_features_check_dqo(struct sk_buff *skb,
+ struct net_device *dev,
+ netdev_features_t features)
+{
+ if (skb_is_gso(skb) && !gve_can_send_tso(skb))
+ return features & ~NETIF_F_GSO_MASK;
+
+ return features;
+}
+
/* Attempt to transmit specified SKB.
*
* Returns 0 if the SKB was transmitted or dropped.
@@ -854,11 +864,10 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx,
int num_buffer_descs;
int total_num_descs;
- if (tx->dqo.qpl) {
- if (skb_is_gso(skb))
- if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
- goto drop;
+ if (skb_is_gso(skb) && unlikely(ipv6_hopopt_jumbo_remove(skb)))
+ goto drop;
+ if (tx->dqo.qpl) {
/* We do not need to verify the number of buffers used per
* packet or per segment in case of TSO as with 2K size buffers
* none of the TX packet rules would be violated.
@@ -868,24 +877,8 @@ static int gve_try_tx_skb(struct gve_priv *priv, struct gve_tx_ring *tx,
*/
num_buffer_descs = DIV_ROUND_UP(skb->len, GVE_TX_BUF_SIZE_DQO);
} else {
- if (skb_is_gso(skb)) {
- /* If TSO doesn't meet HW requirements, attempt to linearize the
- * packet.
- */
- if (unlikely(!gve_can_send_tso(skb) &&
- skb_linearize(skb) < 0)) {
- net_err_ratelimited("%s: Failed to transmit TSO packet\n",
- priv->dev->name);
- goto drop;
- }
-
- if (unlikely(ipv6_hopopt_jumbo_remove(skb)))
- goto drop;
-
- num_buffer_descs = gve_num_buffer_descs_needed(skb);
- } else {
- num_buffer_descs = gve_num_buffer_descs_needed(skb);
-
+ num_buffer_descs = gve_num_buffer_descs_needed(skb);
+ if (!skb_is_gso(skb)) {
if (unlikely(num_buffer_descs > GVE_TX_MAX_DATA_DESCS)) {
if (unlikely(skb_linearize(skb) < 0))
goto drop;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index 8f391e2adcc0..bdb7afaabdd0 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -678,7 +678,7 @@ static void hns_gmac_get_strings(u32 stringset, u8 *data)
return;
for (i = 0; i < ARRAY_SIZE(g_gmac_stats_string); i++)
- ethtool_sprintf(&buff, g_gmac_stats_string[i].desc);
+ ethtool_puts(&buff, g_gmac_stats_string[i].desc);
}
static int hns_gmac_get_sset_count(int stringset)
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
index fc26ffaae620..c58833eb4830 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c
@@ -752,7 +752,7 @@ static void hns_xgmac_get_strings(u32 stringset, u8 *data)
return;
for (i = 0; i < ARRAY_SIZE(g_xgmac_stats_string); i++)
- ethtool_sprintf(&buff, g_xgmac_stats_string[i].desc);
+ ethtool_puts(&buff, g_xgmac_stats_string[i].desc);
}
/**
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index b54f3706fb97..a5bb306b2cf1 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -912,42 +912,41 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
if (stringset == ETH_SS_TEST) {
if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII)
- ethtool_sprintf(&buff,
- hns_nic_test_strs[MAC_INTERNALLOOP_MAC]);
- ethtool_sprintf(&buff,
- hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]);
+ ethtool_puts(&buff,
+ hns_nic_test_strs[MAC_INTERNALLOOP_MAC]);
+ ethtool_puts(&buff, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]);
if ((netdev->phydev) && (!netdev->phydev->is_c45))
- ethtool_sprintf(&buff,
- hns_nic_test_strs[MAC_INTERNALLOOP_PHY]);
+ ethtool_puts(&buff,
+ hns_nic_test_strs[MAC_INTERNALLOOP_PHY]);
} else {
- ethtool_sprintf(&buff, "rx_packets");
- ethtool_sprintf(&buff, "tx_packets");
- ethtool_sprintf(&buff, "rx_bytes");
- ethtool_sprintf(&buff, "tx_bytes");
- ethtool_sprintf(&buff, "rx_errors");
- ethtool_sprintf(&buff, "tx_errors");
- ethtool_sprintf(&buff, "rx_dropped");
- ethtool_sprintf(&buff, "tx_dropped");
- ethtool_sprintf(&buff, "multicast");
- ethtool_sprintf(&buff, "collisions");
- ethtool_sprintf(&buff, "rx_over_errors");
- ethtool_sprintf(&buff, "rx_crc_errors");
- ethtool_sprintf(&buff, "rx_frame_errors");
- ethtool_sprintf(&buff, "rx_fifo_errors");
- ethtool_sprintf(&buff, "rx_missed_errors");
- ethtool_sprintf(&buff, "tx_aborted_errors");
- ethtool_sprintf(&buff, "tx_carrier_errors");
- ethtool_sprintf(&buff, "tx_fifo_errors");
- ethtool_sprintf(&buff, "tx_heartbeat_errors");
- ethtool_sprintf(&buff, "rx_length_errors");
- ethtool_sprintf(&buff, "tx_window_errors");
- ethtool_sprintf(&buff, "rx_compressed");
- ethtool_sprintf(&buff, "tx_compressed");
- ethtool_sprintf(&buff, "netdev_rx_dropped");
- ethtool_sprintf(&buff, "netdev_tx_dropped");
-
- ethtool_sprintf(&buff, "netdev_tx_timeout");
+ ethtool_puts(&buff, "rx_packets");
+ ethtool_puts(&buff, "tx_packets");
+ ethtool_puts(&buff, "rx_bytes");
+ ethtool_puts(&buff, "tx_bytes");
+ ethtool_puts(&buff, "rx_errors");
+ ethtool_puts(&buff, "tx_errors");
+ ethtool_puts(&buff, "rx_dropped");
+ ethtool_puts(&buff, "tx_dropped");
+ ethtool_puts(&buff, "multicast");
+ ethtool_puts(&buff, "collisions");
+ ethtool_puts(&buff, "rx_over_errors");
+ ethtool_puts(&buff, "rx_crc_errors");
+ ethtool_puts(&buff, "rx_frame_errors");
+ ethtool_puts(&buff, "rx_fifo_errors");
+ ethtool_puts(&buff, "rx_missed_errors");
+ ethtool_puts(&buff, "tx_aborted_errors");
+ ethtool_puts(&buff, "tx_carrier_errors");
+ ethtool_puts(&buff, "tx_fifo_errors");
+ ethtool_puts(&buff, "tx_heartbeat_errors");
+ ethtool_puts(&buff, "rx_length_errors");
+ ethtool_puts(&buff, "tx_window_errors");
+ ethtool_puts(&buff, "rx_compressed");
+ ethtool_puts(&buff, "tx_compressed");
+ ethtool_puts(&buff, "netdev_rx_dropped");
+ ethtool_puts(&buff, "netdev_tx_dropped");
+
+ ethtool_puts(&buff, "netdev_tx_timeout");
h->dev->ops->get_strings(h, stringset, buff);
}
@@ -1187,7 +1186,7 @@ hns_get_rss_indir_size(struct net_device *netdev)
}
static int
-hns_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
+hns_get_rss(struct net_device *netdev, struct ethtool_rxfh_param *rxfh)
{
struct hns_nic_priv *priv = netdev_priv(netdev);
struct hnae_ae_ops *ops;
@@ -1200,15 +1199,16 @@ hns_get_rss(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
ops = priv->ae_handle->dev->ops;
- if (!indir)
+ if (!rxfh->indir)
return 0;
- return ops->get_rss(priv->ae_handle, indir, key, hfunc);
+ return ops->get_rss(priv->ae_handle,
+ rxfh->indir, rxfh->key, &rxfh->hfunc);
}
static int
-hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
- const u8 hfunc)
+hns_set_rss(struct net_device *netdev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct hns_nic_priv *priv = netdev_priv(netdev);
struct hnae_ae_ops *ops;
@@ -1221,12 +1221,14 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key,
ops = priv->ae_handle->dev->ops;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) {
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP) {
netdev_err(netdev, "Invalid hfunc!\n");
return -EOPNOTSUPP;
}
- return ops->set_rss(priv->ae_handle, indir, key, hfunc);
+ return ops->set_rss(priv->ae_handle,
+ rxfh->indir, rxfh->key, rxfh->hfunc);
}
static int hns_get_rxnfc(struct net_device *netdev,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
index b618797a7e8d..f1695c889d3a 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
@@ -1041,7 +1041,7 @@ static void hns3_init_tx_spare_buffer(struct hns3_enet_ring *ring)
return;
order = get_order(alloc_size);
- if (order > MAX_ORDER) {
+ if (order > MAX_PAGE_ORDER) {
if (net_ratelimit())
dev_warn(ring_to_dev(ring), "failed to allocate tx spare buffer, exceed to max order\n");
return;
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
index 682239f33082..999a0ee162a6 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
@@ -941,19 +941,21 @@ static u32 hns3_get_rss_indir_size(struct net_device *netdev)
return ae_dev->dev_specs.rss_ind_tbl_size;
}
-static int hns3_get_rss(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int hns3_get_rss(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
if (!h->ae_algo->ops->get_rss)
return -EOPNOTSUPP;
- return h->ae_algo->ops->get_rss(h, indir, key, hfunc);
+ return h->ae_algo->ops->get_rss(h, rxfh->indir, rxfh->key,
+ &rxfh->hfunc);
}
-static int hns3_set_rss(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int hns3_set_rss(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
@@ -962,19 +964,22 @@ static int hns3_set_rss(struct net_device *netdev, const u32 *indir,
return -EOPNOTSUPP;
if ((ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2 &&
- hfunc != ETH_RSS_HASH_TOP) || (hfunc != ETH_RSS_HASH_NO_CHANGE &&
- hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)) {
+ rxfh->hfunc != ETH_RSS_HASH_TOP) ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP &&
+ rxfh->hfunc != ETH_RSS_HASH_XOR)) {
netdev_err(netdev, "hash func not supported\n");
return -EOPNOTSUPP;
}
- if (!indir) {
+ if (!rxfh->indir) {
netdev_err(netdev,
"set rss failed for indir is empty\n");
return -EOPNOTSUPP;
}
- return h->ae_algo->ops->set_rss(h, indir, key, hfunc);
+ return h->ae_algo->ops->set_rss(h, rxfh->indir, rxfh->key,
+ rxfh->hfunc);
}
static int hns3_get_rxnfc(struct net_device *netdev,
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
index ff3f8f424ad9..9ec471ced3d6 100644
--- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
+++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
@@ -981,19 +981,24 @@ static const struct hclge_dbg_item tm_pri_items[] = {
static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len)
{
- char data_str[ARRAY_SIZE(tm_pri_items)][HCLGE_DBG_DATA_STR_LEN];
struct hclge_tm_shaper_para c_shaper_para, p_shaper_para;
char *result[ARRAY_SIZE(tm_pri_items)], *sch_mode_str;
char content[HCLGE_DBG_TM_INFO_LEN];
u8 pri_num, sch_mode, weight, i, j;
+ char *data_str;
int pos, ret;
ret = hclge_tm_get_pri_num(hdev, &pri_num);
if (ret)
return ret;
+ data_str = kcalloc(ARRAY_SIZE(tm_pri_items), HCLGE_DBG_DATA_STR_LEN,
+ GFP_KERNEL);
+ if (!data_str)
+ return -ENOMEM;
+
for (i = 0; i < ARRAY_SIZE(tm_pri_items); i++)
- result[i] = &data_str[i][0];
+ result[i] = &data_str[i * HCLGE_DBG_DATA_STR_LEN];
hclge_dbg_fill_content(content, sizeof(content), tm_pri_items,
NULL, ARRAY_SIZE(tm_pri_items));
@@ -1002,23 +1007,23 @@ static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len)
for (i = 0; i < pri_num; i++) {
ret = hclge_tm_get_pri_sch_mode(hdev, i, &sch_mode);
if (ret)
- return ret;
+ goto out;
ret = hclge_tm_get_pri_weight(hdev, i, &weight);
if (ret)
- return ret;
+ goto out;
ret = hclge_tm_get_pri_shaper(hdev, i,
HCLGE_OPC_TM_PRI_C_SHAPPING,
&c_shaper_para);
if (ret)
- return ret;
+ goto out;
ret = hclge_tm_get_pri_shaper(hdev, i,
HCLGE_OPC_TM_PRI_P_SHAPPING,
&p_shaper_para);
if (ret)
- return ret;
+ goto out;
sch_mode_str = sch_mode & HCLGE_TM_TX_SCHD_DWRR_MSK ? "dwrr" :
"sp";
@@ -1035,7 +1040,9 @@ static int hclge_dbg_dump_tm_pri(struct hclge_dev *hdev, char *buf, int len)
pos += scnprintf(buf + pos, len - pos, "%s", content);
}
- return 0;
+out:
+ kfree(data_str);
+ return ret;
}
static const struct hclge_dbg_item tm_qset_items[] = {
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
index f4b680286911..0304f03d4093 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
@@ -1137,7 +1137,7 @@ static int hinic_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
}
static int hinic_get_rxfh(struct net_device *netdev,
- u32 *indir, u8 *key, u8 *hfunc)
+ struct ethtool_rxfh_param *rxfh)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
u8 hash_engine_type = 0;
@@ -1146,32 +1146,33 @@ static int hinic_get_rxfh(struct net_device *netdev,
if (!(nic_dev->flags & HINIC_RSS_ENABLE))
return -EOPNOTSUPP;
- if (hfunc) {
- err = hinic_rss_get_hash_engine(nic_dev,
- nic_dev->rss_tmpl_idx,
- &hash_engine_type);
- if (err)
- return -EFAULT;
+ err = hinic_rss_get_hash_engine(nic_dev,
+ nic_dev->rss_tmpl_idx,
+ &hash_engine_type);
+ if (err)
+ return -EFAULT;
- *hfunc = hash_engine_type ? ETH_RSS_HASH_TOP : ETH_RSS_HASH_XOR;
- }
+ rxfh->hfunc = hash_engine_type ? ETH_RSS_HASH_TOP : ETH_RSS_HASH_XOR;
- if (indir) {
+ if (rxfh->indir) {
err = hinic_rss_get_indir_tbl(nic_dev,
- nic_dev->rss_tmpl_idx, indir);
+ nic_dev->rss_tmpl_idx,
+ rxfh->indir);
if (err)
return -EFAULT;
}
- if (key)
+ if (rxfh->key)
err = hinic_rss_get_template_tbl(nic_dev,
- nic_dev->rss_tmpl_idx, key);
+ nic_dev->rss_tmpl_idx,
+ rxfh->key);
return err;
}
-static int hinic_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int hinic_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
int err = 0;
@@ -1179,11 +1180,12 @@ static int hinic_set_rxfh(struct net_device *netdev, const u32 *indir,
if (!(nic_dev->flags & HINIC_RSS_ENABLE))
return -EOPNOTSUPP;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE) {
- if (hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE) {
+ if (rxfh->hfunc != ETH_RSS_HASH_TOP &&
+ rxfh->hfunc != ETH_RSS_HASH_XOR)
return -EOPNOTSUPP;
- nic_dev->rss_hash_engine = (hfunc == ETH_RSS_HASH_XOR) ?
+ nic_dev->rss_hash_engine = (rxfh->hfunc == ETH_RSS_HASH_XOR) ?
HINIC_RSS_HASH_ENGINE_TYPE_XOR :
HINIC_RSS_HASH_ENGINE_TYPE_TOEP;
err = hinic_rss_set_hash_engine
@@ -1193,7 +1195,7 @@ static int hinic_set_rxfh(struct net_device *netdev, const u32 *indir,
return -EFAULT;
}
- err = __set_rss_rxfh(netdev, indir, key);
+ err = __set_rss_rxfh(netdev, rxfh->indir, rxfh->key);
return err;
}
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index 4e18b4cefa97..94ac36b1408b 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -48,7 +48,7 @@
* of 4096 jumbo frames (MTU=9000) we will need about 9K*4K = 36MB plus
* some padding.
*
- * But the size of a single DMA region is limited by MAX_ORDER in the
+ * But the size of a single DMA region is limited by MAX_PAGE_ORDER in the
* kernel (about 16MB currently). To support say 4K Jumbo frames, we
* use a set of LTBs (struct ltb_set) per pool.
*
@@ -75,7 +75,7 @@
* pool for the 4MB. Thus the 16 Rx and Tx queues require 32 * 5 = 160
* plus 16 for the TSO pools for a total of 176 LTB mappings per VNIC.
*/
-#define IBMVNIC_ONE_LTB_MAX ((u32)((1 << MAX_ORDER) * PAGE_SIZE))
+#define IBMVNIC_ONE_LTB_MAX ((u32)((1 << MAX_PAGE_ORDER) * PAGE_SIZE))
#define IBMVNIC_ONE_LTB_SIZE min((u32)(8 << 20), IBMVNIC_ONE_LTB_MAX)
#define IBMVNIC_LTB_SET_SIZE (38 << 20)
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 06ddd7147c7f..d55638ad8704 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -299,6 +299,17 @@ config ICE
To compile this driver as a module, choose M here. The module
will be called ice.
+config ICE_HWMON
+ bool "Intel(R) Ethernet Connection E800 Series Support HWMON support"
+ default y
+ depends on ICE && HWMON && !(ICE=y && HWMON=m)
+ help
+ Say Y if you want to expose thermal sensor data on Intel devices.
+
+ Some of our devices contain internal thermal sensors.
+ This data is available via the hwmon sysfs interface and exposes
+ the onboard sensors.
+
config ICE_SWITCHDEV
bool "Switchdev Support"
default y
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 4542e2bc28e8..f9328f2e669f 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -5,6 +5,7 @@
* Shared functions for accessing and configuring the MAC
*/
+#include <linux/bitfield.h>
#include "e1000.h"
static s32 e1000_check_downshift(struct e1000_hw *hw);
@@ -3260,8 +3261,7 @@ static s32 e1000_phy_igp_get_info(struct e1000_hw *hw,
return ret_val;
phy_info->mdix_mode =
- (e1000_auto_x_mode) ((phy_data & IGP01E1000_PSSR_MDIX) >>
- IGP01E1000_PSSR_MDIX_SHIFT);
+ (e1000_auto_x_mode)FIELD_GET(IGP01E1000_PSSR_MDIX, phy_data);
if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
@@ -3272,11 +3272,11 @@ static s32 e1000_phy_igp_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- phy_info->local_rx = ((phy_data & SR_1000T_LOCAL_RX_STATUS) >>
- SR_1000T_LOCAL_RX_STATUS_SHIFT) ?
+ phy_info->local_rx = FIELD_GET(SR_1000T_LOCAL_RX_STATUS,
+ phy_data) ?
e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
- phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
- SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
+ phy_info->remote_rx = FIELD_GET(SR_1000T_REMOTE_RX_STATUS,
+ phy_data) ?
e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
/* Get cable length */
@@ -3326,14 +3326,12 @@ static s32 e1000_phy_m88_get_info(struct e1000_hw *hw,
return ret_val;
phy_info->extended_10bt_distance =
- ((phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
- M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT) ?
+ FIELD_GET(M88E1000_PSCR_10BT_EXT_DIST_ENABLE, phy_data) ?
e1000_10bt_ext_dist_enable_lower :
e1000_10bt_ext_dist_enable_normal;
phy_info->polarity_correction =
- ((phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
- M88E1000_PSCR_POLARITY_REVERSAL_SHIFT) ?
+ FIELD_GET(M88E1000_PSCR_POLARITY_REVERSAL, phy_data) ?
e1000_polarity_reversal_disabled : e1000_polarity_reversal_enabled;
/* Check polarity status */
@@ -3347,27 +3345,25 @@ static s32 e1000_phy_m88_get_info(struct e1000_hw *hw,
return ret_val;
phy_info->mdix_mode =
- (e1000_auto_x_mode) ((phy_data & M88E1000_PSSR_MDIX) >>
- M88E1000_PSSR_MDIX_SHIFT);
+ (e1000_auto_x_mode)FIELD_GET(M88E1000_PSSR_MDIX, phy_data);
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
/* Cable Length Estimation and Local/Remote Receiver Information
* are only valid at 1000 Mbps.
*/
phy_info->cable_length =
- (e1000_cable_length) ((phy_data &
- M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ (e1000_cable_length)FIELD_GET(M88E1000_PSSR_CABLE_LENGTH,
+ phy_data);
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
if (ret_val)
return ret_val;
- phy_info->local_rx = ((phy_data & SR_1000T_LOCAL_RX_STATUS) >>
- SR_1000T_LOCAL_RX_STATUS_SHIFT) ?
+ phy_info->local_rx = FIELD_GET(SR_1000T_LOCAL_RX_STATUS,
+ phy_data) ?
e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
- phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
- SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
+ phy_info->remote_rx = FIELD_GET(SR_1000T_REMOTE_RX_STATUS,
+ phy_data) ?
e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
}
@@ -3515,7 +3511,7 @@ s32 e1000_init_eeprom_params(struct e1000_hw *hw)
if (ret_val)
return ret_val;
eeprom_size =
- (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
+ FIELD_GET(EEPROM_SIZE_MASK, eeprom_size);
/* 256B eeprom size was not supported in earlier hardware, so we
* bump eeprom_size up one to ensure that "1" (which maps to
* 256B) is never the result used in the shifting logic below.
@@ -4891,8 +4887,7 @@ static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length,
&phy_data);
if (ret_val)
return ret_val;
- cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ cable_length = FIELD_GET(M88E1000_PSSR_CABLE_LENGTH, phy_data);
/* Convert the enum value to ranged values */
switch (cable_length) {
@@ -5001,8 +4996,7 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
&phy_data);
if (ret_val)
return ret_val;
- *polarity = ((phy_data & M88E1000_PSSR_REV_POLARITY) >>
- M88E1000_PSSR_REV_POLARITY_SHIFT) ?
+ *polarity = FIELD_GET(M88E1000_PSSR_REV_POLARITY, phy_data) ?
e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
} else if (hw->phy_type == e1000_phy_igp) {
@@ -5072,8 +5066,8 @@ static s32 e1000_check_downshift(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
- M88E1000_PSSR_DOWNSHIFT_SHIFT;
+ hw->speed_downgraded = FIELD_GET(M88E1000_PSSR_DOWNSHIFT,
+ phy_data);
}
return E1000_SUCCESS;
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index be9c695dde12..4eb1ceaf865a 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -92,8 +92,7 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
nvm->type = e1000_nvm_eeprom_spi;
- size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
- E1000_EECD_SIZE_EX_SHIFT);
+ size = (u16)FIELD_GET(E1000_EECD_SIZE_EX_MASK, eecd);
/* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
@@ -1035,17 +1034,18 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
* iteration and increase the max iterations when
* polling the phy; this fixes erroneous timeouts at 10Mbps.
*/
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4),
- 0xFFFF);
+ /* these next three accesses were always meant to use page 0x34 using
+ * GG82563_REG(0x34, N) but never did, so we've just corrected the call
+ * to not drop bits
+ */
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, 4, 0xFFFF);
if (ret_val)
return ret_val;
- ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
- &reg_data);
+ ret_val = e1000_read_kmrn_reg_80003es2lan(hw, 9, &reg_data);
if (ret_val)
return ret_val;
reg_data |= 0x3F;
- ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9),
- reg_data);
+ ret_val = e1000_write_kmrn_reg_80003es2lan(hw, 9, reg_data);
if (ret_val)
return ret_val;
ret_val =
@@ -1209,8 +1209,8 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
if (ret_val)
return ret_val;
- kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
- E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ kmrnctrlsta = FIELD_PREP(E1000_KMRNCTRLSTA_OFFSET, offset) |
+ E1000_KMRNCTRLSTA_REN;
ew32(KMRNCTRLSTA, kmrnctrlsta);
e1e_flush();
@@ -1244,8 +1244,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset,
if (ret_val)
return ret_val;
- kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
- E1000_KMRNCTRLSTA_OFFSET) | data;
+ kmrnctrlsta = FIELD_PREP(E1000_KMRNCTRLSTA_OFFSET, offset) | data;
ew32(KMRNCTRLSTA, kmrnctrlsta);
e1e_flush();
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 0b1e890dd583..969f855a79ee 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -157,8 +157,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
fallthrough;
default:
nvm->type = e1000_nvm_eeprom_spi;
- size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
- E1000_EECD_SIZE_EX_SHIFT);
+ size = (u16)FIELD_GET(E1000_EECD_SIZE_EX_MASK, eecd);
/* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
*/
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index 63c3c79380a1..23a58cada43a 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -678,11 +678,8 @@
/* PCI/PCI-X/PCI-EX Config space */
#define PCI_HEADER_TYPE_REGISTER 0x0E
-#define PCIE_LINK_STATUS 0x12
#define PCI_HEADER_TYPE_MULTIFUNC 0x80
-#define PCIE_LINK_WIDTH_MASK 0x3F0
-#define PCIE_LINK_WIDTH_SHIFT 4
#define PHY_REVISION_MASK 0xFFFFFFF0
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index a187582d2299..ba9c19e6994c 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -360,23 +360,43 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
* As a result, a shift of INCVALUE_SHIFT_n is used to fit a value of
* INCVALUE_n into the TIMINCA register allowing 32+8+(24-INCVALUE_SHIFT_n)
* bits to count nanoseconds leaving the rest for fractional nonseconds.
+ *
+ * Any given INCVALUE also has an associated maximum adjustment value. This
+ * maximum adjustment value is the largest increase (or decrease) which can be
+ * safely applied without overflowing the INCVALUE. Since INCVALUE has
+ * a maximum range of 24 bits, its largest value is 0xFFFFFF.
+ *
+ * To understand where the maximum value comes from, consider the following
+ * equation:
+ *
+ * new_incval = base_incval + (base_incval * adjustment) / 1billion
+ *
+ * To avoid overflow that means:
+ * max_incval = base_incval + (base_incval * max_adj) / billion
+ *
+ * Re-arranging:
+ * max_adj = floor(((max_incval - base_incval) * 1billion) / 1billion)
*/
#define INCVALUE_96MHZ 125
#define INCVALUE_SHIFT_96MHZ 17
#define INCPERIOD_SHIFT_96MHZ 2
#define INCPERIOD_96MHZ (12 >> INCPERIOD_SHIFT_96MHZ)
+#define MAX_PPB_96MHZ 23999900 /* 23,999,900 ppb */
#define INCVALUE_25MHZ 40
#define INCVALUE_SHIFT_25MHZ 18
#define INCPERIOD_25MHZ 1
+#define MAX_PPB_25MHZ 599999900 /* 599,999,900 ppb */
#define INCVALUE_24MHZ 125
#define INCVALUE_SHIFT_24MHZ 14
#define INCPERIOD_24MHZ 3
+#define MAX_PPB_24MHZ 999999999 /* 999,999,999 ppb */
#define INCVALUE_38400KHZ 26
#define INCVALUE_SHIFT_38400KHZ 19
#define INCPERIOD_38400KHZ 1
+#define MAX_PPB_38400KHZ 230769100 /* 230,769,100 ppb */
/* Another drawback of scaling the incvalue by a large factor is the
* 64-bit SYSTIM register overflows more quickly. This is dealt with
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 9835e6a90d56..fc0f98ea6133 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -654,8 +654,8 @@ static void e1000_get_drvinfo(struct net_device *netdev,
*/
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
"%d.%d-%d",
- (adapter->eeprom_vers & 0xF000) >> 12,
- (adapter->eeprom_vers & 0x0FF0) >> 4,
+ FIELD_GET(0xF000, adapter->eeprom_vers),
+ FIELD_GET(0x0FF0, adapter->eeprom_vers),
(adapter->eeprom_vers & 0x000F));
strscpy(drvinfo->bus_info, pci_name(adapter->pdev),
@@ -925,8 +925,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
}
if (mac->type >= e1000_pch_lpt)
- wlock_mac = (er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK) >>
- E1000_FWSM_WLOCK_MAC_SHIFT;
+ wlock_mac = FIELD_GET(E1000_FWSM_WLOCK_MAC_MASK, er32(FWSM));
for (i = 0; i < mac->rar_entry_count; i++) {
if (mac->type >= e1000_pch_lpt) {
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 39e9fc601bf5..19e450a5bd31 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -1072,13 +1072,11 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
lat_enc_d = (lat_enc & E1000_LTRV_VALUE_MASK) *
(1U << (E1000_LTRV_SCALE_FACTOR *
- ((lat_enc & E1000_LTRV_SCALE_MASK)
- >> E1000_LTRV_SCALE_SHIFT)));
+ FIELD_GET(E1000_LTRV_SCALE_MASK, lat_enc)));
max_ltr_enc_d = (max_ltr_enc & E1000_LTRV_VALUE_MASK) *
- (1U << (E1000_LTRV_SCALE_FACTOR *
- ((max_ltr_enc & E1000_LTRV_SCALE_MASK)
- >> E1000_LTRV_SCALE_SHIFT)));
+ (1U << (E1000_LTRV_SCALE_FACTOR *
+ FIELD_GET(E1000_LTRV_SCALE_MASK, max_ltr_enc)));
if (lat_enc_d > max_ltr_enc_d)
lat_enc = max_ltr_enc;
@@ -2075,8 +2073,7 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
{
u16 phy_data;
u32 strap = er32(STRAP);
- u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
- E1000_STRAP_SMT_FREQ_SHIFT;
+ u32 freq = FIELD_GET(E1000_STRAP_SMT_FREQ_MASK, strap);
s32 ret_val;
strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
@@ -2562,8 +2559,7 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
hw->phy.ops.write_reg_page(hw, BM_RAR_H(i),
(u16)(mac_reg & 0xFFFF));
hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i),
- (u16)((mac_reg & E1000_RAH_AV)
- >> 16));
+ (u16)((mac_reg & E1000_RAH_AV) >> 16));
}
e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg);
@@ -3205,7 +3201,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
&nvm_dword);
if (ret_val)
return ret_val;
- sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
+ sig_byte = FIELD_GET(0xFF00, nvm_dword);
if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
E1000_ICH_NVM_SIG_VALUE) {
*bank = 0;
@@ -3218,7 +3214,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
&nvm_dword);
if (ret_val)
return ret_val;
- sig_byte = (u8)((nvm_dword & 0xFF00) >> 8);
+ sig_byte = FIELD_GET(0xFF00, nvm_dword);
if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
E1000_ICH_NVM_SIG_VALUE) {
*bank = 1;
diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c
index 5df7ad93f3d7..d7df2a0ed629 100644
--- a/drivers/net/ethernet/intel/e1000e/mac.c
+++ b/drivers/net/ethernet/intel/e1000e/mac.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 1999 - 2018 Intel Corporation. */
+#include <linux/bitfield.h>
+
#include "e1000.h"
/**
@@ -13,21 +15,17 @@
**/
s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
{
+ struct pci_dev *pdev = hw->adapter->pdev;
struct e1000_mac_info *mac = &hw->mac;
struct e1000_bus_info *bus = &hw->bus;
- struct e1000_adapter *adapter = hw->adapter;
- u16 pcie_link_status, cap_offset;
+ u16 pcie_link_status;
- cap_offset = adapter->pdev->pcie_cap;
- if (!cap_offset) {
+ if (!pci_pcie_cap(pdev)) {
bus->width = e1000_bus_width_unknown;
} else {
- pci_read_config_word(adapter->pdev,
- cap_offset + PCIE_LINK_STATUS,
- &pcie_link_status);
- bus->width = (enum e1000_bus_width)((pcie_link_status &
- PCIE_LINK_WIDTH_MASK) >>
- PCIE_LINK_WIDTH_SHIFT);
+ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &pcie_link_status);
+ bus->width = (enum e1000_bus_width)FIELD_GET(PCI_EXP_LNKSTA_NLW,
+ pcie_link_status);
}
mac->ops.set_lan_id(hw);
@@ -52,7 +50,7 @@ void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw)
* for the device regardless of function swap state.
*/
reg = er32(STATUS);
- bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+ bus->func = FIELD_GET(E1000_STATUS_FUNC_MASK, reg);
}
/**
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index f536c856727c..af5d9d97a0d6 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1788,8 +1788,7 @@ static irqreturn_t e1000_intr_msi(int __always_unused irq, void *data)
adapter->corr_errors +=
pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
adapter->uncorr_errors +=
- (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
- E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+ FIELD_GET(E1000_PBECCSTS_UNCORR_ERR_CNT_MASK, pbeccsts);
/* Do the reset outside of interrupt context */
schedule_work(&adapter->reset_task);
@@ -1868,8 +1867,7 @@ static irqreturn_t e1000_intr(int __always_unused irq, void *data)
adapter->corr_errors +=
pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
adapter->uncorr_errors +=
- (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
- E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+ FIELD_GET(E1000_PBECCSTS_UNCORR_ERR_CNT_MASK, pbeccsts);
/* Do the reset outside of interrupt context */
schedule_work(&adapter->reset_task);
@@ -5031,8 +5029,7 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->corr_errors +=
pbeccsts & E1000_PBECCSTS_CORR_ERR_CNT_MASK;
adapter->uncorr_errors +=
- (pbeccsts & E1000_PBECCSTS_UNCORR_ERR_CNT_MASK) >>
- E1000_PBECCSTS_UNCORR_ERR_CNT_SHIFT;
+ FIELD_GET(E1000_PBECCSTS_UNCORR_ERR_CNT_MASK, pbeccsts);
}
}
@@ -6249,7 +6246,7 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
phy_reg |= BM_RCTL_MPE;
phy_reg &= ~(BM_RCTL_MO_MASK);
if (mac_reg & E1000_RCTL_MO_3)
- phy_reg |= (((mac_reg & E1000_RCTL_MO_3) >> E1000_RCTL_MO_SHIFT)
+ phy_reg |= (FIELD_GET(E1000_RCTL_MO_3, mac_reg)
<< BM_RCTL_MO_SHIFT);
if (mac_reg & E1000_RCTL_BAM)
phy_reg |= BM_RCTL_BAM;
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 08c3d477dd6f..5e329156d1ba 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -154,10 +154,9 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
e_dbg("MDI Read PHY Reg Address %d Error\n", offset);
return -E1000_ERR_PHY;
}
- if (((mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT) != offset) {
+ if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
e_dbg("MDI Read offset error - requested %d, returned %d\n",
- offset,
- (mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+ offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
return -E1000_ERR_PHY;
}
*data = (u16)mdic;
@@ -167,7 +166,6 @@ s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
*/
if (hw->mac.type == e1000_pch2lan)
udelay(100);
-
return 0;
}
@@ -218,10 +216,9 @@ s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
e_dbg("MDI Write PHY Red Address %d Error\n", offset);
return -E1000_ERR_PHY;
}
- if (((mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT) != offset) {
+ if (FIELD_GET(E1000_MDIC_REG_MASK, mdic) != offset) {
e_dbg("MDI Write offset error - requested %d, returned %d\n",
- offset,
- (mdic & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+ offset, FIELD_GET(E1000_MDIC_REG_MASK, mdic));
return -E1000_ERR_PHY;
}
@@ -463,8 +460,8 @@ static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data,
return ret_val;
}
- kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
- E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ kmrnctrlsta = FIELD_PREP(E1000_KMRNCTRLSTA_OFFSET, offset) |
+ E1000_KMRNCTRLSTA_REN;
ew32(KMRNCTRLSTA, kmrnctrlsta);
e1e_flush();
@@ -536,8 +533,7 @@ static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data,
return ret_val;
}
- kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
- E1000_KMRNCTRLSTA_OFFSET) | data;
+ kmrnctrlsta = FIELD_PREP(E1000_KMRNCTRLSTA_OFFSET, offset) | data;
ew32(KMRNCTRLSTA, kmrnctrlsta);
e1e_flush();
@@ -1793,8 +1789,7 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- index = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+ index = FIELD_GET(M88E1000_PSSR_CABLE_LENGTH, phy_data);
if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1)
return -E1000_ERR_PHY;
@@ -3234,8 +3229,7 @@ s32 e1000_get_cable_length_82577(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- length = ((phy_data & I82577_DSTATUS_CABLE_LENGTH) >>
- I82577_DSTATUS_CABLE_LENGTH_SHIFT);
+ length = FIELD_GET(I82577_DSTATUS_CABLE_LENGTH, phy_data);
if (length == E1000_CABLE_LENGTH_UNDEFINED)
return -E1000_ERR_PHY;
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index 02d871bc112a..bbcfd529399b 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -280,8 +280,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
switch (hw->mac.type) {
case e1000_pch2lan:
+ adapter->ptp_clock_info.max_adj = MAX_PPB_96MHZ;
+ break;
case e1000_pch_lpt:
+ if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
+ adapter->ptp_clock_info.max_adj = MAX_PPB_96MHZ;
+ else
+ adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
+ break;
case e1000_pch_spt:
+ adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
+ break;
case e1000_pch_cnp:
case e1000_pch_tgp:
case e1000_pch_adp:
@@ -289,15 +298,14 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
case e1000_pch_lnp:
case e1000_pch_ptp:
case e1000_pch_nvp:
- if ((hw->mac.type < e1000_pch_lpt) ||
- (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
- adapter->ptp_clock_info.max_adj = 24000000 - 1;
- break;
- }
- fallthrough;
+ if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
+ adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
+ else
+ adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
+ break;
case e1000_82574:
case e1000_82583:
- adapter->ptp_clock_info.max_adj = 600000000 - 1;
+ adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
break;
default:
break;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
index 13a05604dcc0..1bc5b6c0b897 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c
@@ -1057,16 +1057,16 @@ static u32 fm10k_get_rssrk_size(struct net_device __always_unused *netdev)
return FM10K_RSSRK_SIZE * FM10K_RSSRK_ENTRIES_PER_REG;
}
-static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int fm10k_get_rssh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
+ u8 *key = rxfh->key;
int i, err;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
- err = fm10k_get_reta(netdev, indir);
+ err = fm10k_get_reta(netdev, rxfh->indir);
if (err || !key)
return err;
@@ -1076,23 +1076,25 @@ static int fm10k_get_rssh(struct net_device *netdev, u32 *indir, u8 *key,
return 0;
}
-static int fm10k_set_rssh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int fm10k_set_rssh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct fm10k_intfc *interface = netdev_priv(netdev);
struct fm10k_hw *hw = &interface->hw;
int i, err;
/* We do not allow change in unsupported parameters */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- err = fm10k_set_reta(netdev, indir);
- if (err || !key)
+ err = fm10k_set_reta(netdev, rxfh->indir);
+ if (err || !rxfh->key)
return err;
- for (i = 0; i < FM10K_RSSRK_SIZE; i++, key += 4) {
- u32 rssrk = le32_to_cpu(*(__le32 *)key);
+ for (i = 0; i < FM10K_RSSRK_SIZE; i++, rxfh->key += 4) {
+ u32 rssrk = le32_to_cpu(*(__le32 *)rxfh->key);
if (interface->rssrk[i] == rssrk)
continue;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
index af1b0cde3670..98861cc6df7c 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2019 Intel Corporation. */
+#include <linux/bitfield.h>
#include "fm10k_pf.h"
#include "fm10k_vf.h"
@@ -865,8 +866,7 @@ static s32 fm10k_iov_assign_default_mac_vlan_pf(struct fm10k_hw *hw,
* register is RO from the VF, so the PF must do this even in the
* case of notifying the VF of a new VID via the mailbox.
*/
- txqctl = ((u32)vf_vid << FM10K_TXQCTL_VID_SHIFT) &
- FM10K_TXQCTL_VID_MASK;
+ txqctl = FIELD_PREP(FM10K_TXQCTL_VID_MASK, vf_vid);
txqctl |= (vf_idx << FM10K_TXQCTL_TC_SHIFT) |
FM10K_TXQCTL_VF | vf_idx;
@@ -1575,8 +1575,7 @@ static s32 fm10k_get_fault_pf(struct fm10k_hw *hw, int type,
if (func & FM10K_FAULT_FUNC_PF)
fault->func = 0;
else
- fault->func = 1 + ((func & FM10K_FAULT_FUNC_VF_MASK) >>
- FM10K_FAULT_FUNC_VF_SHIFT);
+ fault->func = 1 + FIELD_GET(FM10K_FAULT_FUNC_VF_MASK, func);
/* record fault type */
fault->type = func & FM10K_FAULT_FUNC_TYPE_MASK;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c
index dc8ccd378ec9..7fb1961f2921 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2019 Intel Corporation. */
+#include <linux/bitfield.h>
#include "fm10k_vf.h"
/**
@@ -126,15 +127,14 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw)
hw->mac.max_queues = i;
/* fetch default VLAN and ITR scale */
- hw->mac.default_vid = (fm10k_read_reg(hw, FM10K_TXQCTL(0)) &
- FM10K_TXQCTL_VID_MASK) >> FM10K_TXQCTL_VID_SHIFT;
+ hw->mac.default_vid = FIELD_GET(FM10K_TXQCTL_VID_MASK,
+ fm10k_read_reg(hw, FM10K_TXQCTL(0)));
/* Read the ITR scale from TDLEN. See the definition of
* FM10K_TDLEN_ITR_SCALE_SHIFT for more information about how TDLEN is
* used here.
*/
- hw->mac.itr_scale = (fm10k_read_reg(hw, FM10K_TDLEN(0)) &
- FM10K_TDLEN_ITR_SCALE_MASK) >>
- FM10K_TDLEN_ITR_SCALE_SHIFT;
+ hw->mac.itr_scale = FIELD_GET(FM10K_TDLEN_ITR_SCALE_MASK,
+ fm10k_read_reg(hw, FM10K_TDLEN(0)));
return 0;
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index 1bf424ac3145..9b701615c7c6 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -24,6 +24,7 @@
#define I40E_MAX_VEB 16
#define I40E_MAX_NUM_DESCRIPTORS 4096
+#define I40E_MAX_NUM_DESCRIPTORS_XL710 8160
#define I40E_MAX_CSR_SPACE (4 * 1024 * 1024 - 64 * 1024)
#define I40E_DEFAULT_NUM_DESCRIPTORS 512
#define I40E_REQ_DESCRIPTOR_MULTIPLE 32
@@ -33,11 +34,11 @@
#define I40E_MIN_VSI_ALLOC 83 /* LAN, ATR, FCOE, 64 VF */
/* max 16 qps */
#define i40e_default_queues_per_vmdq(pf) \
- (((pf)->hw_features & I40E_HW_RSS_AQ_CAPABLE) ? 4 : 1)
+ (test_bit(I40E_HW_CAP_RSS_AQ, (pf)->hw.caps) ? 4 : 1)
#define I40E_DEFAULT_QUEUES_PER_VF 4
#define I40E_MAX_VF_QUEUES 16
#define i40e_pf_get_max_q_per_tc(pf) \
- (((pf)->hw_features & I40E_HW_128_QP_RSS_CAPABLE) ? 128 : 64)
+ (test_bit(I40E_HW_CAP_128_QP_RSS, (pf)->hw.caps) ? 128 : 64)
#define I40E_FDIR_RING_COUNT 32
#define I40E_MAX_AQ_BUF_SIZE 4096
#define I40E_AQ_LEN 256
@@ -78,7 +79,7 @@
#define I40E_MAX_BW_INACTIVE_ACCUM 4 /* accumulate 4 credits max */
/* driver state flags */
-enum i40e_state_t {
+enum i40e_state {
__I40E_TESTING,
__I40E_CONFIG_BUSY,
__I40E_CONFIG_DONE,
@@ -126,7 +127,7 @@ enum i40e_state_t {
BIT_ULL(__I40E_PF_RESET_AND_REBUILD_REQUESTED)
/* VSI state flags */
-enum i40e_vsi_state_t {
+enum i40e_vsi_state {
__I40E_VSI_DOWN,
__I40E_VSI_NEEDS_RESTART,
__I40E_VSI_SYNCING_FILTERS,
@@ -138,6 +139,60 @@ enum i40e_vsi_state_t {
__I40E_VSI_STATE_SIZE__,
};
+enum i40e_pf_flags {
+ I40E_FLAG_MSI_ENA,
+ I40E_FLAG_MSIX_ENA,
+ I40E_FLAG_RSS_ENA,
+ I40E_FLAG_VMDQ_ENA,
+ I40E_FLAG_SRIOV_ENA,
+ I40E_FLAG_DCB_CAPABLE,
+ I40E_FLAG_DCB_ENA,
+ I40E_FLAG_FD_SB_ENA,
+ I40E_FLAG_FD_ATR_ENA,
+ I40E_FLAG_MFP_ENA,
+ I40E_FLAG_HW_ATR_EVICT_ENA,
+ I40E_FLAG_VEB_MODE_ENA,
+ I40E_FLAG_VEB_STATS_ENA,
+ I40E_FLAG_LINK_POLLING_ENA,
+ I40E_FLAG_TRUE_PROMISC_ENA,
+ I40E_FLAG_LEGACY_RX_ENA,
+ I40E_FLAG_PTP_ENA,
+ I40E_FLAG_IWARP_ENA,
+ I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA,
+ I40E_FLAG_SOURCE_PRUNING_DIS,
+ I40E_FLAG_TC_MQPRIO_ENA,
+ I40E_FLAG_FD_SB_INACTIVE,
+ I40E_FLAG_FD_SB_TO_CLOUD_FILTER,
+ I40E_FLAG_FW_LLDP_DIS,
+ I40E_FLAG_RS_FEC,
+ I40E_FLAG_BASE_R_FEC,
+ /* TOTAL_PORT_SHUTDOWN_ENA
+ * Allows to physically disable the link on the NIC's port.
+ * If enabled, (after link down request from the OS)
+ * no link, traffic or led activity is possible on that port.
+ *
+ * If I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA is set, the
+ * I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA must be explicitly forced
+ * to true and cannot be disabled by system admin at that time.
+ * The functionalities are exclusive in terms of configuration, but
+ * they also have similar behavior (allowing to disable physical
+ * link of the port), with following differences:
+ * - LINK_DOWN_ON_CLOSE_ENA is configurable at host OS run-time and
+ * is supported by whole family of 7xx Intel Ethernet Controllers
+ * - TOTAL_PORT_SHUTDOWN_ENA may be enabled only before OS loads
+ * (in BIOS) only if motherboard's BIOS and NIC's FW has support of it
+ * - when LINK_DOWN_ON_CLOSE_ENABLED is used, the link is being brought
+ * down by sending phy_type=0 to NIC's FW
+ * - when TOTAL_PORT_SHUTDOWN_ENA is used, phy_type is not altered,
+ * instead the link is being brought down by clearing
+ * bit (I40E_AQ_PHY_ENABLE_LINK) in abilities field of
+ * i40e_aq_set_phy_config structure
+ */
+ I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA,
+ I40E_FLAG_VF_VLAN_PRUNING_ENA,
+ I40E_PF_FLAGS_NBITS, /* must be last */
+};
+
enum i40e_interrupt_policy {
I40E_INTERRUPT_BEST_CASE,
I40E_INTERRUPT_MEDIUM,
@@ -413,9 +468,7 @@ struct i40e_pf {
struct i40e_hw hw;
DECLARE_BITMAP(state, __I40E_STATE_SIZE__);
struct msix_entry *msix_entries;
- bool fc_autoneg_status;
- u16 eeprom_version;
u16 num_vmdq_vsis; /* num vmdq vsis this PF has set up */
u16 num_vmdq_qps; /* num queue pairs per vmdq pool */
u16 num_vmdq_msix; /* num queue vectors per vmdq pool */
@@ -431,7 +484,6 @@ struct i40e_pf {
u16 rss_size_max; /* HW defined max RSS queues */
u16 fdir_pf_filter_count; /* num of guaranteed filters for this PF */
u16 num_alloc_vsi; /* num VSIs this driver supports */
- u8 atr_sample_rate;
bool wol_en;
struct hlist_head fdir_filter_list;
@@ -469,89 +521,16 @@ struct i40e_pf {
struct hlist_head cloud_filter_list;
u16 num_cloud_filters;
- enum i40e_interrupt_policy int_policy;
u16 rx_itr_default;
u16 tx_itr_default;
u32 msg_enable;
char int_name[I40E_INT_NAME_STR_LEN];
- u16 adminq_work_limit; /* num of admin receive queue desc to process */
unsigned long service_timer_period;
unsigned long service_timer_previous;
struct timer_list service_timer;
struct work_struct service_task;
- u32 hw_features;
-#define I40E_HW_RSS_AQ_CAPABLE BIT(0)
-#define I40E_HW_128_QP_RSS_CAPABLE BIT(1)
-#define I40E_HW_ATR_EVICT_CAPABLE BIT(2)
-#define I40E_HW_WB_ON_ITR_CAPABLE BIT(3)
-#define I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE BIT(4)
-#define I40E_HW_NO_PCI_LINK_CHECK BIT(5)
-#define I40E_HW_100M_SGMII_CAPABLE BIT(6)
-#define I40E_HW_NO_DCB_SUPPORT BIT(7)
-#define I40E_HW_USE_SET_LLDP_MIB BIT(8)
-#define I40E_HW_GENEVE_OFFLOAD_CAPABLE BIT(9)
-#define I40E_HW_PTP_L4_CAPABLE BIT(10)
-#define I40E_HW_WOL_MC_MAGIC_PKT_WAKE BIT(11)
-#define I40E_HW_HAVE_CRT_RETIMER BIT(13)
-#define I40E_HW_OUTER_UDP_CSUM_CAPABLE BIT(14)
-#define I40E_HW_PHY_CONTROLS_LEDS BIT(15)
-#define I40E_HW_STOP_FW_LLDP BIT(16)
-#define I40E_HW_PORT_ID_VALID BIT(17)
-#define I40E_HW_RESTART_AUTONEG BIT(18)
-
- u32 flags;
-#define I40E_FLAG_RX_CSUM_ENABLED BIT(0)
-#define I40E_FLAG_MSI_ENABLED BIT(1)
-#define I40E_FLAG_MSIX_ENABLED BIT(2)
-#define I40E_FLAG_RSS_ENABLED BIT(3)
-#define I40E_FLAG_VMDQ_ENABLED BIT(4)
-#define I40E_FLAG_SRIOV_ENABLED BIT(5)
-#define I40E_FLAG_DCB_CAPABLE BIT(6)
-#define I40E_FLAG_DCB_ENABLED BIT(7)
-#define I40E_FLAG_FD_SB_ENABLED BIT(8)
-#define I40E_FLAG_FD_ATR_ENABLED BIT(9)
-#define I40E_FLAG_MFP_ENABLED BIT(10)
-#define I40E_FLAG_HW_ATR_EVICT_ENABLED BIT(11)
-#define I40E_FLAG_VEB_MODE_ENABLED BIT(12)
-#define I40E_FLAG_VEB_STATS_ENABLED BIT(13)
-#define I40E_FLAG_LINK_POLLING_ENABLED BIT(14)
-#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT(15)
-#define I40E_FLAG_LEGACY_RX BIT(16)
-#define I40E_FLAG_PTP BIT(17)
-#define I40E_FLAG_IWARP_ENABLED BIT(18)
-#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT(19)
-#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT(20)
-#define I40E_FLAG_TC_MQPRIO BIT(21)
-#define I40E_FLAG_FD_SB_INACTIVE BIT(22)
-#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT(23)
-#define I40E_FLAG_DISABLE_FW_LLDP BIT(24)
-#define I40E_FLAG_RS_FEC BIT(25)
-#define I40E_FLAG_BASE_R_FEC BIT(26)
-/* TOTAL_PORT_SHUTDOWN
- * Allows to physically disable the link on the NIC's port.
- * If enabled, (after link down request from the OS)
- * no link, traffic or led activity is possible on that port.
- *
- * If I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED is set, the
- * I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED must be explicitly forced to true
- * and cannot be disabled by system admin at that time.
- * The functionalities are exclusive in terms of configuration, but they also
- * have similar behavior (allowing to disable physical link of the port),
- * with following differences:
- * - LINK_DOWN_ON_CLOSE_ENABLED is configurable at host OS run-time and is
- * supported by whole family of 7xx Intel Ethernet Controllers
- * - TOTAL_PORT_SHUTDOWN may be enabled only before OS loads (in BIOS)
- * only if motherboard's BIOS and NIC's FW has support of it
- * - when LINK_DOWN_ON_CLOSE_ENABLED is used, the link is being brought down
- * by sending phy_type=0 to NIC's FW
- * - when TOTAL_PORT_SHUTDOWN is used, phy_type is not altered, instead
- * the link is being brought down by clearing bit (I40E_AQ_PHY_ENABLE_LINK)
- * in abilities field of i40e_aq_set_phy_config structure
- */
-#define I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED BIT(27)
-#define I40E_FLAG_VF_VLAN_PRUNING BIT(28)
-
+ DECLARE_BITMAP(flags, I40E_PF_FLAGS_NBITS);
struct i40e_client_instance *cinst;
bool stat_offsets_loaded;
struct i40e_hw_port_stats stats;
@@ -559,7 +538,6 @@ struct i40e_pf {
u32 tx_timeout_count;
u32 tx_timeout_recovery_level;
unsigned long tx_timeout_last_recovery;
- u32 tx_sluggish_count;
u32 hw_csum_rx_error;
u32 led_status;
u16 corer_count; /* Core reset count */
@@ -581,17 +559,13 @@ struct i40e_pf {
struct i40e_lump_tracking *irq_pile;
/* switch config info */
- u16 pf_seid;
u16 main_vsi_seid;
u16 mac_seid;
- struct kobject *switch_kobj;
#ifdef CONFIG_DEBUG_FS
struct dentry *i40e_dbg_pf;
#endif /* CONFIG_DEBUG_FS */
bool cur_promisc;
- u16 instance; /* A unique number per i40e_pf instance in the system */
-
/* sr-iov config info */
struct i40e_vf *vf;
int num_alloc_vfs; /* actual number of VFs allocated */
@@ -685,9 +659,7 @@ struct i40e_pf {
unsigned long ptp_tx_start;
struct hwtstamp_config tstamp_config;
struct timespec64 ptp_prev_hw_time;
- struct work_struct ptp_pps_work;
struct work_struct ptp_extts0_work;
- struct work_struct ptp_extts1_work;
ktime_t ptp_reset_start;
struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */
u32 ptp_adj_mult;
@@ -695,10 +667,7 @@ struct i40e_pf {
u32 tx_hwtstamp_skipped;
u32 rx_hwtstamp_cleared;
u32 latch_event_flags;
- u64 ptp_pps_start;
- u32 pps_delay;
spinlock_t ptp_rx_lock; /* Used to protect Rx timestamp registers. */
- struct ptp_pin_desc ptp_pin[3];
unsigned long latch_events[4];
bool ptp_tx;
bool ptp_rx;
@@ -711,7 +680,6 @@ struct i40e_pf {
u32 fd_inv;
u16 phy_led_val;
- u16 override_q_count;
u16 last_sw_conf_flags;
u16 last_sw_conf_valid_flags;
/* List to keep previous DDP profiles to be rolled back in the future */
@@ -1267,7 +1235,7 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr);
void i40e_vlan_stripping_enable(struct i40e_vsi *vsi);
static inline bool i40e_is_sw_dcb(struct i40e_pf *pf)
{
- return !!(pf->flags & I40E_FLAG_DISABLE_FW_LLDP);
+ return test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags);
}
#ifdef CONFIG_I40E_DCB
@@ -1301,7 +1269,7 @@ int i40e_set_partition_bw_setting(struct i40e_pf *pf);
int i40e_commit_partition_bw_setting(struct i40e_pf *pf);
void i40e_print_link_message(struct i40e_vsi *vsi, bool isup);
-void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags);
+void i40e_set_fec_in_flags(u8 fec_cfg, unsigned long *flags);
static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
{
@@ -1321,13 +1289,13 @@ int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
* i40e_is_tc_mqprio_enabled - check if TC MQPRIO is enabled on PF
* @pf: pointer to a pf.
*
- * Check and return value of flag I40E_FLAG_TC_MQPRIO.
+ * Check and return state of flag I40E_FLAG_TC_MQPRIO.
*
- * Return: I40E_FLAG_TC_MQPRIO set state.
+ * Return: true/false if I40E_FLAG_TC_MQPRIO is set or not
**/
-static inline u32 i40e_is_tc_mqprio_enabled(struct i40e_pf *pf)
+static inline bool i40e_is_tc_mqprio_enabled(struct i40e_pf *pf)
{
- return pf->flags & I40E_FLAG_TC_MQPRIO;
+ return test_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags);
}
/**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index 9ce6e633cc2f..f73f5930fc58 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -9,40 +9,6 @@
static void i40e_resume_aq(struct i40e_hw *hw);
/**
- * i40e_adminq_init_regs - Initialize AdminQ registers
- * @hw: pointer to the hardware structure
- *
- * This assumes the alloc_asq and alloc_arq functions have already been called
- **/
-static void i40e_adminq_init_regs(struct i40e_hw *hw)
-{
- /* set head and tail registers in our local struct */
- if (i40e_is_vf(hw)) {
- hw->aq.asq.tail = I40E_VF_ATQT1;
- hw->aq.asq.head = I40E_VF_ATQH1;
- hw->aq.asq.len = I40E_VF_ATQLEN1;
- hw->aq.asq.bal = I40E_VF_ATQBAL1;
- hw->aq.asq.bah = I40E_VF_ATQBAH1;
- hw->aq.arq.tail = I40E_VF_ARQT1;
- hw->aq.arq.head = I40E_VF_ARQH1;
- hw->aq.arq.len = I40E_VF_ARQLEN1;
- hw->aq.arq.bal = I40E_VF_ARQBAL1;
- hw->aq.arq.bah = I40E_VF_ARQBAH1;
- } else {
- hw->aq.asq.tail = I40E_PF_ATQT;
- hw->aq.asq.head = I40E_PF_ATQH;
- hw->aq.asq.len = I40E_PF_ATQLEN;
- hw->aq.asq.bal = I40E_PF_ATQBAL;
- hw->aq.asq.bah = I40E_PF_ATQBAH;
- hw->aq.arq.tail = I40E_PF_ARQT;
- hw->aq.arq.head = I40E_PF_ARQH;
- hw->aq.arq.len = I40E_PF_ARQLEN;
- hw->aq.arq.bal = I40E_PF_ARQBAL;
- hw->aq.arq.bah = I40E_PF_ARQBAH;
- }
-}
-
-/**
* i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings
* @hw: pointer to the hardware structure
**/
@@ -267,17 +233,17 @@ static int i40e_config_asq_regs(struct i40e_hw *hw)
u32 reg = 0;
/* Clear Head and Tail */
- wr32(hw, hw->aq.asq.head, 0);
- wr32(hw, hw->aq.asq.tail, 0);
+ wr32(hw, I40E_PF_ATQH, 0);
+ wr32(hw, I40E_PF_ATQT, 0);
/* set starting point */
- wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries |
+ wr32(hw, I40E_PF_ATQLEN, (hw->aq.num_asq_entries |
I40E_PF_ATQLEN_ATQENABLE_MASK));
- wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa));
- wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa));
+ wr32(hw, I40E_PF_ATQBAL, lower_32_bits(hw->aq.asq.desc_buf.pa));
+ wr32(hw, I40E_PF_ATQBAH, upper_32_bits(hw->aq.asq.desc_buf.pa));
/* Check one register to verify that config was applied */
- reg = rd32(hw, hw->aq.asq.bal);
+ reg = rd32(hw, I40E_PF_ATQBAL);
if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa))
ret_code = -EIO;
@@ -296,20 +262,20 @@ static int i40e_config_arq_regs(struct i40e_hw *hw)
u32 reg = 0;
/* Clear Head and Tail */
- wr32(hw, hw->aq.arq.head, 0);
- wr32(hw, hw->aq.arq.tail, 0);
+ wr32(hw, I40E_PF_ARQH, 0);
+ wr32(hw, I40E_PF_ARQT, 0);
/* set starting point */
- wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries |
+ wr32(hw, I40E_PF_ARQLEN, (hw->aq.num_arq_entries |
I40E_PF_ARQLEN_ARQENABLE_MASK));
- wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa));
- wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa));
+ wr32(hw, I40E_PF_ARQBAL, lower_32_bits(hw->aq.arq.desc_buf.pa));
+ wr32(hw, I40E_PF_ARQBAH, upper_32_bits(hw->aq.arq.desc_buf.pa));
/* Update tail in the HW to post pre-allocated buffers */
- wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1);
+ wr32(hw, I40E_PF_ARQT, hw->aq.num_arq_entries - 1);
/* Check one register to verify that config was applied */
- reg = rd32(hw, hw->aq.arq.bal);
+ reg = rd32(hw, I40E_PF_ARQBAL);
if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa))
ret_code = -EIO;
@@ -452,11 +418,11 @@ static int i40e_shutdown_asq(struct i40e_hw *hw)
}
/* Stop firmware AdminQ processing */
- wr32(hw, hw->aq.asq.head, 0);
- wr32(hw, hw->aq.asq.tail, 0);
- wr32(hw, hw->aq.asq.len, 0);
- wr32(hw, hw->aq.asq.bal, 0);
- wr32(hw, hw->aq.asq.bah, 0);
+ wr32(hw, I40E_PF_ATQH, 0);
+ wr32(hw, I40E_PF_ATQT, 0);
+ wr32(hw, I40E_PF_ATQLEN, 0);
+ wr32(hw, I40E_PF_ATQBAL, 0);
+ wr32(hw, I40E_PF_ATQBAH, 0);
hw->aq.asq.count = 0; /* to indicate uninitialized queue */
@@ -486,11 +452,11 @@ static int i40e_shutdown_arq(struct i40e_hw *hw)
}
/* Stop firmware AdminQ processing */
- wr32(hw, hw->aq.arq.head, 0);
- wr32(hw, hw->aq.arq.tail, 0);
- wr32(hw, hw->aq.arq.len, 0);
- wr32(hw, hw->aq.arq.bal, 0);
- wr32(hw, hw->aq.arq.bah, 0);
+ wr32(hw, I40E_PF_ARQH, 0);
+ wr32(hw, I40E_PF_ARQT, 0);
+ wr32(hw, I40E_PF_ARQLEN, 0);
+ wr32(hw, I40E_PF_ARQBAL, 0);
+ wr32(hw, I40E_PF_ARQBAH, 0);
hw->aq.arq.count = 0; /* to indicate uninitialized queue */
@@ -503,44 +469,76 @@ shutdown_arq_out:
}
/**
- * i40e_set_hw_flags - set HW flags
+ * i40e_set_hw_caps - set HW flags
* @hw: pointer to the hardware structure
**/
-static void i40e_set_hw_flags(struct i40e_hw *hw)
+static void i40e_set_hw_caps(struct i40e_hw *hw)
{
- struct i40e_adminq_info *aq = &hw->aq;
-
- hw->flags = 0;
+ bitmap_zero(hw->caps, I40E_HW_CAPS_NBITS);
switch (hw->mac.type) {
case I40E_MAC_XL710:
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710)) {
- hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
- hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
+ if (i40e_is_aq_api_ver_ge(hw, 1,
+ I40E_MINOR_VER_GET_LINK_INFO_XL710)) {
+ set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps);
+ set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps);
/* The ability to RX (not drop) 802.1ad frames */
- hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE;
+ set_bit(I40E_HW_CAP_802_1AD, hw->caps);
+ }
+ if (i40e_is_aq_api_ver_ge(hw, 1, 5)) {
+ /* Supported in FW API version higher than 1.4 */
+ set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, hw->caps);
+ }
+ if (i40e_is_fw_ver_lt(hw, 4, 33)) {
+ set_bit(I40E_HW_CAP_RESTART_AUTONEG, hw->caps);
+ /* No DCB support for FW < v4.33 */
+ set_bit(I40E_HW_CAP_NO_DCB_SUPPORT, hw->caps);
+ }
+ if (i40e_is_fw_ver_lt(hw, 4, 3)) {
+ /* Disable FW LLDP if FW < v4.3 */
+ set_bit(I40E_HW_CAP_STOP_FW_LLDP, hw->caps);
+ }
+ if (i40e_is_fw_ver_ge(hw, 4, 40)) {
+ /* Use the FW Set LLDP MIB API if FW >= v4.40 */
+ set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, hw->caps);
+ }
+ if (i40e_is_fw_ver_ge(hw, 6, 0)) {
+ /* Enable PTP L4 if FW > v6.0 */
+ set_bit(I40E_HW_CAP_PTP_L4, hw->caps);
}
break;
case I40E_MAC_X722:
- hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE |
- I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;
+ set_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps);
+ set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps);
+ set_bit(I40E_HW_CAP_RSS_AQ, hw->caps);
+ set_bit(I40E_HW_CAP_128_QP_RSS, hw->caps);
+ set_bit(I40E_HW_CAP_ATR_EVICT, hw->caps);
+ set_bit(I40E_HW_CAP_WB_ON_ITR, hw->caps);
+ set_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, hw->caps);
+ set_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, hw->caps);
+ set_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, hw->caps);
+ set_bit(I40E_HW_CAP_GENEVE_OFFLOAD, hw->caps);
+ set_bit(I40E_HW_CAP_PTP_L4, hw->caps);
+ set_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, hw->caps);
+ set_bit(I40E_HW_CAP_OUTER_UDP_CSUM, hw->caps);
+
+ if (rd32(hw, I40E_GLQF_FDEVICTENA(1)) !=
+ I40E_FDEVICT_PCTYPE_DEFAULT) {
+ hw_warn(hw, "FD EVICT PCTYPES are not right, disable FD HW EVICT\n");
+ clear_bit(I40E_HW_CAP_ATR_EVICT, hw->caps);
+ }
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722))
- hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
+ if (i40e_is_aq_api_ver_ge(hw, 1,
+ I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722))
+ set_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps);
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_X722))
- hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
+ if (i40e_is_aq_api_ver_ge(hw, 1,
+ I40E_MINOR_VER_GET_LINK_INFO_X722))
+ set_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps);
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= I40E_MINOR_VER_FW_REQUEST_FEC_X722))
- hw->flags |= I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE;
+ if (i40e_is_aq_api_ver_ge(hw, 1,
+ I40E_MINOR_VER_FW_REQUEST_FEC_X722))
+ set_bit(I40E_HW_CAP_X722_FEC_REQUEST, hw->caps);
fallthrough;
default:
@@ -548,22 +546,18 @@ static void i40e_set_hw_flags(struct i40e_hw *hw)
}
/* Newer versions of firmware require lock when reading the NVM */
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= 5))
- hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;
-
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= 8)) {
- hw->flags |= I40E_HW_FLAG_FW_LLDP_PERSISTENT;
- hw->flags |= I40E_HW_FLAG_DROP_MODE;
- }
+ if (i40e_is_aq_api_ver_ge(hw, 1, 5))
+ set_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps);
+
+ /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */
+ if (i40e_is_aq_api_ver_ge(hw, 1, 7))
+ set_bit(I40E_HW_CAP_802_1AD, hw->caps);
+
+ if (i40e_is_aq_api_ver_ge(hw, 1, 8))
+ set_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps);
- if (aq->api_maj_ver > 1 ||
- (aq->api_maj_ver == 1 &&
- aq->api_min_ver >= 9))
- hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED;
+ if (i40e_is_aq_api_ver_ge(hw, 1, 9))
+ set_bit(I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, hw->caps);
}
/**
@@ -593,9 +587,6 @@ int i40e_init_adminq(struct i40e_hw *hw)
goto init_adminq_exit;
}
- /* Set up register offsets */
- i40e_adminq_init_regs(hw);
-
/* setup ASQ command write back timeout */
hw->aq.asq_cmd_timeout = I40E_ASQ_CMD_TIMEOUT;
@@ -633,7 +624,7 @@ int i40e_init_adminq(struct i40e_hw *hw)
/* Some features were introduced in different FW API version
* for different MAC type.
*/
- i40e_set_hw_flags(hw);
+ i40e_set_hw_caps(hw);
/* get the NVM version info */
i40e_read_nvm_word(hw, I40E_SR_NVM_DEV_STARTER_VERSION,
@@ -648,25 +639,7 @@ int i40e_init_adminq(struct i40e_hw *hw)
&oem_lo);
hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo;
- if (hw->mac.type == I40E_MAC_XL710 &&
- hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
- hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
- hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
- hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
- }
- if (hw->mac.type == I40E_MAC_X722 &&
- hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
- hw->aq.api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722) {
- hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
- }
-
- /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */
- if (hw->aq.api_maj_ver > 1 ||
- (hw->aq.api_maj_ver == 1 &&
- hw->aq.api_min_ver >= 7))
- hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE;
-
- if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
+ if (i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR + 1, 0)) {
ret_code = -EIO;
goto init_adminq_free_arq;
}
@@ -723,9 +696,9 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
desc = I40E_ADMINQ_DESC(*asq, ntc);
details = I40E_ADMINQ_DETAILS(*asq, ntc);
- while (rd32(hw, hw->aq.asq.head) != ntc) {
+ while (rd32(hw, I40E_PF_ATQH) != ntc) {
i40e_debug(hw, I40E_DEBUG_AQ_COMMAND,
- "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head));
+ "ntc %d head %d.\n", ntc, rd32(hw, I40E_PF_ATQH));
if (details->callback) {
I40E_ADMINQ_CALLBACK cb_func =
@@ -759,7 +732,7 @@ static bool i40e_asq_done(struct i40e_hw *hw)
/* AQ designers suggest use of head for better
* timing reliability than DD bit
*/
- return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use;
+ return rd32(hw, I40E_PF_ATQH) == hw->aq.asq.next_to_use;
}
@@ -800,7 +773,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
hw->aq.asq_last_status = I40E_AQ_RC_OK;
- val = rd32(hw, hw->aq.asq.head);
+ val = rd32(hw, I40E_PF_ATQH);
if (val >= hw->aq.num_asq_entries) {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQTX: head overrun at %d\n", val);
@@ -892,7 +865,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
if (hw->aq.asq.next_to_use == hw->aq.asq.count)
hw->aq.asq.next_to_use = 0;
if (!details->postpone)
- wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use);
+ wr32(hw, I40E_PF_ATQT, hw->aq.asq.next_to_use);
/* if cmd_details are not defined or async flag is not set,
* we need to wait for desc write back
@@ -952,7 +925,7 @@ i40e_asq_send_command_atomic_exec(struct i40e_hw *hw,
/* update the error if time out occurred */
if ((!cmd_completed) &&
(!details->async && !details->postpone)) {
- if (rd32(hw, hw->aq.asq.len) & I40E_GL_ATQLEN_ATQCRIT_MASK) {
+ if (rd32(hw, I40E_PF_ATQLEN) & I40E_GL_ATQLEN_ATQCRIT_MASK) {
i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
"AQTX: AQ Critical error.\n");
status = -EIO;
@@ -1106,7 +1079,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw,
}
/* set next_to_use to head */
- ntu = rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK;
+ ntu = rd32(hw, I40E_PF_ARQH) & I40E_PF_ARQH_ARQH_MASK;
if (ntu == ntc) {
/* nothing to do - shouldn't need to update ring's values */
ret_code = -EALREADY;
@@ -1154,7 +1127,7 @@ int i40e_clean_arq_element(struct i40e_hw *hw,
desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa));
/* set tail = the last cleaned desc index. */
- wr32(hw, hw->aq.arq.tail, ntc);
+ wr32(hw, I40E_PF_ARQT, ntc);
/* ntc is updated to tail + 1 */
ntc++;
if (ntc == hw->aq.num_arq_entries)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
index 80125bea80a2..ee86d2c53079 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
@@ -29,13 +29,6 @@ struct i40e_adminq_ring {
/* used for interrupt processing */
u16 next_to_use;
u16 next_to_clean;
-
- /* used for queue tracking */
- u32 head;
- u32 tail;
- u32 len;
- u32 bah;
- u32 bal;
};
/* ASQ transaction details */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index 18a1c3b6d72c..c8f35d4de271 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -5,6 +5,7 @@
#define _I40E_ADMINQ_CMD_H_
#include <linux/bits.h>
+#include <linux/types.h>
/* This header file defines the i40e Admin Queue commands and is shared between
* i40e Firmware and Software.
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index d7e24d661724..de6ca6295742 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -2,6 +2,7 @@
/* Copyright(c) 2013 - 2021 Intel Corporation. */
#include <linux/avf/virtchnl.h>
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
@@ -195,11 +196,11 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
**/
bool i40e_check_asq_alive(struct i40e_hw *hw)
{
- if (hw->aq.asq.len)
- return !!(rd32(hw, hw->aq.asq.len) &
- I40E_PF_ATQLEN_ATQENABLE_MASK);
- else
+ /* Check if the queue is initialized */
+ if (!hw->aq.asq.count)
return false;
+
+ return !!(rd32(hw, I40E_PF_ATQLEN) & I40E_PF_ATQLEN_ATQENABLE_MASK);
}
/**
@@ -248,6 +249,7 @@ static int i40e_aq_get_set_rss_lut(struct i40e_hw *hw,
struct i40e_aqc_get_set_rss_lut *cmd_resp =
(struct i40e_aqc_get_set_rss_lut *)&desc.params.raw;
int status;
+ u16 flags;
if (set)
i40e_fill_default_direct_cmd_desc(&desc,
@@ -260,23 +262,18 @@ static int i40e_aq_get_set_rss_lut(struct i40e_hw *hw,
desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
- cmd_resp->vsi_id =
- cpu_to_le16((u16)((vsi_id <<
- I40E_AQC_SET_RSS_LUT_VSI_ID_SHIFT) &
- I40E_AQC_SET_RSS_LUT_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_LUT_VSI_VALID);
+ vsi_id = FIELD_PREP(I40E_AQC_SET_RSS_LUT_VSI_ID_MASK, vsi_id) |
+ FIELD_PREP(I40E_AQC_SET_RSS_LUT_VSI_VALID, 1);
+ cmd_resp->vsi_id = cpu_to_le16(vsi_id);
if (pf_lut)
- cmd_resp->flags |= cpu_to_le16((u16)
- ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF <<
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ flags = FIELD_PREP(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK,
+ I40E_AQC_SET_RSS_LUT_TABLE_TYPE_PF);
else
- cmd_resp->flags |= cpu_to_le16((u16)
- ((I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI <<
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ flags = FIELD_PREP(I40E_AQC_SET_RSS_LUT_TABLE_TYPE_MASK,
+ I40E_AQC_SET_RSS_LUT_TABLE_TYPE_VSI);
+ cmd_resp->flags = cpu_to_le16(flags);
status = i40e_asq_send_command(hw, &desc, lut, lut_size, NULL);
return status;
@@ -346,11 +343,9 @@ static int i40e_aq_get_set_rss_key(struct i40e_hw *hw,
desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
- cmd_resp->vsi_id =
- cpu_to_le16((u16)((vsi_id <<
- I40E_AQC_SET_RSS_KEY_VSI_ID_SHIFT) &
- I40E_AQC_SET_RSS_KEY_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)I40E_AQC_SET_RSS_KEY_VSI_VALID);
+ vsi_id = FIELD_PREP(I40E_AQC_SET_RSS_KEY_VSI_ID_MASK, vsi_id) |
+ FIELD_PREP(I40E_AQC_SET_RSS_KEY_VSI_VALID, 1);
+ cmd_resp->vsi_id = cpu_to_le16(vsi_id);
status = i40e_asq_send_command(hw, &desc, key, key_size, NULL);
@@ -669,11 +664,11 @@ int i40e_init_shared_code(struct i40e_hw *hw)
hw->phy.get_link_info = true;
/* Determine port number and PF number*/
- port = (rd32(hw, I40E_PFGEN_PORTNUM) & I40E_PFGEN_PORTNUM_PORT_NUM_MASK)
- >> I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT;
+ port = FIELD_GET(I40E_PFGEN_PORTNUM_PORT_NUM_MASK,
+ rd32(hw, I40E_PFGEN_PORTNUM));
hw->port = (u8)port;
- ari = (rd32(hw, I40E_GLPCI_CAPSUP) & I40E_GLPCI_CAPSUP_ARI_EN_MASK) >>
- I40E_GLPCI_CAPSUP_ARI_EN_SHIFT;
+ ari = FIELD_GET(I40E_GLPCI_CAPSUP_ARI_EN_MASK,
+ rd32(hw, I40E_GLPCI_CAPSUP));
func_rid = rd32(hw, I40E_PF_FUNC_RID);
if (ari)
hw->pf_id = (u8)(func_rid & 0xff);
@@ -991,9 +986,8 @@ int i40e_pf_reset(struct i40e_hw *hw)
* The grst delay value is in 100ms units, and we'll wait a
* couple counts longer to be sure we don't just miss the end.
*/
- grst_del = (rd32(hw, I40E_GLGEN_RSTCTL) &
- I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
- I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
+ grst_del = FIELD_GET(I40E_GLGEN_RSTCTL_GRSTDEL_MASK,
+ rd32(hw, I40E_GLGEN_RSTCTL));
/* It can take upto 15 secs for GRST steady state.
* Bump it to 16 secs max to be safe.
@@ -1085,26 +1079,20 @@ void i40e_clear_hw(struct i40e_hw *hw)
/* get number of interrupts, queues, and VFs */
val = rd32(hw, I40E_GLPCI_CNF2);
- num_pf_int = (val & I40E_GLPCI_CNF2_MSI_X_PF_N_MASK) >>
- I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT;
- num_vf_int = (val & I40E_GLPCI_CNF2_MSI_X_VF_N_MASK) >>
- I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT;
+ num_pf_int = FIELD_GET(I40E_GLPCI_CNF2_MSI_X_PF_N_MASK, val);
+ num_vf_int = FIELD_GET(I40E_GLPCI_CNF2_MSI_X_VF_N_MASK, val);
val = rd32(hw, I40E_PFLAN_QALLOC);
- base_queue = (val & I40E_PFLAN_QALLOC_FIRSTQ_MASK) >>
- I40E_PFLAN_QALLOC_FIRSTQ_SHIFT;
- j = (val & I40E_PFLAN_QALLOC_LASTQ_MASK) >>
- I40E_PFLAN_QALLOC_LASTQ_SHIFT;
+ base_queue = FIELD_GET(I40E_PFLAN_QALLOC_FIRSTQ_MASK, val);
+ j = FIELD_GET(I40E_PFLAN_QALLOC_LASTQ_MASK, val);
if (val & I40E_PFLAN_QALLOC_VALID_MASK && j >= base_queue)
num_queues = (j - base_queue) + 1;
else
num_queues = 0;
val = rd32(hw, I40E_PF_VT_PFALLOC);
- i = (val & I40E_PF_VT_PFALLOC_FIRSTVF_MASK) >>
- I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT;
- j = (val & I40E_PF_VT_PFALLOC_LASTVF_MASK) >>
- I40E_PF_VT_PFALLOC_LASTVF_SHIFT;
+ i = FIELD_GET(I40E_PF_VT_PFALLOC_FIRSTVF_MASK, val);
+ j = FIELD_GET(I40E_PF_VT_PFALLOC_LASTVF_MASK, val);
if (val & I40E_PF_VT_PFALLOC_VALID_MASK && j >= i)
num_vfs = (j - i) + 1;
else
@@ -1199,8 +1187,7 @@ static u32 i40e_led_is_mine(struct i40e_hw *hw, int idx)
!hw->func_caps.led[idx])
return 0;
gpio_val = rd32(hw, I40E_GLGEN_GPIO_CTL(idx));
- port = (gpio_val & I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK) >>
- I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT;
+ port = FIELD_GET(I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK, gpio_val);
/* if PRT_NUM_NA is 1 then this LED is not port specific, OR
* if it is not our port then ignore
@@ -1244,8 +1231,7 @@ u32 i40e_led_get(struct i40e_hw *hw)
if (!gpio_val)
continue;
- mode = (gpio_val & I40E_GLGEN_GPIO_CTL_LED_MODE_MASK) >>
- I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT;
+ mode = FIELD_GET(I40E_GLGEN_GPIO_CTL_LED_MODE_MASK, gpio_val);
break;
}
@@ -1288,14 +1274,14 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink)
pin_func = I40E_PIN_FUNC_LED;
gpio_val &= ~I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK;
- gpio_val |= ((pin_func <<
- I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) &
- I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK);
+ gpio_val |=
+ FIELD_PREP(I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK,
+ pin_func);
}
gpio_val &= ~I40E_GLGEN_GPIO_CTL_LED_MODE_MASK;
/* this & is a bit of paranoia, but serves as a range check */
- gpio_val |= ((mode << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) &
- I40E_GLGEN_GPIO_CTL_LED_MODE_MASK);
+ gpio_val |= FIELD_PREP(I40E_GLGEN_GPIO_CTL_LED_MODE_MASK,
+ mode);
if (blink)
gpio_val |= BIT(I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT);
@@ -1374,8 +1360,8 @@ i40e_aq_get_phy_capabilities(struct i40e_hw *hw,
if (report_init) {
if (hw->mac.type == I40E_MAC_XL710 &&
- hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
- hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
+ i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR,
+ I40E_MINOR_VER_GET_LINK_INFO_XL710)) {
status = i40e_aq_get_link_info(hw, true, NULL, NULL);
} else {
hw->phy.phy_types = le32_to_cpu(abilities->phy_type);
@@ -1645,12 +1631,11 @@ int i40e_aq_get_link_info(struct i40e_hw *hw,
else
hw_link_info->lse_enable = false;
- if ((hw->mac.type == I40E_MAC_XL710) &&
- (hw->aq.fw_maj_ver < 4 || (hw->aq.fw_maj_ver == 4 &&
- hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE)
+ if (hw->mac.type == I40E_MAC_XL710 && i40e_is_fw_ver_lt(hw, 4, 40) &&
+ hw_link_info->phy_type == 0xE)
hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU;
- if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE &&
+ if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps) &&
hw->mac.type != I40E_MAC_X722) {
__le32 tmp;
@@ -1750,21 +1735,6 @@ int i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags,
}
/**
- * i40e_is_aq_api_ver_ge
- * @aq: pointer to AdminQ info containing HW API version to compare
- * @maj: API major value
- * @min: API minor value
- *
- * Assert whether current HW API version is greater/equal than provided.
- **/
-static bool i40e_is_aq_api_ver_ge(struct i40e_adminq_info *aq, u16 maj,
- u16 min)
-{
- return (aq->api_maj_ver > maj ||
- (aq->api_maj_ver == maj && aq->api_min_ver >= min));
-}
-
-/**
* i40e_aq_add_vsi
* @hw: pointer to the hw struct
* @vsi_ctx: pointer to a vsi context struct
@@ -1890,14 +1860,14 @@ int i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
if (set) {
flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
- if (rx_only_promisc && i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+ if (rx_only_promisc && i40e_is_aq_api_ver_ge(hw, 1, 5))
flags |= I40E_AQC_SET_VSI_PROMISC_RX_ONLY;
}
cmd->promiscuous_flags = cpu_to_le16(flags);
cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
- if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+ if (i40e_is_aq_api_ver_ge(hw, 1, 5))
cmd->valid_flags |=
cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_RX_ONLY);
@@ -2000,13 +1970,13 @@ int i40e_aq_set_vsi_uc_promisc_on_vlan(struct i40e_hw *hw,
if (enable) {
flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
- if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+ if (i40e_is_aq_api_ver_ge(hw, 1, 5))
flags |= I40E_AQC_SET_VSI_PROMISC_RX_ONLY;
}
cmd->promiscuous_flags = cpu_to_le16(flags);
cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
- if (i40e_is_aq_api_ver_ge(&hw->aq, 1, 5))
+ if (i40e_is_aq_api_ver_ge(hw, 1, 5))
cmd->valid_flags |=
cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_RX_ONLY);
cmd->seid = cpu_to_le16(seid);
@@ -2253,7 +2223,7 @@ int i40e_aq_set_switch_config(struct i40e_hw *hw,
scfg->flags = cpu_to_le16(flags);
scfg->valid_flags = cpu_to_le16(valid_flags);
scfg->mode = mode;
- if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_802_1AD, hw->caps)) {
scfg->switch_tag = cpu_to_le16(hw->switch_tag);
scfg->first_tag = cpu_to_le16(hw->first_tag);
scfg->second_tag = cpu_to_le16(hw->second_tag);
@@ -3530,8 +3500,7 @@ int i40e_aq_get_lldp_mib(struct i40e_hw *hw, u8 bridge_type,
desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
cmd->type = mib_type & I40E_AQ_LLDP_MIB_TYPE_MASK;
- cmd->type |= ((bridge_type << I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT) &
- I40E_AQ_LLDP_BRIDGE_TYPE_MASK);
+ cmd->type |= FIELD_PREP(I40E_AQ_LLDP_BRIDGE_TYPE_MASK, bridge_type);
desc.datalen = cpu_to_le16(buff_size);
@@ -3637,7 +3606,7 @@ i40e_aq_restore_lldp(struct i40e_hw *hw, u8 *setting, bool restore,
(struct i40e_aqc_lldp_restore *)&desc.params.raw;
int status;
- if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT)) {
+ if (!test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps)) {
i40e_debug(hw, I40E_DEBUG_ALL,
"Restore LLDP not supported by current FW version.\n");
return -ENODEV;
@@ -3680,7 +3649,7 @@ int i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
cmd->command |= I40E_AQ_LLDP_AGENT_SHUTDOWN;
if (persist) {
- if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT)
+ if (test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps))
cmd->command |= I40E_AQ_LLDP_AGENT_STOP_PERSIST;
else
i40e_debug(hw, I40E_DEBUG_ALL,
@@ -3713,7 +3682,7 @@ int i40e_aq_start_lldp(struct i40e_hw *hw, bool persist,
cmd->command = I40E_AQ_LLDP_AGENT_START;
if (persist) {
- if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT)
+ if (test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps))
cmd->command |= I40E_AQ_LLDP_AGENT_START_PERSIST;
else
i40e_debug(hw, I40E_DEBUG_ALL,
@@ -3741,7 +3710,7 @@ i40e_aq_set_dcb_parameters(struct i40e_hw *hw, bool dcb_enable,
(struct i40e_aqc_set_dcb_parameters *)&desc.params.raw;
int status;
- if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))
+ if (!test_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, hw->caps))
return -ENODEV;
i40e_fill_default_direct_cmd_desc(&desc,
@@ -4212,8 +4181,7 @@ i40e_validate_filter_settings(struct i40e_hw *hw,
/* FCHSIZE + FCDSIZE should not be greater than PMFCOEFMAX */
val = rd32(hw, I40E_GLHMC_FCOEFMAX);
- fcoe_fmax = (val & I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK)
- >> I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT;
+ fcoe_fmax = FIELD_GET(I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK, val);
if (fcoe_filt_size + fcoe_cntx_size > fcoe_fmax)
return -EINVAL;
@@ -4249,30 +4217,25 @@ int i40e_set_filter_control(struct i40e_hw *hw,
/* Program required PE hash buckets for the PF */
val &= ~I40E_PFQF_CTL_0_PEHSIZE_MASK;
- val |= ((u32)settings->pe_filt_num << I40E_PFQF_CTL_0_PEHSIZE_SHIFT) &
- I40E_PFQF_CTL_0_PEHSIZE_MASK;
+ val |= FIELD_PREP(I40E_PFQF_CTL_0_PEHSIZE_MASK, settings->pe_filt_num);
/* Program required PE contexts for the PF */
val &= ~I40E_PFQF_CTL_0_PEDSIZE_MASK;
- val |= ((u32)settings->pe_cntx_num << I40E_PFQF_CTL_0_PEDSIZE_SHIFT) &
- I40E_PFQF_CTL_0_PEDSIZE_MASK;
+ val |= FIELD_PREP(I40E_PFQF_CTL_0_PEDSIZE_MASK, settings->pe_cntx_num);
/* Program required FCoE hash buckets for the PF */
val &= ~I40E_PFQF_CTL_0_PFFCHSIZE_MASK;
- val |= ((u32)settings->fcoe_filt_num <<
- I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) &
- I40E_PFQF_CTL_0_PFFCHSIZE_MASK;
+ val |= FIELD_PREP(I40E_PFQF_CTL_0_PFFCHSIZE_MASK,
+ settings->fcoe_filt_num);
/* Program required FCoE DDP contexts for the PF */
val &= ~I40E_PFQF_CTL_0_PFFCDSIZE_MASK;
- val |= ((u32)settings->fcoe_cntx_num <<
- I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) &
- I40E_PFQF_CTL_0_PFFCDSIZE_MASK;
+ val |= FIELD_PREP(I40E_PFQF_CTL_0_PFFCDSIZE_MASK,
+ settings->fcoe_cntx_num);
/* Program Hash LUT size for the PF */
val &= ~I40E_PFQF_CTL_0_HASHLUTSIZE_MASK;
if (settings->hash_lut_size == I40E_HASH_LUT_SIZE_512)
hash_lut_size = 1;
- val |= (hash_lut_size << I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) &
- I40E_PFQF_CTL_0_HASHLUTSIZE_MASK;
+ val |= FIELD_PREP(I40E_PFQF_CTL_0_HASHLUTSIZE_MASK, hash_lut_size);
/* Enable FDIR, Ethertype and MACVLAN filters for PF and VFs */
if (settings->enable_fdir)
@@ -4673,8 +4636,7 @@ int i40e_read_phy_register_clause22(struct i40e_hw *hw,
"PHY: Can't write command to external PHY.\n");
} else {
command = rd32(hw, I40E_GLGEN_MSRWD(port_num));
- *value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >>
- I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT;
+ *value = FIELD_GET(I40E_GLGEN_MSRWD_MDIRDDATA_MASK, command);
}
return status;
@@ -4783,8 +4745,7 @@ int i40e_read_phy_register_clause45(struct i40e_hw *hw,
if (!status) {
command = rd32(hw, I40E_GLGEN_MSRWD(port_num));
- *value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >>
- I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT;
+ *value = FIELD_GET(I40E_GLGEN_MSRWD_MDIRDDATA_MASK, command);
} else {
i40e_debug(hw, I40E_DEBUG_PHY,
"PHY: Can't read register value from external PHY.\n");
@@ -5043,7 +5004,7 @@ static int i40e_led_get_reg(struct i40e_hw *hw, u16 led_addr,
u32 i;
*reg_val = 0;
- if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) {
status =
i40e_aq_get_phy_register(hw,
I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
@@ -5076,7 +5037,7 @@ static int i40e_led_set_reg(struct i40e_hw *hw, u16 led_addr,
int status;
u32 i;
- if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) {
status =
i40e_aq_set_phy_register(hw,
I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
@@ -5115,7 +5076,7 @@ int i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
u8 port_num;
u32 i;
- if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) {
status =
i40e_aq_get_phy_register(hw,
I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
@@ -5238,14 +5199,14 @@ int i40e_aq_rx_ctl_read_register(struct i40e_hw *hw,
**/
u32 i40e_read_rx_ctl(struct i40e_hw *hw, u32 reg_addr)
{
- bool use_register;
+ bool use_register = false;
int status = 0;
int retry = 5;
u32 val = 0;
- use_register = (((hw->aq.api_maj_ver == 1) &&
- (hw->aq.api_min_ver < 5)) ||
- (hw->mac.type == I40E_MAC_X722));
+ if (i40e_is_aq_api_ver_lt(hw, 1, 5) || hw->mac.type == I40E_MAC_X722)
+ use_register = true;
+
if (!use_register) {
do_retry:
status = i40e_aq_rx_ctl_read_register(hw, reg_addr, &val, NULL);
@@ -5300,13 +5261,13 @@ int i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
**/
void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
{
- bool use_register;
+ bool use_register = false;
int status = 0;
int retry = 5;
- use_register = (((hw->aq.api_maj_ver == 1) &&
- (hw->aq.api_min_ver < 5)) ||
- (hw->mac.type == I40E_MAC_X722));
+ if (i40e_is_aq_api_ver_lt(hw, 1, 5) || hw->mac.type == I40E_MAC_X722)
+ use_register = true;
+
if (!use_register) {
do_retry:
status = i40e_aq_rx_ctl_write_register(hw, reg_addr,
@@ -5334,16 +5295,17 @@ static void i40e_mdio_if_number_selection(struct i40e_hw *hw, bool set_mdio,
u8 mdio_num,
struct i40e_aqc_phy_register_access *cmd)
{
- if (set_mdio && cmd->phy_interface == I40E_AQ_PHY_REG_ACCESS_EXTERNAL) {
- if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED)
- cmd->cmd_flags |=
- I40E_AQ_PHY_REG_ACCESS_SET_MDIO_IF_NUMBER |
- ((mdio_num <<
- I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_SHIFT) &
- I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_MASK);
- else
- i40e_debug(hw, I40E_DEBUG_PHY,
- "MDIO I/F number selection not supported by current FW version.\n");
+ if (!set_mdio ||
+ cmd->phy_interface != I40E_AQ_PHY_REG_ACCESS_EXTERNAL)
+ return;
+
+ if (test_bit(I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED, hw->caps)) {
+ cmd->cmd_flags |=
+ I40E_AQ_PHY_REG_ACCESS_SET_MDIO_IF_NUMBER |
+ FIELD_PREP(I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_MASK,
+ mdio_num);
+ } else {
+ i40e_debug(hw, I40E_DEBUG_PHY, "MDIO I/F number selection not supported by current FW version.\n");
}
}
@@ -5928,9 +5890,8 @@ i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
u16 tnl_type;
u32 ti;
- tnl_type = (le16_to_cpu(filters[i].element.flags) &
- I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
- I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
+ tnl_type = le16_get_bits(filters[i].element.flags,
+ I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK);
/* Due to hardware eccentricities, the VNI for Geneve is shifted
* one more byte further than normally used for Tenant ID in
@@ -6022,9 +5983,8 @@ i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
u16 tnl_type;
u32 ti;
- tnl_type = (le16_to_cpu(filters[i].element.flags) &
- I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
- I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
+ tnl_type = le16_get_bits(filters[i].element.flags,
+ I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK);
/* Due to hardware eccentricities, the VNI for Geneve is shifted
* one more byte further than normally used for Tenant ID in
diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c
index 68602fc375f6..8db1eb0c1768 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2021 Intel Corporation. */
+#include <linux/bitfield.h>
+#include "i40e_adminq.h"
#include "i40e_alloc.h"
#include "i40e_dcb.h"
#include "i40e_prototype.h"
@@ -20,8 +22,7 @@ int i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
return -EINVAL;
reg = rd32(hw, I40E_PRTDCB_GENS);
- *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
- I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
+ *status = FIELD_GET(I40E_PRTDCB_GENS_DCBX_STATUS_MASK, reg);
return 0;
}
@@ -50,12 +51,9 @@ static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
* |1bit | 1bit|3 bits|3bits|
*/
etscfg = &dcbcfg->etscfg;
- etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
- I40E_IEEE_ETS_WILLING_SHIFT);
- etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
- I40E_IEEE_ETS_CBS_SHIFT);
- etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
- I40E_IEEE_ETS_MAXTC_SHIFT);
+ etscfg->willing = FIELD_GET(I40E_IEEE_ETS_WILLING_MASK, buf[offset]);
+ etscfg->cbs = FIELD_GET(I40E_IEEE_ETS_CBS_MASK, buf[offset]);
+ etscfg->maxtcs = FIELD_GET(I40E_IEEE_ETS_MAXTC_MASK, buf[offset]);
/* Move offset to Priority Assignment Table */
offset++;
@@ -69,11 +67,9 @@ static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
* -----------------------------------------
*/
for (i = 0; i < 4; i++) {
- priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
- I40E_IEEE_ETS_PRIO_1_SHIFT);
- etscfg->prioritytable[i * 2] = priority;
- priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
- I40E_IEEE_ETS_PRIO_0_SHIFT);
+ priority = FIELD_GET(I40E_IEEE_ETS_PRIO_1_MASK, buf[offset]);
+ etscfg->prioritytable[i * 2] = priority;
+ priority = FIELD_GET(I40E_IEEE_ETS_PRIO_0_MASK, buf[offset]);
etscfg->prioritytable[i * 2 + 1] = priority;
offset++;
}
@@ -124,12 +120,10 @@ static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
* -----------------------------------------
*/
for (i = 0; i < 4; i++) {
- priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
- I40E_IEEE_ETS_PRIO_1_SHIFT);
- dcbcfg->etsrec.prioritytable[i*2] = priority;
- priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
- I40E_IEEE_ETS_PRIO_0_SHIFT);
- dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
+ priority = FIELD_GET(I40E_IEEE_ETS_PRIO_1_MASK, buf[offset]);
+ dcbcfg->etsrec.prioritytable[i * 2] = priority;
+ priority = FIELD_GET(I40E_IEEE_ETS_PRIO_0_MASK, buf[offset]);
+ dcbcfg->etsrec.prioritytable[(i * 2) + 1] = priority;
offset++;
}
@@ -170,12 +164,9 @@ static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
* -----------------------------------------
* |1bit | 1bit|2 bits|4bits| 1 octet |
*/
- dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
- I40E_IEEE_PFC_WILLING_SHIFT);
- dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
- I40E_IEEE_PFC_MBC_SHIFT);
- dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
- I40E_IEEE_PFC_CAP_SHIFT);
+ dcbcfg->pfc.willing = FIELD_GET(I40E_IEEE_PFC_WILLING_MASK, buf[0]);
+ dcbcfg->pfc.mbc = FIELD_GET(I40E_IEEE_PFC_MBC_MASK, buf[0]);
+ dcbcfg->pfc.pfccap = FIELD_GET(I40E_IEEE_PFC_CAP_MASK, buf[0]);
dcbcfg->pfc.pfcenable = buf[1];
}
@@ -196,8 +187,7 @@ static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
u8 *buf;
typelength = ntohs(tlv->typelength);
- length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
- I40E_LLDP_TLV_LEN_SHIFT);
+ length = FIELD_GET(I40E_LLDP_TLV_LEN_MASK, typelength);
buf = tlv->tlvinfo;
/* The App priority table starts 5 octets after TLV header */
@@ -215,12 +205,10 @@ static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
* -----------------------------------------
*/
while (offset < length) {
- dcbcfg->app[i].priority = (u8)((buf[offset] &
- I40E_IEEE_APP_PRIO_MASK) >>
- I40E_IEEE_APP_PRIO_SHIFT);
- dcbcfg->app[i].selector = (u8)((buf[offset] &
- I40E_IEEE_APP_SEL_MASK) >>
- I40E_IEEE_APP_SEL_SHIFT);
+ dcbcfg->app[i].priority = FIELD_GET(I40E_IEEE_APP_PRIO_MASK,
+ buf[offset]);
+ dcbcfg->app[i].selector = FIELD_GET(I40E_IEEE_APP_SEL_MASK,
+ buf[offset]);
dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
buf[offset + 2];
/* Move to next app */
@@ -248,8 +236,7 @@ static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
u8 subtype;
ouisubtype = ntohl(tlv->ouisubtype);
- subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
- I40E_LLDP_TLV_SUBTYPE_SHIFT);
+ subtype = FIELD_GET(I40E_LLDP_TLV_SUBTYPE_MASK, ouisubtype);
switch (subtype) {
case I40E_IEEE_SUBTYPE_ETS_CFG:
i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
@@ -299,11 +286,9 @@ static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
* -----------------------------------------
*/
for (i = 0; i < 4; i++) {
- priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
- I40E_CEE_PGID_PRIO_1_SHIFT);
- etscfg->prioritytable[i * 2] = priority;
- priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
- I40E_CEE_PGID_PRIO_0_SHIFT);
+ priority = FIELD_GET(I40E_CEE_PGID_PRIO_1_MASK, buf[offset]);
+ etscfg->prioritytable[i * 2] = priority;
+ priority = FIELD_GET(I40E_CEE_PGID_PRIO_0_MASK, buf[offset]);
etscfg->prioritytable[i * 2 + 1] = priority;
offset++;
}
@@ -360,8 +345,7 @@ static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
u8 i;
typelength = ntohs(tlv->hdr.typelen);
- length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
- I40E_LLDP_TLV_LEN_SHIFT);
+ length = FIELD_GET(I40E_LLDP_TLV_LEN_MASK, typelength);
dcbcfg->numapps = length / sizeof(*app);
@@ -417,15 +401,13 @@ static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
u32 ouisubtype;
ouisubtype = ntohl(tlv->ouisubtype);
- subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
- I40E_LLDP_TLV_SUBTYPE_SHIFT);
+ subtype = FIELD_GET(I40E_LLDP_TLV_SUBTYPE_MASK, ouisubtype);
/* Return if not CEE DCBX */
if (subtype != I40E_CEE_DCBX_TYPE)
return;
typelength = ntohs(tlv->typelength);
- tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
- I40E_LLDP_TLV_LEN_SHIFT);
+ tlvlen = FIELD_GET(I40E_LLDP_TLV_LEN_MASK, typelength);
len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
sizeof(struct i40e_cee_ctrl_tlv);
/* Return if no CEE DCBX Feature TLVs */
@@ -435,11 +417,8 @@ static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
typelength = ntohs(sub_tlv->hdr.typelen);
- sublen = (u16)((typelength &
- I40E_LLDP_TLV_LEN_MASK) >>
- I40E_LLDP_TLV_LEN_SHIFT);
- subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
- I40E_LLDP_TLV_TYPE_SHIFT);
+ sublen = FIELD_GET(I40E_LLDP_TLV_LEN_MASK, typelength);
+ subtype = FIELD_GET(I40E_LLDP_TLV_TYPE_MASK, typelength);
switch (subtype) {
case I40E_CEE_SUBTYPE_PG_CFG:
i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
@@ -476,8 +455,7 @@ static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
u32 oui;
ouisubtype = ntohl(tlv->ouisubtype);
- oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
- I40E_LLDP_TLV_OUI_SHIFT);
+ oui = FIELD_GET(I40E_LLDP_TLV_OUI_MASK, ouisubtype);
switch (oui) {
case I40E_IEEE_8021QAZ_OUI:
i40e_parse_ieee_tlv(tlv, dcbcfg);
@@ -515,10 +493,8 @@ int i40e_lldp_to_dcb_config(u8 *lldpmib,
tlv = (struct i40e_lldp_org_tlv *)lldpmib;
while (1) {
typelength = ntohs(tlv->typelength);
- type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
- I40E_LLDP_TLV_TYPE_SHIFT);
- length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
- I40E_LLDP_TLV_LEN_SHIFT);
+ type = FIELD_GET(I40E_LLDP_TLV_TYPE_MASK, typelength);
+ length = FIELD_GET(I40E_LLDP_TLV_LEN_MASK, typelength);
offset += sizeof(typelength) + length;
/* END TLV or beyond LLDPDU size */
@@ -592,7 +568,7 @@ static void i40e_cee_to_dcb_v1_config(
{
u16 status, tlv_status = le16_to_cpu(cee_cfg->tlv_status);
u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
- u8 i, tc, err;
+ u8 i, err;
/* CEE PG data to ETS config */
dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
@@ -601,13 +577,13 @@ static void i40e_cee_to_dcb_v1_config(
* from those in the CEE Priority Group sub-TLV.
*/
for (i = 0; i < 4; i++) {
- tc = (u8)((cee_cfg->oper_prio_tc[i] &
- I40E_CEE_PGID_PRIO_0_MASK) >>
- I40E_CEE_PGID_PRIO_0_SHIFT);
- dcbcfg->etscfg.prioritytable[i * 2] = tc;
- tc = (u8)((cee_cfg->oper_prio_tc[i] &
- I40E_CEE_PGID_PRIO_1_MASK) >>
- I40E_CEE_PGID_PRIO_1_SHIFT);
+ u8 tc;
+
+ tc = FIELD_GET(I40E_CEE_PGID_PRIO_0_MASK,
+ cee_cfg->oper_prio_tc[i]);
+ dcbcfg->etscfg.prioritytable[i * 2] = tc;
+ tc = FIELD_GET(I40E_CEE_PGID_PRIO_1_MASK,
+ cee_cfg->oper_prio_tc[i]);
dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
}
@@ -629,8 +605,7 @@ static void i40e_cee_to_dcb_v1_config(
dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
- status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
- I40E_AQC_CEE_APP_STATUS_SHIFT;
+ status = FIELD_GET(I40E_AQC_CEE_APP_STATUS_MASK, tlv_status);
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
/* Add APPs if Error is False */
if (!err) {
@@ -639,22 +614,19 @@ static void i40e_cee_to_dcb_v1_config(
/* FCoE APP */
dcbcfg->app[0].priority =
- (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
- I40E_AQC_CEE_APP_FCOE_SHIFT;
+ FIELD_GET(I40E_AQC_CEE_APP_FCOE_MASK, app_prio);
dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
/* iSCSI APP */
dcbcfg->app[1].priority =
- (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
- I40E_AQC_CEE_APP_ISCSI_SHIFT;
+ FIELD_GET(I40E_AQC_CEE_APP_ISCSI_MASK, app_prio);
dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
/* FIP APP */
dcbcfg->app[2].priority =
- (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
- I40E_AQC_CEE_APP_FIP_SHIFT;
+ FIELD_GET(I40E_AQC_CEE_APP_FIP_MASK, app_prio);
dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
}
@@ -673,7 +645,7 @@ static void i40e_cee_to_dcb_config(
{
u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status);
u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
- u8 i, tc, err, sync, oper;
+ u8 i, err, sync, oper;
/* CEE PG data to ETS config */
dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
@@ -682,13 +654,13 @@ static void i40e_cee_to_dcb_config(
* from those in the CEE Priority Group sub-TLV.
*/
for (i = 0; i < 4; i++) {
- tc = (u8)((cee_cfg->oper_prio_tc[i] &
- I40E_CEE_PGID_PRIO_0_MASK) >>
- I40E_CEE_PGID_PRIO_0_SHIFT);
- dcbcfg->etscfg.prioritytable[i * 2] = tc;
- tc = (u8)((cee_cfg->oper_prio_tc[i] &
- I40E_CEE_PGID_PRIO_1_MASK) >>
- I40E_CEE_PGID_PRIO_1_SHIFT);
+ u8 tc;
+
+ tc = FIELD_GET(I40E_CEE_PGID_PRIO_0_MASK,
+ cee_cfg->oper_prio_tc[i]);
+ dcbcfg->etscfg.prioritytable[i * 2] = tc;
+ tc = FIELD_GET(I40E_CEE_PGID_PRIO_1_MASK,
+ cee_cfg->oper_prio_tc[i]);
dcbcfg->etscfg.prioritytable[i * 2 + 1] = tc;
}
@@ -711,8 +683,7 @@ static void i40e_cee_to_dcb_config(
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
i = 0;
- status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
- I40E_AQC_CEE_FCOE_STATUS_SHIFT;
+ status = FIELD_GET(I40E_AQC_CEE_FCOE_STATUS_MASK, tlv_status);
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
@@ -720,15 +691,13 @@ static void i40e_cee_to_dcb_config(
if (!err && sync && oper) {
/* FCoE APP */
dcbcfg->app[i].priority =
- (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
- I40E_AQC_CEE_APP_FCOE_SHIFT;
+ FIELD_GET(I40E_AQC_CEE_APP_FCOE_MASK, app_prio);
dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
i++;
}
- status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
- I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
+ status = FIELD_GET(I40E_AQC_CEE_ISCSI_STATUS_MASK, tlv_status);
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
@@ -736,15 +705,13 @@ static void i40e_cee_to_dcb_config(
if (!err && sync && oper) {
/* iSCSI APP */
dcbcfg->app[i].priority =
- (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
- I40E_AQC_CEE_APP_ISCSI_SHIFT;
+ FIELD_GET(I40E_AQC_CEE_APP_ISCSI_MASK, app_prio);
dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
i++;
}
- status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
- I40E_AQC_CEE_FIP_STATUS_SHIFT;
+ status = FIELD_GET(I40E_AQC_CEE_FIP_STATUS_MASK, tlv_status);
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
@@ -752,8 +719,7 @@ static void i40e_cee_to_dcb_config(
if (!err && sync && oper) {
/* FIP APP */
dcbcfg->app[i].priority =
- (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
- I40E_AQC_CEE_APP_FIP_SHIFT;
+ FIELD_GET(I40E_AQC_CEE_APP_FIP_MASK, app_prio);
dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
i++;
@@ -804,14 +770,11 @@ int i40e_get_dcb_config(struct i40e_hw *hw)
int ret = 0;
/* If Firmware version < v4.33 on X710/XL710, IEEE only */
- if ((hw->mac.type == I40E_MAC_XL710) &&
- (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
- (hw->aq.fw_maj_ver < 4)))
+ if (hw->mac.type == I40E_MAC_XL710 && i40e_is_fw_ver_lt(hw, 4, 33))
return i40e_get_ieee_dcb_config(hw);
/* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
- if ((hw->mac.type == I40E_MAC_XL710) &&
- ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
+ if (hw->mac.type == I40E_MAC_XL710 && i40e_is_fw_ver_eq(hw, 4, 33)) {
ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
sizeof(cee_v1_cfg), NULL);
if (!ret) {
@@ -877,7 +840,7 @@ int i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
return -EOPNOTSUPP;
/* Read LLDP NVM area */
- if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) {
+ if (test_bit(I40E_HW_CAP_FW_LLDP_PERSISTENT, hw->caps)) {
u8 offset = 0;
if (hw->mac.type == I40E_MAC_XL710)
@@ -1189,7 +1152,7 @@ static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
selector = dcbcfg->app[i].selector & 0x7;
buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
- buf[offset + 2] = dcbcfg->app[i].protocolid & 0xFF;
+ buf[offset + 2] = dcbcfg->app[i].protocolid & 0xFF;
/* Move to next app */
offset += 3;
i++;
@@ -1285,8 +1248,7 @@ int i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
do {
i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
typelength = ntohs(tlv->typelength);
- length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
- I40E_LLDP_TLV_LEN_SHIFT);
+ length = FIELD_GET(I40E_LLDP_TLV_LEN_MASK, typelength);
if (length)
offset += length + I40E_IEEE_TLV_HEADER_LENGTH;
/* END TLV or beyond LLDPDU size */
@@ -1321,20 +1283,16 @@ void i40e_dcb_hw_rx_fifo_config(struct i40e_hw *hw,
u32 reg = rd32(hw, I40E_PRTDCB_RETSC);
reg &= ~I40E_PRTDCB_RETSC_ETS_MODE_MASK;
- reg |= ((u32)ets_mode << I40E_PRTDCB_RETSC_ETS_MODE_SHIFT) &
- I40E_PRTDCB_RETSC_ETS_MODE_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSC_ETS_MODE_MASK, ets_mode);
reg &= ~I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK;
- reg |= ((u32)non_ets_mode << I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT) &
- I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK, non_ets_mode);
reg &= ~I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK;
- reg |= (max_exponent << I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT) &
- I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK, max_exponent);
reg &= ~I40E_PRTDCB_RETSC_LLTC_MASK;
- reg |= (lltc_map << I40E_PRTDCB_RETSC_LLTC_SHIFT) &
- I40E_PRTDCB_RETSC_LLTC_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSC_LLTC_MASK, lltc_map);
wr32(hw, I40E_PRTDCB_RETSC, reg);
}
@@ -1389,14 +1347,12 @@ void i40e_dcb_hw_rx_cmd_monitor_config(struct i40e_hw *hw,
*/
reg = rd32(hw, I40E_PRT_SWR_PM_THR);
reg &= ~I40E_PRT_SWR_PM_THR_THRESHOLD_MASK;
- reg |= (threshold << I40E_PRT_SWR_PM_THR_THRESHOLD_SHIFT) &
- I40E_PRT_SWR_PM_THR_THRESHOLD_MASK;
+ reg |= FIELD_PREP(I40E_PRT_SWR_PM_THR_THRESHOLD_MASK, threshold);
wr32(hw, I40E_PRT_SWR_PM_THR, reg);
reg = rd32(hw, I40E_PRTDCB_RPPMC);
reg &= ~I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK;
- reg |= (fifo_size << I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT) &
- I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK, fifo_size);
wr32(hw, I40E_PRTDCB_RPPMC, reg);
}
@@ -1438,19 +1394,17 @@ void i40e_dcb_hw_pfc_config(struct i40e_hw *hw,
reg &= ~I40E_PRTDCB_MFLCN_RFCE_MASK;
reg &= ~I40E_PRTDCB_MFLCN_RPFCE_MASK;
if (pfc_en) {
- reg |= BIT(I40E_PRTDCB_MFLCN_RPFCM_SHIFT) &
- I40E_PRTDCB_MFLCN_RPFCM_MASK;
- reg |= ((u32)pfc_en << I40E_PRTDCB_MFLCN_RPFCE_SHIFT) &
- I40E_PRTDCB_MFLCN_RPFCE_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_MFLCN_RPFCM_MASK, 1);
+ reg |= FIELD_PREP(I40E_PRTDCB_MFLCN_RPFCE_MASK,
+ pfc_en);
}
wr32(hw, I40E_PRTDCB_MFLCN, reg);
reg = rd32(hw, I40E_PRTDCB_FCCFG);
reg &= ~I40E_PRTDCB_FCCFG_TFCE_MASK;
if (pfc_en)
- reg |= (I40E_DCB_PFC_ENABLED <<
- I40E_PRTDCB_FCCFG_TFCE_SHIFT) &
- I40E_PRTDCB_FCCFG_TFCE_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_FCCFG_TFCE_MASK,
+ I40E_DCB_PFC_ENABLED);
wr32(hw, I40E_PRTDCB_FCCFG, reg);
/* FCTTV and FCRTV to be set by default */
@@ -1468,25 +1422,22 @@ void i40e_dcb_hw_pfc_config(struct i40e_hw *hw,
reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE);
reg &= ~I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_MASK;
- reg |= ((u32)pfc_en <<
- I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT) &
- I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_MASK;
+ reg |= FIELD_PREP(I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_MASK,
+ pfc_en);
wr32(hw, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE, reg);
reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE);
reg &= ~I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_MASK;
- reg |= ((u32)pfc_en <<
- I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT) &
- I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_MASK;
+ reg |= FIELD_PREP(I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_MASK,
+ pfc_en);
wr32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE, reg);
for (i = 0; i < I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MAX_INDEX; i++) {
reg = rd32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(i));
reg &= ~I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK;
if (pfc_en) {
- reg |= ((u32)refresh_time <<
- I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) &
- I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK;
+ reg |= FIELD_PREP(I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK,
+ refresh_time);
}
wr32(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(i), reg);
}
@@ -1498,14 +1449,12 @@ void i40e_dcb_hw_pfc_config(struct i40e_hw *hw,
reg = rd32(hw, I40E_PRTDCB_TC2PFC);
reg &= ~I40E_PRTDCB_TC2PFC_TC2PFC_MASK;
- reg |= ((u32)tc2pfc << I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT) &
- I40E_PRTDCB_TC2PFC_TC2PFC_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_TC2PFC_TC2PFC_MASK, tc2pfc);
wr32(hw, I40E_PRTDCB_TC2PFC, reg);
reg = rd32(hw, I40E_PRTDCB_RUP);
reg &= ~I40E_PRTDCB_RUP_NOVLANUP_MASK;
- reg |= ((u32)first_pfc_prio << I40E_PRTDCB_RUP_NOVLANUP_SHIFT) &
- I40E_PRTDCB_RUP_NOVLANUP_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_RUP_NOVLANUP_MASK, first_pfc_prio);
wr32(hw, I40E_PRTDCB_RUP, reg);
reg = rd32(hw, I40E_PRTDCB_TDPMC);
@@ -1537,8 +1486,7 @@ void i40e_dcb_hw_set_num_tc(struct i40e_hw *hw, u8 num_tc)
u32 reg = rd32(hw, I40E_PRTDCB_GENC);
reg &= ~I40E_PRTDCB_GENC_NUMTC_MASK;
- reg |= ((u32)num_tc << I40E_PRTDCB_GENC_NUMTC_SHIFT) &
- I40E_PRTDCB_GENC_NUMTC_MASK;
+ reg |= FIELD_PREP(I40E_PRTDCB_GENC_NUMTC_MASK, num_tc);
wr32(hw, I40E_PRTDCB_GENC, reg);
}
@@ -1552,8 +1500,7 @@ u8 i40e_dcb_hw_get_num_tc(struct i40e_hw *hw)
{
u32 reg = rd32(hw, I40E_PRTDCB_GENC);
- return (u8)((reg & I40E_PRTDCB_GENC_NUMTC_MASK) >>
- I40E_PRTDCB_GENC_NUMTC_SHIFT);
+ return FIELD_GET(I40E_PRTDCB_GENC_NUMTC_MASK, reg);
}
/**
@@ -1576,13 +1523,13 @@ void i40e_dcb_hw_rx_ets_bw_config(struct i40e_hw *hw, u8 *bw_share,
reg = rd32(hw, I40E_PRTDCB_RETSTCC(i));
reg &= ~(I40E_PRTDCB_RETSTCC_BWSHARE_MASK |
I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK |
- I40E_PRTDCB_RETSTCC_ETSTC_SHIFT);
- reg |= ((u32)bw_share[i] << I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT) &
- I40E_PRTDCB_RETSTCC_BWSHARE_MASK;
- reg |= ((u32)mode[i] << I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT) &
- I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK;
- reg |= ((u32)prio_type[i] << I40E_PRTDCB_RETSTCC_ETSTC_SHIFT) &
- I40E_PRTDCB_RETSTCC_ETSTC_MASK;
+ I40E_PRTDCB_RETSTCC_ETSTC_MASK);
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_BWSHARE_MASK,
+ bw_share[i]);
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK,
+ mode[i]);
+ reg |= FIELD_PREP(I40E_PRTDCB_RETSTCC_ETSTC_MASK,
+ prio_type[i]);
wr32(hw, I40E_PRTDCB_RETSTCC(i), reg);
}
}
@@ -1722,8 +1669,7 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val < old_val) {
reg = rd32(hw, I40E_PRTRPB_SLW);
reg &= ~I40E_PRTRPB_SLW_SLW_MASK;
- reg |= (new_val << I40E_PRTRPB_SLW_SLW_SHIFT) &
- I40E_PRTRPB_SLW_SLW_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SLW_SLW_MASK, new_val);
wr32(hw, I40E_PRTRPB_SLW, reg);
}
@@ -1736,8 +1682,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val < old_val) {
reg = rd32(hw, I40E_PRTRPB_SLT(i));
reg &= ~I40E_PRTRPB_SLT_SLT_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_SLT_SLT_TCN_SHIFT) &
- I40E_PRTRPB_SLT_SLT_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SLT_SLT_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_SLT(i), reg);
}
@@ -1746,8 +1692,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val < old_val) {
reg = rd32(hw, I40E_PRTRPB_DLW(i));
reg &= ~I40E_PRTRPB_DLW_DLW_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_DLW_DLW_TCN_SHIFT) &
- I40E_PRTRPB_DLW_DLW_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_DLW_DLW_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_DLW(i), reg);
}
}
@@ -1758,8 +1704,7 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val < old_val) {
reg = rd32(hw, I40E_PRTRPB_SHW);
reg &= ~I40E_PRTRPB_SHW_SHW_MASK;
- reg |= (new_val << I40E_PRTRPB_SHW_SHW_SHIFT) &
- I40E_PRTRPB_SHW_SHW_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SHW_SHW_MASK, new_val);
wr32(hw, I40E_PRTRPB_SHW, reg);
}
@@ -1772,8 +1717,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val < old_val) {
reg = rd32(hw, I40E_PRTRPB_SHT(i));
reg &= ~I40E_PRTRPB_SHT_SHT_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_SHT_SHT_TCN_SHIFT) &
- I40E_PRTRPB_SHT_SHT_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SHT_SHT_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_SHT(i), reg);
}
@@ -1782,8 +1727,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val < old_val) {
reg = rd32(hw, I40E_PRTRPB_DHW(i));
reg &= ~I40E_PRTRPB_DHW_DHW_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_DHW_DHW_TCN_SHIFT) &
- I40E_PRTRPB_DHW_DHW_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_DHW_DHW_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_DHW(i), reg);
}
}
@@ -1793,8 +1738,7 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
new_val = new_pb_cfg->tc_pool_size[i];
reg = rd32(hw, I40E_PRTRPB_DPS(i));
reg &= ~I40E_PRTRPB_DPS_DPS_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_DPS_DPS_TCN_SHIFT) &
- I40E_PRTRPB_DPS_DPS_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_DPS_DPS_TCN_MASK, new_val);
wr32(hw, I40E_PRTRPB_DPS(i), reg);
}
@@ -1802,8 +1746,7 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
new_val = new_pb_cfg->shared_pool_size;
reg = rd32(hw, I40E_PRTRPB_SPS);
reg &= ~I40E_PRTRPB_SPS_SPS_MASK;
- reg |= (new_val << I40E_PRTRPB_SPS_SPS_SHIFT) &
- I40E_PRTRPB_SPS_SPS_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SPS_SPS_MASK, new_val);
wr32(hw, I40E_PRTRPB_SPS, reg);
/* Program the shared pool low water mark per port if increasing */
@@ -1812,8 +1755,7 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val > old_val) {
reg = rd32(hw, I40E_PRTRPB_SLW);
reg &= ~I40E_PRTRPB_SLW_SLW_MASK;
- reg |= (new_val << I40E_PRTRPB_SLW_SLW_SHIFT) &
- I40E_PRTRPB_SLW_SLW_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SLW_SLW_MASK, new_val);
wr32(hw, I40E_PRTRPB_SLW, reg);
}
@@ -1826,8 +1768,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val > old_val) {
reg = rd32(hw, I40E_PRTRPB_SLT(i));
reg &= ~I40E_PRTRPB_SLT_SLT_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_SLT_SLT_TCN_SHIFT) &
- I40E_PRTRPB_SLT_SLT_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SLT_SLT_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_SLT(i), reg);
}
@@ -1836,8 +1778,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val > old_val) {
reg = rd32(hw, I40E_PRTRPB_DLW(i));
reg &= ~I40E_PRTRPB_DLW_DLW_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_DLW_DLW_TCN_SHIFT) &
- I40E_PRTRPB_DLW_DLW_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_DLW_DLW_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_DLW(i), reg);
}
}
@@ -1848,8 +1790,7 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val > old_val) {
reg = rd32(hw, I40E_PRTRPB_SHW);
reg &= ~I40E_PRTRPB_SHW_SHW_MASK;
- reg |= (new_val << I40E_PRTRPB_SHW_SHW_SHIFT) &
- I40E_PRTRPB_SHW_SHW_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SHW_SHW_MASK, new_val);
wr32(hw, I40E_PRTRPB_SHW, reg);
}
@@ -1862,8 +1803,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val > old_val) {
reg = rd32(hw, I40E_PRTRPB_SHT(i));
reg &= ~I40E_PRTRPB_SHT_SHT_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_SHT_SHT_TCN_SHIFT) &
- I40E_PRTRPB_SHT_SHT_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_SHT_SHT_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_SHT(i), reg);
}
@@ -1872,8 +1813,8 @@ void i40e_dcb_hw_rx_pb_config(struct i40e_hw *hw,
if (new_val > old_val) {
reg = rd32(hw, I40E_PRTRPB_DHW(i));
reg &= ~I40E_PRTRPB_DHW_DHW_TCN_MASK;
- reg |= (new_val << I40E_PRTRPB_DHW_DHW_TCN_SHIFT) &
- I40E_PRTRPB_DHW_DHW_TCN_MASK;
+ reg |= FIELD_PREP(I40E_PRTRPB_DHW_DHW_TCN_MASK,
+ new_val);
wr32(hw, I40E_PRTRPB_DHW(i), reg);
}
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.h b/drivers/net/ethernet/intel/i40e/i40e_dcb.h
index 6b60dc9b7736..d76497566e40 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_dcb.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.h
@@ -43,7 +43,7 @@
#define I40E_LLDP_TLV_SUBTYPE_SHIFT 0
#define I40E_LLDP_TLV_SUBTYPE_MASK (0xFF << I40E_LLDP_TLV_SUBTYPE_SHIFT)
#define I40E_LLDP_TLV_OUI_SHIFT 8
-#define I40E_LLDP_TLV_OUI_MASK (0xFFFFFF << I40E_LLDP_TLV_OUI_SHIFT)
+#define I40E_LLDP_TLV_OUI_MASK (0xFFFFFFU << I40E_LLDP_TLV_OUI_SHIFT)
/* Defines for IEEE ETS TLV */
#define I40E_IEEE_ETS_MAXTC_SHIFT 0
diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
index 077a95dad32c..b96a92187ab3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c
@@ -21,8 +21,7 @@ static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
u32 val;
val = rd32(hw, I40E_PRTDCB_GENC);
- *delay = (u16)((val & I40E_PRTDCB_GENC_PFCLDA_MASK) >>
- I40E_PRTDCB_GENC_PFCLDA_SHIFT);
+ *delay = FIELD_GET(I40E_PRTDCB_GENC_PFCLDA_MASK, val);
}
/**
@@ -310,8 +309,8 @@ static u8 i40e_dcbnl_getstate(struct net_device *netdev)
struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
dev_dbg(&pf->pdev->dev, "DCB state=%d\n",
- !!(pf->flags & I40E_FLAG_DCB_ENABLED));
- return !!(pf->flags & I40E_FLAG_DCB_ENABLED);
+ test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0);
+ return test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0;
}
/**
@@ -331,19 +330,19 @@ static u8 i40e_dcbnl_setstate(struct net_device *netdev, u8 state)
return ret;
dev_dbg(&pf->pdev->dev, "new state=%d current state=%d\n",
- state, (pf->flags & I40E_FLAG_DCB_ENABLED) ? 1 : 0);
+ state, test_bit(I40E_FLAG_DCB_ENA, pf->flags) ? 1 : 0);
/* Nothing to do */
- if (!state == !(pf->flags & I40E_FLAG_DCB_ENABLED))
+ if (!state == !test_bit(I40E_FLAG_DCB_ENA, pf->flags))
return ret;
if (i40e_is_sw_dcb(pf)) {
if (state) {
- pf->flags |= I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_DCB_ENA, pf->flags);
memcpy(&pf->hw.desired_dcbx_config,
&pf->hw.local_dcbx_config,
sizeof(struct i40e_dcbx_config));
} else {
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
}
} else {
/* Cannot directly manipulate FW LLDP Agent */
@@ -653,7 +652,7 @@ static u8 i40e_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
{
struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
- if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
+ if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))
return I40E_DCBNL_STATUS_ERROR;
switch (capid) {
@@ -693,7 +692,7 @@ static int i40e_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
{
struct i40e_pf *pf = i40e_netdev_to_pf(netdev);
- if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
+ if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))
return -EINVAL;
*num = I40E_MAX_TRAFFIC_CLASS;
@@ -827,15 +826,12 @@ static void i40e_dcbnl_get_perm_hw_addr(struct net_device *dev,
u8 *perm_addr)
{
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
- int i, j;
+ int i;
memset(perm_addr, 0xff, MAX_ADDR_LEN);
for (i = 0; i < dev->addr_len; i++)
perm_addr[i] = pf->hw.mac.perm_addr[i];
-
- for (j = 0; j < dev->addr_len; j++, i++)
- perm_addr[i] = pf->hw.mac.san_addr[j];
}
static const struct dcbnl_rtnl_ops dcbnl_ops = {
@@ -891,11 +887,11 @@ void i40e_dcbnl_set_all(struct i40e_vsi *vsi)
return;
/* DCB not enabled */
- if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags))
return;
/* MFP mode but not an iSCSI PF so return */
- if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(hw->func_caps.iscsi))
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(hw->func_caps.iscsi))
return;
dcbxcfg = &hw->local_dcbx_config;
@@ -1002,7 +998,7 @@ void i40e_dcbnl_flush_apps(struct i40e_pf *pf,
int i;
/* MFP mode but not an iSCSI PF so return */
- if ((pf->flags & I40E_FLAG_MFP_ENABLED) && !(pf->hw.func_caps.iscsi))
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) && !(pf->hw.func_caps.iscsi))
return;
for (i = 0; i < old_cfg->numapps; i++) {
@@ -1025,7 +1021,7 @@ void i40e_dcbnl_setup(struct i40e_vsi *vsi)
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
/* Not DCB capable */
- if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
+ if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))
return;
dev->dcbnl_ops = &dcbnl_ops;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ddp.c b/drivers/net/ethernet/intel/i40e/i40e_ddp.c
index cf25bfc5dc3f..2f53f0f53bc3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ddp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ddp.c
@@ -81,8 +81,8 @@ static int i40e_ddp_does_profile_exist(struct i40e_hw *hw,
static bool i40e_ddp_profiles_overlap(struct i40e_profile_info *new,
struct i40e_profile_info *old)
{
- unsigned int group_id_old = (u8)((old->track_id & 0x00FF0000) >> 16);
- unsigned int group_id_new = (u8)((new->track_id & 0x00FF0000) >> 16);
+ unsigned int group_id_old = FIELD_GET(0x00FF0000, old->track_id);
+ unsigned int group_id_new = FIELD_GET(0x00FF0000, new->track_id);
/* 0x00 group must be only the first */
if (group_id_new == 0)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debug.h b/drivers/net/ethernet/intel/i40e/i40e_debug.h
index 27ebc72d8bfe..e9871dfb32bd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debug.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_debug.h
@@ -37,6 +37,7 @@ struct i40e_hw;
struct device *i40e_hw_to_dev(struct i40e_hw *hw);
#define hw_dbg(hw, S, A...) dev_dbg(i40e_hw_to_dev(hw), S, ##A)
+#define hw_warn(hw, S, A...) dev_warn(i40e_hw_to_dev(hw), S, ##A)
#define i40e_debug(h, m, s, ...) \
do { \
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 999c9708def5..ef70ddbe9c2f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -147,9 +147,8 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
" state[%d] = %08lx\n",
i, vsi->state[i]);
if (vsi == pf->vsi[pf->lan_vsi])
- dev_info(&pf->pdev->dev, " MAC address: %pM SAN MAC: %pM Port MAC: %pM\n",
+ dev_info(&pf->pdev->dev, " MAC address: %pM Port MAC: %pM\n",
pf->hw.mac.addr,
- pf->hw.mac.san_addr,
pf->hw.mac.port_addr);
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
dev_info(&pf->pdev->dev,
@@ -820,8 +819,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
/* By default we are in VEPA mode, if this is the first VF/VMDq
* VSI to be added switch to VEB mode.
*/
- if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
- pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+ if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
+ set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
}
@@ -1029,9 +1028,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
"emp reset count: %d\n", pf->empr_count);
dev_info(&pf->pdev->dev,
"pf reset count: %d\n", pf->pfr_count);
- dev_info(&pf->pdev->dev,
- "pf tx sluggish count: %d\n",
- pf->tx_sluggish_count);
} else if (strncmp(&cmd_buf[5], "port", 4) == 0) {
struct i40e_aqc_query_port_ets_config_resp *bw_data;
struct i40e_dcbx_config *cfg =
diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.h b/drivers/net/ethernet/intel/i40e/i40e_diag.h
index ece3a6b9a5c6..ab20202a3da3 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_diag.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_diag.h
@@ -4,6 +4,7 @@
#ifndef _I40E_DIAG_H_
#define _I40E_DIAG_H_
+#include <linux/types.h>
#include "i40e_adminq_cmd.h"
/* forward-declare the HW struct for the compiler */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index fd7163128c4d..c841779713f6 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -430,35 +430,35 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = {
struct i40e_priv_flags {
char flag_string[ETH_GSTRING_LEN];
- u64 flag;
+ u8 bitno;
bool read_only;
};
-#define I40E_PRIV_FLAG(_name, _flag, _read_only) { \
+#define I40E_PRIV_FLAG(_name, _bitno, _read_only) { \
.flag_string = _name, \
- .flag = _flag, \
+ .bitno = _bitno, \
.read_only = _read_only, \
}
static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = {
/* NOTE: MFP setting cannot be changed */
- I40E_PRIV_FLAG("MFP", I40E_FLAG_MFP_ENABLED, 1),
+ I40E_PRIV_FLAG("MFP", I40E_FLAG_MFP_ENA, 1),
I40E_PRIV_FLAG("total-port-shutdown",
- I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED, 1),
- I40E_PRIV_FLAG("LinkPolling", I40E_FLAG_LINK_POLLING_ENABLED, 0),
- I40E_PRIV_FLAG("flow-director-atr", I40E_FLAG_FD_ATR_ENABLED, 0),
- I40E_PRIV_FLAG("veb-stats", I40E_FLAG_VEB_STATS_ENABLED, 0),
- I40E_PRIV_FLAG("hw-atr-eviction", I40E_FLAG_HW_ATR_EVICT_ENABLED, 0),
+ I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, 1),
+ I40E_PRIV_FLAG("LinkPolling", I40E_FLAG_LINK_POLLING_ENA, 0),
+ I40E_PRIV_FLAG("flow-director-atr", I40E_FLAG_FD_ATR_ENA, 0),
+ I40E_PRIV_FLAG("veb-stats", I40E_FLAG_VEB_STATS_ENA, 0),
+ I40E_PRIV_FLAG("hw-atr-eviction", I40E_FLAG_HW_ATR_EVICT_ENA, 0),
I40E_PRIV_FLAG("link-down-on-close",
- I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED, 0),
- I40E_PRIV_FLAG("legacy-rx", I40E_FLAG_LEGACY_RX, 0),
+ I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, 0),
+ I40E_PRIV_FLAG("legacy-rx", I40E_FLAG_LEGACY_RX_ENA, 0),
I40E_PRIV_FLAG("disable-source-pruning",
- I40E_FLAG_SOURCE_PRUNING_DISABLED, 0),
- I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_DISABLE_FW_LLDP, 0),
+ I40E_FLAG_SOURCE_PRUNING_DIS, 0),
+ I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_FW_LLDP_DIS, 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),
+ I40E_FLAG_VF_VLAN_PRUNING_ENA, 0),
};
#define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags)
@@ -466,7 +466,7 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = {
/* Private flags with a global effect, restricted to PF 0 */
static const struct i40e_priv_flags i40e_gl_gstrings_priv_flags[] = {
I40E_PRIV_FLAG("vf-true-promisc-support",
- I40E_FLAG_TRUE_PROMISC_SUPPORT, 0),
+ I40E_FLAG_TRUE_PROMISC_ENA, 0),
};
#define I40E_GL_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gl_gstrings_priv_flags)
@@ -502,7 +502,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf,
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
1000baseT_Full);
- if (pf->hw_features & I40E_HW_100M_SGMII_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_100M_SGMII, pf->hw.caps)) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100baseT_Full);
ethtool_link_ksettings_add_link_mode(ks, advertising,
@@ -601,7 +601,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf,
10000baseKX4_Full);
}
if (phy_types & I40E_CAP_PHY_TYPE_10GBASE_KR &&
- !(pf->hw_features & I40E_HW_HAVE_CRT_RETIMER)) {
+ !test_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps)) {
ethtool_link_ksettings_add_link_mode(ks, supported,
10000baseKR_Full);
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_10GB)
@@ -609,7 +609,7 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf,
10000baseKR_Full);
}
if (phy_types & I40E_CAP_PHY_TYPE_1000BASE_KX &&
- !(pf->hw_features & I40E_HW_HAVE_CRT_RETIMER)) {
+ !test_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps)) {
ethtool_link_ksettings_add_link_mode(ks, supported,
1000baseKX_Full);
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
@@ -917,7 +917,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
if (hw_link_info->requested_speeds & I40E_LINK_SPEED_1GB)
ethtool_link_ksettings_add_link_mode(ks, advertising,
1000baseT_Full);
- if (pf->hw_features & I40E_HW_100M_SGMII_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_100M_SGMII, pf->hw.caps)) {
ethtool_link_ksettings_add_link_mode(ks, supported,
100baseT_Full);
if (hw_link_info->requested_speeds &
@@ -1488,12 +1488,8 @@ static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg)
struct i40e_pf *pf = np->vsi->back;
struct i40e_hw *hw = &pf->hw;
int status = 0;
- u32 flags = 0;
int err = 0;
- flags = READ_ONCE(pf->flags);
- i40e_set_fec_in_flags(fec_cfg, &flags);
-
/* Get the current phy config */
memset(&abilities, 0, sizeof(abilities));
status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
@@ -1525,7 +1521,7 @@ static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg)
err = -EAGAIN;
goto done;
}
- pf->flags = flags;
+ i40e_set_fec_in_flags(fec_cfg, pf->flags);
status = i40e_update_link_info(hw);
if (status)
/* debug level message only due to relation to the link
@@ -1599,7 +1595,7 @@ static int i40e_set_fec_param(struct net_device *netdev,
return -EPERM;
if (hw->mac.type == I40E_MAC_X722 &&
- !(hw->flags & I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE)) {
+ !test_bit(I40E_HW_CAP_X722_FEC_REQUEST, hw->caps)) {
netdev_err(netdev, "Setting FEC encoding not supported by firmware. Please update the NVM image.\n");
return -EOPNOTSUPP;
}
@@ -1915,7 +1911,7 @@ static int i40e_get_eeprom(struct net_device *netdev,
len = eeprom->len - (I40E_NVM_SECTOR_SIZE * i);
last = true;
}
- offset = eeprom->offset + (I40E_NVM_SECTOR_SIZE * i),
+ offset = eeprom->offset + (I40E_NVM_SECTOR_SIZE * i);
ret_val = i40e_aq_read_nvm(hw, 0x0, offset, len,
(u8 *)eeprom_buff + (I40E_NVM_SECTOR_SIZE * i),
last, NULL);
@@ -1956,9 +1952,8 @@ static int i40e_get_eeprom_len(struct net_device *netdev)
val = X722_EEPROM_SCOPE_LIMIT + 1;
return val;
}
- val = (rd32(hw, I40E_GLPCI_LBARCTRL)
- & I40E_GLPCI_LBARCTRL_FL_SIZE_MASK)
- >> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT;
+ val = FIELD_GET(I40E_GLPCI_LBARCTRL_FL_SIZE_MASK,
+ rd32(hw, I40E_GLPCI_LBARCTRL));
/* register returns value in power of 2, 64Kbyte chunks. */
val = (64 * 1024) * BIT(val);
return val;
@@ -2015,6 +2010,18 @@ static void i40e_get_drvinfo(struct net_device *netdev,
drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN;
}
+static u32 i40e_get_max_num_descriptors(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+
+ switch (hw->mac.type) {
+ case I40E_MAC_XL710:
+ return I40E_MAX_NUM_DESCRIPTORS_XL710;
+ default:
+ return I40E_MAX_NUM_DESCRIPTORS;
+ }
+}
+
static void i40e_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -2024,8 +2031,8 @@ static void i40e_get_ringparam(struct net_device *netdev,
struct i40e_pf *pf = np->vsi->back;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
- ring->rx_max_pending = I40E_MAX_NUM_DESCRIPTORS;
- ring->tx_max_pending = I40E_MAX_NUM_DESCRIPTORS;
+ ring->rx_max_pending = i40e_get_max_num_descriptors(pf);
+ ring->tx_max_pending = i40e_get_max_num_descriptors(pf);
ring->rx_mini_max_pending = 0;
ring->rx_jumbo_max_pending = 0;
ring->rx_pending = vsi->rx_rings[0]->count;
@@ -2050,12 +2057,12 @@ static int i40e_set_ringparam(struct net_device *netdev,
struct kernel_ethtool_ringparam *kernel_ring,
struct netlink_ext_ack *extack)
{
+ u32 new_rx_count, new_tx_count, max_num_descriptors;
struct i40e_ring *tx_rings = NULL, *rx_rings = NULL;
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_hw *hw = &np->vsi->back->hw;
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
- u32 new_rx_count, new_tx_count;
u16 tx_alloc_queue_pairs;
int timeout = 50;
int i, err = 0;
@@ -2063,14 +2070,15 @@ static int i40e_set_ringparam(struct net_device *netdev,
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
- if (ring->tx_pending > I40E_MAX_NUM_DESCRIPTORS ||
+ max_num_descriptors = i40e_get_max_num_descriptors(pf);
+ if (ring->tx_pending > max_num_descriptors ||
ring->tx_pending < I40E_MIN_NUM_DESCRIPTORS ||
- ring->rx_pending > I40E_MAX_NUM_DESCRIPTORS ||
+ ring->rx_pending > max_num_descriptors ||
ring->rx_pending < I40E_MIN_NUM_DESCRIPTORS) {
netdev_info(netdev,
"Descriptors requested (Tx: %d / Rx: %d) out of range [%d-%d]\n",
ring->tx_pending, ring->rx_pending,
- I40E_MIN_NUM_DESCRIPTORS, I40E_MAX_NUM_DESCRIPTORS);
+ I40E_MIN_NUM_DESCRIPTORS, max_num_descriptors);
return -EINVAL;
}
@@ -2419,7 +2427,7 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
veb_stats = ((pf->lan_veb != I40E_NO_VEB) &&
(pf->lan_veb < I40E_MAX_VEB) &&
- (pf->flags & I40E_FLAG_VEB_STATS_ENABLED));
+ test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags));
if (veb_stats) {
veb = pf->veb[pf->lan_veb];
@@ -2514,13 +2522,11 @@ static void i40e_get_priv_flag_strings(struct net_device *netdev, u8 *data)
u8 *p = data;
for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++)
- ethtool_sprintf(&p, "%s",
- i40e_gstrings_priv_flags[i].flag_string);
+ ethtool_puts(&p, i40e_gstrings_priv_flags[i].flag_string);
if (pf->hw.pf_id != 0)
return;
for (i = 0; i < I40E_GL_PRIV_FLAGS_STR_LEN; i++)
- ethtool_sprintf(&p, "%s",
- i40e_gl_gstrings_priv_flags[i].flag_string);
+ ethtool_puts(&p, i40e_gl_gstrings_priv_flags[i].flag_string);
}
static void i40e_get_strings(struct net_device *netdev, u32 stringset,
@@ -2548,7 +2554,7 @@ static int i40e_get_ts_info(struct net_device *dev,
struct i40e_pf *pf = i40e_netdev_to_pf(dev);
/* only report HW timestamping if PTP is enabled */
- if (!(pf->flags & I40E_FLAG_PTP))
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags))
return ethtool_op_get_ts_info(dev, info);
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
@@ -2570,7 +2576,7 @@ static int i40e_get_ts_info(struct net_device *dev,
BIT(HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ);
- if (pf->hw_features & I40E_HW_PTP_L4_CAPABLE)
+ if (test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps))
info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
BIT(HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
@@ -2819,10 +2825,10 @@ static int i40e_set_phys_id(struct net_device *netdev,
switch (state) {
case ETHTOOL_ID_ACTIVE:
- if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS)) {
+ if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps)) {
pf->led_status = i40e_led_get(hw);
} else {
- if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE))
+ if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps))
i40e_aq_set_phy_debug(hw, I40E_PHY_DEBUG_ALL,
NULL);
ret = i40e_led_get_phy(hw, &temp_status,
@@ -2831,25 +2837,25 @@ static int i40e_set_phys_id(struct net_device *netdev,
}
return blink_freq;
case ETHTOOL_ID_ON:
- if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS))
+ if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps))
i40e_led_set(hw, 0xf, false);
else
ret = i40e_led_set_phy(hw, true, pf->led_status, 0);
break;
case ETHTOOL_ID_OFF:
- if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS))
+ if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps))
i40e_led_set(hw, 0x0, false);
else
ret = i40e_led_set_phy(hw, false, pf->led_status, 0);
break;
case ETHTOOL_ID_INACTIVE:
- if (!(pf->hw_features & I40E_HW_PHY_CONTROLS_LEDS)) {
+ if (!test_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps)) {
i40e_led_set(hw, pf->led_status, false);
} else {
ret = i40e_led_set_phy(hw, false, pf->led_status,
(pf->phy_led_val |
I40E_PHY_LED_MODE_ORIG));
- if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE))
+ if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps))
i40e_aq_set_phy_debug(hw, 0, NULL);
}
break;
@@ -2886,7 +2892,6 @@ static int __i40e_get_coalesce(struct net_device *netdev,
struct i40e_vsi *vsi = np->vsi;
ec->tx_max_coalesced_frames_irq = vsi->work_limit;
- ec->rx_max_coalesced_frames_irq = vsi->work_limit;
/* rx and tx usecs has per queue value. If user doesn't specify the
* queue, return queue 0's value to represent.
@@ -3020,7 +3025,7 @@ static int __i40e_set_coalesce(struct net_device *netdev,
struct i40e_pf *pf = vsi->back;
int i;
- if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
+ if (ec->tx_max_coalesced_frames_irq)
vsi->work_limit = ec->tx_max_coalesced_frames_irq;
if (queue < 0) {
@@ -3278,7 +3283,7 @@ static int i40e_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
} else if (valid) {
data->flex_word = value & I40E_USERDEF_FLEX_WORD;
data->flex_offset =
- (value & I40E_USERDEF_FLEX_OFFSET) >> 16;
+ FIELD_GET(I40E_USERDEF_FLEX_OFFSET, value);
data->flex_filter = true;
}
@@ -3628,7 +3633,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
bitmap_zero(flow_pctypes, FLOW_PCTYPES_SIZE);
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
dev_err(&pf->pdev->dev,
"Change of RSS hash input set is not supported when MFP mode is enabled\n");
return -EOPNOTSUPP;
@@ -3644,19 +3649,22 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
switch (nfc->flow_type) {
case TCP_V4_FLOW:
set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP, flow_pctypes);
- if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
+ if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE,
+ pf->hw.caps))
set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK,
flow_pctypes);
break;
case TCP_V6_FLOW:
set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP, flow_pctypes);
- if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE)
+ if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE,
+ pf->hw.caps))
set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK,
flow_pctypes);
break;
case UDP_V4_FLOW:
set_bit(I40E_FILTER_PCTYPE_NONF_IPV4_UDP, flow_pctypes);
- if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+ if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE,
+ pf->hw.caps)) {
set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP,
flow_pctypes);
set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP,
@@ -3666,7 +3674,8 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
break;
case UDP_V6_FLOW:
set_bit(I40E_FILTER_PCTYPE_NONF_IPV6_UDP, flow_pctypes);
- if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+ if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE,
+ pf->hw.caps)) {
set_bit(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP,
flow_pctypes);
set_bit(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP,
@@ -4644,7 +4653,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
* main port cannot change them when in MFP mode as this would impact
* any filters on the other ports.
*/
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
netif_err(pf, drv, vsi->netdev, "Cannot change Flow Director input sets while MFP is enabled\n");
return -EOPNOTSUPP;
}
@@ -4804,7 +4813,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
return -EINVAL;
pf = vsi->back;
- if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags))
return -EOPNOTSUPP;
if (test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state))
@@ -5001,7 +5010,7 @@ static void i40e_get_channels(struct net_device *dev,
ch->max_combined = i40e_max_channels(vsi);
/* report info for other vector */
- ch->other_count = (pf->flags & I40E_FLAG_FD_SB_ENABLED) ? 1 : 0;
+ ch->other_count = test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) ? 1 : 0;
ch->max_other = ch->other_count;
/* Note: This code assumes DCB is disabled for now. */
@@ -5044,7 +5053,7 @@ static int i40e_set_channels(struct net_device *dev,
return -EINVAL;
/* verify other_count has not changed */
- if (ch->other_count != ((pf->flags & I40E_FLAG_FD_SB_ENABLED) ? 1 : 0))
+ if (ch->other_count != (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) ? 1 : 0))
return -EINVAL;
/* verify the number of channels does not exceed hardware limits */
@@ -5109,15 +5118,13 @@ static u32 i40e_get_rxfh_indir_size(struct net_device *netdev)
/**
* i40e_get_rxfh - get the rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function
+ * @rxfh: pointer to param struct (indir, key, hfunc)
*
* Reads the indirection table directly from the hardware. Returns 0 on
* success.
**/
-static int i40e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int i40e_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
@@ -5125,13 +5132,12 @@ static int i40e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
int ret;
u16 i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
- seed = key;
+ seed = rxfh->key;
lut = kzalloc(I40E_HLUT_ARRAY_SIZE, GFP_KERNEL);
if (!lut)
return -ENOMEM;
@@ -5139,7 +5145,7 @@ static int i40e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
if (ret)
goto out;
for (i = 0; i < I40E_HLUT_ARRAY_SIZE; i++)
- indir[i] = (u32)(lut[i]);
+ rxfh->indir[i] = (u32)(lut[i]);
out:
kfree(lut);
@@ -5150,15 +5156,15 @@ out:
/**
* i40e_set_rxfh - set the rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function to use
+ * @rxfh: pointer to param struct (indir, key, hfunc)
+ * @extack: extended ACK from the Netlink message
*
* Returns -EINVAL if the table specifies an invalid queue id, otherwise
* returns 0 after programming the table.
**/
-static int i40e_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int i40e_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi;
@@ -5166,17 +5172,18 @@ static int i40e_set_rxfh(struct net_device *netdev, const u32 *indir,
u8 *seed = NULL;
u16 i;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (key) {
+ if (rxfh->key) {
if (!vsi->rss_hkey_user) {
vsi->rss_hkey_user = kzalloc(I40E_HKEY_ARRAY_SIZE,
GFP_KERNEL);
if (!vsi->rss_hkey_user)
return -ENOMEM;
}
- memcpy(vsi->rss_hkey_user, key, I40E_HKEY_ARRAY_SIZE);
+ memcpy(vsi->rss_hkey_user, rxfh->key, I40E_HKEY_ARRAY_SIZE);
seed = vsi->rss_hkey_user;
}
if (!vsi->rss_lut_user) {
@@ -5186,9 +5193,9 @@ static int i40e_set_rxfh(struct net_device *netdev, const u32 *indir,
}
/* Each 32 bits pointed by 'indir' is stored with a lut entry */
- if (indir)
+ if (rxfh->indir)
for (i = 0; i < I40E_HLUT_ARRAY_SIZE; i++)
- vsi->rss_lut_user[i] = (u8)(indir[i]);
+ vsi->rss_lut_user[i] = (u8)(rxfh->indir[i]);
else
i40e_fill_rss_lut(pf, vsi->rss_lut_user, I40E_HLUT_ARRAY_SIZE,
vsi->rss_size);
@@ -5215,11 +5222,11 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
u32 i, j, ret_flags = 0;
for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) {
- const struct i40e_priv_flags *priv_flags;
+ const struct i40e_priv_flags *priv_flag;
- priv_flags = &i40e_gstrings_priv_flags[i];
+ priv_flag = &i40e_gstrings_priv_flags[i];
- if (priv_flags->flag & pf->flags)
+ if (test_bit(priv_flag->bitno, pf->flags))
ret_flags |= BIT(i);
}
@@ -5227,11 +5234,11 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
return ret_flags;
for (j = 0; j < I40E_GL_PRIV_FLAGS_STR_LEN; j++) {
- const struct i40e_priv_flags *priv_flags;
+ const struct i40e_priv_flags *priv_flag;
- priv_flags = &i40e_gl_gstrings_priv_flags[j];
+ priv_flag = &i40e_gl_gstrings_priv_flags[j];
- if (priv_flags->flag & pf->flags)
+ if (test_bit(priv_flag->bitno, pf->flags))
ret_flags |= BIT(i + j);
}
@@ -5245,8 +5252,10 @@ static u32 i40e_get_priv_flags(struct net_device *dev)
**/
static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
{
+ DECLARE_BITMAP(changed_flags, I40E_PF_FLAGS_NBITS);
+ DECLARE_BITMAP(orig_flags, I40E_PF_FLAGS_NBITS);
+ DECLARE_BITMAP(new_flags, I40E_PF_FLAGS_NBITS);
struct i40e_netdev_priv *np = netdev_priv(dev);
- u64 orig_flags, new_flags, changed_flags;
enum i40e_admin_queue_err adq_err;
struct i40e_vsi *vsi = np->vsi;
struct i40e_pf *pf = vsi->back;
@@ -5254,51 +5263,57 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
int status;
u32 i, j;
- orig_flags = READ_ONCE(pf->flags);
- new_flags = orig_flags;
+ bitmap_copy(orig_flags, pf->flags, I40E_PF_FLAGS_NBITS);
+ bitmap_copy(new_flags, pf->flags, I40E_PF_FLAGS_NBITS);
for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) {
- const struct i40e_priv_flags *priv_flags;
-
- priv_flags = &i40e_gstrings_priv_flags[i];
+ const struct i40e_priv_flags *priv_flag;
+ bool new_val;
- if (flags & BIT(i))
- new_flags |= priv_flags->flag;
- else
- new_flags &= ~(priv_flags->flag);
+ priv_flag = &i40e_gstrings_priv_flags[i];
+ new_val = (flags & BIT(i)) ? true : false;
/* If this is a read-only flag, it can't be changed */
- if (priv_flags->read_only &&
- ((orig_flags ^ new_flags) & ~BIT(i)))
+ if (priv_flag->read_only &&
+ test_bit(priv_flag->bitno, orig_flags) != new_val)
return -EOPNOTSUPP;
+
+ if (new_val)
+ set_bit(priv_flag->bitno, new_flags);
+ else
+ clear_bit(priv_flag->bitno, new_flags);
}
if (pf->hw.pf_id != 0)
goto flags_complete;
for (j = 0; j < I40E_GL_PRIV_FLAGS_STR_LEN; j++) {
- const struct i40e_priv_flags *priv_flags;
+ const struct i40e_priv_flags *priv_flag;
+ bool new_val;
- priv_flags = &i40e_gl_gstrings_priv_flags[j];
-
- if (flags & BIT(i + j))
- new_flags |= priv_flags->flag;
- else
- new_flags &= ~(priv_flags->flag);
+ priv_flag = &i40e_gl_gstrings_priv_flags[j];
+ new_val = (flags & BIT(i + j)) ? true : false;
/* If this is a read-only flag, it can't be changed */
- if (priv_flags->read_only &&
- ((orig_flags ^ new_flags) & ~BIT(i)))
+ if (priv_flag->read_only &&
+ test_bit(priv_flag->bitno, orig_flags) != new_val)
return -EOPNOTSUPP;
+
+ if (new_val)
+ set_bit(priv_flag->bitno, new_flags);
+ else
+ clear_bit(priv_flag->bitno, new_flags);
}
flags_complete:
- changed_flags = orig_flags ^ new_flags;
+ bitmap_xor(changed_flags, pf->flags, orig_flags, I40E_PF_FLAGS_NBITS);
- if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP)
+ if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags))
reset_needed = I40E_PF_RESET_AND_REBUILD_FLAG;
- if (changed_flags & (I40E_FLAG_VEB_STATS_ENABLED |
- I40E_FLAG_LEGACY_RX | I40E_FLAG_SOURCE_PRUNING_DISABLED))
+
+ if (test_bit(I40E_FLAG_VEB_STATS_ENA, changed_flags) ||
+ test_bit(I40E_FLAG_LEGACY_RX_ENA, changed_flags) ||
+ test_bit(I40E_FLAG_SOURCE_PRUNING_DIS, changed_flags))
reset_needed = BIT(__I40E_PF_RESET_REQUESTED);
/* Before we finalize any flag changes, we need to perform some
@@ -5306,8 +5321,8 @@ flags_complete:
*/
/* ATR eviction is not supported on all devices */
- if ((new_flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) &&
- !(pf->hw_features & I40E_HW_ATR_EVICT_CAPABLE))
+ if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, new_flags) &&
+ !test_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps))
return -EOPNOTSUPP;
/* If the driver detected FW LLDP was disabled on init, this flag could
@@ -5318,15 +5333,14 @@ flags_complete:
* disable LLDP, however we _must_ not allow the user to enable/disable
* LLDP with this flag on unsupported FW versions.
*/
- if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
- if (!(pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE)) {
- dev_warn(&pf->pdev->dev,
- "Device does not support changing FW LLDP\n");
- return -EOPNOTSUPP;
- }
+ if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags) &&
+ !test_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps)) {
+ dev_warn(&pf->pdev->dev,
+ "Device does not support changing FW LLDP\n");
+ return -EOPNOTSUPP;
}
- if (changed_flags & I40E_FLAG_RS_FEC &&
+ if (test_bit(I40E_FLAG_RS_FEC, changed_flags) &&
pf->hw.device_id != I40E_DEV_ID_25G_SFP28 &&
pf->hw.device_id != I40E_DEV_ID_25G_B) {
dev_warn(&pf->pdev->dev,
@@ -5334,7 +5348,7 @@ flags_complete:
return -EOPNOTSUPP;
}
- if (changed_flags & I40E_FLAG_BASE_R_FEC &&
+ if (test_bit(I40E_FLAG_BASE_R_FEC, changed_flags) &&
pf->hw.device_id != I40E_DEV_ID_25G_SFP28 &&
pf->hw.device_id != I40E_DEV_ID_25G_B &&
pf->hw.device_id != I40E_DEV_ID_KX_X722) {
@@ -5349,17 +5363,17 @@ flags_complete:
*/
/* Flush current ATR settings if ATR was disabled */
- if ((changed_flags & I40E_FLAG_FD_ATR_ENABLED) &&
- !(new_flags & I40E_FLAG_FD_ATR_ENABLED)) {
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, changed_flags) &&
+ !test_bit(I40E_FLAG_FD_ATR_ENA, new_flags)) {
set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
set_bit(__I40E_FD_FLUSH_REQUESTED, pf->state);
}
- if (changed_flags & I40E_FLAG_TRUE_PROMISC_SUPPORT) {
+ if (test_bit(I40E_FLAG_TRUE_PROMISC_ENA, changed_flags)) {
u16 sw_flags = 0, valid_flags = 0;
int ret;
- if (!(new_flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
+ if (!test_bit(I40E_FLAG_TRUE_PROMISC_ENA, new_flags))
sw_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
ret = i40e_aq_set_switch_config(&pf->hw, sw_flags, valid_flags,
@@ -5374,17 +5388,17 @@ flags_complete:
}
}
- if ((changed_flags & I40E_FLAG_RS_FEC) ||
- (changed_flags & I40E_FLAG_BASE_R_FEC)) {
+ if (test_bit(I40E_FLAG_RS_FEC, changed_flags) ||
+ test_bit(I40E_FLAG_BASE_R_FEC, changed_flags)) {
u8 fec_cfg = 0;
- if (new_flags & I40E_FLAG_RS_FEC &&
- new_flags & I40E_FLAG_BASE_R_FEC) {
+ if (test_bit(I40E_FLAG_RS_FEC, new_flags) &&
+ test_bit(I40E_FLAG_BASE_R_FEC, new_flags)) {
fec_cfg = I40E_AQ_SET_FEC_AUTO;
- } else if (new_flags & I40E_FLAG_RS_FEC) {
+ } else if (test_bit(I40E_FLAG_RS_FEC, new_flags)) {
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS |
I40E_AQ_SET_FEC_ABILITY_RS);
- } else if (new_flags & I40E_FLAG_BASE_R_FEC) {
+ } else if (test_bit(I40E_FLAG_BASE_R_FEC, new_flags)) {
fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR |
I40E_AQ_SET_FEC_ABILITY_KR);
}
@@ -5392,35 +5406,35 @@ flags_complete:
dev_warn(&pf->pdev->dev, "Cannot change FEC config\n");
}
- if ((changed_flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
- (orig_flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)) {
+ if (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, changed_flags) &&
+ test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, orig_flags)) {
dev_err(&pf->pdev->dev,
"Setting link-down-on-close not supported on this port (because total-port-shutdown is enabled)\n");
return -EOPNOTSUPP;
}
- if ((changed_flags & I40E_FLAG_VF_VLAN_PRUNING) &&
+ if (test_bit(I40E_FLAG_VF_VLAN_PRUNING_ENA, changed_flags) &&
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 & I40E_FLAG_LEGACY_RX) &&
+ if (test_bit(I40E_FLAG_LEGACY_RX_ENA, changed_flags) &&
I40E_2K_TOO_SMALL_WITH_PADDING) {
dev_warn(&pf->pdev->dev,
"2k Rx buffer is too small to fit standard MTU and skb_shared_info\n");
return -EOPNOTSUPP;
}
- if ((changed_flags & new_flags &
- I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
- (new_flags & I40E_FLAG_MFP_ENABLED))
+ if (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, changed_flags) &&
+ test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, new_flags) &&
+ test_bit(I40E_FLAG_MFP_ENA, new_flags))
dev_warn(&pf->pdev->dev,
"Turning on link-down-on-close flag may affect other partitions\n");
- if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
- if (new_flags & I40E_FLAG_DISABLE_FW_LLDP) {
+ if (test_bit(I40E_FLAG_FW_LLDP_DIS, changed_flags)) {
+ if (test_bit(I40E_FLAG_FW_LLDP_DIS, new_flags)) {
#ifdef CONFIG_I40E_DCB
i40e_dcb_sw_default_config(pf);
#endif /* CONFIG_I40E_DCB */
@@ -5461,7 +5475,7 @@ flags_complete:
* initialization or (b) while holding the RTNL lock, we don't need
* anything fancy here.
*/
- pf->flags = new_flags;
+ bitmap_copy(pf->flags, new_flags, I40E_PF_FLAGS_NBITS);
/* Issue reset to cause things to take effect, as additional bits
* are added we will need to create a mask of bits requiring reset
@@ -5491,7 +5505,7 @@ static int i40e_get_module_info(struct net_device *netdev,
int status;
/* Check if firmware supports reading module EEPROM. */
- if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) {
+ if (!test_bit(I40E_HW_CAP_AQ_PHY_ACCESS, hw->caps)) {
netdev_err(vsi->netdev, "Module EEPROM memory read not supported. Please update the NVM image.\n");
return -EINVAL;
}
@@ -5571,8 +5585,8 @@ static int i40e_get_module_info(struct net_device *netdev,
modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
break;
default:
- netdev_err(vsi->netdev, "Module type unrecognized\n");
- return -EINVAL;
+ netdev_dbg(vsi->netdev, "SFP module type unrecognized or no SFP connector used.\n");
+ return -EOPNOTSUPP;
}
return 0;
}
@@ -5768,7 +5782,7 @@ static const struct ethtool_ops i40e_ethtool_recovery_mode_ops = {
static const struct ethtool_ops i40e_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
- ETHTOOL_COALESCE_MAX_FRAMES_IRQ |
+ ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ |
ETHTOOL_COALESCE_USE_ADAPTIVE |
ETHTOOL_COALESCE_RX_USECS_HIGH |
ETHTOOL_COALESCE_TX_USECS_HIGH,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index d5519af34657..89a3401d20ab 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -377,7 +377,7 @@ static void i40e_tx_timeout(struct net_device *netdev, unsigned int txqueue)
if (tx_ring) {
head = i40e_get_head(tx_ring);
/* Read interrupt register */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
val = rd32(&pf->hw,
I40E_PFINT_DYN_CTLN(tx_ring->q_vector->v_idx +
tx_ring->vsi->base_vector - 1));
@@ -1203,11 +1203,9 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
val = rd32(hw, I40E_PRTPM_EEE_STAT);
nsd->tx_lpi_status =
- (val & I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK) >>
- I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT;
+ FIELD_GET(I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK, val);
nsd->rx_lpi_status =
- (val & I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK) >>
- I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT;
+ FIELD_GET(I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK, val);
i40e_stat_update32(hw, I40E_PRTPM_TLPIC,
pf->stat_offsets_loaded,
&osd->tx_lpi_count, &nsd->tx_lpi_count);
@@ -1215,13 +1213,13 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
pf->stat_offsets_loaded,
&osd->rx_lpi_count, &nsd->rx_lpi_count);
- if (pf->flags & I40E_FLAG_FD_SB_ENABLED &&
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) &&
!test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state))
nsd->fd_sb_status = true;
else
nsd->fd_sb_status = false;
- if (pf->flags & I40E_FLAG_FD_ATR_ENABLED &&
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
!test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
nsd->fd_atr_status = true;
else
@@ -1491,7 +1489,7 @@ static s16 i40e_get_vf_new_vlan(struct i40e_vsi *vsi,
return pvid;
is_any = (trusted ||
- !(pf->flags & I40E_FLAG_VF_VLAN_PRUNING));
+ !test_bit(I40E_FLAG_VF_VLAN_PRUNING_ENA, pf->flags));
if ((vlan_filters && f->vlan == I40E_VLAN_ANY) ||
(!is_any && !vlan_filters && f->vlan == I40E_VLAN_ANY) ||
@@ -1896,7 +1894,7 @@ static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
u8 *lut;
int ret;
- if (!(pf->hw_features & I40E_HW_RSS_AQ_CAPABLE))
+ if (!test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps))
return 0;
if (!vsi->rss_size)
vsi->rss_size = min_t(int, pf->alloc_rss_size,
@@ -2051,7 +2049,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
*/
if (vsi->req_queue_pairs > 0)
vsi->num_queue_pairs = vsi->req_queue_pairs;
- else if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ else if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
vsi->num_queue_pairs = pf->num_lan_msix;
else
vsi->num_queue_pairs = 1;
@@ -2064,7 +2062,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
else
num_tc_qps = vsi->alloc_queue_pairs;
- if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
+ if (enabled_tc && test_bit(I40E_FLAG_DCB_ENA, vsi->back->flags)) {
/* Find numtc from enabled TC bitmap */
for (i = 0, numtc = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (enabled_tc & BIT(i)) /* TC is enabled */
@@ -2083,7 +2081,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
/* Do not allow use more TC queue pairs than MSI-X vectors exist */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
num_tc_qps = min_t(int, num_tc_qps, pf->num_lan_msix);
/* Setup queue offset/count for all TCs for given VSI */
@@ -2095,8 +2093,10 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
switch (vsi->type) {
case I40E_VSI_MAIN:
- if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED |
- I40E_FLAG_FD_ATR_ENABLED)) ||
+ if ((!test_bit(I40E_FLAG_FD_SB_ENA,
+ pf->flags) &&
+ !test_bit(I40E_FLAG_FD_ATR_ENA,
+ pf->flags)) ||
vsi->tc_config.enabled_tc != 1) {
qcount = min_t(int, pf->alloc_rss_size,
num_tc_qps);
@@ -2482,7 +2482,7 @@ static int i40e_set_promiscuous(struct i40e_pf *pf, bool promisc)
if (vsi->type == I40E_VSI_MAIN &&
pf->lan_veb != I40E_NO_VEB &&
- !(pf->flags & I40E_FLAG_MFP_ENABLED)) {
+ !test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
/* set defport ON for Main VSI instead of true promisc
* this way we will get all unicast/multicast and VLAN
* promisc behavior but will not get VF or VMDq traffic
@@ -2913,7 +2913,7 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
*/
static u16 i40e_calculate_vsi_rx_buf_len(struct i40e_vsi *vsi)
{
- if (!vsi->netdev || (vsi->back->flags & I40E_FLAG_LEGACY_RX))
+ if (!vsi->netdev || test_bit(I40E_FLAG_LEGACY_RX_ENA, vsi->back->flags))
return SKB_WITH_OVERHEAD(I40E_RXBUFFER_2048);
return PAGE_SIZE < 8192 ? I40E_RXBUFFER_3072 : I40E_RXBUFFER_2048;
@@ -3468,8 +3468,8 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
ring->xsk_pool = i40e_xsk_pool(ring);
/* some ATR related tx ring init */
- if (vsi->back->flags & I40E_FLAG_FD_ATR_ENABLED) {
- ring->atr_sample_rate = vsi->back->atr_sample_rate;
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, vsi->back->flags)) {
+ ring->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
ring->atr_count = 0;
} else {
ring->atr_sample_rate = 0;
@@ -3484,9 +3484,11 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
tx_ctx.new_context = 1;
tx_ctx.base = (ring->dma / 128);
tx_ctx.qlen = ring->count;
- tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FD_SB_ENABLED |
- I40E_FLAG_FD_ATR_ENABLED));
- tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP);
+ if (test_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags) ||
+ test_bit(I40E_FLAG_FD_ATR_ENA, vsi->back->flags))
+ tx_ctx.fd_ena = 1;
+ if (test_bit(I40E_FLAG_PTP_ENA, vsi->back->flags))
+ tx_ctx.timesync_ena = 1;
/* FDIR VSI tx ring can still use RS bit and writebacks */
if (vsi->type != I40E_VSI_FDIR)
tx_ctx.head_wb_ena = 1;
@@ -3538,21 +3540,19 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
else
return -EINVAL;
- qtx_ctl |= (ring->ch->vsi_number <<
- I40E_QTX_CTL_VFVM_INDX_SHIFT) &
- I40E_QTX_CTL_VFVM_INDX_MASK;
+ qtx_ctl |= FIELD_PREP(I40E_QTX_CTL_VFVM_INDX_MASK,
+ ring->ch->vsi_number);
} else {
if (vsi->type == I40E_VSI_VMDQ2) {
qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
- qtx_ctl |= ((vsi->id) << I40E_QTX_CTL_VFVM_INDX_SHIFT) &
- I40E_QTX_CTL_VFVM_INDX_MASK;
+ qtx_ctl |= FIELD_PREP(I40E_QTX_CTL_VFVM_INDX_MASK,
+ vsi->id);
} else {
qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
}
}
- qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
- I40E_QTX_CTL_PF_INDX_MASK);
+ qtx_ctl |= FIELD_PREP(I40E_QTX_CTL_PF_INDX_MASK, hw->pf_id);
wr32(hw, I40E_QTX_CTL(pf_q), qtx_ctl);
i40e_flush(hw);
@@ -3588,40 +3588,55 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
struct i40e_hmc_obj_rxq rx_ctx;
int err = 0;
bool ok;
- int ret;
bitmap_zero(ring->state, __I40E_RING_STATE_NBITS);
/* clear the context structure first */
memset(&rx_ctx, 0, sizeof(rx_ctx));
- if (ring->vsi->type == I40E_VSI_MAIN)
- xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
+ ring->rx_buf_len = vsi->rx_buf_len;
+
+ /* XDP RX-queue info only needed for RX rings exposed to XDP */
+ if (ring->vsi->type != I40E_VSI_MAIN)
+ goto skip;
+
+ if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->queue_index,
+ ring->q_vector->napi.napi_id,
+ ring->rx_buf_len);
+ if (err)
+ return err;
+ }
ring->xsk_pool = i40e_xsk_pool(ring);
if (ring->xsk_pool) {
- ring->rx_buf_len =
- xsk_pool_get_rx_frame_size(ring->xsk_pool);
- ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
+ ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->queue_index,
+ ring->q_vector->napi.napi_id,
+ ring->rx_buf_len);
+ if (err)
+ return err;
+ err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL);
- if (ret)
- return ret;
+ if (err)
+ return err;
dev_info(&vsi->back->pdev->dev,
"Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
ring->queue_index);
} else {
- ring->rx_buf_len = vsi->rx_buf_len;
- if (ring->vsi->type == I40E_VSI_MAIN) {
- ret = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
- MEM_TYPE_PAGE_SHARED,
- NULL);
- if (ret)
- return ret;
- }
+ err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
+ MEM_TYPE_PAGE_SHARED,
+ NULL);
+ if (err)
+ return err;
}
+skip:
xdp_init_buff(&ring->xdp, i40e_rx_pg_size(ring) / 2, &ring->xdp_rxq);
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
@@ -3669,7 +3684,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
}
/* configure Rx buffer alignment */
- if (!vsi->netdev || (vsi->back->flags & I40E_FLAG_LEGACY_RX)) {
+ if (!vsi->netdev || test_bit(I40E_FLAG_LEGACY_RX_ENA, vsi->back->flags)) {
if (I40E_2K_TOO_SMALL_WITH_PADDING) {
dev_info(&vsi->back->pdev->dev,
"2k Rx buffer is too small to fit standard MTU and skb_shared_info\n");
@@ -3767,7 +3782,7 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
u16 qoffset, qcount;
int i, n;
- if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
+ if (!test_bit(I40E_FLAG_DCB_ENA, vsi->back->flags)) {
/* Reset the TC information */
for (i = 0; i < vsi->num_queue_pairs; i++) {
rx_ring = vsi->rx_rings[i];
@@ -3834,7 +3849,7 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
struct i40e_pf *pf = vsi->back;
struct hlist_node *node;
- if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags))
return;
/* Reset FDir counters as we're replaying all existing filters */
@@ -3972,10 +3987,10 @@ static void i40e_enable_misc_int_causes(struct i40e_pf *pf)
I40E_PFINT_ICR0_ENA_VFLR_MASK |
I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
- if (pf->flags & I40E_FLAG_IWARP_ENABLED)
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags))
val |= I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK;
- if (pf->flags & I40E_FLAG_PTP)
+ if (test_bit(I40E_FLAG_PTP_ENA, pf->flags))
val |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
wr32(hw, I40E_PFINT_ICR0_ENA, val);
@@ -4211,7 +4226,7 @@ static void i40e_vsi_disable_irq(struct i40e_vsi *vsi)
}
/* disable each interrupt */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
for (i = vsi->base_vector;
i < (vsi->num_q_vectors + vsi->base_vector); i++)
wr32(hw, I40E_PFINT_DYN_CTLN(i - 1), 0);
@@ -4237,7 +4252,7 @@ static int i40e_vsi_enable_irq(struct i40e_vsi *vsi)
struct i40e_pf *pf = vsi->back;
int i;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
for (i = 0; i < vsi->num_q_vectors; i++)
i40e_irq_dynamic_enable(vsi, i);
} else {
@@ -4258,7 +4273,7 @@ static void i40e_free_misc_vector(struct i40e_pf *pf)
wr32(&pf->hw, I40E_PFINT_ICR0_ENA, 0);
i40e_flush(&pf->hw);
- if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) {
free_irq(pf->msix_entries[0].vector, pf);
clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
}
@@ -4293,7 +4308,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
(icr0 & I40E_PFINT_ICR0_SWINT_MASK))
pf->sw_int_count++;
- if ((pf->flags & I40E_FLAG_IWARP_ENABLED) &&
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags) &&
(icr0 & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) {
ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK;
dev_dbg(&pf->pdev->dev, "cleared PE_CRITERR\n");
@@ -4344,8 +4359,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
set_bit(__I40E_RESET_INTR_RECEIVED, pf->state);
ena_mask &= ~I40E_PFINT_ICR0_ENA_GRST_MASK;
val = rd32(hw, I40E_GLGEN_RSTAT);
- val = (val & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
- >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
+ val = FIELD_GET(I40E_GLGEN_RSTAT_RESET_TYPE_MASK, val);
if (val == I40E_RESET_CORER) {
pf->corer_count++;
} else if (val == I40E_RESET_GLOBR) {
@@ -4486,7 +4500,7 @@ static bool i40e_clean_fdir_tx_irq(struct i40e_ring *tx_ring, int budget)
i += tx_ring->count;
tx_ring->next_to_clean = i;
- if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags))
i40e_irq_dynamic_enable(vsi, tx_ring->q_vector->v_idx);
return budget > 0;
@@ -4599,9 +4613,9 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename)
struct i40e_pf *pf = vsi->back;
int err;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
err = i40e_vsi_request_irq_msix(vsi, basename);
- else if (pf->flags & I40E_FLAG_MSI_ENABLED)
+ else if (test_bit(I40E_FLAG_MSI_ENA, pf->flags))
err = request_irq(pf->pdev->irq, i40e_intr, 0,
pf->int_name, pf);
else
@@ -4633,7 +4647,7 @@ static void i40e_netpoll(struct net_device *netdev)
if (test_bit(__I40E_VSI_DOWN, vsi->state))
return;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
for (i = 0; i < vsi->num_q_vectors; i++)
i40e_msix_clean_rings(0, vsi->q_vectors[i]);
} else {
@@ -4912,27 +4926,23 @@ int i40e_vsi_start_rings(struct i40e_vsi *vsi)
void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
- int pf_q, err, q_end;
+ u32 pf_q, tx_q_end, rx_q_end;
/* When port TX is suspended, don't wait */
if (test_bit(__I40E_PORT_SUSPENDED, vsi->back->state))
return i40e_vsi_stop_rings_no_wait(vsi);
- q_end = vsi->base_queue + vsi->num_queue_pairs;
- for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
- i40e_pre_tx_queue_cfg(&pf->hw, (u32)pf_q, false);
+ tx_q_end = vsi->base_queue +
+ vsi->alloc_queue_pairs * (i40e_enabled_xdp_vsi(vsi) ? 2 : 1);
+ for (pf_q = vsi->base_queue; pf_q < tx_q_end; pf_q++)
+ i40e_pre_tx_queue_cfg(&pf->hw, pf_q, false);
- for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++) {
- err = i40e_control_wait_rx_q(pf, pf_q, false);
- if (err)
- dev_info(&pf->pdev->dev,
- "VSI seid %d Rx ring %d disable timeout\n",
- vsi->seid, pf_q);
- }
+ rx_q_end = vsi->base_queue + vsi->num_queue_pairs;
+ for (pf_q = vsi->base_queue; pf_q < rx_q_end; pf_q++)
+ i40e_control_rx_q(pf, pf_q, false);
msleep(I40E_DISABLE_TX_GAP_MSEC);
- pf_q = vsi->base_queue;
- for (pf_q = vsi->base_queue; pf_q < q_end; pf_q++)
+ for (pf_q = vsi->base_queue; pf_q < tx_q_end; pf_q++)
wr32(&pf->hw, I40E_QTX_ENA(pf_q), 0);
i40e_vsi_wait_queues_disabled(vsi);
@@ -4973,7 +4983,7 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
u32 val, qp;
int i;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
if (!vsi->q_vectors)
return;
@@ -5007,8 +5017,8 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
* next_q field of the registers.
*/
val = rd32(hw, I40E_PFINT_LNKLSTN(vector - 1));
- qp = (val & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK)
- >> I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT;
+ qp = FIELD_GET(I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK,
+ val);
val |= I40E_QUEUE_END_OF_LIST
<< I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT;
wr32(hw, I40E_PFINT_LNKLSTN(vector - 1), val);
@@ -5030,8 +5040,8 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
val = rd32(hw, I40E_QINT_TQCTL(qp));
- next = (val & I40E_QINT_TQCTL_NEXTQ_INDX_MASK)
- >> I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT;
+ next = FIELD_GET(I40E_QINT_TQCTL_NEXTQ_INDX_MASK,
+ val);
val &= ~(I40E_QINT_TQCTL_MSIX_INDX_MASK |
I40E_QINT_TQCTL_MSIX0_INDX_MASK |
@@ -5049,8 +5059,7 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
free_irq(pf->pdev->irq, pf);
val = rd32(hw, I40E_PFINT_LNKLST0);
- qp = (val & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK)
- >> I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT;
+ qp = FIELD_GET(I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK, val);
val |= I40E_QUEUE_END_OF_LIST
<< I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT;
wr32(hw, I40E_PFINT_LNKLST0, val);
@@ -5135,16 +5144,17 @@ static void i40e_vsi_free_q_vectors(struct i40e_vsi *vsi)
static void i40e_reset_interrupt_capability(struct i40e_pf *pf)
{
/* If we're in Legacy mode, the interrupt was cleaned in vsi_close */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
pci_disable_msix(pf->pdev);
kfree(pf->msix_entries);
pf->msix_entries = NULL;
kfree(pf->irq_pile);
pf->irq_pile = NULL;
- } else if (pf->flags & I40E_FLAG_MSI_ENABLED) {
+ } else if (test_bit(I40E_FLAG_MSI_ENA, pf->flags)) {
pci_disable_msi(pf->pdev);
}
- pf->flags &= ~(I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED);
+ clear_bit(I40E_FLAG_MSI_ENA, pf->flags);
+ clear_bit(I40E_FLAG_MSIX_ENA, pf->flags);
}
/**
@@ -5346,7 +5356,7 @@ static int i40e_pf_wait_queues_disabled(struct i40e_pf *pf)
{
int v, ret = 0;
- for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+ for (v = 0; v < pf->num_alloc_vsi; v++) {
if (pf->vsi[v]) {
ret = i40e_vsi_wait_queues_disabled(pf->vsi[v]);
if (ret)
@@ -5484,11 +5494,11 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
return pf->vsi[pf->lan_vsi]->mqprio_qopt.qopt.num_tc;
/* If neither MQPRIO nor DCB is enabled, then always use single TC */
- if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags))
return 1;
/* SFP mode will be enabled for all TCs on port */
- if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+ if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags))
return i40e_dcb_get_num_tc(dcbcfg);
/* MFP mode return count of enabled TCs for this PF */
@@ -5518,11 +5528,11 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
/* If neither MQPRIO nor DCB is enabled for this PF then just return
* default TC
*/
- if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags))
return I40E_DEFAULT_TRAFFIC_CLASS;
/* SFP mode we want PF to be enabled for all TCs */
- if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+ if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags))
return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config);
/* MFP enabled and iSCSI PF type */
@@ -5611,7 +5621,7 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
/* There is no need to reset BW when mqprio mode is on. */
if (i40e_is_tc_mqprio_enabled(pf))
return 0;
- if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+ if (!vsi->mqprio_qopt.qopt.hw && !test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
ret = i40e_set_bw_limit(vsi, vsi->seid, 0);
if (ret)
dev_info(&pf->pdev->dev,
@@ -5864,7 +5874,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
}
vsi->reconfig_rss = false;
}
- if (vsi->back->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, vsi->back->flags)) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA;
@@ -6277,7 +6287,7 @@ static int i40e_add_channel(struct i40e_pf *pf, u16 uplink_seid,
if (ch->type == I40E_VSI_VMDQ2)
ctxt.flags = I40E_AQ_VSI_TYPE_VMDQ2;
- if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) {
+ if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
ctxt.info.switch_id =
@@ -6582,8 +6592,8 @@ int i40e_create_queue_channel(struct i40e_vsi *vsi,
* VSI to be added switch to VEB mode.
*/
- if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
- pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+ if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
+ set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
if (vsi->type == I40E_VSI_MAIN) {
if (i40e_is_tc_mqprio_enabled(pf))
@@ -6994,9 +7004,9 @@ int i40e_hw_dcb_config(struct i40e_pf *pf, struct i40e_dcbx_config *new_cfg)
if (need_reconfig) {
/* Enable DCB tagging only when more than one TC */
if (new_numtc > 1)
- pf->flags |= I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_DCB_ENA, pf->flags);
else
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
set_bit(__I40E_PORT_SUSPENDED, pf->state);
/* Reconfiguration needed quiesce all VSIs */
@@ -7086,7 +7096,7 @@ out:
set_bit(__I40E_CLIENT_L2_CHANGE, pf->state);
}
/* registers are set, lets apply */
- if (pf->hw_features & I40E_HW_USE_SET_LLDP_MIB)
+ if (test_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps))
ret = i40e_hw_set_dcb_config(pf, new_cfg);
}
@@ -7107,7 +7117,7 @@ int i40e_dcb_sw_default_config(struct i40e_pf *pf)
struct i40e_hw *hw = &pf->hw;
int err;
- if (pf->hw_features & I40E_HW_USE_SET_LLDP_MIB) {
+ if (test_bit(I40E_HW_CAP_USE_SET_LLDP_MIB, pf->hw.caps)) {
/* Update the local cached instance with TC0 ETS */
memset(&pf->tmp_cfg, 0, sizeof(struct i40e_dcbx_config));
pf->tmp_cfg.etscfg.willing = I40E_IEEE_DEFAULT_ETS_WILLING;
@@ -7168,12 +7178,12 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
/* Do not enable DCB for SW1 and SW2 images even if the FW is capable
* Also do not enable DCBx if FW LLDP agent is disabled
*/
- if (pf->hw_features & I40E_HW_NO_DCB_SUPPORT) {
+ if (test_bit(I40E_HW_CAP_NO_DCB_SUPPORT, pf->hw.caps)) {
dev_info(&pf->pdev->dev, "DCB is not supported.\n");
err = -EOPNOTSUPP;
goto out;
}
- if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) {
+ if (test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags)) {
dev_info(&pf->pdev->dev, "FW LLDP is disabled, attempting SW DCB\n");
err = i40e_dcb_sw_default_config(pf);
if (err) {
@@ -7184,8 +7194,8 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
pf->dcbx_cap = DCB_CAP_DCBX_HOST |
DCB_CAP_DCBX_VER_IEEE;
/* at init capable but disabled */
- pf->flags |= I40E_FLAG_DCB_CAPABLE;
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
goto out;
}
err = i40e_init_dcb(hw, true);
@@ -7200,20 +7210,20 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
pf->dcbx_cap = DCB_CAP_DCBX_LLD_MANAGED |
DCB_CAP_DCBX_VER_IEEE;
- pf->flags |= I40E_FLAG_DCB_CAPABLE;
+ set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
/* Enable DCB tagging only when more than one TC
* or explicitly disable if only one TC
*/
if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1)
- pf->flags |= I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_DCB_ENA, pf->flags);
else
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
dev_dbg(&pf->pdev->dev,
"DCBX offload is supported for this PF.\n");
}
} else if (pf->hw.aq.asq_last_status == I40E_AQ_RC_EPERM) {
dev_info(&pf->pdev->dev, "FW LLDP disabled for this PF.\n");
- pf->flags |= I40E_FLAG_DISABLE_FW_LLDP;
+ set_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags);
} else {
dev_info(&pf->pdev->dev,
"Query for DCB configuration failed, err %pe aq_err %s\n",
@@ -7373,7 +7383,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
struct i40e_pf *pf = vsi->back;
int err;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
i40e_vsi_configure_msix(vsi);
else
i40e_configure_msi_and_legacy(vsi);
@@ -7477,7 +7487,7 @@ static int i40e_force_link_state(struct i40e_pf *pf, bool is_up)
* and its speed values are OK, no need for a flap
* if non_zero_phy_type was set, still need to force up
*/
- if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)
+ if (test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags))
non_zero_phy_type = true;
else if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0)
return 0;
@@ -7493,7 +7503,7 @@ static int i40e_force_link_state(struct i40e_pf *pf, bool is_up)
non_zero_phy_type ? (u8)((mask >> 32) & 0xff) : 0;
/* Copy the old settings, except of phy_type */
config.abilities = abilities.abilities;
- if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED) {
+ if (test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags)) {
if (is_up)
config.abilities |= I40E_AQ_PHY_ENABLE_LINK;
else
@@ -7543,8 +7553,8 @@ int i40e_up(struct i40e_vsi *vsi)
int err;
if (vsi->type == I40E_VSI_MAIN &&
- (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED ||
- vsi->back->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED))
+ (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags) ||
+ test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, vsi->back->flags)))
i40e_force_link_state(vsi->back, true);
err = i40e_vsi_configure(vsi);
@@ -7572,8 +7582,8 @@ void i40e_down(struct i40e_vsi *vsi)
i40e_vsi_disable_irq(vsi);
i40e_vsi_stop_rings(vsi);
if (vsi->type == I40E_VSI_MAIN &&
- (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED ||
- vsi->back->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED))
+ (test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags) ||
+ test_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, vsi->back->flags)))
i40e_force_link_state(vsi->back, false);
i40e_napi_disable_all(vsi);
@@ -7979,7 +7989,7 @@ static void *i40e_fwd_add(struct net_device *netdev, struct net_device *vdev)
struct i40e_fwd_adapter *fwd;
int avail_macvlan, ret;
- if ((pf->flags & I40E_FLAG_DCB_ENABLED)) {
+ if (test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
netdev_info(netdev, "Macvlans are not supported when DCB is enabled\n");
return ERR_PTR(-EINVAL);
}
@@ -8174,23 +8184,23 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)
hw = mqprio_qopt->qopt.hw;
mode = mqprio_qopt->mode;
if (!hw) {
- pf->flags &= ~I40E_FLAG_TC_MQPRIO;
+ clear_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags);
memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt));
goto config_tc;
}
/* Check if MFP enabled */
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
netdev_info(netdev,
"Configuring TC not supported in MFP mode\n");
return ret;
}
switch (mode) {
case TC_MQPRIO_MODE_DCB:
- pf->flags &= ~I40E_FLAG_TC_MQPRIO;
+ clear_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags);
/* Check if DCB enabled to continue */
- if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+ if (!test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
netdev_info(netdev,
"DCB is not enabled for adapter\n");
return ret;
@@ -8204,20 +8214,20 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)
}
break;
case TC_MQPRIO_MODE_CHANNEL:
- if (pf->flags & I40E_FLAG_DCB_ENABLED) {
+ if (test_bit(I40E_FLAG_DCB_ENA, pf->flags)) {
netdev_info(netdev,
"Full offload of TC Mqprio options is not supported when DCB is enabled\n");
return ret;
}
- if (!(pf->flags & I40E_FLAG_MSIX_ENABLED))
+ if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
return ret;
ret = i40e_validate_mqprio_qopt(vsi, mqprio_qopt);
if (ret)
return ret;
memcpy(&vsi->mqprio_qopt, mqprio_qopt,
sizeof(*mqprio_qopt));
- pf->flags |= I40E_FLAG_TC_MQPRIO;
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_TC_MQPRIO_ENA, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
break;
default:
return -EINVAL;
@@ -8801,11 +8811,11 @@ static int i40e_configure_clsflower(struct i40e_vsi *vsi,
return -EINVAL;
}
- if (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags)) {
dev_err(&vsi->back->pdev->dev,
"Disable Flow Director Sideband, configuring Cloud filters via tc-flower\n");
- vsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;
- vsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
+ clear_bit(I40E_FLAG_FD_SB_ENA, vsi->back->flags);
+ clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, vsi->back->flags);
}
filter = kzalloc(sizeof(*filter), GFP_KERNEL);
@@ -8901,11 +8911,11 @@ static int i40e_delete_clsflower(struct i40e_vsi *vsi,
pf->num_cloud_filters--;
if (!pf->num_cloud_filters)
- if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
- !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
- pf->flags |= I40E_FLAG_FD_SB_ENABLED;
- pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
- pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
+ if (test_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags) &&
+ !test_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags)) {
+ set_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
}
return 0;
}
@@ -9206,11 +9216,11 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)
}
pf->num_cloud_filters = 0;
- if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
- !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
- pf->flags |= I40E_FLAG_FD_SB_ENABLED;
- pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
- pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
+ if (test_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags) &&
+ !test_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags)) {
+ set_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_TO_CLOUD_FILTER, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
}
}
@@ -9298,7 +9308,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired)
i40e_prep_for_reset(pf);
i40e_reset_and_rebuild(pf, true, lock_acquired);
dev_info(&pf->pdev->dev,
- pf->flags & I40E_FLAG_DISABLE_FW_LLDP ?
+ test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags) ?
"FW LLDP is disabled\n" :
"FW LLDP is enabled\n");
@@ -9413,12 +9423,12 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
if (I40E_IS_X710TL_DEVICE(hw->device_id) &&
(hw->phy.link_info.link_speed &
~(I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB)) &&
- !(pf->flags & I40E_FLAG_DCB_CAPABLE))
+ !test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))
/* let firmware decide if the DCB should be disabled */
- pf->flags |= I40E_FLAG_DCB_CAPABLE;
+ set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
/* Not DCB capable or capability disabled */
- if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
+ if (!test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))
return ret;
/* Ignore if event is not for Nearest Bridge */
@@ -9454,7 +9464,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
(I40E_LINK_SPEED_2_5GB | I40E_LINK_SPEED_5GB))) {
dev_warn(&pf->pdev->dev,
"DCB is not supported for X710-T*L 2.5/5G speeds\n");
- pf->flags &= ~I40E_FLAG_DCB_CAPABLE;
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
} else {
dev_info(&pf->pdev->dev,
"Failed querying DCB configuration data from firmware, err %pe aq_err %s\n",
@@ -9482,9 +9492,9 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
/* Enable DCB tagging only when more than one TC */
if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1)
- pf->flags |= I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_DCB_ENA, pf->flags);
else
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
set_bit(__I40E_PORT_SUSPENDED, pf->state);
/* Reconfiguration needed quiesce all VSIs */
@@ -9552,18 +9562,18 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
dev_dbg(&pf->pdev->dev, "overflow Rx Queue Number = %d QTX_CTL=0x%08x\n",
queue, qtx_ctl);
+ if (FIELD_GET(I40E_QTX_CTL_PFVF_Q_MASK, qtx_ctl) !=
+ I40E_QTX_CTL_VF_QUEUE)
+ return;
+
/* Queue belongs to VF, find the VF and issue VF reset */
- if (((qtx_ctl & I40E_QTX_CTL_PFVF_Q_MASK)
- >> I40E_QTX_CTL_PFVF_Q_SHIFT) == I40E_QTX_CTL_VF_QUEUE) {
- vf_id = (u16)((qtx_ctl & I40E_QTX_CTL_VFVM_INDX_MASK)
- >> I40E_QTX_CTL_VFVM_INDX_SHIFT);
- vf_id -= hw->func_caps.vf_base_id;
- vf = &pf->vf[vf_id];
- i40e_vc_notify_vf_reset(vf);
- /* Allow VF to process pending reset notification */
- msleep(20);
- i40e_reset_vf(vf, false);
- }
+ vf_id = FIELD_GET(I40E_QTX_CTL_VFVM_INDX_MASK, qtx_ctl);
+ vf_id -= hw->func_caps.vf_base_id;
+ vf = &pf->vf[vf_id];
+ i40e_vc_notify_vf_reset(vf);
+ /* Allow VF to process pending reset notification */
+ msleep(20);
+ i40e_reset_vf(vf, false);
}
/**
@@ -9589,8 +9599,7 @@ u32 i40e_get_current_fd_count(struct i40e_pf *pf)
val = rd32(&pf->hw, I40E_PFQF_FDSTAT);
fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) +
- ((val & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
- I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
+ FIELD_GET(I40E_PFQF_FDSTAT_BEST_CNT_MASK, val);
return fcnt_prog;
}
@@ -9604,8 +9613,7 @@ u32 i40e_get_global_fd_count(struct i40e_pf *pf)
val = rd32(&pf->hw, I40E_GLQF_FDCNT_0);
fcnt_prog = (val & I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK) +
- ((val & I40E_GLQF_FDCNT_0_BESTCNT_MASK) >>
- I40E_GLQF_FDCNT_0_BESTCNT_SHIFT);
+ FIELD_GET(I40E_GLQF_FDCNT_0_BESTCNT_MASK, val);
return fcnt_prog;
}
@@ -9616,7 +9624,7 @@ u32 i40e_get_global_fd_count(struct i40e_pf *pf)
static void i40e_reenable_fdir_sb(struct i40e_pf *pf)
{
if (test_and_clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state))
- if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) &&
(I40E_DEBUG_FD & pf->hw.debug_mask))
dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
}
@@ -9637,7 +9645,7 @@ static void i40e_reenable_fdir_atr(struct i40e_pf *pf)
I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
- if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
(I40E_DEBUG_FD & pf->hw.debug_mask))
dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
}
@@ -9952,7 +9960,7 @@ static void i40e_link_event(struct i40e_pf *pf)
if (pf->vf)
i40e_vc_notify_link_state(pf);
- if (pf->flags & I40E_FLAG_PTP)
+ if (test_bit(I40E_FLAG_PTP_ENA, pf->flags))
i40e_ptp_set_increment(pf);
#ifdef CONFIG_I40E_DCB
if (new_link == old_link)
@@ -9969,13 +9977,13 @@ static void i40e_link_event(struct i40e_pf *pf)
memset(&pf->tmp_cfg, 0, sizeof(pf->tmp_cfg));
err = i40e_dcb_sw_default_config(pf);
if (err) {
- pf->flags &= ~(I40E_FLAG_DCB_CAPABLE |
- I40E_FLAG_DCB_ENABLED);
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
} else {
pf->dcbx_cap = DCB_CAP_DCBX_HOST |
DCB_CAP_DCBX_VER_IEEE;
- pf->flags |= I40E_FLAG_DCB_CAPABLE;
- pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+ set_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
}
}
#endif /* CONFIG_I40E_DCB */
@@ -10000,7 +10008,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
return;
pf->service_timer_previous = jiffies;
- if ((pf->flags & I40E_FLAG_LINK_POLLING_ENABLED) ||
+ if (test_bit(I40E_FLAG_LINK_POLLING_ENA, pf->flags) ||
test_bit(__I40E_TEMP_LINK_POLLING, pf->state))
i40e_link_event(pf);
@@ -10011,7 +10019,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
if (pf->vsi[i] && pf->vsi[i]->netdev)
i40e_update_stats(pf->vsi[i]);
- if (pf->flags & I40E_FLAG_VEB_STATS_ENABLED) {
+ if (test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags)) {
/* Update the stats for the active switching components */
for (i = 0; i < I40E_MAX_VEB; i++)
if (pf->veb[i])
@@ -10100,7 +10108,7 @@ static void i40e_handle_link_event(struct i40e_pf *pf,
if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
(!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
(!(status->link_info & I40E_AQ_LINK_UP)) &&
- (!(pf->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))) {
+ (!test_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))) {
dev_err(&pf->pdev->dev,
"Rx/Tx is disabled on this device because an unsupported SFP module type was detected.\n");
dev_err(&pf->pdev->dev,
@@ -10128,7 +10136,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
return;
/* check for error indications */
- val = rd32(&pf->hw, pf->hw.aq.arq.len);
+ val = rd32(&pf->hw, I40E_PF_ARQLEN);
oldval = val;
if (val & I40E_PF_ARQLEN_ARQVFE_MASK) {
if (hw->debug_mask & I40E_DEBUG_AQ)
@@ -10147,9 +10155,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
val &= ~I40E_PF_ARQLEN_ARQCRIT_MASK;
}
if (oldval != val)
- wr32(&pf->hw, pf->hw.aq.arq.len, val);
+ wr32(&pf->hw, I40E_PF_ARQLEN, val);
- val = rd32(&pf->hw, pf->hw.aq.asq.len);
+ val = rd32(&pf->hw, I40E_PF_ATQLEN);
oldval = val;
if (val & I40E_PF_ATQLEN_ATQVFE_MASK) {
if (pf->hw.debug_mask & I40E_DEBUG_AQ)
@@ -10167,7 +10175,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
val &= ~I40E_PF_ATQLEN_ATQCRIT_MASK;
}
if (oldval != val)
- wr32(&pf->hw, pf->hw.aq.asq.len, val);
+ wr32(&pf->hw, I40E_PF_ATQLEN, val);
event.buf_len = I40E_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
@@ -10227,9 +10235,9 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
opcode);
break;
}
- } while (i++ < pf->adminq_work_limit);
+ } while (i++ < I40E_AQ_WORK_LIMIT);
- if (i < pf->adminq_work_limit)
+ if (i < I40E_AQ_WORK_LIMIT)
clear_bit(__I40E_ADMINQ_EVENT_PENDING, pf->state);
/* re-enable Admin queue interrupt cause */
@@ -10406,7 +10414,7 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)
if (ret)
goto end_reconstitute;
- if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED)
+ if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags))
veb->bridge_mode = BRIDGE_MODE_VEB;
else
veb->bridge_mode = BRIDGE_MODE_VEPA;
@@ -10551,7 +10559,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
wr32(&pf->hw, I40E_GLQF_HKEY(i), hkey[i]);
}
- if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags))
return;
/* find existing VSI and see if it needs configuring */
@@ -10563,8 +10571,8 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
pf->vsi[pf->lan_vsi]->seid, 0);
if (!vsi) {
dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n");
- pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
return;
}
}
@@ -10942,14 +10950,14 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
i40e_aq_set_dcb_parameters(hw, false, NULL);
dev_warn(&pf->pdev->dev,
"DCB is not supported for X710-T*L 2.5/5G speeds\n");
- pf->flags &= ~I40E_FLAG_DCB_CAPABLE;
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
} else {
i40e_aq_set_dcb_parameters(hw, true, NULL);
ret = i40e_init_pf_dcb(pf);
if (ret) {
dev_info(&pf->pdev->dev, "DCB init failed %d, disabled\n",
ret);
- pf->flags &= ~I40E_FLAG_DCB_CAPABLE;
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
/* Continue without DCB enabled */
}
}
@@ -11070,7 +11078,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
wr32(hw, I40E_REG_MSS, val);
}
- if (pf->hw_features & I40E_HW_RESTART_AUTONEG) {
+ if (test_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps)) {
msleep(75);
ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL);
if (ret)
@@ -11080,7 +11088,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
pf->hw.aq.asq_last_status));
}
/* reinit the misc interrupt */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
ret = i40e_setup_misc_vector(pf);
if (ret)
goto end_unlock;
@@ -11187,14 +11195,10 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
/* find what triggered the MDD event */
reg = rd32(hw, I40E_GL_MDET_TX);
if (reg & I40E_GL_MDET_TX_VALID_MASK) {
- u8 pf_num = (reg & I40E_GL_MDET_TX_PF_NUM_MASK) >>
- I40E_GL_MDET_TX_PF_NUM_SHIFT;
- u16 vf_num = (reg & I40E_GL_MDET_TX_VF_NUM_MASK) >>
- I40E_GL_MDET_TX_VF_NUM_SHIFT;
- u8 event = (reg & I40E_GL_MDET_TX_EVENT_MASK) >>
- I40E_GL_MDET_TX_EVENT_SHIFT;
- u16 queue = ((reg & I40E_GL_MDET_TX_QUEUE_MASK) >>
- I40E_GL_MDET_TX_QUEUE_SHIFT) -
+ u8 pf_num = FIELD_GET(I40E_GL_MDET_TX_PF_NUM_MASK, reg);
+ u16 vf_num = FIELD_GET(I40E_GL_MDET_TX_VF_NUM_MASK, reg);
+ u8 event = FIELD_GET(I40E_GL_MDET_TX_EVENT_MASK, reg);
+ u16 queue = FIELD_GET(I40E_GL_MDET_TX_QUEUE_MASK, reg) -
pf->hw.func_caps.base_queue;
if (netif_msg_tx_err(pf))
dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on TX queue %d PF number 0x%02x VF number 0x%02x\n",
@@ -11204,12 +11208,9 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
}
reg = rd32(hw, I40E_GL_MDET_RX);
if (reg & I40E_GL_MDET_RX_VALID_MASK) {
- u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK) >>
- I40E_GL_MDET_RX_FUNCTION_SHIFT;
- u8 event = (reg & I40E_GL_MDET_RX_EVENT_MASK) >>
- I40E_GL_MDET_RX_EVENT_SHIFT;
- u16 queue = ((reg & I40E_GL_MDET_RX_QUEUE_MASK) >>
- I40E_GL_MDET_RX_QUEUE_SHIFT) -
+ u8 func = FIELD_GET(I40E_GL_MDET_RX_FUNCTION_MASK, reg);
+ u8 event = FIELD_GET(I40E_GL_MDET_RX_EVENT_MASK, reg);
+ u16 queue = FIELD_GET(I40E_GL_MDET_RX_QUEUE_MASK, reg) -
pf->hw.func_caps.base_queue;
if (netif_msg_rx_err(pf))
dev_info(&pf->pdev->dev, "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
@@ -11355,7 +11356,7 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
if (!vsi->num_rx_desc)
vsi->num_rx_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
I40E_REQ_DESCRIPTOR_MULTIPLE);
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
vsi->num_q_vectors = pf->num_lan_msix;
else
vsi->num_q_vectors = 1;
@@ -11673,7 +11674,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
ring->count = vsi->num_tx_desc;
ring->size = 0;
ring->dcb_tc = 0;
- if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
+ if (test_bit(I40E_HW_CAP_WB_ON_ITR, vsi->back->hw.caps))
ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
ring->itr_setting = pf->tx_itr_default;
WRITE_ONCE(vsi->tx_rings[i], ring++);
@@ -11690,7 +11691,7 @@ static int i40e_alloc_rings(struct i40e_vsi *vsi)
ring->count = vsi->num_tx_desc;
ring->size = 0;
ring->dcb_tc = 0;
- if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
+ if (test_bit(I40E_HW_CAP_WB_ON_ITR, vsi->back->hw.caps))
ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
set_ring_xdp(ring);
ring->itr_setting = pf->tx_itr_default;
@@ -11754,7 +11755,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
int v_actual;
int iwarp_requested = 0;
- if (!(pf->flags & I40E_FLAG_MSIX_ENABLED))
+ if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
return -ENODEV;
/* The number of vectors we'll request will be comprised of:
@@ -11793,7 +11794,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
vectors_left -= pf->num_lan_msix;
/* reserve one vector for sideband flow director */
- if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) {
if (vectors_left) {
pf->num_fdsb_msix = 1;
v_budget++;
@@ -11804,7 +11805,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
}
/* can we reserve enough for iWARP? */
- if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
iwarp_requested = pf->num_iwarp_msix;
if (!vectors_left)
@@ -11816,7 +11817,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
}
/* any vectors left over go for VMDq support */
- if (pf->flags & I40E_FLAG_VMDQ_ENABLED) {
+ if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags)) {
if (!vectors_left) {
pf->num_vmdq_msix = 0;
pf->num_vmdq_qps = 0;
@@ -11873,7 +11874,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
v_actual = i40e_reserve_msix_vectors(pf, v_budget);
if (v_actual < I40E_MIN_MSIX) {
- pf->flags &= ~I40E_FLAG_MSIX_ENABLED;
+ clear_bit(I40E_FLAG_MSIX_ENA, pf->flags);
kfree(pf->msix_entries);
pf->msix_entries = NULL;
pci_disable_msix(pf->pdev);
@@ -11911,7 +11912,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
pf->num_lan_msix = 1;
break;
case 3:
- if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
pf->num_lan_msix = 1;
pf->num_iwarp_msix = 1;
} else {
@@ -11919,7 +11920,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
}
break;
default:
- if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
pf->num_iwarp_msix = min_t(int, (vec / 3),
iwarp_requested);
pf->num_vmdq_vsis = min_t(int, (vec / 3),
@@ -11928,7 +11929,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
pf->num_vmdq_vsis = min_t(int, (vec / 2),
I40E_DEFAULT_NUM_VMDQ_VSI);
}
- if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) {
pf->num_fdsb_msix = 1;
vec--;
}
@@ -11940,22 +11941,20 @@ static int i40e_init_msix(struct i40e_pf *pf)
}
}
- if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
- (pf->num_fdsb_msix == 0)) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) && pf->num_fdsb_msix == 0) {
dev_info(&pf->pdev->dev, "Sideband Flowdir disabled, not enough MSI-X vectors\n");
- pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
}
- if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
- (pf->num_vmdq_msix == 0)) {
+ if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags) && pf->num_vmdq_msix == 0) {
dev_info(&pf->pdev->dev, "VMDq disabled, not enough MSI-X vectors\n");
- pf->flags &= ~I40E_FLAG_VMDQ_ENABLED;
+ clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
}
- if ((pf->flags & I40E_FLAG_IWARP_ENABLED) &&
- (pf->num_iwarp_msix == 0)) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags) &&
+ pf->num_iwarp_msix == 0) {
dev_info(&pf->pdev->dev, "IWARP disabled, not enough MSI-X vectors\n");
- pf->flags &= ~I40E_FLAG_IWARP_ENABLED;
+ clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
}
i40e_debug(&pf->hw, I40E_DEBUG_INIT,
"MSI-X vector distribution: PF %d, VMDq %d, FDSB %d, iWARP %d\n",
@@ -12009,7 +12008,7 @@ static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi)
int err, v_idx, num_q_vectors;
/* if not MSIX, give the one vector only to the LAN VSI */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
num_q_vectors = vsi->num_q_vectors;
else if (vsi == pf->vsi[pf->lan_vsi])
num_q_vectors = 1;
@@ -12040,38 +12039,39 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
int vectors = 0;
ssize_t size;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
vectors = i40e_init_msix(pf);
if (vectors < 0) {
- pf->flags &= ~(I40E_FLAG_MSIX_ENABLED |
- I40E_FLAG_IWARP_ENABLED |
- I40E_FLAG_RSS_ENABLED |
- I40E_FLAG_DCB_CAPABLE |
- I40E_FLAG_DCB_ENABLED |
- I40E_FLAG_SRIOV_ENABLED |
- I40E_FLAG_FD_SB_ENABLED |
- I40E_FLAG_FD_ATR_ENABLED |
- I40E_FLAG_VMDQ_ENABLED);
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
+ clear_bit(I40E_FLAG_MSIX_ENA, pf->flags);
+ clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
+ clear_bit(I40E_FLAG_RSS_ENA, pf->flags);
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags);
+ clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
/* rework the queue expectations without MSIX */
i40e_determine_queue_usage(pf);
}
}
- if (!(pf->flags & I40E_FLAG_MSIX_ENABLED) &&
- (pf->flags & I40E_FLAG_MSI_ENABLED)) {
+ if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags) &&
+ test_bit(I40E_FLAG_MSI_ENA, pf->flags)) {
dev_info(&pf->pdev->dev, "MSI-X not available, trying MSI\n");
vectors = pci_enable_msi(pf->pdev);
if (vectors < 0) {
dev_info(&pf->pdev->dev, "MSI init failed - %d\n",
vectors);
- pf->flags &= ~I40E_FLAG_MSI_ENABLED;
+ clear_bit(I40E_FLAG_MSI_ENA, pf->flags);
}
vectors = 1; /* one MSI or Legacy vector */
}
- if (!(pf->flags & (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED)))
+ if (!test_bit(I40E_FLAG_MSI_ENA, pf->flags) &&
+ !test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
dev_info(&pf->pdev->dev, "MSI-X and MSI not available, falling back to Legacy IRQ\n");
/* set up vector assignment tracking */
@@ -12104,7 +12104,8 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
* scheme. We need to re-enabled them here in order to attempt to
* re-acquire the MSI or MSI-X vectors
*/
- pf->flags |= (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED);
+ set_bit(I40E_FLAG_MSI_ENA, pf->flags);
+ set_bit(I40E_FLAG_MSIX_ENA, pf->flags);
err = i40e_init_interrupt_scheme(pf);
if (err)
@@ -12126,7 +12127,7 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
if (err)
goto err_unwind;
- if (pf->flags & I40E_FLAG_IWARP_ENABLED)
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags))
i40e_client_update_msix_info(pf);
return 0;
@@ -12154,7 +12155,7 @@ static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf)
{
int err;
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
err = i40e_setup_misc_vector(pf);
if (err) {
@@ -12164,7 +12165,7 @@ static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf)
return err;
}
} else {
- u32 flags = pf->flags & I40E_FLAG_MSI_ENABLED ? 0 : IRQF_SHARED;
+ u32 flags = test_bit(I40E_FLAG_MSI_ENA, pf->flags) ? 0 : IRQF_SHARED;
err = request_irq(pf->pdev->irq, i40e_intr, flags,
pf->int_name, pf);
@@ -12368,7 +12369,7 @@ int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
{
struct i40e_pf *pf = vsi->back;
- if (pf->hw_features & I40E_HW_RSS_AQ_CAPABLE)
+ if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps))
return i40e_config_rss_aq(vsi, seed, lut, lut_size);
else
return i40e_config_rss_reg(vsi, seed, lut, lut_size);
@@ -12387,7 +12388,7 @@ int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
{
struct i40e_pf *pf = vsi->back;
- if (pf->hw_features & I40E_HW_RSS_AQ_CAPABLE)
+ if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps))
return i40e_get_rss_aq(vsi, seed, lut, lut_size);
else
return i40e_get_rss_reg(vsi, seed, lut, lut_size);
@@ -12490,7 +12491,7 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
int new_rss_size;
- if (!(pf->flags & I40E_FLAG_RSS_ENABLED))
+ if (!test_bit(I40E_FLAG_RSS_ENA, pf->flags))
return 0;
queue_count = min_t(int, queue_count, num_online_cpus());
@@ -12723,9 +12724,9 @@ static int i40e_sw_init(struct i40e_pf *pf)
u16 pow;
/* Set default capability flags */
- pf->flags = I40E_FLAG_RX_CSUM_ENABLED |
- I40E_FLAG_MSI_ENABLED |
- I40E_FLAG_MSIX_ENABLED;
+ bitmap_zero(pf->flags, I40E_PF_FLAGS_NBITS);
+ set_bit(I40E_FLAG_MSI_ENA, pf->flags);
+ set_bit(I40E_FLAG_MSIX_ENA, pf->flags);
/* Set default ITR */
pf->rx_itr_default = I40E_ITR_RX_DEF;
@@ -12745,14 +12746,14 @@ static int i40e_sw_init(struct i40e_pf *pf)
pf->rss_size_max = min_t(int, pf->rss_size_max, pow);
if (pf->hw.func_caps.rss) {
- pf->flags |= I40E_FLAG_RSS_ENABLED;
+ set_bit(I40E_FLAG_RSS_ENA, pf->flags);
pf->alloc_rss_size = min_t(int, pf->rss_size_max,
num_online_cpus());
}
/* MFP mode enabled */
if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.flex10_enable) {
- pf->flags |= I40E_FLAG_MFP_ENABLED;
+ set_bit(I40E_FLAG_MFP_ENA, pf->flags);
dev_info(&pf->pdev->dev, "MFP mode Enabled\n");
if (i40e_get_partition_bw_setting(pf)) {
dev_warn(&pf->pdev->dev,
@@ -12769,84 +12770,31 @@ static int i40e_sw_init(struct i40e_pf *pf)
if ((pf->hw.func_caps.fd_filters_guaranteed > 0) ||
(pf->hw.func_caps.fd_filters_best_effort > 0)) {
- pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
- pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
- if (pf->flags & I40E_FLAG_MFP_ENABLED &&
+ set_bit(I40E_FLAG_FD_ATR_ENA, pf->flags);
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) &&
pf->hw.num_partitions > 1)
dev_info(&pf->pdev->dev,
"Flow Director Sideband mode Disabled in MFP mode\n");
else
- pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+ set_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
pf->fdir_pf_filter_count =
pf->hw.func_caps.fd_filters_guaranteed;
pf->hw.fdir_shared_filter_count =
pf->hw.func_caps.fd_filters_best_effort;
}
- if (pf->hw.mac.type == I40E_MAC_X722) {
- pf->hw_features |= (I40E_HW_RSS_AQ_CAPABLE |
- I40E_HW_128_QP_RSS_CAPABLE |
- I40E_HW_ATR_EVICT_CAPABLE |
- I40E_HW_WB_ON_ITR_CAPABLE |
- I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE |
- I40E_HW_NO_PCI_LINK_CHECK |
- I40E_HW_USE_SET_LLDP_MIB |
- I40E_HW_GENEVE_OFFLOAD_CAPABLE |
- I40E_HW_PTP_L4_CAPABLE |
- I40E_HW_WOL_MC_MAGIC_PKT_WAKE |
- I40E_HW_OUTER_UDP_CSUM_CAPABLE);
-
-#define I40E_FDEVICT_PCTYPE_DEFAULT 0xc03
- if (rd32(&pf->hw, I40E_GLQF_FDEVICTENA(1)) !=
- I40E_FDEVICT_PCTYPE_DEFAULT) {
- dev_warn(&pf->pdev->dev,
- "FD EVICT PCTYPES are not right, disable FD HW EVICT\n");
- pf->hw_features &= ~I40E_HW_ATR_EVICT_CAPABLE;
- }
- } else if ((pf->hw.aq.api_maj_ver > 1) ||
- ((pf->hw.aq.api_maj_ver == 1) &&
- (pf->hw.aq.api_min_ver > 4))) {
- /* Supported in FW API version higher than 1.4 */
- pf->hw_features |= I40E_HW_GENEVE_OFFLOAD_CAPABLE;
- }
-
/* Enable HW ATR eviction if possible */
- if (pf->hw_features & I40E_HW_ATR_EVICT_CAPABLE)
- pf->flags |= I40E_FLAG_HW_ATR_EVICT_ENABLED;
-
- if ((pf->hw.mac.type == I40E_MAC_XL710) &&
- (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
- (pf->hw.aq.fw_maj_ver < 4))) {
- pf->hw_features |= I40E_HW_RESTART_AUTONEG;
- /* No DCB support for FW < v4.33 */
- pf->hw_features |= I40E_HW_NO_DCB_SUPPORT;
- }
-
- /* Disable FW LLDP if FW < v4.3 */
- if ((pf->hw.mac.type == I40E_MAC_XL710) &&
- (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
- (pf->hw.aq.fw_maj_ver < 4)))
- pf->hw_features |= I40E_HW_STOP_FW_LLDP;
-
- /* Use the FW Set LLDP MIB API if FW > v4.40 */
- if ((pf->hw.mac.type == I40E_MAC_XL710) &&
- (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver >= 40)) ||
- (pf->hw.aq.fw_maj_ver >= 5)))
- pf->hw_features |= I40E_HW_USE_SET_LLDP_MIB;
-
- /* Enable PTP L4 if FW > v6.0 */
- if (pf->hw.mac.type == I40E_MAC_XL710 &&
- pf->hw.aq.fw_maj_ver >= 6)
- pf->hw_features |= I40E_HW_PTP_L4_CAPABLE;
+ if (test_bit(I40E_HW_CAP_ATR_EVICT, pf->hw.caps))
+ set_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags);
if (pf->hw.func_caps.vmdq && num_online_cpus() != 1) {
pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
- pf->flags |= I40E_FLAG_VMDQ_ENABLED;
+ set_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
pf->num_vmdq_qps = i40e_default_queues_per_vmdq(pf);
}
if (pf->hw.func_caps.iwarp && num_online_cpus() != 1) {
- pf->flags |= I40E_FLAG_IWARP_ENABLED;
+ set_bit(I40E_FLAG_IWARP_ENA, pf->flags);
/* IWARP needs one extra vector for CQP just like MISC.*/
pf->num_iwarp_msix = (int)num_online_cpus() + 1;
}
@@ -12856,25 +12804,23 @@ static int i40e_sw_init(struct i40e_pf *pf)
* if NPAR is functioning so unset this hw flag in this case.
*/
if (pf->hw.mac.type == I40E_MAC_XL710 &&
- pf->hw.func_caps.npar_enable &&
- (pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))
- pf->hw.flags &= ~I40E_HW_FLAG_FW_LLDP_STOPPABLE;
+ pf->hw.func_caps.npar_enable)
+ clear_bit(I40E_HW_CAP_FW_LLDP_STOPPABLE, pf->hw.caps);
#ifdef CONFIG_PCI_IOV
if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) {
pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;
- pf->flags |= I40E_FLAG_SRIOV_ENABLED;
+ set_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
pf->num_req_vfs = min_t(int,
pf->hw.func_caps.num_vfs,
I40E_MAX_VF_COUNT);
}
#endif /* CONFIG_PCI_IOV */
- pf->eeprom_version = 0xDEAD;
pf->lan_veb = I40E_NO_VEB;
pf->lan_vsi = I40E_NO_VSI;
/* By default FW has this off for performance reasons */
- pf->flags &= ~I40E_FLAG_VEB_STATS_ENABLED;
+ clear_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags);
/* set up queue assignment tracking */
size = sizeof(struct i40e_lump_tracking)
@@ -12893,8 +12839,8 @@ static int i40e_sw_init(struct i40e_pf *pf)
/* Link down on close must be on when total port shutdown
* is enabled for a given port
*/
- pf->flags |= (I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED |
- I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED);
+ set_bit(I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags);
+ set_bit(I40E_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags);
dev_info(&pf->pdev->dev,
"total-port-shutdown was enabled, link-down-on-close is forced on\n");
}
@@ -12920,31 +12866,31 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
*/
if (features & NETIF_F_NTUPLE) {
/* Enable filters and mark for reset */
- if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+ if (!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags))
need_reset = true;
/* enable FD_SB only if there is MSI-X vector and no cloud
* filters exist
*/
if (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {
- pf->flags |= I40E_FLAG_FD_SB_ENABLED;
- pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
+ set_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
}
} else {
/* turn off filters, mark for reset and clear SW filter list */
- if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) {
need_reset = true;
i40e_fdir_filter_exit(pf);
}
- pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state);
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
/* reset fd counters */
pf->fd_add_err = 0;
pf->fd_atr_cnt = 0;
/* if ATR was auto disabled it can be re-enabled. */
if (test_and_clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
- if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
(I40E_DEBUG_FD & pf->hw.debug_mask))
dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
}
@@ -13093,7 +13039,7 @@ static int i40e_get_phys_port_id(struct net_device *netdev,
struct i40e_pf *pf = np->vsi->back;
struct i40e_hw *hw = &pf->hw;
- if (!(pf->hw_features & I40E_HW_PORT_ID_VALID))
+ if (!test_bit(I40E_HW_CAP_PORT_ID_VALID, pf->hw.caps))
return -EOPNOTSUPP;
ppid->id_len = min_t(int, sizeof(hw->mac.port_addr), sizeof(ppid->id));
@@ -13122,7 +13068,7 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct i40e_pf *pf = np->vsi->back;
int err = 0;
- if (!(pf->flags & I40E_FLAG_SRIOV_ENABLED))
+ if (!test_bit(I40E_FLAG_SRIOV_ENA, pf->flags))
return -EOPNOTSUPP;
if (vid) {
@@ -13222,9 +13168,9 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
veb->bridge_mode = mode;
/* TODO: If no VFs or VMDq VSIs, disallow VEB mode */
if (mode == BRIDGE_MODE_VEB)
- pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+ set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
else
- pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+ clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
break;
}
@@ -13558,7 +13504,7 @@ static void i40e_queue_pair_enable_irq(struct i40e_vsi *vsi, int queue_pair)
struct i40e_hw *hw = &pf->hw;
/* All rings in a qp belong to the same qvector. */
- if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
i40e_irq_dynamic_enable(vsi, rxr->q_vector->v_idx);
else
i40e_irq_dynamic_enable_icr0(pf);
@@ -13583,7 +13529,7 @@ static void i40e_queue_pair_disable_irq(struct i40e_vsi *vsi, int queue_pair)
*
* All rings in a qp belong to the same qvector.
*/
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
u32 intpf = vsi->base_vector + rxr->q_vector->v_idx;
wr32(hw, I40E_PFINT_DYN_CTLN(intpf - 1), 0);
@@ -13614,9 +13560,9 @@ int i40e_queue_pair_disable(struct i40e_vsi *vsi, int queue_pair)
return err;
i40e_queue_pair_disable_irq(vsi, queue_pair);
+ i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */);
err = i40e_queue_pair_toggle_rings(vsi, queue_pair, false /* off */);
i40e_clean_rx_ring(vsi->rx_rings[queue_pair]);
- i40e_queue_pair_toggle_napi(vsi, queue_pair, false /* off */);
i40e_queue_pair_clean_rings(vsi, queue_pair);
i40e_queue_pair_reset_stats(vsi, queue_pair);
@@ -13768,7 +13714,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETIF_F_RXCSUM |
0;
- if (!(pf->hw_features & I40E_HW_OUTER_UDP_CSUM_CAPABLE))
+ if (!test_bit(I40E_HW_CAP_OUTER_UDP_CSUM, pf->hw.caps))
netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM;
netdev->udp_tunnel_nic_info = &pf->udp_tunnel_nic;
@@ -13804,7 +13750,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
NETIF_F_HW_VLAN_CTAG_TX |
NETIF_F_HW_VLAN_CTAG_RX;
- if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+ if (!test_bit(I40E_FLAG_MFP_ENA, pf->flags))
hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;
netdev->hw_features |= hw_features | NETIF_F_LOOPBACK;
@@ -13995,7 +13941,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
* negative logic - if it's set, we need to fiddle with
* the VSI to disable source pruning.
*/
- if (pf->flags & I40E_FLAG_SOURCE_PRUNING_DISABLED) {
+ if (test_bit(I40E_FLAG_SOURCE_PRUNING_DIS, pf->flags)) {
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->main_vsi_seid;
ctxt.pf_num = pf->hw.pf_id;
@@ -14017,7 +13963,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
}
/* MFP mode setup queue map and update VSI */
- if ((pf->flags & I40E_FLAG_MFP_ENABLED) &&
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags) &&
!(pf->hw.func_caps.iscsi)) { /* NIC type PF */
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->main_vsi_seid;
@@ -14065,7 +14011,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
ctxt.uplink_seid = vsi->uplink_seid;
ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
ctxt.flags = I40E_AQ_VSI_TYPE_PF;
- if ((pf->flags & I40E_FLAG_VEB_MODE_ENABLED) &&
+ if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags) &&
(i40e_is_vsi_uplink_mode_veb(vsi))) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
@@ -14113,7 +14059,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
}
- if (vsi->back->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, vsi->back->flags)) {
ctxt.info.valid_sections |=
cpu_to_le16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID);
ctxt.info.queueing_opt_flags |=
@@ -14329,7 +14275,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
/* In Legacy mode, we do not have to get any other vector since we
* piggyback on the misc/ICR0 for queue interrupts.
*/
- if (!(pf->flags & I40E_FLAG_MSIX_ENABLED))
+ if (!test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
return ret;
if (vsi->num_q_vectors)
vsi->base_vector = i40e_get_lump(pf, pf->irq_pile,
@@ -14496,9 +14442,9 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
* already enabled, in which case we can't force VEPA
* mode.
*/
- if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+ if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
veb->bridge_mode = BRIDGE_MODE_VEPA;
- pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+ clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
}
i40e_config_bridge_mode(veb);
}
@@ -14594,12 +14540,16 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
break;
}
- if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) &&
- (vsi->type == I40E_VSI_VMDQ2)) {
+ if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps) &&
+ vsi->type == I40E_VSI_VMDQ2) {
ret = i40e_vsi_config_rss(vsi);
+ if (ret)
+ goto err_config;
}
return vsi;
+err_config:
+ i40e_vsi_clear_rings(vsi);
err_rings:
i40e_vsi_free_q_vectors(vsi);
err_msix:
@@ -14837,7 +14787,7 @@ void i40e_veb_release(struct i40e_veb *veb)
static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi)
{
struct i40e_pf *pf = veb->pf;
- bool enable_stats = !!(pf->flags & I40E_FLAG_VEB_STATS_ENABLED);
+ bool enable_stats = !!test_bit(I40E_FLAG_VEB_STATS_ENA, pf->flags);
int ret;
ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid,
@@ -15026,12 +14976,11 @@ static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
* the PF's VSI
*/
pf->mac_seid = uplink_seid;
- pf->pf_seid = downlink_seid;
pf->main_vsi_seid = seid;
if (printconfig)
dev_info(&pf->pdev->dev,
"pf_seid=%d main_vsi_seid=%d\n",
- pf->pf_seid, pf->main_vsi_seid);
+ downlink_seid, pf->main_vsi_seid);
break;
case I40E_SWITCH_ELEMENT_TYPE_PF:
case I40E_SWITCH_ELEMENT_TYPE_VF:
@@ -15137,7 +15086,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acqui
*/
if ((pf->hw.pf_id == 0) &&
- !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {
+ !test_bit(I40E_FLAG_TRUE_PROMISC_ENA, pf->flags)) {
flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
pf->last_sw_conf_flags = flags;
}
@@ -15204,16 +15153,12 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit, bool lock_acqui
/* enable RSS in the HW, even for only one queue, as the stack can use
* the hash
*/
- if ((pf->flags & I40E_FLAG_RSS_ENABLED))
+ if (test_bit(I40E_FLAG_RSS_ENA, pf->flags))
i40e_pf_config_rss(pf);
/* fill in link information and enable LSE reporting */
i40e_link_event(pf);
- /* Initialize user-specific link properties */
- pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info &
- I40E_AQ_AN_COMPLETED) ? true : false);
-
i40e_ptp_init(pf);
if (!lock_acquired)
@@ -15246,42 +15191,42 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
queues_left = pf->hw.func_caps.num_tx_qp;
if ((queues_left == 1) ||
- !(pf->flags & I40E_FLAG_MSIX_ENABLED)) {
+ !test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
/* one qp for PF, no queues for anything else */
queues_left = 0;
pf->alloc_rss_size = pf->num_lan_qps = 1;
/* make sure all the fancies are disabled */
- pf->flags &= ~(I40E_FLAG_RSS_ENABLED |
- I40E_FLAG_IWARP_ENABLED |
- I40E_FLAG_FD_SB_ENABLED |
- I40E_FLAG_FD_ATR_ENABLED |
- I40E_FLAG_DCB_CAPABLE |
- I40E_FLAG_DCB_ENABLED |
- I40E_FLAG_SRIOV_ENABLED |
- I40E_FLAG_VMDQ_ENABLED);
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
- } else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |
- I40E_FLAG_FD_SB_ENABLED |
- I40E_FLAG_FD_ATR_ENABLED |
- I40E_FLAG_DCB_CAPABLE))) {
+ clear_bit(I40E_FLAG_RSS_ENA, pf->flags);
+ clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags);
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
+ clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
+ } else if (!test_bit(I40E_FLAG_RSS_ENA, pf->flags) &&
+ !test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) &&
+ !test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
+ !test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags)) {
/* one qp for PF */
pf->alloc_rss_size = pf->num_lan_qps = 1;
queues_left -= pf->num_lan_qps;
- pf->flags &= ~(I40E_FLAG_RSS_ENABLED |
- I40E_FLAG_IWARP_ENABLED |
- I40E_FLAG_FD_SB_ENABLED |
- I40E_FLAG_FD_ATR_ENABLED |
- I40E_FLAG_DCB_ENABLED |
- I40E_FLAG_VMDQ_ENABLED);
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
+ clear_bit(I40E_FLAG_RSS_ENA, pf->flags);
+ clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_FD_ATR_ENA, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
+ clear_bit(I40E_FLAG_VMDQ_ENA, pf->flags);
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
} else {
/* Not enough queues for all TCs */
- if ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&
- (queues_left < I40E_MAX_TRAFFIC_CLASS)) {
- pf->flags &= ~(I40E_FLAG_DCB_CAPABLE |
- I40E_FLAG_DCB_ENABLED);
+ if (test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags) &&
+ queues_left < I40E_MAX_TRAFFIC_CLASS) {
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
dev_info(&pf->pdev->dev, "not enough queues for DCB. DCB is disabled.\n");
}
@@ -15294,24 +15239,24 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
queues_left -= pf->num_lan_qps;
}
- if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) {
if (queues_left > 1) {
queues_left -= 1; /* save 1 queue for FD */
} else {
- pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
- pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
+ clear_bit(I40E_FLAG_FD_SB_ENA, pf->flags);
+ set_bit(I40E_FLAG_FD_SB_INACTIVE, pf->flags);
dev_info(&pf->pdev->dev, "not enough queues for Flow Director. Flow Director feature is disabled\n");
}
}
- if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
+ if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) &&
pf->num_vf_qps && pf->num_req_vfs && queues_left) {
pf->num_req_vfs = min_t(int, pf->num_req_vfs,
(queues_left / pf->num_vf_qps));
queues_left -= (pf->num_req_vfs * pf->num_vf_qps);
}
- if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
+ if (test_bit(I40E_FLAG_VMDQ_ENA, pf->flags) &&
pf->num_vmdq_vsis && pf->num_vmdq_qps && queues_left) {
pf->num_vmdq_vsis = min_t(int, pf->num_vmdq_vsis,
(queues_left / pf->num_vmdq_qps));
@@ -15322,7 +15267,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
dev_dbg(&pf->pdev->dev,
"qs_avail=%d FD SB=%d lan_qs=%d lan_tc0=%d vf=%d*%d vmdq=%d*%d, remaining=%d\n",
pf->hw.func_caps.num_tx_qp,
- !!(pf->flags & I40E_FLAG_FD_SB_ENABLED),
+ !!test_bit(I40E_FLAG_FD_SB_ENA, pf->flags),
pf->num_lan_qps, pf->alloc_rss_size, pf->num_req_vfs,
pf->num_vf_qps, pf->num_vmdq_vsis, pf->num_vmdq_qps,
queues_left);
@@ -15346,7 +15291,8 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf)
settings->hash_lut_size = I40E_HASH_LUT_SIZE_128;
/* Flow Director is enabled */
- if (pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED))
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) ||
+ test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags))
settings->enable_fdir = true;
/* Ethtype and MACVLAN filters enabled for PF */
@@ -15378,21 +15324,21 @@ static void i40e_print_features(struct i40e_pf *pf)
i += scnprintf(&buf[i], REMAIN(i), " VSIs: %d QP: %d",
pf->hw.func_caps.num_vsis,
pf->vsi[pf->lan_vsi]->num_queue_pairs);
- if (pf->flags & I40E_FLAG_RSS_ENABLED)
+ if (test_bit(I40E_FLAG_RSS_ENA, pf->flags))
i += scnprintf(&buf[i], REMAIN(i), " RSS");
- if (pf->flags & I40E_FLAG_FD_ATR_ENABLED)
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags))
i += scnprintf(&buf[i], REMAIN(i), " FD_ATR");
- if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags)) {
i += scnprintf(&buf[i], REMAIN(i), " FD_SB");
i += scnprintf(&buf[i], REMAIN(i), " NTUPLE");
}
- if (pf->flags & I40E_FLAG_DCB_CAPABLE)
+ if (test_bit(I40E_FLAG_DCB_CAPABLE, pf->flags))
i += scnprintf(&buf[i], REMAIN(i), " DCB");
i += scnprintf(&buf[i], REMAIN(i), " VxLAN");
i += scnprintf(&buf[i], REMAIN(i), " Geneve");
- if (pf->flags & I40E_FLAG_PTP)
+ if (test_bit(I40E_FLAG_PTP_ENA, pf->flags))
i += scnprintf(&buf[i], REMAIN(i), " PTP");
- if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED)
+ if (test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags))
i += scnprintf(&buf[i], REMAIN(i), " VEB");
else
i += scnprintf(&buf[i], REMAIN(i), " VEPA");
@@ -15423,22 +15369,26 @@ static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf)
* @fec_cfg: FEC option to set in flags
* @flags: ptr to flags in which we set FEC option
**/
-void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags)
+void i40e_set_fec_in_flags(u8 fec_cfg, unsigned long *flags)
{
- if (fec_cfg & I40E_AQ_SET_FEC_AUTO)
- *flags |= I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC;
+ if (fec_cfg & I40E_AQ_SET_FEC_AUTO) {
+ set_bit(I40E_FLAG_RS_FEC, flags);
+ set_bit(I40E_FLAG_BASE_R_FEC, flags);
+ }
if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_RS) ||
(fec_cfg & I40E_AQ_SET_FEC_ABILITY_RS)) {
- *flags |= I40E_FLAG_RS_FEC;
- *flags &= ~I40E_FLAG_BASE_R_FEC;
+ set_bit(I40E_FLAG_RS_FEC, flags);
+ clear_bit(I40E_FLAG_BASE_R_FEC, flags);
}
if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_KR) ||
(fec_cfg & I40E_AQ_SET_FEC_ABILITY_KR)) {
- *flags |= I40E_FLAG_BASE_R_FEC;
- *flags &= ~I40E_FLAG_RS_FEC;
+ set_bit(I40E_FLAG_BASE_R_FEC, flags);
+ clear_bit(I40E_FLAG_RS_FEC, flags);
+ }
+ if (fec_cfg == 0) {
+ clear_bit(I40E_FLAG_RS_FEC, flags);
+ clear_bit(I40E_FLAG_BASE_R_FEC, flags);
}
- if (fec_cfg == 0)
- *flags &= ~(I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC);
}
/**
@@ -15682,7 +15632,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif /* CONFIG_I40E_DCB */
struct i40e_pf *pf;
struct i40e_hw *hw;
- static u16 pfs_found;
u16 wol_nvm_bits;
char nvm_ver[32];
u16 link_status;
@@ -15760,7 +15709,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->bus.device = PCI_SLOT(pdev->devfn);
hw->bus.func = PCI_FUNC(pdev->devfn);
hw->bus.bus_id = pdev->bus->number;
- pf->instance = pfs_found;
/* Select something other than the 802.1ad ethertype for the
* switch to use internally and drop on ingress.
@@ -15822,7 +15770,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
hw->aq.arq_buf_size = I40E_MAX_AQ_BUF_SIZE;
hw->aq.asq_buf_size = I40E_MAX_AQ_BUF_SIZE;
- pf->adminq_work_limit = I40E_AQ_WORK_LIMIT;
snprintf(pf->int_name, sizeof(pf->int_name) - 1,
"%s-%s:misc",
@@ -15864,15 +15811,15 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->vendor_id, hw->device_id, hw->subsystem_vendor_id,
hw->subsystem_device_id);
- if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
- hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw))
+ if (i40e_is_aq_api_ver_ge(hw, I40E_FW_API_VERSION_MAJOR,
+ I40E_FW_MINOR_VERSION(hw) + 1))
dev_dbg(&pdev->dev,
"The driver for the device detected a newer version of the NVM image v%u.%u than v%u.%u.\n",
hw->aq.api_maj_ver,
hw->aq.api_min_ver,
I40E_FW_API_VERSION_MAJOR,
I40E_FW_MINOR_VERSION(hw));
- else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4)
+ else if (i40e_is_aq_api_ver_lt(hw, 1, 4))
dev_info(&pdev->dev,
"The driver for the device detected an older version of the NVM image v%u.%u than expected v%u.%u. Please update the NVM image.\n",
hw->aq.api_maj_ver,
@@ -15919,7 +15866,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* Ignore error return codes because if it was already disabled via
* hardware settings this will fail
*/
- if (pf->hw_features & I40E_HW_STOP_FW_LLDP) {
+ if (test_bit(I40E_HW_CAP_STOP_FW_LLDP, pf->hw.caps)) {
dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n");
i40e_aq_stop_lldp(hw, true, false, NULL);
}
@@ -15936,7 +15883,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ether_addr_copy(hw->mac.perm_addr, hw->mac.addr);
i40e_get_port_mac_addr(hw, hw->mac.port_addr);
if (is_valid_ether_addr(hw->mac.port_addr))
- pf->hw_features |= I40E_HW_PORT_ID_VALID;
+ set_bit(I40E_HW_CAP_PORT_ID_VALID, pf->hw.caps);
i40e_ptp_alloc_pins(pf);
pci_set_drvdata(pdev, pf);
@@ -15946,10 +15893,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
status = i40e_get_fw_lldp_status(&pf->hw, &lldp_status);
(!status &&
lldp_status == I40E_GET_FW_LLDP_STATUS_ENABLED) ?
- (pf->flags &= ~I40E_FLAG_DISABLE_FW_LLDP) :
- (pf->flags |= I40E_FLAG_DISABLE_FW_LLDP);
+ (clear_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags)) :
+ (set_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags));
dev_info(&pdev->dev,
- (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) ?
+ test_bit(I40E_FLAG_FW_LLDP_DIS, pf->flags) ?
"FW LLDP is disabled\n" :
"FW LLDP is enabled\n");
@@ -15959,7 +15906,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = i40e_init_pf_dcb(pf);
if (err) {
dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err);
- pf->flags &= ~(I40E_FLAG_DCB_CAPABLE | I40E_FLAG_DCB_ENABLED);
+ clear_bit(I40E_FLAG_DCB_CAPABLE, pf->flags);
+ clear_bit(I40E_FLAG_DCB_ENA, pf->flags);
/* Continue without DCB enabled */
}
#endif /* CONFIG_I40E_DCB */
@@ -16027,11 +15975,11 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PCI_IOV
/* prep for VF support */
- if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
- (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
+ if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) &&
+ test_bit(I40E_FLAG_MSIX_ENA, pf->flags) &&
!test_bit(__I40E_BAD_EEPROM, pf->state)) {
if (pci_num_vf(pdev))
- pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+ set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
}
#endif
err = i40e_setup_pf_switch(pf, false, false);
@@ -16072,7 +16020,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
wr32(hw, I40E_REG_MSS, val);
}
- if (pf->hw_features & I40E_HW_RESTART_AUTONEG) {
+ if (test_bit(I40E_HW_CAP_RESTART_AUTONEG, pf->hw.caps)) {
msleep(75);
err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL);
if (err)
@@ -16092,7 +16040,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* the misc functionality and queue processing is combined in
* the same vector and that gets setup at open.
*/
- if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, pf->flags)) {
err = i40e_setup_misc_vector(pf);
if (err) {
dev_info(&pdev->dev,
@@ -16105,8 +16053,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PCI_IOV
/* prep for VF support */
- if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
- (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
+ if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags) &&
+ test_bit(I40E_FLAG_MSIX_ENA, pf->flags) &&
!test_bit(__I40E_BAD_EEPROM, pf->state)) {
/* disable link interrupts for VFs */
val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
@@ -16126,7 +16074,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
#endif /* CONFIG_PCI_IOV */
- if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
pf->iwarp_base_vector = i40e_get_lump(pf, pf->irq_pile,
pf->num_iwarp_msix,
I40E_IWARP_IRQ_PILE_ID);
@@ -16134,7 +16082,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_info(&pdev->dev,
"failed to get tracking for %d vectors for IWARP err=%d\n",
pf->num_iwarp_msix, pf->iwarp_base_vector);
- pf->flags &= ~I40E_FLAG_IWARP_ENABLED;
+ clear_bit(I40E_FLAG_IWARP_ENA, pf->flags);
}
}
@@ -16148,7 +16096,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
round_jiffies(jiffies + pf->service_timer_period));
/* add this PF to client device list and launch a client service task */
- if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
err = i40e_lan_add_device(pf);
if (err)
dev_info(&pdev->dev, "Failed to add PF to client API service list: %d\n",
@@ -16161,7 +16109,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* and will report PCI Gen 1 x 1 by default so don't bother
* checking them.
*/
- if (!(pf->hw_features & I40E_HW_NO_PCI_LINK_CHECK)) {
+ if (!test_bit(I40E_HW_CAP_NO_PCI_LINK_CHECK, pf->hw.caps)) {
char speed[PCI_SPEED_SIZE] = "Unknown";
char width[PCI_WIDTH_SIZE] = "Unknown";
@@ -16215,7 +16163,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pf->hw.phy.link_info.requested_speeds = abilities.link_speed;
/* set the FEC config due to the board capabilities */
- i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, &pf->flags);
+ i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, pf->flags);
/* get the supported phy types from the fw */
err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities, NULL);
@@ -16226,8 +16174,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* make sure the MFS hasn't been set lower than the default */
#define MAX_FRAME_SIZE_DEFAULT 0x2600
- val = (rd32(&pf->hw, I40E_PRTGL_SAH) &
- I40E_PRTGL_SAH_MFS_MASK) >> I40E_PRTGL_SAH_MFS_SHIFT;
+ val = FIELD_GET(I40E_PRTGL_SAH_MFS_MASK,
+ rd32(&pf->hw, I40E_PRTGL_SAH));
if (val < MAX_FRAME_SIZE_DEFAULT)
dev_warn(&pdev->dev, "MFS for port %x has been set below the default: %x\n",
pf->hw.port, val);
@@ -16242,10 +16190,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pf->main_vsi_seid);
if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) ||
- (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
- pf->hw_features |= I40E_HW_PHY_CONTROLS_LEDS;
+ (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
+ set_bit(I40E_HW_CAP_PHY_CONTROLS_LEDS, pf->hw.caps);
if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722)
- pf->hw_features |= I40E_HW_HAVE_CRT_RETIMER;
+ set_bit(I40E_HW_CAP_CRT_RETIMER, pf->hw.caps);
/* print a string summarizing features */
i40e_print_features(pf);
@@ -16314,10 +16262,10 @@ static void i40e_remove(struct pci_dev *pdev)
usleep_range(1000, 2000);
set_bit(__I40E_IN_REMOVE, pf->state);
- if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
+ if (test_bit(I40E_FLAG_SRIOV_ENA, pf->flags)) {
set_bit(__I40E_VF_RESETS_DISABLED, pf->state);
i40e_free_vfs(pf);
- pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
+ clear_bit(I40E_FLAG_SRIOV_ENA, pf->flags);
}
/* no more scheduling of any task */
set_bit(__I40E_SUSPENDED, pf->state);
@@ -16372,7 +16320,7 @@ static void i40e_remove(struct pci_dev *pdev)
i40e_cloud_filter_exit(pf);
/* remove attached clients */
- if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+ if (test_bit(I40E_FLAG_IWARP_ENA, pf->flags)) {
ret_code = i40e_lan_del_device(pf);
if (ret_code)
dev_warn(&pdev->dev, "Failed to delete client device: %d\n",
@@ -16391,7 +16339,7 @@ static void i40e_remove(struct pci_dev *pdev)
unmap:
/* Free MSI/legacy interrupt 0 when in recovery mode. */
if (test_bit(__I40E_RECOVERY_MODE, pf->state) &&
- !(pf->flags & I40E_FLAG_MSIX_ENABLED))
+ !test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
free_irq(pf->pdev->irq, pf);
/* shutdown the adminq */
@@ -16610,7 +16558,8 @@ static void i40e_shutdown(struct pci_dev *pdev)
*/
i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
- if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE))
+ if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) &&
+ pf->wol_en)
i40e_enable_mc_magic_wake(pf);
i40e_prep_for_reset(pf);
@@ -16622,7 +16571,7 @@ static void i40e_shutdown(struct pci_dev *pdev)
/* Free MSI/legacy interrupt 0 when in recovery mode. */
if (test_bit(__I40E_RECOVERY_MODE, pf->state) &&
- !(pf->flags & I40E_FLAG_MSIX_ENABLED))
+ !test_bit(I40E_FLAG_MSIX_ENA, pf->flags))
free_irq(pf->pdev->irq, pf);
/* Since we're going to destroy queues during the
@@ -16663,7 +16612,8 @@ static int __maybe_unused i40e_suspend(struct device *dev)
*/
i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
- if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE))
+ if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) &&
+ pf->wol_en)
i40e_enable_mc_magic_wake(pf);
/* Since we're going to destroy queues during the
diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
index 77cdbfc19d47..605fd82f5d20 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include "i40e_alloc.h"
#include "i40e_prototype.h"
@@ -26,8 +27,7 @@ int i40e_init_nvm(struct i40e_hw *hw)
* as the blank mode may be used in the factory line.
*/
gens = rd32(hw, I40E_GLNVM_GENS);
- sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
- I40E_GLNVM_GENS_SR_SIZE_SHIFT);
+ sr_size = FIELD_GET(I40E_GLNVM_GENS_SR_SIZE_MASK, gens);
/* Switching to words (sr_size contains power of 2KB) */
nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB;
@@ -193,9 +193,8 @@ static int i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset,
ret_code = i40e_poll_sr_srctl_done_bit(hw);
if (!ret_code) {
sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
- *data = (u16)((sr_reg &
- I40E_GLNVM_SRDATA_RDDATA_MASK)
- >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
+ *data = FIELD_GET(I40E_GLNVM_SRDATA_RDDATA_MASK,
+ sr_reg);
}
}
if (ret_code)
@@ -291,7 +290,7 @@ static int i40e_read_nvm_word_aq(struct i40e_hw *hw, u16 offset,
static int __i40e_read_nvm_word(struct i40e_hw *hw,
u16 offset, u16 *data)
{
- if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+ if (test_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps))
return i40e_read_nvm_word_aq(hw, offset, data);
return i40e_read_nvm_word_srctl(hw, offset, data);
@@ -310,14 +309,14 @@ int i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
{
int ret_code = 0;
- if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
+ if (test_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps))
ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
if (ret_code)
return ret_code;
ret_code = __i40e_read_nvm_word(hw, offset, data);
- if (hw->flags & I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK)
+ if (test_bit(I40E_HW_CAP_NVM_READ_REQUIRES_LOCK, hw->caps))
i40e_release_nvm(hw);
return ret_code;
@@ -499,7 +498,7 @@ static int __i40e_read_nvm_buffer(struct i40e_hw *hw,
u16 offset, u16 *words,
u16 *data)
{
- if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+ if (test_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps))
return i40e_read_nvm_buffer_aq(hw, offset, words, data);
return i40e_read_nvm_buffer_srctl(hw, offset, words, data);
@@ -521,7 +520,7 @@ int i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
{
int ret_code = 0;
- if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) {
+ if (test_bit(I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE, hw->caps)) {
ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
if (!ret_code) {
ret_code = i40e_read_nvm_buffer_aq(hw, offset, words,
@@ -771,13 +770,12 @@ static inline u8 i40e_nvmupd_get_module(u32 val)
}
static inline u8 i40e_nvmupd_get_transaction(u32 val)
{
- return (u8)((val & I40E_NVM_TRANS_MASK) >> I40E_NVM_TRANS_SHIFT);
+ return FIELD_GET(I40E_NVM_TRANS_MASK, val);
}
static inline u8 i40e_nvmupd_get_preservation_flags(u32 val)
{
- return (u8)((val & I40E_NVM_PRESERVATION_FLAGS_MASK) >>
- I40E_NVM_PRESERVATION_FLAGS_SHIFT);
+ return FIELD_GET(I40E_NVM_PRESERVATION_FLAGS_MASK, val);
}
static const char * const i40e_nvm_update_state_str[] = {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index 001162042050..ce1f11b8ad65 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -501,4 +501,73 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,
/* i40e_ddp */
int i40e_ddp_flash(struct net_device *netdev, struct ethtool_flash *flash);
+/* Firmware and AdminQ version check helpers */
+
+/**
+ * i40e_is_aq_api_ver_ge
+ * @hw: pointer to i40e_hw structure
+ * @maj: API major value to compare
+ * @min: API minor value to compare
+ *
+ * Assert whether current HW API version is greater/equal than provided.
+ **/
+static inline bool i40e_is_aq_api_ver_ge(struct i40e_hw *hw, u16 maj, u16 min)
+{
+ return (hw->aq.api_maj_ver > maj ||
+ (hw->aq.api_maj_ver == maj && hw->aq.api_min_ver >= min));
+}
+
+/**
+ * i40e_is_aq_api_ver_lt
+ * @hw: pointer to i40e_hw structure
+ * @maj: API major value to compare
+ * @min: API minor value to compare
+ *
+ * Assert whether current HW API version is less than provided.
+ **/
+static inline bool i40e_is_aq_api_ver_lt(struct i40e_hw *hw, u16 maj, u16 min)
+{
+ return !i40e_is_aq_api_ver_ge(hw, maj, min);
+}
+
+/**
+ * i40e_is_fw_ver_ge
+ * @hw: pointer to i40e_hw structure
+ * @maj: API major value to compare
+ * @min: API minor value to compare
+ *
+ * Assert whether current firmware version is greater/equal than provided.
+ **/
+static inline bool i40e_is_fw_ver_ge(struct i40e_hw *hw, u16 maj, u16 min)
+{
+ return (hw->aq.fw_maj_ver > maj ||
+ (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver >= min));
+}
+
+/**
+ * i40e_is_fw_ver_lt
+ * @hw: pointer to i40e_hw structure
+ * @maj: API major value to compare
+ * @min: API minor value to compare
+ *
+ * Assert whether current firmware version is less than provided.
+ **/
+static inline bool i40e_is_fw_ver_lt(struct i40e_hw *hw, u16 maj, u16 min)
+{
+ return !i40e_is_fw_ver_ge(hw, maj, min);
+}
+
+/**
+ * i40e_is_fw_ver_eq
+ * @hw: pointer to i40e_hw structure
+ * @maj: API major value to compare
+ * @min: API minor value to compare
+ *
+ * Assert whether current firmware version is equal to provided.
+ **/
+static inline bool i40e_is_fw_ver_eq(struct i40e_hw *hw, u16 maj, u16 min)
+{
+ return (hw->aq.fw_maj_ver == maj && hw->aq.fw_min_ver == min);
+}
+
#endif /* _I40E_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 20b77398f060..e7ebcb09f23c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -35,7 +35,7 @@ enum i40e_ptp_pin {
GPIO_4
};
-enum i40e_can_set_pins_t {
+enum i40e_can_set_pins {
CANT_DO_PINS = -1,
CAN_SET_PINS,
CAN_DO_PINS
@@ -193,7 +193,7 @@ static bool i40e_is_ptp_pin_dev(struct i40e_hw *hw)
* return CAN_DO_PINS if pins can be manipulated within a NIC or
* return CANT_DO_PINS otherwise.
**/
-static enum i40e_can_set_pins_t i40e_can_set_pins(struct i40e_pf *pf)
+static enum i40e_can_set_pins i40e_can_set_pins(struct i40e_pf *pf)
{
if (!i40e_is_ptp_pin_dev(&pf->hw)) {
dev_warn(&pf->pdev->dev,
@@ -680,7 +680,7 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf)
* configured. We don't want to spuriously warn about Rx timestamp
* hangs if we don't care about the timestamps.
*/
- if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx)
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_rx)
return;
spin_lock_bh(&pf->ptp_rx_lock);
@@ -733,7 +733,7 @@ void i40e_ptp_tx_hang(struct i40e_pf *pf)
{
struct sk_buff *skb;
- if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_tx)
return;
/* Nothing to do if we're not already waiting for a timestamp */
@@ -771,7 +771,7 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf)
u32 hi, lo;
u64 ns;
- if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_tx)
return;
/* don't attempt to timestamp if we don't have an skb */
@@ -818,7 +818,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index)
/* Since we cannot turn off the Rx timestamp logic if the device is
* doing Tx timestamping, check if Rx timestamping is configured.
*/
- if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx)
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags) || !pf->ptp_rx)
return;
hw = &pf->hw;
@@ -924,7 +924,7 @@ int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
{
struct hwtstamp_config *config = &pf->tstamp_config;
- if (!(pf->flags & I40E_FLAG_PTP))
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags))
return -EOPNOTSUPP;
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
@@ -1071,7 +1071,7 @@ static void i40e_ptp_set_pins_hw(struct i40e_pf *pf)
static int i40e_ptp_set_pins(struct i40e_pf *pf,
struct i40e_ptp_pins_settings *pins)
{
- enum i40e_can_set_pins_t pin_caps = i40e_can_set_pins(pf);
+ enum i40e_can_set_pins pin_caps = i40e_can_set_pins(pf);
int i = 0;
if (pin_caps == CANT_DO_PINS)
@@ -1211,7 +1211,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
- if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE))
+ if (!test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps))
return -ERANGE;
pf->ptp_rx = true;
tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK |
@@ -1225,7 +1225,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
- if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE))
+ if (!test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps))
return -ERANGE;
fallthrough;
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
@@ -1234,7 +1234,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
pf->ptp_rx = true;
tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK |
I40E_PRTTSYN_CTL1_TSYNTYPE_V2;
- if (pf->hw_features & I40E_HW_PTP_L4_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_PTP_L4, pf->hw.caps)) {
tsyntype |= I40E_PRTTSYN_CTL1_UDP_ENA_MASK;
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
} else {
@@ -1308,7 +1308,7 @@ int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr)
struct hwtstamp_config config;
int err;
- if (!(pf->flags & I40E_FLAG_PTP))
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags))
return -EOPNOTSUPP;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
@@ -1426,7 +1426,7 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf)
void i40e_ptp_save_hw_time(struct i40e_pf *pf)
{
/* don't try to access the PTP clock if it's not enabled */
- if (!(pf->flags & I40E_FLAG_PTP))
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags))
return;
i40e_ptp_gettimex(&pf->ptp_caps, &pf->ptp_prev_hw_time, NULL);
@@ -1480,10 +1480,10 @@ void i40e_ptp_init(struct i40e_pf *pf)
/* Only one PF is assigned to control 1588 logic per port. Do not
* enable any support for PFs not assigned via PRTTSYN_CTL0.PF_ID
*/
- pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >>
- I40E_PRTTSYN_CTL0_PF_ID_SHIFT;
+ pf_id = FIELD_GET(I40E_PRTTSYN_CTL0_PF_ID_MASK,
+ rd32(hw, I40E_PRTTSYN_CTL0));
if (hw->pf_id != pf_id) {
- pf->flags &= ~I40E_FLAG_PTP;
+ clear_bit(I40E_FLAG_PTP_ENA, pf->flags);
dev_info(&pf->pdev->dev, "%s: PTP not supported on %s\n",
__func__,
netdev->name);
@@ -1504,7 +1504,7 @@ void i40e_ptp_init(struct i40e_pf *pf)
if (pf->hw.debug_mask & I40E_DEBUG_LAN)
dev_info(&pf->pdev->dev, "PHC enabled\n");
- pf->flags |= I40E_FLAG_PTP;
+ set_bit(I40E_FLAG_PTP_ENA, pf->flags);
/* Ensure the clocks are running. */
regval = rd32(hw, I40E_PRTTSYN_CTL0);
@@ -1539,7 +1539,7 @@ void i40e_ptp_stop(struct i40e_pf *pf)
struct i40e_hw *hw = &pf->hw;
u32 regval;
- pf->flags &= ~I40E_FLAG_PTP;
+ clear_bit(I40E_FLAG_PTP_ENA, pf->flags);
pf->ptp_tx = false;
pf->ptp_rx = false;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h
index f6671ac79735..14ab642cafdb 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_register.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_register.h
@@ -863,16 +863,6 @@
#define I40E_PFPM_WUFC 0x0006B400 /* Reset: POR */
#define I40E_PFPM_WUFC_MAG_SHIFT 1
#define I40E_PFPM_WUFC_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MAG_SHIFT)
-#define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */
-#define I40E_VF_ARQBAL1 0x00006C00 /* Reset: EMPR */
-#define I40E_VF_ARQH1 0x00007400 /* Reset: EMPR */
-#define I40E_VF_ARQLEN1 0x00008000 /* Reset: EMPR */
-#define I40E_VF_ARQT1 0x00007000 /* Reset: EMPR */
-#define I40E_VF_ATQBAH1 0x00007800 /* Reset: EMPR */
-#define I40E_VF_ATQBAL1 0x00007C00 /* Reset: EMPR */
-#define I40E_VF_ATQH1 0x00006400 /* Reset: EMPR */
-#define I40E_VF_ATQLEN1 0x00006800 /* Reset: EMPR */
-#define I40E_VF_ATQT1 0x00008400 /* Reset: EMPR */
#define I40E_VFQF_HLUT_MAX_INDEX 15
@@ -899,6 +889,7 @@
#define I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT 7
#define I40E_GLQF_ORT_FLX_PAYLOAD_MASK I40E_MASK(0x1, I40E_GLQF_ORT_FLX_PAYLOAD_SHIFT)
#define I40E_GLQF_FDEVICTENA(_i) (0x00270384 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */
+#define I40E_FDEVICT_PCTYPE_DEFAULT 0xc03
/* Redefined for X722 family */
#define I40E_GLGEN_STAT_CLEAR 0x00390004 /* Reset: CORER */
#endif /* _I40E_REGISTER_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index dd410b15000f..0d7177083708 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -33,19 +33,16 @@ static void i40e_fdir(struct i40e_ring *tx_ring,
i++;
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
- flex_ptype = I40E_TXD_FLTR_QW0_QINDEX_MASK &
- (fdata->q_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT);
+ flex_ptype = FIELD_PREP(I40E_TXD_FLTR_QW0_QINDEX_MASK, fdata->q_index);
- flex_ptype |= I40E_TXD_FLTR_QW0_FLEXOFF_MASK &
- (fdata->flex_off << I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT);
+ flex_ptype |= FIELD_PREP(I40E_TXD_FLTR_QW0_FLEXOFF_MASK,
+ fdata->flex_off);
- flex_ptype |= I40E_TXD_FLTR_QW0_PCTYPE_MASK &
- (fdata->pctype << I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
+ flex_ptype |= FIELD_PREP(I40E_TXD_FLTR_QW0_PCTYPE_MASK, fdata->pctype);
/* Use LAN VSI Id if not programmed by user */
- flex_ptype |= I40E_TXD_FLTR_QW0_DEST_VSI_MASK &
- ((u32)(fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id) <<
- I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT);
+ flex_ptype |= FIELD_PREP(I40E_TXD_FLTR_QW0_DEST_VSI_MASK,
+ fdata->dest_vsi ? : pf->vsi[pf->lan_vsi]->id);
dtype_cmd = I40E_TX_DESC_DTYPE_FILTER_PROG;
@@ -55,17 +52,15 @@ static void i40e_fdir(struct i40e_ring *tx_ring,
I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
I40E_TXD_FLTR_QW1_PCMD_SHIFT;
- dtype_cmd |= I40E_TXD_FLTR_QW1_DEST_MASK &
- (fdata->dest_ctl << I40E_TXD_FLTR_QW1_DEST_SHIFT);
+ dtype_cmd |= FIELD_PREP(I40E_TXD_FLTR_QW1_DEST_MASK, fdata->dest_ctl);
- dtype_cmd |= I40E_TXD_FLTR_QW1_FD_STATUS_MASK &
- (fdata->fd_status << I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT);
+ dtype_cmd |= FIELD_PREP(I40E_TXD_FLTR_QW1_FD_STATUS_MASK,
+ fdata->fd_status);
if (fdata->cnt_index) {
dtype_cmd |= I40E_TXD_FLTR_QW1_CNT_ENA_MASK;
- dtype_cmd |= I40E_TXD_FLTR_QW1_CNTINDEX_MASK &
- ((u32)fdata->cnt_index <<
- I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT);
+ dtype_cmd |= FIELD_PREP(I40E_TXD_FLTR_QW1_CNTINDEX_MASK,
+ fdata->cnt_index);
}
fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
@@ -464,7 +459,7 @@ static int i40e_add_del_fdir_tcp(struct i40e_vsi *vsi,
&pf->fd_tcp6_filter_cnt);
if (add) {
- if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+ if (test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags) &&
I40E_DEBUG_FD & pf->hw.debug_mask)
dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
@@ -691,8 +686,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u64 qword0_raw,
u32 error;
qw0 = (struct i40e_16b_rx_wb_qw0 *)&qword0_raw;
- error = (qword1 & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>
- I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
+ error = FIELD_GET(I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK, qword1);
if (error == BIT(I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {
pf->fd_inv = le32_to_cpu(qw0->hi_dword.fd_id);
@@ -734,7 +728,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u64 qword0_raw,
* FD ATR/SB and then re-enable it when there is room.
*/
if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
- if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+ if (test_bit(I40E_FLAG_FD_SB_ENA, pf->flags) &&
!test_and_set_bit(__I40E_FD_SB_AUTO_DISABLED,
pf->state))
if (I40E_DEBUG_FD & pf->hw.debug_mask)
@@ -1071,7 +1065,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
if (q_vector->arm_wb_state)
return;
- if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) {
val = I40E_PFINT_DYN_CTLN_WB_ON_ITR_MASK |
I40E_PFINT_DYN_CTLN_ITR_INDX_MASK; /* set noitr */
@@ -1095,7 +1089,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi,
**/
void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
{
- if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+ if (test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) {
u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
I40E_PFINT_DYN_CTLN_ITR_INDX_MASK | /* set noitr */
I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK |
@@ -1403,8 +1397,7 @@ void i40e_clean_programming_status(struct i40e_ring *rx_ring, u64 qword0_raw,
{
u8 id;
- id = (qword1 & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >>
- I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
+ id = FIELD_GET(I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK, qword1);
if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
i40e_fd_handle_status(rx_ring, qword0_raw, qword1, id);
@@ -1555,7 +1548,6 @@ void i40e_free_rx_resources(struct i40e_ring *rx_ring)
int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
{
struct device *dev = rx_ring->dev;
- int err;
u64_stats_init(&rx_ring->syncp);
@@ -1576,14 +1568,6 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
rx_ring->next_to_process = 0;
rx_ring->next_to_use = 0;
- /* XDP RX-queue info only needed for RX rings exposed to XDP */
- if (rx_ring->vsi->type == I40E_VSI_MAIN) {
- err = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev,
- rx_ring->queue_index, rx_ring->q_vector->napi.napi_id);
- if (err < 0)
- return err;
- }
-
rx_ring->xdp_prog = rx_ring->vsi->xdp_prog;
rx_ring->rx_bi =
@@ -1764,11 +1748,9 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
u64 qword;
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT;
- rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >>
- I40E_RXD_QW1_ERROR_SHIFT;
- rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
- I40E_RXD_QW1_STATUS_SHIFT;
+ ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, qword);
+ rx_error = FIELD_GET(I40E_RXD_QW1_ERROR_MASK, qword);
+ rx_status = FIELD_GET(I40E_RXD_QW1_STATUS_MASK, qword);
decoded = decode_rx_desc_ptype(ptype);
skb->ip_summed = CHECKSUM_NONE;
@@ -1901,13 +1883,10 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,
union i40e_rx_desc *rx_desc, struct sk_buff *skb)
{
u64 qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- u32 rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
- I40E_RXD_QW1_STATUS_SHIFT;
+ u32 rx_status = FIELD_GET(I40E_RXD_QW1_STATUS_MASK, qword);
u32 tsynvalid = rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK;
- u32 tsyn = (rx_status & I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
- I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT;
- u8 rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >>
- I40E_RXD_QW1_PTYPE_SHIFT;
+ u32 tsyn = FIELD_GET(I40E_RXD_QW1_STATUS_TSYNINDX_MASK, rx_status);
+ u8 rx_ptype = FIELD_GET(I40E_RXD_QW1_PTYPE_MASK, qword);
if (unlikely(tsynvalid))
i40e_ptp_rx_hwtstamp(rx_ring->vsi->back, skb, tsyn);
@@ -2099,7 +2078,8 @@ static void i40e_put_rx_buffer(struct i40e_ring *rx_ring,
static void i40e_process_rx_buffs(struct i40e_ring *rx_ring, int xdp_res,
struct xdp_buff *xdp)
{
- u32 next = rx_ring->next_to_clean;
+ u32 nr_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags;
+ u32 next = rx_ring->next_to_clean, i = 0;
struct i40e_rx_buffer *rx_buffer;
xdp->flags = 0;
@@ -2112,10 +2092,10 @@ static void i40e_process_rx_buffs(struct i40e_ring *rx_ring, int xdp_res,
if (!rx_buffer->page)
continue;
- if (xdp_res == I40E_XDP_CONSUMED)
- rx_buffer->pagecnt_bias++;
- else
+ if (xdp_res != I40E_XDP_CONSUMED)
i40e_rx_buffer_flip(rx_buffer, xdp->frame_sz);
+ else if (i++ <= nr_frags)
+ rx_buffer->pagecnt_bias++;
/* EOP buffer will be put in i40e_clean_rx_irq() */
if (next == rx_ring->next_to_process)
@@ -2129,20 +2109,20 @@ static void i40e_process_rx_buffs(struct i40e_ring *rx_ring, int xdp_res,
* i40e_construct_skb - Allocate skb and populate it
* @rx_ring: rx descriptor ring to transact packets on
* @xdp: xdp_buff pointing to the data
- * @nr_frags: number of buffers for the packet
*
* This function allocates an skb. It then populates it with the page
* data from the current receive descriptor, taking care to set up the
* skb correctly.
*/
static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
- struct xdp_buff *xdp,
- u32 nr_frags)
+ struct xdp_buff *xdp)
{
unsigned int size = xdp->data_end - xdp->data;
struct i40e_rx_buffer *rx_buffer;
+ struct skb_shared_info *sinfo;
unsigned int headlen;
struct sk_buff *skb;
+ u32 nr_frags = 0;
/* prefetch first cache line of first page */
net_prefetch(xdp->data);
@@ -2180,6 +2160,10 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
memcpy(__skb_put(skb, headlen), xdp->data,
ALIGN(headlen, sizeof(long)));
+ if (unlikely(xdp_buff_has_frags(xdp))) {
+ sinfo = xdp_get_shared_info_from_buff(xdp);
+ nr_frags = sinfo->nr_frags;
+ }
rx_buffer = i40e_rx_bi(rx_ring, rx_ring->next_to_clean);
/* update all of the pointers */
size -= headlen;
@@ -2199,9 +2183,8 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
}
if (unlikely(xdp_buff_has_frags(xdp))) {
- struct skb_shared_info *sinfo, *skinfo = skb_shinfo(skb);
+ struct skb_shared_info *skinfo = skb_shinfo(skb);
- sinfo = xdp_get_shared_info_from_buff(xdp);
memcpy(&skinfo->frags[skinfo->nr_frags], &sinfo->frags[0],
sizeof(skb_frag_t) * nr_frags);
@@ -2224,17 +2207,17 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
* i40e_build_skb - Build skb around an existing buffer
* @rx_ring: Rx descriptor ring to transact packets on
* @xdp: xdp_buff pointing to the data
- * @nr_frags: number of buffers for the packet
*
* This function builds an skb around an existing Rx buffer, taking care
* to set up the skb correctly and avoid any memcpy overhead.
*/
static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
- struct xdp_buff *xdp,
- u32 nr_frags)
+ struct xdp_buff *xdp)
{
unsigned int metasize = xdp->data - xdp->data_meta;
+ struct skb_shared_info *sinfo;
struct sk_buff *skb;
+ u32 nr_frags;
/* Prefetch first cache line of first page. If xdp->data_meta
* is unused, this points exactly as xdp->data, otherwise we
@@ -2243,6 +2226,11 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
*/
net_prefetch(xdp->data_meta);
+ if (unlikely(xdp_buff_has_frags(xdp))) {
+ sinfo = xdp_get_shared_info_from_buff(xdp);
+ nr_frags = sinfo->nr_frags;
+ }
+
/* build an skb around the page buffer */
skb = napi_build_skb(xdp->data_hard_start, xdp->frame_sz);
if (unlikely(!skb))
@@ -2255,9 +2243,6 @@ static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
skb_metadata_set(skb, metasize);
if (unlikely(xdp_buff_has_frags(xdp))) {
- struct skb_shared_info *sinfo;
-
- sinfo = xdp_get_shared_info_from_buff(xdp);
xdp_update_skb_shared_info(skb, nr_frags,
sinfo->xdp_frags_size,
nr_frags * xdp->frame_sz,
@@ -2554,8 +2539,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
continue;
}
- size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
- I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
+ size = FIELD_GET(I40E_RXD_QW1_LENGTH_PBUF_MASK, qword);
if (!size)
break;
@@ -2602,9 +2586,9 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget,
total_rx_bytes += size;
} else {
if (ring_uses_build_skb(rx_ring))
- skb = i40e_build_skb(rx_ring, xdp, nfrags);
+ skb = i40e_build_skb(rx_ring, xdp);
else
- skb = i40e_construct_skb(rx_ring, xdp, nfrags);
+ skb = i40e_construct_skb(rx_ring, xdp);
/* drop if we failed to retrieve a buffer */
if (!skb) {
@@ -2699,7 +2683,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi,
u32 intval;
/* If we don't have MSIX, then we only need to re-enable icr0 */
- if (!(vsi->back->flags & I40E_FLAG_MSIX_ENABLED)) {
+ if (!test_bit(I40E_FLAG_MSIX_ENA, vsi->back->flags)) {
i40e_irq_dynamic_enable_icr0(vsi->back);
return;
}
@@ -2888,7 +2872,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
u16 i;
/* make sure ATR is enabled */
- if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
+ if (!test_bit(I40E_FLAG_FD_ATR_ENA, pf->flags))
return;
if (test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
@@ -2933,7 +2917,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
/* Due to lack of space, no more new filters can be programmed */
if (th->syn && test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
return;
- if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) {
+ if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags)) {
/* HW ATR eviction will take care of removing filters on FIN
* and RST packets.
*/
@@ -2959,8 +2943,8 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
i++;
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
- flex_ptype = (tx_ring->queue_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
- I40E_TXD_FLTR_QW0_QINDEX_MASK;
+ flex_ptype = FIELD_PREP(I40E_TXD_FLTR_QW0_QINDEX_MASK,
+ tx_ring->queue_index);
flex_ptype |= (tx_flags & I40E_TX_FLAGS_IPV4) ?
(I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
@@ -2986,16 +2970,14 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
dtype_cmd |= I40E_TXD_FLTR_QW1_CNT_ENA_MASK;
if (!(tx_flags & I40E_TX_FLAGS_UDP_TUNNEL))
dtype_cmd |=
- ((u32)I40E_FD_ATR_STAT_IDX(pf->hw.pf_id) <<
- I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
- I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
+ FIELD_PREP(I40E_TXD_FLTR_QW1_CNTINDEX_MASK,
+ I40E_FD_ATR_STAT_IDX(pf->hw.pf_id));
else
dtype_cmd |=
- ((u32)I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id) <<
- I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) &
- I40E_TXD_FLTR_QW1_CNTINDEX_MASK;
+ FIELD_PREP(I40E_TXD_FLTR_QW1_CNTINDEX_MASK,
+ I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id));
- if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED)
+ if (test_bit(I40E_FLAG_HW_ATR_EVICT_ENA, pf->flags))
dtype_cmd |= I40E_TXD_FLTR_QW1_ATR_MASK;
fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
@@ -3053,7 +3035,7 @@ static inline int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
tx_flags |= I40E_TX_FLAGS_SW_VLAN;
}
- if (!(tx_ring->vsi->back->flags & I40E_FLAG_DCB_ENABLED))
+ if (!test_bit(I40E_FLAG_DCB_ENA, tx_ring->vsi->back->flags))
goto out;
/* Insert 802.1p priority into VLAN header */
@@ -3229,7 +3211,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
* we are not already transmitting a packet to be timestamped
*/
pf = i40e_netdev_to_pf(tx_ring->netdev);
- if (!(pf->flags & I40E_FLAG_PTP))
+ if (!test_bit(I40E_FLAG_PTP_ENA, pf->flags))
return 0;
if (pf->ptp_tx &&
@@ -3601,8 +3583,7 @@ static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
- td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >>
- I40E_TX_FLAGS_VLAN_SHIFT;
+ td_tag = FIELD_GET(I40E_TX_FLAGS_VLAN_MASK, tx_flags);
}
first->tx_flags = tx_flags;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
index 421fe5675584..abf15067eb5d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
@@ -58,7 +58,7 @@ static inline u16 i40e_intrl_usec_to_reg(int intrl)
* mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any
* register but instead is a special value meaning "don't update" ITR0/1/2.
*/
-enum i40e_dyn_idx_t {
+enum i40e_dyn_idx {
I40E_IDX_ITR0 = 0,
I40E_IDX_ITR1 = 1,
I40E_IDX_ITR2 = 2,
@@ -92,8 +92,8 @@ enum i40e_dyn_idx_t {
BIT_ULL(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
#define i40e_pf_get_default_rss_hena(pf) \
- (((pf)->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \
- I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA)
+ (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, (pf)->hw.caps) ? \
+ I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA)
/* Supported Rx Buffer Sizes (a multiple of 128) */
#define I40E_RXBUFFER_256 256
@@ -306,7 +306,7 @@ struct i40e_rx_queue_stats {
u64 page_busy_count;
};
-enum i40e_ring_state_t {
+enum i40e_ring_state {
__I40E_TX_FDIR_INIT_DONE,
__I40E_TX_XPS_INIT_DONE,
__I40E_RING_STATE_NBITS /* must be last */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index f95bc2a4a838..d9031499697e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -64,9 +64,7 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
enum i40e_mac_type {
I40E_MAC_UNKNOWN = 0,
I40E_MAC_XL710,
- I40E_MAC_VF,
I40E_MAC_X722,
- I40E_MAC_X722_VF,
I40E_MAC_GENERIC,
};
@@ -272,9 +270,7 @@ struct i40e_mac_info {
enum i40e_mac_type type;
u8 addr[ETH_ALEN];
u8 perm_addr[ETH_ALEN];
- u8 san_addr[ETH_ALEN];
u8 port_addr[ETH_ALEN];
- u16 max_fcoeq;
};
enum i40e_aq_resources_ids {
@@ -482,6 +478,36 @@ struct i40e_dcbx_config {
struct i40e_dcb_app_priority_table app[I40E_DCBX_MAX_APPS];
};
+enum i40e_hw_flags {
+ I40E_HW_CAP_AQ_SRCTL_ACCESS_ENABLE,
+ I40E_HW_CAP_802_1AD,
+ I40E_HW_CAP_AQ_PHY_ACCESS,
+ I40E_HW_CAP_NVM_READ_REQUIRES_LOCK,
+ I40E_HW_CAP_FW_LLDP_STOPPABLE,
+ I40E_HW_CAP_FW_LLDP_PERSISTENT,
+ I40E_HW_CAP_AQ_PHY_ACCESS_EXTENDED,
+ I40E_HW_CAP_X722_FEC_REQUEST,
+ I40E_HW_CAP_RSS_AQ,
+ I40E_HW_CAP_128_QP_RSS,
+ I40E_HW_CAP_ATR_EVICT,
+ I40E_HW_CAP_WB_ON_ITR,
+ I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE,
+ I40E_HW_CAP_NO_PCI_LINK_CHECK,
+ I40E_HW_CAP_100M_SGMII,
+ I40E_HW_CAP_NO_DCB_SUPPORT,
+ I40E_HW_CAP_USE_SET_LLDP_MIB,
+ I40E_HW_CAP_GENEVE_OFFLOAD,
+ I40E_HW_CAP_PTP_L4,
+ I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE,
+ I40E_HW_CAP_CRT_RETIMER,
+ I40E_HW_CAP_OUTER_UDP_CSUM,
+ I40E_HW_CAP_PHY_CONTROLS_LEDS,
+ I40E_HW_CAP_STOP_FW_LLDP,
+ I40E_HW_CAP_PORT_ID_VALID,
+ I40E_HW_CAP_RESTART_AUTONEG,
+ I40E_HW_CAPS_NBITS,
+};
+
/* Port hardware description */
struct i40e_hw {
u8 __iomem *hw_addr;
@@ -546,16 +572,7 @@ struct i40e_hw {
struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */
struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */
-#define I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE BIT_ULL(0)
-#define I40E_HW_FLAG_802_1AD_CAPABLE BIT_ULL(1)
-#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE BIT_ULL(2)
-#define I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK BIT_ULL(3)
-#define I40E_HW_FLAG_FW_LLDP_STOPPABLE BIT_ULL(4)
-#define I40E_HW_FLAG_FW_LLDP_PERSISTENT BIT_ULL(5)
-#define I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED BIT_ULL(6)
-#define I40E_HW_FLAG_DROP_MODE BIT_ULL(7)
-#define I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE BIT_ULL(8)
- u64 flags;
+ DECLARE_BITMAP(caps, I40E_HW_CAPS_NBITS);
/* Used in set switch config AQ command */
u16 switch_tag;
@@ -567,12 +584,6 @@ struct i40e_hw {
char err_str[16];
};
-static inline bool i40e_is_vf(struct i40e_hw *hw)
-{
- return (hw->mac.type == I40E_MAC_VF ||
- hw->mac.type == I40E_MAC_X722_VF);
-}
-
struct i40e_driver_version {
u8 major_version;
u8 minor_version;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index de5ec4e6bedf..b34c71770887 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -500,10 +500,10 @@ static void i40e_release_rdma_qvlist(struct i40e_vf *vf)
*/
reg_idx = (msix_vf - 1) * vf->vf_id + qv_info->ceq_idx;
reg = rd32(hw, I40E_VPINT_CEQCTL(reg_idx));
- next_q_index = (reg & I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK)
- >> I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT;
- next_q_type = (reg & I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK)
- >> I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT;
+ next_q_index = FIELD_GET(I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK,
+ reg);
+ next_q_type = FIELD_GET(I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK,
+ reg);
reg_idx = ((msix_vf - 1) * vf->vf_id) + (v_idx - 1);
reg = (next_q_index &
@@ -581,10 +581,10 @@ i40e_config_rdma_qvlist(struct i40e_vf *vf,
* queue on top. Also link it with the new queue in CEQCTL.
*/
reg = rd32(hw, I40E_VPINT_LNKLSTN(reg_idx));
- next_q_idx = ((reg & I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK) >>
- I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT);
- next_q_type = ((reg & I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK) >>
- I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
+ next_q_idx = FIELD_GET(I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK,
+ reg);
+ next_q_type = FIELD_GET(I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK,
+ reg);
if (qv_info->ceq_idx != I40E_QUEUE_INVALID_IDX) {
reg_idx = (msix_vf - 1) * vf->vf_id + qv_info->ceq_idx;
@@ -685,11 +685,9 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id,
/* associate this queue with the PCI VF function */
qtx_ctl = I40E_QTX_CTL_VF_QUEUE;
- qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT)
- & I40E_QTX_CTL_PF_INDX_MASK);
- qtx_ctl |= (((vf->vf_id + hw->func_caps.vf_base_id)
- << I40E_QTX_CTL_VFVM_INDX_SHIFT)
- & I40E_QTX_CTL_VFVM_INDX_MASK);
+ qtx_ctl |= FIELD_PREP(I40E_QTX_CTL_PF_INDX_MASK, hw->pf_id);
+ qtx_ctl |= FIELD_PREP(I40E_QTX_CTL_VFVM_INDX_MASK,
+ vf->vf_id + hw->func_caps.vf_base_id);
wr32(hw, I40E_QTX_CTL(pf_queue_id), qtx_ctl);
i40e_flush(hw);
@@ -1834,7 +1832,7 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
if (pci_num_vf(pf->pdev) != num_alloc_vfs) {
ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
if (ret) {
- pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+ clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
pf->num_alloc_vfs = 0;
goto err_iov;
}
@@ -1945,8 +1943,8 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
}
if (num_vfs) {
- if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
- pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+ if (!test_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags)) {
+ set_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
i40e_do_reset_safe(pf, I40E_PF_RESET_AND_REBUILD_FLAG);
}
ret = i40e_pci_sriov_enable(pdev, num_vfs);
@@ -1955,7 +1953,7 @@ int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
if (!pci_vfs_assigned(pf->pdev)) {
i40e_free_vfs(pf);
- pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+ clear_bit(I40E_FLAG_VEB_MODE_ENA, pf->flags);
i40e_do_reset_safe(pf, I40E_PF_RESET_AND_REBUILD_FLAG);
} else {
dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
@@ -2163,14 +2161,14 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
} else {
- if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) &&
+ if (test_bit(I40E_HW_CAP_RSS_AQ, pf->hw.caps) &&
(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ))
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ;
else
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG;
}
- if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+ if (test_bit(I40E_HW_CAP_MULTI_TCP_UDP_RSS_PCTYPE, pf->hw.caps)) {
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
vfres->vf_cap_flags |=
VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
@@ -2179,12 +2177,12 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP;
- if ((pf->hw_features & I40E_HW_OUTER_UDP_CSUM_CAPABLE) &&
+ if (test_bit(I40E_HW_CAP_OUTER_UDP_CSUM, pf->hw.caps) &&
(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM))
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM;
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) {
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
dev_err(&pf->pdev->dev,
"VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n",
vf->vf_id);
@@ -2194,7 +2192,7 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING;
}
- if (pf->hw_features & I40E_HW_WB_ON_ITR_CAPABLE) {
+ if (test_bit(I40E_HW_CAP_WB_ON_ITR, pf->hw.caps)) {
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
vfres->vf_cap_flags |=
VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
@@ -2607,6 +2605,14 @@ static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
int aq_ret = 0;
int i;
+ if (vf->is_disabled_from_host) {
+ aq_ret = -EPERM;
+ dev_info(&pf->pdev->dev,
+ "Admin has disabled VF %d, will not enable queues\n",
+ vf->vf_id);
+ goto error_param;
+ }
+
if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
aq_ret = -EINVAL;
goto error_param;
@@ -2842,6 +2848,24 @@ error_param:
(u8 *)&stats, sizeof(stats));
}
+/**
+ * i40e_can_vf_change_mac
+ * @vf: pointer to the VF info
+ *
+ * Return true if the VF is allowed to change its MAC filters, false otherwise
+ */
+static bool i40e_can_vf_change_mac(struct i40e_vf *vf)
+{
+ /* If the VF MAC address has been set administratively (via the
+ * ndo_set_vf_mac command), then deny permission to the VF to
+ * add/delete unicast MAC addresses, unless the VF is trusted
+ */
+ if (vf->pf_set_mac && !vf->trusted)
+ return false;
+
+ return true;
+}
+
#define I40E_MAX_MACVLAN_PER_HW 3072
#define I40E_MAX_MACVLAN_PER_PF(num_ports) (I40E_MAX_MACVLAN_PER_HW / \
(num_ports))
@@ -2901,8 +2925,8 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf,
* The VF may request to set the MAC address filter already
* assigned to it so do not return an error in that case.
*/
- if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
- !is_multicast_ether_addr(addr) && vf->pf_set_mac &&
+ if (!i40e_can_vf_change_mac(vf) &&
+ !is_multicast_ether_addr(addr) &&
!ether_addr_equal(addr, vf->default_lan_addr.addr)) {
dev_err(&pf->pdev->dev,
"VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
@@ -3108,19 +3132,29 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
ret = -EINVAL;
goto error_param;
}
- if (ether_addr_equal(al->list[i].addr, vf->default_lan_addr.addr))
- was_unimac_deleted = true;
}
vsi = pf->vsi[vf->lan_vsi_idx];
spin_lock_bh(&vsi->mac_filter_hash_lock);
/* delete addresses from the list */
- for (i = 0; i < al->num_elements; i++)
+ for (i = 0; i < al->num_elements; i++) {
+ const u8 *addr = al->list[i].addr;
+
+ /* Allow to delete VF primary MAC only if it was not set
+ * administratively by PF or if VF is trusted.
+ */
+ if (ether_addr_equal(addr, vf->default_lan_addr.addr) &&
+ i40e_can_vf_change_mac(vf))
+ was_unimac_deleted = true;
+ else
+ continue;
+
if (i40e_del_mac_filter(vsi, al->list[i].addr)) {
ret = -EINVAL;
spin_unlock_bh(&vsi->mac_filter_hash_lock);
goto error_param;
}
+ }
spin_unlock_bh(&vsi->mac_filter_hash_lock);
@@ -4701,9 +4735,8 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
ivi->max_tx_rate = vf->tx_rate;
ivi->min_tx_rate = 0;
- ivi->vlan = le16_to_cpu(vsi->info.pvid) & I40E_VLAN_MASK;
- ivi->qos = (le16_to_cpu(vsi->info.pvid) & I40E_PRIORITY_MASK) >>
- I40E_VLAN_PRIORITY_SHIFT;
+ ivi->vlan = le16_get_bits(vsi->info.pvid, I40E_VLAN_MASK);
+ ivi->qos = le16_get_bits(vsi->info.pvid, I40E_PRIORITY_MASK);
if (vf->link_forced == false)
ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
else if (vf->link_up == true)
@@ -4734,9 +4767,12 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
struct i40e_link_status *ls = &pf->hw.phy.link_info;
struct virtchnl_pf_event pfe;
struct i40e_hw *hw = &pf->hw;
+ struct i40e_vsi *vsi;
+ unsigned long q_map;
struct i40e_vf *vf;
int abs_vf_id;
int ret = 0;
+ int tmp;
if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
@@ -4759,17 +4795,38 @@ int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
switch (link) {
case IFLA_VF_LINK_STATE_AUTO:
vf->link_forced = false;
+ vf->is_disabled_from_host = false;
+ /* reset needed to reinit VF resources */
+ i40e_vc_reset_vf(vf, true);
i40e_set_vf_link_state(vf, &pfe, ls);
break;
case IFLA_VF_LINK_STATE_ENABLE:
vf->link_forced = true;
vf->link_up = true;
+ vf->is_disabled_from_host = false;
+ /* reset needed to reinit VF resources */
+ i40e_vc_reset_vf(vf, true);
i40e_set_vf_link_state(vf, &pfe, ls);
break;
case IFLA_VF_LINK_STATE_DISABLE:
vf->link_forced = true;
vf->link_up = false;
i40e_set_vf_link_state(vf, &pfe, ls);
+
+ vsi = pf->vsi[vf->lan_vsi_idx];
+ q_map = BIT(vsi->num_queue_pairs) - 1;
+
+ vf->is_disabled_from_host = true;
+
+ /* Try to stop both Tx&Rx rings even if one of the calls fails
+ * to ensure we stop the rings even in case of errors.
+ * If any of them returns with an error then the first
+ * error that occurred will be returned.
+ */
+ tmp = i40e_ctrl_vf_tx_rings(vsi, q_map, false);
+ ret = i40e_ctrl_vf_rx_rings(vsi, q_map, false);
+
+ ret = tmp ? tmp : ret;
break;
default:
ret = -EINVAL;
@@ -4869,7 +4926,7 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
goto out;
}
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if (test_bit(I40E_FLAG_MFP_ENA, pf->flags)) {
dev_err(&pf->pdev->dev, "Trusted VF not supported in MFP mode.\n");
ret = -EINVAL;
goto out;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 5fd607c0de0a..66f95e2f3146 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -100,6 +100,7 @@ struct i40e_vf {
bool link_forced;
bool link_up; /* only valid if VF link is forced */
bool spoofchk;
+ bool is_disabled_from_host; /* PF ctrl of VF enable/disable */
u16 num_vlan;
/* ADq related variables */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_xsk.c b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
index e99fa854d17f..11500003af0d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_xsk.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_xsk.c
@@ -414,7 +414,8 @@ i40e_add_xsk_frag(struct i40e_ring *rx_ring, struct xdp_buff *first,
}
__skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++,
- virt_to_page(xdp->data_hard_start), 0, size);
+ virt_to_page(xdp->data_hard_start),
+ XDP_PACKET_HEADROOM, size);
sinfo->xdp_frags_size += size;
xsk_buff_add_frag(xdp);
@@ -476,8 +477,7 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
continue;
}
- size = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
- I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
+ size = FIELD_GET(I40E_RXD_QW1_LENGTH_PBUF_MASK, qword);
if (!size)
break;
@@ -499,7 +499,6 @@ int i40e_clean_rx_irq_zc(struct i40e_ring *rx_ring, int budget)
xdp_res = i40e_run_xdp_zc(rx_ring, first, xdp_prog);
i40e_handle_xdp_result_zc(rx_ring, first, rx_desc, &rx_packets,
&rx_bytes, xdp_res, &failure);
- first->flags = 0;
next_to_clean = next_to_process;
if (failure)
break;
diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h
index 63b45c61cc4a..db8188c7ac4b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf.h
+++ b/drivers/net/ethernet/intel/iavf/iavf.h
@@ -313,7 +313,8 @@ struct iavf_adapter {
#define IAVF_FLAG_AQ_SET_HENA BIT_ULL(12)
#define IAVF_FLAG_AQ_SET_RSS_KEY BIT_ULL(13)
#define IAVF_FLAG_AQ_SET_RSS_LUT BIT_ULL(14)
-#define IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE BIT_ULL(15)
+#define IAVF_FLAG_AQ_SET_RSS_HFUNC BIT_ULL(15)
+#define IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE BIT_ULL(16)
#define IAVF_FLAG_AQ_ENABLE_VLAN_STRIPPING BIT_ULL(19)
#define IAVF_FLAG_AQ_DISABLE_VLAN_STRIPPING BIT_ULL(20)
#define IAVF_FLAG_AQ_ENABLE_CHANNELS BIT_ULL(21)
@@ -415,6 +416,7 @@ struct iavf_adapter {
struct iavf_vsi vsi;
u32 aq_wait_count;
/* RSS stuff */
+ enum virtchnl_rss_algorithm hfunc;
u64 hena;
u16 rss_key_size;
u16 rss_lut_size;
@@ -540,6 +542,7 @@ void iavf_get_hena(struct iavf_adapter *adapter);
void iavf_set_hena(struct iavf_adapter *adapter);
void iavf_set_rss_key(struct iavf_adapter *adapter);
void iavf_set_rss_lut(struct iavf_adapter *adapter);
+void iavf_set_rss_hfunc(struct iavf_adapter *adapter);
void iavf_enable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_disable_vlan_stripping(struct iavf_adapter *adapter);
void iavf_virtchnl_completion(struct iavf_adapter *adapter,
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq.c b/drivers/net/ethernet/intel/iavf/iavf_adminq.c
index 9ffbd24d83cb..82fcd18ad660 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_adminq.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.c
@@ -8,27 +8,6 @@
#include "iavf_prototype.h"
/**
- * iavf_adminq_init_regs - Initialize AdminQ registers
- * @hw: pointer to the hardware structure
- *
- * This assumes the alloc_asq and alloc_arq functions have already been called
- **/
-static void iavf_adminq_init_regs(struct iavf_hw *hw)
-{
- /* set head and tail registers in our local struct */
- hw->aq.asq.tail = IAVF_VF_ATQT1;
- hw->aq.asq.head = IAVF_VF_ATQH1;
- hw->aq.asq.len = IAVF_VF_ATQLEN1;
- hw->aq.asq.bal = IAVF_VF_ATQBAL1;
- hw->aq.asq.bah = IAVF_VF_ATQBAH1;
- hw->aq.arq.tail = IAVF_VF_ARQT1;
- hw->aq.arq.head = IAVF_VF_ARQH1;
- hw->aq.arq.len = IAVF_VF_ARQLEN1;
- hw->aq.arq.bal = IAVF_VF_ARQBAL1;
- hw->aq.arq.bah = IAVF_VF_ARQBAH1;
-}
-
-/**
* iavf_alloc_adminq_asq_ring - Allocate Admin Queue send rings
* @hw: pointer to the hardware structure
**/
@@ -259,17 +238,17 @@ static enum iavf_status iavf_config_asq_regs(struct iavf_hw *hw)
u32 reg = 0;
/* Clear Head and Tail */
- wr32(hw, hw->aq.asq.head, 0);
- wr32(hw, hw->aq.asq.tail, 0);
+ wr32(hw, IAVF_VF_ATQH1, 0);
+ wr32(hw, IAVF_VF_ATQT1, 0);
/* set starting point */
- wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries |
+ wr32(hw, IAVF_VF_ATQLEN1, (hw->aq.num_asq_entries |
IAVF_VF_ATQLEN1_ATQENABLE_MASK));
- wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa));
- wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa));
+ wr32(hw, IAVF_VF_ATQBAL1, lower_32_bits(hw->aq.asq.desc_buf.pa));
+ wr32(hw, IAVF_VF_ATQBAH1, upper_32_bits(hw->aq.asq.desc_buf.pa));
/* Check one register to verify that config was applied */
- reg = rd32(hw, hw->aq.asq.bal);
+ reg = rd32(hw, IAVF_VF_ATQBAL1);
if (reg != lower_32_bits(hw->aq.asq.desc_buf.pa))
ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR;
@@ -288,20 +267,20 @@ static enum iavf_status iavf_config_arq_regs(struct iavf_hw *hw)
u32 reg = 0;
/* Clear Head and Tail */
- wr32(hw, hw->aq.arq.head, 0);
- wr32(hw, hw->aq.arq.tail, 0);
+ wr32(hw, IAVF_VF_ARQH1, 0);
+ wr32(hw, IAVF_VF_ARQT1, 0);
/* set starting point */
- wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries |
+ wr32(hw, IAVF_VF_ARQLEN1, (hw->aq.num_arq_entries |
IAVF_VF_ARQLEN1_ARQENABLE_MASK));
- wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa));
- wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa));
+ wr32(hw, IAVF_VF_ARQBAL1, lower_32_bits(hw->aq.arq.desc_buf.pa));
+ wr32(hw, IAVF_VF_ARQBAH1, upper_32_bits(hw->aq.arq.desc_buf.pa));
/* Update tail in the HW to post pre-allocated buffers */
- wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1);
+ wr32(hw, IAVF_VF_ARQT1, hw->aq.num_arq_entries - 1);
/* Check one register to verify that config was applied */
- reg = rd32(hw, hw->aq.arq.bal);
+ reg = rd32(hw, IAVF_VF_ARQBAL1);
if (reg != lower_32_bits(hw->aq.arq.desc_buf.pa))
ret_code = IAVF_ERR_ADMIN_QUEUE_ERROR;
@@ -455,11 +434,11 @@ static enum iavf_status iavf_shutdown_asq(struct iavf_hw *hw)
}
/* Stop firmware AdminQ processing */
- wr32(hw, hw->aq.asq.head, 0);
- wr32(hw, hw->aq.asq.tail, 0);
- wr32(hw, hw->aq.asq.len, 0);
- wr32(hw, hw->aq.asq.bal, 0);
- wr32(hw, hw->aq.asq.bah, 0);
+ wr32(hw, IAVF_VF_ATQH1, 0);
+ wr32(hw, IAVF_VF_ATQT1, 0);
+ wr32(hw, IAVF_VF_ATQLEN1, 0);
+ wr32(hw, IAVF_VF_ATQBAL1, 0);
+ wr32(hw, IAVF_VF_ATQBAH1, 0);
hw->aq.asq.count = 0; /* to indicate uninitialized queue */
@@ -489,11 +468,11 @@ static enum iavf_status iavf_shutdown_arq(struct iavf_hw *hw)
}
/* Stop firmware AdminQ processing */
- wr32(hw, hw->aq.arq.head, 0);
- wr32(hw, hw->aq.arq.tail, 0);
- wr32(hw, hw->aq.arq.len, 0);
- wr32(hw, hw->aq.arq.bal, 0);
- wr32(hw, hw->aq.arq.bah, 0);
+ wr32(hw, IAVF_VF_ARQH1, 0);
+ wr32(hw, IAVF_VF_ARQT1, 0);
+ wr32(hw, IAVF_VF_ARQLEN1, 0);
+ wr32(hw, IAVF_VF_ARQBAL1, 0);
+ wr32(hw, IAVF_VF_ARQBAH1, 0);
hw->aq.arq.count = 0; /* to indicate uninitialized queue */
@@ -529,9 +508,6 @@ enum iavf_status iavf_init_adminq(struct iavf_hw *hw)
goto init_adminq_exit;
}
- /* Set up register offsets */
- iavf_adminq_init_regs(hw);
-
/* setup ASQ command write back timeout */
hw->aq.asq_cmd_timeout = IAVF_ASQ_CMD_TIMEOUT;
@@ -587,9 +563,9 @@ static u16 iavf_clean_asq(struct iavf_hw *hw)
desc = IAVF_ADMINQ_DESC(*asq, ntc);
details = IAVF_ADMINQ_DETAILS(*asq, ntc);
- while (rd32(hw, hw->aq.asq.head) != ntc) {
+ while (rd32(hw, IAVF_VF_ATQH1) != ntc) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
- "ntc %d head %d.\n", ntc, rd32(hw, hw->aq.asq.head));
+ "ntc %d head %d.\n", ntc, rd32(hw, IAVF_VF_ATQH1));
if (details->callback) {
IAVF_ADMINQ_CALLBACK cb_func =
@@ -624,7 +600,7 @@ bool iavf_asq_done(struct iavf_hw *hw)
/* AQ designers suggest use of head for better
* timing reliability than DD bit
*/
- return rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use;
+ return rd32(hw, IAVF_VF_ATQH1) == hw->aq.asq.next_to_use;
}
/**
@@ -663,7 +639,7 @@ enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
hw->aq.asq_last_status = IAVF_AQ_RC_OK;
- val = rd32(hw, hw->aq.asq.head);
+ val = rd32(hw, IAVF_VF_ATQH1);
if (val >= hw->aq.num_asq_entries) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: head overrun at %d\n", val);
@@ -755,7 +731,7 @@ enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
if (hw->aq.asq.next_to_use == hw->aq.asq.count)
hw->aq.asq.next_to_use = 0;
if (!details->postpone)
- wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use);
+ wr32(hw, IAVF_VF_ATQT1, hw->aq.asq.next_to_use);
/* if cmd_details are not defined or async flag is not set,
* we need to wait for desc write back
@@ -810,7 +786,7 @@ enum iavf_status iavf_asq_send_command(struct iavf_hw *hw,
/* update the error if time out occurred */
if ((!cmd_completed) &&
(!details->async && !details->postpone)) {
- if (rd32(hw, hw->aq.asq.len) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) {
+ if (rd32(hw, IAVF_VF_ATQLEN1) & IAVF_VF_ATQLEN1_ATQCRIT_MASK) {
iavf_debug(hw, IAVF_DEBUG_AQ_MESSAGE,
"AQTX: AQ Critical error.\n");
status = IAVF_ERR_ADMIN_QUEUE_CRITICAL_ERROR;
@@ -878,7 +854,7 @@ enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
}
/* set next_to_use to head */
- ntu = rd32(hw, hw->aq.arq.head) & IAVF_VF_ARQH1_ARQH_MASK;
+ ntu = rd32(hw, IAVF_VF_ARQH1) & IAVF_VF_ARQH1_ARQH_MASK;
if (ntu == ntc) {
/* nothing to do - shouldn't need to update ring's values */
ret_code = IAVF_ERR_ADMIN_QUEUE_NO_WORK;
@@ -926,7 +902,7 @@ enum iavf_status iavf_clean_arq_element(struct iavf_hw *hw,
desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa));
/* set tail = the last cleaned desc index. */
- wr32(hw, hw->aq.arq.tail, ntc);
+ wr32(hw, IAVF_VF_ARQT1, ntc);
/* ntc is updated to tail + 1 */
ntc++;
if (ntc == hw->aq.num_arq_entries)
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adminq.h b/drivers/net/ethernet/intel/iavf/iavf_adminq.h
index 1f60518eb0e5..406506f64bdd 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_adminq.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_adminq.h
@@ -29,13 +29,6 @@ struct iavf_adminq_ring {
/* used for interrupt processing */
u16 next_to_use;
u16 next_to_clean;
-
- /* used for queue tracking */
- u32 head;
- u32 tail;
- u32 len;
- u32 bah;
- u32 bal;
};
/* ASQ transaction details */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adv_rss.c b/drivers/net/ethernet/intel/iavf/iavf_adv_rss.c
index 6edbf134b73f..a9e1da35e248 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_adv_rss.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_adv_rss.c
@@ -95,17 +95,21 @@ iavf_fill_adv_rss_sctp_hdr(struct virtchnl_proto_hdr *hdr, u64 hash_flds)
* @rss_cfg: the virtchnl message to be filled with RSS configuration setting
* @packet_hdrs: the RSS configuration protocol header types
* @hash_flds: the RSS configuration protocol hash fields
+ * @symm: if true, symmetric hash is required
*
* Returns 0 if the RSS configuration virtchnl message is filled successfully
*/
int
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
- u32 packet_hdrs, u64 hash_flds)
+ u32 packet_hdrs, u64 hash_flds, bool symm)
{
struct virtchnl_proto_hdrs *proto_hdrs = &rss_cfg->proto_hdrs;
struct virtchnl_proto_hdr *hdr;
- rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
+ if (symm)
+ rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
+ else
+ rss_cfg->rss_algorithm = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
proto_hdrs->tunnel_level = 0; /* always outer layer */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_adv_rss.h b/drivers/net/ethernet/intel/iavf/iavf_adv_rss.h
index 4d3be11af7aa..e31eb2afebea 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_adv_rss.h
+++ b/drivers/net/ethernet/intel/iavf/iavf_adv_rss.h
@@ -80,13 +80,14 @@ struct iavf_adv_rss {
u32 packet_hdrs;
u64 hash_flds;
+ bool symm;
struct virtchnl_rss_cfg cfg_msg;
};
int
iavf_fill_adv_rss_cfg_msg(struct virtchnl_rss_cfg *rss_cfg,
- u32 packet_hdrs, u64 hash_flds);
+ u32 packet_hdrs, u64 hash_flds, bool symm);
struct iavf_adv_rss *
iavf_find_adv_rss_cfg_by_hdrs(struct iavf_adapter *adapter, u32 packet_hdrs);
void
diff --git a/drivers/net/ethernet/intel/iavf/iavf_common.c b/drivers/net/ethernet/intel/iavf/iavf_common.c
index 8091e6feca01..5a25233a89d5 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_common.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_common.c
@@ -1,10 +1,11 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
+#include <linux/avf/virtchnl.h>
+#include <linux/bitfield.h>
#include "iavf_type.h"
#include "iavf_adminq.h"
#include "iavf_prototype.h"
-#include <linux/avf/virtchnl.h>
/**
* iavf_aq_str - convert AQ err code to a string
@@ -279,11 +280,11 @@ void iavf_debug_aq(struct iavf_hw *hw, enum iavf_debug_mask mask, void *desc,
**/
bool iavf_check_asq_alive(struct iavf_hw *hw)
{
- if (hw->aq.asq.len)
- return !!(rd32(hw, hw->aq.asq.len) &
- IAVF_VF_ATQLEN1_ATQENABLE_MASK);
- else
+ /* Check if the queue is initialized */
+ if (!hw->aq.asq.count)
return false;
+
+ return !!(rd32(hw, IAVF_VF_ATQLEN1) & IAVF_VF_ATQLEN1_ATQENABLE_MASK);
}
/**
@@ -330,6 +331,7 @@ static enum iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
struct iavf_aq_desc desc;
struct iavf_aqc_get_set_rss_lut *cmd_resp =
(struct iavf_aqc_get_set_rss_lut *)&desc.params.raw;
+ u16 flags;
if (set)
iavf_fill_default_direct_cmd_desc(&desc,
@@ -342,22 +344,18 @@ static enum iavf_status iavf_aq_get_set_rss_lut(struct iavf_hw *hw,
desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_BUF);
desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_RD);
- cmd_resp->vsi_id =
- cpu_to_le16((u16)((vsi_id <<
- IAVF_AQC_SET_RSS_LUT_VSI_ID_SHIFT) &
- IAVF_AQC_SET_RSS_LUT_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)IAVF_AQC_SET_RSS_LUT_VSI_VALID);
+ vsi_id = FIELD_PREP(IAVF_AQC_SET_RSS_LUT_VSI_ID_MASK, vsi_id) |
+ FIELD_PREP(IAVF_AQC_SET_RSS_LUT_VSI_VALID, 1);
+ cmd_resp->vsi_id = cpu_to_le16(vsi_id);
if (pf_lut)
- cmd_resp->flags |= cpu_to_le16((u16)
- ((IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_PF <<
- IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ flags = FIELD_PREP(IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK,
+ IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_PF);
else
- cmd_resp->flags |= cpu_to_le16((u16)
- ((IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_VSI <<
- IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_SHIFT) &
- IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK));
+ flags = FIELD_PREP(IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_MASK,
+ IAVF_AQC_SET_RSS_LUT_TABLE_TYPE_VSI);
+
+ cmd_resp->flags = cpu_to_le16(flags);
status = iavf_asq_send_command(hw, &desc, lut, lut_size, NULL);
@@ -411,11 +409,9 @@ iavf_status iavf_aq_get_set_rss_key(struct iavf_hw *hw, u16 vsi_id,
desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_BUF);
desc.flags |= cpu_to_le16((u16)IAVF_AQ_FLAG_RD);
- cmd_resp->vsi_id =
- cpu_to_le16((u16)((vsi_id <<
- IAVF_AQC_SET_RSS_KEY_VSI_ID_SHIFT) &
- IAVF_AQC_SET_RSS_KEY_VSI_ID_MASK));
- cmd_resp->vsi_id |= cpu_to_le16((u16)IAVF_AQC_SET_RSS_KEY_VSI_VALID);
+ vsi_id = FIELD_PREP(IAVF_AQC_SET_RSS_KEY_VSI_ID_MASK, vsi_id) |
+ FIELD_PREP(IAVF_AQC_SET_RSS_KEY_VSI_VALID, 1);
+ cmd_resp->vsi_id = cpu_to_le16(vsi_id);
status = iavf_asq_send_command(hw, &desc, key, key_size, NULL);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
index dc499fe7734e..378c3e9ddf9d 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
+#include <linux/bitfield.h>
+#include <linux/uaccess.h>
+
/* ethtool support for iavf */
#include "iavf.h"
-#include <linux/uaccess.h>
-
/* ethtool statistics helpers */
/**
@@ -396,8 +397,7 @@ static void iavf_get_priv_flag_strings(struct net_device *netdev, u8 *data)
unsigned int i;
for (i = 0; i < IAVF_PRIV_FLAGS_STR_LEN; i++)
- ethtool_sprintf(&data, "%s",
- iavf_gstrings_priv_flags[i].flag_string);
+ ethtool_puts(&data, iavf_gstrings_priv_flags[i].flag_string);
}
/**
@@ -1017,8 +1017,7 @@ iavf_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
#define IAVF_USERDEF_FLEX_MAX_OFFS_VAL 504
flex = &fltr->flex_words[cnt++];
flex->word = value & IAVF_USERDEF_FLEX_WORD_M;
- flex->offset = (value & IAVF_USERDEF_FLEX_OFFS_M) >>
- IAVF_USERDEF_FLEX_OFFS_S;
+ flex->offset = FIELD_GET(IAVF_USERDEF_FLEX_OFFS_M, value);
if (flex->offset > IAVF_USERDEF_FLEX_MAX_OFFS_VAL)
return -EINVAL;
}
@@ -1436,16 +1435,15 @@ static int iavf_add_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
spin_lock_bh(&adapter->fdir_fltr_lock);
iavf_fdir_list_add_fltr(adapter, fltr);
adapter->fdir_active_fltr++;
- if (adapter->link_up) {
+
+ if (adapter->link_up)
fltr->state = IAVF_FDIR_FLTR_ADD_REQUEST;
- adapter->aq_required |= IAVF_FLAG_AQ_ADD_FDIR_FILTER;
- } else {
+ else
fltr->state = IAVF_FDIR_FLTR_INACTIVE;
- }
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (adapter->link_up)
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
+ iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_FDIR_FILTER);
ret:
if (err && fltr)
kfree(fltr);
@@ -1475,7 +1473,6 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
if (fltr) {
if (fltr->state == IAVF_FDIR_FLTR_ACTIVE) {
fltr->state = IAVF_FDIR_FLTR_DEL_REQUEST;
- adapter->aq_required |= IAVF_FLAG_AQ_DEL_FDIR_FILTER;
} else if (fltr->state == IAVF_FDIR_FLTR_INACTIVE) {
list_del(&fltr->list);
kfree(fltr);
@@ -1490,7 +1487,7 @@ static int iavf_del_fdir_ethtool(struct iavf_adapter *adapter, struct ethtool_rx
spin_unlock_bh(&adapter->fdir_fltr_lock);
if (fltr && fltr->state == IAVF_FDIR_FLTR_DEL_REQUEST)
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
+ iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_FDIR_FILTER);
return err;
}
@@ -1541,11 +1538,12 @@ static u32 iavf_adv_rss_parse_hdrs(struct ethtool_rxnfc *cmd)
/**
* iavf_adv_rss_parse_hash_flds - parses hash fields from RSS hash input
* @cmd: ethtool rxnfc command
+ * @symm: true if Symmetric Topelitz is set
*
* This function parses the rxnfc command and returns intended hash fields for
* RSS configuration
*/
-static u64 iavf_adv_rss_parse_hash_flds(struct ethtool_rxnfc *cmd)
+static u64 iavf_adv_rss_parse_hash_flds(struct ethtool_rxnfc *cmd, bool symm)
{
u64 hfld = IAVF_ADV_RSS_HASH_INVALID;
@@ -1617,17 +1615,20 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
struct iavf_adv_rss *rss_old, *rss_new;
bool rss_new_add = false;
int count = 50, err = 0;
+ bool symm = false;
u64 hash_flds;
u32 hdrs;
if (!ADV_RSS_SUPPORT(adapter))
return -EOPNOTSUPP;
+ symm = !!(adapter->hfunc == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC);
+
hdrs = iavf_adv_rss_parse_hdrs(cmd);
if (hdrs == IAVF_ADV_RSS_FLOW_SEG_HDR_NONE)
return -EINVAL;
- hash_flds = iavf_adv_rss_parse_hash_flds(cmd);
+ hash_flds = iavf_adv_rss_parse_hash_flds(cmd, symm);
if (hash_flds == IAVF_ADV_RSS_HASH_INVALID)
return -EINVAL;
@@ -1635,7 +1636,8 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
if (!rss_new)
return -ENOMEM;
- if (iavf_fill_adv_rss_cfg_msg(&rss_new->cfg_msg, hdrs, hash_flds)) {
+ if (iavf_fill_adv_rss_cfg_msg(&rss_new->cfg_msg, hdrs, hash_flds,
+ symm)) {
kfree(rss_new);
return -EINVAL;
}
@@ -1654,12 +1656,13 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
if (rss_old) {
if (rss_old->state != IAVF_ADV_RSS_ACTIVE) {
err = -EBUSY;
- } else if (rss_old->hash_flds != hash_flds) {
+ } else if (rss_old->hash_flds != hash_flds ||
+ rss_old->symm != symm) {
rss_old->state = IAVF_ADV_RSS_ADD_REQUEST;
rss_old->hash_flds = hash_flds;
+ rss_old->symm = symm;
memcpy(&rss_old->cfg_msg, &rss_new->cfg_msg,
sizeof(rss_new->cfg_msg));
- adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG;
} else {
err = -EEXIST;
}
@@ -1668,13 +1671,13 @@ iavf_set_adv_rss_hash_opt(struct iavf_adapter *adapter,
rss_new->state = IAVF_ADV_RSS_ADD_REQUEST;
rss_new->packet_hdrs = hdrs;
rss_new->hash_flds = hash_flds;
+ rss_new->symm = symm;
list_add_tail(&rss_new->list, &adapter->adv_rss_list_head);
- adapter->aq_required |= IAVF_FLAG_AQ_ADD_ADV_RSS_CFG;
}
spin_unlock_bh(&adapter->adv_rss_lock);
if (!err)
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
+ iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_ADV_RSS_CFG);
mutex_unlock(&adapter->crit_lock);
@@ -1908,27 +1911,27 @@ static u32 iavf_get_rxfh_indir_size(struct net_device *netdev)
/**
* iavf_get_rxfh - get the rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function in use
+ * @rxfh: pointer to param struct (indir, key, hfunc)
*
* Reads the indirection table directly from the hardware. Always returns 0.
**/
-static int iavf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int iavf_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u16 i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (key)
- memcpy(key, adapter->rss_key, adapter->rss_key_size);
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (adapter->hfunc == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)
+ rxfh->input_xfrm |= RXH_XFRM_SYM_XOR;
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, adapter->rss_key_size);
- if (indir)
+ if (rxfh->indir)
/* Each 32 bits pointed by 'indir' is stored with a lut entry */
for (i = 0; i < adapter->rss_lut_size; i++)
- indir[i] = (u32)adapter->rss_lut[i];
+ rxfh->indir[i] = (u32)adapter->rss_lut[i];
return 0;
}
@@ -1936,33 +1939,46 @@ static int iavf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
/**
* iavf_set_rxfh - set the rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function to use
+ * @rxfh: pointer to param struct (indir, key, hfunc)
+ * @extack: extended ACK from the Netlink message
*
* Returns -EINVAL if the table specifies an invalid queue id, otherwise
* returns 0 after programming the table.
**/
-static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int iavf_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct iavf_adapter *adapter = netdev_priv(netdev);
u16 i;
/* Only support toeplitz hash function */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!key && !indir)
+ if ((rxfh->input_xfrm & RXH_XFRM_SYM_XOR) &&
+ adapter->hfunc != VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC) {
+ if (!ADV_RSS_SUPPORT(adapter))
+ return -EOPNOTSUPP;
+ adapter->hfunc = VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
+ adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_HFUNC;
+ } else if (!(rxfh->input_xfrm & RXH_XFRM_SYM_XOR) &&
+ adapter->hfunc != VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC) {
+ adapter->hfunc = VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
+ adapter->aq_required |= IAVF_FLAG_AQ_SET_RSS_HFUNC;
+ }
+
+ if (!rxfh->key && !rxfh->indir)
return 0;
- if (key)
- memcpy(adapter->rss_key, key, adapter->rss_key_size);
+ if (rxfh->key)
+ memcpy(adapter->rss_key, rxfh->key, adapter->rss_key_size);
- if (indir) {
+ if (rxfh->indir) {
/* Each 32 bits pointed by 'indir' is stored with a lut entry */
for (i = 0; i < adapter->rss_lut_size; i++)
- adapter->rss_lut[i] = (u8)(indir[i]);
+ adapter->rss_lut[i] = (u8)(rxfh->indir[i]);
}
return iavf_config_rss(adapter);
@@ -1971,6 +1987,7 @@ static int iavf_set_rxfh(struct net_device *netdev, const u32 *indir,
static const struct ethtool_ops iavf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USE_ADAPTIVE,
+ .cap_rss_sym_xor_supported = true,
.get_drvinfo = iavf_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = iavf_get_ringparam,
diff --git a/drivers/net/ethernet/intel/iavf/iavf_fdir.c b/drivers/net/ethernet/intel/iavf/iavf_fdir.c
index 03e774bd2a5b..2d47b0b4640e 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_fdir.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_fdir.c
@@ -3,6 +3,7 @@
/* flow director ethtool support for iavf */
+#include <linux/bitfield.h>
#include "iavf.h"
#define GTPU_PORT 2152
@@ -357,7 +358,7 @@ iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
if (fltr->ip_mask.tclass == U8_MAX) {
iph->priority = (fltr->ip_data.tclass >> 4) & 0xF;
- iph->flow_lbl[0] = (fltr->ip_data.tclass << 4) & 0xF0;
+ iph->flow_lbl[0] = FIELD_PREP(0xF0, fltr->ip_data.tclass);
VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, TC);
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index e8d5b889addc..335fd13e86f7 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -1038,13 +1038,12 @@ static int iavf_replace_primary_mac(struct iavf_adapter *adapter,
*/
new_f->is_primary = true;
new_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 */
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
+ iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_MAC_FILTER);
return 0;
}
@@ -1263,8 +1262,7 @@ static void iavf_up_complete(struct iavf_adapter *adapter)
iavf_napi_enable_all(adapter);
- adapter->aq_required |= IAVF_FLAG_AQ_ENABLE_QUEUES;
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
+ iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ENABLE_QUEUES);
}
/**
@@ -1420,8 +1418,7 @@ void iavf_down(struct iavf_adapter *adapter)
adapter->aq_required |= IAVF_FLAG_AQ_DEL_ADV_RSS_CFG;
}
- adapter->aq_required |= IAVF_FLAG_AQ_DISABLE_QUEUES;
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
+ iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DISABLE_QUEUES);
}
/**
@@ -2150,6 +2147,10 @@ static int iavf_process_aq_command(struct iavf_adapter *adapter)
iavf_set_rss_lut(adapter);
return 0;
}
+ if (adapter->aq_required & IAVF_FLAG_AQ_SET_RSS_HFUNC) {
+ iavf_set_rss_hfunc(adapter);
+ return 0;
+ }
if (adapter->aq_required & IAVF_FLAG_AQ_CONFIGURE_PROMISC_MODE) {
iavf_set_promiscuous(adapter);
@@ -2318,10 +2319,8 @@ iavf_set_vlan_offload_features(struct iavf_adapter *adapter,
}
}
- if (aq_required) {
- adapter->aq_required |= aq_required;
- mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0);
- }
+ if (aq_required)
+ iavf_schedule_aq_request(adapter, aq_required);
}
/**
@@ -3234,7 +3233,7 @@ static void iavf_adminq_task(struct work_struct *work)
goto freedom;
/* check for error indications */
- val = rd32(hw, hw->aq.arq.len);
+ val = rd32(hw, IAVF_VF_ARQLEN1);
if (val == 0xdeadbeef || val == 0xffffffff) /* device in reset */
goto freedom;
oldval = val;
@@ -3251,9 +3250,9 @@ static void iavf_adminq_task(struct work_struct *work)
val &= ~IAVF_VF_ARQLEN1_ARQCRIT_MASK;
}
if (oldval != val)
- wr32(hw, hw->aq.arq.len, val);
+ wr32(hw, IAVF_VF_ARQLEN1, val);
- val = rd32(hw, hw->aq.asq.len);
+ val = rd32(hw, IAVF_VF_ATQLEN1);
oldval = val;
if (val & IAVF_VF_ATQLEN1_ATQVFE_MASK) {
dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n");
@@ -3268,7 +3267,7 @@ static void iavf_adminq_task(struct work_struct *work)
val &= ~IAVF_VF_ATQLEN1_ATQCRIT_MASK;
}
if (oldval != val)
- wr32(hw, hw->aq.asq.len, val);
+ wr32(hw, IAVF_VF_ATQLEN1, val);
freedom:
kfree(event.msg_buf);
diff --git a/drivers/net/ethernet/intel/iavf/iavf_txrx.c b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
index d64c4997136b..b71484c87a84 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_txrx.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_txrx.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2013 - 2018 Intel Corporation. */
+#include <linux/bitfield.h>
#include <linux/prefetch.h>
#include "iavf.h"
@@ -988,11 +989,9 @@ static void iavf_rx_checksum(struct iavf_vsi *vsi,
u64 qword;
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK) >> IAVF_RXD_QW1_PTYPE_SHIFT;
- rx_error = (qword & IAVF_RXD_QW1_ERROR_MASK) >>
- IAVF_RXD_QW1_ERROR_SHIFT;
- rx_status = (qword & IAVF_RXD_QW1_STATUS_MASK) >>
- IAVF_RXD_QW1_STATUS_SHIFT;
+ ptype = FIELD_GET(IAVF_RXD_QW1_PTYPE_MASK, qword);
+ rx_error = FIELD_GET(IAVF_RXD_QW1_ERROR_MASK, qword);
+ rx_status = FIELD_GET(IAVF_RXD_QW1_STATUS_MASK, qword);
decoded = decode_rx_desc_ptype(ptype);
skb->ip_summed = CHECKSUM_NONE;
@@ -1533,8 +1532,7 @@ static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
if (!iavf_test_staterr(rx_desc, IAVF_RXD_DD))
break;
- size = (qword & IAVF_RXD_QW1_LENGTH_PBUF_MASK) >>
- IAVF_RXD_QW1_LENGTH_PBUF_SHIFT;
+ size = FIELD_GET(IAVF_RXD_QW1_LENGTH_PBUF_MASK, qword);
iavf_trace(clean_rx_irq, rx_ring, rx_desc, skb);
rx_buffer = iavf_get_rx_buffer(rx_ring, size);
@@ -1581,8 +1579,7 @@ static int iavf_clean_rx_irq(struct iavf_ring *rx_ring, int budget)
total_rx_bytes += skb->len;
qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
- rx_ptype = (qword & IAVF_RXD_QW1_PTYPE_MASK) >>
- IAVF_RXD_QW1_PTYPE_SHIFT;
+ rx_ptype = FIELD_GET(IAVF_RXD_QW1_PTYPE_MASK, qword);
/* populate checksum, VLAN, and protocol */
iavf_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
@@ -2290,8 +2287,7 @@ static void iavf_tx_map(struct iavf_ring *tx_ring, struct sk_buff *skb,
if (tx_flags & IAVF_TX_FLAGS_HW_VLAN) {
td_cmd |= IAVF_TX_DESC_CMD_IL2TAG1;
- td_tag = (tx_flags & IAVF_TX_FLAGS_VLAN_MASK) >>
- IAVF_TX_FLAGS_VLAN_SHIFT;
+ td_tag = FIELD_GET(IAVF_TX_FLAGS_VLAN_MASK, tx_flags);
}
first->tx_flags = tx_flags;
@@ -2467,8 +2463,7 @@ static netdev_tx_t iavf_xmit_frame_ring(struct sk_buff *skb,
if (tx_flags & IAVF_TX_FLAGS_HW_OUTER_SINGLE_VLAN) {
cd_type_cmd_tso_mss |= IAVF_TX_CTX_DESC_IL2TAG2 <<
IAVF_TXD_CTX_QW1_CMD_SHIFT;
- cd_l2tag2 = (tx_flags & IAVF_TX_FLAGS_VLAN_MASK) >>
- IAVF_TX_FLAGS_VLAN_SHIFT;
+ cd_l2tag2 = FIELD_GET(IAVF_TX_FLAGS_VLAN_MASK, tx_flags);
}
/* obtain protocol of skb */
diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
index 2d9366be0ec5..22f2df7c460b 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
@@ -1142,6 +1142,34 @@ void iavf_set_rss_lut(struct iavf_adapter *adapter)
}
/**
+ * iavf_set_rss_hfunc
+ * @adapter: adapter structure
+ *
+ * Request the PF to set our RSS Hash function
+ **/
+void iavf_set_rss_hfunc(struct iavf_adapter *adapter)
+{
+ struct virtchnl_rss_hfunc *vrh;
+ int len = sizeof(*vrh);
+
+ if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+ /* bail because we already have a command pending */
+ dev_err(&adapter->pdev->dev, "Cannot set RSS Hash function, command %d pending\n",
+ adapter->current_op);
+ return;
+ }
+ vrh = kzalloc(len, GFP_KERNEL);
+ if (!vrh)
+ return;
+ vrh->vsi_id = adapter->vsi.id;
+ vrh->rss_algorithm = adapter->hfunc;
+ adapter->current_op = VIRTCHNL_OP_CONFIG_RSS_HFUNC;
+ adapter->aq_required &= ~IAVF_FLAG_AQ_SET_RSS_HFUNC;
+ iavf_send_pf_msg(adapter, VIRTCHNL_OP_CONFIG_RSS_HFUNC, (u8 *)vrh, len);
+ kfree(vrh);
+}
+
+/**
* iavf_enable_vlan_stripping
* @adapter: adapter structure
*
@@ -2190,6 +2218,19 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
dev_warn(&adapter->pdev->dev, "Failed to add VLAN filter, error %s\n",
iavf_stat_str(&adapter->hw, v_retval));
break;
+ case VIRTCHNL_OP_CONFIG_RSS_HFUNC:
+ dev_warn(&adapter->pdev->dev, "Failed to configure hash function, error %s\n",
+ iavf_stat_str(&adapter->hw, v_retval));
+
+ if (adapter->hfunc ==
+ VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)
+ adapter->hfunc =
+ VIRTCHNL_RSS_ALG_TOEPLITZ_ASYMMETRIC;
+ else
+ adapter->hfunc =
+ VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC;
+
+ break;
default:
dev_err(&adapter->pdev->dev, "PF returned error %d (%s) to our request %d\n",
v_retval, iavf_stat_str(&adapter->hw, v_retval),
diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile
index 0679907980f7..cddd82d4ca0f 100644
--- a/drivers/net/ethernet/intel/ice/Makefile
+++ b/drivers/net/ethernet/intel/ice/Makefile
@@ -34,7 +34,9 @@ ice-y := ice_main.o \
ice_lag.o \
ice_ethtool.o \
ice_repr.o \
- ice_tc_lib.o
+ ice_tc_lib.o \
+ ice_fwlog.o \
+ ice_debugfs.o
ice-$(CONFIG_PCI_IOV) += \
ice_sriov.o \
ice_virtchnl.o \
@@ -49,3 +51,4 @@ ice-$(CONFIG_RFS_ACCEL) += ice_arfs.o
ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o
ice-$(CONFIG_ICE_SWITCHDEV) += ice_eswitch.o ice_eswitch_br.o
ice-$(CONFIG_GNSS) += ice_gnss.o
+ice-$(CONFIG_ICE_HWMON) += ice_hwmon.o
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index 351e0d36df44..367b613d92c0 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -360,6 +360,7 @@ struct ice_vsi {
/* RSS config */
u16 rss_table_size; /* HW RSS table size */
u16 rss_size; /* Allocated RSS queues */
+ u8 rss_hfunc; /* User configured hash type */
u8 *rss_hkey_user; /* User configured hash keys */
u8 *rss_lut_user; /* User configured lookup table entries */
u8 rss_lut_type; /* used to configure Get/Set RSS LUT AQ call */
@@ -517,16 +518,22 @@ enum ice_pf_flags {
};
enum ice_misc_thread_tasks {
- ICE_MISC_THREAD_EXTTS_EVENT,
ICE_MISC_THREAD_TX_TSTAMP,
ICE_MISC_THREAD_NBITS /* must be last */
};
-struct ice_switchdev_info {
+struct ice_eswitch {
struct ice_vsi *control_vsi;
struct ice_vsi *uplink_vsi;
struct ice_esw_br_offloads *br_offloads;
+ struct xarray reprs;
bool is_running;
+ /* struct to allow cp queues management optimization */
+ struct {
+ int to_reach;
+ int value;
+ bool is_reaching;
+ } qs;
};
struct ice_agg_node {
@@ -563,6 +570,10 @@ struct ice_pf {
struct ice_vsi_stats **vsi_stats;
struct ice_sw *first_sw; /* first switch created by firmware */
u16 eswitch_mode; /* current mode of eswitch */
+ struct dentry *ice_debugfs_pf;
+ struct dentry *ice_debugfs_pf_fwlog;
+ /* keep track of all the dentrys for FW log modules */
+ struct dentry **ice_debugfs_pf_fwlog_modules;
struct ice_vfs vfs;
DECLARE_BITMAP(features, ICE_F_MAX);
DECLARE_BITMAP(state, ICE_STATE_NBITS);
@@ -597,6 +608,7 @@ struct ice_pf {
u32 hw_csum_rx_error;
u32 oicr_err_reg;
struct msi_map oicr_irq; /* Other interrupt cause MSIX vector */
+ struct msi_map ll_ts_irq; /* LL_TS interrupt MSIX vector */
u16 max_pf_txqs; /* Total Tx queues PF wide */
u16 max_pf_rxqs; /* Total Rx queues PF wide */
u16 num_lan_msix; /* Total MSIX vectors for base driver */
@@ -621,6 +633,7 @@ struct ice_pf {
unsigned long tx_timeout_last_recovery;
u32 tx_timeout_recovery_level;
char int_name[ICE_INT_NAME_STR_LEN];
+ char int_name_ll_ts[ICE_INT_NAME_STR_LEN];
struct auxiliary_device *adev;
int aux_idx;
u32 sw_int_count;
@@ -637,7 +650,7 @@ struct ice_pf {
struct ice_link_default_override_tlv link_dflt_override;
struct ice_lag *lag; /* Link Aggregation information */
- struct ice_switchdev_info switchdev;
+ struct ice_eswitch eswitch;
struct ice_esw_br_port *br_port;
#define ICE_INVALID_AGG_NODE_ID 0
@@ -648,6 +661,7 @@ struct ice_pf {
#define ICE_MAX_VF_AGG_NODES 32
struct ice_agg_node vf_agg_node[ICE_MAX_VF_AGG_NODES];
struct ice_dplls dplls;
+ struct device *hwmon_dev;
};
extern struct workqueue_struct *ice_lag_wq;
@@ -846,7 +860,7 @@ static inline struct ice_vsi *ice_find_vsi(struct ice_pf *pf, u16 vsi_num)
*/
static inline bool ice_is_switchdev_running(struct ice_pf *pf)
{
- return pf->switchdev.is_running;
+ return pf->eswitch.is_running;
}
#define ICE_FD_STAT_CTR_BLOCK_COUNT 256
@@ -881,6 +895,11 @@ static inline bool ice_is_adq_active(struct ice_pf *pf)
return false;
}
+void ice_debugfs_fwlog_init(struct ice_pf *pf);
+void ice_debugfs_init(void);
+void ice_debugfs_exit(void);
+void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module);
+
bool netif_is_ice(const struct net_device *dev);
int ice_vsi_setup_tx_rings(struct ice_vsi *vsi);
int ice_vsi_setup_rx_rings(struct ice_vsi *vsi);
@@ -912,6 +931,7 @@ int ice_set_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size);
int ice_get_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size);
int ice_set_rss_key(struct ice_vsi *vsi, u8 *seed);
int ice_get_rss_key(struct ice_vsi *vsi, u8 *seed);
+int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc);
void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);
int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
@@ -989,4 +1009,6 @@ static inline void ice_clear_rdma_cap(struct ice_pf *pf)
set_bit(ICE_FLAG_UNPLUG_AUX_DEV, pf->flags);
clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
}
+
+extern const struct xdp_metadata_ops ice_xdp_md_ops;
#endif /* _ICE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
index fbd5d92182d3..8040317c9561 100644
--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h
@@ -117,6 +117,7 @@ struct ice_aqc_list_caps_elem {
#define ICE_AQC_CAPS_NET_VER 0x004C
#define ICE_AQC_CAPS_PENDING_NET_VER 0x004D
#define ICE_AQC_CAPS_RDMA 0x0051
+#define ICE_AQC_CAPS_SENSOR_READING 0x0067
#define ICE_AQC_CAPS_PCIE_RESET_AVOIDANCE 0x0076
#define ICE_AQC_CAPS_POST_UPDATE_RESET_RESTRICT 0x0077
#define ICE_AQC_CAPS_NVM_MGMT 0x0080
@@ -421,10 +422,10 @@ struct ice_aqc_vsi_props {
#define ICE_AQ_VSI_INNER_VLAN_INSERT_PVID BIT(2)
#define ICE_AQ_VSI_INNER_VLAN_EMODE_S 3
#define ICE_AQ_VSI_INNER_VLAN_EMODE_M (0x3 << ICE_AQ_VSI_INNER_VLAN_EMODE_S)
-#define ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH (0x0 << ICE_AQ_VSI_INNER_VLAN_EMODE_S)
-#define ICE_AQ_VSI_INNER_VLAN_EMODE_STR_UP (0x1 << ICE_AQ_VSI_INNER_VLAN_EMODE_S)
-#define ICE_AQ_VSI_INNER_VLAN_EMODE_STR (0x2 << ICE_AQ_VSI_INNER_VLAN_EMODE_S)
-#define ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING (0x3 << ICE_AQ_VSI_INNER_VLAN_EMODE_S)
+#define ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH 0x0U
+#define ICE_AQ_VSI_INNER_VLAN_EMODE_STR_UP 0x1U
+#define ICE_AQ_VSI_INNER_VLAN_EMODE_STR 0x2U
+#define ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING 0x3U
u8 inner_vlan_reserved2[3];
/* ingress egress up sections */
__le32 ingress_table; /* bitmap, 3 bits per up */
@@ -490,11 +491,11 @@ struct ice_aqc_vsi_props {
#define ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_S 2
#define ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_M (0xF << ICE_AQ_VSI_Q_OPT_RSS_GBL_LUT_S)
#define ICE_AQ_VSI_Q_OPT_RSS_HASH_S 6
-#define ICE_AQ_VSI_Q_OPT_RSS_HASH_M (0x3 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S)
-#define ICE_AQ_VSI_Q_OPT_RSS_TPLZ (0x0 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S)
-#define ICE_AQ_VSI_Q_OPT_RSS_SYM_TPLZ (0x1 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S)
-#define ICE_AQ_VSI_Q_OPT_RSS_XOR (0x2 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S)
-#define ICE_AQ_VSI_Q_OPT_RSS_JHASH (0x3 << ICE_AQ_VSI_Q_OPT_RSS_HASH_S)
+#define ICE_AQ_VSI_Q_OPT_RSS_HASH_M GENMASK(7, 6)
+#define ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ 0x0U
+#define ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ 0x1U
+#define ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR 0x2U
+#define ICE_AQ_VSI_Q_OPT_RSS_HASH_JHASH 0x3U
u8 q_opt_tc;
#define ICE_AQ_VSI_Q_OPT_TC_OVR_S 0
#define ICE_AQ_VSI_Q_OPT_TC_OVR_M (0x1F << ICE_AQ_VSI_Q_OPT_TC_OVR_S)
@@ -1414,6 +1415,30 @@ struct ice_aqc_get_phy_rec_clk_out {
__le16 node_handle;
};
+/* Get sensor reading (direct 0x0632) */
+struct ice_aqc_get_sensor_reading {
+ u8 sensor;
+ u8 format;
+ u8 reserved[6];
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+/* Get sensor reading response (direct 0x0632) */
+struct ice_aqc_get_sensor_reading_resp {
+ union {
+ u8 raw[8];
+ /* Output data for sensor 0x00, format 0x00 */
+ struct _packed {
+ s8 temp;
+ u8 temp_warning_threshold;
+ u8 temp_critical_threshold;
+ u8 temp_fatal_threshold;
+ u8 reserved[4];
+ } s0f0;
+ } data;
+};
+
struct ice_aqc_link_topo_params {
u8 lport_num;
u8 lport_num_valid;
@@ -2070,78 +2095,6 @@ struct ice_aqc_add_rdma_qset_data {
struct ice_aqc_add_tx_rdma_qset_entry rdma_qsets[];
};
-/* Configure Firmware Logging Command (indirect 0xFF09)
- * Logging Information Read Response (indirect 0xFF10)
- * Note: The 0xFF10 command has no input parameters.
- */
-struct ice_aqc_fw_logging {
- u8 log_ctrl;
-#define ICE_AQC_FW_LOG_AQ_EN BIT(0)
-#define ICE_AQC_FW_LOG_UART_EN BIT(1)
- u8 rsvd0;
- u8 log_ctrl_valid; /* Not used by 0xFF10 Response */
-#define ICE_AQC_FW_LOG_AQ_VALID BIT(0)
-#define ICE_AQC_FW_LOG_UART_VALID BIT(1)
- u8 rsvd1[5];
- __le32 addr_high;
- __le32 addr_low;
-};
-
-enum ice_aqc_fw_logging_mod {
- ICE_AQC_FW_LOG_ID_GENERAL = 0,
- ICE_AQC_FW_LOG_ID_CTRL,
- ICE_AQC_FW_LOG_ID_LINK,
- ICE_AQC_FW_LOG_ID_LINK_TOPO,
- ICE_AQC_FW_LOG_ID_DNL,
- ICE_AQC_FW_LOG_ID_I2C,
- ICE_AQC_FW_LOG_ID_SDP,
- ICE_AQC_FW_LOG_ID_MDIO,
- ICE_AQC_FW_LOG_ID_ADMINQ,
- ICE_AQC_FW_LOG_ID_HDMA,
- ICE_AQC_FW_LOG_ID_LLDP,
- ICE_AQC_FW_LOG_ID_DCBX,
- ICE_AQC_FW_LOG_ID_DCB,
- ICE_AQC_FW_LOG_ID_NETPROXY,
- ICE_AQC_FW_LOG_ID_NVM,
- ICE_AQC_FW_LOG_ID_AUTH,
- ICE_AQC_FW_LOG_ID_VPD,
- ICE_AQC_FW_LOG_ID_IOSF,
- ICE_AQC_FW_LOG_ID_PARSER,
- ICE_AQC_FW_LOG_ID_SW,
- ICE_AQC_FW_LOG_ID_SCHEDULER,
- ICE_AQC_FW_LOG_ID_TXQ,
- ICE_AQC_FW_LOG_ID_RSVD,
- ICE_AQC_FW_LOG_ID_POST,
- ICE_AQC_FW_LOG_ID_WATCHDOG,
- ICE_AQC_FW_LOG_ID_TASK_DISPATCH,
- ICE_AQC_FW_LOG_ID_MNG,
- ICE_AQC_FW_LOG_ID_MAX,
-};
-
-/* Defines for both above FW logging command/response buffers */
-#define ICE_AQC_FW_LOG_ID_S 0
-#define ICE_AQC_FW_LOG_ID_M (0xFFF << ICE_AQC_FW_LOG_ID_S)
-
-#define ICE_AQC_FW_LOG_CONF_SUCCESS 0 /* Used by response */
-#define ICE_AQC_FW_LOG_CONF_BAD_INDX BIT(12) /* Used by response */
-
-#define ICE_AQC_FW_LOG_EN_S 12
-#define ICE_AQC_FW_LOG_EN_M (0xF << ICE_AQC_FW_LOG_EN_S)
-#define ICE_AQC_FW_LOG_INFO_EN BIT(12) /* Used by command */
-#define ICE_AQC_FW_LOG_INIT_EN BIT(13) /* Used by command */
-#define ICE_AQC_FW_LOG_FLOW_EN BIT(14) /* Used by command */
-#define ICE_AQC_FW_LOG_ERR_EN BIT(15) /* Used by command */
-
-/* Get/Clear FW Log (indirect 0xFF11) */
-struct ice_aqc_get_clear_fw_log {
- u8 flags;
-#define ICE_AQC_FW_LOG_CLEAR BIT(0)
-#define ICE_AQC_FW_LOG_MORE_DATA_AVAIL BIT(1)
- u8 rsvd1[7];
- __le32 addr_high;
- __le32 addr_low;
-};
-
/* Download Package (indirect 0x0C40) */
/* Also used for Update Package (indirect 0x0C41 and 0x0C42) */
struct ice_aqc_download_pkg {
@@ -2404,6 +2357,84 @@ struct ice_aqc_event_lan_overflow {
u8 reserved[8];
};
+enum ice_aqc_fw_logging_mod {
+ ICE_AQC_FW_LOG_ID_GENERAL = 0,
+ ICE_AQC_FW_LOG_ID_CTRL,
+ ICE_AQC_FW_LOG_ID_LINK,
+ ICE_AQC_FW_LOG_ID_LINK_TOPO,
+ ICE_AQC_FW_LOG_ID_DNL,
+ ICE_AQC_FW_LOG_ID_I2C,
+ ICE_AQC_FW_LOG_ID_SDP,
+ ICE_AQC_FW_LOG_ID_MDIO,
+ ICE_AQC_FW_LOG_ID_ADMINQ,
+ ICE_AQC_FW_LOG_ID_HDMA,
+ ICE_AQC_FW_LOG_ID_LLDP,
+ ICE_AQC_FW_LOG_ID_DCBX,
+ ICE_AQC_FW_LOG_ID_DCB,
+ ICE_AQC_FW_LOG_ID_XLR,
+ ICE_AQC_FW_LOG_ID_NVM,
+ ICE_AQC_FW_LOG_ID_AUTH,
+ ICE_AQC_FW_LOG_ID_VPD,
+ ICE_AQC_FW_LOG_ID_IOSF,
+ ICE_AQC_FW_LOG_ID_PARSER,
+ ICE_AQC_FW_LOG_ID_SW,
+ ICE_AQC_FW_LOG_ID_SCHEDULER,
+ ICE_AQC_FW_LOG_ID_TXQ,
+ ICE_AQC_FW_LOG_ID_RSVD,
+ ICE_AQC_FW_LOG_ID_POST,
+ ICE_AQC_FW_LOG_ID_WATCHDOG,
+ ICE_AQC_FW_LOG_ID_TASK_DISPATCH,
+ ICE_AQC_FW_LOG_ID_MNG,
+ ICE_AQC_FW_LOG_ID_SYNCE,
+ ICE_AQC_FW_LOG_ID_HEALTH,
+ ICE_AQC_FW_LOG_ID_TSDRV,
+ ICE_AQC_FW_LOG_ID_PFREG,
+ ICE_AQC_FW_LOG_ID_MDLVER,
+ ICE_AQC_FW_LOG_ID_MAX,
+};
+
+/* Set FW Logging configuration (indirect 0xFF30)
+ * Register for FW Logging (indirect 0xFF31)
+ * Query FW Logging (indirect 0xFF32)
+ * FW Log Event (indirect 0xFF33)
+ */
+struct ice_aqc_fw_log {
+ u8 cmd_flags;
+#define ICE_AQC_FW_LOG_CONF_UART_EN BIT(0)
+#define ICE_AQC_FW_LOG_CONF_AQ_EN BIT(1)
+#define ICE_AQC_FW_LOG_QUERY_REGISTERED BIT(2)
+#define ICE_AQC_FW_LOG_CONF_SET_VALID BIT(3)
+#define ICE_AQC_FW_LOG_AQ_REGISTER BIT(0)
+#define ICE_AQC_FW_LOG_AQ_QUERY BIT(2)
+
+ u8 rsp_flag;
+ __le16 fw_rt_msb;
+ union {
+ struct {
+ __le32 fw_rt_lsb;
+ } sync;
+ struct {
+ __le16 log_resolution;
+#define ICE_AQC_FW_LOG_MIN_RESOLUTION (1)
+#define ICE_AQC_FW_LOG_MAX_RESOLUTION (128)
+
+ __le16 mdl_cnt;
+ } cfg;
+ } ops;
+ __le32 addr_high;
+ __le32 addr_low;
+};
+
+/* Response Buffer for:
+ * Set Firmware Logging Configuration (0xFF30)
+ * Query FW Logging (0xFF32)
+ */
+struct ice_aqc_fw_log_cfg_resp {
+ __le16 module_identifier;
+ u8 log_level;
+ u8 rsvd0;
+};
+
/**
* struct ice_aq_desc - Admin Queue (AQ) descriptor
* @flags: ICE_AQ_FLAG_* flags
@@ -2444,6 +2475,8 @@ struct ice_aq_desc {
struct ice_aqc_restart_an restart_an;
struct ice_aqc_set_phy_rec_clk_out set_phy_rec_clk_out;
struct ice_aqc_get_phy_rec_clk_out get_phy_rec_clk_out;
+ struct ice_aqc_get_sensor_reading get_sensor_reading;
+ struct ice_aqc_get_sensor_reading_resp get_sensor_reading_resp;
struct ice_aqc_gpio read_write_gpio;
struct ice_aqc_sff_eeprom read_write_sff_param;
struct ice_aqc_set_port_id_led set_port_id_led;
@@ -2481,8 +2514,6 @@ struct ice_aq_desc {
struct ice_aqc_add_rdma_qset add_rdma_qset;
struct ice_aqc_add_get_update_free_vsi vsi_cmd;
struct ice_aqc_add_update_free_vsi_resp add_update_free_vsi_res;
- struct ice_aqc_fw_logging fw_logging;
- struct ice_aqc_get_clear_fw_log get_clear_fw_log;
struct ice_aqc_download_pkg download_pkg;
struct ice_aqc_set_cgu_input_config set_cgu_input_config;
struct ice_aqc_get_cgu_input_config get_cgu_input_config;
@@ -2494,6 +2525,7 @@ struct ice_aq_desc {
struct ice_aqc_get_cgu_ref_prio get_cgu_ref_prio;
struct ice_aqc_get_cgu_info get_cgu_info;
struct ice_aqc_driver_shared_params drv_shared_params;
+ struct ice_aqc_fw_log fw_log;
struct ice_aqc_set_mac_lb set_mac_lb;
struct ice_aqc_alloc_free_res_cmd sw_res_ctrl;
struct ice_aqc_set_mac_cfg set_mac_cfg;
@@ -2619,6 +2651,7 @@ enum ice_adminq_opc {
ice_aqc_opc_set_mac_lb = 0x0620,
ice_aqc_opc_set_phy_rec_clk_out = 0x0630,
ice_aqc_opc_get_phy_rec_clk_out = 0x0631,
+ ice_aqc_opc_get_sensor_reading = 0x0632,
ice_aqc_opc_get_link_topo = 0x06E0,
ice_aqc_opc_read_i2c = 0x06E2,
ice_aqc_opc_write_i2c = 0x06E3,
@@ -2691,9 +2724,11 @@ enum ice_adminq_opc {
/* Standalone Commands/Events */
ice_aqc_opc_event_lan_overflow = 0x1001,
- /* debug commands */
- ice_aqc_opc_fw_logging = 0xFF09,
- ice_aqc_opc_fw_logging_info = 0xFF10,
+ /* FW Logging Commands */
+ ice_aqc_opc_fw_logs_config = 0xFF30,
+ ice_aqc_opc_fw_logs_register = 0xFF31,
+ ice_aqc_opc_fw_logs_query = 0xFF32,
+ ice_aqc_opc_fw_logs_event = 0xFF33,
};
#endif /* _ICE_ADMINQ_CMD_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index 7fa43827a3f0..c979192e44d1 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -189,10 +189,16 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx)
}
q_vector = vsi->q_vectors[v_idx];
- ice_for_each_tx_ring(tx_ring, q_vector->tx)
+ ice_for_each_tx_ring(tx_ring, q_vector->tx) {
+ ice_queue_set_napi(vsi, tx_ring->q_index, NETDEV_QUEUE_TYPE_TX,
+ NULL);
tx_ring->q_vector = NULL;
- ice_for_each_rx_ring(rx_ring, q_vector->rx)
+ }
+ ice_for_each_rx_ring(rx_ring, q_vector->rx) {
+ ice_queue_set_napi(vsi, rx_ring->q_index, NETDEV_QUEUE_TYPE_RX,
+ NULL);
rx_ring->q_vector = NULL;
+ }
/* only VSI with an associated netdev is set up with NAPI */
if (vsi->netdev)
@@ -224,24 +230,16 @@ static void ice_cfg_itr_gran(struct ice_hw *hw)
/* no need to update global register if ITR gran is already set */
if (!(regval & GLINT_CTL_DIS_AUTOMASK_M) &&
- (((regval & GLINT_CTL_ITR_GRAN_200_M) >>
- GLINT_CTL_ITR_GRAN_200_S) == ICE_ITR_GRAN_US) &&
- (((regval & GLINT_CTL_ITR_GRAN_100_M) >>
- GLINT_CTL_ITR_GRAN_100_S) == ICE_ITR_GRAN_US) &&
- (((regval & GLINT_CTL_ITR_GRAN_50_M) >>
- GLINT_CTL_ITR_GRAN_50_S) == ICE_ITR_GRAN_US) &&
- (((regval & GLINT_CTL_ITR_GRAN_25_M) >>
- GLINT_CTL_ITR_GRAN_25_S) == ICE_ITR_GRAN_US))
+ (FIELD_GET(GLINT_CTL_ITR_GRAN_200_M, regval) == ICE_ITR_GRAN_US) &&
+ (FIELD_GET(GLINT_CTL_ITR_GRAN_100_M, regval) == ICE_ITR_GRAN_US) &&
+ (FIELD_GET(GLINT_CTL_ITR_GRAN_50_M, regval) == ICE_ITR_GRAN_US) &&
+ (FIELD_GET(GLINT_CTL_ITR_GRAN_25_M, regval) == ICE_ITR_GRAN_US))
return;
- regval = ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_200_S) &
- GLINT_CTL_ITR_GRAN_200_M) |
- ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_100_S) &
- GLINT_CTL_ITR_GRAN_100_M) |
- ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_50_S) &
- GLINT_CTL_ITR_GRAN_50_M) |
- ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_25_S) &
- GLINT_CTL_ITR_GRAN_25_M);
+ regval = FIELD_PREP(GLINT_CTL_ITR_GRAN_200_M, ICE_ITR_GRAN_US) |
+ FIELD_PREP(GLINT_CTL_ITR_GRAN_100_M, ICE_ITR_GRAN_US) |
+ FIELD_PREP(GLINT_CTL_ITR_GRAN_50_M, ICE_ITR_GRAN_US) |
+ FIELD_PREP(GLINT_CTL_ITR_GRAN_25_M, ICE_ITR_GRAN_US);
wr32(hw, GLINT_CTL, regval);
}
@@ -278,7 +276,7 @@ static u16 ice_calc_txq_handle(struct ice_vsi *vsi, struct ice_tx_ring *ring, u8
*/
static u16 ice_eswitch_calc_txq_handle(struct ice_tx_ring *ring)
{
- struct ice_vsi *vsi = ring->vsi;
+ const struct ice_vsi *vsi = ring->vsi;
int i;
ice_for_each_txq(vsi, i) {
@@ -519,6 +517,19 @@ static int ice_setup_rx_ctx(struct ice_rx_ring *ring)
return 0;
}
+static void ice_xsk_pool_fill_cb(struct ice_rx_ring *ring)
+{
+ void *ctx_ptr = &ring->pkt_ctx;
+ struct xsk_cb_desc desc = {};
+
+ XSK_CHECK_PRIV_TYPE(struct ice_xdp_buff);
+ desc.src = &ctx_ptr;
+ desc.off = offsetof(struct ice_xdp_buff, pkt_ctx) -
+ sizeof(struct xdp_buff);
+ desc.bytes = sizeof(ctx_ptr);
+ xsk_pool_fill_cb(ring->xsk_pool, &desc);
+}
+
/**
* ice_vsi_cfg_rxq - Configure an Rx queue
* @ring: the ring being configured
@@ -534,36 +545,46 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
ring->rx_buf_len = ring->vsi->rx_buf_len;
if (ring->vsi->type == ICE_VSI_PF) {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
- /* coverity[check_return] */
- __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->vsi->rx_buf_len);
+ if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ring->rx_buf_len);
+ if (err)
+ return err;
+ }
ring->xsk_pool = ice_xsk_pool(ring);
if (ring->xsk_pool) {
- xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq);
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
ring->rx_buf_len =
xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ring->rx_buf_len);
+ if (err)
+ return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL);
if (err)
return err;
xsk_pool_set_rxq_info(ring->xsk_pool, &ring->xdp_rxq);
+ ice_xsk_pool_fill_cb(ring);
dev_info(dev, "Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
ring->q_index);
} else {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq))
- /* coverity[check_return] */
- __xdp_rxq_info_reg(&ring->xdp_rxq,
- ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->vsi->rx_buf_len);
+ if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ring->rx_buf_len);
+ if (err)
+ return err;
+ }
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED,
@@ -575,6 +596,7 @@ int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
xdp_init_buff(&ring->xdp, ice_rx_pg_size(ring) / 2, &ring->xdp_rxq);
ring->xdp.data = NULL;
+ ring->xdp_ext.pkt_ctx = &ring->pkt_ctx;
err = ice_setup_rx_ctx(ring);
if (err) {
dev_err(dev, "ice_setup_rx_ctx failed for RxQ %d, err %d\n",
@@ -913,10 +935,10 @@ ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx)
struct ice_hw *hw = &pf->hw;
u32 val;
- itr_idx = (itr_idx << QINT_TQCTL_ITR_INDX_S) & QINT_TQCTL_ITR_INDX_M;
+ itr_idx = FIELD_PREP(QINT_TQCTL_ITR_INDX_M, itr_idx);
val = QINT_TQCTL_CAUSE_ENA_M | itr_idx |
- ((msix_idx << QINT_TQCTL_MSIX_INDX_S) & QINT_TQCTL_MSIX_INDX_M);
+ FIELD_PREP(QINT_TQCTL_MSIX_INDX_M, msix_idx);
wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val);
if (ice_is_xdp_ena_vsi(vsi)) {
@@ -945,10 +967,10 @@ ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx)
struct ice_hw *hw = &pf->hw;
u32 val;
- itr_idx = (itr_idx << QINT_RQCTL_ITR_INDX_S) & QINT_RQCTL_ITR_INDX_M;
+ itr_idx = FIELD_PREP(QINT_RQCTL_ITR_INDX_M, itr_idx);
val = QINT_RQCTL_CAUSE_ENA_M | itr_idx |
- ((msix_idx << QINT_RQCTL_MSIX_INDX_S) & QINT_RQCTL_MSIX_INDX_M);
+ FIELD_PREP(QINT_RQCTL_MSIX_INDX_M, msix_idx);
wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val);
@@ -960,7 +982,7 @@ ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx)
* @hw: pointer to the HW structure
* @q_vector: interrupt vector to trigger the software interrupt for
*/
-void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector)
+void ice_trigger_sw_intr(struct ice_hw *hw, const struct ice_q_vector *q_vector)
{
wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx),
(ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S) |
@@ -1035,7 +1057,7 @@ ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
* are needed for stopping Tx queue
*/
void
-ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ice_fill_txq_meta(const struct ice_vsi *vsi, struct ice_tx_ring *ring,
struct ice_txq_meta *txq_meta)
{
struct ice_channel *ch = ring->ch;
diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h
index b67dca417acb..17321ba75602 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.h
+++ b/drivers/net/ethernet/intel/ice/ice_base.h
@@ -22,12 +22,12 @@ void
ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx);
void
ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx);
-void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector);
+void ice_trigger_sw_intr(struct ice_hw *hw, const struct ice_q_vector *q_vector);
int
ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
u16 rel_vmvf_num, struct ice_tx_ring *ring,
struct ice_txq_meta *txq_meta);
void
-ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_tx_ring *ring,
+ice_fill_txq_meta(const struct ice_vsi *vsi, struct ice_tx_ring *ring,
struct ice_txq_meta *txq_meta);
#endif /* _ICE_BASE_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index edac34c796ce..10c32cd80fff 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -934,216 +934,6 @@ static void ice_cleanup_fltr_mgmt_struct(struct ice_hw *hw)
}
/**
- * ice_get_fw_log_cfg - get FW logging configuration
- * @hw: pointer to the HW struct
- */
-static int ice_get_fw_log_cfg(struct ice_hw *hw)
-{
- struct ice_aq_desc desc;
- __le16 *config;
- int status;
- u16 size;
-
- size = sizeof(*config) * ICE_AQC_FW_LOG_ID_MAX;
- config = kzalloc(size, GFP_KERNEL);
- if (!config)
- return -ENOMEM;
-
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging_info);
-
- status = ice_aq_send_cmd(hw, &desc, config, size, NULL);
- if (!status) {
- u16 i;
-
- /* Save FW logging information into the HW structure */
- for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
- u16 v, m, flgs;
-
- v = le16_to_cpu(config[i]);
- m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
- flgs = (v & ICE_AQC_FW_LOG_EN_M) >> ICE_AQC_FW_LOG_EN_S;
-
- if (m < ICE_AQC_FW_LOG_ID_MAX)
- hw->fw_log.evnts[m].cur = flgs;
- }
- }
-
- kfree(config);
-
- return status;
-}
-
-/**
- * ice_cfg_fw_log - configure FW logging
- * @hw: pointer to the HW struct
- * @enable: enable certain FW logging events if true, disable all if false
- *
- * This function enables/disables the FW logging via Rx CQ events and a UART
- * port based on predetermined configurations. FW logging via the Rx CQ can be
- * enabled/disabled for individual PF's. However, FW logging via the UART can
- * only be enabled/disabled for all PFs on the same device.
- *
- * To enable overall FW logging, the "cq_en" and "uart_en" enable bits in
- * hw->fw_log need to be set accordingly, e.g. based on user-provided input,
- * before initializing the device.
- *
- * When re/configuring FW logging, callers need to update the "cfg" elements of
- * the hw->fw_log.evnts array with the desired logging event configurations for
- * modules of interest. When disabling FW logging completely, the callers can
- * just pass false in the "enable" parameter. On completion, the function will
- * update the "cur" element of the hw->fw_log.evnts array with the resulting
- * logging event configurations of the modules that are being re/configured. FW
- * logging modules that are not part of a reconfiguration operation retain their
- * previous states.
- *
- * Before resetting the device, it is recommended that the driver disables FW
- * logging before shutting down the control queue. When disabling FW logging
- * ("enable" = false), the latest configurations of FW logging events stored in
- * hw->fw_log.evnts[] are not overridden to allow them to be reconfigured after
- * a device reset.
- *
- * When enabling FW logging to emit log messages via the Rx CQ during the
- * device's initialization phase, a mechanism alternative to interrupt handlers
- * needs to be used to extract FW log messages from the Rx CQ periodically and
- * to prevent the Rx CQ from being full and stalling other types of control
- * messages from FW to SW. Interrupts are typically disabled during the device's
- * initialization phase.
- */
-static int ice_cfg_fw_log(struct ice_hw *hw, bool enable)
-{
- struct ice_aqc_fw_logging *cmd;
- u16 i, chgs = 0, len = 0;
- struct ice_aq_desc desc;
- __le16 *data = NULL;
- u8 actv_evnts = 0;
- void *buf = NULL;
- int status = 0;
-
- if (!hw->fw_log.cq_en && !hw->fw_log.uart_en)
- return 0;
-
- /* Disable FW logging only when the control queue is still responsive */
- if (!enable &&
- (!hw->fw_log.actv_evnts || !ice_check_sq_alive(hw, &hw->adminq)))
- return 0;
-
- /* Get current FW log settings */
- status = ice_get_fw_log_cfg(hw);
- if (status)
- return status;
-
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logging);
- cmd = &desc.params.fw_logging;
-
- /* Indicate which controls are valid */
- if (hw->fw_log.cq_en)
- cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_AQ_VALID;
-
- if (hw->fw_log.uart_en)
- cmd->log_ctrl_valid |= ICE_AQC_FW_LOG_UART_VALID;
-
- if (enable) {
- /* Fill in an array of entries with FW logging modules and
- * logging events being reconfigured.
- */
- for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
- u16 val;
-
- /* Keep track of enabled event types */
- actv_evnts |= hw->fw_log.evnts[i].cfg;
-
- if (hw->fw_log.evnts[i].cfg == hw->fw_log.evnts[i].cur)
- continue;
-
- if (!data) {
- data = devm_kcalloc(ice_hw_to_dev(hw),
- ICE_AQC_FW_LOG_ID_MAX,
- sizeof(*data),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- }
-
- val = i << ICE_AQC_FW_LOG_ID_S;
- val |= hw->fw_log.evnts[i].cfg << ICE_AQC_FW_LOG_EN_S;
- data[chgs++] = cpu_to_le16(val);
- }
-
- /* Only enable FW logging if at least one module is specified.
- * If FW logging is currently enabled but all modules are not
- * enabled to emit log messages, disable FW logging altogether.
- */
- if (actv_evnts) {
- /* Leave if there is effectively no change */
- if (!chgs)
- goto out;
-
- if (hw->fw_log.cq_en)
- cmd->log_ctrl |= ICE_AQC_FW_LOG_AQ_EN;
-
- if (hw->fw_log.uart_en)
- cmd->log_ctrl |= ICE_AQC_FW_LOG_UART_EN;
-
- buf = data;
- len = sizeof(*data) * chgs;
- desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
- }
- }
-
- status = ice_aq_send_cmd(hw, &desc, buf, len, NULL);
- if (!status) {
- /* Update the current configuration to reflect events enabled.
- * hw->fw_log.cq_en and hw->fw_log.uart_en indicate if the FW
- * logging mode is enabled for the device. They do not reflect
- * actual modules being enabled to emit log messages. So, their
- * values remain unchanged even when all modules are disabled.
- */
- u16 cnt = enable ? chgs : (u16)ICE_AQC_FW_LOG_ID_MAX;
-
- hw->fw_log.actv_evnts = actv_evnts;
- for (i = 0; i < cnt; i++) {
- u16 v, m;
-
- if (!enable) {
- /* When disabling all FW logging events as part
- * of device's de-initialization, the original
- * configurations are retained, and can be used
- * to reconfigure FW logging later if the device
- * is re-initialized.
- */
- hw->fw_log.evnts[i].cur = 0;
- continue;
- }
-
- v = le16_to_cpu(data[i]);
- m = (v & ICE_AQC_FW_LOG_ID_M) >> ICE_AQC_FW_LOG_ID_S;
- hw->fw_log.evnts[m].cur = hw->fw_log.evnts[m].cfg;
- }
- }
-
-out:
- devm_kfree(ice_hw_to_dev(hw), data);
-
- return status;
-}
-
-/**
- * ice_output_fw_log
- * @hw: pointer to the HW struct
- * @desc: pointer to the AQ message descriptor
- * @buf: pointer to the buffer accompanying the AQ message
- *
- * Formats a FW Log message and outputs it via the standard driver logs.
- */
-void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
-{
- ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg Start ]\n");
- ice_debug_array(hw, ICE_DBG_FW_LOG, 16, 1, (u8 *)buf,
- le16_to_cpu(desc->datalen));
- ice_debug(hw, ICE_DBG_FW_LOG, "[ FW Log Msg End ]\n");
-}
-
-/**
* ice_get_itr_intrl_gran
* @hw: pointer to the HW struct
*
@@ -1152,9 +942,8 @@ void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf)
*/
static void ice_get_itr_intrl_gran(struct ice_hw *hw)
{
- u8 max_agg_bw = (rd32(hw, GL_PWR_MODE_CTL) &
- GL_PWR_MODE_CTL_CAR_MAX_BW_M) >>
- GL_PWR_MODE_CTL_CAR_MAX_BW_S;
+ u8 max_agg_bw = FIELD_GET(GL_PWR_MODE_CTL_CAR_MAX_BW_M,
+ rd32(hw, GL_PWR_MODE_CTL));
switch (max_agg_bw) {
case ICE_MAX_AGG_BW_200G:
@@ -1186,9 +975,7 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
return status;
- hw->pf_id = (u8)(rd32(hw, PF_FUNC_RID) &
- PF_FUNC_RID_FUNC_NUM_M) >>
- PF_FUNC_RID_FUNC_NUM_S;
+ hw->pf_id = FIELD_GET(PF_FUNC_RID_FUNC_NUM_M, rd32(hw, PF_FUNC_RID));
status = ice_reset(hw, ICE_RESET_PFR);
if (status)
@@ -1200,10 +987,10 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_cqinit;
- /* Enable FW logging. Not fatal if this fails. */
- status = ice_cfg_fw_log(hw, true);
+ status = ice_fwlog_init(hw);
if (status)
- ice_debug(hw, ICE_DBG_INIT, "Failed to enable FW logging.\n");
+ ice_debug(hw, ICE_DBG_FW_LOG, "Error initializing FW logging: %d\n",
+ status);
status = ice_clear_pf_cfg(hw);
if (status)
@@ -1354,8 +1141,7 @@ void ice_deinit_hw(struct ice_hw *hw)
ice_free_hw_tbls(hw);
mutex_destroy(&hw->tnl_lock);
- /* Attempt to disable FW logging before shutting down control queues */
- ice_cfg_fw_log(hw, false);
+ ice_fwlog_deinit(hw);
ice_destroy_all_ctrlq(hw);
/* Clear VSI contexts if not already cleared */
@@ -1374,8 +1160,8 @@ int ice_check_reset(struct ice_hw *hw)
* or EMPR has occurred. The grst delay value is in 100ms units.
* Add 1sec for outstanding AQ commands that can take a long time.
*/
- grst_timeout = ((rd32(hw, GLGEN_RSTCTL) & GLGEN_RSTCTL_GRSTDEL_M) >>
- GLGEN_RSTCTL_GRSTDEL_S) + 10;
+ grst_timeout = FIELD_GET(GLGEN_RSTCTL_GRSTDEL_M,
+ rd32(hw, GLGEN_RSTCTL)) + 10;
for (cnt = 0; cnt < grst_timeout; cnt++) {
mdelay(100);
@@ -2459,7 +2245,7 @@ ice_parse_1588_func_caps(struct ice_hw *hw, struct ice_hw_func_caps *func_p,
info->tmr_index_owned = ((number & ICE_TS_TMR_IDX_OWND_M) != 0);
info->tmr_index_assoc = ((number & ICE_TS_TMR_IDX_ASSOC_M) != 0);
- info->clk_freq = (number & ICE_TS_CLK_FREQ_M) >> ICE_TS_CLK_FREQ_S;
+ info->clk_freq = FIELD_GET(ICE_TS_CLK_FREQ_M, number);
info->clk_src = ((number & ICE_TS_CLK_SRC_M) != 0);
if (info->clk_freq < NUM_ICE_TIME_REF_FREQ) {
@@ -2660,11 +2446,12 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
info->tmr0_owned = ((number & ICE_TS_TMR0_OWND_M) != 0);
info->tmr0_ena = ((number & ICE_TS_TMR0_ENA_M) != 0);
- info->tmr1_owner = (number & ICE_TS_TMR1_OWNR_M) >> ICE_TS_TMR1_OWNR_S;
+ info->tmr1_owner = FIELD_GET(ICE_TS_TMR1_OWNR_M, number);
info->tmr1_owned = ((number & ICE_TS_TMR1_OWND_M) != 0);
info->tmr1_ena = ((number & ICE_TS_TMR1_ENA_M) != 0);
info->ts_ll_read = ((number & ICE_TS_LL_TX_TS_READ_M) != 0);
+ info->ts_ll_int_read = ((number & ICE_TS_LL_TX_TS_INT_READ_M) != 0);
info->ena_ports = logical_id;
info->tmr_own_map = phys_id;
@@ -2685,6 +2472,8 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
info->tmr1_ena);
ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_read = %u\n",
info->ts_ll_read);
+ ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_int_read = %u\n",
+ info->ts_ll_int_read);
ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 ena_ports = %u\n",
info->ena_ports);
ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr_own_map = %u\n",
@@ -2711,6 +2500,26 @@ ice_parse_fdir_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
}
/**
+ * ice_parse_sensor_reading_cap - Parse ICE_AQC_CAPS_SENSOR_READING cap
+ * @hw: pointer to the HW struct
+ * @dev_p: pointer to device capabilities structure
+ * @cap: capability element to parse
+ *
+ * Parse ICE_AQC_CAPS_SENSOR_READING for device capability for reading
+ * enabled sensors.
+ */
+static void
+ice_parse_sensor_reading_cap(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
+ struct ice_aqc_list_caps_elem *cap)
+{
+ dev_p->supported_sensors = le32_to_cpu(cap->number);
+
+ ice_debug(hw, ICE_DBG_INIT,
+ "dev caps: supported sensors (bitmap) = 0x%x\n",
+ dev_p->supported_sensors);
+}
+
+/**
* ice_parse_dev_caps - Parse device capabilities
* @hw: pointer to the HW struct
* @dev_p: pointer to device capabilities structure
@@ -2755,9 +2564,12 @@ ice_parse_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
case ICE_AQC_CAPS_1588:
ice_parse_1588_dev_caps(hw, dev_p, &cap_resp[i]);
break;
- case ICE_AQC_CAPS_FD:
+ case ICE_AQC_CAPS_FD:
ice_parse_fdir_dev_caps(hw, dev_p, &cap_resp[i]);
break;
+ case ICE_AQC_CAPS_SENSOR_READING:
+ ice_parse_sensor_reading_cap(hw, dev_p, &cap_resp[i]);
+ break;
default:
/* Don't list common capabilities as unknown */
if (!found)
@@ -4072,6 +3884,7 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
{
struct ice_aqc_sff_eeprom *cmd;
struct ice_aq_desc desc;
+ u16 i2c_bus_addr;
int status;
if (!data || (mem_addr & 0xff00))
@@ -4082,15 +3895,13 @@ ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
desc.flags = cpu_to_le16(ICE_AQ_FLAG_RD);
cmd->lport_num = (u8)(lport & 0xff);
cmd->lport_num_valid = (u8)((lport >> 8) & 0x01);
- cmd->i2c_bus_addr = cpu_to_le16(((bus_addr >> 1) &
- ICE_AQC_SFF_I2CBUS_7BIT_M) |
- ((set_page <<
- ICE_AQC_SFF_SET_EEPROM_PAGE_S) &
- ICE_AQC_SFF_SET_EEPROM_PAGE_M));
- cmd->i2c_mem_addr = cpu_to_le16(mem_addr & 0xff);
- cmd->eeprom_page = cpu_to_le16((u16)page << ICE_AQC_SFF_EEPROM_PAGE_S);
+ i2c_bus_addr = FIELD_PREP(ICE_AQC_SFF_I2CBUS_7BIT_M, bus_addr >> 1) |
+ FIELD_PREP(ICE_AQC_SFF_SET_EEPROM_PAGE_M, set_page);
if (write)
- cmd->i2c_bus_addr |= cpu_to_le16(ICE_AQC_SFF_IS_WRITE);
+ i2c_bus_addr |= ICE_AQC_SFF_IS_WRITE;
+ cmd->i2c_bus_addr = cpu_to_le16(i2c_bus_addr);
+ cmd->i2c_mem_addr = cpu_to_le16(mem_addr & 0xff);
+ cmd->eeprom_page = le16_encode_bits(page, ICE_AQC_SFF_EEPROM_PAGE_M);
status = ice_aq_send_cmd(hw, &desc, data, length, cd);
return status;
@@ -4345,6 +4156,7 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
struct ice_aqc_dis_txq_item *item;
struct ice_aqc_dis_txqs *cmd;
struct ice_aq_desc desc;
+ u16 vmvf_and_timeout;
u16 i, sz = 0;
int status;
@@ -4360,27 +4172,26 @@ ice_aq_dis_lan_txq(struct ice_hw *hw, u8 num_qgrps,
cmd->num_entries = num_qgrps;
- cmd->vmvf_and_timeout = cpu_to_le16((5 << ICE_AQC_Q_DIS_TIMEOUT_S) &
- ICE_AQC_Q_DIS_TIMEOUT_M);
+ vmvf_and_timeout = FIELD_PREP(ICE_AQC_Q_DIS_TIMEOUT_M, 5);
switch (rst_src) {
case ICE_VM_RESET:
cmd->cmd_type = ICE_AQC_Q_DIS_CMD_VM_RESET;
- cmd->vmvf_and_timeout |=
- cpu_to_le16(vmvf_num & ICE_AQC_Q_DIS_VMVF_NUM_M);
+ vmvf_and_timeout |= vmvf_num & ICE_AQC_Q_DIS_VMVF_NUM_M;
break;
case ICE_VF_RESET:
cmd->cmd_type = ICE_AQC_Q_DIS_CMD_VF_RESET;
/* In this case, FW expects vmvf_num to be absolute VF ID */
- cmd->vmvf_and_timeout |=
- cpu_to_le16((vmvf_num + hw->func_caps.vf_base_id) &
- ICE_AQC_Q_DIS_VMVF_NUM_M);
+ vmvf_and_timeout |= (vmvf_num + hw->func_caps.vf_base_id) &
+ ICE_AQC_Q_DIS_VMVF_NUM_M;
break;
case ICE_NO_RESET:
default:
break;
}
+ cmd->vmvf_and_timeout = cpu_to_le16(vmvf_and_timeout);
+
/* flush pipe on time out */
cmd->cmd_type |= ICE_AQC_Q_DIS_CMD_FLUSH_PIPE;
/* If no queue group info, we are in a reset flow. Issue the AQ */
@@ -4455,10 +4266,8 @@ ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf,
cmd->cmd_type = ICE_AQC_Q_CFG_TC_CHNG;
cmd->num_qs = num_qs;
cmd->port_num_chng = (oldport & ICE_AQC_Q_CFG_SRC_PRT_M);
- cmd->port_num_chng |= (newport << ICE_AQC_Q_CFG_DST_PRT_S) &
- ICE_AQC_Q_CFG_DST_PRT_M;
- cmd->time_out = (5 << ICE_AQC_Q_CFG_TIMEOUT_S) &
- ICE_AQC_Q_CFG_TIMEOUT_M;
+ cmd->port_num_chng |= FIELD_PREP(ICE_AQC_Q_CFG_DST_PRT_M, newport);
+ cmd->time_out = FIELD_PREP(ICE_AQC_Q_CFG_TIMEOUT_M, 5);
cmd->blocked_cgds = 0;
status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
@@ -5539,6 +5348,35 @@ ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num,
}
/**
+ * ice_aq_get_sensor_reading
+ * @hw: pointer to the HW struct
+ * @data: pointer to data to be read from the sensor
+ *
+ * Get sensor reading (0x0632)
+ */
+int ice_aq_get_sensor_reading(struct ice_hw *hw,
+ struct ice_aqc_get_sensor_reading_resp *data)
+{
+ struct ice_aqc_get_sensor_reading *cmd;
+ struct ice_aq_desc desc;
+ int status;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sensor_reading);
+ cmd = &desc.params.get_sensor_reading;
+#define ICE_INTERNAL_TEMP_SENSOR_FORMAT 0
+#define ICE_INTERNAL_TEMP_SENSOR 0
+ cmd->sensor = ICE_INTERNAL_TEMP_SENSOR;
+ cmd->format = ICE_INTERNAL_TEMP_SENSOR_FORMAT;
+
+ status = ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+ if (!status)
+ memcpy(data, &desc.params.get_sensor_reading_resp,
+ sizeof(*data));
+
+ return status;
+}
+
+/**
* ice_replay_pre_init - replay pre initialization
* @hw: pointer to the HW struct
*
@@ -5933,7 +5771,7 @@ ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
ice_debug(hw, ICE_DBG_INIT, "Failed to read override link options.\n");
return status;
}
- ldo->options = buf & ICE_LINK_OVERRIDE_OPT_M;
+ ldo->options = FIELD_GET(ICE_LINK_OVERRIDE_OPT_M, buf);
ldo->phy_config = (buf & ICE_LINK_OVERRIDE_PHY_CFG_M) >>
ICE_LINK_OVERRIDE_PHY_CFG_S;
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 31fdcac33986..3e933f75e948 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -6,6 +6,7 @@
#include <linux/bitfield.h>
+#include "ice.h"
#include "ice_type.h"
#include "ice_nvm.h"
#include "ice_flex_pipe.h"
@@ -199,7 +200,6 @@ ice_aq_cfg_lan_txq(struct ice_hw *hw, struct ice_aqc_cfg_txqs_buf *buf,
struct ice_sq_cd *cd);
int ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle);
void ice_replay_post(struct ice_hw *hw);
-void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf);
struct ice_q_ctx *
ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle);
int ice_sbq_rw_reg(struct ice_hw *hw, struct ice_sbq_msg_input *in);
@@ -241,6 +241,8 @@ ice_aq_set_phy_rec_clk_out(struct ice_hw *hw, u8 phy_output, bool enable,
int
ice_aq_get_phy_rec_clk_out(struct ice_hw *hw, u8 *phy_output, u8 *port_num,
u8 *flags, u16 *node_handle);
+int ice_aq_get_sensor_reading(struct ice_hw *hw,
+ struct ice_aqc_get_sensor_reading_resp *data);
void
ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded,
u64 *prev_stat, u64 *cur_stat);
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb.c b/drivers/net/ethernet/intel/ice/ice_dcb.c
index 396e555023aa..74418c445cc4 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb.c
@@ -35,8 +35,7 @@ ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf,
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_get_mib);
cmd->type = mib_type & ICE_AQ_LLDP_MIB_TYPE_M;
- cmd->type |= (bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
- ICE_AQ_LLDP_BRID_TYPE_M;
+ cmd->type |= FIELD_PREP(ICE_AQ_LLDP_BRID_TYPE_M, bridge_type);
desc.datalen = cpu_to_le16(buf_size);
@@ -147,8 +146,7 @@ static u8 ice_get_dcbx_status(struct ice_hw *hw)
u32 reg;
reg = rd32(hw, PRTDCB_GENS);
- return (u8)((reg & PRTDCB_GENS_DCBX_STATUS_M) >>
- PRTDCB_GENS_DCBX_STATUS_S);
+ return FIELD_GET(PRTDCB_GENS_DCBX_STATUS_M, reg);
}
/**
@@ -174,11 +172,9 @@ ice_parse_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
*/
for (i = 0; i < 4; i++) {
ets_cfg->prio_table[i * 2] =
- ((buf[offset] & ICE_IEEE_ETS_PRIO_1_M) >>
- ICE_IEEE_ETS_PRIO_1_S);
+ FIELD_GET(ICE_IEEE_ETS_PRIO_1_M, buf[offset]);
ets_cfg->prio_table[i * 2 + 1] =
- ((buf[offset] & ICE_IEEE_ETS_PRIO_0_M) >>
- ICE_IEEE_ETS_PRIO_0_S);
+ FIELD_GET(ICE_IEEE_ETS_PRIO_0_M, buf[offset]);
offset++;
}
@@ -222,11 +218,9 @@ ice_parse_ieee_etscfg_tlv(struct ice_lldp_org_tlv *tlv,
* |1bit | 1bit|3 bits|3bits|
*/
etscfg = &dcbcfg->etscfg;
- etscfg->willing = ((buf[0] & ICE_IEEE_ETS_WILLING_M) >>
- ICE_IEEE_ETS_WILLING_S);
- etscfg->cbs = ((buf[0] & ICE_IEEE_ETS_CBS_M) >> ICE_IEEE_ETS_CBS_S);
- etscfg->maxtcs = ((buf[0] & ICE_IEEE_ETS_MAXTC_M) >>
- ICE_IEEE_ETS_MAXTC_S);
+ etscfg->willing = FIELD_GET(ICE_IEEE_ETS_WILLING_M, buf[0]);
+ etscfg->cbs = FIELD_GET(ICE_IEEE_ETS_CBS_M, buf[0]);
+ etscfg->maxtcs = FIELD_GET(ICE_IEEE_ETS_MAXTC_M, buf[0]);
/* Begin parsing at Priority Assignment Table (offset 1 in buf) */
ice_parse_ieee_ets_common_tlv(&buf[1], etscfg);
@@ -268,11 +262,9 @@ ice_parse_ieee_pfccfg_tlv(struct ice_lldp_org_tlv *tlv,
* -----------------------------------------
* |1bit | 1bit|2 bits|4bits| 1 octet |
*/
- dcbcfg->pfc.willing = ((buf[0] & ICE_IEEE_PFC_WILLING_M) >>
- ICE_IEEE_PFC_WILLING_S);
- dcbcfg->pfc.mbc = ((buf[0] & ICE_IEEE_PFC_MBC_M) >> ICE_IEEE_PFC_MBC_S);
- dcbcfg->pfc.pfccap = ((buf[0] & ICE_IEEE_PFC_CAP_M) >>
- ICE_IEEE_PFC_CAP_S);
+ dcbcfg->pfc.willing = FIELD_GET(ICE_IEEE_PFC_WILLING_M, buf[0]);
+ dcbcfg->pfc.mbc = FIELD_GET(ICE_IEEE_PFC_MBC_M, buf[0]);
+ dcbcfg->pfc.pfccap = FIELD_GET(ICE_IEEE_PFC_CAP_M, buf[0]);
dcbcfg->pfc.pfcena = buf[1];
}
@@ -294,7 +286,7 @@ ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,
u8 *buf;
typelen = ntohs(tlv->typelen);
- len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
+ len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
buf = tlv->tlvinfo;
/* Removing sizeof(ouisubtype) and reserved byte from len.
@@ -314,12 +306,10 @@ ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,
* -----------------------------------------
*/
while (offset < len) {
- dcbcfg->app[i].priority = ((buf[offset] &
- ICE_IEEE_APP_PRIO_M) >>
- ICE_IEEE_APP_PRIO_S);
- dcbcfg->app[i].selector = ((buf[offset] &
- ICE_IEEE_APP_SEL_M) >>
- ICE_IEEE_APP_SEL_S);
+ dcbcfg->app[i].priority = FIELD_GET(ICE_IEEE_APP_PRIO_M,
+ buf[offset]);
+ dcbcfg->app[i].selector = FIELD_GET(ICE_IEEE_APP_SEL_M,
+ buf[offset]);
dcbcfg->app[i].prot_id = (buf[offset + 1] << 0x8) |
buf[offset + 2];
/* Move to next app */
@@ -347,8 +337,7 @@ ice_parse_ieee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
u8 subtype;
ouisubtype = ntohl(tlv->ouisubtype);
- subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
- ICE_LLDP_TLV_SUBTYPE_S);
+ subtype = FIELD_GET(ICE_LLDP_TLV_SUBTYPE_M, ouisubtype);
switch (subtype) {
case ICE_IEEE_SUBTYPE_ETS_CFG:
ice_parse_ieee_etscfg_tlv(tlv, dcbcfg);
@@ -399,11 +388,9 @@ ice_parse_cee_pgcfg_tlv(struct ice_cee_feat_tlv *tlv,
*/
for (i = 0; i < 4; i++) {
etscfg->prio_table[i * 2] =
- ((buf[offset] & ICE_CEE_PGID_PRIO_1_M) >>
- ICE_CEE_PGID_PRIO_1_S);
+ FIELD_GET(ICE_CEE_PGID_PRIO_1_M, buf[offset]);
etscfg->prio_table[i * 2 + 1] =
- ((buf[offset] & ICE_CEE_PGID_PRIO_0_M) >>
- ICE_CEE_PGID_PRIO_0_S);
+ FIELD_GET(ICE_CEE_PGID_PRIO_0_M, buf[offset]);
offset++;
}
@@ -466,7 +453,7 @@ ice_parse_cee_app_tlv(struct ice_cee_feat_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
u8 i;
typelen = ntohs(tlv->hdr.typelen);
- len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
+ len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
dcbcfg->numapps = len / sizeof(*app);
if (!dcbcfg->numapps)
@@ -521,14 +508,13 @@ ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
u32 ouisubtype;
ouisubtype = ntohl(tlv->ouisubtype);
- subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
- ICE_LLDP_TLV_SUBTYPE_S);
+ subtype = FIELD_GET(ICE_LLDP_TLV_SUBTYPE_M, ouisubtype);
/* Return if not CEE DCBX */
if (subtype != ICE_CEE_DCBX_TYPE)
return;
typelen = ntohs(tlv->typelen);
- tlvlen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
+ tlvlen = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
len = sizeof(tlv->typelen) + sizeof(ouisubtype) +
sizeof(struct ice_cee_ctrl_tlv);
/* Return if no CEE DCBX Feature TLVs */
@@ -540,9 +526,8 @@ ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
u16 sublen;
typelen = ntohs(sub_tlv->hdr.typelen);
- sublen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
- subtype = (u8)((typelen & ICE_LLDP_TLV_TYPE_M) >>
- ICE_LLDP_TLV_TYPE_S);
+ sublen = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
+ subtype = FIELD_GET(ICE_LLDP_TLV_TYPE_M, typelen);
switch (subtype) {
case ICE_CEE_SUBTYPE_PG_CFG:
ice_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
@@ -579,7 +564,7 @@ ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
u32 oui;
ouisubtype = ntohl(tlv->ouisubtype);
- oui = ((ouisubtype & ICE_LLDP_TLV_OUI_M) >> ICE_LLDP_TLV_OUI_S);
+ oui = FIELD_GET(ICE_LLDP_TLV_OUI_M, ouisubtype);
switch (oui) {
case ICE_IEEE_8021QAZ_OUI:
ice_parse_ieee_tlv(tlv, dcbcfg);
@@ -616,8 +601,8 @@ static int ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
tlv = (struct ice_lldp_org_tlv *)lldpmib;
while (1) {
typelen = ntohs(tlv->typelen);
- type = ((typelen & ICE_LLDP_TLV_TYPE_M) >> ICE_LLDP_TLV_TYPE_S);
- len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
+ type = FIELD_GET(ICE_LLDP_TLV_TYPE_M, typelen);
+ len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
offset += sizeof(typelen) + len;
/* END TLV or beyond LLDPDU size */
@@ -806,11 +791,11 @@ ice_cee_to_dcb_cfg(struct ice_aqc_get_cee_dcb_cfg_resp *cee_cfg,
*/
for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
dcbcfg->etscfg.prio_table[i * 2] =
- ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_0_M) >>
- ICE_CEE_PGID_PRIO_0_S);
+ FIELD_GET(ICE_CEE_PGID_PRIO_0_M,
+ cee_cfg->oper_prio_tc[i]);
dcbcfg->etscfg.prio_table[i * 2 + 1] =
- ((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_1_M) >>
- ICE_CEE_PGID_PRIO_1_S);
+ FIELD_GET(ICE_CEE_PGID_PRIO_1_M,
+ cee_cfg->oper_prio_tc[i]);
}
ice_for_each_traffic_class(i) {
@@ -982,7 +967,7 @@ void ice_get_dcb_cfg_from_mib_change(struct ice_port_info *pi,
mib = (struct ice_aqc_lldp_get_mib *)&event->desc.params.raw;
- change_type = FIELD_GET(ICE_AQ_LLDP_MIB_TYPE_M, mib->type);
+ change_type = FIELD_GET(ICE_AQ_LLDP_MIB_TYPE_M, mib->type);
if (change_type == ICE_AQ_LLDP_MIB_REMOTE)
dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;
@@ -1483,7 +1468,7 @@ ice_dcb_cfg_to_lldp(u8 *lldpmib, u16 *miblen, struct ice_dcbx_cfg *dcbcfg)
while (1) {
ice_add_dcb_tlv(tlv, dcbcfg, tlvid++);
typelen = ntohs(tlv->typelen);
- len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
+ len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
if (len)
offset += len + 2;
/* END TLV or beyond LLDPDU size */
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
index 850db8e0e6b0..6e20ee610022 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c
@@ -934,7 +934,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring,
skb->priority != TC_PRIO_CONTROL) {
first->vid &= ~VLAN_PRIO_MASK;
/* Mask the lower 3 bits to set the 802.1p priority */
- first->vid |= (skb->priority << VLAN_PRIO_SHIFT) & VLAN_PRIO_MASK;
+ first->vid |= FIELD_PREP(VLAN_PRIO_MASK, skb->priority);
/* if this is not already set it means a VLAN 0 + priority needs
* to be offloaded
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
index e1fbc6de452d..6d50b90a7359 100644
--- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c
@@ -227,7 +227,7 @@ static void ice_get_pfc_delay(struct ice_hw *hw, u16 *delay)
u32 val;
val = rd32(hw, PRTDCB_GENC);
- *delay = (u16)((val & PRTDCB_GENC_PFCLDA_M) >> PRTDCB_GENC_PFCLDA_S);
+ *delay = FIELD_GET(PRTDCB_GENC_PFCLDA_M, val);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_debugfs.c b/drivers/net/ethernet/intel/ice/ice_debugfs.c
new file mode 100644
index 000000000000..c2bfba6b9ead
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_debugfs.c
@@ -0,0 +1,667 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022, Intel Corporation. */
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/vmalloc.h>
+#include "ice.h"
+
+static struct dentry *ice_debugfs_root;
+
+/* create a define that has an extra module that doesn't really exist. this
+ * is so we can add a module 'all' to easily enable/disable all the modules
+ */
+#define ICE_NR_FW_LOG_MODULES (ICE_AQC_FW_LOG_ID_MAX + 1)
+
+/* the ordering in this array is important. it matches the ordering of the
+ * values in the FW so the index is the same value as in ice_aqc_fw_logging_mod
+ */
+static const char * const ice_fwlog_module_string[] = {
+ "general",
+ "ctrl",
+ "link",
+ "link_topo",
+ "dnl",
+ "i2c",
+ "sdp",
+ "mdio",
+ "adminq",
+ "hdma",
+ "lldp",
+ "dcbx",
+ "dcb",
+ "xlr",
+ "nvm",
+ "auth",
+ "vpd",
+ "iosf",
+ "parser",
+ "sw",
+ "scheduler",
+ "txq",
+ "rsvd",
+ "post",
+ "watchdog",
+ "task_dispatch",
+ "mng",
+ "synce",
+ "health",
+ "tsdrv",
+ "pfreg",
+ "mdlver",
+ "all",
+};
+
+/* the ordering in this array is important. it matches the ordering of the
+ * values in the FW so the index is the same value as in ice_fwlog_level
+ */
+static const char * const ice_fwlog_level_string[] = {
+ "none",
+ "error",
+ "warning",
+ "normal",
+ "verbose",
+};
+
+/* the order in this array is important. it matches the ordering of the
+ * values in the FW so the index is the same value as in ice_fwlog_level
+ */
+static const char * const ice_fwlog_log_size[] = {
+ "128K",
+ "256K",
+ "512K",
+ "1M",
+ "2M",
+};
+
+/**
+ * ice_fwlog_print_module_cfg - print current FW logging module configuration
+ * @hw: pointer to the HW structure
+ * @module: module to print
+ * @s: the seq file to put data into
+ */
+static void
+ice_fwlog_print_module_cfg(struct ice_hw *hw, int module, struct seq_file *s)
+{
+ struct ice_fwlog_cfg *cfg = &hw->fwlog_cfg;
+ struct ice_fwlog_module_entry *entry;
+
+ if (module != ICE_AQC_FW_LOG_ID_MAX) {
+ entry = &cfg->module_entries[module];
+
+ seq_printf(s, "\tModule: %s, Log Level: %s\n",
+ ice_fwlog_module_string[entry->module_id],
+ ice_fwlog_level_string[entry->log_level]);
+ } else {
+ int i;
+
+ for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++) {
+ entry = &cfg->module_entries[i];
+
+ seq_printf(s, "\tModule: %s, Log Level: %s\n",
+ ice_fwlog_module_string[entry->module_id],
+ ice_fwlog_level_string[entry->log_level]);
+ }
+ }
+}
+
+static int ice_find_module_by_dentry(struct ice_pf *pf, struct dentry *d)
+{
+ int i, module;
+
+ module = -1;
+ /* find the module based on the dentry */
+ for (i = 0; i < ICE_NR_FW_LOG_MODULES; i++) {
+ if (d == pf->ice_debugfs_pf_fwlog_modules[i]) {
+ module = i;
+ break;
+ }
+ }
+
+ return module;
+}
+
+/**
+ * ice_debugfs_module_show - read from 'module' file
+ * @s: the opened file
+ * @v: pointer to the offset
+ */
+static int ice_debugfs_module_show(struct seq_file *s, void *v)
+{
+ const struct file *filp = s->file;
+ struct dentry *dentry;
+ struct ice_pf *pf;
+ int module;
+
+ dentry = file_dentry(filp);
+ pf = s->private;
+
+ module = ice_find_module_by_dentry(pf, dentry);
+ if (module < 0) {
+ dev_info(ice_pf_to_dev(pf), "unknown module\n");
+ return -EINVAL;
+ }
+
+ ice_fwlog_print_module_cfg(&pf->hw, module, s);
+
+ return 0;
+}
+
+static int ice_debugfs_module_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, ice_debugfs_module_show, inode->i_private);
+}
+
+/**
+ * ice_debugfs_module_write - write into 'module' file
+ * @filp: the opened file
+ * @buf: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ */
+static ssize_t
+ice_debugfs_module_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ice_pf *pf = file_inode(filp)->i_private;
+ struct dentry *dentry = file_dentry(filp);
+ struct device *dev = ice_pf_to_dev(pf);
+ char user_val[16], *cmd_buf;
+ int module, log_level, cnt;
+
+ /* don't allow partial writes or invalid input */
+ if (*ppos != 0 || count > 8)
+ return -EINVAL;
+
+ cmd_buf = memdup_user(buf, count);
+ if (IS_ERR(cmd_buf))
+ return PTR_ERR(cmd_buf);
+
+ module = ice_find_module_by_dentry(pf, dentry);
+ if (module < 0) {
+ dev_info(dev, "unknown module\n");
+ return -EINVAL;
+ }
+
+ cnt = sscanf(cmd_buf, "%s", user_val);
+ if (cnt != 1)
+ return -EINVAL;
+
+ log_level = sysfs_match_string(ice_fwlog_level_string, user_val);
+ if (log_level < 0) {
+ dev_info(dev, "unknown log level '%s'\n", user_val);
+ return -EINVAL;
+ }
+
+ if (module != ICE_AQC_FW_LOG_ID_MAX) {
+ ice_pf_fwlog_update_module(pf, log_level, module);
+ } else {
+ /* the module 'all' is a shortcut so that we can set
+ * all of the modules to the same level quickly
+ */
+ int i;
+
+ for (i = 0; i < ICE_AQC_FW_LOG_ID_MAX; i++)
+ ice_pf_fwlog_update_module(pf, log_level, i);
+ }
+
+ return count;
+}
+
+static const struct file_operations ice_debugfs_module_fops = {
+ .owner = THIS_MODULE,
+ .open = ice_debugfs_module_open,
+ .read = seq_read,
+ .release = single_release,
+ .write = ice_debugfs_module_write,
+};
+
+/**
+ * ice_debugfs_nr_messages_read - read from 'nr_messages' file
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ */
+static ssize_t ice_debugfs_nr_messages_read(struct file *filp,
+ char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct ice_hw *hw = &pf->hw;
+ char buff[32] = {};
+
+ snprintf(buff, sizeof(buff), "%d\n",
+ hw->fwlog_cfg.log_resolution);
+
+ return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
+}
+
+/**
+ * ice_debugfs_nr_messages_write - write into 'nr_messages' file
+ * @filp: the opened file
+ * @buf: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ */
+static ssize_t
+ice_debugfs_nr_messages_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_hw *hw = &pf->hw;
+ char user_val[8], *cmd_buf;
+ s16 nr_messages;
+ ssize_t ret;
+
+ /* don't allow partial writes or invalid input */
+ if (*ppos != 0 || count > 4)
+ return -EINVAL;
+
+ cmd_buf = memdup_user(buf, count);
+ if (IS_ERR(cmd_buf))
+ return PTR_ERR(cmd_buf);
+
+ ret = sscanf(cmd_buf, "%s", user_val);
+ if (ret != 1)
+ return -EINVAL;
+
+ ret = kstrtos16(user_val, 0, &nr_messages);
+ if (ret)
+ return ret;
+
+ if (nr_messages < ICE_AQC_FW_LOG_MIN_RESOLUTION ||
+ nr_messages > ICE_AQC_FW_LOG_MAX_RESOLUTION) {
+ dev_err(dev, "Invalid FW log number of messages %d, value must be between %d - %d\n",
+ nr_messages, ICE_AQC_FW_LOG_MIN_RESOLUTION,
+ ICE_AQC_FW_LOG_MAX_RESOLUTION);
+ return -EINVAL;
+ }
+
+ hw->fwlog_cfg.log_resolution = nr_messages;
+
+ return count;
+}
+
+static const struct file_operations ice_debugfs_nr_messages_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = ice_debugfs_nr_messages_read,
+ .write = ice_debugfs_nr_messages_write,
+};
+
+/**
+ * ice_debugfs_enable_read - read from 'enable' file
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ */
+static ssize_t ice_debugfs_enable_read(struct file *filp,
+ char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct ice_hw *hw = &pf->hw;
+ char buff[32] = {};
+
+ snprintf(buff, sizeof(buff), "%u\n",
+ (u16)(hw->fwlog_cfg.options &
+ ICE_FWLOG_OPTION_IS_REGISTERED) >> 3);
+
+ return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
+}
+
+/**
+ * ice_debugfs_enable_write - write into 'enable' file
+ * @filp: the opened file
+ * @buf: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ */
+static ssize_t
+ice_debugfs_enable_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct ice_hw *hw = &pf->hw;
+ char user_val[8], *cmd_buf;
+ bool enable;
+ ssize_t ret;
+
+ /* don't allow partial writes or invalid input */
+ if (*ppos != 0 || count > 2)
+ return -EINVAL;
+
+ cmd_buf = memdup_user(buf, count);
+ if (IS_ERR(cmd_buf))
+ return PTR_ERR(cmd_buf);
+
+ ret = sscanf(cmd_buf, "%s", user_val);
+ if (ret != 1)
+ return -EINVAL;
+
+ ret = kstrtobool(user_val, &enable);
+ if (ret)
+ goto enable_write_error;
+
+ if (enable)
+ hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_ARQ_ENA;
+ else
+ hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA;
+
+ ret = ice_fwlog_set(hw, &hw->fwlog_cfg);
+ if (ret)
+ goto enable_write_error;
+
+ if (enable)
+ ret = ice_fwlog_register(hw);
+ else
+ ret = ice_fwlog_unregister(hw);
+
+ if (ret)
+ goto enable_write_error;
+
+ /* if we get here, nothing went wrong; return count since we didn't
+ * really write anything
+ */
+ ret = (ssize_t)count;
+
+enable_write_error:
+ /* This function always consumes all of the written input, or produces
+ * an error. Check and enforce this. Otherwise, the write operation
+ * won't complete properly.
+ */
+ if (WARN_ON(ret != (ssize_t)count && ret >= 0))
+ ret = -EIO;
+
+ return ret;
+}
+
+static const struct file_operations ice_debugfs_enable_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = ice_debugfs_enable_read,
+ .write = ice_debugfs_enable_write,
+};
+
+/**
+ * ice_debugfs_log_size_read - read from 'log_size' file
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ */
+static ssize_t ice_debugfs_log_size_read(struct file *filp,
+ char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct ice_hw *hw = &pf->hw;
+ char buff[32] = {};
+ int index;
+
+ index = hw->fwlog_ring.index;
+ snprintf(buff, sizeof(buff), "%s\n", ice_fwlog_log_size[index]);
+
+ return simple_read_from_buffer(buffer, count, ppos, buff, strlen(buff));
+}
+
+/**
+ * ice_debugfs_log_size_write - write into 'log_size' file
+ * @filp: the opened file
+ * @buf: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ */
+static ssize_t
+ice_debugfs_log_size_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_hw *hw = &pf->hw;
+ char user_val[8], *cmd_buf;
+ ssize_t ret;
+ int index;
+
+ /* don't allow partial writes or invalid input */
+ if (*ppos != 0 || count > 5)
+ return -EINVAL;
+
+ cmd_buf = memdup_user(buf, count);
+ if (IS_ERR(cmd_buf))
+ return PTR_ERR(cmd_buf);
+
+ ret = sscanf(cmd_buf, "%s", user_val);
+ if (ret != 1)
+ return -EINVAL;
+
+ index = sysfs_match_string(ice_fwlog_log_size, user_val);
+ if (index < 0) {
+ dev_info(dev, "Invalid log size '%s'. The value must be one of 128K, 256K, 512K, 1M, 2M\n",
+ user_val);
+ ret = -EINVAL;
+ goto log_size_write_error;
+ } else if (hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED) {
+ dev_info(dev, "FW logging is currently running. Please disable FW logging to change log_size\n");
+ ret = -EINVAL;
+ goto log_size_write_error;
+ }
+
+ /* free all the buffers and the tracking info and resize */
+ ice_fwlog_realloc_rings(hw, index);
+
+ /* if we get here, nothing went wrong; return count since we didn't
+ * really write anything
+ */
+ ret = (ssize_t)count;
+
+log_size_write_error:
+ /* This function always consumes all of the written input, or produces
+ * an error. Check and enforce this. Otherwise, the write operation
+ * won't complete properly.
+ */
+ if (WARN_ON(ret != (ssize_t)count && ret >= 0))
+ ret = -EIO;
+
+ return ret;
+}
+
+static const struct file_operations ice_debugfs_log_size_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = ice_debugfs_log_size_read,
+ .write = ice_debugfs_log_size_write,
+};
+
+/**
+ * ice_debugfs_data_read - read from 'data' file
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ */
+static ssize_t ice_debugfs_data_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct ice_hw *hw = &pf->hw;
+ int data_copied = 0;
+ bool done = false;
+
+ if (ice_fwlog_ring_empty(&hw->fwlog_ring))
+ return 0;
+
+ while (!ice_fwlog_ring_empty(&hw->fwlog_ring) && !done) {
+ struct ice_fwlog_data *log;
+ u16 cur_buf_len;
+
+ log = &hw->fwlog_ring.rings[hw->fwlog_ring.head];
+ cur_buf_len = log->data_size;
+ if (cur_buf_len >= count) {
+ done = true;
+ continue;
+ }
+
+ if (copy_to_user(buffer, log->data, cur_buf_len)) {
+ /* if there is an error then bail and return whatever
+ * the driver has copied so far
+ */
+ done = true;
+ continue;
+ }
+
+ data_copied += cur_buf_len;
+ buffer += cur_buf_len;
+ count -= cur_buf_len;
+ *ppos += cur_buf_len;
+ ice_fwlog_ring_increment(&hw->fwlog_ring.head,
+ hw->fwlog_ring.size);
+ }
+
+ return data_copied;
+}
+
+/**
+ * ice_debugfs_data_write - write into 'data' file
+ * @filp: the opened file
+ * @buf: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ */
+static ssize_t
+ice_debugfs_data_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct ice_pf *pf = filp->private_data;
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_hw *hw = &pf->hw;
+ ssize_t ret;
+
+ /* don't allow partial writes */
+ if (*ppos != 0)
+ return 0;
+
+ /* any value is allowed to clear the buffer so no need to even look at
+ * what the value is
+ */
+ if (!(hw->fwlog_cfg.options & ICE_FWLOG_OPTION_IS_REGISTERED)) {
+ hw->fwlog_ring.head = 0;
+ hw->fwlog_ring.tail = 0;
+ } else {
+ dev_info(dev, "Can't clear FW log data while FW log running\n");
+ ret = -EINVAL;
+ goto nr_buffs_write_error;
+ }
+
+ /* if we get here, nothing went wrong; return count since we didn't
+ * really write anything
+ */
+ ret = (ssize_t)count;
+
+nr_buffs_write_error:
+ /* This function always consumes all of the written input, or produces
+ * an error. Check and enforce this. Otherwise, the write operation
+ * won't complete properly.
+ */
+ if (WARN_ON(ret != (ssize_t)count && ret >= 0))
+ ret = -EIO;
+
+ return ret;
+}
+
+static const struct file_operations ice_debugfs_data_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = ice_debugfs_data_read,
+ .write = ice_debugfs_data_write,
+};
+
+/**
+ * ice_debugfs_fwlog_init - setup the debugfs directory
+ * @pf: the ice that is starting up
+ */
+void ice_debugfs_fwlog_init(struct ice_pf *pf)
+{
+ const char *name = pci_name(pf->pdev);
+ struct dentry *fw_modules_dir;
+ struct dentry **fw_modules;
+ int i;
+
+ /* only support fw log commands on PF 0 */
+ if (pf->hw.bus.func)
+ return;
+
+ /* allocate space for this first because if it fails then we don't
+ * need to unwind
+ */
+ fw_modules = kcalloc(ICE_NR_FW_LOG_MODULES, sizeof(*fw_modules),
+ GFP_KERNEL);
+ if (!fw_modules)
+ return;
+
+ pf->ice_debugfs_pf = debugfs_create_dir(name, ice_debugfs_root);
+ if (IS_ERR(pf->ice_debugfs_pf))
+ goto err_create_module_files;
+
+ pf->ice_debugfs_pf_fwlog = debugfs_create_dir("fwlog",
+ pf->ice_debugfs_pf);
+ if (IS_ERR(pf->ice_debugfs_pf))
+ goto err_create_module_files;
+
+ fw_modules_dir = debugfs_create_dir("modules",
+ pf->ice_debugfs_pf_fwlog);
+ if (IS_ERR(fw_modules_dir))
+ goto err_create_module_files;
+
+ for (i = 0; i < ICE_NR_FW_LOG_MODULES; i++) {
+ fw_modules[i] = debugfs_create_file(ice_fwlog_module_string[i],
+ 0600, fw_modules_dir, pf,
+ &ice_debugfs_module_fops);
+ if (IS_ERR(fw_modules[i]))
+ goto err_create_module_files;
+ }
+
+ debugfs_create_file("nr_messages", 0600,
+ pf->ice_debugfs_pf_fwlog, pf,
+ &ice_debugfs_nr_messages_fops);
+
+ pf->ice_debugfs_pf_fwlog_modules = fw_modules;
+
+ debugfs_create_file("enable", 0600, pf->ice_debugfs_pf_fwlog,
+ pf, &ice_debugfs_enable_fops);
+
+ debugfs_create_file("log_size", 0600, pf->ice_debugfs_pf_fwlog,
+ pf, &ice_debugfs_log_size_fops);
+
+ debugfs_create_file("data", 0600, pf->ice_debugfs_pf_fwlog,
+ pf, &ice_debugfs_data_fops);
+
+ return;
+
+err_create_module_files:
+ debugfs_remove_recursive(pf->ice_debugfs_pf_fwlog);
+ kfree(fw_modules);
+}
+
+/**
+ * ice_debugfs_init - create root directory for debugfs entries
+ */
+void ice_debugfs_init(void)
+{
+ ice_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(ice_debugfs_root))
+ pr_info("init of debugfs failed\n");
+}
+
+/**
+ * ice_debugfs_exit - remove debugfs entries
+ */
+void ice_debugfs_exit(void)
+{
+ debugfs_remove_recursive(ice_debugfs_root);
+ ice_debugfs_root = NULL;
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c
index 80dc5445b50d..65be56f2af9e 100644
--- a/drivers/net/ethernet/intel/ice/ice_devlink.c
+++ b/drivers/net/ethernet/intel/ice/ice_devlink.c
@@ -193,6 +193,24 @@ ice_info_pending_netlist_build(struct ice_pf __always_unused *pf,
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash);
}
+static void ice_info_cgu_fw_build(struct ice_pf *pf, struct ice_info_ctx *ctx)
+{
+ u32 id, cfg_ver, fw_ver;
+
+ if (!ice_is_feature_supported(pf, ICE_F_CGU))
+ return;
+ if (ice_aq_get_cgu_info(&pf->hw, &id, &cfg_ver, &fw_ver))
+ return;
+ snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", id, cfg_ver, fw_ver);
+}
+
+static void ice_info_cgu_id(struct ice_pf *pf, struct ice_info_ctx *ctx)
+{
+ if (!ice_is_feature_supported(pf, ICE_F_CGU))
+ return;
+ snprintf(ctx->buf, sizeof(ctx->buf), "%u", pf->hw.cgu_part_number);
+}
+
#define fixed(key, getter) { ICE_VERSION_FIXED, key, getter, NULL }
#define running(key, getter) { ICE_VERSION_RUNNING, key, getter, NULL }
#define stored(key, getter, fallback) { ICE_VERSION_STORED, key, getter, fallback }
@@ -235,6 +253,8 @@ static const struct ice_devlink_version {
running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id),
combined("fw.netlist", ice_info_netlist_ver, ice_info_pending_netlist_ver),
combined("fw.netlist.build", ice_info_netlist_build, ice_info_pending_netlist_build),
+ fixed("cgu.id", ice_info_cgu_id),
+ running("fw.cgu", ice_info_cgu_fw_build),
};
/**
@@ -810,6 +830,10 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node
struct ice_vf *vf;
int i;
+ if (node->rate_node)
+ /* already added, skip to the next */
+ goto traverse_children;
+
if (node->parent == tc_node) {
/* create root node */
rate_node = devl_rate_node_create(devlink, node, node->name, NULL);
@@ -831,6 +855,7 @@ static void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node
if (rate_node && !IS_ERR(rate_node))
node->rate_node = rate_node;
+traverse_children:
for (i = 0; i < node->num_children; i++)
ice_traverse_tx_tree(devlink, node->children[i], tc_node, pf);
}
@@ -861,6 +886,30 @@ int ice_devlink_rate_init_tx_topology(struct devlink *devlink, struct ice_vsi *v
return 0;
}
+static void ice_clear_rate_nodes(struct ice_sched_node *node)
+{
+ node->rate_node = NULL;
+
+ for (int i = 0; i < node->num_children; i++)
+ ice_clear_rate_nodes(node->children[i]);
+}
+
+/**
+ * ice_devlink_rate_clear_tx_topology - clear node->rate_node
+ * @vsi: main vsi struct
+ *
+ * Clear rate_node to cleanup creation of Tx topology.
+ *
+ */
+void ice_devlink_rate_clear_tx_topology(struct ice_vsi *vsi)
+{
+ struct ice_port_info *pi = vsi->port_info;
+
+ mutex_lock(&pi->sched_lock);
+ ice_clear_rate_nodes(pi->root->children[0]);
+ mutex_unlock(&pi->sched_lock);
+}
+
/**
* ice_set_object_tx_share - sets node scheduling parameter
* @pi: devlink struct instance
diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.h b/drivers/net/ethernet/intel/ice/ice_devlink.h
index 6ec96779f52e..d291c0e2e17b 100644
--- a/drivers/net/ethernet/intel/ice/ice_devlink.h
+++ b/drivers/net/ethernet/intel/ice/ice_devlink.h
@@ -20,5 +20,6 @@ void ice_devlink_destroy_regions(struct ice_pf *pf);
int ice_devlink_rate_init_tx_topology(struct devlink *devlink, struct ice_vsi *vsi);
void ice_tear_down_devlink_rate_tree(struct ice_pf *pf);
+void ice_devlink_rate_clear_tx_topology(struct ice_vsi *vsi);
#endif /* _ICE_DEVLINK_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index 86b180cb32a0..bd9b1fed74ab 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -31,6 +31,26 @@ static const char * const pin_type_name[] = {
};
/**
+ * ice_dpll_is_reset - check if reset is in progress
+ * @pf: private board structure
+ * @extack: error reporting
+ *
+ * If reset is in progress, fill extack with error.
+ *
+ * Return:
+ * * false - no reset in progress
+ * * true - reset in progress
+ */
+static bool ice_dpll_is_reset(struct ice_pf *pf, struct netlink_ext_ack *extack)
+{
+ if (ice_is_reset_in_progress(pf->state)) {
+ NL_SET_ERR_MSG(extack, "PF reset in progress");
+ return true;
+ }
+ return false;
+}
+
+/**
* ice_dpll_pin_freq_set - set pin's frequency
* @pf: private board structure
* @pin: pointer to a pin
@@ -109,6 +129,9 @@ ice_dpll_frequency_set(const struct dpll_pin *pin, void *pin_priv,
struct ice_pf *pf = d->pf;
int ret;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_pin_freq_set(pf, p, pin_type, frequency, extack);
mutex_unlock(&pf->dplls.lock);
@@ -254,6 +277,7 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv,
* ice_dpll_pin_enable - enable a pin on dplls
* @hw: board private hw structure
* @pin: pointer to a pin
+ * @dpll_idx: dpll index to connect to output pin
* @pin_type: type of pin being enabled
* @extack: error reporting
*
@@ -266,7 +290,7 @@ ice_dpll_output_frequency_get(const struct dpll_pin *pin, void *pin_priv,
*/
static int
ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin,
- enum ice_dpll_pin_type pin_type,
+ u8 dpll_idx, enum ice_dpll_pin_type pin_type,
struct netlink_ext_ack *extack)
{
u8 flags = 0;
@@ -280,10 +304,12 @@ ice_dpll_pin_enable(struct ice_hw *hw, struct ice_dpll_pin *pin,
ret = ice_aq_set_input_pin_cfg(hw, pin->idx, 0, flags, 0, 0);
break;
case ICE_DPLL_PIN_TYPE_OUTPUT:
+ flags = ICE_AQC_SET_CGU_OUT_CFG_UPDATE_SRC_SEL;
if (pin->flags[0] & ICE_AQC_GET_CGU_OUT_CFG_ESYNC_EN)
flags |= ICE_AQC_SET_CGU_OUT_CFG_ESYNC_EN;
flags |= ICE_AQC_SET_CGU_OUT_CFG_OUT_EN;
- ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, 0, 0, 0);
+ ret = ice_aq_set_output_pin_cfg(hw, pin->idx, flags, dpll_idx,
+ 0, 0);
break;
default:
return -EINVAL;
@@ -370,7 +396,7 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin,
case ICE_DPLL_PIN_TYPE_INPUT:
ret = ice_aq_get_input_pin_cfg(&pf->hw, pin->idx, NULL, NULL,
NULL, &pin->flags[0],
- &pin->freq, NULL);
+ &pin->freq, &pin->phase_adjust);
if (ret)
goto err;
if (ICE_AQC_GET_CGU_IN_CFG_FLG2_INPUT_EN & pin->flags[0]) {
@@ -398,14 +424,27 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct ice_dpll_pin *pin,
break;
case ICE_DPLL_PIN_TYPE_OUTPUT:
ret = ice_aq_get_output_pin_cfg(&pf->hw, pin->idx,
- &pin->flags[0], NULL,
+ &pin->flags[0], &parent,
&pin->freq, NULL);
if (ret)
goto err;
- if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0])
- pin->state[0] = DPLL_PIN_STATE_CONNECTED;
- else
- pin->state[0] = DPLL_PIN_STATE_DISCONNECTED;
+
+ parent &= ICE_AQC_GET_CGU_OUT_CFG_DPLL_SRC_SEL;
+ if (ICE_AQC_SET_CGU_OUT_CFG_OUT_EN & pin->flags[0]) {
+ pin->state[pf->dplls.eec.dpll_idx] =
+ parent == pf->dplls.eec.dpll_idx ?
+ DPLL_PIN_STATE_CONNECTED :
+ DPLL_PIN_STATE_DISCONNECTED;
+ pin->state[pf->dplls.pps.dpll_idx] =
+ parent == pf->dplls.pps.dpll_idx ?
+ DPLL_PIN_STATE_CONNECTED :
+ DPLL_PIN_STATE_DISCONNECTED;
+ } else {
+ pin->state[pf->dplls.eec.dpll_idx] =
+ DPLL_PIN_STATE_DISCONNECTED;
+ pin->state[pf->dplls.pps.dpll_idx] =
+ DPLL_PIN_STATE_DISCONNECTED;
+ }
break;
case ICE_DPLL_PIN_TYPE_RCLK_INPUT:
for (parent = 0; parent < pf->dplls.rclk.num_parents;
@@ -513,31 +552,6 @@ ice_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv,
}
/**
- * ice_dpll_mode_supported - check if dpll's working mode is supported
- * @dpll: registered dpll pointer
- * @dpll_priv: private data pointer passed on dpll registration
- * @mode: mode to be checked for support
- * @extack: error reporting
- *
- * Dpll subsystem callback. Provides information if working mode is supported
- * by dpll.
- *
- * Return:
- * * true - mode is supported
- * * false - mode is not supported
- */
-static bool ice_dpll_mode_supported(const struct dpll_device *dpll,
- void *dpll_priv,
- enum dpll_mode mode,
- struct netlink_ext_ack *extack)
-{
- if (mode == DPLL_MODE_AUTOMATIC)
- return true;
-
- return false;
-}
-
-/**
* ice_dpll_mode_get - get dpll's working mode
* @dpll: registered dpll pointer
* @dpll_priv: private data pointer passed on dpll registration
@@ -593,9 +607,13 @@ ice_dpll_pin_state_set(const struct dpll_pin *pin, void *pin_priv,
struct ice_pf *pf = d->pf;
int ret;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
if (enable)
- ret = ice_dpll_pin_enable(&pf->hw, p, pin_type, extack);
+ ret = ice_dpll_pin_enable(&pf->hw, p, d->dpll_idx, pin_type,
+ extack);
else
ret = ice_dpll_pin_disable(&pf->hw, p, pin_type, extack);
if (!ret)
@@ -628,6 +646,11 @@ ice_dpll_output_state_set(const struct dpll_pin *pin, void *pin_priv,
struct netlink_ext_ack *extack)
{
bool enable = state == DPLL_PIN_STATE_CONNECTED;
+ struct ice_dpll_pin *p = pin_priv;
+ struct ice_dpll *d = dpll_priv;
+
+ if (!enable && p->state[d->dpll_idx] == DPLL_PIN_STATE_DISCONNECTED)
+ return 0;
return ice_dpll_pin_state_set(pin, pin_priv, dpll, dpll_priv, enable,
extack, ICE_DPLL_PIN_TYPE_OUTPUT);
@@ -690,14 +713,16 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin, void *pin_priv,
struct ice_pf *pf = d->pf;
int ret;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_pin_state_update(pf, p, pin_type, extack);
if (ret)
goto unlock;
- if (pin_type == ICE_DPLL_PIN_TYPE_INPUT)
+ if (pin_type == ICE_DPLL_PIN_TYPE_INPUT ||
+ pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)
*state = p->state[d->dpll_idx];
- else if (pin_type == ICE_DPLL_PIN_TYPE_OUTPUT)
- *state = p->state[0];
ret = 0;
unlock:
mutex_unlock(&pf->dplls.lock);
@@ -815,6 +840,9 @@ ice_dpll_input_prio_set(const struct dpll_pin *pin, void *pin_priv,
struct ice_pf *pf = d->pf;
int ret;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_hw_input_prio_set(pf, d, p, prio, extack);
mutex_unlock(&pf->dplls.lock);
@@ -935,6 +963,9 @@ ice_dpll_pin_phase_adjust_set(const struct dpll_pin *pin, void *pin_priv,
u8 flag, flags_en = 0;
int ret;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
switch (type) {
case ICE_DPLL_PIN_TYPE_INPUT:
@@ -1094,6 +1125,9 @@ ice_dpll_rclk_state_on_pin_set(const struct dpll_pin *pin, void *pin_priv,
int ret = -EINVAL;
u32 hw_idx;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
hw_idx = parent->idx - pf->dplls.base_rclk_idx;
if (hw_idx >= pf->dplls.num_inputs)
@@ -1148,6 +1182,9 @@ ice_dpll_rclk_state_on_pin_get(const struct dpll_pin *pin, void *pin_priv,
int ret = -EINVAL;
u32 hw_idx;
+ if (ice_dpll_is_reset(pf, extack))
+ return -EBUSY;
+
mutex_lock(&pf->dplls.lock);
hw_idx = parent->idx - pf->dplls.base_rclk_idx;
if (hw_idx >= pf->dplls.num_inputs)
@@ -1197,7 +1234,6 @@ static const struct dpll_pin_ops ice_dpll_output_ops = {
static const struct dpll_device_ops ice_dpll_ops = {
.lock_status_get = ice_dpll_lock_status_get,
- .mode_supported = ice_dpll_mode_supported,
.mode_get = ice_dpll_mode_get,
};
@@ -1331,8 +1367,10 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
struct ice_pf *pf = container_of(d, struct ice_pf, dplls);
struct ice_dpll *de = &pf->dplls.eec;
struct ice_dpll *dp = &pf->dplls.pps;
- int ret;
+ int ret = 0;
+ if (ice_is_reset_in_progress(pf->state))
+ goto resched;
mutex_lock(&pf->dplls.lock);
ret = ice_dpll_update_state(pf, de, false);
if (!ret)
@@ -1352,6 +1390,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work)
ice_dpll_notify_changes(de);
ice_dpll_notify_changes(dp);
+resched:
/* Run twice a second or reschedule if update failed */
kthread_queue_delayed_work(d->kworker, &d->work,
ret ? msecs_to_jiffies(10) :
@@ -1558,7 +1597,7 @@ static void ice_dpll_deinit_rclk_pin(struct ice_pf *pf)
}
if (WARN_ON_ONCE(!vsi || !vsi->netdev))
return;
- netdev_dpll_pin_clear(vsi->netdev);
+ dpll_netdev_pin_clear(vsi->netdev);
dpll_pin_put(rclk->pin);
}
@@ -1602,7 +1641,7 @@ ice_dpll_init_rclk_pins(struct ice_pf *pf, struct ice_dpll_pin *pin,
}
if (WARN_ON((!vsi || !vsi->netdev)))
return -EINVAL;
- netdev_dpll_pin_set(vsi->netdev, pf->dplls.rclk.pin);
+ dpll_netdev_pin_set(vsi->netdev, pf->dplls.rclk.pin);
return 0;
@@ -2081,6 +2120,7 @@ void ice_dpll_init(struct ice_pf *pf)
struct ice_dplls *d = &pf->dplls;
int err = 0;
+ mutex_init(&d->lock);
err = ice_dpll_init_info(pf, cgu);
if (err)
goto err_exit;
@@ -2093,7 +2133,6 @@ void ice_dpll_init(struct ice_pf *pf)
err = ice_dpll_init_pins(pf, cgu);
if (err)
goto deinit_pps;
- mutex_init(&d->lock);
if (cgu) {
err = ice_dpll_init_worker(pf);
if (err)
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
index a655d499abfa..9069725c71b4 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
@@ -11,17 +11,34 @@
#include "ice_tc_lib.h"
/**
- * ice_eswitch_add_vf_sp_rule - add adv rule with VF's VSI index
+ * ice_eswitch_del_sp_rules - delete adv rules added on PRs
+ * @pf: pointer to the PF struct
+ *
+ * Delete all advanced rules that were used to forward packets with the
+ * device's VSI index to the corresponding eswitch ctrl VSI queue.
+ */
+static void ice_eswitch_del_sp_rules(struct ice_pf *pf)
+{
+ struct ice_repr *repr;
+ unsigned long id;
+
+ xa_for_each(&pf->eswitch.reprs, id, repr) {
+ if (repr->sp_rule.rid)
+ ice_rem_adv_rule_by_id(&pf->hw, &repr->sp_rule);
+ }
+}
+
+/**
+ * ice_eswitch_add_sp_rule - add adv rule with device's VSI index
* @pf: pointer to PF struct
- * @vf: pointer to VF struct
+ * @repr: pointer to the repr struct
*
* This function adds advanced rule that forwards packets with
- * VF's VSI index to the corresponding switchdev ctrl VSI queue.
+ * device's VSI index to the corresponding eswitch ctrl VSI queue.
*/
-static int
-ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf)
+static int ice_eswitch_add_sp_rule(struct ice_pf *pf, struct ice_repr *repr)
{
- struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
+ struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
struct ice_adv_rule_info rule_info = { 0 };
struct ice_adv_lkup_elem *list;
struct ice_hw *hw = &pf->hw;
@@ -38,39 +55,42 @@ ice_eswitch_add_vf_sp_rule(struct ice_pf *pf, struct ice_vf *vf)
rule_info.sw_act.vsi_handle = ctrl_vsi->idx;
rule_info.sw_act.fltr_act = ICE_FWD_TO_Q;
rule_info.sw_act.fwd_id.q_id = hw->func_caps.common_cap.rxq_first_id +
- ctrl_vsi->rxq_map[vf->vf_id];
+ ctrl_vsi->rxq_map[repr->q_id];
rule_info.flags_info.act |= ICE_SINGLE_ACT_LB_ENABLE;
rule_info.flags_info.act_valid = true;
rule_info.tun_type = ICE_SW_TUN_AND_NON_TUN;
- rule_info.src_vsi = vf->lan_vsi_idx;
+ rule_info.src_vsi = repr->src_vsi->idx;
err = ice_add_adv_rule(hw, list, lkups_cnt, &rule_info,
- &vf->repr->sp_rule);
+ &repr->sp_rule);
if (err)
- dev_err(ice_pf_to_dev(pf), "Unable to add VF slow-path rule in switchdev mode for VF %d",
- vf->vf_id);
+ dev_err(ice_pf_to_dev(pf), "Unable to add slow-path rule for eswitch for PR %d",
+ repr->id);
kfree(list);
return err;
}
-/**
- * ice_eswitch_del_vf_sp_rule - delete adv rule with VF's VSI index
- * @vf: pointer to the VF struct
- *
- * Delete the advanced rule that was used to forward packets with the VF's VSI
- * index to the corresponding switchdev ctrl VSI queue.
- */
-static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf)
+static int
+ice_eswitch_add_sp_rules(struct ice_pf *pf)
{
- if (!vf->repr)
- return;
+ struct ice_repr *repr;
+ unsigned long id;
+ int err;
+
+ xa_for_each(&pf->eswitch.reprs, id, repr) {
+ err = ice_eswitch_add_sp_rule(pf, repr);
+ if (err) {
+ ice_eswitch_del_sp_rules(pf);
+ return err;
+ }
+ }
- ice_rem_adv_rule_by_id(&vf->pf->hw, &vf->repr->sp_rule);
+ return 0;
}
/**
- * ice_eswitch_setup_env - configure switchdev HW filters
+ * ice_eswitch_setup_env - configure eswitch HW filters
* @pf: pointer to PF struct
*
* This function adds HW filters configuration specific for switchdev
@@ -78,18 +98,18 @@ static void ice_eswitch_del_vf_sp_rule(struct ice_vf *vf)
*/
static int ice_eswitch_setup_env(struct ice_pf *pf)
{
- struct ice_vsi *uplink_vsi = pf->switchdev.uplink_vsi;
- struct net_device *uplink_netdev = uplink_vsi->netdev;
- struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
+ struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi;
+ struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
+ struct net_device *netdev = uplink_vsi->netdev;
struct ice_vsi_vlan_ops *vlan_ops;
bool rule_added = false;
ice_remove_vsi_fltr(&pf->hw, uplink_vsi->idx);
- netif_addr_lock_bh(uplink_netdev);
- __dev_uc_unsync(uplink_netdev, NULL);
- __dev_mc_unsync(uplink_netdev, NULL);
- netif_addr_unlock_bh(uplink_netdev);
+ netif_addr_lock_bh(netdev);
+ __dev_uc_unsync(netdev, NULL);
+ __dev_mc_unsync(netdev, NULL);
+ netif_addr_unlock_bh(netdev);
if (ice_vsi_add_vlan_zero(uplink_vsi))
goto err_def_rx;
@@ -132,19 +152,20 @@ err_def_rx:
}
/**
- * ice_eswitch_remap_rings_to_vectors - reconfigure rings of switchdev ctrl VSI
- * @pf: pointer to PF struct
+ * ice_eswitch_remap_rings_to_vectors - reconfigure rings of eswitch ctrl VSI
+ * @eswitch: pointer to eswitch struct
*
- * In switchdev number of allocated Tx/Rx rings is equal.
+ * In eswitch number of allocated Tx/Rx rings is equal.
*
* This function fills q_vectors structures associated with representor and
* move each ring pairs to port representor netdevs. Each port representor
* will have dedicated 1 Tx/Rx ring pair, so number of rings pair is equal to
* number of VFs.
*/
-static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf)
+static void ice_eswitch_remap_rings_to_vectors(struct ice_eswitch *eswitch)
{
- struct ice_vsi *vsi = pf->switchdev.control_vsi;
+ struct ice_vsi *vsi = eswitch->control_vsi;
+ unsigned long repr_id = 0;
int q_id;
ice_for_each_txq(vsi, q_id) {
@@ -152,13 +173,14 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf)
struct ice_tx_ring *tx_ring;
struct ice_rx_ring *rx_ring;
struct ice_repr *repr;
- struct ice_vf *vf;
- vf = ice_get_vf_by_id(pf, q_id);
- if (WARN_ON(!vf))
- continue;
+ repr = xa_find(&eswitch->reprs, &repr_id, U32_MAX,
+ XA_PRESENT);
+ if (!repr)
+ break;
- repr = vf->repr;
+ repr_id += 1;
+ repr->q_id = q_id;
q_vector = repr->q_vector;
tx_ring = vsi->tx_rings[q_id];
rx_ring = vsi->rx_rings[q_id];
@@ -181,136 +203,96 @@ static void ice_eswitch_remap_rings_to_vectors(struct ice_pf *pf)
rx_ring->q_vector = q_vector;
rx_ring->next = NULL;
rx_ring->netdev = repr->netdev;
-
- ice_put_vf(vf);
}
}
/**
- * ice_eswitch_release_reprs - clear PR VSIs configuration
+ * ice_eswitch_release_repr - clear PR VSI configuration
* @pf: poiner to PF struct
- * @ctrl_vsi: pointer to switchdev control VSI
+ * @repr: pointer to PR
*/
static void
-ice_eswitch_release_reprs(struct ice_pf *pf, struct ice_vsi *ctrl_vsi)
+ice_eswitch_release_repr(struct ice_pf *pf, struct ice_repr *repr)
{
- struct ice_vf *vf;
- unsigned int bkt;
+ struct ice_vsi *vsi = repr->src_vsi;
- lockdep_assert_held(&pf->vfs.table_lock);
-
- ice_for_each_vf(pf, bkt, vf) {
- struct ice_vsi *vsi = vf->repr->src_vsi;
-
- /* Skip VFs that aren't configured */
- if (!vf->repr->dst)
- continue;
+ /* Skip representors that aren't configured */
+ if (!repr->dst)
+ return;
- ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof);
- metadata_dst_free(vf->repr->dst);
- vf->repr->dst = NULL;
- ice_eswitch_del_vf_sp_rule(vf);
- ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr,
- ICE_FWD_TO_VSI);
+ ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof);
+ metadata_dst_free(repr->dst);
+ repr->dst = NULL;
+ ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac,
+ ICE_FWD_TO_VSI);
- netif_napi_del(&vf->repr->q_vector->napi);
- }
+ netif_napi_del(&repr->q_vector->napi);
}
/**
- * ice_eswitch_setup_reprs - configure port reprs to run in switchdev mode
+ * ice_eswitch_setup_repr - configure PR to run in switchdev mode
* @pf: pointer to PF struct
+ * @repr: pointer to PR struct
*/
-static int ice_eswitch_setup_reprs(struct ice_pf *pf)
+static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr)
{
- struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
- int max_vsi_num = 0;
- struct ice_vf *vf;
- unsigned int bkt;
-
- lockdep_assert_held(&pf->vfs.table_lock);
-
- ice_for_each_vf(pf, bkt, vf) {
- struct ice_vsi *vsi = vf->repr->src_vsi;
-
- ice_remove_vsi_fltr(&pf->hw, vsi->idx);
- vf->repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
- GFP_KERNEL);
- if (!vf->repr->dst) {
- ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr,
- ICE_FWD_TO_VSI);
- goto err;
- }
+ struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
+ struct ice_vsi *vsi = repr->src_vsi;
+ struct metadata_dst *dst;
- if (ice_eswitch_add_vf_sp_rule(pf, vf)) {
- ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr,
- ICE_FWD_TO_VSI);
- goto err;
- }
+ ice_remove_vsi_fltr(&pf->hw, vsi->idx);
+ repr->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
+ GFP_KERNEL);
+ if (!repr->dst)
+ goto err_add_mac_fltr;
- if (ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof)) {
- ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr,
- ICE_FWD_TO_VSI);
- ice_eswitch_del_vf_sp_rule(vf);
- metadata_dst_free(vf->repr->dst);
- vf->repr->dst = NULL;
- goto err;
- }
+ if (ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof))
+ goto err_dst_free;
- if (ice_vsi_add_vlan_zero(vsi)) {
- ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr,
- ICE_FWD_TO_VSI);
- ice_eswitch_del_vf_sp_rule(vf);
- metadata_dst_free(vf->repr->dst);
- vf->repr->dst = NULL;
- ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof);
- goto err;
- }
-
- if (max_vsi_num < vsi->vsi_num)
- max_vsi_num = vsi->vsi_num;
+ if (ice_vsi_add_vlan_zero(vsi))
+ goto err_update_security;
- netif_napi_add(vf->repr->netdev, &vf->repr->q_vector->napi,
- ice_napi_poll);
+ netif_napi_add(repr->netdev, &repr->q_vector->napi,
+ ice_napi_poll);
- netif_keep_dst(vf->repr->netdev);
- }
+ netif_keep_dst(repr->netdev);
- ice_for_each_vf(pf, bkt, vf) {
- struct ice_repr *repr = vf->repr;
- struct ice_vsi *vsi = repr->src_vsi;
- struct metadata_dst *dst;
-
- dst = repr->dst;
- dst->u.port_info.port_id = vsi->vsi_num;
- dst->u.port_info.lower_dev = repr->netdev;
- ice_repr_set_traffic_vsi(repr, ctrl_vsi);
- }
+ dst = repr->dst;
+ dst->u.port_info.port_id = vsi->vsi_num;
+ dst->u.port_info.lower_dev = repr->netdev;
+ ice_repr_set_traffic_vsi(repr, ctrl_vsi);
return 0;
-err:
- ice_eswitch_release_reprs(pf, ctrl_vsi);
+err_update_security:
+ ice_vsi_update_security(vsi, ice_vsi_ctx_set_antispoof);
+err_dst_free:
+ metadata_dst_free(repr->dst);
+ repr->dst = NULL;
+err_add_mac_fltr:
+ ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac, ICE_FWD_TO_VSI);
return -ENODEV;
}
/**
- * ice_eswitch_update_repr - reconfigure VF port representor
- * @vsi: VF VSI for which port representor is configured
+ * ice_eswitch_update_repr - reconfigure port representor
+ * @repr_id: representor ID
+ * @vsi: VSI for which port representor is configured
*/
-void ice_eswitch_update_repr(struct ice_vsi *vsi)
+void ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi)
{
struct ice_pf *pf = vsi->back;
struct ice_repr *repr;
- struct ice_vf *vf;
int ret;
if (!ice_is_switchdev_running(pf))
return;
- vf = vsi->vf;
- repr = vf->repr;
+ repr = xa_load(&pf->eswitch.reprs, repr_id);
+ if (!repr)
+ return;
+
repr->src_vsi = vsi;
repr->dst->u.port_info.port_id = vsi->vsi_num;
@@ -319,9 +301,10 @@ void ice_eswitch_update_repr(struct ice_vsi *vsi)
ret = ice_vsi_update_security(vsi, ice_vsi_ctx_clear_antispoof);
if (ret) {
- ice_fltr_add_mac_and_broadcast(vsi, vf->hw_lan_addr, ICE_FWD_TO_VSI);
- dev_err(ice_pf_to_dev(pf), "Failed to update VF %d port representor",
- vsi->vf->vf_id);
+ ice_fltr_add_mac_and_broadcast(vsi, repr->parent_mac,
+ ICE_FWD_TO_VSI);
+ dev_err(ice_pf_to_dev(pf), "Failed to update VSI of port representor %d",
+ repr->id);
}
}
@@ -353,13 +336,13 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev)
skb_dst_drop(skb);
dst_hold((struct dst_entry *)repr->dst);
skb_dst_set(skb, (struct dst_entry *)repr->dst);
- skb->queue_mapping = repr->vf->vf_id;
+ skb->queue_mapping = repr->q_id;
return ice_start_xmit(skb, netdev);
}
/**
- * ice_eswitch_set_target_vsi - set switchdev context in Tx context descriptor
+ * ice_eswitch_set_target_vsi - set eswitch context in Tx context descriptor
* @skb: pointer to send buffer
* @off: pointer to offload struct
*/
@@ -375,14 +358,14 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb,
off->cd_qw1 |= (cd_cmd | ICE_TX_DESC_DTYPE_CTX);
} else {
cd_cmd = ICE_TX_CTX_DESC_SWTCH_VSI << ICE_TXD_CTX_QW1_CMD_S;
- dst_vsi = ((u64)dst->u.port_info.port_id <<
- ICE_TXD_CTX_QW1_VSI_S) & ICE_TXD_CTX_QW1_VSI_M;
+ dst_vsi = FIELD_PREP(ICE_TXD_CTX_QW1_VSI_M,
+ dst->u.port_info.port_id);
off->cd_qw1 = cd_cmd | dst_vsi | ICE_TX_DESC_DTYPE_CTX;
}
}
/**
- * ice_eswitch_release_env - clear switchdev HW filters
+ * ice_eswitch_release_env - clear eswitch HW filters
* @pf: pointer to PF struct
*
* This function removes HW filters configuration specific for switchdev
@@ -390,8 +373,8 @@ ice_eswitch_set_target_vsi(struct sk_buff *skb,
*/
static void ice_eswitch_release_env(struct ice_pf *pf)
{
- struct ice_vsi *uplink_vsi = pf->switchdev.uplink_vsi;
- struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
+ struct ice_vsi *uplink_vsi = pf->eswitch.uplink_vsi;
+ struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
struct ice_vsi_vlan_ops *vlan_ops;
vlan_ops = ice_get_compat_vsi_vlan_ops(uplink_vsi);
@@ -407,7 +390,7 @@ static void ice_eswitch_release_env(struct ice_pf *pf)
}
/**
- * ice_eswitch_vsi_setup - configure switchdev control VSI
+ * ice_eswitch_vsi_setup - configure eswitch control VSI
* @pf: pointer to PF structure
* @pi: pointer to port_info structure
*/
@@ -424,48 +407,29 @@ ice_eswitch_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
}
/**
- * ice_eswitch_napi_del - remove NAPI handle for all port representors
- * @pf: pointer to PF structure
- */
-static void ice_eswitch_napi_del(struct ice_pf *pf)
-{
- struct ice_vf *vf;
- unsigned int bkt;
-
- lockdep_assert_held(&pf->vfs.table_lock);
-
- ice_for_each_vf(pf, bkt, vf)
- netif_napi_del(&vf->repr->q_vector->napi);
-}
-
-/**
* ice_eswitch_napi_enable - enable NAPI for all port representors
- * @pf: pointer to PF structure
+ * @reprs: xarray of reprs
*/
-static void ice_eswitch_napi_enable(struct ice_pf *pf)
+static void ice_eswitch_napi_enable(struct xarray *reprs)
{
- struct ice_vf *vf;
- unsigned int bkt;
-
- lockdep_assert_held(&pf->vfs.table_lock);
+ struct ice_repr *repr;
+ unsigned long id;
- ice_for_each_vf(pf, bkt, vf)
- napi_enable(&vf->repr->q_vector->napi);
+ xa_for_each(reprs, id, repr)
+ napi_enable(&repr->q_vector->napi);
}
/**
* ice_eswitch_napi_disable - disable NAPI for all port representors
- * @pf: pointer to PF structure
+ * @reprs: xarray of reprs
*/
-static void ice_eswitch_napi_disable(struct ice_pf *pf)
+static void ice_eswitch_napi_disable(struct xarray *reprs)
{
- struct ice_vf *vf;
- unsigned int bkt;
-
- lockdep_assert_held(&pf->vfs.table_lock);
+ struct ice_repr *repr;
+ unsigned long id;
- ice_for_each_vf(pf, bkt, vf)
- napi_disable(&vf->repr->q_vector->napi);
+ xa_for_each(reprs, id, repr)
+ napi_disable(&repr->q_vector->napi);
}
/**
@@ -486,39 +450,26 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf)
return -EINVAL;
}
- pf->switchdev.control_vsi = ice_eswitch_vsi_setup(pf, pf->hw.port_info);
- if (!pf->switchdev.control_vsi)
+ pf->eswitch.control_vsi = ice_eswitch_vsi_setup(pf, pf->hw.port_info);
+ if (!pf->eswitch.control_vsi)
return -ENODEV;
- ctrl_vsi = pf->switchdev.control_vsi;
- pf->switchdev.uplink_vsi = uplink_vsi;
+ ctrl_vsi = pf->eswitch.control_vsi;
+ /* cp VSI is createad with 1 queue as default */
+ pf->eswitch.qs.value = 1;
+ pf->eswitch.uplink_vsi = uplink_vsi;
if (ice_eswitch_setup_env(pf))
goto err_vsi;
- if (ice_repr_add_for_all_vfs(pf))
- goto err_repr_add;
-
- if (ice_eswitch_setup_reprs(pf))
- goto err_setup_reprs;
-
- ice_eswitch_remap_rings_to_vectors(pf);
-
- if (ice_vsi_open(ctrl_vsi))
- goto err_setup_reprs;
-
if (ice_eswitch_br_offloads_init(pf))
goto err_br_offloads;
- ice_eswitch_napi_enable(pf);
+ pf->eswitch.is_running = true;
return 0;
err_br_offloads:
- ice_vsi_close(ctrl_vsi);
-err_setup_reprs:
- ice_repr_rem_from_all_vfs(pf);
-err_repr_add:
ice_eswitch_release_env(pf);
err_vsi:
ice_vsi_release(ctrl_vsi);
@@ -526,19 +477,19 @@ err_vsi:
}
/**
- * ice_eswitch_disable_switchdev - disable switchdev resources
+ * ice_eswitch_disable_switchdev - disable eswitch resources
* @pf: pointer to PF structure
*/
static void ice_eswitch_disable_switchdev(struct ice_pf *pf)
{
- struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
+ struct ice_vsi *ctrl_vsi = pf->eswitch.control_vsi;
- ice_eswitch_napi_disable(pf);
ice_eswitch_br_offloads_deinit(pf);
ice_eswitch_release_env(pf);
- ice_eswitch_release_reprs(pf, ctrl_vsi);
ice_vsi_release(ctrl_vsi);
- ice_repr_rem_from_all_vfs(pf);
+
+ pf->eswitch.is_running = false;
+ pf->eswitch.qs.is_reaching = false;
}
/**
@@ -566,6 +517,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode,
case DEVLINK_ESWITCH_MODE_LEGACY:
dev_info(ice_pf_to_dev(pf), "PF %d changed eswitch mode to legacy",
pf->hw.pf_id);
+ xa_destroy(&pf->eswitch.reprs);
NL_SET_ERR_MSG_MOD(extack, "Changed eswitch mode to legacy");
break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
@@ -578,6 +530,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode,
dev_info(ice_pf_to_dev(pf), "PF %d changed eswitch mode to switchdev",
pf->hw.pf_id);
+ xa_init_flags(&pf->eswitch.reprs, XA_FLAGS_ALLOC);
NL_SET_ERR_MSG_MOD(extack, "Changed eswitch mode to switchdev");
break;
}
@@ -616,74 +569,168 @@ bool ice_is_eswitch_mode_switchdev(struct ice_pf *pf)
}
/**
- * ice_eswitch_release - cleanup eswitch
+ * ice_eswitch_start_all_tx_queues - start Tx queues of all port representors
* @pf: pointer to PF structure
*/
-void ice_eswitch_release(struct ice_pf *pf)
+static void ice_eswitch_start_all_tx_queues(struct ice_pf *pf)
{
- if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY)
+ struct ice_repr *repr;
+ unsigned long id;
+
+ if (test_bit(ICE_DOWN, pf->state))
return;
- ice_eswitch_disable_switchdev(pf);
- pf->switchdev.is_running = false;
+ xa_for_each(&pf->eswitch.reprs, id, repr)
+ ice_repr_start_tx_queues(repr);
}
/**
- * ice_eswitch_configure - configure eswitch
+ * ice_eswitch_stop_all_tx_queues - stop Tx queues of all port representors
* @pf: pointer to PF structure
*/
-int ice_eswitch_configure(struct ice_pf *pf)
+void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf)
{
- int status;
-
- if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY || pf->switchdev.is_running)
- return 0;
+ struct ice_repr *repr;
+ unsigned long id;
- status = ice_eswitch_enable_switchdev(pf);
- if (status)
- return status;
+ if (test_bit(ICE_DOWN, pf->state))
+ return;
- pf->switchdev.is_running = true;
- return 0;
+ xa_for_each(&pf->eswitch.reprs, id, repr)
+ ice_repr_stop_tx_queues(repr);
}
-/**
- * ice_eswitch_start_all_tx_queues - start Tx queues of all port representors
- * @pf: pointer to PF structure
- */
-static void ice_eswitch_start_all_tx_queues(struct ice_pf *pf)
+static void ice_eswitch_stop_reprs(struct ice_pf *pf)
{
- struct ice_vf *vf;
- unsigned int bkt;
+ ice_eswitch_del_sp_rules(pf);
+ ice_eswitch_stop_all_tx_queues(pf);
+ ice_eswitch_napi_disable(&pf->eswitch.reprs);
+}
- lockdep_assert_held(&pf->vfs.table_lock);
+static void ice_eswitch_start_reprs(struct ice_pf *pf)
+{
+ ice_eswitch_napi_enable(&pf->eswitch.reprs);
+ ice_eswitch_start_all_tx_queues(pf);
+ ice_eswitch_add_sp_rules(pf);
+}
- if (test_bit(ICE_DOWN, pf->state))
- return;
+static void
+ice_eswitch_cp_change_queues(struct ice_eswitch *eswitch, int change)
+{
+ struct ice_vsi *cp = eswitch->control_vsi;
+ int queues = 0;
+
+ if (eswitch->qs.is_reaching) {
+ if (eswitch->qs.to_reach >= eswitch->qs.value + change) {
+ queues = eswitch->qs.to_reach;
+ eswitch->qs.is_reaching = false;
+ } else {
+ queues = 0;
+ }
+ } else if ((change > 0 && cp->alloc_txq <= eswitch->qs.value) ||
+ change < 0) {
+ queues = cp->alloc_txq + change;
+ }
- ice_for_each_vf(pf, bkt, vf) {
- if (vf->repr)
- ice_repr_start_tx_queues(vf->repr);
+ if (queues) {
+ cp->req_txq = queues;
+ cp->req_rxq = queues;
+ ice_vsi_close(cp);
+ ice_vsi_rebuild(cp, ICE_VSI_FLAG_NO_INIT);
+ ice_vsi_open(cp);
+ } else if (!change) {
+ /* change == 0 means that VSI wasn't open, open it here */
+ ice_vsi_open(cp);
}
+
+ eswitch->qs.value += change;
+ ice_eswitch_remap_rings_to_vectors(eswitch);
}
-/**
- * ice_eswitch_stop_all_tx_queues - stop Tx queues of all port representors
- * @pf: pointer to PF structure
- */
-void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf)
+int
+ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
{
- struct ice_vf *vf;
- unsigned int bkt;
+ struct ice_repr *repr;
+ int change = 1;
+ int err;
- lockdep_assert_held(&pf->vfs.table_lock);
+ if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_LEGACY)
+ return 0;
- if (test_bit(ICE_DOWN, pf->state))
+ if (xa_empty(&pf->eswitch.reprs)) {
+ err = ice_eswitch_enable_switchdev(pf);
+ if (err)
+ return err;
+ /* Control plane VSI is created with 1 queue as default */
+ pf->eswitch.qs.to_reach -= 1;
+ change = 0;
+ }
+
+ ice_eswitch_stop_reprs(pf);
+
+ repr = ice_repr_add_vf(vf);
+ if (IS_ERR(repr)) {
+ err = PTR_ERR(repr);
+ goto err_create_repr;
+ }
+
+ err = ice_eswitch_setup_repr(pf, repr);
+ if (err)
+ goto err_setup_repr;
+
+ err = xa_alloc(&pf->eswitch.reprs, &repr->id, repr,
+ XA_LIMIT(1, INT_MAX), GFP_KERNEL);
+ if (err)
+ goto err_xa_alloc;
+
+ vf->repr_id = repr->id;
+
+ ice_eswitch_cp_change_queues(&pf->eswitch, change);
+ ice_eswitch_start_reprs(pf);
+
+ return 0;
+
+err_xa_alloc:
+ ice_eswitch_release_repr(pf, repr);
+err_setup_repr:
+ ice_repr_rem_vf(repr);
+err_create_repr:
+ if (xa_empty(&pf->eswitch.reprs))
+ ice_eswitch_disable_switchdev(pf);
+ ice_eswitch_start_reprs(pf);
+
+ return err;
+}
+
+void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf)
+{
+ struct ice_repr *repr = xa_load(&pf->eswitch.reprs, vf->repr_id);
+ struct devlink *devlink = priv_to_devlink(pf);
+
+ if (!repr)
return;
- ice_for_each_vf(pf, bkt, vf) {
- if (vf->repr)
- ice_repr_stop_tx_queues(vf->repr);
+ ice_eswitch_stop_reprs(pf);
+ xa_erase(&pf->eswitch.reprs, repr->id);
+
+ if (xa_empty(&pf->eswitch.reprs))
+ ice_eswitch_disable_switchdev(pf);
+ else
+ ice_eswitch_cp_change_queues(&pf->eswitch, -1);
+
+ ice_eswitch_release_repr(pf, repr);
+ ice_repr_rem_vf(repr);
+
+ if (xa_empty(&pf->eswitch.reprs)) {
+ /* since all port representors are destroyed, there is
+ * no point in keeping the nodes
+ */
+ ice_devlink_rate_clear_tx_topology(ice_get_main_vsi(pf));
+ devl_lock(devlink);
+ devl_rate_nodes_destroy(devlink);
+ devl_unlock(devlink);
+ } else {
+ ice_eswitch_start_reprs(pf);
}
}
@@ -693,30 +740,35 @@ void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf)
*/
int ice_eswitch_rebuild(struct ice_pf *pf)
{
- struct ice_vsi *ctrl_vsi = pf->switchdev.control_vsi;
- int status;
-
- ice_eswitch_napi_disable(pf);
- ice_eswitch_napi_del(pf);
-
- status = ice_eswitch_setup_env(pf);
- if (status)
- return status;
+ struct ice_repr *repr;
+ unsigned long id;
+ int err;
- status = ice_eswitch_setup_reprs(pf);
- if (status)
- return status;
+ if (!ice_is_switchdev_running(pf))
+ return 0;
- ice_eswitch_remap_rings_to_vectors(pf);
+ err = ice_vsi_rebuild(pf->eswitch.control_vsi, ICE_VSI_FLAG_INIT);
+ if (err)
+ return err;
- ice_replay_tc_fltrs(pf);
+ xa_for_each(&pf->eswitch.reprs, id, repr)
+ ice_eswitch_detach(pf, repr->vf);
- status = ice_vsi_open(ctrl_vsi);
- if (status)
- return status;
+ return 0;
+}
- ice_eswitch_napi_enable(pf);
- ice_eswitch_start_all_tx_queues(pf);
+/**
+ * ice_eswitch_reserve_cp_queues - reserve control plane VSI queues
+ * @pf: pointer to PF structure
+ * @change: how many more (or less) queues is needed
+ *
+ * Remember to call ice_eswitch_attach/detach() the "change" times.
+ */
+void ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change)
+{
+ if (pf->eswitch.qs.value + change < 0)
+ return;
- return 0;
+ pf->eswitch.qs.to_reach = pf->eswitch.qs.value + change;
+ pf->eswitch.qs.is_reaching = true;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.h b/drivers/net/ethernet/intel/ice/ice_eswitch.h
index b18bf83a2f5b..1a288a03a79a 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch.h
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch.h
@@ -7,8 +7,9 @@
#include <net/devlink.h>
#ifdef CONFIG_ICE_SWITCHDEV
-void ice_eswitch_release(struct ice_pf *pf);
-int ice_eswitch_configure(struct ice_pf *pf);
+void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf);
+int
+ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf);
int ice_eswitch_rebuild(struct ice_pf *pf);
int ice_eswitch_mode_get(struct devlink *devlink, u16 *mode);
@@ -17,7 +18,7 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack);
bool ice_is_eswitch_mode_switchdev(struct ice_pf *pf);
-void ice_eswitch_update_repr(struct ice_vsi *vsi);
+void ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi);
void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf);
@@ -25,8 +26,15 @@ void ice_eswitch_set_target_vsi(struct sk_buff *skb,
struct ice_tx_offload_params *off);
netdev_tx_t
ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev);
+void ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change);
#else /* CONFIG_ICE_SWITCHDEV */
-static inline void ice_eswitch_release(struct ice_pf *pf) { }
+static inline void ice_eswitch_detach(struct ice_pf *pf, struct ice_vf *vf) { }
+
+static inline int
+ice_eswitch_attach(struct ice_pf *pf, struct ice_vf *vf)
+{
+ return -EOPNOTSUPP;
+}
static inline void ice_eswitch_stop_all_tx_queues(struct ice_pf *pf) { }
@@ -34,7 +42,8 @@ static inline void
ice_eswitch_set_target_vsi(struct sk_buff *skb,
struct ice_tx_offload_params *off) { }
-static inline void ice_eswitch_update_repr(struct ice_vsi *vsi) { }
+static inline void
+ice_eswitch_update_repr(unsigned long repr_id, struct ice_vsi *vsi) { }
static inline int ice_eswitch_configure(struct ice_pf *pf)
{
@@ -68,5 +77,8 @@ ice_eswitch_port_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
return NETDEV_TX_BUSY;
}
+
+static inline void
+ice_eswitch_reserve_cp_queues(struct ice_pf *pf, int change) { }
#endif /* CONFIG_ICE_SWITCHDEV */
#endif /* _ICE_ESWITCH_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
index 6ae0269bdf73..ac5beecd028b 100644
--- a/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
+++ b/drivers/net/ethernet/intel/ice/ice_eswitch_br.c
@@ -893,10 +893,14 @@ ice_eswitch_br_port_deinit(struct ice_esw_br *bridge,
ice_eswitch_br_fdb_entry_delete(bridge, fdb_entry);
}
- if (br_port->type == ICE_ESWITCH_BR_UPLINK_PORT && vsi->back)
+ if (br_port->type == ICE_ESWITCH_BR_UPLINK_PORT && vsi->back) {
vsi->back->br_port = NULL;
- else if (vsi->vf && vsi->vf->repr)
- vsi->vf->repr->br_port = NULL;
+ } else {
+ struct ice_repr *repr = ice_repr_get_by_vsi(vsi);
+
+ if (repr)
+ repr->br_port = NULL;
+ }
xa_erase(&bridge->ports, br_port->vsi_idx);
ice_eswitch_br_port_vlans_flush(br_port);
@@ -947,7 +951,7 @@ ice_eswitch_br_vf_repr_port_init(struct ice_esw_br *bridge,
static int
ice_eswitch_br_uplink_port_init(struct ice_esw_br *bridge, struct ice_pf *pf)
{
- struct ice_vsi *vsi = pf->switchdev.uplink_vsi;
+ struct ice_vsi *vsi = pf->eswitch.uplink_vsi;
struct ice_esw_br_port *br_port;
int err;
@@ -1185,7 +1189,7 @@ ice_eswitch_br_port_event(struct notifier_block *nb,
static void
ice_eswitch_br_offloads_dealloc(struct ice_pf *pf)
{
- struct ice_esw_br_offloads *br_offloads = pf->switchdev.br_offloads;
+ struct ice_esw_br_offloads *br_offloads = pf->eswitch.br_offloads;
ASSERT_RTNL();
@@ -1194,7 +1198,7 @@ ice_eswitch_br_offloads_dealloc(struct ice_pf *pf)
ice_eswitch_br_deinit(br_offloads, br_offloads->bridge);
- pf->switchdev.br_offloads = NULL;
+ pf->eswitch.br_offloads = NULL;
kfree(br_offloads);
}
@@ -1205,14 +1209,14 @@ ice_eswitch_br_offloads_alloc(struct ice_pf *pf)
ASSERT_RTNL();
- if (pf->switchdev.br_offloads)
+ if (pf->eswitch.br_offloads)
return ERR_PTR(-EEXIST);
br_offloads = kzalloc(sizeof(*br_offloads), GFP_KERNEL);
if (!br_offloads)
return ERR_PTR(-ENOMEM);
- pf->switchdev.br_offloads = br_offloads;
+ pf->eswitch.br_offloads = br_offloads;
br_offloads->pf = pf;
return br_offloads;
@@ -1223,7 +1227,7 @@ ice_eswitch_br_offloads_deinit(struct ice_pf *pf)
{
struct ice_esw_br_offloads *br_offloads;
- br_offloads = pf->switchdev.br_offloads;
+ br_offloads = pf->eswitch.br_offloads;
if (!br_offloads)
return;
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index bde9bc74f928..a19b06f18e40 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -129,7 +129,6 @@ static const struct ice_stats ice_gstrings_pf_stats[] = {
ICE_PF_STAT("rx_oversize.nic", stats.rx_oversize),
ICE_PF_STAT("rx_jabber.nic", stats.rx_jabber),
ICE_PF_STAT("rx_csum_bad.nic", hw_csum_rx_error),
- ICE_PF_STAT("rx_length_errors.nic", stats.rx_len_errors),
ICE_PF_STAT("rx_dropped.nic", stats.eth.rx_discards),
ICE_PF_STAT("rx_crc_errors.nic", stats.crc_errors),
ICE_PF_STAT("illegal_bytes.nic", stats.illegal_bytes),
@@ -1142,8 +1141,7 @@ __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data,
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ICE_VSI_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- ice_gstrings_vsi_stats[i].stat_string);
+ ethtool_puts(&p, ice_gstrings_vsi_stats[i].stat_string);
if (ice_is_port_repr_netdev(netdev))
return;
@@ -1162,8 +1160,7 @@ __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data,
return;
for (i = 0; i < ICE_PF_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- ice_gstrings_pf_stats[i].stat_string);
+ ethtool_puts(&p, ice_gstrings_pf_stats[i].stat_string);
for (i = 0; i < ICE_MAX_USER_PRIORITY; i++) {
ethtool_sprintf(&p, "tx_priority_%u_xon.nic", i);
@@ -1179,8 +1176,7 @@ __ice_get_strings(struct net_device *netdev, u32 stringset, u8 *data,
break;
case ETH_SS_PRIV_FLAGS:
for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++)
- ethtool_sprintf(&p, "%s",
- ice_gstrings_priv_flags[i].name);
+ ethtool_puts(&p, ice_gstrings_priv_flags[i].name);
break;
default:
break;
@@ -2505,27 +2501,15 @@ static u32 ice_parse_hdrs(struct ethtool_rxnfc *nfc)
return hdrs;
}
-#define ICE_FLOW_HASH_FLD_IPV4_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)
-#define ICE_FLOW_HASH_FLD_IPV6_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)
-#define ICE_FLOW_HASH_FLD_IPV4_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)
-#define ICE_FLOW_HASH_FLD_IPV6_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)
-#define ICE_FLOW_HASH_FLD_TCP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)
-#define ICE_FLOW_HASH_FLD_TCP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)
-#define ICE_FLOW_HASH_FLD_UDP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)
-#define ICE_FLOW_HASH_FLD_UDP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)
-#define ICE_FLOW_HASH_FLD_SCTP_SRC_PORT \
- BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)
-#define ICE_FLOW_HASH_FLD_SCTP_DST_PORT \
- BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)
-
/**
* ice_parse_hash_flds - parses hash fields from RSS hash input
* @nfc: ethtool rxnfc command
+ * @symm: true if Symmetric Topelitz is set
*
* This function parses the rxnfc command and returns intended
* hash fields for RSS configuration
*/
-static u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc)
+static u64 ice_parse_hash_flds(struct ethtool_rxnfc *nfc, bool symm)
{
u64 hfld = ICE_HASH_INVALID;
@@ -2594,9 +2578,11 @@ static int
ice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
{
struct ice_pf *pf = vsi->back;
+ struct ice_rss_hash_cfg cfg;
struct device *dev;
u64 hashed_flds;
int status;
+ bool symm;
u32 hdrs;
dev = ice_pf_to_dev(pf);
@@ -2606,7 +2592,8 @@ ice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
return -EINVAL;
}
- hashed_flds = ice_parse_hash_flds(nfc);
+ symm = !!(vsi->rss_hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ);
+ hashed_flds = ice_parse_hash_flds(nfc, symm);
if (hashed_flds == ICE_HASH_INVALID) {
dev_dbg(dev, "Invalid hash fields, vsi num = %d\n",
vsi->vsi_num);
@@ -2620,7 +2607,12 @@ ice_set_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
return -EINVAL;
}
- status = ice_add_rss_cfg(&pf->hw, vsi->idx, hashed_flds, hdrs);
+ cfg.hash_flds = hashed_flds;
+ cfg.addl_hdrs = hdrs;
+ cfg.hdr_type = ICE_RSS_ANY_HEADERS;
+ cfg.symm = symm;
+
+ status = ice_add_rss_cfg(&pf->hw, vsi, &cfg);
if (status) {
dev_dbg(dev, "ice_add_rss_cfg failed, vsi num = %d, error = %d\n",
vsi->vsi_num, status);
@@ -2641,6 +2633,7 @@ ice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
struct ice_pf *pf = vsi->back;
struct device *dev;
u64 hash_flds;
+ bool symm;
u32 hdrs;
dev = ice_pf_to_dev(pf);
@@ -2659,7 +2652,7 @@ ice_get_rss_hash_opt(struct ice_vsi *vsi, struct ethtool_rxnfc *nfc)
return;
}
- hash_flds = ice_get_rss_cfg(&pf->hw, vsi->idx, hdrs);
+ hash_flds = ice_get_rss_cfg(&pf->hw, vsi->idx, hdrs, &symm);
if (hash_flds == ICE_HASH_INVALID) {
dev_dbg(dev, "No hash fields found for the given header type, vsi num = %d\n",
vsi->vsi_num);
@@ -3198,11 +3191,18 @@ static u32 ice_get_rxfh_indir_size(struct net_device *netdev)
return np->vsi->rss_table_size;
}
+/**
+ * ice_get_rxfh - get the Rx flow hash indirection table
+ * @netdev: network interface device structure
+ * @rxfh: pointer to param struct (indir, key, hfunc)
+ *
+ * Reads the indirection table directly from the hardware.
+ */
static int
-ice_get_rxfh_context(struct net_device *netdev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context)
+ice_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
+ u32 rss_context = rxfh->rss_context;
struct ice_vsi *vsi = np->vsi;
struct ice_pf *pf = vsi->back;
u16 qcount, offset;
@@ -3233,17 +3233,18 @@ ice_get_rxfh_context(struct net_device *netdev, u32 *indir,
vsi = vsi->tc_map_vsi[rss_context];
}
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (vsi->rss_hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ)
+ rxfh->input_xfrm |= RXH_XFRM_SYM_XOR;
- if (!indir)
+ if (!rxfh->indir)
return 0;
lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
if (!lut)
return -ENOMEM;
- err = ice_get_rss_key(vsi, key);
+ err = ice_get_rss_key(vsi, rxfh->key);
if (err)
goto out;
@@ -3253,12 +3254,12 @@ ice_get_rxfh_context(struct net_device *netdev, u32 *indir,
if (ice_is_adq_active(pf)) {
for (i = 0; i < vsi->rss_table_size; i++)
- indir[i] = offset + lut[i] % qcount;
+ rxfh->indir[i] = offset + lut[i] % qcount;
goto out;
}
for (i = 0; i < vsi->rss_table_size; i++)
- indir[i] = lut[i];
+ rxfh->indir[i] = lut[i];
out:
kfree(lut);
@@ -3266,42 +3267,31 @@ out:
}
/**
- * ice_get_rxfh - get the Rx flow hash indirection table
- * @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function
- *
- * Reads the indirection table directly from the hardware.
- */
-static int
-ice_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc)
-{
- return ice_get_rxfh_context(netdev, indir, key, hfunc, 0);
-}
-
-/**
* ice_set_rxfh - set the Rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function
+ * @rxfh: pointer to param struct (indir, key, hfunc)
+ * @extack: extended ACK from the Netlink message
*
* Returns -EINVAL if the table specifies an invalid queue ID, otherwise
* returns 0 after programming the table.
*/
static int
-ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
- const u8 hfunc)
+ice_set_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct ice_netdev_priv *np = netdev_priv(netdev);
+ u8 hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
struct ice_vsi *vsi = np->vsi;
struct ice_pf *pf = vsi->back;
struct device *dev;
int err;
dev = ice_pf_to_dev(pf);
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
+ if (rxfh->rss_context)
return -EOPNOTSUPP;
if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {
@@ -3315,7 +3305,15 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
return -EOPNOTSUPP;
}
- if (key) {
+ /* Update the VSI's hash function */
+ if (rxfh->input_xfrm & RXH_XFRM_SYM_XOR)
+ hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ;
+
+ err = ice_set_rss_hfunc(vsi, hfunc);
+ if (err)
+ return err;
+
+ if (rxfh->key) {
if (!vsi->rss_hkey_user) {
vsi->rss_hkey_user =
devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE,
@@ -3323,7 +3321,8 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
if (!vsi->rss_hkey_user)
return -ENOMEM;
}
- memcpy(vsi->rss_hkey_user, key, ICE_VSIQF_HKEY_ARRAY_SIZE);
+ memcpy(vsi->rss_hkey_user, rxfh->key,
+ ICE_VSIQF_HKEY_ARRAY_SIZE);
err = ice_set_rss_key(vsi, vsi->rss_hkey_user);
if (err)
@@ -3338,11 +3337,11 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key,
}
/* Each 32 bits pointed by 'indir' is stored with a lut entry */
- if (indir) {
+ if (rxfh->indir) {
int i;
for (i = 0; i < vsi->rss_table_size; i++)
- vsi->rss_lut_user[i] = (u8)(indir[i]);
+ vsi->rss_lut_user[i] = (u8)(rxfh->indir[i]);
} else {
ice_fill_rss_lut(vsi->rss_lut_user, vsi->rss_table_size,
vsi->rss_size);
@@ -4220,9 +4219,11 @@ ice_get_module_eeprom(struct net_device *netdev,
}
static const struct ethtool_ops ice_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USE_ADAPTIVE |
ETHTOOL_COALESCE_RX_USECS_HIGH,
+ .cap_rss_sym_xor_supported = true,
.get_link_ksettings = ice_get_link_ksettings,
.set_link_ksettings = ice_set_link_ksettings,
.get_drvinfo = ice_get_drvinfo,
@@ -4253,7 +4254,6 @@ static const struct ethtool_ops ice_ethtool_ops = {
.set_pauseparam = ice_set_pauseparam,
.get_rxfh_key_size = ice_get_rxfh_key_size,
.get_rxfh_indir_size = ice_get_rxfh_indir_size,
- .get_rxfh_context = ice_get_rxfh_context,
.get_rxfh = ice_get_rxfh,
.set_rxfh = ice_set_rxfh,
.get_channels = ice_get_channels,
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
index d151e5bacfec..9a1a04f5f146 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool_fdir.c
@@ -302,9 +302,7 @@ void ice_fdir_rem_adq_chnl(struct ice_hw *hw, u16 vsi_idx)
continue;
for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {
- u64 prof_id;
-
- prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
+ u64 prof_id = prof->prof_id[tun];
for (i = 0; i < prof->cnt; i++) {
if (prof->vsi_h[i] != vsi_idx)
@@ -362,10 +360,9 @@ ice_fdir_erase_flow_from_hw(struct ice_hw *hw, enum ice_block blk, int flow)
return;
for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {
- u64 prof_id;
+ u64 prof_id = prof->prof_id[tun];
int j;
- prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
for (j = 0; j < prof->cnt; j++) {
u16 vsi_num;
@@ -439,14 +436,12 @@ void ice_fdir_replay_flows(struct ice_hw *hw)
for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {
struct ice_flow_prof *hw_prof;
struct ice_fd_hw_prof *prof;
- u64 prof_id;
int j;
prof = hw->fdir_prof[flow];
- prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
- ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id,
+ ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX,
prof->fdir_seg[tun], TNL_SEG_CNT(tun),
- &hw_prof);
+ false, &hw_prof);
for (j = 0; j < prof->cnt; j++) {
enum ice_flow_priority prio;
u64 entry_h = 0;
@@ -454,7 +449,7 @@ void ice_fdir_replay_flows(struct ice_hw *hw)
prio = ICE_FLOW_PRIO_NORMAL;
err = ice_flow_add_entry(hw, ICE_BLK_FD,
- prof_id,
+ hw_prof->id,
prof->vsi_h[0],
prof->vsi_h[j],
prio, prof->fdir_seg,
@@ -464,6 +459,7 @@ void ice_fdir_replay_flows(struct ice_hw *hw)
flow);
continue;
}
+ prof->prof_id[tun] = hw_prof->id;
prof->entry_h[j][tun] = entry_h;
}
}
@@ -507,8 +503,7 @@ ice_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
return -EINVAL;
data->flex_word = value & ICE_USERDEF_FLEX_WORD_M;
- data->flex_offset = (value & ICE_USERDEF_FLEX_OFFS_M) >>
- ICE_USERDEF_FLEX_OFFS_S;
+ data->flex_offset = FIELD_GET(ICE_USERDEF_FLEX_OFFS_M, value);
if (data->flex_offset > ICE_USERDEF_FLEX_MAX_OFFS_VAL)
return -EINVAL;
@@ -638,7 +633,6 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,
u64 entry1_h = 0;
u64 entry2_h = 0;
bool del_last;
- u64 prof_id;
int err;
int idx;
@@ -668,7 +662,7 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,
* then return error.
*/
if (hw->fdir_fltr_cnt[flow]) {
- dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n");
+ dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n");
return -EINVAL;
}
@@ -686,23 +680,23 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,
* That is the final parameters are 1 header (segment), no
* actions (NULL) and zero actions 0.
*/
- prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
- err = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg,
- TNL_SEG_CNT(tun), &prof);
+ err = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, seg,
+ TNL_SEG_CNT(tun), false, &prof);
if (err)
return err;
- err = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, main_vsi->idx,
+ err = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id, main_vsi->idx,
main_vsi->idx, ICE_FLOW_PRIO_NORMAL,
seg, &entry1_h);
if (err)
goto err_prof;
- err = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, main_vsi->idx,
+ err = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id, main_vsi->idx,
ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,
seg, &entry2_h);
if (err)
goto err_entry;
hw_prof->fdir_seg[tun] = seg;
+ hw_prof->prof_id[tun] = prof->id;
hw_prof->entry_h[0][tun] = entry1_h;
hw_prof->entry_h[1][tun] = entry2_h;
hw_prof->vsi_h[0] = main_vsi->idx;
@@ -719,7 +713,7 @@ ice_fdir_set_hw_fltr_rule(struct ice_pf *pf, struct ice_flow_seg_info *seg,
entry1_h = 0;
vsi_h = main_vsi->tc_map_vsi[idx]->idx;
- err = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id,
+ err = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id,
main_vsi->idx, vsi_h,
ICE_FLOW_PRIO_NORMAL, seg,
&entry1_h);
@@ -756,7 +750,7 @@ err_unroll:
if (!hw_prof->entry_h[idx][tun])
continue;
- ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof_id);
+ ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof->id);
ice_flow_rem_entry(hw, ICE_BLK_FD, hw_prof->entry_h[idx][tun]);
hw_prof->entry_h[idx][tun] = 0;
if (del_last)
@@ -766,11 +760,11 @@ err_unroll:
hw_prof->cnt = 0;
err_entry:
ice_rem_prof_id_flow(hw, ICE_BLK_FD,
- ice_get_hw_vsi_num(hw, main_vsi->idx), prof_id);
+ ice_get_hw_vsi_num(hw, main_vsi->idx), prof->id);
ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);
err_prof:
- ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
- dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n");
+ ice_flow_rem_prof(hw, ICE_BLK_FD, prof->id);
+ dev_err(dev, "Failed to add filter. Flow director filters on each port must have the same input set.\n");
return err;
}
@@ -1853,6 +1847,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
struct ice_pf *pf;
struct ice_hw *hw;
int fltrs_needed;
+ u32 max_location;
u16 tunnel_port;
int ret;
@@ -1884,8 +1879,10 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
if (ret)
return ret;
- if (fsp->location >= ice_get_fdir_cnt_all(hw)) {
- dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n");
+ max_location = ice_get_fdir_cnt_all(hw);
+ if (fsp->location >= max_location) {
+ dev_err(dev, "Failed to add filter. The number of ntuple filters or provided location exceed max %d.\n",
+ max_location);
return -ENOSPC;
}
@@ -1893,7 +1890,7 @@ int ice_add_fdir_ethtool(struct ice_vsi *vsi, struct ethtool_rxnfc *cmd)
fltrs_needed = ice_get_open_tunnel_port(hw, &tunnel_port, TNL_ALL) ? 2 : 1;
if (!ice_fdir_find_fltr_by_idx(hw, fsp->location) &&
ice_fdir_num_avail_fltr(hw, pf->vsi[vsi->idx]) < fltrs_needed) {
- dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n");
+ dev_err(dev, "Failed to add filter. The maximum number of flow director filters has been reached.\n");
return -ENOSPC;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_fdir.c b/drivers/net/ethernet/intel/ice/ice_fdir.c
index ae089d32ee9d..5840c3e04a5b 100644
--- a/drivers/net/ethernet/intel/ice/ice_fdir.c
+++ b/drivers/net/ethernet/intel/ice/ice_fdir.c
@@ -604,55 +604,32 @@ ice_set_fd_desc_val(struct ice_fd_fltr_desc_ctx *ctx,
u64 qword;
/* prep QW0 of FD filter programming desc */
- qword = ((u64)ctx->qindex << ICE_FXD_FLTR_QW0_QINDEX_S) &
- ICE_FXD_FLTR_QW0_QINDEX_M;
- qword |= ((u64)ctx->comp_q << ICE_FXD_FLTR_QW0_COMP_Q_S) &
- ICE_FXD_FLTR_QW0_COMP_Q_M;
- qword |= ((u64)ctx->comp_report << ICE_FXD_FLTR_QW0_COMP_REPORT_S) &
- ICE_FXD_FLTR_QW0_COMP_REPORT_M;
- qword |= ((u64)ctx->fd_space << ICE_FXD_FLTR_QW0_FD_SPACE_S) &
- ICE_FXD_FLTR_QW0_FD_SPACE_M;
- qword |= ((u64)ctx->cnt_index << ICE_FXD_FLTR_QW0_STAT_CNT_S) &
- ICE_FXD_FLTR_QW0_STAT_CNT_M;
- qword |= ((u64)ctx->cnt_ena << ICE_FXD_FLTR_QW0_STAT_ENA_S) &
- ICE_FXD_FLTR_QW0_STAT_ENA_M;
- qword |= ((u64)ctx->evict_ena << ICE_FXD_FLTR_QW0_EVICT_ENA_S) &
- ICE_FXD_FLTR_QW0_EVICT_ENA_M;
- qword |= ((u64)ctx->toq << ICE_FXD_FLTR_QW0_TO_Q_S) &
- ICE_FXD_FLTR_QW0_TO_Q_M;
- qword |= ((u64)ctx->toq_prio << ICE_FXD_FLTR_QW0_TO_Q_PRI_S) &
- ICE_FXD_FLTR_QW0_TO_Q_PRI_M;
- qword |= ((u64)ctx->dpu_recipe << ICE_FXD_FLTR_QW0_DPU_RECIPE_S) &
- ICE_FXD_FLTR_QW0_DPU_RECIPE_M;
- qword |= ((u64)ctx->drop << ICE_FXD_FLTR_QW0_DROP_S) &
- ICE_FXD_FLTR_QW0_DROP_M;
- qword |= ((u64)ctx->flex_prio << ICE_FXD_FLTR_QW0_FLEX_PRI_S) &
- ICE_FXD_FLTR_QW0_FLEX_PRI_M;
- qword |= ((u64)ctx->flex_mdid << ICE_FXD_FLTR_QW0_FLEX_MDID_S) &
- ICE_FXD_FLTR_QW0_FLEX_MDID_M;
- qword |= ((u64)ctx->flex_val << ICE_FXD_FLTR_QW0_FLEX_VAL_S) &
- ICE_FXD_FLTR_QW0_FLEX_VAL_M;
+ qword = FIELD_PREP(ICE_FXD_FLTR_QW0_QINDEX_M, ctx->qindex);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_COMP_Q_M, ctx->comp_q);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_COMP_REPORT_M, ctx->comp_report);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_FD_SPACE_M, ctx->fd_space);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_STAT_CNT_M, ctx->cnt_index);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_STAT_ENA_M, ctx->cnt_ena);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_EVICT_ENA_M, ctx->evict_ena);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_TO_Q_M, ctx->toq);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_TO_Q_PRI_M, ctx->toq_prio);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_DPU_RECIPE_M, ctx->dpu_recipe);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_DROP_M, ctx->drop);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_FLEX_PRI_M, ctx->flex_prio);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_FLEX_MDID_M, ctx->flex_mdid);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW0_FLEX_VAL_M, ctx->flex_val);
fdir_desc->qidx_compq_space_stat = cpu_to_le64(qword);
/* prep QW1 of FD filter programming desc */
- qword = ((u64)ctx->dtype << ICE_FXD_FLTR_QW1_DTYPE_S) &
- ICE_FXD_FLTR_QW1_DTYPE_M;
- qword |= ((u64)ctx->pcmd << ICE_FXD_FLTR_QW1_PCMD_S) &
- ICE_FXD_FLTR_QW1_PCMD_M;
- qword |= ((u64)ctx->desc_prof_prio << ICE_FXD_FLTR_QW1_PROF_PRI_S) &
- ICE_FXD_FLTR_QW1_PROF_PRI_M;
- qword |= ((u64)ctx->desc_prof << ICE_FXD_FLTR_QW1_PROF_S) &
- ICE_FXD_FLTR_QW1_PROF_M;
- qword |= ((u64)ctx->fd_vsi << ICE_FXD_FLTR_QW1_FD_VSI_S) &
- ICE_FXD_FLTR_QW1_FD_VSI_M;
- qword |= ((u64)ctx->swap << ICE_FXD_FLTR_QW1_SWAP_S) &
- ICE_FXD_FLTR_QW1_SWAP_M;
- qword |= ((u64)ctx->fdid_prio << ICE_FXD_FLTR_QW1_FDID_PRI_S) &
- ICE_FXD_FLTR_QW1_FDID_PRI_M;
- qword |= ((u64)ctx->fdid_mdid << ICE_FXD_FLTR_QW1_FDID_MDID_S) &
- ICE_FXD_FLTR_QW1_FDID_MDID_M;
- qword |= ((u64)ctx->fdid << ICE_FXD_FLTR_QW1_FDID_S) &
- ICE_FXD_FLTR_QW1_FDID_M;
+ qword = FIELD_PREP(ICE_FXD_FLTR_QW1_DTYPE_M, ctx->dtype);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_PCMD_M, ctx->pcmd);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_PROF_PRI_M, ctx->desc_prof_prio);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_PROF_M, ctx->desc_prof);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_FD_VSI_M, ctx->fd_vsi);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_SWAP_M, ctx->swap);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_FDID_PRI_M, ctx->fdid_prio);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_FDID_MDID_M, ctx->fdid_mdid);
+ qword |= FIELD_PREP(ICE_FXD_FLTR_QW1_FDID_M, ctx->fdid);
fdir_desc->dtype_cmd_vsi_fdid = cpu_to_le64(qword);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
index 5ce413965930..20d5db88c99f 100644
--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c
@@ -1218,11 +1218,13 @@ ice_prof_has_mask(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 *masks)
* @blk: HW block
* @fv: field vector to search for
* @masks: masks for FV
+ * @symm: symmetric setting for RSS flows
* @prof_id: receives the profile ID
*/
static int
ice_find_prof_id_with_mask(struct ice_hw *hw, enum ice_block blk,
- struct ice_fv_word *fv, u16 *masks, u8 *prof_id)
+ struct ice_fv_word *fv, u16 *masks, bool symm,
+ u8 *prof_id)
{
struct ice_es *es = &hw->blk[blk].es;
u8 i;
@@ -1236,6 +1238,9 @@ ice_find_prof_id_with_mask(struct ice_hw *hw, enum ice_block blk,
for (i = 0; i < (u8)es->count; i++) {
u16 off = i * es->fvw;
+ if (blk == ICE_BLK_RSS && es->symm[i] != symm)
+ continue;
+
if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
continue;
@@ -1409,13 +1414,13 @@ ice_write_prof_mask_reg(struct ice_hw *hw, enum ice_block blk, u16 mask_idx,
switch (blk) {
case ICE_BLK_RSS:
offset = GLQF_HMASK(mask_idx);
- val = (idx << GLQF_HMASK_MSK_INDEX_S) & GLQF_HMASK_MSK_INDEX_M;
- val |= (mask << GLQF_HMASK_MASK_S) & GLQF_HMASK_MASK_M;
+ val = FIELD_PREP(GLQF_HMASK_MSK_INDEX_M, idx);
+ val |= FIELD_PREP(GLQF_HMASK_MASK_M, mask);
break;
case ICE_BLK_FD:
offset = GLQF_FDMASK(mask_idx);
- val = (idx << GLQF_FDMASK_MSK_INDEX_S) & GLQF_FDMASK_MSK_INDEX_M;
- val |= (mask << GLQF_FDMASK_MASK_S) & GLQF_FDMASK_MASK_M;
+ val = FIELD_PREP(GLQF_FDMASK_MSK_INDEX_M, idx);
+ val |= FIELD_PREP(GLQF_FDMASK_MASK_M, mask);
break;
default:
ice_debug(hw, ICE_DBG_PKG, "No profile masks for block %d\n",
@@ -1716,15 +1721,16 @@ ice_update_prof_masking(struct ice_hw *hw, enum ice_block blk, u16 prof_id,
}
/**
- * ice_write_es - write an extraction sequence to hardware
+ * ice_write_es - write an extraction sequence and symmetric setting to hardware
* @hw: pointer to the HW struct
* @blk: the block in which to write the extraction sequence
* @prof_id: the profile ID to write
* @fv: pointer to the extraction sequence to write - NULL to clear extraction
+ * @symm: symmetric setting for RSS profiles
*/
static void
ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id,
- struct ice_fv_word *fv)
+ struct ice_fv_word *fv, bool symm)
{
u16 off;
@@ -1737,6 +1743,9 @@ ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id,
memcpy(&hw->blk[blk].es.t[off], fv,
hw->blk[blk].es.fvw * sizeof(*fv));
}
+
+ if (blk == ICE_BLK_RSS)
+ hw->blk[blk].es.symm[prof_id] = symm;
}
/**
@@ -1753,7 +1762,7 @@ ice_prof_dec_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id)
if (hw->blk[blk].es.ref_count[prof_id] > 0) {
if (!--hw->blk[blk].es.ref_count[prof_id]) {
- ice_write_es(hw, blk, prof_id, NULL);
+ ice_write_es(hw, blk, prof_id, NULL, false);
ice_free_prof_masks(hw, blk, prof_id);
return ice_free_prof_id(hw, blk, prof_id);
}
@@ -2116,8 +2125,10 @@ void ice_free_hw_tbls(struct ice_hw *hw)
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].prof_redir.t);
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].es.t);
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].es.ref_count);
+ devm_kfree(ice_hw_to_dev(hw), hw->blk[i].es.symm);
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].es.written);
devm_kfree(ice_hw_to_dev(hw), hw->blk[i].es.mask_ena);
+ devm_kfree(ice_hw_to_dev(hw), hw->blk[i].prof_id.id);
}
list_for_each_entry_safe(r, rt, &hw->rss_list_head, l_entry) {
@@ -2150,6 +2161,7 @@ void ice_clear_hw_tbls(struct ice_hw *hw)
for (i = 0; i < ICE_BLK_COUNT; i++) {
struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
+ struct ice_prof_id *prof_id = &hw->blk[i].prof_id;
struct ice_prof_tcam *prof = &hw->blk[i].prof;
struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1;
struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2;
@@ -2178,8 +2190,11 @@ void ice_clear_hw_tbls(struct ice_hw *hw)
memset(es->t, 0, es->count * sizeof(*es->t) * es->fvw);
memset(es->ref_count, 0, es->count * sizeof(*es->ref_count));
+ memset(es->symm, 0, es->count * sizeof(*es->symm));
memset(es->written, 0, es->count * sizeof(*es->written));
memset(es->mask_ena, 0, es->count * sizeof(*es->mask_ena));
+
+ memset(prof_id->id, 0, prof_id->count * sizeof(*prof_id->id));
}
}
@@ -2196,6 +2211,7 @@ int ice_init_hw_tbls(struct ice_hw *hw)
ice_init_all_prof_masks(hw);
for (i = 0; i < ICE_BLK_COUNT; i++) {
struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
+ struct ice_prof_id *prof_id = &hw->blk[i].prof_id;
struct ice_prof_tcam *prof = &hw->blk[i].prof;
struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1;
struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2;
@@ -2292,6 +2308,11 @@ int ice_init_hw_tbls(struct ice_hw *hw)
if (!es->ref_count)
goto err;
+ es->symm = devm_kcalloc(ice_hw_to_dev(hw), es->count,
+ sizeof(*es->symm), GFP_KERNEL);
+ if (!es->symm)
+ goto err;
+
es->written = devm_kcalloc(ice_hw_to_dev(hw), es->count,
sizeof(*es->written), GFP_KERNEL);
if (!es->written)
@@ -2301,6 +2322,12 @@ int ice_init_hw_tbls(struct ice_hw *hw)
sizeof(*es->mask_ena), GFP_KERNEL);
if (!es->mask_ena)
goto err;
+
+ prof_id->count = blk_sizes[i].prof_id;
+ prof_id->id = devm_kcalloc(ice_hw_to_dev(hw), prof_id->count,
+ sizeof(*prof_id->id), GFP_KERNEL);
+ if (!prof_id->id)
+ goto err;
}
return 0;
@@ -2963,6 +2990,7 @@ ice_add_prof_attrib(struct ice_prof_map *prof, u8 ptg, u16 ptype,
* @attr_cnt: number of elements in attr array
* @es: extraction sequence (length of array is determined by the block)
* @masks: mask for extraction sequence
+ * @symm: symmetric setting for RSS profiles
*
* This function registers a profile, which matches a set of PTYPES with a
* particular extraction sequence. While the hardware profile is allocated
@@ -2972,7 +3000,7 @@ ice_add_prof_attrib(struct ice_prof_map *prof, u8 ptg, u16 ptype,
int
ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
const struct ice_ptype_attributes *attr, u16 attr_cnt,
- struct ice_fv_word *es, u16 *masks)
+ struct ice_fv_word *es, u16 *masks, bool symm)
{
u32 bytes = DIV_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE);
DECLARE_BITMAP(ptgs_used, ICE_XLT1_CNT);
@@ -2986,7 +3014,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
mutex_lock(&hw->blk[blk].es.prof_map_lock);
/* search for existing profile */
- status = ice_find_prof_id_with_mask(hw, blk, es, masks, &prof_id);
+ status = ice_find_prof_id_with_mask(hw, blk, es, masks, symm, &prof_id);
if (status) {
/* allocate profile ID */
status = ice_alloc_prof_id(hw, blk, &prof_id);
@@ -3009,7 +3037,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
goto err_ice_add_prof;
/* and write new es */
- ice_write_es(hw, blk, prof_id, es);
+ ice_write_es(hw, blk, prof_id, es, symm);
}
ice_prof_inc_ref(hw, blk, prof_id);
@@ -3097,7 +3125,7 @@ err_ice_add_prof:
* This will search for a profile tracking ID which was previously added.
* The profile map lock should be held before calling this function.
*/
-static struct ice_prof_map *
+struct ice_prof_map *
ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id)
{
struct ice_prof_map *entry = NULL;
diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h
index 7af7c8e9aa4e..b39d7cdc381f 100644
--- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.h
+++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.h
@@ -42,7 +42,9 @@ bool ice_hw_ptype_ena(struct ice_hw *hw, u16 ptype);
int
ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
const struct ice_ptype_attributes *attr, u16 attr_cnt,
- struct ice_fv_word *es, u16 *masks);
+ struct ice_fv_word *es, u16 *masks, bool symm);
+struct ice_prof_map *
+ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id);
int
ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl);
int
diff --git a/drivers/net/ethernet/intel/ice/ice_flex_type.h b/drivers/net/ethernet/intel/ice/ice_flex_type.h
index 4f42e14ed3ae..d427a79d001a 100644
--- a/drivers/net/ethernet/intel/ice/ice_flex_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_flex_type.h
@@ -146,6 +146,7 @@ struct ice_es {
u32 *mask_ena;
struct list_head prof_map;
struct ice_fv_word *t;
+ u8 *symm; /* symmetric setting per profile (RSS blk)*/
struct mutex prof_map_lock; /* protect access to profiles list */
u8 *written;
u8 reverse; /* set to true to reverse FV order */
@@ -304,10 +305,16 @@ struct ice_masks {
struct ice_mask masks[ICE_PROF_MASK_COUNT];
};
+struct ice_prof_id {
+ unsigned long *id;
+ int count;
+};
+
/* Tables per block */
struct ice_blk_info {
struct ice_xlt1 xlt1;
struct ice_xlt2 xlt2;
+ struct ice_prof_id prof_id;
struct ice_prof_tcam prof;
struct ice_prof_redir prof_redir;
struct ice_es es;
diff --git a/drivers/net/ethernet/intel/ice/ice_flow.c b/drivers/net/ethernet/intel/ice/ice_flow.c
index fb8b925aaf8b..fc2b58f56279 100644
--- a/drivers/net/ethernet/intel/ice/ice_flow.c
+++ b/drivers/net/ethernet/intel/ice/ice_flow.c
@@ -1235,6 +1235,7 @@ ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
#define ICE_FLOW_FIND_PROF_CHK_FLDS 0x00000001
#define ICE_FLOW_FIND_PROF_CHK_VSI 0x00000002
#define ICE_FLOW_FIND_PROF_NOT_CHK_DIR 0x00000004
+#define ICE_FLOW_FIND_PROF_CHK_SYMM 0x00000008
/**
* ice_flow_find_prof_conds - Find a profile matching headers and conditions
@@ -1243,13 +1244,14 @@ ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
* @dir: flow direction
* @segs: array of one or more packet segments that describe the flow
* @segs_cnt: number of packet segments provided
+ * @symm: symmetric setting for RSS profiles
* @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI)
* @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*)
*/
static struct ice_flow_prof *
ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
- u8 segs_cnt, u16 vsi_handle, u32 conds)
+ u8 segs_cnt, bool symm, u16 vsi_handle, u32 conds)
{
struct ice_flow_prof *p, *prof = NULL;
@@ -1265,6 +1267,11 @@ ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
!test_bit(vsi_handle, p->vsis))
continue;
+ /* Check for symmetric settings */
+ if ((conds & ICE_FLOW_FIND_PROF_CHK_SYMM) &&
+ p->symm != symm)
+ continue;
+
/* Protocol headers must be checked. Matched fields are
* checked if specified.
*/
@@ -1328,26 +1335,33 @@ ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,
* @hw: pointer to the HW struct
* @blk: classification stage
* @dir: flow direction
- * @prof_id: unique ID to identify this flow profile
* @segs: array of one or more packet segments that describe the flow
* @segs_cnt: number of packet segments provided
+ * @symm: symmetric setting for RSS profiles
* @prof: stores the returned flow profile added
*
* Assumption: the caller has acquired the lock to the profile list
*/
static int
ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
- enum ice_flow_dir dir, u64 prof_id,
+ enum ice_flow_dir dir,
struct ice_flow_seg_info *segs, u8 segs_cnt,
- struct ice_flow_prof **prof)
+ bool symm, struct ice_flow_prof **prof)
{
struct ice_flow_prof_params *params;
+ struct ice_prof_id *ids;
int status;
+ u64 prof_id;
u8 i;
if (!prof)
return -EINVAL;
+ ids = &hw->blk[blk].prof_id;
+ prof_id = find_first_zero_bit(ids->id, ids->count);
+ if (prof_id >= ids->count)
+ return -ENOSPC;
+
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
@@ -1369,6 +1383,7 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
params->prof->id = prof_id;
params->prof->dir = dir;
params->prof->segs_cnt = segs_cnt;
+ params->prof->symm = symm;
/* Make a copy of the segments that need to be persistent in the flow
* profile instance
@@ -1385,7 +1400,7 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
/* Add a HW profile for this flow profile */
status = ice_add_prof(hw, blk, prof_id, (u8 *)params->ptypes,
params->attr, params->attr_cnt, params->es,
- params->mask);
+ params->mask, symm);
if (status) {
ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
goto out;
@@ -1393,6 +1408,7 @@ ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
INIT_LIST_HEAD(&params->prof->entries);
mutex_init(&params->prof->entries_lock);
+ set_bit(prof_id, ids->id);
*prof = params->prof;
out:
@@ -1436,6 +1452,7 @@ ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,
/* Remove all hardware profiles associated with this flow profile */
status = ice_rem_prof(hw, blk, prof->id);
if (!status) {
+ clear_bit(prof->id, hw->blk[blk].prof_id.id);
list_del(&prof->l_entry);
mutex_destroy(&prof->entries_lock);
devm_kfree(ice_hw_to_dev(hw), prof);
@@ -1511,15 +1528,15 @@ ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
* @hw: pointer to the HW struct
* @blk: classification stage
* @dir: flow direction
- * @prof_id: unique ID to identify this flow profile
* @segs: array of one or more packet segments that describe the flow
* @segs_cnt: number of packet segments provided
+ * @symm: symmetric setting for RSS profiles
* @prof: stores the returned flow profile added
*/
int
ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
- u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
- struct ice_flow_prof **prof)
+ struct ice_flow_seg_info *segs, u8 segs_cnt,
+ bool symm, struct ice_flow_prof **prof)
{
int status;
@@ -1538,8 +1555,8 @@ ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
mutex_lock(&hw->fl_profs_locks[blk]);
- status = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,
- prof);
+ status = ice_flow_add_prof_sync(hw, blk, dir, segs, segs_cnt,
+ symm, prof);
if (!status)
list_add(&(*prof)->l_entry, &hw->fl_profs[blk]);
@@ -1855,37 +1872,49 @@ int ice_flow_rem_vsi_prof(struct ice_hw *hw, u16 vsi_handle, u64 prof_id)
/**
* ice_flow_set_rss_seg_info - setup packet segments for RSS
* @segs: pointer to the flow field segment(s)
- * @hash_fields: fields to be hashed on for the segment(s)
- * @flow_hdr: protocol header fields within a packet segment
+ * @seg_cnt: segment count
+ * @cfg: configure parameters
*
* Helper function to extract fields from hash bitmap and use flow
* header value to set flow field segment for further use in flow
* profile entry or removal.
*/
static int
-ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
- u32 flow_hdr)
+ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u8 seg_cnt,
+ const struct ice_rss_hash_cfg *cfg)
{
+ struct ice_flow_seg_info *seg;
u64 val;
- u8 i;
+ u16 i;
- for_each_set_bit(i, (unsigned long *)&hash_fields,
- ICE_FLOW_FIELD_IDX_MAX)
- ice_flow_set_fld(segs, (enum ice_flow_field)i,
+ /* set inner most segment */
+ seg = &segs[seg_cnt - 1];
+
+ for_each_set_bit(i, (const unsigned long *)&cfg->hash_flds,
+ (u16)ICE_FLOW_FIELD_IDX_MAX)
+ ice_flow_set_fld(seg, (enum ice_flow_field)i,
ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
ICE_FLOW_FLD_OFF_INVAL, false);
- ICE_FLOW_SET_HDRS(segs, flow_hdr);
+ ICE_FLOW_SET_HDRS(seg, cfg->addl_hdrs);
+
+ /* set outer most header */
+ if (cfg->hdr_type == ICE_RSS_INNER_HEADERS_W_OUTER_IPV4)
+ segs[ICE_RSS_OUTER_HEADERS].hdrs |= ICE_FLOW_SEG_HDR_IPV4 |
+ ICE_FLOW_SEG_HDR_IPV_OTHER;
+ else if (cfg->hdr_type == ICE_RSS_INNER_HEADERS_W_OUTER_IPV6)
+ segs[ICE_RSS_OUTER_HEADERS].hdrs |= ICE_FLOW_SEG_HDR_IPV6 |
+ ICE_FLOW_SEG_HDR_IPV_OTHER;
- if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS &
+ if (seg->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS &
~ICE_FLOW_RSS_HDRS_INNER_MASK & ~ICE_FLOW_SEG_HDR_IPV_OTHER)
return -EINVAL;
- val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
+ val = (u64)(seg->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
if (val && !is_power_of_2(val))
return -EIO;
- val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
+ val = (u64)(seg->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
if (val && !is_power_of_2(val))
return -EIO;
@@ -1956,6 +1985,39 @@ int ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
}
/**
+ * ice_get_rss_hdr_type - get a RSS profile's header type
+ * @prof: RSS flow profile
+ */
+static enum ice_rss_cfg_hdr_type
+ice_get_rss_hdr_type(struct ice_flow_prof *prof)
+{
+ if (prof->segs_cnt == ICE_FLOW_SEG_SINGLE) {
+ return ICE_RSS_OUTER_HEADERS;
+ } else if (prof->segs_cnt == ICE_FLOW_SEG_MAX) {
+ const struct ice_flow_seg_info *s;
+
+ s = &prof->segs[ICE_RSS_OUTER_HEADERS];
+ if (s->hdrs == ICE_FLOW_SEG_HDR_NONE)
+ return ICE_RSS_INNER_HEADERS;
+ if (s->hdrs & ICE_FLOW_SEG_HDR_IPV4)
+ return ICE_RSS_INNER_HEADERS_W_OUTER_IPV4;
+ if (s->hdrs & ICE_FLOW_SEG_HDR_IPV6)
+ return ICE_RSS_INNER_HEADERS_W_OUTER_IPV6;
+ }
+
+ return ICE_RSS_ANY_HEADERS;
+}
+
+static bool
+ice_rss_match_prof(struct ice_rss_cfg *r, struct ice_flow_prof *prof,
+ enum ice_rss_cfg_hdr_type hdr_type)
+{
+ return (r->hash.hdr_type == hdr_type &&
+ r->hash.hash_flds == prof->segs[prof->segs_cnt - 1].match &&
+ r->hash.addl_hdrs == prof->segs[prof->segs_cnt - 1].hdrs);
+}
+
+/**
* ice_rem_rss_list - remove RSS configuration from list
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
@@ -1966,15 +2028,16 @@ int ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
static void
ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
{
+ enum ice_rss_cfg_hdr_type hdr_type;
struct ice_rss_cfg *r, *tmp;
/* Search for RSS hash fields associated to the VSI that match the
* hash configurations associated to the flow profile. If found
* remove from the RSS entry list of the VSI context and delete entry.
*/
+ hdr_type = ice_get_rss_hdr_type(prof);
list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
- if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
- r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
+ if (ice_rss_match_prof(r, prof, hdr_type)) {
clear_bit(vsi_handle, r->vsis);
if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
list_del(&r->l_entry);
@@ -1995,11 +2058,12 @@ ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
static int
ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
{
+ enum ice_rss_cfg_hdr_type hdr_type;
struct ice_rss_cfg *r, *rss_cfg;
+ hdr_type = ice_get_rss_hdr_type(prof);
list_for_each_entry(r, &hw->rss_list_head, l_entry)
- if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
- r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
+ if (ice_rss_match_prof(r, prof, hdr_type)) {
set_bit(vsi_handle, r->vsis);
return 0;
}
@@ -2009,8 +2073,10 @@ ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
if (!rss_cfg)
return -ENOMEM;
- rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match;
- rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs;
+ rss_cfg->hash.hash_flds = prof->segs[prof->segs_cnt - 1].match;
+ rss_cfg->hash.addl_hdrs = prof->segs[prof->segs_cnt - 1].hdrs;
+ rss_cfg->hash.hdr_type = hdr_type;
+ rss_cfg->hash.symm = prof->symm;
set_bit(vsi_handle, rss_cfg->vsis);
list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head);
@@ -2018,65 +2084,177 @@ ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
return 0;
}
-#define ICE_FLOW_PROF_HASH_S 0
-#define ICE_FLOW_PROF_HASH_M (0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
-#define ICE_FLOW_PROF_HDR_S 32
-#define ICE_FLOW_PROF_HDR_M (0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
-#define ICE_FLOW_PROF_ENCAP_S 63
-#define ICE_FLOW_PROF_ENCAP_M (BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
+/**
+ * ice_rss_config_xor_word - set the HSYMM registers for one input set word
+ * @hw: pointer to the hardware structure
+ * @prof_id: RSS hardware profile id
+ * @src: the FV index used by the protocol's source field
+ * @dst: the FV index used by the protocol's destination field
+ *
+ * Write to the HSYMM register with the index of @src FV the value of the @dst
+ * FV index. This will tell the hardware to XOR HSYMM[src] with INSET[dst]
+ * while calculating the RSS input set.
+ */
+static void
+ice_rss_config_xor_word(struct ice_hw *hw, u8 prof_id, u8 src, u8 dst)
+{
+ u32 val, reg, bits_shift;
+ u8 reg_idx;
+
+ reg_idx = src / GLQF_HSYMM_REG_SIZE;
+ bits_shift = ((src % GLQF_HSYMM_REG_SIZE) << 3);
+ val = dst | GLQF_HSYMM_ENABLE_BIT;
+
+ reg = rd32(hw, GLQF_HSYMM(prof_id, reg_idx));
+ reg = (reg & ~(0xff << bits_shift)) | (val << bits_shift);
+ wr32(hw, GLQF_HSYMM(prof_id, reg_idx), reg);
+}
-#define ICE_RSS_OUTER_HEADERS 1
-#define ICE_RSS_INNER_HEADERS 2
+/**
+ * ice_rss_config_xor - set the symmetric registers for a profile's protocol
+ * @hw: pointer to the hardware structure
+ * @prof_id: RSS hardware profile id
+ * @src: the FV index used by the protocol's source field
+ * @dst: the FV index used by the protocol's destination field
+ * @len: length of the source/destination fields in words
+ */
+static void
+ice_rss_config_xor(struct ice_hw *hw, u8 prof_id, u8 src, u8 dst, u8 len)
+{
+ int fv_last_word =
+ ICE_FLOW_SW_FIELD_VECTOR_MAX / ICE_FLOW_FV_EXTRACT_SZ - 1;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ ice_rss_config_xor_word(hw, prof_id,
+ /* Yes, field vector in GLQF_HSYMM and
+ * GLQF_HINSET is inversed!
+ */
+ fv_last_word - (src + i),
+ fv_last_word - (dst + i));
+ ice_rss_config_xor_word(hw, prof_id,
+ fv_last_word - (dst + i),
+ fv_last_word - (src + i));
+ }
+}
-/* Flow profile ID format:
- * [0:31] - Packet match fields
- * [32:62] - Protocol header
- * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
+/**
+ * ice_rss_set_symm - set the symmetric settings for an RSS profile
+ * @hw: pointer to the hardware structure
+ * @prof: pointer to flow profile
+ *
+ * The symmetric hash will result from XORing the protocol's fields with
+ * indexes in GLQF_HSYMM and GLQF_HINSET. This function configures the profile's
+ * GLQF_HSYMM registers.
*/
-#define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
- ((u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
- (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
- ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0)))
+static void ice_rss_set_symm(struct ice_hw *hw, struct ice_flow_prof *prof)
+{
+ struct ice_prof_map *map;
+ u8 prof_id, m;
+
+ mutex_lock(&hw->blk[ICE_BLK_RSS].es.prof_map_lock);
+ map = ice_search_prof_id(hw, ICE_BLK_RSS, prof->id);
+ if (map)
+ prof_id = map->prof_id;
+ mutex_unlock(&hw->blk[ICE_BLK_RSS].es.prof_map_lock);
+
+ if (!map)
+ return;
+
+ /* clear to default */
+ for (m = 0; m < GLQF_HSYMM_REG_PER_PROF; m++)
+ wr32(hw, GLQF_HSYMM(prof_id, m), 0);
+
+ if (prof->symm) {
+ struct ice_flow_seg_xtrct *ipv4_src, *ipv4_dst;
+ struct ice_flow_seg_xtrct *ipv6_src, *ipv6_dst;
+ struct ice_flow_seg_xtrct *sctp_src, *sctp_dst;
+ struct ice_flow_seg_xtrct *tcp_src, *tcp_dst;
+ struct ice_flow_seg_xtrct *udp_src, *udp_dst;
+ struct ice_flow_seg_info *seg;
+
+ seg = &prof->segs[prof->segs_cnt - 1];
+
+ ipv4_src = &seg->fields[ICE_FLOW_FIELD_IDX_IPV4_SA].xtrct;
+ ipv4_dst = &seg->fields[ICE_FLOW_FIELD_IDX_IPV4_DA].xtrct;
+
+ ipv6_src = &seg->fields[ICE_FLOW_FIELD_IDX_IPV6_SA].xtrct;
+ ipv6_dst = &seg->fields[ICE_FLOW_FIELD_IDX_IPV6_DA].xtrct;
+
+ tcp_src = &seg->fields[ICE_FLOW_FIELD_IDX_TCP_SRC_PORT].xtrct;
+ tcp_dst = &seg->fields[ICE_FLOW_FIELD_IDX_TCP_DST_PORT].xtrct;
+
+ udp_src = &seg->fields[ICE_FLOW_FIELD_IDX_UDP_SRC_PORT].xtrct;
+ udp_dst = &seg->fields[ICE_FLOW_FIELD_IDX_UDP_DST_PORT].xtrct;
+
+ sctp_src = &seg->fields[ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT].xtrct;
+ sctp_dst = &seg->fields[ICE_FLOW_FIELD_IDX_SCTP_DST_PORT].xtrct;
+
+ /* xor IPv4 */
+ if (ipv4_src->prot_id != 0 && ipv4_dst->prot_id != 0)
+ ice_rss_config_xor(hw, prof_id,
+ ipv4_src->idx, ipv4_dst->idx, 2);
+
+ /* xor IPv6 */
+ if (ipv6_src->prot_id != 0 && ipv6_dst->prot_id != 0)
+ ice_rss_config_xor(hw, prof_id,
+ ipv6_src->idx, ipv6_dst->idx, 8);
+
+ /* xor TCP */
+ if (tcp_src->prot_id != 0 && tcp_dst->prot_id != 0)
+ ice_rss_config_xor(hw, prof_id,
+ tcp_src->idx, tcp_dst->idx, 1);
+
+ /* xor UDP */
+ if (udp_src->prot_id != 0 && udp_dst->prot_id != 0)
+ ice_rss_config_xor(hw, prof_id,
+ udp_src->idx, udp_dst->idx, 1);
+
+ /* xor SCTP */
+ if (sctp_src->prot_id != 0 && sctp_dst->prot_id != 0)
+ ice_rss_config_xor(hw, prof_id,
+ sctp_src->idx, sctp_dst->idx, 1);
+ }
+}
/**
* ice_add_rss_cfg_sync - add an RSS configuration
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
- * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
- * @addl_hdrs: protocol header fields
- * @segs_cnt: packet segment count
+ * @cfg: configure parameters
*
* Assumption: lock has already been acquired for RSS list
*/
static int
-ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
- u32 addl_hdrs, u8 segs_cnt)
+ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle,
+ const struct ice_rss_hash_cfg *cfg)
{
const enum ice_block blk = ICE_BLK_RSS;
struct ice_flow_prof *prof = NULL;
struct ice_flow_seg_info *segs;
+ u8 segs_cnt;
int status;
- if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
- return -EINVAL;
+ segs_cnt = (cfg->hdr_type == ICE_RSS_OUTER_HEADERS) ?
+ ICE_FLOW_SEG_SINGLE : ICE_FLOW_SEG_MAX;
segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
if (!segs)
return -ENOMEM;
/* Construct the packet segment info from the hashed fields */
- status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
- addl_hdrs);
+ status = ice_flow_set_rss_seg_info(segs, segs_cnt, cfg);
if (status)
goto exit;
- /* Search for a flow profile that has matching headers, hash fields
- * and has the input VSI associated to it. If found, no further
+ /* Search for a flow profile that has matching headers, hash fields,
+ * symm and has the input VSI associated to it. If found, no further
* operations required and exit.
*/
prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
- vsi_handle,
+ cfg->symm, vsi_handle,
ICE_FLOW_FIND_PROF_CHK_FLDS |
+ ICE_FLOW_FIND_PROF_CHK_SYMM |
ICE_FLOW_FIND_PROF_CHK_VSI);
if (prof)
goto exit;
@@ -2087,7 +2265,8 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
* the protocol header and new hash field configuration.
*/
prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
- vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
+ cfg->symm, vsi_handle,
+ ICE_FLOW_FIND_PROF_CHK_VSI);
if (prof) {
status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
if (!status)
@@ -2103,11 +2282,12 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
}
}
- /* Search for a profile that has same match fields only. If this
- * exists then associate the VSI to this profile.
+ /* Search for a profile that has the same match fields and symmetric
+ * setting. If this exists then associate the VSI to this profile.
*/
prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
- vsi_handle,
+ cfg->symm, vsi_handle,
+ ICE_FLOW_FIND_PROF_CHK_SYMM |
ICE_FLOW_FIND_PROF_CHK_FLDS);
if (prof) {
status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
@@ -2116,17 +2296,14 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
goto exit;
}
- /* Create a new flow profile with generated profile and packet
- * segment information.
- */
+ /* Create a new flow profile with packet segment information. */
status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
- ICE_FLOW_GEN_PROFID(hashed_flds,
- segs[segs_cnt - 1].hdrs,
- segs_cnt),
- segs, segs_cnt, &prof);
+ segs, segs_cnt, cfg->symm, &prof);
if (status)
goto exit;
+ prof->symm = cfg->symm;
+ ice_rss_set_symm(hw, prof);
status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
/* If association to a new flow profile failed then this profile can
* be removed.
@@ -2146,30 +2323,43 @@ exit:
/**
* ice_add_rss_cfg - add an RSS configuration with specified hashed fields
* @hw: pointer to the hardware structure
- * @vsi_handle: software VSI handle
- * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
- * @addl_hdrs: protocol header fields
+ * @vsi: VSI to add the RSS configuration to
+ * @cfg: configure parameters
*
* This function will generate a flow profile based on fields associated with
* the input fields to hash on, the flow type and use the VSI number to add
* a flow entry to the profile.
*/
int
-ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
- u32 addl_hdrs)
+ice_add_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi,
+ const struct ice_rss_hash_cfg *cfg)
{
+ struct ice_rss_hash_cfg local_cfg;
+ u16 vsi_handle;
int status;
- if (hashed_flds == ICE_HASH_INVALID ||
- !ice_is_vsi_valid(hw, vsi_handle))
+ if (!vsi)
+ return -EINVAL;
+
+ vsi_handle = vsi->idx;
+ if (!ice_is_vsi_valid(hw, vsi_handle) ||
+ !cfg || cfg->hdr_type > ICE_RSS_ANY_HEADERS ||
+ cfg->hash_flds == ICE_HASH_INVALID)
return -EINVAL;
mutex_lock(&hw->rss_locks);
- status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
- ICE_RSS_OUTER_HEADERS);
- if (!status)
- status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
- addl_hdrs, ICE_RSS_INNER_HEADERS);
+ local_cfg = *cfg;
+ if (cfg->hdr_type < ICE_RSS_ANY_HEADERS) {
+ status = ice_add_rss_cfg_sync(hw, vsi_handle, &local_cfg);
+ } else {
+ local_cfg.hdr_type = ICE_RSS_OUTER_HEADERS;
+ status = ice_add_rss_cfg_sync(hw, vsi_handle, &local_cfg);
+ if (!status) {
+ local_cfg.hdr_type = ICE_RSS_INNER_HEADERS;
+ status = ice_add_rss_cfg_sync(hw, vsi_handle,
+ &local_cfg);
+ }
+ }
mutex_unlock(&hw->rss_locks);
return status;
@@ -2179,33 +2369,33 @@ ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
* ice_rem_rss_cfg_sync - remove an existing RSS configuration
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
- * @hashed_flds: Packet hash types (ICE_FLOW_HASH_*) to remove
- * @addl_hdrs: Protocol header fields within a packet segment
- * @segs_cnt: packet segment count
+ * @cfg: configure parameters
*
* Assumption: lock has already been acquired for RSS list
*/
static int
-ice_rem_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
- u32 addl_hdrs, u8 segs_cnt)
+ice_rem_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle,
+ const struct ice_rss_hash_cfg *cfg)
{
const enum ice_block blk = ICE_BLK_RSS;
struct ice_flow_seg_info *segs;
struct ice_flow_prof *prof;
+ u8 segs_cnt;
int status;
+ segs_cnt = (cfg->hdr_type == ICE_RSS_OUTER_HEADERS) ?
+ ICE_FLOW_SEG_SINGLE : ICE_FLOW_SEG_MAX;
segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
if (!segs)
return -ENOMEM;
/* Construct the packet segment info from the hashed fields */
- status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
- addl_hdrs);
+ status = ice_flow_set_rss_seg_info(segs, segs_cnt, cfg);
if (status)
goto out;
prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
- vsi_handle,
+ cfg->symm, vsi_handle,
ICE_FLOW_FIND_PROF_CHK_FLDS);
if (!prof) {
status = -ENOENT;
@@ -2233,31 +2423,39 @@ out:
* ice_rem_rss_cfg - remove an existing RSS config with matching hashed fields
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
- * @hashed_flds: Packet hash types (ICE_FLOW_HASH_*) to remove
- * @addl_hdrs: Protocol header fields within a packet segment
+ * @cfg: configure parameters
*
* This function will lookup the flow profile based on the input
* hash field bitmap, iterate through the profile entry list of
* that profile and find entry associated with input VSI to be
- * removed. Calls are made to underlying flow s which will APIs
+ * removed. Calls are made to underlying flow apis which will in
* turn build or update buffers for RSS XLT1 section.
*/
-int __maybe_unused
-ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
- u32 addl_hdrs)
+int
+ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle,
+ const struct ice_rss_hash_cfg *cfg)
{
+ struct ice_rss_hash_cfg local_cfg;
int status;
- if (hashed_flds == ICE_HASH_INVALID ||
- !ice_is_vsi_valid(hw, vsi_handle))
+ if (!ice_is_vsi_valid(hw, vsi_handle) ||
+ !cfg || cfg->hdr_type > ICE_RSS_ANY_HEADERS ||
+ cfg->hash_flds == ICE_HASH_INVALID)
return -EINVAL;
mutex_lock(&hw->rss_locks);
- status = ice_rem_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
- ICE_RSS_OUTER_HEADERS);
- if (!status)
- status = ice_rem_rss_cfg_sync(hw, vsi_handle, hashed_flds,
- addl_hdrs, ICE_RSS_INNER_HEADERS);
+ local_cfg = *cfg;
+ if (cfg->hdr_type < ICE_RSS_ANY_HEADERS) {
+ status = ice_rem_rss_cfg_sync(hw, vsi_handle, &local_cfg);
+ } else {
+ local_cfg.hdr_type = ICE_RSS_OUTER_HEADERS;
+ status = ice_rem_rss_cfg_sync(hw, vsi_handle, &local_cfg);
+ if (!status) {
+ local_cfg.hdr_type = ICE_RSS_INNER_HEADERS;
+ status = ice_rem_rss_cfg_sync(hw, vsi_handle,
+ &local_cfg);
+ }
+ }
mutex_unlock(&hw->rss_locks);
return status;
@@ -2298,18 +2496,24 @@ ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
/**
* ice_add_avf_rss_cfg - add an RSS configuration for AVF driver
* @hw: pointer to the hardware structure
- * @vsi_handle: software VSI handle
+ * @vsi: VF's VSI
* @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure
*
* This function will take the hash bitmap provided by the AVF driver via a
* message, convert it to ICE-compatible values, and configure RSS flow
* profiles.
*/
-int ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
+int ice_add_avf_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi, u64 avf_hash)
{
+ struct ice_rss_hash_cfg hcfg;
+ u16 vsi_handle;
int status = 0;
u64 hash_flds;
+ if (!vsi)
+ return -EINVAL;
+
+ vsi_handle = vsi->idx;
if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID ||
!ice_is_vsi_valid(hw, vsi_handle))
return -EINVAL;
@@ -2379,8 +2583,11 @@ int ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
if (rss_hash == ICE_HASH_INVALID)
return -EIO;
- status = ice_add_rss_cfg(hw, vsi_handle, rss_hash,
- ICE_FLOW_SEG_HDR_NONE);
+ hcfg.addl_hdrs = ICE_FLOW_SEG_HDR_NONE;
+ hcfg.hash_flds = rss_hash;
+ hcfg.hdr_type = ICE_RSS_ANY_HEADERS;
+ hcfg.symm = false;
+ status = ice_add_rss_cfg(hw, vsi, &hcfg);
if (status)
break;
}
@@ -2388,6 +2595,54 @@ int ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
return status;
}
+static bool rss_cfg_symm_valid(u64 hfld)
+{
+ return !((!!(hfld & ICE_FLOW_HASH_FLD_IPV4_SA) ^
+ !!(hfld & ICE_FLOW_HASH_FLD_IPV4_DA)) ||
+ (!!(hfld & ICE_FLOW_HASH_FLD_IPV6_SA) ^
+ !!(hfld & ICE_FLOW_HASH_FLD_IPV6_DA)) ||
+ (!!(hfld & ICE_FLOW_HASH_FLD_TCP_SRC_PORT) ^
+ !!(hfld & ICE_FLOW_HASH_FLD_TCP_DST_PORT)) ||
+ (!!(hfld & ICE_FLOW_HASH_FLD_UDP_SRC_PORT) ^
+ !!(hfld & ICE_FLOW_HASH_FLD_UDP_DST_PORT)) ||
+ (!!(hfld & ICE_FLOW_HASH_FLD_SCTP_SRC_PORT) ^
+ !!(hfld & ICE_FLOW_HASH_FLD_SCTP_DST_PORT)));
+}
+
+/**
+ * ice_set_rss_cfg_symm - set symmtery for all VSI's RSS configurations
+ * @hw: pointer to the hardware structure
+ * @vsi: VSI to set/unset Symmetric RSS
+ * @symm: TRUE to set Symmetric RSS hashing
+ */
+int ice_set_rss_cfg_symm(struct ice_hw *hw, struct ice_vsi *vsi, bool symm)
+{
+ struct ice_rss_hash_cfg local;
+ struct ice_rss_cfg *r, *tmp;
+ u16 vsi_handle = vsi->idx;
+ int status = 0;
+
+ if (!ice_is_vsi_valid(hw, vsi_handle))
+ return -EINVAL;
+
+ mutex_lock(&hw->rss_locks);
+ list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry) {
+ if (test_bit(vsi_handle, r->vsis) && r->hash.symm != symm) {
+ local = r->hash;
+ local.symm = symm;
+ if (symm && !rss_cfg_symm_valid(r->hash.hash_flds))
+ continue;
+
+ status = ice_add_rss_cfg_sync(hw, vsi_handle, &local);
+ if (status)
+ break;
+ }
+ }
+ mutex_unlock(&hw->rss_locks);
+
+ return status;
+}
+
/**
* ice_replay_rss_cfg - replay RSS configurations associated with VSI
* @hw: pointer to the hardware structure
@@ -2404,16 +2659,7 @@ int ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
mutex_lock(&hw->rss_locks);
list_for_each_entry(r, &hw->rss_list_head, l_entry) {
if (test_bit(vsi_handle, r->vsis)) {
- status = ice_add_rss_cfg_sync(hw, vsi_handle,
- r->hashed_flds,
- r->packet_hdr,
- ICE_RSS_OUTER_HEADERS);
- if (status)
- break;
- status = ice_add_rss_cfg_sync(hw, vsi_handle,
- r->hashed_flds,
- r->packet_hdr,
- ICE_RSS_INNER_HEADERS);
+ status = ice_add_rss_cfg_sync(hw, vsi_handle, &r->hash);
if (status)
break;
}
@@ -2428,11 +2674,12 @@ int ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
* @hw: pointer to the hardware structure
* @vsi_handle: software VSI handle
* @hdrs: protocol header type
+ * @symm: whether the RSS is symmetric (bool, output)
*
* This function will return the match fields of the first instance of flow
* profile having the given header types and containing input VSI
*/
-u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
+u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs, bool *symm)
{
u64 rss_hash = ICE_HASH_INVALID;
struct ice_rss_cfg *r;
@@ -2444,8 +2691,9 @@ u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
mutex_lock(&hw->rss_locks);
list_for_each_entry(r, &hw->rss_list_head, l_entry)
if (test_bit(vsi_handle, r->vsis) &&
- r->packet_hdr == hdrs) {
- rss_hash = r->hashed_flds;
+ r->hash.addl_hdrs == hdrs) {
+ rss_hash = r->hash.hash_flds;
+ *symm = r->hash.symm;
break;
}
mutex_unlock(&hw->rss_locks);
diff --git a/drivers/net/ethernet/intel/ice/ice_flow.h b/drivers/net/ethernet/intel/ice/ice_flow.h
index 96923ef0a5a8..ff82915ab497 100644
--- a/drivers/net/ethernet/intel/ice/ice_flow.h
+++ b/drivers/net/ethernet/intel/ice/ice_flow.h
@@ -34,6 +34,8 @@
#define ICE_HASH_TCP_IPV6 (ICE_FLOW_HASH_IPV6 | ICE_FLOW_HASH_TCP_PORT)
#define ICE_HASH_UDP_IPV4 (ICE_FLOW_HASH_IPV4 | ICE_FLOW_HASH_UDP_PORT)
#define ICE_HASH_UDP_IPV6 (ICE_FLOW_HASH_IPV6 | ICE_FLOW_HASH_UDP_PORT)
+#define ICE_HASH_SCTP_IPV4 (ICE_FLOW_HASH_IPV4 | ICE_FLOW_HASH_SCTP_PORT)
+#define ICE_HASH_SCTP_IPV6 (ICE_FLOW_HASH_IPV6 | ICE_FLOW_HASH_SCTP_PORT)
#define ICE_FLOW_HASH_GTP_TEID \
(BIT_ULL(ICE_FLOW_FIELD_IDX_GTPC_TEID))
@@ -227,6 +229,19 @@ enum ice_flow_field {
ICE_FLOW_FIELD_IDX_MAX
};
+#define ICE_FLOW_HASH_FLD_IPV4_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_SA)
+#define ICE_FLOW_HASH_FLD_IPV6_SA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_SA)
+#define ICE_FLOW_HASH_FLD_IPV4_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV4_DA)
+#define ICE_FLOW_HASH_FLD_IPV6_DA BIT_ULL(ICE_FLOW_FIELD_IDX_IPV6_DA)
+#define ICE_FLOW_HASH_FLD_TCP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_SRC_PORT)
+#define ICE_FLOW_HASH_FLD_TCP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_TCP_DST_PORT)
+#define ICE_FLOW_HASH_FLD_UDP_SRC_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_SRC_PORT)
+#define ICE_FLOW_HASH_FLD_UDP_DST_PORT BIT_ULL(ICE_FLOW_FIELD_IDX_UDP_DST_PORT)
+#define ICE_FLOW_HASH_FLD_SCTP_SRC_PORT \
+ BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT)
+#define ICE_FLOW_HASH_FLD_SCTP_DST_PORT \
+ BIT_ULL(ICE_FLOW_FIELD_IDX_SCTP_DST_PORT)
+
/* Flow headers and fields for AVF support */
enum ice_flow_avf_hdr_field {
/* Values 0 - 28 are reserved for future use */
@@ -279,6 +294,24 @@ enum ice_flow_avf_hdr_field {
BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \
BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP))
+enum ice_rss_cfg_hdr_type {
+ ICE_RSS_OUTER_HEADERS, /* take outer headers as inputset. */
+ ICE_RSS_INNER_HEADERS, /* take inner headers as inputset. */
+ /* take inner headers as inputset for packet with outer ipv4. */
+ ICE_RSS_INNER_HEADERS_W_OUTER_IPV4,
+ /* take inner headers as inputset for packet with outer ipv6. */
+ ICE_RSS_INNER_HEADERS_W_OUTER_IPV6,
+ /* take outer headers first then inner headers as inputset */
+ ICE_RSS_ANY_HEADERS
+};
+
+struct ice_rss_hash_cfg {
+ u32 addl_hdrs; /* protocol header fields */
+ u64 hash_flds; /* hash bit field (ICE_FLOW_HASH_*) to configure */
+ enum ice_rss_cfg_hdr_type hdr_type; /* to specify inner or outer */
+ bool symm; /* symmetric or asymmetric hash */
+};
+
enum ice_flow_dir {
ICE_FLOW_RX = 0x02,
};
@@ -289,8 +322,10 @@ enum ice_flow_priority {
ICE_FLOW_PRIO_HIGH
};
+#define ICE_FLOW_SEG_SINGLE 1
#define ICE_FLOW_SEG_MAX 2
#define ICE_FLOW_SEG_RAW_FLD_MAX 2
+#define ICE_FLOW_SW_FIELD_VECTOR_MAX 48
#define ICE_FLOW_FV_EXTRACT_SZ 2
#define ICE_FLOW_SET_HDRS(seg, val) ((seg)->hdrs |= (u32)(val))
@@ -372,20 +407,21 @@ struct ice_flow_prof {
/* software VSI handles referenced by this flow profile */
DECLARE_BITMAP(vsis, ICE_MAX_VSI);
+
+ bool symm; /* Symmetric Hash for RSS */
};
struct ice_rss_cfg {
struct list_head l_entry;
/* bitmap of VSIs added to the RSS entry */
DECLARE_BITMAP(vsis, ICE_MAX_VSI);
- u64 hashed_flds;
- u32 packet_hdr;
+ struct ice_rss_hash_cfg hash;
};
int
ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
- u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
- struct ice_flow_prof **prof);
+ struct ice_flow_seg_info *segs, u8 segs_cnt,
+ bool symm, struct ice_flow_prof **prof);
int ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id);
int
ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
@@ -401,13 +437,13 @@ ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
int ice_flow_rem_vsi_prof(struct ice_hw *hw, u16 vsi_handle, u64 prof_id);
void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle);
int ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle);
-int ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds);
+int ice_set_rss_cfg_symm(struct ice_hw *hw, struct ice_vsi *vsi, bool symm);
+int ice_add_avf_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi,
+ u64 hashed_flds);
int ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle);
-int
-ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
- u32 addl_hdrs);
-int
-ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
- u32 addl_hdrs);
-u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs);
+int ice_add_rss_cfg(struct ice_hw *hw, struct ice_vsi *vsi,
+ const struct ice_rss_hash_cfg *cfg);
+int ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle,
+ const struct ice_rss_hash_cfg *cfg);
+u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs, bool *symm);
#endif /* _ICE_FLOW_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.c b/drivers/net/ethernet/intel/ice/ice_fwlog.c
new file mode 100644
index 000000000000..92b5dac481cd
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_fwlog.c
@@ -0,0 +1,470 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2022, Intel Corporation. */
+
+#include <linux/vmalloc.h>
+#include "ice.h"
+#include "ice_common.h"
+#include "ice_fwlog.h"
+
+bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings)
+{
+ u16 head, tail;
+
+ head = rings->head;
+ tail = rings->tail;
+
+ if (head < tail && (tail - head == (rings->size - 1)))
+ return true;
+ else if (head > tail && (tail == (head - 1)))
+ return true;
+
+ return false;
+}
+
+bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings)
+{
+ return rings->head == rings->tail;
+}
+
+void ice_fwlog_ring_increment(u16 *item, u16 size)
+{
+ *item = (*item + 1) & (size - 1);
+}
+
+static int ice_fwlog_alloc_ring_buffs(struct ice_fwlog_ring *rings)
+{
+ int i, nr_bytes;
+ u8 *mem;
+
+ nr_bytes = rings->size * ICE_AQ_MAX_BUF_LEN;
+ mem = vzalloc(nr_bytes);
+ if (!mem)
+ return -ENOMEM;
+
+ for (i = 0; i < rings->size; i++) {
+ struct ice_fwlog_data *ring = &rings->rings[i];
+
+ ring->data_size = ICE_AQ_MAX_BUF_LEN;
+ ring->data = mem;
+ mem += ICE_AQ_MAX_BUF_LEN;
+ }
+
+ return 0;
+}
+
+static void ice_fwlog_free_ring_buffs(struct ice_fwlog_ring *rings)
+{
+ int i;
+
+ for (i = 0; i < rings->size; i++) {
+ struct ice_fwlog_data *ring = &rings->rings[i];
+
+ /* the first ring is the base memory for the whole range so
+ * free it
+ */
+ if (!i)
+ vfree(ring->data);
+
+ ring->data = NULL;
+ ring->data_size = 0;
+ }
+}
+
+#define ICE_FWLOG_INDEX_TO_BYTES(n) ((128 * 1024) << (n))
+/**
+ * ice_fwlog_realloc_rings - reallocate the FW log rings
+ * @hw: pointer to the HW structure
+ * @index: the new index to use to allocate memory for the log data
+ *
+ */
+void ice_fwlog_realloc_rings(struct ice_hw *hw, int index)
+{
+ struct ice_fwlog_ring ring;
+ int status, ring_size;
+
+ /* convert the number of bytes into a number of 4K buffers. externally
+ * the driver presents the interface to the FW log data as a number of
+ * bytes because that's easy for users to understand. internally the
+ * driver uses a ring of buffers because the driver doesn't know where
+ * the beginning and end of any line of log data is so the driver has
+ * to overwrite data as complete blocks. when the data is returned to
+ * the user the driver knows that the data is correct and the FW log
+ * can be correctly parsed by the tools
+ */
+ ring_size = ICE_FWLOG_INDEX_TO_BYTES(index) / ICE_AQ_MAX_BUF_LEN;
+ if (ring_size == hw->fwlog_ring.size)
+ return;
+
+ /* allocate space for the new rings and buffers then release the
+ * old rings and buffers. that way if we don't have enough
+ * memory then we at least have what we had before
+ */
+ ring.rings = kcalloc(ring_size, sizeof(*ring.rings), GFP_KERNEL);
+ if (!ring.rings)
+ return;
+
+ ring.size = ring_size;
+
+ status = ice_fwlog_alloc_ring_buffs(&ring);
+ if (status) {
+ dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n");
+ ice_fwlog_free_ring_buffs(&ring);
+ kfree(ring.rings);
+ return;
+ }
+
+ ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
+ kfree(hw->fwlog_ring.rings);
+
+ hw->fwlog_ring.rings = ring.rings;
+ hw->fwlog_ring.size = ring.size;
+ hw->fwlog_ring.index = index;
+ hw->fwlog_ring.head = 0;
+ hw->fwlog_ring.tail = 0;
+}
+
+/**
+ * ice_fwlog_init - Initialize FW logging configuration
+ * @hw: pointer to the HW structure
+ *
+ * This function should be called on driver initialization during
+ * ice_init_hw().
+ */
+int ice_fwlog_init(struct ice_hw *hw)
+{
+ /* only support fw log commands on PF 0 */
+ if (hw->bus.func)
+ return -EINVAL;
+
+ ice_fwlog_set_supported(hw);
+
+ if (ice_fwlog_supported(hw)) {
+ int status;
+
+ /* read the current config from the FW and store it */
+ status = ice_fwlog_get(hw, &hw->fwlog_cfg);
+ if (status)
+ return status;
+
+ hw->fwlog_ring.rings = kcalloc(ICE_FWLOG_RING_SIZE_DFLT,
+ sizeof(*hw->fwlog_ring.rings),
+ GFP_KERNEL);
+ if (!hw->fwlog_ring.rings) {
+ dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log rings\n");
+ return -ENOMEM;
+ }
+
+ hw->fwlog_ring.size = ICE_FWLOG_RING_SIZE_DFLT;
+ hw->fwlog_ring.index = ICE_FWLOG_RING_SIZE_INDEX_DFLT;
+
+ status = ice_fwlog_alloc_ring_buffs(&hw->fwlog_ring);
+ if (status) {
+ dev_warn(ice_hw_to_dev(hw), "Unable to allocate memory for FW log ring data buffers\n");
+ ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
+ kfree(hw->fwlog_ring.rings);
+ return status;
+ }
+
+ ice_debugfs_fwlog_init(hw->back);
+ } else {
+ dev_warn(ice_hw_to_dev(hw), "FW logging is not supported in this NVM image. Please update the NVM to get FW log support\n");
+ }
+
+ return 0;
+}
+
+/**
+ * ice_fwlog_deinit - unroll FW logging configuration
+ * @hw: pointer to the HW structure
+ *
+ * This function should be called in ice_deinit_hw().
+ */
+void ice_fwlog_deinit(struct ice_hw *hw)
+{
+ struct ice_pf *pf = hw->back;
+ int status;
+
+ /* only support fw log commands on PF 0 */
+ if (hw->bus.func)
+ return;
+
+ /* make sure FW logging is disabled to not put the FW in a weird state
+ * for the next driver load
+ */
+ hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_ARQ_ENA;
+ status = ice_fwlog_set(hw, &hw->fwlog_cfg);
+ if (status)
+ dev_warn(ice_hw_to_dev(hw), "Unable to turn off FW logging, status: %d\n",
+ status);
+
+ kfree(pf->ice_debugfs_pf_fwlog_modules);
+
+ pf->ice_debugfs_pf_fwlog_modules = NULL;
+
+ status = ice_fwlog_unregister(hw);
+ if (status)
+ dev_warn(ice_hw_to_dev(hw), "Unable to unregister FW logging, status: %d\n",
+ status);
+
+ if (hw->fwlog_ring.rings) {
+ ice_fwlog_free_ring_buffs(&hw->fwlog_ring);
+ kfree(hw->fwlog_ring.rings);
+ }
+}
+
+/**
+ * ice_fwlog_supported - Cached for whether FW supports FW logging or not
+ * @hw: pointer to the HW structure
+ *
+ * This will always return false if called before ice_init_hw(), so it must be
+ * called after ice_init_hw().
+ */
+bool ice_fwlog_supported(struct ice_hw *hw)
+{
+ return hw->fwlog_supported;
+}
+
+/**
+ * ice_aq_fwlog_set - Set FW logging configuration AQ command (0xFF30)
+ * @hw: pointer to the HW structure
+ * @entries: entries to configure
+ * @num_entries: number of @entries
+ * @options: options from ice_fwlog_cfg->options structure
+ * @log_resolution: logging resolution
+ */
+static int
+ice_aq_fwlog_set(struct ice_hw *hw, struct ice_fwlog_module_entry *entries,
+ u16 num_entries, u16 options, u16 log_resolution)
+{
+ struct ice_aqc_fw_log_cfg_resp *fw_modules;
+ struct ice_aqc_fw_log *cmd;
+ struct ice_aq_desc desc;
+ int status;
+ int i;
+
+ fw_modules = kcalloc(num_entries, sizeof(*fw_modules), GFP_KERNEL);
+ if (!fw_modules)
+ return -ENOMEM;
+
+ for (i = 0; i < num_entries; i++) {
+ fw_modules[i].module_identifier =
+ cpu_to_le16(entries[i].module_id);
+ fw_modules[i].log_level = entries[i].log_level;
+ }
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_config);
+ desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
+
+ cmd = &desc.params.fw_log;
+
+ cmd->cmd_flags = ICE_AQC_FW_LOG_CONF_SET_VALID;
+ cmd->ops.cfg.log_resolution = cpu_to_le16(log_resolution);
+ cmd->ops.cfg.mdl_cnt = cpu_to_le16(num_entries);
+
+ if (options & ICE_FWLOG_OPTION_ARQ_ENA)
+ cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_AQ_EN;
+ if (options & ICE_FWLOG_OPTION_UART_ENA)
+ cmd->cmd_flags |= ICE_AQC_FW_LOG_CONF_UART_EN;
+
+ status = ice_aq_send_cmd(hw, &desc, fw_modules,
+ sizeof(*fw_modules) * num_entries,
+ NULL);
+
+ kfree(fw_modules);
+
+ return status;
+}
+
+/**
+ * ice_fwlog_set - Set the firmware logging settings
+ * @hw: pointer to the HW structure
+ * @cfg: config used to set firmware logging
+ *
+ * This function should be called whenever the driver needs to set the firmware
+ * logging configuration. It can be called on initialization, reset, or during
+ * runtime.
+ *
+ * If the PF wishes to receive FW logging then it must register via
+ * ice_fwlog_register. Note, that ice_fwlog_register does not need to be called
+ * for init.
+ */
+int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
+{
+ if (!ice_fwlog_supported(hw))
+ return -EOPNOTSUPP;
+
+ return ice_aq_fwlog_set(hw, cfg->module_entries,
+ ICE_AQC_FW_LOG_ID_MAX, cfg->options,
+ cfg->log_resolution);
+}
+
+/**
+ * ice_aq_fwlog_get - Get the current firmware logging configuration (0xFF32)
+ * @hw: pointer to the HW structure
+ * @cfg: firmware logging configuration to populate
+ */
+static int ice_aq_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
+{
+ struct ice_aqc_fw_log_cfg_resp *fw_modules;
+ struct ice_aqc_fw_log *cmd;
+ struct ice_aq_desc desc;
+ u16 module_id_cnt;
+ int status;
+ void *buf;
+ int i;
+
+ memset(cfg, 0, sizeof(*cfg));
+
+ buf = kzalloc(ICE_AQ_MAX_BUF_LEN, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_query);
+ cmd = &desc.params.fw_log;
+
+ cmd->cmd_flags = ICE_AQC_FW_LOG_AQ_QUERY;
+
+ status = ice_aq_send_cmd(hw, &desc, buf, ICE_AQ_MAX_BUF_LEN, NULL);
+ if (status) {
+ ice_debug(hw, ICE_DBG_FW_LOG, "Failed to get FW log configuration\n");
+ goto status_out;
+ }
+
+ module_id_cnt = le16_to_cpu(cmd->ops.cfg.mdl_cnt);
+ if (module_id_cnt < ICE_AQC_FW_LOG_ID_MAX) {
+ ice_debug(hw, ICE_DBG_FW_LOG, "FW returned less than the expected number of FW log module IDs\n");
+ } else if (module_id_cnt > ICE_AQC_FW_LOG_ID_MAX) {
+ ice_debug(hw, ICE_DBG_FW_LOG, "FW returned more than expected number of FW log module IDs, setting module_id_cnt to software expected max %u\n",
+ ICE_AQC_FW_LOG_ID_MAX);
+ module_id_cnt = ICE_AQC_FW_LOG_ID_MAX;
+ }
+
+ cfg->log_resolution = le16_to_cpu(cmd->ops.cfg.log_resolution);
+ if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_AQ_EN)
+ cfg->options |= ICE_FWLOG_OPTION_ARQ_ENA;
+ if (cmd->cmd_flags & ICE_AQC_FW_LOG_CONF_UART_EN)
+ cfg->options |= ICE_FWLOG_OPTION_UART_ENA;
+ if (cmd->cmd_flags & ICE_AQC_FW_LOG_QUERY_REGISTERED)
+ cfg->options |= ICE_FWLOG_OPTION_IS_REGISTERED;
+
+ fw_modules = (struct ice_aqc_fw_log_cfg_resp *)buf;
+
+ for (i = 0; i < module_id_cnt; i++) {
+ struct ice_aqc_fw_log_cfg_resp *fw_module = &fw_modules[i];
+
+ cfg->module_entries[i].module_id =
+ le16_to_cpu(fw_module->module_identifier);
+ cfg->module_entries[i].log_level = fw_module->log_level;
+ }
+
+status_out:
+ kfree(buf);
+ return status;
+}
+
+/**
+ * ice_fwlog_get - Get the firmware logging settings
+ * @hw: pointer to the HW structure
+ * @cfg: config to populate based on current firmware logging settings
+ */
+int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg)
+{
+ if (!ice_fwlog_supported(hw))
+ return -EOPNOTSUPP;
+
+ return ice_aq_fwlog_get(hw, cfg);
+}
+
+/**
+ * ice_aq_fwlog_register - Register PF for firmware logging events (0xFF31)
+ * @hw: pointer to the HW structure
+ * @reg: true to register and false to unregister
+ */
+static int ice_aq_fwlog_register(struct ice_hw *hw, bool reg)
+{
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_fw_logs_register);
+
+ if (reg)
+ desc.params.fw_log.cmd_flags = ICE_AQC_FW_LOG_AQ_REGISTER;
+
+ return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+}
+
+/**
+ * ice_fwlog_register - Register the PF for firmware logging
+ * @hw: pointer to the HW structure
+ *
+ * After this call the PF will start to receive firmware logging based on the
+ * configuration set in ice_fwlog_set.
+ */
+int ice_fwlog_register(struct ice_hw *hw)
+{
+ int status;
+
+ if (!ice_fwlog_supported(hw))
+ return -EOPNOTSUPP;
+
+ status = ice_aq_fwlog_register(hw, true);
+ if (status)
+ ice_debug(hw, ICE_DBG_FW_LOG, "Failed to register for firmware logging events over ARQ\n");
+ else
+ hw->fwlog_cfg.options |= ICE_FWLOG_OPTION_IS_REGISTERED;
+
+ return status;
+}
+
+/**
+ * ice_fwlog_unregister - Unregister the PF from firmware logging
+ * @hw: pointer to the HW structure
+ */
+int ice_fwlog_unregister(struct ice_hw *hw)
+{
+ int status;
+
+ if (!ice_fwlog_supported(hw))
+ return -EOPNOTSUPP;
+
+ status = ice_aq_fwlog_register(hw, false);
+ if (status)
+ ice_debug(hw, ICE_DBG_FW_LOG, "Failed to unregister from firmware logging events over ARQ\n");
+ else
+ hw->fwlog_cfg.options &= ~ICE_FWLOG_OPTION_IS_REGISTERED;
+
+ return status;
+}
+
+/**
+ * ice_fwlog_set_supported - Set if FW logging is supported by FW
+ * @hw: pointer to the HW struct
+ *
+ * If FW returns success to the ice_aq_fwlog_get call then it supports FW
+ * logging, else it doesn't. Set the fwlog_supported flag accordingly.
+ *
+ * This function is only meant to be called during driver init to determine if
+ * the FW support FW logging.
+ */
+void ice_fwlog_set_supported(struct ice_hw *hw)
+{
+ struct ice_fwlog_cfg *cfg;
+ int status;
+
+ hw->fwlog_supported = false;
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return;
+
+ /* don't call ice_fwlog_get() because that would check to see if FW
+ * logging is supported which is what the driver is determining now
+ */
+ status = ice_aq_fwlog_get(hw, cfg);
+ if (status)
+ ice_debug(hw, ICE_DBG_FW_LOG, "ice_aq_fwlog_get failed, FW logging is not supported on this version of FW, status %d\n",
+ status);
+ else
+ hw->fwlog_supported = true;
+
+ kfree(cfg);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_fwlog.h b/drivers/net/ethernet/intel/ice/ice_fwlog.h
new file mode 100644
index 000000000000..287e71fa4b86
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_fwlog.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2022, Intel Corporation. */
+
+#ifndef _ICE_FWLOG_H_
+#define _ICE_FWLOG_H_
+#include "ice_adminq_cmd.h"
+
+struct ice_hw;
+
+/* Only a single log level should be set and all log levels under the set value
+ * are enabled, e.g. if log level is set to ICE_FW_LOG_LEVEL_VERBOSE, then all
+ * other log levels are included (except ICE_FW_LOG_LEVEL_NONE)
+ */
+enum ice_fwlog_level {
+ ICE_FWLOG_LEVEL_NONE = 0,
+ ICE_FWLOG_LEVEL_ERROR = 1,
+ ICE_FWLOG_LEVEL_WARNING = 2,
+ ICE_FWLOG_LEVEL_NORMAL = 3,
+ ICE_FWLOG_LEVEL_VERBOSE = 4,
+ ICE_FWLOG_LEVEL_INVALID, /* all values >= this entry are invalid */
+};
+
+struct ice_fwlog_module_entry {
+ /* module ID for the corresponding firmware logging event */
+ u16 module_id;
+ /* verbosity level for the module_id */
+ u8 log_level;
+};
+
+struct ice_fwlog_cfg {
+ /* list of modules for configuring log level */
+ struct ice_fwlog_module_entry module_entries[ICE_AQC_FW_LOG_ID_MAX];
+ /* options used to configure firmware logging */
+ u16 options;
+#define ICE_FWLOG_OPTION_ARQ_ENA BIT(0)
+#define ICE_FWLOG_OPTION_UART_ENA BIT(1)
+ /* set before calling ice_fwlog_init() so the PF registers for firmware
+ * logging on initialization
+ */
+#define ICE_FWLOG_OPTION_REGISTER_ON_INIT BIT(2)
+ /* set in the ice_fwlog_get() response if the PF is registered for FW
+ * logging events over ARQ
+ */
+#define ICE_FWLOG_OPTION_IS_REGISTERED BIT(3)
+
+ /* minimum number of log events sent per Admin Receive Queue event */
+ u16 log_resolution;
+};
+
+struct ice_fwlog_data {
+ u16 data_size;
+ u8 *data;
+};
+
+struct ice_fwlog_ring {
+ struct ice_fwlog_data *rings;
+ u16 index;
+ u16 size;
+ u16 head;
+ u16 tail;
+};
+
+#define ICE_FWLOG_RING_SIZE_INDEX_DFLT 3
+#define ICE_FWLOG_RING_SIZE_DFLT 256
+#define ICE_FWLOG_RING_SIZE_MAX 512
+
+bool ice_fwlog_ring_full(struct ice_fwlog_ring *rings);
+bool ice_fwlog_ring_empty(struct ice_fwlog_ring *rings);
+void ice_fwlog_ring_increment(u16 *item, u16 size);
+void ice_fwlog_set_supported(struct ice_hw *hw);
+bool ice_fwlog_supported(struct ice_hw *hw);
+int ice_fwlog_init(struct ice_hw *hw);
+void ice_fwlog_deinit(struct ice_hw *hw);
+int ice_fwlog_set(struct ice_hw *hw, struct ice_fwlog_cfg *cfg);
+int ice_fwlog_get(struct ice_hw *hw, struct ice_fwlog_cfg *cfg);
+int ice_fwlog_register(struct ice_hw *hw);
+int ice_fwlog_unregister(struct ice_hw *hw);
+void ice_fwlog_realloc_rings(struct ice_hw *hw, int index);
+#endif /* _ICE_FWLOG_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
index 86936b758ade..cfac1d432c15 100644
--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h
@@ -200,6 +200,8 @@
#define GLINT_VECT2FUNC_PF_NUM_M ICE_M(0x7, 12)
#define GLINT_VECT2FUNC_IS_PF_S 16
#define GLINT_VECT2FUNC_IS_PF_M BIT(16)
+#define PFINT_ALLOC 0x001D2600
+#define PFINT_ALLOC_FIRST ICE_M(0x7FF, 0)
#define PFINT_FW_CTL 0x0016C800
#define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
#define PFINT_FW_CTL_ITR_INDX_S 11
@@ -404,6 +406,10 @@
#define GLQF_HMASK_SEL(_i) (0x00410000 + ((_i) * 4))
#define GLQF_HMASK_SEL_MAX_INDEX 127
#define GLQF_HMASK_SEL_MASK_SEL_S 0
+#define GLQF_HSYMM(_i, _j) (0x0040F000 + ((_i) * 4 + (_j) * 512))
+#define GLQF_HSYMM_REG_SIZE 4
+#define GLQF_HSYMM_REG_PER_PROF 6
+#define GLQF_HSYMM_ENABLE_BIT BIT(7)
#define E800_PFQF_FD_CNT_FD_GCNT_M GENMASK(14, 0)
#define E830_PFQF_FD_CNT_FD_GCNT_M GENMASK(15, 0)
#define E800_PFQF_FD_CNT_FD_BCNT_M GENMASK(30, 16)
diff --git a/drivers/net/ethernet/intel/ice/ice_hwmon.c b/drivers/net/ethernet/intel/ice/ice_hwmon.c
new file mode 100644
index 000000000000..e4c2c1bff6c0
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_hwmon.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2023, Intel Corporation. */
+
+#include "ice.h"
+#include "ice_hwmon.h"
+#include "ice_adminq_cmd.h"
+
+#include <linux/hwmon.h>
+
+#define TEMP_FROM_REG(reg) ((reg) * 1000)
+
+static const struct hwmon_channel_info *ice_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT | HWMON_T_MAX |
+ HWMON_T_CRIT | HWMON_T_EMERGENCY),
+ NULL
+};
+
+static int ice_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct ice_aqc_get_sensor_reading_resp resp;
+ struct ice_pf *pf = dev_get_drvdata(dev);
+ int ret;
+
+ if (type != hwmon_temp)
+ return -EOPNOTSUPP;
+
+ ret = ice_aq_get_sensor_reading(&pf->hw, &resp);
+ if (ret) {
+ dev_warn_ratelimited(dev,
+ "%s HW read failure (%d)\n",
+ __func__,
+ ret);
+ return ret;
+ }
+
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = TEMP_FROM_REG(resp.data.s0f0.temp);
+ break;
+ case hwmon_temp_max:
+ *val = TEMP_FROM_REG(resp.data.s0f0.temp_warning_threshold);
+ break;
+ case hwmon_temp_crit:
+ *val = TEMP_FROM_REG(resp.data.s0f0.temp_critical_threshold);
+ break;
+ case hwmon_temp_emergency:
+ *val = TEMP_FROM_REG(resp.data.s0f0.temp_fatal_threshold);
+ break;
+ default:
+ dev_dbg(dev, "%s unsupported attribute (%d)\n",
+ __func__, attr);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static umode_t ice_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ if (type != hwmon_temp)
+ return 0;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ case hwmon_temp_crit:
+ case hwmon_temp_max:
+ case hwmon_temp_emergency:
+ return 0444;
+ }
+
+ return 0;
+}
+
+static const struct hwmon_ops ice_hwmon_ops = {
+ .is_visible = ice_hwmon_is_visible,
+ .read = ice_hwmon_read
+};
+
+static const struct hwmon_chip_info ice_chip_info = {
+ .ops = &ice_hwmon_ops,
+ .info = ice_hwmon_info
+};
+
+static bool ice_is_internal_reading_supported(struct ice_pf *pf)
+{
+ /* Only the first PF will report temperature for a chip.
+ * Note that internal temp reading is not supported
+ * for older FW (< v4.30).
+ */
+ if (pf->hw.pf_id)
+ return false;
+
+ unsigned long sensors = pf->hw.dev_caps.supported_sensors;
+
+ return _test_bit(ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT, &sensors);
+};
+
+void ice_hwmon_init(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct device *hdev;
+
+ if (!ice_is_internal_reading_supported(pf))
+ return;
+
+ hdev = hwmon_device_register_with_info(dev, "ice", pf, &ice_chip_info,
+ NULL);
+ if (IS_ERR(hdev)) {
+ dev_warn(dev,
+ "hwmon_device_register_with_info returns error (%ld)",
+ PTR_ERR(hdev));
+ return;
+ }
+ pf->hwmon_dev = hdev;
+}
+
+void ice_hwmon_exit(struct ice_pf *pf)
+{
+ if (!pf->hwmon_dev)
+ return;
+ hwmon_device_unregister(pf->hwmon_dev);
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_hwmon.h b/drivers/net/ethernet/intel/ice/ice_hwmon.h
new file mode 100644
index 000000000000..d66d40354f5a
--- /dev/null
+++ b/drivers/net/ethernet/intel/ice/ice_hwmon.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2023, Intel Corporation. */
+
+#ifndef _ICE_HWMON_H_
+#define _ICE_HWMON_H_
+
+#ifdef CONFIG_ICE_HWMON
+void ice_hwmon_init(struct ice_pf *pf);
+void ice_hwmon_exit(struct ice_pf *pf);
+#else /* CONFIG_ICE_HWMON */
+static inline void ice_hwmon_init(struct ice_pf *pf) { }
+static inline void ice_hwmon_exit(struct ice_pf *pf) { }
+#endif /* CONFIG_ICE_HWMON */
+
+#endif /* _ICE_HWMON_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
index b47cd43ae871..467372d541d2 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.c
+++ b/drivers/net/ethernet/intel/ice/ice_lag.c
@@ -152,6 +152,27 @@ ice_lag_find_hw_by_lport(struct ice_lag *lag, u8 lport)
}
/**
+ * ice_pkg_has_lport_extract - check if lport extraction supported
+ * @hw: HW struct
+ */
+static bool ice_pkg_has_lport_extract(struct ice_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->blk[ICE_BLK_SW].es.count; i++) {
+ u16 offset;
+ u8 fv_prot;
+
+ ice_find_prot_off(hw, ICE_BLK_SW, ICE_SW_DEFAULT_PROFILE, i,
+ &fv_prot, &offset);
+ if (fv_prot == ICE_FV_PROT_MDID &&
+ offset == ICE_LP_EXT_BUF_OFFSET)
+ return true;
+ }
+ return false;
+}
+
+/**
* ice_lag_find_primary - returns pointer to primary interfaces lag struct
* @lag: local interfaces lag struct
*/
@@ -208,8 +229,7 @@ ice_lag_cfg_fltr(struct ice_lag *lag, u32 act, u16 recipe_id, u16 *rule_idx,
eth_hdr = s_rule->hdr_data;
ice_fill_eth_hdr(eth_hdr);
- act |= (vsi_num << ICE_SINGLE_ACT_VSI_ID_S) &
- ICE_SINGLE_ACT_VSI_ID_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, vsi_num);
s_rule->hdr.type = cpu_to_le16(ICE_AQC_SW_RULES_T_LKUP_RX);
s_rule->recipe_id = cpu_to_le16(recipe_id);
@@ -754,9 +774,7 @@ ice_lag_cfg_cp_fltr(struct ice_lag *lag, bool add)
s_rule->act = cpu_to_le32(ICE_FWD_TO_VSI |
ICE_SINGLE_ACT_LAN_ENABLE |
ICE_SINGLE_ACT_VALID_BIT |
- ((vsi->vsi_num <<
- ICE_SINGLE_ACT_VSI_ID_S) &
- ICE_SINGLE_ACT_VSI_ID_M));
+ FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M, vsi->vsi_num));
s_rule->hdr_len = cpu_to_le16(ICE_LAG_SRIOV_TRAIN_PKT_LEN);
memcpy(s_rule->hdr_data, lacp_train_pkt, LACP_TRAIN_PKT_LEN);
opc = ice_aqc_opc_add_sw_rules;
@@ -1209,7 +1227,7 @@ static void ice_lag_del_prune_list(struct ice_lag *lag, struct ice_pf *event_pf)
}
/**
- * ice_lag_init_feature_support_flag - Check for NVM support for LAG
+ * ice_lag_init_feature_support_flag - Check for package and NVM support for LAG
* @pf: PF struct
*/
static void ice_lag_init_feature_support_flag(struct ice_pf *pf)
@@ -1222,7 +1240,7 @@ static void ice_lag_init_feature_support_flag(struct ice_pf *pf)
else
ice_clear_feature_support(pf, ICE_F_ROCE_LAG);
- if (caps->sriov_lag)
+ if (caps->sriov_lag && ice_pkg_has_lport_extract(&pf->hw))
ice_set_feature_support(pf, ICE_F_SRIOV_LAG);
else
ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
diff --git a/drivers/net/ethernet/intel/ice/ice_lag.h b/drivers/net/ethernet/intel/ice/ice_lag.h
index ede833dfa658..183b38792ef2 100644
--- a/drivers/net/ethernet/intel/ice/ice_lag.h
+++ b/drivers/net/ethernet/intel/ice/ice_lag.h
@@ -17,6 +17,9 @@ enum ice_lag_role {
#define ICE_LAG_INVALID_PORT 0xFF
#define ICE_LAG_RESET_RETRIES 5
+#define ICE_SW_DEFAULT_PROFILE 0
+#define ICE_FV_PROT_MDID 255
+#define ICE_LP_EXT_BUF_OFFSET 32
struct ice_pf;
struct ice_vf;
diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
index 89f986a75cc8..d384ddfcb83e 100644
--- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
+++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h
@@ -673,6 +673,212 @@ struct ice_tlan_ctx {
* Use the enum ice_rx_l2_ptype to decode the packet type
* ENDIF
*/
+#define ICE_PTYPES \
+ /* L2 Packet types */ \
+ ICE_PTT_UNUSED_ENTRY(0), \
+ ICE_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), \
+ ICE_PTT_UNUSED_ENTRY(2), \
+ ICE_PTT_UNUSED_ENTRY(3), \
+ ICE_PTT_UNUSED_ENTRY(4), \
+ ICE_PTT_UNUSED_ENTRY(5), \
+ ICE_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), \
+ ICE_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), \
+ ICE_PTT_UNUSED_ENTRY(8), \
+ ICE_PTT_UNUSED_ENTRY(9), \
+ ICE_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), \
+ ICE_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), \
+ ICE_PTT_UNUSED_ENTRY(12), \
+ ICE_PTT_UNUSED_ENTRY(13), \
+ ICE_PTT_UNUSED_ENTRY(14), \
+ ICE_PTT_UNUSED_ENTRY(15), \
+ ICE_PTT_UNUSED_ENTRY(16), \
+ ICE_PTT_UNUSED_ENTRY(17), \
+ ICE_PTT_UNUSED_ENTRY(18), \
+ ICE_PTT_UNUSED_ENTRY(19), \
+ ICE_PTT_UNUSED_ENTRY(20), \
+ ICE_PTT_UNUSED_ENTRY(21), \
+ \
+ /* Non Tunneled IPv4 */ \
+ ICE_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), \
+ ICE_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), \
+ ICE_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(25), \
+ ICE_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), \
+ ICE_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), \
+ ICE_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> IPv4 */ \
+ ICE_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(32), \
+ ICE_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> IPv6 */ \
+ ICE_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(39), \
+ ICE_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> GRE/NAT */ \
+ ICE_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), \
+ \
+ /* IPv4 --> GRE/NAT --> IPv4 */ \
+ ICE_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(47), \
+ ICE_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> GRE/NAT --> IPv6 */ \
+ ICE_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(54), \
+ ICE_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> GRE/NAT --> MAC */ \
+ ICE_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), \
+ \
+ /* IPv4 --> GRE/NAT --> MAC --> IPv4 */ \
+ ICE_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(62), \
+ ICE_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> GRE/NAT -> MAC --> IPv6 */ \
+ ICE_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(69), \
+ ICE_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 --> GRE/NAT --> MAC/VLAN */ \
+ ICE_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), \
+ \
+ /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ \
+ ICE_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(77), \
+ ICE_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ \
+ ICE_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(84), \
+ ICE_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* Non Tunneled IPv6 */ \
+ ICE_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), \
+ ICE_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), \
+ ICE_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(91), \
+ ICE_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), \
+ ICE_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), \
+ ICE_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> IPv4 */ \
+ ICE_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(98), \
+ ICE_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> IPv6 */ \
+ ICE_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(105), \
+ ICE_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> GRE/NAT */ \
+ ICE_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), \
+ \
+ /* IPv6 --> GRE/NAT -> IPv4 */ \
+ ICE_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(113), \
+ ICE_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> GRE/NAT -> IPv6 */ \
+ ICE_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(120), \
+ ICE_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> GRE/NAT -> MAC */ \
+ ICE_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), \
+ \
+ /* IPv6 --> GRE/NAT -> MAC -> IPv4 */ \
+ ICE_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(128), \
+ ICE_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> GRE/NAT -> MAC -> IPv6 */ \
+ ICE_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(135), \
+ ICE_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> GRE/NAT -> MAC/VLAN */ \
+ ICE_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), \
+ \
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ \
+ ICE_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), \
+ ICE_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), \
+ ICE_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(143), \
+ ICE_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), \
+ ICE_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), \
+ ICE_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), \
+ \
+ /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ \
+ ICE_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), \
+ ICE_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), \
+ ICE_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), \
+ ICE_PTT_UNUSED_ENTRY(150), \
+ ICE_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), \
+ ICE_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), \
+ ICE_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+#define ICE_NUM_DEFINED_PTYPES 154
/* macro to make the table lines short, use explicit indexing with [PTYPE] */
#define ICE_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
@@ -695,212 +901,10 @@ struct ice_tlan_ctx {
/* Lookup table mapping in the 10-bit HW PTYPE to the bit field for decoding */
static const struct ice_rx_ptype_decoded ice_ptype_lkup[BIT(10)] = {
- /* L2 Packet types */
- ICE_PTT_UNUSED_ENTRY(0),
- ICE_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
- ICE_PTT_UNUSED_ENTRY(2),
- ICE_PTT_UNUSED_ENTRY(3),
- ICE_PTT_UNUSED_ENTRY(4),
- ICE_PTT_UNUSED_ENTRY(5),
- ICE_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
- ICE_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
- ICE_PTT_UNUSED_ENTRY(8),
- ICE_PTT_UNUSED_ENTRY(9),
- ICE_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
- ICE_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
- ICE_PTT_UNUSED_ENTRY(12),
- ICE_PTT_UNUSED_ENTRY(13),
- ICE_PTT_UNUSED_ENTRY(14),
- ICE_PTT_UNUSED_ENTRY(15),
- ICE_PTT_UNUSED_ENTRY(16),
- ICE_PTT_UNUSED_ENTRY(17),
- ICE_PTT_UNUSED_ENTRY(18),
- ICE_PTT_UNUSED_ENTRY(19),
- ICE_PTT_UNUSED_ENTRY(20),
- ICE_PTT_UNUSED_ENTRY(21),
-
- /* Non Tunneled IPv4 */
- ICE_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
- ICE_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
- ICE_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(25),
- ICE_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4),
- ICE_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
- ICE_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
-
- /* IPv4 --> IPv4 */
- ICE_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
- ICE_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
- ICE_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(32),
- ICE_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
- ICE_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 --> IPv6 */
- ICE_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
- ICE_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
- ICE_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(39),
- ICE_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
- ICE_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT */
- ICE_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
-
- /* IPv4 --> GRE/NAT --> IPv4 */
- ICE_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
- ICE_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
- ICE_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(47),
- ICE_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
- ICE_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT --> IPv6 */
- ICE_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
- ICE_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
- ICE_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(54),
- ICE_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
- ICE_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT --> MAC */
- ICE_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
-
- /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
- ICE_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
- ICE_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
- ICE_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(62),
- ICE_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
- ICE_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
- ICE_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
- ICE_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
- ICE_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(69),
- ICE_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
- ICE_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
-
- /* IPv4 --> GRE/NAT --> MAC/VLAN */
- ICE_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
-
- /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
- ICE_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
- ICE_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
- ICE_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(77),
- ICE_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
- ICE_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
-
- /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
- ICE_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
- ICE_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
- ICE_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(84),
- ICE_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
- ICE_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
-
- /* Non Tunneled IPv6 */
- ICE_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
- ICE_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
- ICE_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(91),
- ICE_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4),
- ICE_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
- ICE_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
-
- /* IPv6 --> IPv4 */
- ICE_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
- ICE_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
- ICE_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(98),
- ICE_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4),
- ICE_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> IPv6 */
- ICE_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
- ICE_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
- ICE_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(105),
- ICE_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4),
- ICE_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT */
- ICE_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
-
- /* IPv6 --> GRE/NAT -> IPv4 */
- ICE_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
- ICE_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
- ICE_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(113),
- ICE_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4),
- ICE_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> IPv6 */
- ICE_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
- ICE_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
- ICE_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(120),
- ICE_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4),
- ICE_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC */
- ICE_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
-
- /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
- ICE_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
- ICE_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
- ICE_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(128),
- ICE_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4),
- ICE_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
- ICE_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
- ICE_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
- ICE_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(135),
- ICE_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4),
- ICE_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC/VLAN */
- ICE_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
-
- /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
- ICE_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
- ICE_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
- ICE_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(143),
- ICE_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4),
- ICE_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
- ICE_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
-
- /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
- ICE_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
- ICE_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
- ICE_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4),
- ICE_PTT_UNUSED_ENTRY(150),
- ICE_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4),
- ICE_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
- ICE_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+ ICE_PTYPES
/* unused entries */
- [154 ... 1023] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ [ICE_NUM_DEFINED_PTYPES ... 1023] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
static inline struct ice_rx_ptype_decoded ice_decode_rx_desc_ptype(u16 ptype)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 1bad6e17f9be..fc23dbe302b4 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -212,11 +212,18 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
vsi->alloc_txq));
break;
case ICE_VSI_SWITCHDEV_CTRL:
- /* The number of queues for ctrl VSI is equal to number of VFs.
+ /* The number of queues for ctrl VSI is equal to number of PRs
* Each ring is associated to the corresponding VF_PR netdev.
+ * Tx and Rx rings are always equal
*/
- vsi->alloc_txq = ice_get_num_vfs(pf);
- vsi->alloc_rxq = vsi->alloc_txq;
+ if (vsi->req_txq && vsi->req_rxq) {
+ vsi->alloc_txq = vsi->req_txq;
+ vsi->alloc_rxq = vsi->req_rxq;
+ } else {
+ vsi->alloc_txq = 1;
+ vsi->alloc_rxq = 1;
+ }
+
vsi->num_q_vectors = 1;
break;
case ICE_VSI_VF:
@@ -519,16 +526,14 @@ static irqreturn_t ice_eswitch_msix_clean_rings(int __always_unused irq, void *d
{
struct ice_q_vector *q_vector = (struct ice_q_vector *)data;
struct ice_pf *pf = q_vector->vsi->back;
- struct ice_vf *vf;
- unsigned int bkt;
+ struct ice_repr *repr;
+ unsigned long id;
if (!q_vector->tx.tx_ring && !q_vector->rx.rx_ring)
return IRQ_HANDLED;
- rcu_read_lock();
- ice_for_each_vf_rcu(pf, bkt, vf)
- napi_schedule(&vf->repr->q_vector->napi);
- rcu_read_unlock();
+ xa_for_each(&pf->eswitch.reprs, id, repr)
+ napi_schedule(&repr->q_vector->napi);
return IRQ_HANDLED;
}
@@ -969,9 +974,8 @@ static void ice_set_dflt_vsi_ctx(struct ice_hw *hw, struct ice_vsi_ctx *ctxt)
/* Traffic from VSI can be sent to LAN */
ctxt->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA;
/* allow all untagged/tagged packets by default on Tx */
- ctxt->info.inner_vlan_flags = ((ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL &
- ICE_AQ_VSI_INNER_VLAN_TX_MODE_M) >>
- ICE_AQ_VSI_INNER_VLAN_TX_MODE_S);
+ ctxt->info.inner_vlan_flags = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_TX_MODE_M,
+ ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL);
/* SVM - by default bits 3 and 4 in inner_vlan_flags are 0's which
* results in legacy behavior (show VLAN, DEI, and UP) in descriptor.
*
@@ -979,15 +983,14 @@ static void ice_set_dflt_vsi_ctx(struct ice_hw *hw, struct ice_vsi_ctx *ctxt)
*/
if (ice_is_dvm_ena(hw)) {
ctxt->info.inner_vlan_flags |=
- ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING;
+ FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M,
+ ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING);
ctxt->info.outer_vlan_flags =
- (ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
- ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
- ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M;
+ FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M,
+ ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL);
ctxt->info.outer_vlan_flags |=
- (ICE_AQ_VSI_OUTER_TAG_VLAN_8100 <<
- ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
- ICE_AQ_VSI_OUTER_TAG_TYPE_M;
+ FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M,
+ ICE_AQ_VSI_OUTER_TAG_VLAN_8100);
ctxt->info.outer_vlan_flags |=
FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_EMODE_M,
ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING);
@@ -1066,10 +1069,8 @@ static int ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
vsi->tc_cfg.tc_info[i].qcount_tx = num_txq_per_tc;
vsi->tc_cfg.tc_info[i].netdev_tc = netdev_tc++;
- qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) &
- ICE_AQ_VSI_TC_Q_OFFSET_M) |
- ((pow << ICE_AQ_VSI_TC_Q_NUM_S) &
- ICE_AQ_VSI_TC_Q_NUM_M);
+ qmap = FIELD_PREP(ICE_AQ_VSI_TC_Q_OFFSET_M, offset);
+ qmap |= FIELD_PREP(ICE_AQ_VSI_TC_Q_NUM_M, pow);
offset += num_rxq_per_tc;
tx_count += num_txq_per_tc;
ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
@@ -1152,18 +1153,14 @@ static void ice_set_fd_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
ctxt->info.max_fd_fltr_shared =
cpu_to_le16(vsi->num_bfltr);
/* default queue index within the VSI of the default FD */
- val = ((dflt_q << ICE_AQ_VSI_FD_DEF_Q_S) &
- ICE_AQ_VSI_FD_DEF_Q_M);
+ val = FIELD_PREP(ICE_AQ_VSI_FD_DEF_Q_M, dflt_q);
/* target queue or queue group to the FD filter */
- val |= ((dflt_q_group << ICE_AQ_VSI_FD_DEF_GRP_S) &
- ICE_AQ_VSI_FD_DEF_GRP_M);
+ val |= FIELD_PREP(ICE_AQ_VSI_FD_DEF_GRP_M, dflt_q_group);
ctxt->info.fd_def_q = cpu_to_le16(val);
/* queue index on which FD filter completion is reported */
- val = ((report_q << ICE_AQ_VSI_FD_REPORT_Q_S) &
- ICE_AQ_VSI_FD_REPORT_Q_M);
+ val = FIELD_PREP(ICE_AQ_VSI_FD_REPORT_Q_M, report_q);
/* priority of the default qindex action */
- val |= ((dflt_q_prio << ICE_AQ_VSI_FD_DEF_PRIORITY_S) &
- ICE_AQ_VSI_FD_DEF_PRIORITY_M);
+ val |= FIELD_PREP(ICE_AQ_VSI_FD_DEF_PRIORITY_M, dflt_q_prio);
ctxt->info.fd_report_opt = cpu_to_le16(val);
}
@@ -1186,12 +1183,10 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
case ICE_VSI_PF:
/* PF VSI will inherit RSS instance of PF */
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_PF;
- hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
break;
case ICE_VSI_VF:
/* VF VSI will gets a small RSS table which is a VSI LUT type */
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
- hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
break;
default:
dev_dbg(dev, "Unsupported VSI type %s\n",
@@ -1199,9 +1194,12 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi)
return;
}
- ctxt->info.q_opt_rss = ((lut_type << ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
- ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
- (hash_type & ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
+ hash_type = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
+ vsi->rss_hfunc = hash_type;
+
+ ctxt->info.q_opt_rss =
+ FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) |
+ FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type);
}
static void
@@ -1215,10 +1213,8 @@ ice_chnl_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt)
qcount = min_t(int, vsi->num_rxq, pf->num_lan_msix);
pow = order_base_2(qcount);
- qmap = ((offset << ICE_AQ_VSI_TC_Q_OFFSET_S) &
- ICE_AQ_VSI_TC_Q_OFFSET_M) |
- ((pow << ICE_AQ_VSI_TC_Q_NUM_S) &
- ICE_AQ_VSI_TC_Q_NUM_M);
+ qmap = FIELD_PREP(ICE_AQ_VSI_TC_Q_OFFSET_M, offset);
+ qmap |= FIELD_PREP(ICE_AQ_VSI_TC_Q_NUM_M, pow);
ctxt->info.tc_mapping[0] = cpu_to_le16(qmap);
ctxt->info.mapping_flags |= cpu_to_le16(ICE_AQ_VSI_Q_MAP_CONTIG);
@@ -1600,12 +1596,44 @@ static void ice_vsi_set_vf_rss_flow_fld(struct ice_vsi *vsi)
return;
}
- status = ice_add_avf_rss_cfg(&pf->hw, vsi->idx, ICE_DEFAULT_RSS_HENA);
+ status = ice_add_avf_rss_cfg(&pf->hw, vsi, ICE_DEFAULT_RSS_HENA);
if (status)
dev_dbg(dev, "ice_add_avf_rss_cfg failed for vsi = %d, error = %d\n",
vsi->vsi_num, status);
}
+static const struct ice_rss_hash_cfg default_rss_cfgs[] = {
+ /* configure RSS for IPv4 with input set IP src/dst */
+ {ICE_FLOW_SEG_HDR_IPV4, ICE_FLOW_HASH_IPV4, ICE_RSS_ANY_HEADERS, false},
+ /* configure RSS for IPv6 with input set IPv6 src/dst */
+ {ICE_FLOW_SEG_HDR_IPV6, ICE_FLOW_HASH_IPV6, ICE_RSS_ANY_HEADERS, false},
+ /* configure RSS for tcp4 with input set IP src/dst, TCP src/dst */
+ {ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4,
+ ICE_HASH_TCP_IPV4, ICE_RSS_ANY_HEADERS, false},
+ /* configure RSS for udp4 with input set IP src/dst, UDP src/dst */
+ {ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4,
+ ICE_HASH_UDP_IPV4, ICE_RSS_ANY_HEADERS, false},
+ /* configure RSS for sctp4 with input set IP src/dst - only support
+ * RSS on SCTPv4 on outer headers (non-tunneled)
+ */
+ {ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4,
+ ICE_HASH_SCTP_IPV4, ICE_RSS_OUTER_HEADERS, false},
+ /* configure RSS for tcp6 with input set IPv6 src/dst, TCP src/dst */
+ {ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6,
+ ICE_HASH_TCP_IPV6, ICE_RSS_ANY_HEADERS, false},
+ /* configure RSS for udp6 with input set IPv6 src/dst, UDP src/dst */
+ {ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6,
+ ICE_HASH_UDP_IPV6, ICE_RSS_ANY_HEADERS, false},
+ /* configure RSS for sctp6 with input set IPv6 src/dst - only support
+ * RSS on SCTPv6 on outer headers (non-tunneled)
+ */
+ {ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6,
+ ICE_HASH_SCTP_IPV6, ICE_RSS_OUTER_HEADERS, false},
+ /* configure RSS for IPSEC ESP SPI with input set MAC_IPV4_SPI */
+ {ICE_FLOW_SEG_HDR_ESP,
+ ICE_FLOW_HASH_ESP_SPI, ICE_RSS_OUTER_HEADERS, false},
+};
+
/**
* ice_vsi_set_rss_flow_fld - Sets RSS input set for different flows
* @vsi: VSI to be configured
@@ -1619,11 +1647,12 @@ static void ice_vsi_set_vf_rss_flow_fld(struct ice_vsi *vsi)
*/
static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi)
{
- u16 vsi_handle = vsi->idx, vsi_num = vsi->vsi_num;
+ u16 vsi_num = vsi->vsi_num;
struct ice_pf *pf = vsi->back;
struct ice_hw *hw = &pf->hw;
struct device *dev;
int status;
+ u32 i;
dev = ice_pf_to_dev(pf);
if (ice_is_safe_mode(pf)) {
@@ -1631,67 +1660,15 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi)
vsi_num);
return;
}
- /* configure RSS for IPv4 with input set IP src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4,
- ICE_FLOW_SEG_HDR_IPV4);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for ipv4 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- /* configure RSS for IPv6 with input set IPv6 src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6,
- ICE_FLOW_SEG_HDR_IPV6);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for ipv6 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- /* configure RSS for tcp4 with input set IP src/dst, TCP src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV4,
- ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for tcp4 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- /* configure RSS for udp4 with input set IP src/dst, UDP src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV4,
- ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for udp4 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- /* configure RSS for sctp4 with input set IP src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4,
- ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for sctp4 flow, vsi = %d, error = %d\n",
- vsi_num, status);
+ for (i = 0; i < ARRAY_SIZE(default_rss_cfgs); i++) {
+ const struct ice_rss_hash_cfg *cfg = &default_rss_cfgs[i];
- /* configure RSS for tcp6 with input set IPv6 src/dst, TCP src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV6,
- ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for tcp6 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- /* configure RSS for udp6 with input set IPv6 src/dst, UDP src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV6,
- ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for udp6 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- /* configure RSS for sctp6 with input set IPv6 src/dst */
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6,
- ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for sctp6 flow, vsi = %d, error = %d\n",
- vsi_num, status);
-
- status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_ESP_SPI,
- ICE_FLOW_SEG_HDR_ESP);
- if (status)
- dev_dbg(dev, "ice_add_rss_cfg failed for esp/spi flow, vsi = %d, error = %d\n",
- vsi_num, status);
+ status = ice_add_rss_cfg(hw, vsi, cfg);
+ if (status)
+ dev_dbg(dev, "ice_add_rss_cfg failed, addl_hdrs = %x, hash_flds = %llx, hdr_type = %d, symm = %d\n",
+ cfg->addl_hdrs, cfg->hash_flds,
+ cfg->hdr_type, cfg->symm);
+ }
}
/**
@@ -1808,11 +1785,8 @@ ice_write_qrxflxp_cntxt(struct ice_hw *hw, u16 pf_q, u32 rxdid, u32 prio,
QRXFLXP_CNTXT_RXDID_PRIO_M |
QRXFLXP_CNTXT_TS_M);
- regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) &
- QRXFLXP_CNTXT_RXDID_IDX_M;
-
- regval |= (prio << QRXFLXP_CNTXT_RXDID_PRIO_S) &
- QRXFLXP_CNTXT_RXDID_PRIO_M;
+ regval |= FIELD_PREP(QRXFLXP_CNTXT_RXDID_IDX_M, rxdid);
+ regval |= FIELD_PREP(QRXFLXP_CNTXT_RXDID_PRIO_M, prio);
if (ena_ts)
/* Enable TimeSync on this queue */
@@ -2450,6 +2424,10 @@ ice_vsi_cfg_def(struct ice_vsi *vsi, struct ice_vsi_cfg_params *params)
goto unroll_vector_base;
ice_vsi_map_rings_to_vectors(vsi);
+
+ /* Associate q_vector rings to napi */
+ ice_vsi_set_napi_queues(vsi);
+
vsi->stat_offsets_loaded = false;
if (ice_is_xdp_ena_vsi(vsi)) {
@@ -2926,6 +2904,123 @@ void ice_vsi_dis_irq(struct ice_vsi *vsi)
}
/**
+ * __ice_queue_set_napi - Set the napi instance for the queue
+ * @dev: device to which NAPI and queue belong
+ * @queue_index: Index of queue
+ * @type: queue type as RX or TX
+ * @napi: NAPI context
+ * @locked: is the rtnl_lock already held
+ *
+ * Set the napi instance for the queue. Caller indicates the lock status.
+ */
+static void
+__ice_queue_set_napi(struct net_device *dev, unsigned int queue_index,
+ enum netdev_queue_type type, struct napi_struct *napi,
+ bool locked)
+{
+ if (!locked)
+ rtnl_lock();
+ netif_queue_set_napi(dev, queue_index, type, napi);
+ if (!locked)
+ rtnl_unlock();
+}
+
+/**
+ * ice_queue_set_napi - Set the napi instance for the queue
+ * @vsi: VSI being configured
+ * @queue_index: Index of queue
+ * @type: queue type as RX or TX
+ * @napi: NAPI context
+ *
+ * Set the napi instance for the queue. The rtnl lock state is derived from the
+ * execution path.
+ */
+void
+ice_queue_set_napi(struct ice_vsi *vsi, unsigned int queue_index,
+ enum netdev_queue_type type, struct napi_struct *napi)
+{
+ struct ice_pf *pf = vsi->back;
+
+ if (!vsi->netdev)
+ return;
+
+ if (current_work() == &pf->serv_task ||
+ test_bit(ICE_PREPARED_FOR_RESET, pf->state) ||
+ test_bit(ICE_DOWN, pf->state) ||
+ test_bit(ICE_SUSPENDED, pf->state))
+ __ice_queue_set_napi(vsi->netdev, queue_index, type, napi,
+ false);
+ else
+ __ice_queue_set_napi(vsi->netdev, queue_index, type, napi,
+ true);
+}
+
+/**
+ * __ice_q_vector_set_napi_queues - Map queue[s] associated with the napi
+ * @q_vector: q_vector pointer
+ * @locked: is the rtnl_lock already held
+ *
+ * Associate the q_vector napi with all the queue[s] on the vector.
+ * Caller indicates the lock status.
+ */
+void __ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked)
+{
+ struct ice_rx_ring *rx_ring;
+ struct ice_tx_ring *tx_ring;
+
+ ice_for_each_rx_ring(rx_ring, q_vector->rx)
+ __ice_queue_set_napi(q_vector->vsi->netdev, rx_ring->q_index,
+ NETDEV_QUEUE_TYPE_RX, &q_vector->napi,
+ locked);
+
+ ice_for_each_tx_ring(tx_ring, q_vector->tx)
+ __ice_queue_set_napi(q_vector->vsi->netdev, tx_ring->q_index,
+ NETDEV_QUEUE_TYPE_TX, &q_vector->napi,
+ locked);
+ /* Also set the interrupt number for the NAPI */
+ netif_napi_set_irq(&q_vector->napi, q_vector->irq.virq);
+}
+
+/**
+ * ice_q_vector_set_napi_queues - Map queue[s] associated with the napi
+ * @q_vector: q_vector pointer
+ *
+ * Associate the q_vector napi with all the queue[s] on the vector
+ */
+void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector)
+{
+ struct ice_rx_ring *rx_ring;
+ struct ice_tx_ring *tx_ring;
+
+ ice_for_each_rx_ring(rx_ring, q_vector->rx)
+ ice_queue_set_napi(q_vector->vsi, rx_ring->q_index,
+ NETDEV_QUEUE_TYPE_RX, &q_vector->napi);
+
+ ice_for_each_tx_ring(tx_ring, q_vector->tx)
+ ice_queue_set_napi(q_vector->vsi, tx_ring->q_index,
+ NETDEV_QUEUE_TYPE_TX, &q_vector->napi);
+ /* Also set the interrupt number for the NAPI */
+ netif_napi_set_irq(&q_vector->napi, q_vector->irq.virq);
+}
+
+/**
+ * ice_vsi_set_napi_queues
+ * @vsi: VSI pointer
+ *
+ * Associate queue[s] with napi for all vectors
+ */
+void ice_vsi_set_napi_queues(struct ice_vsi *vsi)
+{
+ int i;
+
+ if (!vsi->netdev)
+ return;
+
+ ice_for_each_q_vector(vsi, i)
+ ice_q_vector_set_napi_queues(vsi->q_vectors[i]);
+}
+
+/**
* ice_vsi_release - Delete a VSI and free its resources
* @vsi: the VSI being removed
*
@@ -3070,27 +3165,26 @@ ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi,
}
/**
- * ice_vsi_realloc_stat_arrays - Frees unused stat structures
+ * ice_vsi_realloc_stat_arrays - Frees unused stat structures or alloc new ones
* @vsi: VSI pointer
- * @prev_txq: Number of Tx rings before ring reallocation
- * @prev_rxq: Number of Rx rings before ring reallocation
*/
-static void
-ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi, int prev_txq, int prev_rxq)
+static int
+ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi)
{
+ u16 req_txq = vsi->req_txq ? vsi->req_txq : vsi->alloc_txq;
+ u16 req_rxq = vsi->req_rxq ? vsi->req_rxq : vsi->alloc_rxq;
+ struct ice_ring_stats **tx_ring_stats;
+ struct ice_ring_stats **rx_ring_stats;
struct ice_vsi_stats *vsi_stat;
struct ice_pf *pf = vsi->back;
+ u16 prev_txq = vsi->alloc_txq;
+ u16 prev_rxq = vsi->alloc_rxq;
int i;
- if (!prev_txq || !prev_rxq)
- return;
- if (vsi->type == ICE_VSI_CHNL)
- return;
-
vsi_stat = pf->vsi_stats[vsi->idx];
- if (vsi->num_txq < prev_txq) {
- for (i = vsi->num_txq; i < prev_txq; i++) {
+ if (req_txq < prev_txq) {
+ for (i = req_txq; i < prev_txq; i++) {
if (vsi_stat->tx_ring_stats[i]) {
kfree_rcu(vsi_stat->tx_ring_stats[i], rcu);
WRITE_ONCE(vsi_stat->tx_ring_stats[i], NULL);
@@ -3098,14 +3192,36 @@ ice_vsi_realloc_stat_arrays(struct ice_vsi *vsi, int prev_txq, int prev_rxq)
}
}
- if (vsi->num_rxq < prev_rxq) {
- for (i = vsi->num_rxq; i < prev_rxq; i++) {
+ tx_ring_stats = vsi_stat->tx_ring_stats;
+ vsi_stat->tx_ring_stats =
+ krealloc_array(vsi_stat->tx_ring_stats, req_txq,
+ sizeof(*vsi_stat->tx_ring_stats),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!vsi_stat->tx_ring_stats) {
+ vsi_stat->tx_ring_stats = tx_ring_stats;
+ return -ENOMEM;
+ }
+
+ if (req_rxq < prev_rxq) {
+ for (i = req_rxq; i < prev_rxq; i++) {
if (vsi_stat->rx_ring_stats[i]) {
kfree_rcu(vsi_stat->rx_ring_stats[i], rcu);
WRITE_ONCE(vsi_stat->rx_ring_stats[i], NULL);
}
}
}
+
+ rx_ring_stats = vsi_stat->rx_ring_stats;
+ vsi_stat->rx_ring_stats =
+ krealloc_array(vsi_stat->rx_ring_stats, req_rxq,
+ sizeof(*vsi_stat->rx_ring_stats),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!vsi_stat->rx_ring_stats) {
+ vsi_stat->rx_ring_stats = rx_ring_stats;
+ return -ENOMEM;
+ }
+
+ return 0;
}
/**
@@ -3122,9 +3238,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags)
{
struct ice_vsi_cfg_params params = {};
struct ice_coalesce_stored *coalesce;
- int ret, prev_txq, prev_rxq;
int prev_num_q_vectors = 0;
struct ice_pf *pf;
+ int ret;
if (!vsi)
return -EINVAL;
@@ -3143,8 +3259,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags)
prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, coalesce);
- prev_txq = vsi->num_txq;
- prev_rxq = vsi->num_rxq;
+ ret = ice_vsi_realloc_stat_arrays(vsi);
+ if (ret)
+ goto err_vsi_cfg;
ice_vsi_decfg(vsi);
ret = ice_vsi_cfg_def(vsi, &params);
@@ -3162,8 +3279,6 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, u32 vsi_flags)
return ice_schedule_reset(pf, ICE_RESET_PFR);
}
- ice_vsi_realloc_stat_arrays(vsi, prev_txq, prev_rxq);
-
ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors);
kfree(coalesce);
@@ -3315,9 +3430,8 @@ ice_vsi_setup_q_map_mqprio(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt,
vsi->tc_cfg.ena_tc = ena_tc ? ena_tc : 1;
pow = order_base_2(tc0_qcount);
- qmap = ((tc0_offset << ICE_AQ_VSI_TC_Q_OFFSET_S) &
- ICE_AQ_VSI_TC_Q_OFFSET_M) |
- ((pow << ICE_AQ_VSI_TC_Q_NUM_S) & ICE_AQ_VSI_TC_Q_NUM_M);
+ qmap = FIELD_PREP(ICE_AQ_VSI_TC_Q_OFFSET_M, tc0_offset);
+ qmap |= FIELD_PREP(ICE_AQ_VSI_TC_Q_NUM_M, pow);
ice_for_each_traffic_class(i) {
if (!(vsi->tc_cfg.ena_tc & BIT(i))) {
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h
index f24f5d1e6f9c..bfcfc582a4c0 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_lib.h
@@ -91,6 +91,16 @@ void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc);
struct ice_vsi *
ice_vsi_setup(struct ice_pf *pf, struct ice_vsi_cfg_params *params);
+void
+ice_queue_set_napi(struct ice_vsi *vsi, unsigned int queue_index,
+ enum netdev_queue_type type, struct napi_struct *napi);
+
+void __ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector, bool locked);
+
+void ice_q_vector_set_napi_queues(struct ice_q_vector *q_vector);
+
+void ice_vsi_set_napi_queues(struct ice_vsi *vsi);
+
int ice_vsi_release(struct ice_vsi *vsi);
void ice_vsi_close(struct ice_vsi *vsi);
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index adfdea1e2805..df6a68ab747e 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -14,6 +14,7 @@
#include "ice_dcb_lib.h"
#include "ice_dcb_nl.h"
#include "ice_devlink.h"
+#include "ice_hwmon.h"
/* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
* ice tracepoint functions. This must be done exactly once across the
* ice driver.
@@ -979,7 +980,7 @@ static void ice_set_dflt_mib(struct ice_pf *pf)
* Octets 13 - 20 are TSA values - leave as zeros
*/
buf[5] = 0x64;
- len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
+ len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
offset += len + 2;
tlv = (struct ice_lldp_org_tlv *)
((char *)tlv + sizeof(tlv->typelen) + len);
@@ -1013,7 +1014,7 @@ static void ice_set_dflt_mib(struct ice_pf *pf)
/* Octet 1 left as all zeros - PFC disabled */
buf[0] = 0x08;
- len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
+ len = FIELD_GET(ICE_LLDP_TLV_LEN_M, typelen);
offset += len + 2;
if (ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, offset, NULL))
@@ -1252,6 +1253,32 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
}
/**
+ * ice_get_fwlog_data - copy the FW log data from ARQ event
+ * @pf: PF that the FW log event is associated with
+ * @event: event structure containing FW log data
+ */
+static void
+ice_get_fwlog_data(struct ice_pf *pf, struct ice_rq_event_info *event)
+{
+ struct ice_fwlog_data *fwlog;
+ struct ice_hw *hw = &pf->hw;
+
+ fwlog = &hw->fwlog_ring.rings[hw->fwlog_ring.tail];
+
+ memset(fwlog->data, 0, PAGE_SIZE);
+ fwlog->data_size = le16_to_cpu(event->desc.datalen);
+
+ memcpy(fwlog->data, event->msg_buf, fwlog->data_size);
+ ice_fwlog_ring_increment(&hw->fwlog_ring.tail, hw->fwlog_ring.size);
+
+ if (ice_fwlog_ring_full(&hw->fwlog_ring)) {
+ /* the rings are full so bump the head to create room */
+ ice_fwlog_ring_increment(&hw->fwlog_ring.head,
+ hw->fwlog_ring.size);
+ }
+}
+
+/**
* ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware
* @pf: pointer to the PF private structure
* @task: intermediate helper storage and identifier for waiting
@@ -1532,8 +1559,8 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
ice_vc_process_vf_msg(pf, &event, &data);
break;
- case ice_aqc_opc_fw_logging:
- ice_output_fw_log(hw, &event.desc, event.msg_buf);
+ case ice_aqc_opc_fw_logs_event:
+ ice_get_fwlog_data(pf, &event);
break;
case ice_aqc_opc_lldp_set_mib_change:
ice_dcb_process_lldp_set_mib_change(pf, &event);
@@ -1744,14 +1771,10 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
/* find what triggered an MDD event */
reg = rd32(hw, GL_MDET_TX_PQM);
if (reg & GL_MDET_TX_PQM_VALID_M) {
- u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >>
- GL_MDET_TX_PQM_PF_NUM_S;
- u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >>
- GL_MDET_TX_PQM_VF_NUM_S;
- u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >>
- GL_MDET_TX_PQM_MAL_TYPE_S;
- u16 queue = ((reg & GL_MDET_TX_PQM_QNUM_M) >>
- GL_MDET_TX_PQM_QNUM_S);
+ u8 pf_num = FIELD_GET(GL_MDET_TX_PQM_PF_NUM_M, reg);
+ u16 vf_num = FIELD_GET(GL_MDET_TX_PQM_VF_NUM_M, reg);
+ u8 event = FIELD_GET(GL_MDET_TX_PQM_MAL_TYPE_M, reg);
+ u16 queue = FIELD_GET(GL_MDET_TX_PQM_QNUM_M, reg);
if (netif_msg_tx_err(pf))
dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n",
@@ -1761,14 +1784,10 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, GL_MDET_TX_TCLAN_BY_MAC(hw));
if (reg & GL_MDET_TX_TCLAN_VALID_M) {
- u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >>
- GL_MDET_TX_TCLAN_PF_NUM_S;
- u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >>
- GL_MDET_TX_TCLAN_VF_NUM_S;
- u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >>
- GL_MDET_TX_TCLAN_MAL_TYPE_S;
- u16 queue = ((reg & GL_MDET_TX_TCLAN_QNUM_M) >>
- GL_MDET_TX_TCLAN_QNUM_S);
+ u8 pf_num = FIELD_GET(GL_MDET_TX_TCLAN_PF_NUM_M, reg);
+ u16 vf_num = FIELD_GET(GL_MDET_TX_TCLAN_VF_NUM_M, reg);
+ u8 event = FIELD_GET(GL_MDET_TX_TCLAN_MAL_TYPE_M, reg);
+ u16 queue = FIELD_GET(GL_MDET_TX_TCLAN_QNUM_M, reg);
if (netif_msg_tx_err(pf))
dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n",
@@ -1778,14 +1797,10 @@ static void ice_handle_mdd_event(struct ice_pf *pf)
reg = rd32(hw, GL_MDET_RX);
if (reg & GL_MDET_RX_VALID_M) {
- u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >>
- GL_MDET_RX_PF_NUM_S;
- u16 vf_num = (reg & GL_MDET_RX_VF_NUM_M) >>
- GL_MDET_RX_VF_NUM_S;
- u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >>
- GL_MDET_RX_MAL_TYPE_S;
- u16 queue = ((reg & GL_MDET_RX_QNUM_M) >>
- GL_MDET_RX_QNUM_S);
+ u8 pf_num = FIELD_GET(GL_MDET_RX_PF_NUM_M, reg);
+ u16 vf_num = FIELD_GET(GL_MDET_RX_VF_NUM_M, reg);
+ u8 event = FIELD_GET(GL_MDET_RX_MAL_TYPE_M, reg);
+ u16 queue = FIELD_GET(GL_MDET_RX_QNUM_M, reg);
if (netif_msg_rx_err(pf))
dev_info(dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n",
@@ -3031,6 +3046,7 @@ static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp)
static void ice_ena_misc_vector(struct ice_pf *pf)
{
struct ice_hw *hw = &pf->hw;
+ u32 pf_intr_start_offset;
u32 val;
/* Disable anti-spoof detection interrupt to prevent spurious event
@@ -3059,6 +3075,47 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
/* SW_ITR_IDX = 0, but don't change INTENA */
wr32(hw, GLINT_DYN_CTL(pf->oicr_irq.index),
GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
+
+ if (!pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
+ return;
+ pf_intr_start_offset = rd32(hw, PFINT_ALLOC) & PFINT_ALLOC_FIRST;
+ wr32(hw, GLINT_DYN_CTL(pf->ll_ts_irq.index + pf_intr_start_offset),
+ GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
+}
+
+/**
+ * ice_ll_ts_intr - ll_ts interrupt handler
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ */
+static irqreturn_t ice_ll_ts_intr(int __always_unused irq, void *data)
+{
+ struct ice_pf *pf = data;
+ u32 pf_intr_start_offset;
+ struct ice_ptp_tx *tx;
+ unsigned long flags;
+ struct ice_hw *hw;
+ u32 val;
+ u8 idx;
+
+ hw = &pf->hw;
+ tx = &pf->ptp.port.tx;
+ spin_lock_irqsave(&tx->lock, flags);
+ ice_ptp_complete_tx_single_tstamp(tx);
+
+ idx = find_next_bit_wrap(tx->in_use, tx->len,
+ tx->last_ll_ts_idx_read + 1);
+ if (idx != tx->len)
+ ice_ptp_req_tx_single_tstamp(tx, idx);
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ val = GLINT_DYN_CTL_INTENA_M | GLINT_DYN_CTL_CLEARPBA_M |
+ (ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S);
+ pf_intr_start_offset = rd32(hw, PFINT_ALLOC) & PFINT_ALLOC_FIRST;
+ wr32(hw, GLINT_DYN_CTL(pf->ll_ts_irq.index + pf_intr_start_offset),
+ val);
+
+ return IRQ_HANDLED;
}
/**
@@ -3069,6 +3126,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
{
struct ice_pf *pf = (struct ice_pf *)data;
+ irqreturn_t ret = IRQ_HANDLED;
struct ice_hw *hw = &pf->hw;
struct device *dev;
u32 oicr, ena_mask;
@@ -3108,8 +3166,8 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
/* we have a reset warning */
ena_mask &= ~PFINT_OICR_GRST_M;
- reset = (rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_RESET_TYPE_M) >>
- GLGEN_RSTAT_RESET_TYPE_S;
+ reset = FIELD_GET(GLGEN_RSTAT_RESET_TYPE_M,
+ rd32(hw, GLGEN_RSTAT));
if (reset == ICE_RESET_CORER)
pf->corer_count++;
@@ -3150,8 +3208,22 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
if (oicr & PFINT_OICR_TSYN_TX_M) {
ena_mask &= ~PFINT_OICR_TSYN_TX_M;
- if (!hw->reset_ongoing && ice_ptp_pf_handles_tx_interrupt(pf))
+ if (ice_pf_state_is_nominal(pf) &&
+ pf->hw.dev_caps.ts_dev_info.ts_ll_int_read) {
+ struct ice_ptp_tx *tx = &pf->ptp.port.tx;
+ unsigned long flags;
+ u8 idx;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ idx = find_next_bit_wrap(tx->in_use, tx->len,
+ tx->last_ll_ts_idx_read + 1);
+ if (idx != tx->len)
+ ice_ptp_req_tx_single_tstamp(tx, idx);
+ spin_unlock_irqrestore(&tx->lock, flags);
+ } else if (ice_ptp_pf_handles_tx_interrupt(pf)) {
set_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread);
+ ret = IRQ_WAKE_THREAD;
+ }
}
if (oicr & PFINT_OICR_TSYN_EVNT_M) {
@@ -3167,7 +3239,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
GLTSYN_STAT_EVENT1_M |
GLTSYN_STAT_EVENT2_M);
- set_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread);
+ ice_ptp_extts_event(pf);
}
}
@@ -3190,8 +3262,11 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
set_bit(ICE_PFR_REQ, pf->state);
}
}
+ ice_service_task_schedule(pf);
+ if (ret == IRQ_HANDLED)
+ ice_irq_dynamic_ena(hw, NULL, NULL);
- return IRQ_WAKE_THREAD;
+ return ret;
}
/**
@@ -3207,12 +3282,7 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
hw = &pf->hw;
if (ice_is_reset_in_progress(pf->state))
- return IRQ_HANDLED;
-
- ice_service_task_schedule(pf);
-
- if (test_and_clear_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread))
- ice_ptp_extts_event(pf);
+ goto skip_irq;
if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) {
/* Process outstanding Tx timestamps. If there is more work,
@@ -3224,6 +3294,7 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
}
}
+skip_irq:
ice_irq_dynamic_ena(hw, NULL, NULL);
return IRQ_HANDLED;
@@ -3254,6 +3325,20 @@ static void ice_dis_ctrlq_interrupts(struct ice_hw *hw)
}
/**
+ * ice_free_irq_msix_ll_ts- Unroll ll_ts vector setup
+ * @pf: board private structure
+ */
+static void ice_free_irq_msix_ll_ts(struct ice_pf *pf)
+{
+ int irq_num = pf->ll_ts_irq.virq;
+
+ synchronize_irq(irq_num);
+ devm_free_irq(ice_pf_to_dev(pf), irq_num, pf);
+
+ ice_free_irq(pf, pf->ll_ts_irq);
+}
+
+/**
* ice_free_irq_msix_misc - Unroll misc vector setup
* @pf: board private structure
*/
@@ -3272,6 +3357,8 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)
devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf);
ice_free_irq(pf, pf->oicr_irq);
+ if (pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
+ ice_free_irq_msix_ll_ts(pf);
}
/**
@@ -3297,10 +3384,12 @@ static void ice_ena_ctrlq_interrupts(struct ice_hw *hw, u16 reg_idx)
PFINT_MBX_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_MBX_CTL, val);
- /* This enables Sideband queue Interrupt causes */
- val = ((reg_idx & PFINT_SB_CTL_MSIX_INDX_M) |
- PFINT_SB_CTL_CAUSE_ENA_M);
- wr32(hw, PFINT_SB_CTL, val);
+ if (!hw->dev_caps.ts_dev_info.ts_ll_int_read) {
+ /* enable Sideband queue Interrupt causes */
+ val = ((reg_idx & PFINT_SB_CTL_MSIX_INDX_M) |
+ PFINT_SB_CTL_CAUSE_ENA_M);
+ wr32(hw, PFINT_SB_CTL, val);
+ }
ice_flush(hw);
}
@@ -3317,13 +3406,17 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
- struct msi_map oicr_irq;
+ u32 pf_intr_start_offset;
+ struct msi_map irq;
int err = 0;
if (!pf->int_name[0])
snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc",
dev_driver_string(dev), dev_name(dev));
+ if (!pf->int_name_ll_ts[0])
+ snprintf(pf->int_name_ll_ts, sizeof(pf->int_name_ll_ts) - 1,
+ "%s-%s:ll_ts", dev_driver_string(dev), dev_name(dev));
/* Do not request IRQ but do enable OICR interrupt since settings are
* lost during reset. Note that this function is called only during
* rebuild path and not while reset is in progress.
@@ -3332,11 +3425,11 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
goto skip_req_irq;
/* reserve one vector in irq_tracker for misc interrupts */
- oicr_irq = ice_alloc_irq(pf, false);
- if (oicr_irq.index < 0)
- return oicr_irq.index;
+ irq = ice_alloc_irq(pf, false);
+ if (irq.index < 0)
+ return irq.index;
- pf->oicr_irq = oicr_irq;
+ pf->oicr_irq = irq;
err = devm_request_threaded_irq(dev, pf->oicr_irq.virq, ice_misc_intr,
ice_misc_intr_thread_fn, 0,
pf->int_name, pf);
@@ -3347,10 +3440,34 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
return err;
}
+ /* reserve one vector in irq_tracker for ll_ts interrupt */
+ if (!pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
+ goto skip_req_irq;
+
+ irq = ice_alloc_irq(pf, false);
+ if (irq.index < 0)
+ return irq.index;
+
+ pf->ll_ts_irq = irq;
+ err = devm_request_irq(dev, pf->ll_ts_irq.virq, ice_ll_ts_intr, 0,
+ pf->int_name_ll_ts, pf);
+ if (err) {
+ dev_err(dev, "devm_request_irq for %s failed: %d\n",
+ pf->int_name_ll_ts, err);
+ ice_free_irq(pf, pf->ll_ts_irq);
+ return err;
+ }
+
skip_req_irq:
ice_ena_misc_vector(pf);
ice_ena_ctrlq_interrupts(hw, pf->oicr_irq.index);
+ /* This enables LL TS interrupt */
+ pf_intr_start_offset = rd32(hw, PFINT_ALLOC) & PFINT_ALLOC_FIRST;
+ if (pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
+ wr32(hw, PFINT_SB_CTL,
+ ((pf->ll_ts_irq.index + pf_intr_start_offset) &
+ PFINT_SB_CTL_MSIX_INDX_M) | PFINT_SB_CTL_CAUSE_ENA_M);
wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_irq.index),
ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S);
@@ -3375,9 +3492,11 @@ static void ice_napi_add(struct ice_vsi *vsi)
if (!vsi->netdev)
return;
- ice_for_each_q_vector(vsi, v_idx)
+ ice_for_each_q_vector(vsi, v_idx) {
netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
ice_napi_poll);
+ __ice_q_vector_set_napi_queues(vsi->q_vectors[v_idx], false);
+ }
}
/**
@@ -3397,6 +3516,7 @@ static void ice_set_ops(struct ice_vsi *vsi)
netdev->netdev_ops = &ice_netdev_ops;
netdev->udp_tunnel_nic_info = &pf->hw.udp_tunnel_nic;
+ netdev->xdp_metadata_ops = &ice_xdp_md_ops;
ice_set_ethtool_ops(netdev);
if (vsi->type != ICE_VSI_PF)
@@ -4361,6 +4481,19 @@ static void ice_print_wake_reason(struct ice_pf *pf)
}
/**
+ * ice_pf_fwlog_update_module - update 1 module
+ * @pf: pointer to the PF struct
+ * @log_level: log_level to use for the @module
+ * @module: module to update
+ */
+void ice_pf_fwlog_update_module(struct ice_pf *pf, int log_level, int module)
+{
+ struct ice_hw *hw = &pf->hw;
+
+ hw->fwlog_cfg.module_entries[module].log_level = log_level;
+}
+
+/**
* ice_register_netdev - register netdev
* @vsi: pointer to the VSI struct
*/
@@ -4685,6 +4818,8 @@ static void ice_init_features(struct ice_pf *pf)
if (ice_init_lag(pf))
dev_warn(dev, "Failed to init link aggregation support\n");
+
+ ice_hwmon_init(pf);
}
static void ice_deinit_features(struct ice_pf *pf)
@@ -4702,6 +4837,8 @@ static void ice_deinit_features(struct ice_pf *pf)
ice_ptp_release(pf);
if (test_bit(ICE_FLAG_DPLL, pf->flags))
ice_dpll_deinit(pf);
+ if (pf->eswitch_mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
+ xa_destroy(&pf->eswitch.reprs);
}
static void ice_init_wakeup(struct ice_pf *pf)
@@ -5203,11 +5340,15 @@ static void ice_remove(struct pci_dev *pdev)
msleep(100);
}
+ ice_debugfs_exit();
+
if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {
set_bit(ICE_VF_RESETS_DISABLED, pf->state);
ice_free_vfs(pf);
}
+ ice_hwmon_exit(pf);
+
ice_service_task_stop(pf);
ice_aq_cancel_waiting_tasks(pf);
set_bit(ICE_DOWN, pf->state);
@@ -5306,6 +5447,7 @@ static int ice_reinit_interrupt_scheme(struct ice_pf *pf)
if (ret)
goto err_reinit;
ice_vsi_map_rings_to_vectors(pf->vsi[v]);
+ ice_vsi_set_napi_queues(pf->vsi[v]);
}
ret = ice_req_irq_msix_misc(pf);
@@ -5672,6 +5814,8 @@ static int __init ice_module_init(void)
goto err_dest_wq;
}
+ ice_debugfs_init();
+
status = pci_register_driver(&ice_driver);
if (status) {
pr_err("failed to register PCI driver, err %d\n", status);
@@ -5682,6 +5826,7 @@ static int __init ice_module_init(void)
err_dest_lag_wq:
destroy_workqueue(ice_lag_wq);
+ ice_debugfs_exit();
err_dest_wq:
destroy_workqueue(ice_wq);
return status;
@@ -6041,6 +6186,23 @@ ice_fix_features(struct net_device *netdev, netdev_features_t features)
}
/**
+ * ice_set_rx_rings_vlan_proto - update rings with new stripped VLAN proto
+ * @vsi: PF's VSI
+ * @vlan_ethertype: VLAN ethertype (802.1Q or 802.1ad) in network byte order
+ *
+ * Store current stripped VLAN proto in ring packet context,
+ * so it can be accessed more efficiently by packet processing code.
+ */
+static void
+ice_set_rx_rings_vlan_proto(struct ice_vsi *vsi, __be16 vlan_ethertype)
+{
+ u16 i;
+
+ ice_for_each_alloc_rxq(vsi, i)
+ vsi->rx_rings[i]->pkt_ctx.vlan_proto = vlan_ethertype;
+}
+
+/**
* ice_set_vlan_offload_features - set VLAN offload features for the PF VSI
* @vsi: PF's VSI
* @features: features used to determine VLAN offload settings
@@ -6082,6 +6244,9 @@ ice_set_vlan_offload_features(struct ice_vsi *vsi, netdev_features_t features)
if (strip_err || insert_err)
return -EIO;
+ ice_set_rx_rings_vlan_proto(vsi, enable_stripping ?
+ htons(vlan_ethertype) : 0);
+
return 0;
}
@@ -6670,13 +6835,11 @@ void ice_update_vsi_stats(struct ice_vsi *vsi)
cur_ns->rx_crc_errors = pf->stats.crc_errors;
cur_ns->rx_errors = pf->stats.crc_errors +
pf->stats.illegal_bytes +
- pf->stats.rx_len_errors +
pf->stats.rx_undersize +
pf->hw_csum_rx_error +
pf->stats.rx_jabber +
pf->stats.rx_fragments +
pf->stats.rx_oversize;
- cur_ns->rx_length_errors = pf->stats.rx_len_errors;
/* record drops from the port level */
cur_ns->rx_missed_errors = pf->stats.eth.rx_discards;
}
@@ -6816,9 +6979,6 @@ void ice_update_pf_stats(struct ice_pf *pf)
&prev_ps->mac_remote_faults,
&cur_ps->mac_remote_faults);
- ice_stat_update32(hw, GLPRT_RLEC(port), pf->stat_prev_loaded,
- &prev_ps->rx_len_errors, &cur_ps->rx_len_errors);
-
ice_stat_update32(hw, GLPRT_RUC(port), pf->stat_prev_loaded,
&prev_ps->rx_undersize, &cur_ps->rx_undersize);
@@ -7401,9 +7561,9 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
goto err_vsi_rebuild;
}
- err = ice_vsi_rebuild_by_type(pf, ICE_VSI_SWITCHDEV_CTRL);
+ err = ice_eswitch_rebuild(pf);
if (err) {
- dev_err(dev, "Switchdev CTRL VSI rebuild failed: %d\n", err);
+ dev_err(dev, "Switchdev rebuild failed: %d\n", err);
goto err_vsi_rebuild;
}
@@ -7704,6 +7864,59 @@ int ice_get_rss_key(struct ice_vsi *vsi, u8 *seed)
}
/**
+ * ice_set_rss_hfunc - Set RSS HASH function
+ * @vsi: Pointer to VSI structure
+ * @hfunc: hash function (ICE_AQ_VSI_Q_OPT_RSS_*)
+ *
+ * Returns 0 on success, negative on failure
+ */
+int ice_set_rss_hfunc(struct ice_vsi *vsi, u8 hfunc)
+{
+ struct ice_hw *hw = &vsi->back->hw;
+ struct ice_vsi_ctx *ctx;
+ bool symm;
+ int err;
+
+ if (hfunc == vsi->rss_hfunc)
+ return 0;
+
+ if (hfunc != ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ &&
+ hfunc != ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ)
+ return -EOPNOTSUPP;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID);
+ ctx->info.q_opt_rss = vsi->info.q_opt_rss;
+ ctx->info.q_opt_rss &= ~ICE_AQ_VSI_Q_OPT_RSS_HASH_M;
+ ctx->info.q_opt_rss |=
+ FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hfunc);
+ ctx->info.q_opt_tc = vsi->info.q_opt_tc;
+ ctx->info.q_opt_flags = vsi->info.q_opt_rss;
+
+ err = ice_update_vsi(hw, vsi->idx, ctx, NULL);
+ if (err) {
+ dev_err(ice_pf_to_dev(vsi->back), "Failed to configure RSS hash for VSI %d, error %d\n",
+ vsi->vsi_num, err);
+ } else {
+ vsi->info.q_opt_rss = ctx->info.q_opt_rss;
+ vsi->rss_hfunc = hfunc;
+ netdev_info(vsi->netdev, "Hash function set to: %sToeplitz\n",
+ hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ ?
+ "Symmetric " : "");
+ }
+ kfree(ctx);
+ if (err)
+ return err;
+
+ /* Fix the symmetry setting for all existing RSS configurations */
+ symm = !!(hfunc == ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ);
+ return ice_set_rss_cfg_symm(hw, vsi, symm);
+}
+
+/**
* ice_bridge_getlink - Get the hardware bridge mode
* @skb: skb buff
* @pid: process ID
@@ -7800,6 +8013,8 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
pf_sw = pf->first_sw;
/* find the attribute in the netlink message */
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) {
__u16 mode;
@@ -7889,8 +8104,8 @@ static void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue)
struct ice_hw *hw = &pf->hw;
u32 head, val = 0;
- head = (rd32(hw, QTX_COMM_HEAD(vsi->txq_map[txqueue])) &
- QTX_COMM_HEAD_HEAD_M) >> QTX_COMM_HEAD_HEAD_S;
+ head = FIELD_GET(QTX_COMM_HEAD_HEAD_M,
+ rd32(hw, QTX_COMM_HEAD(vsi->txq_map[txqueue])));
/* Read interrupt register */
val = rd32(hw, GLINT_DYN_CTL(tx_ring->q_vector->reg_idx));
@@ -8138,13 +8353,12 @@ static int ice_add_vsi_to_fdir(struct ice_pf *pf, struct ice_vsi *vsi)
for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {
enum ice_flow_priority prio;
- u64 prof_id;
/* add this VSI to FDir profile for this flow */
prio = ICE_FLOW_PRIO_NORMAL;
prof = hw->fdir_prof[flow];
- prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
- status = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id,
+ status = ice_flow_add_entry(hw, ICE_BLK_FD,
+ prof->prof_id[tun],
prof->vsi_h[0], vsi->idx,
prio, prof->fdir_seg[tun],
&entry_h);
diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
index f6f52a248066..d4e05d2cb30c 100644
--- a/drivers/net/ethernet/intel/ice/ice_nvm.c
+++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
@@ -571,8 +571,8 @@ ice_get_nvm_ver_info(struct ice_hw *hw, enum ice_bank_select bank, struct ice_nv
return status;
}
- nvm->major = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT;
- nvm->minor = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT;
+ nvm->major = FIELD_GET(ICE_NVM_VER_HI_MASK, ver);
+ nvm->minor = FIELD_GET(ICE_NVM_VER_LO_MASK, ver);
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_EETRACK_LO, &eetrack_lo);
if (status) {
@@ -706,9 +706,9 @@ ice_get_orom_ver_info(struct ice_hw *hw, enum ice_bank_select bank, struct ice_o
combo_ver = le32_to_cpu(civd.combo_ver);
- orom->major = (u8)((combo_ver & ICE_OROM_VER_MASK) >> ICE_OROM_VER_SHIFT);
- orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK);
- orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >> ICE_OROM_VER_BUILD_SHIFT);
+ orom->major = FIELD_GET(ICE_OROM_VER_MASK, combo_ver);
+ orom->patch = FIELD_GET(ICE_OROM_VER_PATCH_MASK, combo_ver);
+ orom->build = FIELD_GET(ICE_OROM_VER_BUILD_MASK, combo_ver);
return 0;
}
@@ -950,7 +950,8 @@ static int ice_determine_active_flash_banks(struct ice_hw *hw)
}
/* Check that the control word indicates validity */
- if ((ctrl_word & ICE_SR_CTRL_WORD_1_M) >> ICE_SR_CTRL_WORD_1_S != ICE_SR_CTRL_WORD_VALID) {
+ if (FIELD_GET(ICE_SR_CTRL_WORD_1_M, ctrl_word) !=
+ ICE_SR_CTRL_WORD_VALID) {
ice_debug(hw, ICE_DBG_NVM, "Shadow RAM control word is invalid\n");
return -EIO;
}
@@ -1027,7 +1028,7 @@ int ice_init_nvm(struct ice_hw *hw)
* as the blank mode may be used in the factory line.
*/
gens_stat = rd32(hw, GLNVM_GENS);
- sr_size = (gens_stat & GLNVM_GENS_SR_SIZE_M) >> GLNVM_GENS_SR_SIZE_S;
+ sr_size = FIELD_GET(GLNVM_GENS_SR_SIZE_M, gens_stat);
/* Switching to words (sr_size contains power of 2) */
flash->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB;
diff --git a/drivers/net/ethernet/intel/ice/ice_osdep.h b/drivers/net/ethernet/intel/ice/ice_osdep.h
index 82bc54fec7f3..a2562f04267f 100644
--- a/drivers/net/ethernet/intel/ice/ice_osdep.h
+++ b/drivers/net/ethernet/intel/ice/ice_osdep.h
@@ -24,7 +24,7 @@
#define rd64(a, reg) readq((a)->hw_addr + (reg))
#define ice_flush(a) rd32((a), GLGEN_STAT)
-#define ICE_M(m, s) ((m) << (s))
+#define ICE_M(m, s) ((m ## U) << (s))
struct ice_dma_mem {
void *va;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index 71f405f8a6fe..3b6605c8585e 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -7,7 +7,7 @@
#define E810_OUT_PROP_DELAY_NS 1
-#define UNKNOWN_INCVAL_E822 0x100000000ULL
+#define UNKNOWN_INCVAL_E82X 0x100000000ULL
static const struct ptp_pin_desc ice_pin_desc_e810t[] = {
/* name idx func chan */
@@ -525,6 +525,119 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
}
/**
+ * ice_ptp_req_tx_single_tstamp - Request Tx timestamp for a port from FW
+ * @tx: the PTP Tx timestamp tracker
+ * @idx: index of the timestamp to request
+ */
+void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
+{
+ struct ice_ptp_port *ptp_port;
+ struct sk_buff *skb;
+ struct ice_pf *pf;
+
+ if (!tx->init)
+ return;
+
+ ptp_port = container_of(tx, struct ice_ptp_port, tx);
+ pf = ptp_port_to_pf(ptp_port);
+
+ /* Drop packets which have waited for more than 2 seconds */
+ if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
+ /* Count the number of Tx timestamps that timed out */
+ pf->ptp.tx_hwtstamp_timeouts++;
+
+ skb = tx->tstamps[idx].skb;
+ tx->tstamps[idx].skb = NULL;
+ clear_bit(idx, tx->in_use);
+
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ ice_trace(tx_tstamp_fw_req, tx->tstamps[idx].skb, idx);
+
+ /* Write TS index to read to the PF register so the FW can read it */
+ wr32(&pf->hw, PF_SB_ATQBAL,
+ TS_LL_READ_TS_INTR | FIELD_PREP(TS_LL_READ_TS_IDX, idx) |
+ TS_LL_READ_TS);
+ tx->last_ll_ts_idx_read = idx;
+}
+
+/**
+ * ice_ptp_complete_tx_single_tstamp - Complete Tx timestamp for a port
+ * @tx: the PTP Tx timestamp tracker
+ */
+void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx)
+{
+ struct skb_shared_hwtstamps shhwtstamps = {};
+ u8 idx = tx->last_ll_ts_idx_read;
+ struct ice_ptp_port *ptp_port;
+ u64 raw_tstamp, tstamp;
+ bool drop_ts = false;
+ struct sk_buff *skb;
+ struct ice_pf *pf;
+ u32 val;
+
+ if (!tx->init || tx->last_ll_ts_idx_read < 0)
+ return;
+
+ ptp_port = container_of(tx, struct ice_ptp_port, tx);
+ pf = ptp_port_to_pf(ptp_port);
+
+ ice_trace(tx_tstamp_fw_done, tx->tstamps[idx].skb, idx);
+
+ val = rd32(&pf->hw, PF_SB_ATQBAL);
+
+ /* When the bit is cleared, the TS is ready in the register */
+ if (val & TS_LL_READ_TS) {
+ dev_err(ice_pf_to_dev(pf), "Failed to get the Tx tstamp - FW not ready");
+ return;
+ }
+
+ /* High 8 bit value of the TS is on the bits 16:23 */
+ raw_tstamp = FIELD_GET(TS_LL_READ_TS_HIGH, val);
+ raw_tstamp <<= 32;
+
+ /* Read the low 32 bit value */
+ raw_tstamp |= (u64)rd32(&pf->hw, PF_SB_ATQBAH);
+
+ /* For PHYs which don't implement a proper timestamp ready bitmap,
+ * verify that the timestamp value is different from the last cached
+ * timestamp. If it is not, skip this for now assuming it hasn't yet
+ * been captured by hardware.
+ */
+ if (!drop_ts && tx->verify_cached &&
+ raw_tstamp == tx->tstamps[idx].cached_tstamp)
+ return;
+
+ if (tx->verify_cached && raw_tstamp)
+ tx->tstamps[idx].cached_tstamp = raw_tstamp;
+ clear_bit(idx, tx->in_use);
+ skb = tx->tstamps[idx].skb;
+ tx->tstamps[idx].skb = NULL;
+ if (test_and_clear_bit(idx, tx->stale))
+ drop_ts = true;
+
+ if (!skb)
+ return;
+
+ if (drop_ts) {
+ dev_kfree_skb_any(skb);
+ return;
+ }
+
+ /* Extend the timestamp using cached PHC time */
+ tstamp = ice_ptp_extend_40b_ts(pf, raw_tstamp);
+ if (tstamp) {
+ shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
+ ice_trace(tx_tstamp_complete, skb, idx);
+ }
+
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
+}
+
+/**
* ice_ptp_process_tx_tstamp - Process Tx timestamps for a port
* @tx: the PTP Tx timestamp tracker
*
@@ -575,6 +688,7 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
{
struct ice_ptp_port *ptp_port;
+ unsigned long flags;
struct ice_pf *pf;
struct ice_hw *hw;
u64 tstamp_ready;
@@ -646,7 +760,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
drop_ts = true;
skip_ts_read:
- spin_lock(&tx->lock);
+ spin_lock_irqsave(&tx->lock, flags);
if (tx->verify_cached && raw_tstamp)
tx->tstamps[idx].cached_tstamp = raw_tstamp;
clear_bit(idx, tx->in_use);
@@ -654,7 +768,7 @@ skip_ts_read:
tx->tstamps[idx].skb = NULL;
if (test_and_clear_bit(idx, tx->stale))
drop_ts = true;
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
/* It is unlikely but possible that the SKB will have been
* flushed at this point due to link change or teardown.
@@ -705,7 +819,9 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
/* Read the Tx ready status first */
err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
- if (err || tstamp_ready)
+ if (err)
+ break;
+ else if (tstamp_ready)
return ICE_TX_TSTAMP_WORK_PENDING;
}
@@ -722,6 +838,7 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
{
bool more_timestamps;
+ unsigned long flags;
if (!tx->init)
return ICE_TX_TSTAMP_WORK_DONE;
@@ -730,9 +847,9 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
ice_ptp_process_tx_tstamp(tx);
/* Check if there are outstanding Tx timestamps */
- spin_lock(&tx->lock);
+ spin_lock_irqsave(&tx->lock, flags);
more_timestamps = tx->init && !bitmap_empty(tx->in_use, tx->len);
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
if (more_timestamps)
return ICE_TX_TSTAMP_WORK_PENDING;
@@ -769,6 +886,7 @@ ice_ptp_alloc_tx_tracker(struct ice_ptp_tx *tx)
tx->in_use = in_use;
tx->stale = stale;
tx->init = 1;
+ tx->last_ll_ts_idx_read = -1;
spin_lock_init(&tx->lock);
@@ -786,6 +904,7 @@ static void
ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
{
struct ice_hw *hw = &pf->hw;
+ unsigned long flags;
u64 tstamp_ready;
int err;
u8 idx;
@@ -809,12 +928,12 @@ ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
if (!hw->reset_ongoing && (tstamp_ready & BIT_ULL(phy_idx)))
ice_clear_phy_tstamp(hw, tx->block, phy_idx);
- spin_lock(&tx->lock);
+ spin_lock_irqsave(&tx->lock, flags);
skb = tx->tstamps[idx].skb;
tx->tstamps[idx].skb = NULL;
clear_bit(idx, tx->in_use);
clear_bit(idx, tx->stale);
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
/* Count the number of Tx timestamps flushed */
pf->ptp.tx_hwtstamp_flushed++;
@@ -838,9 +957,11 @@ ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
static void
ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx)
{
- spin_lock(&tx->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
bitmap_or(tx->stale, tx->stale, tx->in_use, tx->len);
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
}
/**
@@ -853,9 +974,11 @@ ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx)
static void
ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
{
- spin_lock(&tx->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
tx->init = 0;
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
/* wait for potentially outstanding interrupt to complete */
synchronize_irq(pf->oicr_irq.virq);
@@ -875,7 +998,7 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
}
/**
- * ice_ptp_init_tx_e822 - Initialize tracking for Tx timestamps
+ * ice_ptp_init_tx_e82x - Initialize tracking for Tx timestamps
* @pf: Board private structure
* @tx: the Tx tracking structure to initialize
* @port: the port this structure tracks
@@ -886,11 +1009,11 @@ ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
* registers into chunks based on the port number.
*/
static int
-ice_ptp_init_tx_e822(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port)
+ice_ptp_init_tx_e82x(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port)
{
tx->block = port / ICE_PORTS_PER_QUAD;
- tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E822;
- tx->len = INDEX_PER_PORT_E822;
+ tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E82X;
+ tx->len = INDEX_PER_PORT_E82X;
tx->verify_cached = 0;
return ice_ptp_alloc_tx_tracker(tx);
@@ -1093,10 +1216,10 @@ static u64 ice_base_incval(struct ice_pf *pf)
if (ice_is_e810(hw))
incval = ICE_PTP_NOMINAL_INCVAL_E810;
- else if (ice_e822_time_ref(hw) < NUM_ICE_TIME_REF_FREQ)
- incval = ice_e822_nominal_incval(ice_e822_time_ref(hw));
+ else if (ice_e82x_time_ref(hw) < NUM_ICE_TIME_REF_FREQ)
+ incval = ice_e82x_nominal_incval(ice_e82x_time_ref(hw));
else
- incval = UNKNOWN_INCVAL_E822;
+ incval = UNKNOWN_INCVAL_E82X;
dev_dbg(ice_pf_to_dev(pf), "PTP: using base increment value of 0x%016llx\n",
incval);
@@ -1125,10 +1248,10 @@ static int ice_ptp_check_tx_fifo(struct ice_ptp_port *port)
/* need to read FIFO state */
if (offs == 0 || offs == 1)
- err = ice_read_quad_reg_e822(hw, quad, Q_REG_FIFO01_STATUS,
+ err = ice_read_quad_reg_e82x(hw, quad, Q_REG_FIFO01_STATUS,
&val);
else
- err = ice_read_quad_reg_e822(hw, quad, Q_REG_FIFO23_STATUS,
+ err = ice_read_quad_reg_e82x(hw, quad, Q_REG_FIFO23_STATUS,
&val);
if (err) {
@@ -1138,9 +1261,9 @@ static int ice_ptp_check_tx_fifo(struct ice_ptp_port *port)
}
if (offs & 0x1)
- phy_sts = (val & Q_REG_FIFO13_M) >> Q_REG_FIFO13_S;
+ phy_sts = FIELD_GET(Q_REG_FIFO13_M, val);
else
- phy_sts = (val & Q_REG_FIFO02_M) >> Q_REG_FIFO02_S;
+ phy_sts = FIELD_GET(Q_REG_FIFO02_M, val);
if (phy_sts & FIFO_EMPTY) {
port->tx_fifo_busy_cnt = FIFO_OK;
@@ -1156,7 +1279,7 @@ static int ice_ptp_check_tx_fifo(struct ice_ptp_port *port)
dev_dbg(ice_pf_to_dev(pf),
"Port %d Tx FIFO still not empty; resetting quad %d\n",
port->port_num, quad);
- ice_ptp_reset_ts_memory_quad_e822(hw, quad);
+ ice_ptp_reset_ts_memory_quad_e82x(hw, quad);
port->tx_fifo_busy_cnt = FIFO_OK;
return 0;
}
@@ -1201,8 +1324,8 @@ static void ice_ptp_wait_for_offsets(struct kthread_work *work)
tx_err = ice_ptp_check_tx_fifo(port);
if (!tx_err)
- tx_err = ice_phy_cfg_tx_offset_e822(hw, port->port_num);
- rx_err = ice_phy_cfg_rx_offset_e822(hw, port->port_num);
+ tx_err = ice_phy_cfg_tx_offset_e82x(hw, port->port_num);
+ rx_err = ice_phy_cfg_rx_offset_e82x(hw, port->port_num);
if (tx_err || rx_err) {
/* Tx and/or Rx offset not yet configured, try again later */
kthread_queue_delayed_work(pf->ptp.kworker,
@@ -1231,7 +1354,7 @@ ice_ptp_port_phy_stop(struct ice_ptp_port *ptp_port)
kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
- err = ice_stop_phy_timer_e822(hw, port, true);
+ err = ice_stop_phy_timer_e82x(hw, port, true);
if (err)
dev_err(ice_pf_to_dev(pf), "PTP failed to set PHY port %d down, err %d\n",
port, err);
@@ -1255,6 +1378,7 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
struct ice_pf *pf = ptp_port_to_pf(ptp_port);
u8 port = ptp_port->port_num;
struct ice_hw *hw = &pf->hw;
+ unsigned long flags;
int err;
if (ice_is_e810(hw))
@@ -1268,20 +1392,20 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
/* temporarily disable Tx timestamps while calibrating PHY offset */
- spin_lock(&ptp_port->tx.lock);
+ spin_lock_irqsave(&ptp_port->tx.lock, flags);
ptp_port->tx.calibrating = true;
- spin_unlock(&ptp_port->tx.lock);
+ spin_unlock_irqrestore(&ptp_port->tx.lock, flags);
ptp_port->tx_fifo_busy_cnt = 0;
/* Start the PHY timer in Vernier mode */
- err = ice_start_phy_timer_e822(hw, port);
+ err = ice_start_phy_timer_e82x(hw, port);
if (err)
goto out_unlock;
/* Enable Tx timestamps right away */
- spin_lock(&ptp_port->tx.lock);
+ spin_lock_irqsave(&ptp_port->tx.lock, flags);
ptp_port->tx.calibrating = false;
- spin_unlock(&ptp_port->tx.lock);
+ spin_unlock_irqrestore(&ptp_port->tx.lock, flags);
kthread_queue_delayed_work(pf->ptp.kworker, &ptp_port->ov_work, 0);
@@ -1323,7 +1447,7 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup)
case ICE_PHY_E810:
/* Do not reconfigure E810 PHY */
return;
- case ICE_PHY_E822:
+ case ICE_PHY_E82X:
ice_ptp_port_phy_restart(ptp_port);
return;
default:
@@ -1349,7 +1473,7 @@ static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold)
ice_ptp_reset_ts_memory(hw);
for (quad = 0; quad < ICE_MAX_QUAD; quad++) {
- err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG,
+ err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG,
&val);
if (err)
break;
@@ -1357,13 +1481,13 @@ static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold)
if (ena) {
val |= Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M;
val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_THR_M;
- val |= ((threshold << Q_REG_TX_MEM_GBL_CFG_INTR_THR_S) &
- Q_REG_TX_MEM_GBL_CFG_INTR_THR_M);
+ val |= FIELD_PREP(Q_REG_TX_MEM_GBL_CFG_INTR_THR_M,
+ threshold);
} else {
val &= ~Q_REG_TX_MEM_GBL_CFG_INTR_ENA_M;
}
- err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG,
+ err = ice_write_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG,
val);
if (err)
break;
@@ -1503,8 +1627,7 @@ ice_ptp_cfg_extts(struct ice_pf *pf, bool ena, unsigned int chan, u32 gpio_pin,
* + num_in_channels * tmr_idx
*/
func = 1 + chan + (tmr_idx * 3);
- gpio_reg = ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) &
- GLGEN_GPIO_CTL_PIN_FUNC_M);
+ gpio_reg = FIELD_PREP(GLGEN_GPIO_CTL_PIN_FUNC_M, func);
pf->ptp.ext_ts_chan |= (1 << chan);
} else {
/* clear the values we set to reset defaults */
@@ -1601,7 +1724,7 @@ static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan,
if (ice_is_e810(hw))
start_time -= E810_OUT_PROP_DELAY_NS;
else
- start_time -= ice_e822_pps_delay(ice_e822_time_ref(hw));
+ start_time -= ice_e82x_pps_delay(ice_e82x_time_ref(hw));
/* 2. Write TARGET time */
wr32(hw, GLTSYN_TGT_L(chan, tmr_idx), lower_32_bits(start_time));
@@ -1614,7 +1737,7 @@ static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan,
/* 4. write GPIO CTL reg */
func = 8 + chan + (tmr_idx * 4);
val = GLGEN_GPIO_CTL_PIN_DIR_M |
- ((func << GLGEN_GPIO_CTL_PIN_FUNC_S) & GLGEN_GPIO_CTL_PIN_FUNC_M);
+ FIELD_PREP(GLGEN_GPIO_CTL_PIN_FUNC_M, func);
wr32(hw, GLGEN_GPIO_CTL(gpio_pin), val);
/* Store the value if requested */
@@ -1840,7 +1963,7 @@ ice_ptp_settime64(struct ptp_clock_info *info, const struct timespec64 *ts)
ice_ptp_enable_all_clkout(pf);
/* Recalibrate and re-enable timestamp blocks for E822/E823 */
- if (hw->phy_model == ICE_PHY_E822)
+ if (hw->phy_model == ICE_PHY_E82X)
ice_ptp_restart_all_phy(pf);
exit:
if (err) {
@@ -2127,30 +2250,26 @@ int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr)
}
/**
- * ice_ptp_rx_hwtstamp - Check for an Rx timestamp
- * @rx_ring: Ring to get the VSI info
+ * ice_ptp_get_rx_hwts - Get packet Rx timestamp in ns
* @rx_desc: Receive descriptor
- * @skb: Particular skb to send timestamp with
+ * @pkt_ctx: Packet context to get the cached time
*
* The driver receives a notification in the receive descriptor with timestamp.
- * The timestamp is in ns, so we must convert the result first.
*/
-void
-ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring,
- union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb)
+u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc,
+ const struct ice_pkt_ctx *pkt_ctx)
{
- struct skb_shared_hwtstamps *hwtstamps;
u64 ts_ns, cached_time;
u32 ts_high;
if (!(rx_desc->wb.time_stamp_low & ICE_PTP_TS_VALID))
- return;
+ return 0;
- cached_time = READ_ONCE(rx_ring->cached_phctime);
+ cached_time = READ_ONCE(pkt_ctx->cached_phctime);
/* Do not report a timestamp if we don't have a cached PHC time */
if (!cached_time)
- return;
+ return 0;
/* Use ice_ptp_extend_32b_ts directly, using the ring-specific cached
* PHC value, rather than accessing the PF. This also allows us to
@@ -2161,9 +2280,7 @@ ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring,
ts_high = le32_to_cpu(rx_desc->wb.flex_ts.ts_high);
ts_ns = ice_ptp_extend_32b_ts(cached_time, ts_high);
- hwtstamps = skb_hwtstamps(skb);
- memset(hwtstamps, 0, sizeof(*hwtstamps));
- hwtstamps->hwtstamp = ns_to_ktime(ts_ns);
+ return ts_ns;
}
/**
@@ -2378,18 +2495,23 @@ static long ice_ptp_create_clock(struct ice_pf *pf)
*/
s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
{
+ unsigned long flags;
u8 idx;
- spin_lock(&tx->lock);
+ spin_lock_irqsave(&tx->lock, flags);
/* Check that this tracker is accepting new timestamp requests */
if (!ice_ptp_is_tx_tracker_up(tx)) {
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
return -1;
}
/* Find and set the first available index */
- idx = find_first_zero_bit(tx->in_use, tx->len);
+ idx = find_next_zero_bit(tx->in_use, tx->len,
+ tx->last_ll_ts_idx_read + 1);
+ if (idx == tx->len)
+ idx = find_first_zero_bit(tx->in_use, tx->len);
+
if (idx < tx->len) {
/* We got a valid index that no other thread could have set. Store
* a reference to the skb and the start time to allow discarding old
@@ -2403,7 +2525,7 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
ice_trace(tx_tstamp_request, skb, idx);
}
- spin_unlock(&tx->lock);
+ spin_unlock_irqrestore(&tx->lock, flags);
/* return the appropriate PHY timestamp register index, -1 if no
* indexes were available.
@@ -2440,6 +2562,54 @@ enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf)
}
}
+/**
+ * ice_ptp_maybe_trigger_tx_interrupt - Trigger Tx timstamp interrupt
+ * @pf: Board private structure
+ *
+ * The device PHY issues Tx timestamp interrupts to the driver for processing
+ * timestamp data from the PHY. It will not interrupt again until all
+ * current timestamp data is read. In rare circumstances, it is possible that
+ * the driver fails to read all outstanding data.
+ *
+ * To avoid getting permanently stuck, periodically check if the PHY has
+ * outstanding timestamp data. If so, trigger an interrupt from software to
+ * process this data.
+ */
+static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct ice_hw *hw = &pf->hw;
+ bool trigger_oicr = false;
+ unsigned int i;
+
+ if (ice_is_e810(hw))
+ return;
+
+ if (!ice_pf_src_tmr_owned(pf))
+ return;
+
+ for (i = 0; i < ICE_MAX_QUAD; i++) {
+ u64 tstamp_ready;
+ int err;
+
+ err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready);
+ if (!err && tstamp_ready) {
+ trigger_oicr = true;
+ break;
+ }
+ }
+
+ if (trigger_oicr) {
+ /* Trigger a software interrupt, to ensure this data
+ * gets processed.
+ */
+ dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n");
+
+ wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
+ ice_flush(hw);
+ }
+}
+
static void ice_ptp_periodic_work(struct kthread_work *work)
{
struct ice_ptp *ptp = container_of(work, struct ice_ptp, work.work);
@@ -2451,6 +2621,8 @@ static void ice_ptp_periodic_work(struct kthread_work *work)
err = ice_ptp_update_cached_phctime(pf);
+ ice_ptp_maybe_trigger_tx_interrupt(pf);
+
/* Run twice a second or reschedule if phc update failed */
kthread_queue_delayed_work(ptp->kworker, &ptp->work,
msecs_to_jiffies(err ? 10 : 500));
@@ -2468,12 +2640,10 @@ void ice_ptp_reset(struct ice_pf *pf)
int err, itr = 1;
u64 time_diff;
- if (test_bit(ICE_PFR_REQ, pf->state))
+ if (test_bit(ICE_PFR_REQ, pf->state) ||
+ !ice_pf_src_tmr_owned(pf))
goto pfr;
- if (!ice_pf_src_tmr_owned(pf))
- goto reset_ts;
-
err = ice_ptp_init_phc(hw);
if (err)
goto err;
@@ -2517,10 +2687,6 @@ void ice_ptp_reset(struct ice_pf *pf)
goto err;
}
-reset_ts:
- /* Restart the PHY timestamping block */
- ice_ptp_reset_phy_timestamping(pf);
-
pfr:
/* Init Tx structures */
if (ice_is_e810(&pf->hw)) {
@@ -2528,7 +2694,7 @@ pfr:
} else {
kthread_init_delayed_work(&ptp->port.ov_work,
ice_ptp_wait_for_offsets);
- err = ice_ptp_init_tx_e822(pf, &ptp->port.tx,
+ err = ice_ptp_init_tx_e82x(pf, &ptp->port.tx,
ptp->port.port_num);
}
if (err)
@@ -2536,6 +2702,11 @@ pfr:
set_bit(ICE_FLAG_PTP, pf->flags);
+ /* Restart the PHY timestamping block */
+ if (!test_bit(ICE_PFR_REQ, pf->state) &&
+ ice_pf_src_tmr_owned(pf))
+ ice_ptp_restart_all_phy(pf);
+
/* Start periodic work going */
kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0);
@@ -2692,6 +2863,8 @@ static int ice_ptp_register_auxbus_driver(struct ice_pf *pf)
name = devm_kasprintf(dev, GFP_KERNEL, "ptp_aux_dev_%u_%u_clk%u",
pf->pdev->bus->number, PCI_SLOT(pf->pdev->devfn),
ice_get_ptp_src_clock_index(&pf->hw));
+ if (!name)
+ return -ENOMEM;
aux_driver->name = name;
aux_driver->shutdown = ice_ptp_auxbus_shutdown;
@@ -2896,11 +3069,11 @@ static int ice_ptp_init_port(struct ice_pf *pf, struct ice_ptp_port *ptp_port)
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_ptp_init_tx_e810(pf, &ptp_port->tx);
- case ICE_PHY_E822:
+ case ICE_PHY_E82X:
kthread_init_delayed_work(&ptp_port->ov_work,
ice_ptp_wait_for_offsets);
- return ice_ptp_init_tx_e822(pf, &ptp_port->tx,
+ return ice_ptp_init_tx_e82x(pf, &ptp_port->tx,
ptp_port->port_num);
default:
return -ENODEV;
@@ -2938,6 +3111,8 @@ static int ice_ptp_create_auxbus_device(struct ice_pf *pf)
name = devm_kasprintf(dev, GFP_KERNEL, "ptp_aux_dev_%u_%u_clk%u",
pf->pdev->bus->number, PCI_SLOT(pf->pdev->devfn),
ice_get_ptp_src_clock_index(&pf->hw));
+ if (!name)
+ return -ENOMEM;
aux_dev->name = name;
aux_dev->id = id;
@@ -2987,7 +3162,7 @@ static void ice_ptp_remove_auxbus_device(struct ice_pf *pf)
static void ice_ptp_init_tx_interrupt_mode(struct ice_pf *pf)
{
switch (pf->hw.phy_model) {
- case ICE_PHY_E822:
+ case ICE_PHY_E82X:
/* E822 based PHY has the clock owner process the interrupt
* for all ports.
*/
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h
index 06a330867fc9..087dd32d8762 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.h
@@ -131,6 +131,7 @@ enum ice_tx_tstamp_work {
* @calibrating: if true, the PHY is calibrating the Tx offset. During this
* window, timestamps are temporarily disabled.
* @verify_cached: if true, verify new timestamp differs from last read value
+ * @last_ll_ts_idx_read: index of the last LL TS read by the FW
*/
struct ice_ptp_tx {
spinlock_t lock; /* lock protecting in_use bitmap */
@@ -143,11 +144,12 @@ struct ice_ptp_tx {
u8 init : 1;
u8 calibrating : 1;
u8 verify_cached : 1;
+ s8 last_ll_ts_idx_read;
};
/* Quad and port information for initializing timestamp blocks */
#define INDEX_PER_QUAD 64
-#define INDEX_PER_PORT_E822 16
+#define INDEX_PER_PORT_E82X 16
#define INDEX_PER_PORT_E810 64
/**
@@ -296,11 +298,12 @@ void ice_ptp_restore_timestamp_mode(struct ice_pf *pf);
void ice_ptp_extts_event(struct ice_pf *pf);
s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb);
+void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx);
+void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx);
enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf);
-void
-ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring,
- union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb);
+u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc,
+ const struct ice_pkt_ctx *pkt_ctx);
void ice_ptp_reset(struct ice_pf *pf);
void ice_ptp_prepare_for_reset(struct ice_pf *pf);
void ice_ptp_init(struct ice_pf *pf);
@@ -325,13 +328,23 @@ ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
return -1;
}
+static inline void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
+{ }
+
+static inline void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) { }
+
static inline bool ice_ptp_process_ts(struct ice_pf *pf)
{
return true;
}
-static inline void
-ice_ptp_rx_hwtstamp(struct ice_rx_ring *rx_ring,
- union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb) { }
+
+static inline u64
+ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc,
+ const struct ice_pkt_ctx *pkt_ctx)
+{
+ return 0;
+}
+
static inline void ice_ptp_reset(struct ice_pf *pf) { }
static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf) { }
static inline void ice_ptp_init(struct ice_pf *pf) { }
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
index 4109aa3b2fcd..2c4dab0c48ab 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_consts.h
@@ -9,17 +9,17 @@
*/
/* Constants defined for the PTP 1588 clock hardware. */
-/* struct ice_time_ref_info_e822
+/* struct ice_time_ref_info_e82x
*
* E822 hardware can use different sources as the reference for the PTP
* hardware clock. Each clock has different characteristics such as a slightly
* different frequency, etc.
*
* This lookup table defines several constants that depend on the current time
- * reference. See the struct ice_time_ref_info_e822 for information about the
+ * reference. See the struct ice_time_ref_info_e82x for information about the
* meaning of each constant.
*/
-const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ] = {
+const struct ice_time_ref_info_e82x e822_time_ref[NUM_ICE_TIME_REF_FREQ] = {
/* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */
{
/* pll_freq */
@@ -81,7 +81,7 @@ const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ] = {
},
};
-const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = {
+const struct ice_cgu_pll_params_e82x e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = {
/* ICE_TIME_REF_FREQ_25_000 -> 25 MHz */
{
/* refclk_pre_div */
@@ -155,7 +155,7 @@ const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = {
},
};
-/* struct ice_vernier_info_e822
+/* struct ice_vernier_info_e82x
*
* E822 hardware calibrates the delay of the timestamp indication from the
* actual packet transmission or reception during the initialization of the
@@ -168,7 +168,7 @@ const struct ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ] = {
* used by this link speed, and that the register should be cleared by writing
* 0. Other values specify the clock frequency in Hz.
*/
-const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD] = {
+const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD] = {
/* ICE_PTP_LNK_SPD_1G */
{
/* tx_par_clk */
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
index a00b55e14aac..187ce9b54e1a 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
@@ -284,19 +284,19 @@ static void ice_ptp_exec_tmr_cmd(struct ice_hw *hw)
*/
/**
- * ice_fill_phy_msg_e822 - Fill message data for a PHY register access
+ * ice_fill_phy_msg_e82x - Fill message data for a PHY register access
* @msg: the PHY message buffer to fill in
* @port: the port to access
* @offset: the register offset
*/
static void
-ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
+ice_fill_phy_msg_e82x(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
{
int phy_port, phy, quadtype;
- phy_port = port % ICE_PORTS_PER_PHY_E822;
- phy = port / ICE_PORTS_PER_PHY_E822;
- quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_QUADS_PER_PHY_E822;
+ phy_port = port % ICE_PORTS_PER_PHY_E82X;
+ phy = port / ICE_PORTS_PER_PHY_E82X;
+ quadtype = (port / ICE_PORTS_PER_QUAD) % ICE_QUADS_PER_PHY_E82X;
if (quadtype == 0) {
msg->msg_addr_low = P_Q0_L(P_0_BASE + offset, phy_port);
@@ -315,7 +315,7 @@ ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
}
/**
- * ice_is_64b_phy_reg_e822 - Check if this is a 64bit PHY register
+ * ice_is_64b_phy_reg_e82x - Check if this is a 64bit PHY register
* @low_addr: the low address to check
* @high_addr: on return, contains the high address of the 64bit register
*
@@ -323,7 +323,7 @@ ice_fill_phy_msg_e822(struct ice_sbq_msg_input *msg, u8 port, u16 offset)
* represented as two 32bit registers. If it is, return the appropriate high
* register offset to use.
*/
-static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
+static bool ice_is_64b_phy_reg_e82x(u16 low_addr, u16 *high_addr)
{
switch (low_addr) {
case P_REG_PAR_PCS_TX_OFFSET_L:
@@ -368,7 +368,7 @@ static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
}
/**
- * ice_is_40b_phy_reg_e822 - Check if this is a 40bit PHY register
+ * ice_is_40b_phy_reg_e82x - Check if this is a 40bit PHY register
* @low_addr: the low address to check
* @high_addr: on return, contains the high address of the 40bit value
*
@@ -377,7 +377,7 @@ static bool ice_is_64b_phy_reg_e822(u16 low_addr, u16 *high_addr)
* upper 32 bits in the high register. If it is, return the appropriate high
* register offset to use.
*/
-static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
+static bool ice_is_40b_phy_reg_e82x(u16 low_addr, u16 *high_addr)
{
switch (low_addr) {
case P_REG_TIMETUS_L:
@@ -413,7 +413,7 @@ static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
}
/**
- * ice_read_phy_reg_e822 - Read a PHY register
+ * ice_read_phy_reg_e82x - Read a PHY register
* @hw: pointer to the HW struct
* @port: PHY port to read from
* @offset: PHY register offset to read
@@ -422,12 +422,12 @@ static bool ice_is_40b_phy_reg_e822(u16 low_addr, u16 *high_addr)
* Read a PHY register for the given port over the device sideband queue.
*/
static int
-ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
+ice_read_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
{
struct ice_sbq_msg_input msg = {0};
int err;
- ice_fill_phy_msg_e822(&msg, port, offset);
+ ice_fill_phy_msg_e82x(&msg, port, offset);
msg.opcode = ice_sbq_msg_rd;
err = ice_sbq_rw_reg(hw, &msg);
@@ -443,7 +443,7 @@ ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
}
/**
- * ice_read_64b_phy_reg_e822 - Read a 64bit value from PHY registers
+ * ice_read_64b_phy_reg_e82x - Read a 64bit value from PHY registers
* @hw: pointer to the HW struct
* @port: PHY port to read from
* @low_addr: offset of the lower register to read from
@@ -455,7 +455,7 @@ ice_read_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 *val)
* known to be two parts of a 64bit value.
*/
static int
-ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
+ice_read_64b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
{
u32 low, high;
u16 high_addr;
@@ -464,20 +464,20 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
/* Only operate on registers known to be split into two 32bit
* registers.
*/
- if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
+ if (!ice_is_64b_phy_reg_e82x(low_addr, &high_addr)) {
ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
low_addr);
return -EINVAL;
}
- err = ice_read_phy_reg_e822(hw, port, low_addr, &low);
+ err = ice_read_phy_reg_e82x(hw, port, low_addr, &low);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read from low register 0x%08x\n, err %d",
low_addr, err);
return err;
}
- err = ice_read_phy_reg_e822(hw, port, high_addr, &high);
+ err = ice_read_phy_reg_e82x(hw, port, high_addr, &high);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read from high register 0x%08x\n, err %d",
high_addr, err);
@@ -490,7 +490,7 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
}
/**
- * ice_write_phy_reg_e822 - Write a PHY register
+ * ice_write_phy_reg_e82x - Write a PHY register
* @hw: pointer to the HW struct
* @port: PHY port to write to
* @offset: PHY register offset to write
@@ -499,12 +499,12 @@ ice_read_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 *val)
* Write a PHY register for the given port over the device sideband queue.
*/
static int
-ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
+ice_write_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 offset, u32 val)
{
struct ice_sbq_msg_input msg = {0};
int err;
- ice_fill_phy_msg_e822(&msg, port, offset);
+ ice_fill_phy_msg_e82x(&msg, port, offset);
msg.opcode = ice_sbq_msg_wr;
msg.data = val;
@@ -519,7 +519,7 @@ ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
}
/**
- * ice_write_40b_phy_reg_e822 - Write a 40b value to the PHY
+ * ice_write_40b_phy_reg_e82x - Write a 40b value to the PHY
* @hw: pointer to the HW struct
* @port: port to write to
* @low_addr: offset of the low register
@@ -529,7 +529,7 @@ ice_write_phy_reg_e822(struct ice_hw *hw, u8 port, u16 offset, u32 val)
* it up into two chunks, the lower 8 bits and the upper 32 bits.
*/
static int
-ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
+ice_write_40b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
{
u32 low, high;
u16 high_addr;
@@ -538,7 +538,7 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
/* Only operate on registers known to be split into a lower 8 bit
* register and an upper 32 bit register.
*/
- if (!ice_is_40b_phy_reg_e822(low_addr, &high_addr)) {
+ if (!ice_is_40b_phy_reg_e82x(low_addr, &high_addr)) {
ice_debug(hw, ICE_DBG_PTP, "Invalid 40b register addr 0x%08x\n",
low_addr);
return -EINVAL;
@@ -547,14 +547,14 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
low = (u32)(val & P_REG_40B_LOW_M);
high = (u32)(val >> P_REG_40B_HIGH_S);
- err = ice_write_phy_reg_e822(hw, port, low_addr, low);
+ err = ice_write_phy_reg_e82x(hw, port, low_addr, low);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
low_addr, err);
return err;
}
- err = ice_write_phy_reg_e822(hw, port, high_addr, high);
+ err = ice_write_phy_reg_e82x(hw, port, high_addr, high);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
high_addr, err);
@@ -565,7 +565,7 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
}
/**
- * ice_write_64b_phy_reg_e822 - Write a 64bit value to PHY registers
+ * ice_write_64b_phy_reg_e82x - Write a 64bit value to PHY registers
* @hw: pointer to the HW struct
* @port: PHY port to read from
* @low_addr: offset of the lower register to read from
@@ -577,7 +577,7 @@ ice_write_40b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
* a 64bit value.
*/
static int
-ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
+ice_write_64b_phy_reg_e82x(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
{
u32 low, high;
u16 high_addr;
@@ -586,7 +586,7 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
/* Only operate on registers known to be split into two 32bit
* registers.
*/
- if (!ice_is_64b_phy_reg_e822(low_addr, &high_addr)) {
+ if (!ice_is_64b_phy_reg_e82x(low_addr, &high_addr)) {
ice_debug(hw, ICE_DBG_PTP, "Invalid 64b register addr 0x%08x\n",
low_addr);
return -EINVAL;
@@ -595,14 +595,14 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
low = lower_32_bits(val);
high = upper_32_bits(val);
- err = ice_write_phy_reg_e822(hw, port, low_addr, low);
+ err = ice_write_phy_reg_e82x(hw, port, low_addr, low);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write to low register 0x%08x\n, err %d",
low_addr, err);
return err;
}
- err = ice_write_phy_reg_e822(hw, port, high_addr, high);
+ err = ice_write_phy_reg_e82x(hw, port, high_addr, high);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write to high register 0x%08x\n, err %d",
high_addr, err);
@@ -613,7 +613,7 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
}
/**
- * ice_fill_quad_msg_e822 - Fill message data for quad register access
+ * ice_fill_quad_msg_e82x - Fill message data for quad register access
* @msg: the PHY message buffer to fill in
* @quad: the quad to access
* @offset: the register offset
@@ -622,7 +622,7 @@ ice_write_64b_phy_reg_e822(struct ice_hw *hw, u8 port, u16 low_addr, u64 val)
* multiple PHYs.
*/
static int
-ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
+ice_fill_quad_msg_e82x(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
{
u32 addr;
@@ -631,7 +631,7 @@ ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
msg->dest_dev = rmn_0;
- if ((quad % ICE_QUADS_PER_PHY_E822) == 0)
+ if ((quad % ICE_QUADS_PER_PHY_E82X) == 0)
addr = Q_0_BASE + offset;
else
addr = Q_1_BASE + offset;
@@ -643,7 +643,7 @@ ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
}
/**
- * ice_read_quad_reg_e822 - Read a PHY quad register
+ * ice_read_quad_reg_e82x - Read a PHY quad register
* @hw: pointer to the HW struct
* @quad: quad to read from
* @offset: quad register offset to read
@@ -653,12 +653,12 @@ ice_fill_quad_msg_e822(struct ice_sbq_msg_input *msg, u8 quad, u16 offset)
* shared between multiple PHYs.
*/
int
-ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
+ice_read_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
{
struct ice_sbq_msg_input msg = {0};
int err;
- err = ice_fill_quad_msg_e822(&msg, quad, offset);
+ err = ice_fill_quad_msg_e82x(&msg, quad, offset);
if (err)
return err;
@@ -677,7 +677,7 @@ ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
}
/**
- * ice_write_quad_reg_e822 - Write a PHY quad register
+ * ice_write_quad_reg_e82x - Write a PHY quad register
* @hw: pointer to the HW struct
* @quad: quad to write to
* @offset: quad register offset to write
@@ -687,12 +687,12 @@ ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val)
* shared between multiple PHYs.
*/
int
-ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
+ice_write_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
{
struct ice_sbq_msg_input msg = {0};
int err;
- err = ice_fill_quad_msg_e822(&msg, quad, offset);
+ err = ice_fill_quad_msg_e82x(&msg, quad, offset);
if (err)
return err;
@@ -710,7 +710,7 @@ ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
}
/**
- * ice_read_phy_tstamp_e822 - Read a PHY timestamp out of the quad block
+ * ice_read_phy_tstamp_e82x - Read a PHY timestamp out of the quad block
* @hw: pointer to the HW struct
* @quad: the quad to read from
* @idx: the timestamp index to read
@@ -721,7 +721,7 @@ ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val)
* family of devices.
*/
static int
-ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
+ice_read_phy_tstamp_e82x(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
{
u16 lo_addr, hi_addr;
u32 lo, hi;
@@ -730,14 +730,14 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
lo_addr = (u16)TS_L(Q_REG_TX_MEMORY_BANK_START, idx);
hi_addr = (u16)TS_H(Q_REG_TX_MEMORY_BANK_START, idx);
- err = ice_read_quad_reg_e822(hw, quad, lo_addr, &lo);
+ err = ice_read_quad_reg_e82x(hw, quad, lo_addr, &lo);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read low PTP timestamp register, err %d\n",
err);
return err;
}
- err = ice_read_quad_reg_e822(hw, quad, hi_addr, &hi);
+ err = ice_read_quad_reg_e82x(hw, quad, hi_addr, &hi);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read high PTP timestamp register, err %d\n",
err);
@@ -754,7 +754,7 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
}
/**
- * ice_clear_phy_tstamp_e822 - Clear a timestamp from the quad block
+ * ice_clear_phy_tstamp_e82x - Clear a timestamp from the quad block
* @hw: pointer to the HW struct
* @quad: the quad to read from
* @idx: the timestamp index to reset
@@ -770,18 +770,18 @@ ice_read_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx, u64 *tstamp)
*
* To directly clear the contents of the timestamp block entirely, discarding
* all timestamp data at once, software should instead use
- * ice_ptp_reset_ts_memory_quad_e822().
+ * ice_ptp_reset_ts_memory_quad_e82x().
*
* This function should only be called on an idx whose bit is set according to
* ice_get_phy_tx_tstamp_ready().
*/
static int
-ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
+ice_clear_phy_tstamp_e82x(struct ice_hw *hw, u8 quad, u8 idx)
{
u64 unused_tstamp;
int err;
- err = ice_read_phy_tstamp_e822(hw, quad, idx, &unused_tstamp);
+ err = ice_read_phy_tstamp_e82x(hw, quad, idx, &unused_tstamp);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read the timestamp register for quad %u, idx %u, err %d\n",
quad, idx, err);
@@ -792,33 +792,33 @@ ice_clear_phy_tstamp_e822(struct ice_hw *hw, u8 quad, u8 idx)
}
/**
- * ice_ptp_reset_ts_memory_quad_e822 - Clear all timestamps from the quad block
+ * ice_ptp_reset_ts_memory_quad_e82x - Clear all timestamps from the quad block
* @hw: pointer to the HW struct
* @quad: the quad to read from
*
* Clear all timestamps from the PHY quad block that is shared between the
* internal PHYs on the E822 devices.
*/
-void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad)
+void ice_ptp_reset_ts_memory_quad_e82x(struct ice_hw *hw, u8 quad)
{
- ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M);
- ice_write_quad_reg_e822(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M);
+ ice_write_quad_reg_e82x(hw, quad, Q_REG_TS_CTRL, Q_REG_TS_CTRL_M);
+ ice_write_quad_reg_e82x(hw, quad, Q_REG_TS_CTRL, ~(u32)Q_REG_TS_CTRL_M);
}
/**
- * ice_ptp_reset_ts_memory_e822 - Clear all timestamps from all quad blocks
+ * ice_ptp_reset_ts_memory_e82x - Clear all timestamps from all quad blocks
* @hw: pointer to the HW struct
*/
-static void ice_ptp_reset_ts_memory_e822(struct ice_hw *hw)
+static void ice_ptp_reset_ts_memory_e82x(struct ice_hw *hw)
{
unsigned int quad;
for (quad = 0; quad < ICE_MAX_QUAD; quad++)
- ice_ptp_reset_ts_memory_quad_e822(hw, quad);
+ ice_ptp_reset_ts_memory_quad_e82x(hw, quad);
}
/**
- * ice_read_cgu_reg_e822 - Read a CGU register
+ * ice_read_cgu_reg_e82x - Read a CGU register
* @hw: pointer to the HW struct
* @addr: Register address to read
* @val: storage for register value read
@@ -827,7 +827,7 @@ static void ice_ptp_reset_ts_memory_e822(struct ice_hw *hw)
* applicable to E822 devices.
*/
static int
-ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
+ice_read_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 *val)
{
struct ice_sbq_msg_input cgu_msg;
int err;
@@ -850,7 +850,7 @@ ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
}
/**
- * ice_write_cgu_reg_e822 - Write a CGU register
+ * ice_write_cgu_reg_e82x - Write a CGU register
* @hw: pointer to the HW struct
* @addr: Register address to write
* @val: value to write into the register
@@ -859,7 +859,7 @@ ice_read_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 *val)
* applicable to E822 devices.
*/
static int
-ice_write_cgu_reg_e822(struct ice_hw *hw, u32 addr, u32 val)
+ice_write_cgu_reg_e82x(struct ice_hw *hw, u32 addr, u32 val)
{
struct ice_sbq_msg_input cgu_msg;
int err;
@@ -925,7 +925,7 @@ static const char *ice_clk_src_str(u8 clk_src)
}
/**
- * ice_cfg_cgu_pll_e822 - Configure the Clock Generation Unit
+ * ice_cfg_cgu_pll_e82x - Configure the Clock Generation Unit
* @hw: pointer to the HW struct
* @clk_freq: Clock frequency to program
* @clk_src: Clock source to select (TIME_REF, or TCX0)
@@ -934,7 +934,7 @@ static const char *ice_clk_src_str(u8 clk_src)
* time reference, enabling the PLL which drives the PTP hardware clock.
*/
static int
-ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
+ice_cfg_cgu_pll_e82x(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
enum ice_clk_src clk_src)
{
union tspll_ro_bwm_lf bwm_lf;
@@ -963,15 +963,15 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
return -EINVAL;
}
- err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD9, &dw9.val);
+ err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD9, &dw9.val);
if (err)
return err;
- err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
+ err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val);
if (err)
return err;
- err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
+ err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
if (err)
return err;
@@ -986,43 +986,43 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
if (dw24.field.ts_pll_enable) {
dw24.field.ts_pll_enable = 0;
- err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
+ err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
}
/* Set the frequency */
dw9.field.time_ref_freq_sel = clk_freq;
- err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD9, dw9.val);
+ err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD9, dw9.val);
if (err)
return err;
/* Configure the TS PLL feedback divisor */
- err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD19, &dw19.val);
+ err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD19, &dw19.val);
if (err)
return err;
dw19.field.tspll_fbdiv_intgr = e822_cgu_params[clk_freq].feedback_div;
dw19.field.tspll_ndivratio = 1;
- err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD19, dw19.val);
+ err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD19, dw19.val);
if (err)
return err;
/* Configure the TS PLL post divisor */
- err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD22, &dw22.val);
+ err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD22, &dw22.val);
if (err)
return err;
dw22.field.time1588clk_div = e822_cgu_params[clk_freq].post_pll_div;
dw22.field.time1588clk_sel_div2 = 0;
- err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD22, dw22.val);
+ err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD22, dw22.val);
if (err)
return err;
/* Configure the TS PLL pre divisor and clock source */
- err = ice_read_cgu_reg_e822(hw, NAC_CGU_DWORD24, &dw24.val);
+ err = ice_read_cgu_reg_e82x(hw, NAC_CGU_DWORD24, &dw24.val);
if (err)
return err;
@@ -1030,21 +1030,21 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
dw24.field.tspll_fbdiv_frac = e822_cgu_params[clk_freq].frac_n_div;
dw24.field.time_ref_sel = clk_src;
- err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
+ err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
/* Finally, enable the PLL */
dw24.field.ts_pll_enable = 1;
- err = ice_write_cgu_reg_e822(hw, NAC_CGU_DWORD24, dw24.val);
+ err = ice_write_cgu_reg_e82x(hw, NAC_CGU_DWORD24, dw24.val);
if (err)
return err;
/* Wait to verify if the PLL locks */
usleep_range(1000, 5000);
- err = ice_read_cgu_reg_e822(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
+ err = ice_read_cgu_reg_e82x(hw, TSPLL_RO_BWM_LF, &bwm_lf.val);
if (err)
return err;
@@ -1064,18 +1064,18 @@ ice_cfg_cgu_pll_e822(struct ice_hw *hw, enum ice_time_ref_freq clk_freq,
}
/**
- * ice_init_cgu_e822 - Initialize CGU with settings from firmware
+ * ice_init_cgu_e82x - Initialize CGU with settings from firmware
* @hw: pointer to the HW structure
*
* Initialize the Clock Generation Unit of the E822 device.
*/
-static int ice_init_cgu_e822(struct ice_hw *hw)
+static int ice_init_cgu_e82x(struct ice_hw *hw)
{
struct ice_ts_func_info *ts_info = &hw->func_caps.ts_func_info;
union tspll_cntr_bist_settings cntr_bist;
int err;
- err = ice_read_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
+ err = ice_read_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS,
&cntr_bist.val);
if (err)
return err;
@@ -1084,7 +1084,7 @@ static int ice_init_cgu_e822(struct ice_hw *hw)
cntr_bist.field.i_plllock_sel_0 = 0;
cntr_bist.field.i_plllock_sel_1 = 0;
- err = ice_write_cgu_reg_e822(hw, TSPLL_CNTR_BIST_SETTINGS,
+ err = ice_write_cgu_reg_e82x(hw, TSPLL_CNTR_BIST_SETTINGS,
cntr_bist.val);
if (err)
return err;
@@ -1092,7 +1092,7 @@ static int ice_init_cgu_e822(struct ice_hw *hw)
/* Configure the CGU PLL using the parameters from the function
* capabilities.
*/
- err = ice_cfg_cgu_pll_e822(hw, ts_info->time_ref,
+ err = ice_cfg_cgu_pll_e82x(hw, ts_info->time_ref,
(enum ice_clk_src)ts_info->clk_src);
if (err)
return err;
@@ -1113,7 +1113,7 @@ static int ice_ptp_set_vernier_wl(struct ice_hw *hw)
for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
int err;
- err = ice_write_phy_reg_e822(hw, port, P_REG_WL,
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_WL,
PTP_VERNIER_WL);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to set vernier window length for port %u, err %d\n",
@@ -1126,12 +1126,12 @@ static int ice_ptp_set_vernier_wl(struct ice_hw *hw)
}
/**
- * ice_ptp_init_phc_e822 - Perform E822 specific PHC initialization
+ * ice_ptp_init_phc_e82x - Perform E822 specific PHC initialization
* @hw: pointer to HW struct
*
* Perform PHC initialization steps specific to E822 devices.
*/
-static int ice_ptp_init_phc_e822(struct ice_hw *hw)
+static int ice_ptp_init_phc_e82x(struct ice_hw *hw)
{
int err;
u32 regval;
@@ -1145,7 +1145,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw)
wr32(hw, PF_SB_REM_DEV_CTL, regval);
/* Initialize the Clock Generation Unit */
- err = ice_init_cgu_e822(hw);
+ err = ice_init_cgu_e82x(hw);
if (err)
return err;
@@ -1154,7 +1154,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw)
}
/**
- * ice_ptp_prep_phy_time_e822 - Prepare PHY port with initial time
+ * ice_ptp_prep_phy_time_e82x - Prepare PHY port with initial time
* @hw: pointer to the HW struct
* @time: Time to initialize the PHY port clocks to
*
@@ -1164,7 +1164,7 @@ static int ice_ptp_init_phc_e822(struct ice_hw *hw)
* units of nominal nanoseconds.
*/
static int
-ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
+ice_ptp_prep_phy_time_e82x(struct ice_hw *hw, u32 time)
{
u64 phy_time;
u8 port;
@@ -1177,14 +1177,14 @@ ice_ptp_prep_phy_time_e822(struct ice_hw *hw, u32 time)
for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
/* Tx case */
- err = ice_write_64b_phy_reg_e822(hw, port,
+ err = ice_write_64b_phy_reg_e82x(hw, port,
P_REG_TX_TIMER_INC_PRE_L,
phy_time);
if (err)
goto exit_err;
/* Rx case */
- err = ice_write_64b_phy_reg_e822(hw, port,
+ err = ice_write_64b_phy_reg_e82x(hw, port,
P_REG_RX_TIMER_INC_PRE_L,
phy_time);
if (err)
@@ -1201,7 +1201,7 @@ exit_err:
}
/**
- * ice_ptp_prep_port_adj_e822 - Prepare a single port for time adjust
+ * ice_ptp_prep_port_adj_e82x - Prepare a single port for time adjust
* @hw: pointer to HW struct
* @port: Port number to be programmed
* @time: time in cycles to adjust the port Tx and Rx clocks
@@ -1216,7 +1216,7 @@ exit_err:
* Negative adjustments are supported using 2s complement arithmetic.
*/
static int
-ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time)
+ice_ptp_prep_port_adj_e82x(struct ice_hw *hw, u8 port, s64 time)
{
u32 l_time, u_time;
int err;
@@ -1225,23 +1225,23 @@ ice_ptp_prep_port_adj_e822(struct ice_hw *hw, u8 port, s64 time)
u_time = upper_32_bits(time);
/* Tx case */
- err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_L,
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_TIMER_INC_PRE_L,
l_time);
if (err)
goto exit_err;
- err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TIMER_INC_PRE_U,
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_TIMER_INC_PRE_U,
u_time);
if (err)
goto exit_err;
/* Rx case */
- err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_L,
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_TIMER_INC_PRE_L,
l_time);
if (err)
goto exit_err;
- err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TIMER_INC_PRE_U,
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_TIMER_INC_PRE_U,
u_time);
if (err)
goto exit_err;
@@ -1255,7 +1255,7 @@ exit_err:
}
/**
- * ice_ptp_prep_phy_adj_e822 - Prep PHY ports for a time adjustment
+ * ice_ptp_prep_phy_adj_e82x - Prep PHY ports for a time adjustment
* @hw: pointer to HW struct
* @adj: adjustment in nanoseconds
*
@@ -1264,7 +1264,7 @@ exit_err:
* ICE_PTP_ADJ_TIME or ICE_PTP_ADJ_TIME_AT_TIME sync command.
*/
static int
-ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
+ice_ptp_prep_phy_adj_e82x(struct ice_hw *hw, s32 adj)
{
s64 cycles;
u8 port;
@@ -1281,7 +1281,7 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
int err;
- err = ice_ptp_prep_port_adj_e822(hw, port, cycles);
+ err = ice_ptp_prep_port_adj_e82x(hw, port, cycles);
if (err)
return err;
}
@@ -1290,7 +1290,7 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
}
/**
- * ice_ptp_prep_phy_incval_e822 - Prepare PHY ports for time adjustment
+ * ice_ptp_prep_phy_incval_e82x - Prepare PHY ports for time adjustment
* @hw: pointer to HW struct
* @incval: new increment value to prepare
*
@@ -1299,13 +1299,13 @@ ice_ptp_prep_phy_adj_e822(struct ice_hw *hw, s32 adj)
* issuing an ICE_PTP_INIT_INCVAL command.
*/
static int
-ice_ptp_prep_phy_incval_e822(struct ice_hw *hw, u64 incval)
+ice_ptp_prep_phy_incval_e82x(struct ice_hw *hw, u64 incval)
{
int err;
u8 port;
for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_TIMETUS_L,
incval);
if (err)
goto exit_err;
@@ -1337,7 +1337,7 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
int err;
/* Tx case */
- err = ice_read_64b_phy_reg_e822(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
+ err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_TX_CAPTURE_L, tx_ts);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read REG_TX_CAPTURE, err %d\n",
err);
@@ -1348,7 +1348,7 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
(unsigned long long)*tx_ts);
/* Rx case */
- err = ice_read_64b_phy_reg_e822(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
+ err = ice_read_64b_phy_reg_e82x(hw, port, P_REG_RX_CAPTURE_L, rx_ts);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_CAPTURE, err %d\n",
err);
@@ -1362,7 +1362,7 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
}
/**
- * ice_ptp_write_port_cmd_e822 - Prepare a single PHY port for a timer command
+ * ice_ptp_write_port_cmd_e82x - Prepare a single PHY port for a timer command
* @hw: pointer to HW struct
* @port: Port to which cmd has to be sent
* @cmd: Command to be sent to the port
@@ -1372,8 +1372,8 @@ ice_ptp_read_port_capture(struct ice_hw *hw, u8 port, u64 *tx_ts, u64 *rx_ts)
* Do not use this function directly. If you want to configure exactly one
* port, use ice_ptp_one_port_cmd() instead.
*/
-static int
-ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd)
+static int ice_ptp_write_port_cmd_e82x(struct ice_hw *hw, u8 port,
+ enum ice_ptp_tmr_cmd cmd)
{
u32 cmd_val, val;
u8 tmr_idx;
@@ -1403,7 +1403,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd
/* Tx case */
/* Read, modify, write */
- err = ice_read_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, &val);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_TX_TMR_CMD, &val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_TMR_CMD, err %d\n",
err);
@@ -1414,7 +1414,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd
val &= ~TS_CMD_MASK;
val |= cmd_val;
- err = ice_write_phy_reg_e822(hw, port, P_REG_TX_TMR_CMD, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_TMR_CMD, val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_TMR_CMD, err %d\n",
err);
@@ -1423,7 +1423,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd
/* Rx case */
/* Read, modify, write */
- err = ice_read_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, &val);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_TMR_CMD, &val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_TMR_CMD, err %d\n",
err);
@@ -1434,7 +1434,7 @@ ice_ptp_write_port_cmd_e822(struct ice_hw *hw, u8 port, enum ice_ptp_tmr_cmd cmd
val &= ~TS_CMD_MASK;
val |= cmd_val;
- err = ice_write_phy_reg_e822(hw, port, P_REG_RX_TMR_CMD, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_TMR_CMD, val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write back RX_TMR_CMD, err %d\n",
err);
@@ -1469,7 +1469,7 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
else
cmd = ICE_PTP_NOP;
- err = ice_ptp_write_port_cmd_e822(hw, port, cmd);
+ err = ice_ptp_write_port_cmd_e82x(hw, port, cmd);
if (err)
return err;
}
@@ -1478,7 +1478,7 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
}
/**
- * ice_ptp_port_cmd_e822 - Prepare all ports for a timer command
+ * ice_ptp_port_cmd_e82x - Prepare all ports for a timer command
* @hw: pointer to the HW struct
* @cmd: timer command to prepare
*
@@ -1486,14 +1486,14 @@ ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port,
* command.
*/
static int
-ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
+ice_ptp_port_cmd_e82x(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
{
u8 port;
for (port = 0; port < ICE_NUM_EXTERNAL_PORTS; port++) {
int err;
- err = ice_ptp_write_port_cmd_e822(hw, port, cmd);
+ err = ice_ptp_write_port_cmd_e82x(hw, port, cmd);
if (err)
return err;
}
@@ -1509,7 +1509,7 @@ ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
*/
/**
- * ice_phy_get_speed_and_fec_e822 - Get link speed and FEC based on serdes mode
+ * ice_phy_get_speed_and_fec_e82x - Get link speed and FEC based on serdes mode
* @hw: pointer to HW struct
* @port: the port to read from
* @link_out: if non-NULL, holds link speed on success
@@ -1519,7 +1519,7 @@ ice_ptp_port_cmd_e822(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
* algorithm.
*/
static int
-ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
+ice_phy_get_speed_and_fec_e82x(struct ice_hw *hw, u8 port,
enum ice_ptp_link_spd *link_out,
enum ice_ptp_fec_mode *fec_out)
{
@@ -1528,7 +1528,7 @@ ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
u32 serdes;
int err;
- err = ice_read_phy_reg_e822(hw, port, P_REG_LINK_SPEED, &serdes);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_LINK_SPEED, &serdes);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read serdes info\n");
return err;
@@ -1585,18 +1585,18 @@ ice_phy_get_speed_and_fec_e822(struct ice_hw *hw, u8 port,
}
/**
- * ice_phy_cfg_lane_e822 - Configure PHY quad for single/multi-lane timestamp
+ * ice_phy_cfg_lane_e82x - Configure PHY quad for single/multi-lane timestamp
* @hw: pointer to HW struct
* @port: to configure the quad for
*/
-static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
+static void ice_phy_cfg_lane_e82x(struct ice_hw *hw, u8 port)
{
enum ice_ptp_link_spd link_spd;
int err;
u32 val;
u8 quad;
- err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, NULL);
+ err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, NULL);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to get PHY link speed, err %d\n",
err);
@@ -1605,7 +1605,7 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
quad = port / ICE_PORTS_PER_QUAD;
- err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
+ err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG, &val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEM_GLB_CFG, err %d\n",
err);
@@ -1617,7 +1617,7 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
else
val |= Q_REG_TX_MEM_GBL_CFG_LANE_TYPE_M;
- err = ice_write_quad_reg_e822(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
+ err = ice_write_quad_reg_e82x(hw, quad, Q_REG_TX_MEM_GBL_CFG, val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write back TX_MEM_GBL_CFG, err %d\n",
err);
@@ -1626,7 +1626,7 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
}
/**
- * ice_phy_cfg_uix_e822 - Configure Serdes UI to TU conversion for E822
+ * ice_phy_cfg_uix_e82x - Configure Serdes UI to TU conversion for E822
* @hw: pointer to the HW structure
* @port: the port to configure
*
@@ -1671,12 +1671,12 @@ static void ice_phy_cfg_lane_e822(struct ice_hw *hw, u8 port)
* a divide by 390,625,000. This does lose some precision, but avoids
* miscalculation due to arithmetic overflow.
*/
-static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
+static int ice_phy_cfg_uix_e82x(struct ice_hw *hw, u8 port)
{
u64 cur_freq, clk_incval, tu_per_sec, uix;
int err;
- cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
+ cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw));
clk_incval = ice_ptp_read_src_incval(hw);
/* Calculate TUs per second divided by 256 */
@@ -1688,7 +1688,7 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
/* Program the 10Gb/40Gb conversion ratio */
uix = div_u64(tu_per_sec * LINE_UI_10G_40G, 390625000);
- err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_10G_40G_L,
+ err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_UIX66_10G_40G_L,
uix);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_10G_40G, err %d\n",
@@ -1699,7 +1699,7 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
/* Program the 25Gb/100Gb conversion ratio */
uix = div_u64(tu_per_sec * LINE_UI_25G_100G, 390625000);
- err = ice_write_64b_phy_reg_e822(hw, port, P_REG_UIX66_25G_100G_L,
+ err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_UIX66_25G_100G_L,
uix);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to write UIX66_25G_100G, err %d\n",
@@ -1711,7 +1711,7 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
}
/**
- * ice_phy_cfg_parpcs_e822 - Configure TUs per PAR/PCS clock cycle
+ * ice_phy_cfg_parpcs_e82x - Configure TUs per PAR/PCS clock cycle
* @hw: pointer to the HW struct
* @port: port to configure
*
@@ -1753,18 +1753,18 @@ static int ice_phy_cfg_uix_e822(struct ice_hw *hw, u8 port)
* frequency is ~29 bits, so multiplying them together should fit within the
* 64 bit arithmetic.
*/
-static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
+static int ice_phy_cfg_parpcs_e82x(struct ice_hw *hw, u8 port)
{
u64 cur_freq, clk_incval, tu_per_sec, phy_tus;
enum ice_ptp_link_spd link_spd;
enum ice_ptp_fec_mode fec_mode;
int err;
- err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
+ err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, &fec_mode);
if (err)
return err;
- cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
+ cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw));
clk_incval = ice_ptp_read_src_incval(hw);
/* Calculate TUs per cycle of the PHC clock */
@@ -1784,7 +1784,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_TX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PAR_TX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1796,7 +1796,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PAR_RX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PAR_RX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1808,7 +1808,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_TX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PCS_TX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1820,7 +1820,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_PCS_RX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_PCS_RX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1832,7 +1832,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_TX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PAR_TX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1844,7 +1844,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PAR_RX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PAR_RX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1856,7 +1856,7 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_TX_TUS_L,
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PCS_TX_TUS_L,
phy_tus);
if (err)
return err;
@@ -1868,23 +1868,23 @@ static int ice_phy_cfg_parpcs_e822(struct ice_hw *hw, u8 port)
else
phy_tus = 0;
- return ice_write_40b_phy_reg_e822(hw, port, P_REG_DESK_PCS_RX_TUS_L,
+ return ice_write_40b_phy_reg_e82x(hw, port, P_REG_DESK_PCS_RX_TUS_L,
phy_tus);
}
/**
- * ice_calc_fixed_tx_offset_e822 - Calculated Fixed Tx offset for a port
+ * ice_calc_fixed_tx_offset_e82x - Calculated Fixed Tx offset for a port
* @hw: pointer to the HW struct
* @link_spd: the Link speed to calculate for
*
* Calculate the fixed offset due to known static latency data.
*/
static u64
-ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
+ice_calc_fixed_tx_offset_e82x(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
{
u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
- cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
+ cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw));
clk_incval = ice_ptp_read_src_incval(hw);
/* Calculate TUs per second */
@@ -1904,7 +1904,7 @@ ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
}
/**
- * ice_phy_cfg_tx_offset_e822 - Configure total Tx timestamp offset
+ * ice_phy_cfg_tx_offset_e82x - Configure total Tx timestamp offset
* @hw: pointer to the HW struct
* @port: the PHY port to configure
*
@@ -1926,7 +1926,7 @@ ice_calc_fixed_tx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
* Returns zero on success, -EBUSY if the hardware vernier offset
* calibration has not completed, or another error code on failure.
*/
-int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
+int ice_phy_cfg_tx_offset_e82x(struct ice_hw *hw, u8 port)
{
enum ice_ptp_link_spd link_spd;
enum ice_ptp_fec_mode fec_mode;
@@ -1935,7 +1935,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
u32 reg;
/* Nothing to do if we've already programmed the offset */
- err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OR, &reg);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_TX_OR, &reg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OR for port %u, err %d\n",
port, err);
@@ -1945,7 +1945,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
if (reg)
return 0;
- err = ice_read_phy_reg_e822(hw, port, P_REG_TX_OV_STATUS, &reg);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_TX_OV_STATUS, &reg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_OV_STATUS for port %u, err %d\n",
port, err);
@@ -1955,11 +1955,11 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
if (!(reg & P_REG_TX_OV_STATUS_OV_M))
return -EBUSY;
- err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
+ err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, &fec_mode);
if (err)
return err;
- total_offset = ice_calc_fixed_tx_offset_e822(hw, link_spd);
+ total_offset = ice_calc_fixed_tx_offset_e82x(hw, link_spd);
/* Read the first Vernier offset from the PHY register and add it to
* the total offset.
@@ -1970,7 +1970,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
link_spd == ICE_PTP_LNK_SPD_25G_RS ||
link_spd == ICE_PTP_LNK_SPD_40G ||
link_spd == ICE_PTP_LNK_SPD_50G) {
- err = ice_read_64b_phy_reg_e822(hw, port,
+ err = ice_read_64b_phy_reg_e82x(hw, port,
P_REG_PAR_PCS_TX_OFFSET_L,
&val);
if (err)
@@ -1985,7 +1985,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
*/
if (link_spd == ICE_PTP_LNK_SPD_50G_RS ||
link_spd == ICE_PTP_LNK_SPD_100G_RS) {
- err = ice_read_64b_phy_reg_e822(hw, port,
+ err = ice_read_64b_phy_reg_e82x(hw, port,
P_REG_PAR_TX_TIME_L,
&val);
if (err)
@@ -1998,12 +1998,12 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
* PHY and indicate that the Tx offset is ready. After this,
* timestamps will be enabled.
*/
- err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_TX_OFFSET_L,
+ err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_TOTAL_TX_OFFSET_L,
total_offset);
if (err)
return err;
- err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 1);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_OR, 1);
if (err)
return err;
@@ -2014,7 +2014,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
}
/**
- * ice_phy_calc_pmd_adj_e822 - Calculate PMD adjustment for Rx
+ * ice_phy_calc_pmd_adj_e82x - Calculate PMD adjustment for Rx
* @hw: pointer to the HW struct
* @port: the PHY port to adjust for
* @link_spd: the current link speed of the PHY
@@ -2026,7 +2026,7 @@ int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port)
* various delays caused when receiving a packet.
*/
static int
-ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
+ice_phy_calc_pmd_adj_e82x(struct ice_hw *hw, u8 port,
enum ice_ptp_link_spd link_spd,
enum ice_ptp_fec_mode fec_mode, u64 *pmd_adj)
{
@@ -2035,7 +2035,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
u32 val;
int err;
- err = ice_read_phy_reg_e822(hw, port, P_REG_PMD_ALIGNMENT, &val);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_PMD_ALIGNMENT, &val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read PMD alignment, err %d\n",
err);
@@ -2044,7 +2044,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
pmd_align = (u8)val;
- cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
+ cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw));
clk_incval = ice_ptp_read_src_incval(hw);
/* Calculate TUs per second */
@@ -2123,7 +2123,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
u64 cycle_adj;
u8 rx_cycle;
- err = ice_read_phy_reg_e822(hw, port, P_REG_RX_40_TO_160_CNT,
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_40_TO_160_CNT,
&val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read 25G-RS Rx cycle count, err %d\n",
@@ -2145,7 +2145,7 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
u64 cycle_adj;
u8 rx_cycle;
- err = ice_read_phy_reg_e822(hw, port, P_REG_RX_80_TO_160_CNT,
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_80_TO_160_CNT,
&val);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read 50G-RS Rx cycle count, err %d\n",
@@ -2172,18 +2172,18 @@ ice_phy_calc_pmd_adj_e822(struct ice_hw *hw, u8 port,
}
/**
- * ice_calc_fixed_rx_offset_e822 - Calculated the fixed Rx offset for a port
+ * ice_calc_fixed_rx_offset_e82x - Calculated the fixed Rx offset for a port
* @hw: pointer to HW struct
* @link_spd: The Link speed to calculate for
*
* Determine the fixed Rx latency for a given link speed.
*/
static u64
-ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
+ice_calc_fixed_rx_offset_e82x(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
{
u64 cur_freq, clk_incval, tu_per_sec, fixed_offset;
- cur_freq = ice_e822_pll_freq(ice_e822_time_ref(hw));
+ cur_freq = ice_e82x_pll_freq(ice_e82x_time_ref(hw));
clk_incval = ice_ptp_read_src_incval(hw);
/* Calculate TUs per second */
@@ -2203,7 +2203,7 @@ ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
}
/**
- * ice_phy_cfg_rx_offset_e822 - Configure total Rx timestamp offset
+ * ice_phy_cfg_rx_offset_e82x - Configure total Rx timestamp offset
* @hw: pointer to the HW struct
* @port: the PHY port to configure
*
@@ -2229,7 +2229,7 @@ ice_calc_fixed_rx_offset_e822(struct ice_hw *hw, enum ice_ptp_link_spd link_spd)
* Returns zero on success, -EBUSY if the hardware vernier offset
* calibration has not completed, or another error code on failure.
*/
-int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
+int ice_phy_cfg_rx_offset_e82x(struct ice_hw *hw, u8 port)
{
enum ice_ptp_link_spd link_spd;
enum ice_ptp_fec_mode fec_mode;
@@ -2238,7 +2238,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
u32 reg;
/* Nothing to do if we've already programmed the offset */
- err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OR, &reg);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_OR, &reg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OR for port %u, err %d\n",
port, err);
@@ -2248,7 +2248,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
if (reg)
return 0;
- err = ice_read_phy_reg_e822(hw, port, P_REG_RX_OV_STATUS, &reg);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_RX_OV_STATUS, &reg);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read RX_OV_STATUS for port %u, err %d\n",
port, err);
@@ -2258,16 +2258,16 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
if (!(reg & P_REG_RX_OV_STATUS_OV_M))
return -EBUSY;
- err = ice_phy_get_speed_and_fec_e822(hw, port, &link_spd, &fec_mode);
+ err = ice_phy_get_speed_and_fec_e82x(hw, port, &link_spd, &fec_mode);
if (err)
return err;
- total_offset = ice_calc_fixed_rx_offset_e822(hw, link_spd);
+ total_offset = ice_calc_fixed_rx_offset_e82x(hw, link_spd);
/* Read the first Vernier offset from the PHY register and add it to
* the total offset.
*/
- err = ice_read_64b_phy_reg_e822(hw, port,
+ err = ice_read_64b_phy_reg_e82x(hw, port,
P_REG_PAR_PCS_RX_OFFSET_L,
&val);
if (err)
@@ -2282,7 +2282,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
link_spd == ICE_PTP_LNK_SPD_50G ||
link_spd == ICE_PTP_LNK_SPD_50G_RS ||
link_spd == ICE_PTP_LNK_SPD_100G_RS) {
- err = ice_read_64b_phy_reg_e822(hw, port,
+ err = ice_read_64b_phy_reg_e82x(hw, port,
P_REG_PAR_RX_TIME_L,
&val);
if (err)
@@ -2292,7 +2292,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
}
/* In addition, Rx must account for the PMD alignment */
- err = ice_phy_calc_pmd_adj_e822(hw, port, link_spd, fec_mode, &pmd);
+ err = ice_phy_calc_pmd_adj_e82x(hw, port, link_spd, fec_mode, &pmd);
if (err)
return err;
@@ -2308,12 +2308,12 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
* PHY and indicate that the Rx offset is ready. After this,
* timestamps will be enabled.
*/
- err = ice_write_64b_phy_reg_e822(hw, port, P_REG_TOTAL_RX_OFFSET_L,
+ err = ice_write_64b_phy_reg_e82x(hw, port, P_REG_TOTAL_RX_OFFSET_L,
total_offset);
if (err)
return err;
- err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 1);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_OR, 1);
if (err)
return err;
@@ -2324,7 +2324,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
}
/**
- * ice_read_phy_and_phc_time_e822 - Simultaneously capture PHC and PHY time
+ * ice_read_phy_and_phc_time_e82x - Simultaneously capture PHC and PHY time
* @hw: pointer to the HW struct
* @port: the PHY port to read
* @phy_time: on return, the 64bit PHY timer value
@@ -2334,7 +2334,7 @@ int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port)
* and PHC timer values.
*/
static int
-ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
+ice_read_phy_and_phc_time_e82x(struct ice_hw *hw, u8 port, u64 *phy_time,
u64 *phc_time)
{
u64 tx_time, rx_time;
@@ -2381,7 +2381,7 @@ ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
}
/**
- * ice_sync_phy_timer_e822 - Synchronize the PHY timer with PHC timer
+ * ice_sync_phy_timer_e82x - Synchronize the PHY timer with PHC timer
* @hw: pointer to the HW struct
* @port: the PHY port to synchronize
*
@@ -2392,7 +2392,7 @@ ice_read_phy_and_phc_time_e822(struct ice_hw *hw, u8 port, u64 *phy_time,
* to the PHY timer in order to ensure it reads the same value as the
* primary PHC timer.
*/
-static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
+static int ice_sync_phy_timer_e82x(struct ice_hw *hw, u8 port)
{
u64 phc_time, phy_time, difference;
int err;
@@ -2402,7 +2402,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
return -EBUSY;
}
- err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
+ err = ice_read_phy_and_phc_time_e82x(hw, port, &phy_time, &phc_time);
if (err)
goto err_unlock;
@@ -2416,7 +2416,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
*/
difference = phc_time - phy_time;
- err = ice_ptp_prep_port_adj_e822(hw, port, (s64)difference);
+ err = ice_ptp_prep_port_adj_e82x(hw, port, (s64)difference);
if (err)
goto err_unlock;
@@ -2433,7 +2433,7 @@ static int ice_sync_phy_timer_e822(struct ice_hw *hw, u8 port)
/* Re-capture the timer values to flush the command registers and
* verify that the time was properly adjusted.
*/
- err = ice_read_phy_and_phc_time_e822(hw, port, &phy_time, &phc_time);
+ err = ice_read_phy_and_phc_time_e82x(hw, port, &phy_time, &phc_time);
if (err)
goto err_unlock;
@@ -2452,7 +2452,7 @@ err_unlock:
}
/**
- * ice_stop_phy_timer_e822 - Stop the PHY clock timer
+ * ice_stop_phy_timer_e82x - Stop the PHY clock timer
* @hw: pointer to the HW struct
* @port: the PHY port to stop
* @soft_reset: if true, hold the SOFT_RESET bit of P_REG_PS
@@ -2462,36 +2462,36 @@ err_unlock:
* initialized or when link speed changes.
*/
int
-ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
+ice_stop_phy_timer_e82x(struct ice_hw *hw, u8 port, bool soft_reset)
{
int err;
u32 val;
- err = ice_write_phy_reg_e822(hw, port, P_REG_TX_OR, 0);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_TX_OR, 0);
if (err)
return err;
- err = ice_write_phy_reg_e822(hw, port, P_REG_RX_OR, 0);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_RX_OR, 0);
if (err)
return err;
- err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_PS, &val);
if (err)
return err;
val &= ~P_REG_PS_START_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
val &= ~P_REG_PS_ENA_CLK_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
if (soft_reset) {
val |= P_REG_PS_SFT_RESET_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
}
@@ -2502,7 +2502,7 @@ ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
}
/**
- * ice_start_phy_timer_e822 - Start the PHY clock timer
+ * ice_start_phy_timer_e82x - Start the PHY clock timer
* @hw: pointer to the HW struct
* @port: the PHY port to start
*
@@ -2512,7 +2512,7 @@ ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset)
*
* Hardware will take Vernier measurements on Tx or Rx of packets.
*/
-int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
+int ice_start_phy_timer_e82x(struct ice_hw *hw, u8 port)
{
u32 lo, hi, val;
u64 incval;
@@ -2521,17 +2521,17 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
tmr_idx = ice_get_ptp_src_clock_index(hw);
- err = ice_stop_phy_timer_e822(hw, port, false);
+ err = ice_stop_phy_timer_e82x(hw, port, false);
if (err)
return err;
- ice_phy_cfg_lane_e822(hw, port);
+ ice_phy_cfg_lane_e82x(hw, port);
- err = ice_phy_cfg_uix_e822(hw, port);
+ err = ice_phy_cfg_uix_e82x(hw, port);
if (err)
return err;
- err = ice_phy_cfg_parpcs_e822(hw, port);
+ err = ice_phy_cfg_parpcs_e82x(hw, port);
if (err)
return err;
@@ -2539,7 +2539,7 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
hi = rd32(hw, GLTSYN_INCVAL_H(tmr_idx));
incval = (u64)hi << 32 | lo;
- err = ice_write_40b_phy_reg_e822(hw, port, P_REG_TIMETUS_L, incval);
+ err = ice_write_40b_phy_reg_e82x(hw, port, P_REG_TIMETUS_L, incval);
if (err)
return err;
@@ -2552,22 +2552,22 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
ice_ptp_exec_tmr_cmd(hw);
- err = ice_read_phy_reg_e822(hw, port, P_REG_PS, &val);
+ err = ice_read_phy_reg_e82x(hw, port, P_REG_PS, &val);
if (err)
return err;
val |= P_REG_PS_SFT_RESET_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
val |= P_REG_PS_START_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
val &= ~P_REG_PS_SFT_RESET_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
@@ -2578,18 +2578,18 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
ice_ptp_exec_tmr_cmd(hw);
val |= P_REG_PS_ENA_CLK_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
val |= P_REG_PS_LOAD_OFFSET_M;
- err = ice_write_phy_reg_e822(hw, port, P_REG_PS, val);
+ err = ice_write_phy_reg_e82x(hw, port, P_REG_PS, val);
if (err)
return err;
ice_ptp_exec_tmr_cmd(hw);
- err = ice_sync_phy_timer_e822(hw, port);
+ err = ice_sync_phy_timer_e82x(hw, port);
if (err)
return err;
@@ -2599,7 +2599,7 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
}
/**
- * ice_get_phy_tx_tstamp_ready_e822 - Read Tx memory status register
+ * ice_get_phy_tx_tstamp_ready_e82x - Read Tx memory status register
* @hw: pointer to the HW struct
* @quad: the timestamp quad to read from
* @tstamp_ready: contents of the Tx memory status register
@@ -2609,19 +2609,19 @@ int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port)
* ready to be captured from the PHY timestamp block.
*/
static int
-ice_get_phy_tx_tstamp_ready_e822(struct ice_hw *hw, u8 quad, u64 *tstamp_ready)
+ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready)
{
u32 hi, lo;
int err;
- err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi);
+ err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEMORY_STATUS_U, &hi);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_U for quad %u, err %d\n",
quad, err);
return err;
}
- err = ice_read_quad_reg_e822(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo);
+ err = ice_read_quad_reg_e82x(hw, quad, Q_REG_TX_MEMORY_STATUS_L, &lo);
if (err) {
ice_debug(hw, ICE_DBG_PTP, "Failed to read TX_MEMORY_STATUS_L for quad %u, err %d\n",
quad, err);
@@ -3307,7 +3307,7 @@ void ice_ptp_init_phy_model(struct ice_hw *hw)
if (ice_is_e810(hw))
hw->phy_model = ICE_PHY_E810;
else
- hw->phy_model = ICE_PHY_E822;
+ hw->phy_model = ICE_PHY_E82X;
}
/**
@@ -3332,8 +3332,8 @@ static int ice_ptp_tmr_cmd(struct ice_hw *hw, enum ice_ptp_tmr_cmd cmd)
case ICE_PHY_E810:
err = ice_ptp_port_cmd_e810(hw, cmd);
break;
- case ICE_PHY_E822:
- err = ice_ptp_port_cmd_e822(hw, cmd);
+ case ICE_PHY_E82X:
+ err = ice_ptp_port_cmd_e82x(hw, cmd);
break;
default:
err = -EOPNOTSUPP;
@@ -3384,8 +3384,8 @@ int ice_ptp_init_time(struct ice_hw *hw, u64 time)
case ICE_PHY_E810:
err = ice_ptp_prep_phy_time_e810(hw, time & 0xFFFFFFFF);
break;
- case ICE_PHY_E822:
- err = ice_ptp_prep_phy_time_e822(hw, time & 0xFFFFFFFF);
+ case ICE_PHY_E82X:
+ err = ice_ptp_prep_phy_time_e82x(hw, time & 0xFFFFFFFF);
break;
default:
err = -EOPNOTSUPP;
@@ -3426,8 +3426,8 @@ int ice_ptp_write_incval(struct ice_hw *hw, u64 incval)
case ICE_PHY_E810:
err = ice_ptp_prep_phy_incval_e810(hw, incval);
break;
- case ICE_PHY_E822:
- err = ice_ptp_prep_phy_incval_e822(hw, incval);
+ case ICE_PHY_E82X:
+ err = ice_ptp_prep_phy_incval_e82x(hw, incval);
break;
default:
err = -EOPNOTSUPP;
@@ -3492,8 +3492,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj)
case ICE_PHY_E810:
err = ice_ptp_prep_phy_adj_e810(hw, adj);
break;
- case ICE_PHY_E822:
- err = ice_ptp_prep_phy_adj_e822(hw, adj);
+ case ICE_PHY_E82X:
+ err = ice_ptp_prep_phy_adj_e82x(hw, adj);
break;
default:
err = -EOPNOTSUPP;
@@ -3521,8 +3521,8 @@ int ice_read_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx, u64 *tstamp)
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_read_phy_tstamp_e810(hw, block, idx, tstamp);
- case ICE_PHY_E822:
- return ice_read_phy_tstamp_e822(hw, block, idx, tstamp);
+ case ICE_PHY_E82X:
+ return ice_read_phy_tstamp_e82x(hw, block, idx, tstamp);
default:
return -EOPNOTSUPP;
}
@@ -3549,8 +3549,8 @@ int ice_clear_phy_tstamp(struct ice_hw *hw, u8 block, u8 idx)
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_clear_phy_tstamp_e810(hw, block, idx);
- case ICE_PHY_E822:
- return ice_clear_phy_tstamp_e822(hw, block, idx);
+ case ICE_PHY_E82X:
+ return ice_clear_phy_tstamp_e82x(hw, block, idx);
default:
return -EOPNOTSUPP;
}
@@ -3608,8 +3608,8 @@ static int ice_get_pf_c827_idx(struct ice_hw *hw, u8 *idx)
void ice_ptp_reset_ts_memory(struct ice_hw *hw)
{
switch (hw->phy_model) {
- case ICE_PHY_E822:
- ice_ptp_reset_ts_memory_e822(hw);
+ case ICE_PHY_E82X:
+ ice_ptp_reset_ts_memory_e82x(hw);
break;
case ICE_PHY_E810:
default:
@@ -3636,8 +3636,8 @@ int ice_ptp_init_phc(struct ice_hw *hw)
switch (hw->phy_model) {
case ICE_PHY_E810:
return ice_ptp_init_phc_e810(hw);
- case ICE_PHY_E822:
- return ice_ptp_init_phc_e822(hw);
+ case ICE_PHY_E82X:
+ return ice_ptp_init_phc_e82x(hw);
default:
return -EOPNOTSUPP;
}
@@ -3660,8 +3660,8 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready)
case ICE_PHY_E810:
return ice_get_phy_tx_tstamp_ready_e810(hw, block,
tstamp_ready);
- case ICE_PHY_E822:
- return ice_get_phy_tx_tstamp_ready_e822(hw, block,
+ case ICE_PHY_E82X:
+ return ice_get_phy_tx_tstamp_ready_e82x(hw, block,
tstamp_ready);
break;
default:
@@ -3942,7 +3942,7 @@ int ice_get_cgu_rclk_pin_info(struct ice_hw *hw, u8 *base_idx, u8 *pin_num)
case ICE_DEV_ID_E823C_QSFP:
case ICE_DEV_ID_E823C_SFP:
case ICE_DEV_ID_E823C_SGMII:
- *pin_num = ICE_E822_RCLK_PINS_NUM;
+ *pin_num = ICE_E82X_RCLK_PINS_NUM;
ret = 0;
if (hw->cgu_part_number ==
ICE_AQC_GET_LINK_TOPO_NODE_NR_ZL30632_80032)
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
index cf76701566c7..1f3e03124430 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
+++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h
@@ -42,7 +42,7 @@ enum ice_ptp_fec_mode {
};
/**
- * struct ice_time_ref_info_e822
+ * struct ice_time_ref_info_e82x
* @pll_freq: Frequency of PLL that drives timer ticks in Hz
* @nominal_incval: increment to generate nanoseconds in GLTSYN_TIME_L
* @pps_delay: propagation delay of the PPS output signal
@@ -50,14 +50,14 @@ enum ice_ptp_fec_mode {
* Characteristic information for the various TIME_REF sources possible in the
* E822 devices
*/
-struct ice_time_ref_info_e822 {
+struct ice_time_ref_info_e82x {
u64 pll_freq;
u64 nominal_incval;
u8 pps_delay;
};
/**
- * struct ice_vernier_info_e822
+ * struct ice_vernier_info_e82x
* @tx_par_clk: Frequency used to calculate P_REG_PAR_TX_TUS
* @rx_par_clk: Frequency used to calculate P_REG_PAR_RX_TUS
* @tx_pcs_clk: Frequency used to calculate P_REG_PCS_TX_TUS
@@ -80,7 +80,7 @@ struct ice_time_ref_info_e822 {
* different link speeds, either the deskew marker for multi-lane link speeds
* or the Reed Solomon gearbox marker for RS-FEC.
*/
-struct ice_vernier_info_e822 {
+struct ice_vernier_info_e82x {
u32 tx_par_clk;
u32 rx_par_clk;
u32 tx_pcs_clk;
@@ -95,7 +95,7 @@ struct ice_vernier_info_e822 {
};
/**
- * struct ice_cgu_pll_params_e822
+ * struct ice_cgu_pll_params_e82x
* @refclk_pre_div: Reference clock pre-divisor
* @feedback_div: Feedback divisor
* @frac_n_div: Fractional divisor
@@ -104,7 +104,7 @@ struct ice_vernier_info_e822 {
* Clock Generation Unit parameters used to program the PLL based on the
* selected TIME_REF frequency.
*/
-struct ice_cgu_pll_params_e822 {
+struct ice_cgu_pll_params_e82x {
u32 refclk_pre_div;
u32 feedback_div;
u32 frac_n_div;
@@ -124,7 +124,7 @@ enum ice_phy_rclk_pins {
};
#define ICE_E810_RCLK_PINS_NUM (ICE_RCLKB_PIN + 1)
-#define ICE_E822_RCLK_PINS_NUM (ICE_RCLKA_PIN + 1)
+#define ICE_E82X_RCLK_PINS_NUM (ICE_RCLKA_PIN + 1)
#define E810T_CGU_INPUT_C827(_phy, _pin) ((_phy) * ICE_E810_RCLK_PINS_NUM + \
(_pin) + ZL_REF1P)
@@ -183,16 +183,16 @@ struct ice_cgu_pin_desc {
};
extern const struct
-ice_cgu_pll_params_e822 e822_cgu_params[NUM_ICE_TIME_REF_FREQ];
+ice_cgu_pll_params_e82x e822_cgu_params[NUM_ICE_TIME_REF_FREQ];
#define E810C_QSFP_C827_0_HANDLE 2
#define E810C_QSFP_C827_1_HANDLE 3
/* Table of constants related to possible TIME_REF sources */
-extern const struct ice_time_ref_info_e822 e822_time_ref[NUM_ICE_TIME_REF_FREQ];
+extern const struct ice_time_ref_info_e82x e822_time_ref[NUM_ICE_TIME_REF_FREQ];
/* Table of constants for Vernier calibration on E822 */
-extern const struct ice_vernier_info_e822 e822_vernier[NUM_ICE_PTP_LNK_SPD];
+extern const struct ice_vernier_info_e82x e822_vernier[NUM_ICE_PTP_LNK_SPD];
/* Increment value to generate nanoseconds in the GLTSYN_TIME_L register for
* the E810 devices. Based off of a PLL with an 812.5 MHz frequency.
@@ -215,23 +215,23 @@ int ice_ptp_init_phc(struct ice_hw *hw);
int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready);
/* E822 family functions */
-int ice_read_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 *val);
-int ice_write_quad_reg_e822(struct ice_hw *hw, u8 quad, u16 offset, u32 val);
-void ice_ptp_reset_ts_memory_quad_e822(struct ice_hw *hw, u8 quad);
+int ice_read_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 *val);
+int ice_write_quad_reg_e82x(struct ice_hw *hw, u8 quad, u16 offset, u32 val);
+void ice_ptp_reset_ts_memory_quad_e82x(struct ice_hw *hw, u8 quad);
/**
- * ice_e822_time_ref - Get the current TIME_REF from capabilities
+ * ice_e82x_time_ref - Get the current TIME_REF from capabilities
* @hw: pointer to the HW structure
*
* Returns the current TIME_REF from the capabilities structure.
*/
-static inline enum ice_time_ref_freq ice_e822_time_ref(struct ice_hw *hw)
+static inline enum ice_time_ref_freq ice_e82x_time_ref(struct ice_hw *hw)
{
return hw->func_caps.ts_func_info.time_ref;
}
/**
- * ice_set_e822_time_ref - Set new TIME_REF
+ * ice_set_e82x_time_ref - Set new TIME_REF
* @hw: pointer to the HW structure
* @time_ref: new TIME_REF to set
*
@@ -239,31 +239,31 @@ static inline enum ice_time_ref_freq ice_e822_time_ref(struct ice_hw *hw)
* change, such as an update to the CGU registers.
*/
static inline void
-ice_set_e822_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref)
+ice_set_e82x_time_ref(struct ice_hw *hw, enum ice_time_ref_freq time_ref)
{
hw->func_caps.ts_func_info.time_ref = time_ref;
}
-static inline u64 ice_e822_pll_freq(enum ice_time_ref_freq time_ref)
+static inline u64 ice_e82x_pll_freq(enum ice_time_ref_freq time_ref)
{
return e822_time_ref[time_ref].pll_freq;
}
-static inline u64 ice_e822_nominal_incval(enum ice_time_ref_freq time_ref)
+static inline u64 ice_e82x_nominal_incval(enum ice_time_ref_freq time_ref)
{
return e822_time_ref[time_ref].nominal_incval;
}
-static inline u64 ice_e822_pps_delay(enum ice_time_ref_freq time_ref)
+static inline u64 ice_e82x_pps_delay(enum ice_time_ref_freq time_ref)
{
return e822_time_ref[time_ref].pps_delay;
}
/* E822 Vernier calibration functions */
-int ice_stop_phy_timer_e822(struct ice_hw *hw, u8 port, bool soft_reset);
-int ice_start_phy_timer_e822(struct ice_hw *hw, u8 port);
-int ice_phy_cfg_tx_offset_e822(struct ice_hw *hw, u8 port);
-int ice_phy_cfg_rx_offset_e822(struct ice_hw *hw, u8 port);
+int ice_stop_phy_timer_e82x(struct ice_hw *hw, u8 port, bool soft_reset);
+int ice_start_phy_timer_e82x(struct ice_hw *hw, u8 port);
+int ice_phy_cfg_tx_offset_e82x(struct ice_hw *hw, u8 port);
+int ice_phy_cfg_rx_offset_e82x(struct ice_hw *hw, u8 port);
/* E810 family functions */
int ice_ptp_init_phy_e810(struct ice_hw *hw);
@@ -509,6 +509,7 @@ int ice_cgu_get_output_pin_state_caps(struct ice_hw *hw, u8 pin_id,
#define TS_LL_READ_RETRIES 200
#define TS_LL_READ_TS_HIGH GENMASK(23, 16)
#define TS_LL_READ_TS_IDX GENMASK(29, 24)
+#define TS_LL_READ_TS_INTR BIT(30)
#define TS_LL_READ_TS BIT(31)
/* Internal PHY timestamp address */
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c
index c686ac0935eb..5f30fb131f74 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.c
+++ b/drivers/net/ethernet/intel/ice/ice_repr.c
@@ -14,7 +14,7 @@
*/
static int ice_repr_get_sw_port_id(struct ice_repr *repr)
{
- return repr->vf->pf->hw.port_info->lport;
+ return repr->src_vsi->back->hw.port_info->lport;
}
/**
@@ -35,7 +35,7 @@ ice_repr_get_phys_port_name(struct net_device *netdev, char *buf, size_t len)
return -EOPNOTSUPP;
res = snprintf(buf, len, "pf%dvfr%d", ice_repr_get_sw_port_id(repr),
- repr->vf->vf_id);
+ repr->id);
if (res <= 0)
return -EOPNOTSUPP;
return 0;
@@ -278,25 +278,67 @@ ice_repr_reg_netdev(struct net_device *netdev)
return register_netdev(netdev);
}
+static void ice_repr_remove_node(struct devlink_port *devlink_port)
+{
+ devl_lock(devlink_port->devlink);
+ devl_rate_leaf_destroy(devlink_port);
+ devl_unlock(devlink_port->devlink);
+}
+
/**
- * ice_repr_add - add representor for VF
- * @vf: pointer to VF structure
+ * ice_repr_rem - remove representor from VF
+ * @repr: pointer to representor structure
*/
-static int ice_repr_add(struct ice_vf *vf)
+static void ice_repr_rem(struct ice_repr *repr)
+{
+ kfree(repr->q_vector);
+ free_netdev(repr->netdev);
+ kfree(repr);
+}
+
+/**
+ * ice_repr_rem_vf - remove representor from VF
+ * @repr: pointer to representor structure
+ */
+void ice_repr_rem_vf(struct ice_repr *repr)
+{
+ ice_repr_remove_node(&repr->vf->devlink_port);
+ unregister_netdev(repr->netdev);
+ ice_devlink_destroy_vf_port(repr->vf);
+ ice_virtchnl_set_dflt_ops(repr->vf);
+ ice_repr_rem(repr);
+}
+
+static void ice_repr_set_tx_topology(struct ice_pf *pf)
+{
+ struct devlink *devlink;
+
+ /* only export if ADQ and DCB disabled and eswitch enabled*/
+ if (ice_is_adq_active(pf) || ice_is_dcb_active(pf) ||
+ !ice_is_switchdev_running(pf))
+ return;
+
+ devlink = priv_to_devlink(pf);
+ ice_devlink_rate_init_tx_topology(devlink, ice_get_main_vsi(pf));
+}
+
+/**
+ * ice_repr_add - add representor for generic VSI
+ * @pf: pointer to PF structure
+ * @src_vsi: pointer to VSI structure of device to represent
+ * @parent_mac: device MAC address
+ */
+static struct ice_repr *
+ice_repr_add(struct ice_pf *pf, struct ice_vsi *src_vsi, const u8 *parent_mac)
{
struct ice_q_vector *q_vector;
struct ice_netdev_priv *np;
struct ice_repr *repr;
- struct ice_vsi *vsi;
int err;
- vsi = ice_get_vf_vsi(vf);
- if (!vsi)
- return -EINVAL;
-
repr = kzalloc(sizeof(*repr), GFP_KERNEL);
if (!repr)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
repr->netdev = alloc_etherdev(sizeof(struct ice_netdev_priv));
if (!repr->netdev) {
@@ -304,9 +346,7 @@ static int ice_repr_add(struct ice_vf *vf)
goto err_alloc;
}
- repr->src_vsi = vsi;
- repr->vf = vf;
- vf->repr = repr;
+ repr->src_vsi = src_vsi;
np = netdev_priv(repr->netdev);
np->repr = repr;
@@ -316,10 +356,40 @@ static int ice_repr_add(struct ice_vf *vf)
goto err_alloc_q_vector;
}
repr->q_vector = q_vector;
+ repr->q_id = repr->id;
+
+ ether_addr_copy(repr->parent_mac, parent_mac);
+
+ return repr;
+
+err_alloc_q_vector:
+ free_netdev(repr->netdev);
+err_alloc:
+ kfree(repr);
+ return ERR_PTR(err);
+}
+
+struct ice_repr *ice_repr_add_vf(struct ice_vf *vf)
+{
+ struct ice_repr *repr;
+ struct ice_vsi *vsi;
+ int err;
+
+ vsi = ice_get_vf_vsi(vf);
+ if (!vsi)
+ return ERR_PTR(-ENOENT);
err = ice_devlink_create_vf_port(vf);
if (err)
- goto err_devlink;
+ return ERR_PTR(err);
+
+ repr = ice_repr_add(vf->pf, vsi, vf->hw_lan_addr);
+ if (IS_ERR(repr)) {
+ err = PTR_ERR(repr);
+ goto err_repr_add;
+ }
+
+ repr->vf = vf;
repr->netdev->min_mtu = ETH_MIN_MTU;
repr->netdev->max_mtu = ICE_MAX_MTU;
@@ -331,100 +401,23 @@ static int ice_repr_add(struct ice_vf *vf)
goto err_netdev;
ice_virtchnl_set_repr_ops(vf);
+ ice_repr_set_tx_topology(vf->pf);
- return 0;
+ return repr;
err_netdev:
+ ice_repr_rem(repr);
+err_repr_add:
ice_devlink_destroy_vf_port(vf);
-err_devlink:
- kfree(repr->q_vector);
- vf->repr->q_vector = NULL;
-err_alloc_q_vector:
- free_netdev(repr->netdev);
- repr->netdev = NULL;
-err_alloc:
- kfree(repr);
- vf->repr = NULL;
- return err;
-}
-
-/**
- * ice_repr_rem - remove representor from VF
- * @vf: pointer to VF structure
- */
-static void ice_repr_rem(struct ice_vf *vf)
-{
- if (!vf->repr)
- return;
-
- kfree(vf->repr->q_vector);
- vf->repr->q_vector = NULL;
- unregister_netdev(vf->repr->netdev);
- ice_devlink_destroy_vf_port(vf);
- free_netdev(vf->repr->netdev);
- vf->repr->netdev = NULL;
- kfree(vf->repr);
- vf->repr = NULL;
-
- ice_virtchnl_set_dflt_ops(vf);
-}
-
-/**
- * ice_repr_rem_from_all_vfs - remove port representor for all VFs
- * @pf: pointer to PF structure
- */
-void ice_repr_rem_from_all_vfs(struct ice_pf *pf)
-{
- struct devlink *devlink;
- struct ice_vf *vf;
- unsigned int bkt;
-
- lockdep_assert_held(&pf->vfs.table_lock);
-
- ice_for_each_vf(pf, bkt, vf)
- ice_repr_rem(vf);
-
- /* since all port representors are destroyed, there is
- * no point in keeping the nodes
- */
- devlink = priv_to_devlink(pf);
- devl_lock(devlink);
- devl_rate_nodes_destroy(devlink);
- devl_unlock(devlink);
+ return ERR_PTR(err);
}
-/**
- * ice_repr_add_for_all_vfs - add port representor for all VFs
- * @pf: pointer to PF structure
- */
-int ice_repr_add_for_all_vfs(struct ice_pf *pf)
+struct ice_repr *ice_repr_get_by_vsi(struct ice_vsi *vsi)
{
- struct devlink *devlink;
- struct ice_vf *vf;
- unsigned int bkt;
- int err;
-
- lockdep_assert_held(&pf->vfs.table_lock);
-
- ice_for_each_vf(pf, bkt, vf) {
- err = ice_repr_add(vf);
- if (err)
- goto err;
- }
-
- /* only export if ADQ and DCB disabled */
- if (ice_is_adq_active(pf) || ice_is_dcb_active(pf))
- return 0;
-
- devlink = priv_to_devlink(pf);
- ice_devlink_rate_init_tx_topology(devlink, ice_get_main_vsi(pf));
-
- return 0;
-
-err:
- ice_repr_rem_from_all_vfs(pf);
+ if (!vsi->vf)
+ return NULL;
- return err;
+ return xa_load(&vsi->back->eswitch.reprs, vsi->vf->repr_id);
}
/**
diff --git a/drivers/net/ethernet/intel/ice/ice_repr.h b/drivers/net/ethernet/intel/ice/ice_repr.h
index e1ee2d2c1d2d..f9aede315716 100644
--- a/drivers/net/ethernet/intel/ice/ice_repr.h
+++ b/drivers/net/ethernet/intel/ice/ice_repr.h
@@ -13,14 +13,17 @@ struct ice_repr {
struct net_device *netdev;
struct metadata_dst *dst;
struct ice_esw_br_port *br_port;
+ int q_id;
+ u32 id;
+ u8 parent_mac[ETH_ALEN];
#ifdef CONFIG_ICE_SWITCHDEV
/* info about slow path rule */
struct ice_rule_query_data sp_rule;
#endif
};
-int ice_repr_add_for_all_vfs(struct ice_pf *pf);
-void ice_repr_rem_from_all_vfs(struct ice_pf *pf);
+struct ice_repr *ice_repr_add_vf(struct ice_vf *vf);
+void ice_repr_rem_vf(struct ice_repr *repr);
void ice_repr_start_tx_queues(struct ice_repr *repr);
void ice_repr_stop_tx_queues(struct ice_repr *repr);
@@ -29,4 +32,6 @@ void ice_repr_set_traffic_vsi(struct ice_repr *repr, struct ice_vsi *vsi);
struct ice_repr *ice_netdev_to_repr(struct net_device *netdev);
bool ice_is_port_repr_netdev(const struct net_device *netdev);
+
+struct ice_repr *ice_repr_get_by_vsi(struct ice_vsi *vsi);
#endif
diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c
index 2f4a621254e8..d174a4eeb899 100644
--- a/drivers/net/ethernet/intel/ice/ice_sched.c
+++ b/drivers/net/ethernet/intel/ice/ice_sched.c
@@ -1387,8 +1387,7 @@ void ice_sched_get_psm_clk_freq(struct ice_hw *hw)
u32 val, clk_src;
val = rd32(hw, GLGEN_CLKSTAT_SRC);
- clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >>
- GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S;
+ clk_src = FIELD_GET(GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M, val);
#define PSM_CLK_SRC_367_MHZ 0x0
#define PSM_CLK_SRC_416_MHZ 0x1
diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c
index e1494f24f661..b0f78c2f2790 100644
--- a/drivers/net/ethernet/intel/ice/ice_sriov.c
+++ b/drivers/net/ethernet/intel/ice/ice_sriov.c
@@ -106,10 +106,8 @@ static void ice_dis_vf_mappings(struct ice_vf *vf)
for (v = first; v <= last; v++) {
u32 reg;
- reg = (((1 << GLINT_VECT2FUNC_IS_PF_S) &
- GLINT_VECT2FUNC_IS_PF_M) |
- ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) &
- GLINT_VECT2FUNC_PF_NUM_M));
+ reg = FIELD_PREP(GLINT_VECT2FUNC_IS_PF_M, 1) |
+ FIELD_PREP(GLINT_VECT2FUNC_PF_NUM_M, hw->pf_id);
wr32(hw, GLINT_VECT2FUNC(v), reg);
}
@@ -172,13 +170,14 @@ void ice_free_vfs(struct ice_pf *pf)
else
dev_warn(dev, "VFs are assigned - not disabling SR-IOV\n");
- mutex_lock(&vfs->table_lock);
+ ice_eswitch_reserve_cp_queues(pf, -ice_get_num_vfs(pf));
- ice_eswitch_release(pf);
+ mutex_lock(&vfs->table_lock);
ice_for_each_vf(pf, bkt, vf) {
mutex_lock(&vf->cfg_lock);
+ ice_eswitch_detach(pf, vf);
ice_dis_vf_qs(vf);
if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
@@ -274,24 +273,20 @@ static void ice_ena_vf_msix_mappings(struct ice_vf *vf)
(device_based_first_msix + vf->num_msix) - 1;
device_based_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
- reg = (((device_based_first_msix << VPINT_ALLOC_FIRST_S) &
- VPINT_ALLOC_FIRST_M) |
- ((device_based_last_msix << VPINT_ALLOC_LAST_S) &
- VPINT_ALLOC_LAST_M) | VPINT_ALLOC_VALID_M);
+ reg = FIELD_PREP(VPINT_ALLOC_FIRST_M, device_based_first_msix) |
+ FIELD_PREP(VPINT_ALLOC_LAST_M, device_based_last_msix) |
+ VPINT_ALLOC_VALID_M;
wr32(hw, VPINT_ALLOC(vf->vf_id), reg);
- reg = (((device_based_first_msix << VPINT_ALLOC_PCI_FIRST_S)
- & VPINT_ALLOC_PCI_FIRST_M) |
- ((device_based_last_msix << VPINT_ALLOC_PCI_LAST_S) &
- VPINT_ALLOC_PCI_LAST_M) | VPINT_ALLOC_PCI_VALID_M);
+ reg = FIELD_PREP(VPINT_ALLOC_PCI_FIRST_M, device_based_first_msix) |
+ FIELD_PREP(VPINT_ALLOC_PCI_LAST_M, device_based_last_msix) |
+ VPINT_ALLOC_PCI_VALID_M;
wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), reg);
/* map the interrupts to its functions */
for (v = pf_based_first_msix; v <= pf_based_last_msix; v++) {
- reg = (((device_based_vf_id << GLINT_VECT2FUNC_VF_NUM_S) &
- GLINT_VECT2FUNC_VF_NUM_M) |
- ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) &
- GLINT_VECT2FUNC_PF_NUM_M));
+ reg = FIELD_PREP(GLINT_VECT2FUNC_VF_NUM_M, device_based_vf_id) |
+ FIELD_PREP(GLINT_VECT2FUNC_PF_NUM_M, hw->pf_id);
wr32(hw, GLINT_VECT2FUNC(v), reg);
}
@@ -324,10 +319,8 @@ static void ice_ena_vf_q_mappings(struct ice_vf *vf, u16 max_txq, u16 max_rxq)
* VFNUMQ value should be set to (number of queues - 1). A value
* of 0 means 1 queue and a value of 255 means 256 queues
*/
- reg = (((vsi->txq_map[0] << VPLAN_TX_QBASE_VFFIRSTQ_S) &
- VPLAN_TX_QBASE_VFFIRSTQ_M) |
- (((max_txq - 1) << VPLAN_TX_QBASE_VFNUMQ_S) &
- VPLAN_TX_QBASE_VFNUMQ_M));
+ reg = FIELD_PREP(VPLAN_TX_QBASE_VFFIRSTQ_M, vsi->txq_map[0]) |
+ FIELD_PREP(VPLAN_TX_QBASE_VFNUMQ_M, max_txq - 1);
wr32(hw, VPLAN_TX_QBASE(vf->vf_id), reg);
} else {
dev_err(dev, "Scattered mode for VF Tx queues is not yet implemented\n");
@@ -342,10 +335,8 @@ static void ice_ena_vf_q_mappings(struct ice_vf *vf, u16 max_txq, u16 max_rxq)
* VFNUMQ value should be set to (number of queues - 1). A value
* of 0 means 1 queue and a value of 255 means 256 queues
*/
- reg = (((vsi->rxq_map[0] << VPLAN_RX_QBASE_VFFIRSTQ_S) &
- VPLAN_RX_QBASE_VFFIRSTQ_M) |
- (((max_rxq - 1) << VPLAN_RX_QBASE_VFNUMQ_S) &
- VPLAN_RX_QBASE_VFNUMQ_M));
+ reg = FIELD_PREP(VPLAN_RX_QBASE_VFFIRSTQ_M, vsi->rxq_map[0]) |
+ FIELD_PREP(VPLAN_RX_QBASE_VFNUMQ_M, max_rxq - 1);
wr32(hw, VPLAN_RX_QBASE(vf->vf_id), reg);
} else {
dev_err(dev, "Scattered mode for VF Rx queues is not yet implemented\n");
@@ -609,6 +600,14 @@ static int ice_start_vfs(struct ice_pf *pf)
goto teardown;
}
+ retval = ice_eswitch_attach(pf, vf);
+ if (retval) {
+ dev_err(ice_pf_to_dev(pf), "Failed to attach VF %d to eswitch, error %d",
+ vf->vf_id, retval);
+ ice_vf_vsi_release(vf);
+ goto teardown;
+ }
+
set_bit(ICE_VF_STATE_INIT, vf->vf_states);
ice_ena_vf_mappings(vf);
wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
@@ -763,24 +762,6 @@ static void ice_sriov_clear_reset_trigger(struct ice_vf *vf)
}
/**
- * ice_sriov_create_vsi - Create a new VSI for a VF
- * @vf: VF to create the VSI for
- *
- * This is called by ice_vf_recreate_vsi to create the new VSI after the old
- * VSI has been released.
- */
-static int ice_sriov_create_vsi(struct ice_vf *vf)
-{
- struct ice_vsi *vsi;
-
- vsi = ice_vf_vsi_setup(vf);
- if (!vsi)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
* ice_sriov_post_vsi_rebuild - tasks to do after the VF's VSI have been rebuilt
* @vf: VF to perform tasks on
*/
@@ -799,7 +780,6 @@ static const struct ice_vf_ops ice_sriov_vf_ops = {
.poll_reset_status = ice_sriov_poll_reset_status,
.clear_reset_trigger = ice_sriov_clear_reset_trigger,
.irq_close = NULL,
- .create_vsi = ice_sriov_create_vsi,
.post_vsi_rebuild = ice_sriov_post_vsi_rebuild,
};
@@ -918,6 +898,7 @@ static int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs)
goto err_unroll_sriov;
}
+ ice_eswitch_reserve_cp_queues(pf, num_vfs);
ret = ice_start_vfs(pf);
if (ret) {
dev_err(dev, "Failed to start %d VFs, err %d\n", num_vfs, ret);
@@ -927,12 +908,6 @@ static int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs)
clear_bit(ICE_VF_DIS, pf->state);
- ret = ice_eswitch_configure(pf);
- if (ret) {
- dev_err(dev, "Failed to configure eswitch, err %d\n", ret);
- goto err_unroll_sriov;
- }
-
/* rearm global interrupts */
if (test_and_clear_bit(ICE_OICR_INTR_DIS, pf->state))
ice_irq_dynamic_ena(hw, NULL, NULL);
@@ -1093,6 +1068,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
struct ice_pf *pf = pci_get_drvdata(pdev);
u16 prev_msix, prev_queues, queues;
bool needs_rebuild = false;
+ struct ice_vsi *vsi;
struct ice_vf *vf;
int id;
@@ -1127,6 +1103,10 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
if (!vf)
return -ENOENT;
+ vsi = ice_get_vf_vsi(vf);
+ if (!vsi)
+ return -ENOENT;
+
prev_msix = vf->num_msix;
prev_queues = vf->num_vf_qs;
@@ -1147,8 +1127,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
if (vf->first_vector_idx < 0)
goto unroll;
- ice_vf_vsi_release(vf);
- if (vf->vf_ops->create_vsi(vf)) {
+ if (ice_vf_reconfig_vsi(vf) || ice_vf_init_host_cfg(vf, vsi)) {
/* Try to rebuild with previous values */
needs_rebuild = true;
goto unroll;
@@ -1174,8 +1153,10 @@ unroll:
if (vf->first_vector_idx < 0)
return -EINVAL;
- if (needs_rebuild)
- vf->vf_ops->create_vsi(vf);
+ if (needs_rebuild) {
+ ice_vf_reconfig_vsi(vf);
+ ice_vf_init_host_cfg(vf, vsi);
+ }
ice_ena_vf_mappings(vf);
ice_put_vf(vf);
@@ -1324,8 +1305,7 @@ ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event)
dev_dbg(ice_pf_to_dev(pf), "GLDCB_RTCTQ: 0x%08x\n", gldcb_rtctq);
/* event returns device global Rx queue number */
- queue = (gldcb_rtctq & GLDCB_RTCTQ_RXQNUM_M) >>
- GLDCB_RTCTQ_RXQNUM_S;
+ queue = FIELD_GET(GLDCB_RTCTQ_RXQNUM_M, gldcb_rtctq);
vf = ice_get_vf_from_pfq(pf, ice_globalq_to_pfq(pf, queue));
if (!vf)
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c
index ee19f3aa3d19..f84bab80ca42 100644
--- a/drivers/net/ethernet/intel/ice/ice_switch.c
+++ b/drivers/net/ethernet/intel/ice/ice_switch.c
@@ -2492,25 +2492,24 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
switch (f_info->fltr_act) {
case ICE_FWD_TO_VSI:
- act |= (f_info->fwd_id.hw_vsi_id << ICE_SINGLE_ACT_VSI_ID_S) &
- ICE_SINGLE_ACT_VSI_ID_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+ f_info->fwd_id.hw_vsi_id);
if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
act |= ICE_SINGLE_ACT_VSI_FORWARDING |
ICE_SINGLE_ACT_VALID_BIT;
break;
case ICE_FWD_TO_VSI_LIST:
act |= ICE_SINGLE_ACT_VSI_LIST;
- act |= (f_info->fwd_id.vsi_list_id <<
- ICE_SINGLE_ACT_VSI_LIST_ID_S) &
- ICE_SINGLE_ACT_VSI_LIST_ID_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_LIST_ID_M,
+ f_info->fwd_id.vsi_list_id);
if (f_info->lkup_type != ICE_SW_LKUP_VLAN)
act |= ICE_SINGLE_ACT_VSI_FORWARDING |
ICE_SINGLE_ACT_VALID_BIT;
break;
case ICE_FWD_TO_Q:
act |= ICE_SINGLE_ACT_TO_Q;
- act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
- ICE_SINGLE_ACT_Q_INDEX_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+ f_info->fwd_id.q_id);
break;
case ICE_DROP_PACKET:
act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
@@ -2520,10 +2519,9 @@ ice_fill_sw_rule(struct ice_hw *hw, struct ice_fltr_info *f_info,
q_rgn = f_info->qgrp_size > 0 ?
(u8)ilog2(f_info->qgrp_size) : 0;
act |= ICE_SINGLE_ACT_TO_Q;
- act |= (f_info->fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
- ICE_SINGLE_ACT_Q_INDEX_M;
- act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
- ICE_SINGLE_ACT_Q_REGION_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+ f_info->fwd_id.q_id);
+ act |= FIELD_PREP(ICE_SINGLE_ACT_Q_REGION_M, q_rgn);
break;
default:
return;
@@ -2649,7 +2647,7 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
m_ent->fltr_info.fwd_id.hw_vsi_id;
act = ICE_LG_ACT_VSI_FORWARDING | ICE_LG_ACT_VALID_BIT;
- act |= (id << ICE_LG_ACT_VSI_LIST_ID_S) & ICE_LG_ACT_VSI_LIST_ID_M;
+ act |= FIELD_PREP(ICE_LG_ACT_VSI_LIST_ID_M, id);
if (m_ent->vsi_count > 1)
act |= ICE_LG_ACT_VSI_LIST;
lg_act->act[0] = cpu_to_le32(act);
@@ -2657,16 +2655,15 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
/* Second action descriptor type */
act = ICE_LG_ACT_GENERIC;
- act |= (1 << ICE_LG_ACT_GENERIC_VALUE_S) & ICE_LG_ACT_GENERIC_VALUE_M;
+ act |= FIELD_PREP(ICE_LG_ACT_GENERIC_VALUE_M, 1);
lg_act->act[1] = cpu_to_le32(act);
- act = (ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX <<
- ICE_LG_ACT_GENERIC_OFFSET_S) & ICE_LG_ACT_GENERIC_OFFSET_M;
+ act = FIELD_PREP(ICE_LG_ACT_GENERIC_OFFSET_M,
+ ICE_LG_ACT_GENERIC_OFF_RX_DESC_PROF_IDX);
/* Third action Marker value */
act |= ICE_LG_ACT_GENERIC;
- act |= (sw_marker << ICE_LG_ACT_GENERIC_VALUE_S) &
- ICE_LG_ACT_GENERIC_VALUE_M;
+ act |= FIELD_PREP(ICE_LG_ACT_GENERIC_VALUE_M, sw_marker);
lg_act->act[2] = cpu_to_le32(act);
@@ -2675,9 +2672,9 @@ ice_add_marker_act(struct ice_hw *hw, struct ice_fltr_mgmt_list_entry *m_ent,
ice_aqc_opc_update_sw_rules);
/* Update the action to point to the large action ID */
- rx_tx->act = cpu_to_le32(ICE_SINGLE_ACT_PTR |
- ((l_id << ICE_SINGLE_ACT_PTR_VAL_S) &
- ICE_SINGLE_ACT_PTR_VAL_M));
+ act = ICE_SINGLE_ACT_PTR;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_PTR_VAL_M, l_id);
+ rx_tx->act = cpu_to_le32(act);
/* Use the filter rule ID of the previously created rule with single
* act. Once the update happens, hardware will treat this as large
@@ -4426,8 +4423,8 @@ ice_alloc_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
int status;
buf->num_elems = cpu_to_le16(num_items);
- buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
- ICE_AQC_RES_TYPE_M) | alloc_shared);
+ buf->res_type = cpu_to_le16(FIELD_PREP(ICE_AQC_RES_TYPE_M, type) |
+ alloc_shared);
status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_alloc_res);
if (status)
@@ -4454,8 +4451,8 @@ ice_free_res_cntr(struct ice_hw *hw, u8 type, u8 alloc_shared, u16 num_items,
int status;
buf->num_elems = cpu_to_le16(num_items);
- buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
- ICE_AQC_RES_TYPE_M) | alloc_shared);
+ buf->res_type = cpu_to_le16(FIELD_PREP(ICE_AQC_RES_TYPE_M, type) |
+ alloc_shared);
buf->elem[0].e.sw_resp = cpu_to_le16(counter_id);
status = ice_aq_alloc_free_res(hw, buf, buf_len, ice_aqc_opc_free_res);
@@ -4481,18 +4478,15 @@ int ice_share_res(struct ice_hw *hw, u16 type, u8 shared, u16 res_id)
{
DEFINE_FLEX(struct ice_aqc_alloc_free_res_elem, buf, elem, 1);
u16 buf_len = __struct_size(buf);
+ u16 res_type;
int status;
buf->num_elems = cpu_to_le16(1);
+ res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, type);
if (shared)
- buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
- ICE_AQC_RES_TYPE_M) |
- ICE_AQC_RES_TYPE_FLAG_SHARED);
- else
- buf->res_type = cpu_to_le16(((type << ICE_AQC_RES_TYPE_S) &
- ICE_AQC_RES_TYPE_M) &
- ~ICE_AQC_RES_TYPE_FLAG_SHARED);
+ res_type |= ICE_AQC_RES_TYPE_FLAG_SHARED;
+ buf->res_type = cpu_to_le16(res_type);
buf->elem[0].e.sw_resp = cpu_to_le16(res_id);
status = ice_aq_alloc_free_res(hw, buf, buf_len,
ice_aqc_opc_share_res);
@@ -5024,8 +5018,8 @@ ice_add_sw_recipe(struct ice_hw *hw, struct ice_sw_recipe *rm,
entry->chain_idx = chain_idx;
content->result_indx =
ICE_AQ_RECIPE_RESULT_EN |
- ((chain_idx << ICE_AQ_RECIPE_RESULT_DATA_S) &
- ICE_AQ_RECIPE_RESULT_DATA_M);
+ FIELD_PREP(ICE_AQ_RECIPE_RESULT_DATA_M,
+ chain_idx);
clear_bit(chain_idx, result_idx_bm);
chain_idx = find_first_bit(result_idx_bm,
ICE_MAX_FV_WORDS);
@@ -6065,6 +6059,7 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
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 ||
+ rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET ||
rinfo->sw_act.fltr_act == ICE_NOP)) {
status = -EIO;
goto free_pkt_profile;
@@ -6077,9 +6072,11 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
}
if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
- rinfo->sw_act.fltr_act == ICE_NOP)
+ rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET ||
+ rinfo->sw_act.fltr_act == ICE_NOP) {
rinfo->sw_act.fwd_id.hw_vsi_id =
ice_get_hw_vsi_num(hw, vsi_handle);
+ }
if (rinfo->src_vsi)
rinfo->sw_act.src = ice_get_hw_vsi_num(hw, rinfo->src_vsi);
@@ -6115,38 +6112,45 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
status = -ENOMEM;
goto free_pkt_profile;
}
- if (!rinfo->flags_info.act_valid) {
- act |= ICE_SINGLE_ACT_LAN_ENABLE;
- act |= ICE_SINGLE_ACT_LB_ENABLE;
- } else {
- act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
- ICE_SINGLE_ACT_LB_ENABLE);
+
+ if (rinfo->sw_act.fltr_act != ICE_MIRROR_PACKET) {
+ if (!rinfo->flags_info.act_valid) {
+ act |= ICE_SINGLE_ACT_LAN_ENABLE;
+ act |= ICE_SINGLE_ACT_LB_ENABLE;
+ } else {
+ act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
+ ICE_SINGLE_ACT_LB_ENABLE);
+ }
}
switch (rinfo->sw_act.fltr_act) {
case ICE_FWD_TO_VSI:
- act |= (rinfo->sw_act.fwd_id.hw_vsi_id <<
- ICE_SINGLE_ACT_VSI_ID_S) & ICE_SINGLE_ACT_VSI_ID_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+ rinfo->sw_act.fwd_id.hw_vsi_id);
act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_VALID_BIT;
break;
case ICE_FWD_TO_Q:
act |= ICE_SINGLE_ACT_TO_Q;
- act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
- ICE_SINGLE_ACT_Q_INDEX_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+ rinfo->sw_act.fwd_id.q_id);
break;
case ICE_FWD_TO_QGRP:
q_rgn = rinfo->sw_act.qgrp_size > 0 ?
(u8)ilog2(rinfo->sw_act.qgrp_size) : 0;
act |= ICE_SINGLE_ACT_TO_Q;
- act |= (rinfo->sw_act.fwd_id.q_id << ICE_SINGLE_ACT_Q_INDEX_S) &
- ICE_SINGLE_ACT_Q_INDEX_M;
- act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) &
- ICE_SINGLE_ACT_Q_REGION_M;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_Q_INDEX_M,
+ rinfo->sw_act.fwd_id.q_id);
+ act |= FIELD_PREP(ICE_SINGLE_ACT_Q_REGION_M, q_rgn);
break;
case ICE_DROP_PACKET:
act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
ICE_SINGLE_ACT_VALID_BIT;
break;
+ case ICE_MIRROR_PACKET:
+ act |= ICE_SINGLE_ACT_OTHER_ACTS;
+ act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
+ rinfo->sw_act.fwd_id.hw_vsi_id);
+ break;
case ICE_NOP:
act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
rinfo->sw_act.fwd_id.hw_vsi_id);
diff --git a/drivers/net/ethernet/intel/ice/ice_tc_lib.c b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
index dd03cb69ad26..b890410a2bc0 100644
--- a/drivers/net/ethernet/intel/ice/ice_tc_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_tc_lib.c
@@ -653,7 +653,7 @@ static int ice_tc_setup_redirect_action(struct net_device *filter_dev,
ice_tc_is_dev_uplink(target_dev)) {
repr = ice_netdev_to_repr(filter_dev);
- fltr->dest_vsi = repr->src_vsi->back->switchdev.uplink_vsi;
+ fltr->dest_vsi = repr->src_vsi->back->eswitch.uplink_vsi;
fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
} else if (ice_tc_is_dev_uplink(filter_dev) &&
ice_is_port_repr_netdev(target_dev)) {
@@ -689,6 +689,41 @@ ice_tc_setup_drop_action(struct net_device *filter_dev,
return 0;
}
+static int ice_tc_setup_mirror_action(struct net_device *filter_dev,
+ struct ice_tc_flower_fltr *fltr,
+ struct net_device *target_dev)
+{
+ struct ice_repr *repr;
+
+ fltr->action.fltr_act = ICE_MIRROR_PACKET;
+
+ if (ice_is_port_repr_netdev(filter_dev) &&
+ ice_is_port_repr_netdev(target_dev)) {
+ repr = ice_netdev_to_repr(target_dev);
+
+ fltr->dest_vsi = repr->src_vsi;
+ fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
+ } else if (ice_is_port_repr_netdev(filter_dev) &&
+ ice_tc_is_dev_uplink(target_dev)) {
+ repr = ice_netdev_to_repr(filter_dev);
+
+ fltr->dest_vsi = repr->src_vsi->back->eswitch.uplink_vsi;
+ fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
+ } else if (ice_tc_is_dev_uplink(filter_dev) &&
+ ice_is_port_repr_netdev(target_dev)) {
+ repr = ice_netdev_to_repr(target_dev);
+
+ fltr->dest_vsi = repr->src_vsi;
+ fltr->direction = ICE_ESWITCH_FLTR_INGRESS;
+ } else {
+ NL_SET_ERR_MSG_MOD(fltr->extack,
+ "Unsupported netdevice in switchdev mode");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int ice_eswitch_tc_parse_action(struct net_device *filter_dev,
struct ice_tc_flower_fltr *fltr,
struct flow_action_entry *act)
@@ -710,6 +745,12 @@ static int ice_eswitch_tc_parse_action(struct net_device *filter_dev,
break;
+ case FLOW_ACTION_MIRRED:
+ err = ice_tc_setup_mirror_action(filter_dev, fltr, act->dev);
+ if (err)
+ return err;
+ break;
+
default:
NL_SET_ERR_MSG_MOD(fltr->extack, "Unsupported action in switchdev mode");
return -EINVAL;
@@ -765,7 +806,7 @@ ice_eswitch_add_tc_fltr(struct ice_vsi *vsi, struct ice_tc_flower_fltr *fltr)
rule_info.sw_act.src = hw->pf_id;
rule_info.flags_info.act = ICE_SINGLE_ACT_LB_ENABLE;
} else if (fltr->direction == ICE_ESWITCH_FLTR_EGRESS &&
- fltr->dest_vsi == vsi->back->switchdev.uplink_vsi) {
+ fltr->dest_vsi == vsi->back->eswitch.uplink_vsi) {
/* VF to Uplink */
rule_info.sw_act.flag |= ICE_FLTR_TX;
rule_info.sw_act.src = vsi->idx;
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index 9e97ea863068..97d41d6ebf1f 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -513,11 +513,6 @@ int ice_setup_rx_ring(struct ice_rx_ring *rx_ring)
if (ice_is_xdp_ena_vsi(rx_ring->vsi))
WRITE_ONCE(rx_ring->xdp_prog, rx_ring->vsi->xdp_prog);
- if (rx_ring->vsi->type == ICE_VSI_PF &&
- !xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
- if (xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev,
- rx_ring->q_index, rx_ring->q_vector->napi.napi_id))
- goto err;
return 0;
err:
@@ -557,13 +552,14 @@ ice_rx_frame_truesize(struct ice_rx_ring *rx_ring, const unsigned int size)
* @xdp_prog: XDP program to run
* @xdp_ring: ring to be used for XDP_TX action
* @rx_buf: Rx buffer to store the XDP action
+ * @eop_desc: Last descriptor in packet to read metadata from
*
* Returns any of ICE_XDP_{PASS, CONSUMED, TX, REDIR}
*/
static void
ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
struct bpf_prog *xdp_prog, struct ice_tx_ring *xdp_ring,
- struct ice_rx_buf *rx_buf)
+ struct ice_rx_buf *rx_buf, union ice_32b_rx_flex_desc *eop_desc)
{
unsigned int ret = ICE_XDP_PASS;
u32 act;
@@ -571,6 +567,8 @@ ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
if (!xdp_prog)
goto exit;
+ ice_xdp_meta_set_desc(xdp, eop_desc);
+
act = bpf_prog_run_xdp(xdp_prog, xdp);
switch (act) {
case XDP_PASS:
@@ -600,9 +598,7 @@ out_failure:
ret = ICE_XDP_CONSUMED;
}
exit:
- rx_buf->act = ret;
- if (unlikely(xdp_buff_has_frags(xdp)))
- ice_set_rx_bufs_act(xdp, rx_ring, ret);
+ ice_set_rx_bufs_act(xdp, rx_ring, ret);
}
/**
@@ -890,14 +886,17 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
}
if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) {
- if (unlikely(xdp_buff_has_frags(xdp)))
- ice_set_rx_bufs_act(xdp, rx_ring, ICE_XDP_CONSUMED);
+ ice_set_rx_bufs_act(xdp, rx_ring, ICE_XDP_CONSUMED);
return -ENOMEM;
}
__skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page,
rx_buf->page_offset, size);
sinfo->xdp_frags_size += size;
+ /* remember frag count before XDP prog execution; bpf_xdp_adjust_tail()
+ * can pop off frags but driver has to handle it on its own
+ */
+ rx_ring->nr_frags = sinfo->nr_frags;
if (page_is_pfmemalloc(rx_buf->page))
xdp_buff_set_frag_pfmemalloc(xdp);
@@ -1180,8 +1179,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
struct sk_buff *skb;
unsigned int size;
u16 stat_err_bits;
- u16 vlan_tag = 0;
- u16 rx_ptype;
+ u16 vlan_tci;
/* get the Rx desc from Rx ring based on 'next_to_clean' */
rx_desc = ICE_RX_DESC(rx_ring, ntc);
@@ -1241,7 +1239,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
if (ice_is_non_eop(rx_ring, rx_desc))
continue;
- ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_buf);
+ ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_buf, rx_desc);
if (rx_buf->act == ICE_XDP_PASS)
goto construct_skb;
total_rx_bytes += xdp_get_buff_len(xdp);
@@ -1249,6 +1247,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
xdp->data = NULL;
rx_ring->first_desc = ntc;
+ rx_ring->nr_frags = 0;
continue;
construct_skb:
if (likely(ice_ring_uses_build_skb(rx_ring)))
@@ -1264,10 +1263,12 @@ construct_skb:
ICE_XDP_CONSUMED);
xdp->data = NULL;
rx_ring->first_desc = ntc;
+ rx_ring->nr_frags = 0;
break;
}
xdp->data = NULL;
rx_ring->first_desc = ntc;
+ rx_ring->nr_frags = 0;
stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_RXE_S);
if (unlikely(ice_test_staterr(rx_desc->wb.status_error0,
@@ -1276,7 +1277,7 @@ construct_skb:
continue;
}
- vlan_tag = ice_get_vlan_tag_from_rx_desc(rx_desc);
+ vlan_tci = ice_get_vlan_tci(rx_desc);
/* pad the skb if needed, to make a valid ethernet frame */
if (eth_skb_pad(skb))
@@ -1286,14 +1287,11 @@ construct_skb:
total_rx_bytes += skb->len;
/* populate checksum, VLAN, and protocol */
- rx_ptype = le16_to_cpu(rx_desc->wb.ptype_flex_flags0) &
- ICE_RX_FLEX_DESC_PTYPE_M;
-
- ice_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
+ ice_process_skb_fields(rx_ring, rx_desc, skb);
ice_trace(clean_rx_irq_indicate, rx_ring, rx_desc, skb);
/* send completed skb up the stack */
- ice_receive_skb(rx_ring, skb, vlan_tag);
+ ice_receive_skb(rx_ring, skb, vlan_tci);
/* update budget accounting */
total_rx_pkts++;
@@ -1494,9 +1492,9 @@ static void ice_set_wb_on_itr(struct ice_q_vector *q_vector)
* be static in non-adaptive mode (user configured)
*/
wr32(&vsi->back->hw, GLINT_DYN_CTL(q_vector->reg_idx),
- ((ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S) &
- GLINT_DYN_CTL_ITR_INDX_M) | GLINT_DYN_CTL_INTENA_MSK_M |
- GLINT_DYN_CTL_WB_ON_ITR_M);
+ FIELD_PREP(GLINT_DYN_CTL_ITR_INDX_M, ICE_ITR_NONE) |
+ FIELD_PREP(GLINT_DYN_CTL_INTENA_MSK_M, 1) |
+ FIELD_PREP(GLINT_DYN_CTL_WB_ON_ITR_M, 1));
q_vector->wb_on_itr = true;
}
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h
index daf7b9dbb143..af955b0e5dc5 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h
@@ -257,6 +257,20 @@ enum ice_rx_dtype {
ICE_RX_DTYPE_SPLIT_ALWAYS = 2,
};
+struct ice_pkt_ctx {
+ u64 cached_phctime;
+ __be16 vlan_proto;
+};
+
+struct ice_xdp_buff {
+ struct xdp_buff xdp_buff;
+ const union ice_32b_rx_flex_desc *eop_desc;
+ const struct ice_pkt_ctx *pkt_ctx;
+};
+
+/* Required for compatibility with xdp_buffs from xsk_pool */
+static_assert(offsetof(struct ice_xdp_buff, xdp_buff) == 0);
+
/* indices into GLINT_ITR registers */
#define ICE_RX_ITR ICE_IDX_ITR0
#define ICE_TX_ITR ICE_IDX_ITR1
@@ -298,7 +312,6 @@ enum ice_dynamic_itr {
/* descriptor ring, associated with a VSI */
struct ice_rx_ring {
/* CL1 - 1st cacheline starts here */
- struct ice_rx_ring *next; /* pointer to next ring in q_vector */
void *desc; /* Descriptor ring memory */
struct device *dev; /* Used for DMA mapping */
struct net_device *netdev; /* netdev ring maps to */
@@ -310,13 +323,24 @@ struct ice_rx_ring {
u16 count; /* Number of descriptors */
u16 reg_idx; /* HW register index of the ring */
u16 next_to_alloc;
- /* CL2 - 2nd cacheline starts here */
+
union {
struct ice_rx_buf *rx_buf;
struct xdp_buff **xdp_buf;
};
- struct xdp_buff xdp;
+ /* CL2 - 2nd cacheline starts here */
+ union {
+ struct ice_xdp_buff xdp_ext;
+ struct xdp_buff xdp;
+ };
/* CL3 - 3rd cacheline starts here */
+ union {
+ struct ice_pkt_ctx pkt_ctx;
+ struct {
+ u64 cached_phctime;
+ __be16 vlan_proto;
+ };
+ };
struct bpf_prog *xdp_prog;
u16 rx_offset;
@@ -332,9 +356,10 @@ struct ice_rx_ring {
/* CL4 - 4th cacheline starts here */
struct ice_channel *ch;
struct ice_tx_ring *xdp_ring;
+ struct ice_rx_ring *next; /* pointer to next ring in q_vector */
struct xsk_buff_pool *xsk_pool;
+ u32 nr_frags;
dma_addr_t dma; /* physical address of ring */
- u64 cached_phctime;
u16 rx_buf_len;
u8 dcb_tc; /* Traffic class of ring */
u8 ptp_rx;
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
index 7e06373e14d9..839e5da24ad5 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c
@@ -63,28 +63,42 @@ static enum pkt_hash_types ice_ptype_to_htype(u16 ptype)
}
/**
- * ice_rx_hash - set the hash value in the skb
+ * ice_get_rx_hash - get RX hash value from descriptor
+ * @rx_desc: specific descriptor
+ *
+ * Returns hash, if present, 0 otherwise.
+ */
+static u32 ice_get_rx_hash(const union ice_32b_rx_flex_desc *rx_desc)
+{
+ const struct ice_32b_rx_flex_desc_nic *nic_mdid;
+
+ if (unlikely(rx_desc->wb.rxdid != ICE_RXDID_FLEX_NIC))
+ return 0;
+
+ nic_mdid = (struct ice_32b_rx_flex_desc_nic *)rx_desc;
+ return le32_to_cpu(nic_mdid->rss_hash);
+}
+
+/**
+ * ice_rx_hash_to_skb - set the hash value in the skb
* @rx_ring: descriptor ring
* @rx_desc: specific descriptor
* @skb: pointer to current skb
* @rx_ptype: the ptype value from the descriptor
*/
static void
-ice_rx_hash(struct ice_rx_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc,
- struct sk_buff *skb, u16 rx_ptype)
+ice_rx_hash_to_skb(const struct ice_rx_ring *rx_ring,
+ const union ice_32b_rx_flex_desc *rx_desc,
+ struct sk_buff *skb, u16 rx_ptype)
{
- struct ice_32b_rx_flex_desc_nic *nic_mdid;
u32 hash;
if (!(rx_ring->netdev->features & NETIF_F_RXHASH))
return;
- if (rx_desc->wb.rxdid != ICE_RXDID_FLEX_NIC)
- return;
-
- nic_mdid = (struct ice_32b_rx_flex_desc_nic *)rx_desc;
- hash = le32_to_cpu(nic_mdid->rss_hash);
- skb_set_hash(skb, hash, ice_ptype_to_htype(rx_ptype));
+ hash = ice_get_rx_hash(rx_desc);
+ if (likely(hash))
+ skb_set_hash(skb, hash, ice_ptype_to_htype(rx_ptype));
}
/**
@@ -171,11 +185,38 @@ checksum_fail:
}
/**
+ * ice_ptp_rx_hwts_to_skb - Put RX timestamp into skb
+ * @rx_ring: Ring to get the VSI info
+ * @rx_desc: Receive descriptor
+ * @skb: Particular skb to send timestamp with
+ *
+ * The timestamp is in ns, so we must convert the result first.
+ */
+static void
+ice_ptp_rx_hwts_to_skb(struct ice_rx_ring *rx_ring,
+ const union ice_32b_rx_flex_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ u64 ts_ns = ice_ptp_get_rx_hwts(rx_desc, &rx_ring->pkt_ctx);
+
+ skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ts_ns);
+}
+
+/**
+ * ice_get_ptype - Read HW packet type from the descriptor
+ * @rx_desc: RX descriptor
+ */
+static u16 ice_get_ptype(const union ice_32b_rx_flex_desc *rx_desc)
+{
+ return le16_to_cpu(rx_desc->wb.ptype_flex_flags0) &
+ ICE_RX_FLEX_DESC_PTYPE_M;
+}
+
+/**
* ice_process_skb_fields - Populate skb header fields from Rx descriptor
* @rx_ring: Rx descriptor ring packet is being transacted on
* @rx_desc: pointer to the EOP Rx descriptor
* @skb: pointer to current skb being populated
- * @ptype: the packet type decoded by hardware
*
* This function checks the ring, descriptor, and packet information in
* order to populate the hash, checksum, VLAN, protocol, and
@@ -184,9 +225,11 @@ checksum_fail:
void
ice_process_skb_fields(struct ice_rx_ring *rx_ring,
union ice_32b_rx_flex_desc *rx_desc,
- struct sk_buff *skb, u16 ptype)
+ struct sk_buff *skb)
{
- ice_rx_hash(rx_ring, rx_desc, skb, ptype);
+ u16 ptype = ice_get_ptype(rx_desc);
+
+ ice_rx_hash_to_skb(rx_ring, rx_desc, skb, ptype);
/* modifies the skb - consumes the enet header */
skb->protocol = eth_type_trans(skb, rx_ring->netdev);
@@ -194,28 +237,24 @@ ice_process_skb_fields(struct ice_rx_ring *rx_ring,
ice_rx_csum(rx_ring, skb, rx_desc, ptype);
if (rx_ring->ptp_rx)
- ice_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
+ ice_ptp_rx_hwts_to_skb(rx_ring, rx_desc, skb);
}
/**
* ice_receive_skb - Send a completed packet up the stack
* @rx_ring: Rx ring in play
* @skb: packet to send up
- * @vlan_tag: VLAN tag for packet
+ * @vlan_tci: VLAN TCI for packet
*
* This function sends the completed packet (via. skb) up the stack using
* gro receive functions (with/without VLAN tag)
*/
void
-ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag)
+ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tci)
{
- netdev_features_t features = rx_ring->netdev->features;
- bool non_zero_vlan = !!(vlan_tag & VLAN_VID_MASK);
-
- if ((features & NETIF_F_HW_VLAN_CTAG_RX) && non_zero_vlan)
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
- else if ((features & NETIF_F_HW_VLAN_STAG_RX) && non_zero_vlan)
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), vlan_tag);
+ if ((vlan_tci & VLAN_VID_MASK) && rx_ring->vlan_proto)
+ __vlan_hwaccel_put_tag(skb, rx_ring->vlan_proto,
+ vlan_tci);
napi_gro_receive(&rx_ring->q_vector->napi, skb);
}
@@ -464,3 +503,125 @@ void ice_finalize_xdp_rx(struct ice_tx_ring *xdp_ring, unsigned int xdp_res,
spin_unlock(&xdp_ring->tx_lock);
}
}
+
+/**
+ * ice_xdp_rx_hw_ts - HW timestamp XDP hint handler
+ * @ctx: XDP buff pointer
+ * @ts_ns: destination address
+ *
+ * Copy HW timestamp (if available) to the destination address.
+ */
+static int ice_xdp_rx_hw_ts(const struct xdp_md *ctx, u64 *ts_ns)
+{
+ const struct ice_xdp_buff *xdp_ext = (void *)ctx;
+
+ *ts_ns = ice_ptp_get_rx_hwts(xdp_ext->eop_desc,
+ xdp_ext->pkt_ctx);
+ if (!*ts_ns)
+ return -ENODATA;
+
+ return 0;
+}
+
+/* Define a ptype index -> XDP hash type lookup table.
+ * It uses the same ptype definitions as ice_decode_rx_desc_ptype[],
+ * avoiding possible copy-paste errors.
+ */
+#undef ICE_PTT
+#undef ICE_PTT_UNUSED_ENTRY
+
+#define ICE_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+ [PTYPE] = XDP_RSS_L3_##OUTER_IP_VER | XDP_RSS_L4_##I | XDP_RSS_TYPE_##PL
+
+#define ICE_PTT_UNUSED_ENTRY(PTYPE) [PTYPE] = 0
+
+/* A few supplementary definitions for when XDP hash types do not coincide
+ * with what can be generated from ptype definitions
+ * by means of preprocessor concatenation.
+ */
+#define XDP_RSS_L3_NONE XDP_RSS_TYPE_NONE
+#define XDP_RSS_L4_NONE XDP_RSS_TYPE_NONE
+#define XDP_RSS_TYPE_PAY2 XDP_RSS_TYPE_L2
+#define XDP_RSS_TYPE_PAY3 XDP_RSS_TYPE_NONE
+#define XDP_RSS_TYPE_PAY4 XDP_RSS_L4
+
+static const enum xdp_rss_hash_type
+ice_ptype_to_xdp_hash[ICE_NUM_DEFINED_PTYPES] = {
+ ICE_PTYPES
+};
+
+#undef XDP_RSS_L3_NONE
+#undef XDP_RSS_L4_NONE
+#undef XDP_RSS_TYPE_PAY2
+#undef XDP_RSS_TYPE_PAY3
+#undef XDP_RSS_TYPE_PAY4
+
+#undef ICE_PTT
+#undef ICE_PTT_UNUSED_ENTRY
+
+/**
+ * ice_xdp_rx_hash_type - Get XDP-specific hash type from the RX descriptor
+ * @eop_desc: End of Packet descriptor
+ */
+static enum xdp_rss_hash_type
+ice_xdp_rx_hash_type(const union ice_32b_rx_flex_desc *eop_desc)
+{
+ u16 ptype = ice_get_ptype(eop_desc);
+
+ if (unlikely(ptype >= ICE_NUM_DEFINED_PTYPES))
+ return 0;
+
+ return ice_ptype_to_xdp_hash[ptype];
+}
+
+/**
+ * ice_xdp_rx_hash - RX hash XDP hint handler
+ * @ctx: XDP buff pointer
+ * @hash: hash destination address
+ * @rss_type: XDP hash type destination address
+ *
+ * Copy RX hash (if available) and its type to the destination address.
+ */
+static int ice_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash,
+ enum xdp_rss_hash_type *rss_type)
+{
+ const struct ice_xdp_buff *xdp_ext = (void *)ctx;
+
+ *hash = ice_get_rx_hash(xdp_ext->eop_desc);
+ *rss_type = ice_xdp_rx_hash_type(xdp_ext->eop_desc);
+ if (!likely(*hash))
+ return -ENODATA;
+
+ return 0;
+}
+
+/**
+ * ice_xdp_rx_vlan_tag - VLAN tag XDP hint handler
+ * @ctx: XDP buff pointer
+ * @vlan_proto: destination address for VLAN protocol
+ * @vlan_tci: destination address for VLAN TCI
+ *
+ * Copy VLAN tag (if was stripped) and corresponding protocol
+ * to the destination address.
+ */
+static int ice_xdp_rx_vlan_tag(const struct xdp_md *ctx, __be16 *vlan_proto,
+ u16 *vlan_tci)
+{
+ const struct ice_xdp_buff *xdp_ext = (void *)ctx;
+
+ *vlan_proto = xdp_ext->pkt_ctx->vlan_proto;
+ if (!*vlan_proto)
+ return -ENODATA;
+
+ *vlan_tci = ice_get_vlan_tci(xdp_ext->eop_desc);
+ if (!*vlan_tci)
+ return -ENODATA;
+
+ return 0;
+}
+
+const struct xdp_metadata_ops ice_xdp_md_ops = {
+ .xmo_rx_timestamp = ice_xdp_rx_hw_ts,
+ .xmo_rx_hash = ice_xdp_rx_hash,
+ .xmo_rx_vlan_tag = ice_xdp_rx_vlan_tag,
+};
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
index 115969ecdf7b..afcead4baef4 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h
@@ -12,26 +12,39 @@
* act: action to store onto Rx buffers related to XDP buffer parts
*
* Set action that should be taken before putting Rx buffer from first frag
- * to one before last. Last one is handled by caller of this function as it
- * is the EOP frag that is currently being processed. This function is
- * supposed to be called only when XDP buffer contains frags.
+ * to the last.
*/
static inline void
ice_set_rx_bufs_act(struct xdp_buff *xdp, const struct ice_rx_ring *rx_ring,
const unsigned int act)
{
- const struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
- u32 first = rx_ring->first_desc;
- u32 nr_frags = sinfo->nr_frags;
+ u32 sinfo_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags;
+ u32 nr_frags = rx_ring->nr_frags + 1;
+ u32 idx = rx_ring->first_desc;
u32 cnt = rx_ring->count;
struct ice_rx_buf *buf;
for (int i = 0; i < nr_frags; i++) {
- buf = &rx_ring->rx_buf[first];
+ buf = &rx_ring->rx_buf[idx];
buf->act = act;
- if (++first == cnt)
- first = 0;
+ if (++idx == cnt)
+ idx = 0;
+ }
+
+ /* adjust pagecnt_bias on frags freed by XDP prog */
+ if (sinfo_frags < rx_ring->nr_frags && act == ICE_XDP_CONSUMED) {
+ u32 delta = rx_ring->nr_frags - sinfo_frags;
+
+ while (delta) {
+ if (idx == 0)
+ idx = cnt - 1;
+ else
+ idx--;
+ buf = &rx_ring->rx_buf[idx];
+ buf->pagecnt_bias--;
+ delta--;
+ }
}
}
@@ -84,7 +97,7 @@ ice_build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag)
}
/**
- * ice_get_vlan_tag_from_rx_desc - get VLAN from Rx flex descriptor
+ * ice_get_vlan_tci - get VLAN TCI from Rx flex descriptor
* @rx_desc: Rx 32b flex descriptor with RXDID=2
*
* The OS and current PF implementation only support stripping a single VLAN tag
@@ -92,7 +105,7 @@ ice_build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag)
* one is found return the tag, else return 0 to mean no VLAN tag was found.
*/
static inline u16
-ice_get_vlan_tag_from_rx_desc(union ice_32b_rx_flex_desc *rx_desc)
+ice_get_vlan_tci(const union ice_32b_rx_flex_desc *rx_desc)
{
u16 stat_err_bits;
@@ -148,7 +161,17 @@ void ice_release_rx_desc(struct ice_rx_ring *rx_ring, u16 val);
void
ice_process_skb_fields(struct ice_rx_ring *rx_ring,
union ice_32b_rx_flex_desc *rx_desc,
- struct sk_buff *skb, u16 ptype);
+ struct sk_buff *skb);
void
-ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag);
+ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tci);
+
+static inline void
+ice_xdp_meta_set_desc(struct xdp_buff *xdp,
+ union ice_32b_rx_flex_desc *eop_desc)
+{
+ struct ice_xdp_buff *xdp_ext = container_of(xdp, struct ice_xdp_buff,
+ xdp_buff);
+
+ xdp_ext->eop_desc = eop_desc;
+}
#endif /* !_ICE_TXRX_LIB_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index a18ca0ff879f..a508e917ce5f 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -17,6 +17,7 @@
#include "ice_protocol_type.h"
#include "ice_sbq_cmd.h"
#include "ice_vlan_mode.h"
+#include "ice_fwlog.h"
static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc)
{
@@ -246,6 +247,7 @@ struct ice_fd_hw_prof {
int cnt;
u64 entry_h[ICE_MAX_FDIR_VSI_PER_FILTER][ICE_FD_HW_SEG_MAX];
u16 vsi_h[ICE_MAX_FDIR_VSI_PER_FILTER];
+ u64 prof_id[ICE_FD_HW_SEG_MAX];
};
/* Common HW capabilities for SW use */
@@ -351,6 +353,7 @@ struct ice_ts_func_info {
#define ICE_TS_TMR0_ENA_M BIT(25)
#define ICE_TS_TMR1_ENA_M BIT(26)
#define ICE_TS_LL_TX_TS_READ_M BIT(28)
+#define ICE_TS_LL_TX_TS_INT_READ_M BIT(29)
struct ice_ts_dev_info {
/* Device specific info */
@@ -364,6 +367,7 @@ struct ice_ts_dev_info {
u8 tmr0_ena;
u8 tmr1_ena;
u8 ts_ll_read;
+ u8 ts_ll_int_read;
};
/* Function specific capabilities */
@@ -377,6 +381,8 @@ struct ice_hw_func_caps {
struct ice_ts_func_info ts_func_info;
};
+#define ICE_SENSOR_SUPPORT_E810_INT_TEMP_BIT 0
+
/* Device wide capabilities */
struct ice_hw_dev_caps {
struct ice_hw_common_caps common_cap;
@@ -385,6 +391,11 @@ struct ice_hw_dev_caps {
u32 num_flow_director_fltr; /* Number of FD filters available */
struct ice_ts_dev_info ts_dev_info;
u32 num_funcs;
+ /* bitmap of supported sensors
+ * bit 0 - internal temperature sensor
+ * bit 31:1 - Reserved
+ */
+ u32 supported_sensors;
};
/* MAC info */
@@ -730,24 +741,6 @@ struct ice_switch_info {
DECLARE_BITMAP(prof_res_bm[ICE_MAX_NUM_PROFILES], ICE_MAX_FV_WORDS);
};
-/* FW logging configuration */
-struct ice_fw_log_evnt {
- u8 cfg : 4; /* New event enables to configure */
- u8 cur : 4; /* Current/active event enables */
-};
-
-struct ice_fw_log_cfg {
- u8 cq_en : 1; /* FW logging is enabled via the control queue */
- u8 uart_en : 1; /* FW logging is enabled via UART for all PFs */
- u8 actv_evnts; /* Cumulation of currently enabled log events */
-
-#define ICE_FW_LOG_EVNT_INFO (ICE_AQC_FW_LOG_INFO_EN >> ICE_AQC_FW_LOG_EN_S)
-#define ICE_FW_LOG_EVNT_INIT (ICE_AQC_FW_LOG_INIT_EN >> ICE_AQC_FW_LOG_EN_S)
-#define ICE_FW_LOG_EVNT_FLOW (ICE_AQC_FW_LOG_FLOW_EN >> ICE_AQC_FW_LOG_EN_S)
-#define ICE_FW_LOG_EVNT_ERR (ICE_AQC_FW_LOG_ERR_EN >> ICE_AQC_FW_LOG_EN_S)
- struct ice_fw_log_evnt evnts[ICE_AQC_FW_LOG_ID_MAX];
-};
-
/* Enum defining the different states of the mailbox snapshot in the
* PF-VF mailbox overflow detection algorithm. The snapshot can be in
* states:
@@ -827,7 +820,7 @@ struct ice_mbx_data {
enum ice_phy_model {
ICE_PHY_UNSUP = -1,
ICE_PHY_E810 = 1,
- ICE_PHY_E822,
+ ICE_PHY_E82X,
};
/* Port hardware description */
@@ -889,7 +882,9 @@ struct ice_hw {
u8 fw_patch; /* firmware patch version */
u32 fw_build; /* firmware build number */
- struct ice_fw_log_cfg fw_log;
+ struct ice_fwlog_cfg fwlog_cfg;
+ bool fwlog_supported; /* does hardware support FW logging? */
+ struct ice_fwlog_ring fwlog_ring;
/* Device max aggregate bandwidths corresponding to the GL_PWR_MODE_CTL
* register. Used for determining the ITR/INTRL granularity during
@@ -910,10 +905,9 @@ struct ice_hw {
/* INTRL granularity in 1 us */
u8 intrl_gran;
-#define ICE_PHY_PER_NAC_E822 1
#define ICE_MAX_QUAD 2
-#define ICE_QUADS_PER_PHY_E822 2
-#define ICE_PORTS_PER_PHY_E822 8
+#define ICE_QUADS_PER_PHY_E82X 2
+#define ICE_PORTS_PER_PHY_E82X 8
#define ICE_PORTS_PER_QUAD 4
#define ICE_PORTS_PER_PHY_E810 4
#define ICE_NUM_EXTERNAL_PORTS (ICE_MAX_QUAD * ICE_PORTS_PER_QUAD)
@@ -1009,7 +1003,6 @@ struct ice_hw_port_stats {
u64 error_bytes; /* errbc */
u64 mac_local_faults; /* mlfc */
u64 mac_remote_faults; /* mrfc */
- u64 rx_len_errors; /* rlec */
u64 link_xon_rx; /* lxonrxc */
u64 link_xoff_rx; /* lxoffrxc */
u64 link_xon_tx; /* lxontxc */
@@ -1048,6 +1041,7 @@ enum ice_sw_fwd_act_type {
ICE_FWD_TO_Q,
ICE_FWD_TO_QGRP,
ICE_DROP_PACKET,
+ ICE_MIRROR_PACKET,
ICE_NOP,
ICE_INVAL_ACT
};
@@ -1078,7 +1072,7 @@ struct ice_aq_get_set_rss_lut_params {
#define ICE_OROM_VER_BUILD_SHIFT 8
#define ICE_OROM_VER_BUILD_MASK (0xffff << ICE_OROM_VER_BUILD_SHIFT)
#define ICE_OROM_VER_SHIFT 24
-#define ICE_OROM_VER_MASK (0xff << ICE_OROM_VER_SHIFT)
+#define ICE_OROM_VER_MASK (0xffU << ICE_OROM_VER_SHIFT)
#define ICE_SR_PFA_PTR 0x40
#define ICE_SR_1ST_NVM_BANK_PTR 0x42
#define ICE_SR_NVM_BANK_SIZE 0x43
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
index b7ae09952156..2ffdae9a82df 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c
@@ -248,29 +248,44 @@ static void ice_vf_pre_vsi_rebuild(struct ice_vf *vf)
}
/**
- * ice_vf_recreate_vsi - Release and re-create the VF's VSI
- * @vf: VF to recreate the VSI for
+ * ice_vf_reconfig_vsi - Reconfigure a VF VSI with the device
+ * @vf: VF to reconfigure the VSI for
*
- * This is only called when a single VF is being reset (i.e. VVF, VFLR, host
- * VF configuration change, etc)
+ * This is called when a single VF is being reset (i.e. VVF, VFLR, host VF
+ * configuration change, etc).
*
- * It releases and then re-creates a new VSI.
+ * It brings the VSI down and then reconfigures it with the hardware.
*/
-static int ice_vf_recreate_vsi(struct ice_vf *vf)
+int ice_vf_reconfig_vsi(struct ice_vf *vf)
{
+ struct ice_vsi *vsi = ice_get_vf_vsi(vf);
+ struct ice_vsi_cfg_params params = {};
struct ice_pf *pf = vf->pf;
int err;
- ice_vf_vsi_release(vf);
+ if (WARN_ON(!vsi))
+ return -EINVAL;
+
+ params = ice_vsi_to_params(vsi);
+ params.flags = ICE_VSI_FLAG_NO_INIT;
+
+ ice_vsi_decfg(vsi);
+ ice_fltr_remove_all(vsi);
- err = vf->vf_ops->create_vsi(vf);
+ err = ice_vsi_cfg(vsi, &params);
if (err) {
dev_err(ice_pf_to_dev(pf),
- "Failed to recreate the VF%u's VSI, error %d\n",
+ "Failed to reconfigure the VF%u's VSI, error %d\n",
vf->vf_id, err);
return err;
}
+ /* Update the lan_vsi_num field since it might have been changed. The
+ * PF lan_vsi_idx number remains the same so we don't need to change
+ * that.
+ */
+ vf->lan_vsi_num = vsi->vsi_num;
+
return 0;
}
@@ -760,6 +775,7 @@ void ice_reset_all_vfs(struct ice_pf *pf)
ice_for_each_vf(pf, bkt, vf) {
mutex_lock(&vf->cfg_lock);
+ ice_eswitch_detach(pf, vf);
vf->driver_caps = 0;
ice_vc_set_default_allowlist(vf);
@@ -775,13 +791,11 @@ void ice_reset_all_vfs(struct ice_pf *pf)
ice_vf_rebuild_vsi(vf);
ice_vf_post_vsi_rebuild(vf);
+ ice_eswitch_attach(pf, vf);
+
mutex_unlock(&vf->cfg_lock);
}
- if (ice_is_eswitch_mode_switchdev(pf))
- if (ice_eswitch_rebuild(pf))
- dev_warn(dev, "eswitch rebuild failed\n");
-
ice_flush(hw);
clear_bit(ICE_VF_DIS, pf->state);
@@ -929,7 +943,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
ice_vf_pre_vsi_rebuild(vf);
- if (ice_vf_recreate_vsi(vf)) {
+ if (ice_vf_reconfig_vsi(vf)) {
dev_err(dev, "Failed to release and setup the VF%u's VSI\n",
vf->vf_id);
err = -EFAULT;
@@ -943,7 +957,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
goto out_unlock;
}
- ice_eswitch_update_repr(vsi);
+ ice_eswitch_update_repr(vf->repr_id, vsi);
/* if the VF has been reset allow it to come up again */
ice_mbx_clear_malvf(&vf->mbx_info);
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.h b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
index 93c774f2f437..0cc9034065c5 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.h
@@ -62,7 +62,6 @@ struct ice_vf_ops {
bool (*poll_reset_status)(struct ice_vf *vf);
void (*clear_reset_trigger)(struct ice_vf *vf);
void (*irq_close)(struct ice_vf *vf);
- int (*create_vsi)(struct ice_vf *vf);
void (*post_vsi_rebuild)(struct ice_vf *vf);
};
@@ -130,7 +129,7 @@ struct ice_vf {
struct ice_mdd_vf_events mdd_tx_events;
DECLARE_BITMAP(opcodes_allowlist, VIRTCHNL_OP_MAX);
- struct ice_repr *repr;
+ unsigned long repr_id;
const struct ice_virtchnl_ops *virtchnl_ops;
const struct ice_vf_ops *vf_ops;
diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
index 0c7e77c0a09f..91ba7fe0eaee 100644
--- a/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
+++ b/drivers/net/ethernet/intel/ice/ice_vf_lib_private.h
@@ -23,6 +23,7 @@
#warning "Only include ice_vf_lib_private.h in CONFIG_PCI_IOV virtualization files"
#endif
+int ice_vf_reconfig_vsi(struct ice_vf *vf);
void ice_initialize_vf_entry(struct ice_vf *vf);
void ice_dis_vf_qs(struct ice_vf *vf);
int ice_check_vf_init(struct ice_vf *vf);
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.c b/drivers/net/ethernet/intel/ice/ice_virtchnl.c
index 1c7b4ded948b..6f2328a049bf 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.c
@@ -440,7 +440,6 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
vf->driver_caps = *(u32 *)msg;
else
vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 |
- VIRTCHNL_VF_OFFLOAD_RSS_REG |
VIRTCHNL_VF_OFFLOAD_VLAN;
vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2;
@@ -453,14 +452,8 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg)
vfres->vf_cap_flags |= ice_vc_get_vlan_caps(hw, vf, vsi,
vf->driver_caps);
- if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
+ if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
- } else {
- if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ)
- vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ;
- else
- vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG;
- }
if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC)
vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC;
@@ -689,9 +682,7 @@ out:
* a specific virtchnl RSS cfg
* @hw: pointer to the hardware
* @rss_cfg: pointer to the virtchnl RSS cfg
- * @addl_hdrs: pointer to the protocol header fields (ICE_FLOW_SEG_HDR_*)
- * to configure
- * @hash_flds: pointer to the hash bit fields (ICE_FLOW_HASH_*) to configure
+ * @hash_cfg: pointer to the HW hash configuration
*
* Return true if all the protocol header and hash fields in the RSS cfg could
* be parsed, else return false
@@ -699,13 +690,23 @@ out:
* This function parses the virtchnl RSS cfg to be the intended
* hash fields and the intended header for RSS configuration
*/
-static bool
-ice_vc_parse_rss_cfg(struct ice_hw *hw, struct virtchnl_rss_cfg *rss_cfg,
- u32 *addl_hdrs, u64 *hash_flds)
+static bool ice_vc_parse_rss_cfg(struct ice_hw *hw,
+ struct virtchnl_rss_cfg *rss_cfg,
+ struct ice_rss_hash_cfg *hash_cfg)
{
const struct ice_vc_hash_field_match_type *hf_list;
const struct ice_vc_hdr_match_type *hdr_list;
int i, hf_list_len, hdr_list_len;
+ u32 *addl_hdrs = &hash_cfg->addl_hdrs;
+ u64 *hash_flds = &hash_cfg->hash_flds;
+
+ /* set outer layer RSS as default */
+ hash_cfg->hdr_type = ICE_RSS_OUTER_HEADERS;
+
+ if (rss_cfg->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)
+ hash_cfg->symm = true;
+ else
+ hash_cfg->symm = false;
hf_list = ice_vc_hash_field_list;
hf_list_len = ARRAY_SIZE(ice_vc_hash_field_list);
@@ -823,8 +824,8 @@ static int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add)
int status;
lut_type = ICE_AQ_VSI_Q_OPT_RSS_LUT_VSI;
- hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_XOR :
- ICE_AQ_VSI_Q_OPT_RSS_TPLZ;
+ hash_type = add ? ICE_AQ_VSI_Q_OPT_RSS_HASH_XOR :
+ ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
@@ -832,11 +833,9 @@ static int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add)
goto error_param;
}
- ctx->info.q_opt_rss = ((lut_type <<
- ICE_AQ_VSI_Q_OPT_RSS_LUT_S) &
- ICE_AQ_VSI_Q_OPT_RSS_LUT_M) |
- (hash_type &
- ICE_AQ_VSI_Q_OPT_RSS_HASH_M);
+ ctx->info.q_opt_rss =
+ FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_LUT_M, lut_type) |
+ FIELD_PREP(ICE_AQ_VSI_Q_OPT_RSS_HASH_M, hash_type);
/* Preserve existing queueing option setting */
ctx->info.q_opt_rss |= (vsi->info.q_opt_rss &
@@ -858,18 +857,24 @@ static int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add)
kfree(ctx);
} else {
- u32 addl_hdrs = ICE_FLOW_SEG_HDR_NONE;
- u64 hash_flds = ICE_HASH_INVALID;
+ struct ice_rss_hash_cfg cfg;
+
+ /* Only check for none raw pattern case */
+ if (!ice_vc_validate_pattern(vf, &rss_cfg->proto_hdrs)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+ cfg.addl_hdrs = ICE_FLOW_SEG_HDR_NONE;
+ cfg.hash_flds = ICE_HASH_INVALID;
+ cfg.hdr_type = ICE_RSS_ANY_HEADERS;
- if (!ice_vc_parse_rss_cfg(hw, rss_cfg, &addl_hdrs,
- &hash_flds)) {
+ if (!ice_vc_parse_rss_cfg(hw, rss_cfg, &cfg)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
goto error_param;
}
if (add) {
- if (ice_add_rss_cfg(hw, vsi->idx, hash_flds,
- addl_hdrs)) {
+ if (ice_add_rss_cfg(hw, vsi, &cfg)) {
v_ret = VIRTCHNL_STATUS_ERR_PARAM;
dev_err(dev, "ice_add_rss_cfg failed for vsi = %d, v_ret = %d\n",
vsi->vsi_num, v_ret);
@@ -877,8 +882,7 @@ static int ice_vc_handle_rss_cfg(struct ice_vf *vf, u8 *msg, bool add)
} else {
int status;
- status = ice_rem_rss_cfg(hw, vsi->idx, hash_flds,
- addl_hdrs);
+ status = ice_rem_rss_cfg(hw, vsi->idx, &cfg);
/* We just ignore -ENOENT, because if two configurations
* share the same profile remove one of them actually
* removes both, since the profile is deleted.
@@ -989,6 +993,51 @@ error_param:
}
/**
+ * ice_vc_config_rss_hfunc
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Configure the VF's RSS Hash function
+ */
+static int ice_vc_config_rss_hfunc(struct ice_vf *vf, u8 *msg)
+{
+ struct virtchnl_rss_hfunc *vrh = (struct virtchnl_rss_hfunc *)msg;
+ enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS;
+ u8 hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_TPLZ;
+ struct ice_vsi *vsi;
+
+ if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!ice_vc_isvalid_vsi_id(vf, vrh->vsi_id)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (!test_bit(ICE_FLAG_RSS_ENA, vf->pf->flags)) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ vsi = ice_get_vf_vsi(vf);
+ if (!vsi) {
+ v_ret = VIRTCHNL_STATUS_ERR_PARAM;
+ goto error_param;
+ }
+
+ if (vrh->rss_algorithm == VIRTCHNL_RSS_ALG_TOEPLITZ_SYMMETRIC)
+ hfunc = ICE_AQ_VSI_Q_OPT_RSS_HASH_SYM_TPLZ;
+
+ if (ice_set_rss_hfunc(vsi, hfunc))
+ v_ret = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+error_param:
+ return ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_HFUNC, v_ret,
+ NULL, 0);
+}
+
+/**
* ice_vc_cfg_promiscuous_mode_msg
* @vf: pointer to the VF info
* @msg: pointer to the msg buffer
@@ -2634,7 +2683,7 @@ static int ice_vc_set_rss_hena(struct ice_vf *vf, u8 *msg)
}
if (vrh->hena) {
- status = ice_add_avf_rss_cfg(&pf->hw, vsi->idx, vrh->hena);
+ status = ice_add_avf_rss_cfg(&pf->hw, vsi, vrh->hena);
v_ret = ice_err_to_virt_err(status);
}
@@ -3046,7 +3095,7 @@ static struct ice_vlan ice_vc_to_vlan(struct virtchnl_vlan *vc_vlan)
{
struct ice_vlan vlan = { 0 };
- vlan.prio = (vc_vlan->tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+ vlan.prio = FIELD_GET(VLAN_PRIO_MASK, vc_vlan->tci);
vlan.vid = vc_vlan->tci & VLAN_VID_MASK;
vlan.tpid = vc_vlan->tpid;
@@ -3755,6 +3804,7 @@ static const struct ice_virtchnl_ops ice_virtchnl_dflt_ops = {
.cfg_irq_map_msg = ice_vc_cfg_irq_map_msg,
.config_rss_key = ice_vc_config_rss_key,
.config_rss_lut = ice_vc_config_rss_lut,
+ .config_rss_hfunc = ice_vc_config_rss_hfunc,
.get_stats_msg = ice_vc_get_stats_msg,
.cfg_promiscuous_mode_msg = ice_vc_cfg_promiscuous_mode_msg,
.add_vlan_msg = ice_vc_add_vlan_msg,
@@ -3884,6 +3934,7 @@ static const struct ice_virtchnl_ops ice_virtchnl_repr_ops = {
.cfg_irq_map_msg = ice_vc_cfg_irq_map_msg,
.config_rss_key = ice_vc_config_rss_key,
.config_rss_lut = ice_vc_config_rss_lut,
+ .config_rss_hfunc = ice_vc_config_rss_hfunc,
.get_stats_msg = ice_vc_get_stats_msg,
.cfg_promiscuous_mode_msg = ice_vc_repr_cfg_promiscuous_mode,
.add_vlan_msg = ice_vc_add_vlan_msg,
@@ -4066,6 +4117,9 @@ error_handler:
case VIRTCHNL_OP_CONFIG_RSS_LUT:
err = ops->config_rss_lut(vf, msg);
break;
+ case VIRTCHNL_OP_CONFIG_RSS_HFUNC:
+ err = ops->config_rss_hfunc(vf, msg);
+ break;
case VIRTCHNL_OP_GET_STATS:
err = ops->get_stats_msg(vf, msg);
break;
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl.h b/drivers/net/ethernet/intel/ice/ice_virtchnl.h
index cd747718de73..60dfbe05980a 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl.h
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl.h
@@ -32,6 +32,7 @@ struct ice_virtchnl_ops {
int (*cfg_irq_map_msg)(struct ice_vf *vf, u8 *msg);
int (*config_rss_key)(struct ice_vf *vf, u8 *msg);
int (*config_rss_lut)(struct ice_vf *vf, u8 *msg);
+ int (*config_rss_hfunc)(struct ice_vf *vf, u8 *msg);
int (*get_stats_msg)(struct ice_vf *vf, u8 *msg);
int (*cfg_promiscuous_mode_msg)(struct ice_vf *vf, u8 *msg);
int (*add_vlan_msg)(struct ice_vf *vf, u8 *msg);
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c
index 7d547fa616fa..d796dbd2a440 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_allowlist.c
@@ -13,8 +13,6 @@
* - opcodes needed by VF when caps are activated
*
* Caps that don't use new opcodes (no opcodes should be allowed):
- * - VIRTCHNL_VF_OFFLOAD_RSS_AQ
- * - VIRTCHNL_VF_OFFLOAD_RSS_REG
* - VIRTCHNL_VF_OFFLOAD_WB_ON_ITR
* - VIRTCHNL_VF_OFFLOAD_CRC
* - VIRTCHNL_VF_OFFLOAD_RX_POLLING
@@ -68,6 +66,7 @@ static const u32 vlan_v2_allowlist_opcodes[] = {
static const u32 rss_pf_allowlist_opcodes[] = {
VIRTCHNL_OP_CONFIG_RSS_KEY, VIRTCHNL_OP_CONFIG_RSS_LUT,
VIRTCHNL_OP_GET_RSS_HENA_CAPS, VIRTCHNL_OP_SET_RSS_HENA,
+ VIRTCHNL_OP_CONFIG_RSS_HFUNC,
};
/* VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC */
diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
index 24b23b7ef04a..f001553e1a1a 100644
--- a/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
+++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_fdir.c
@@ -10,19 +10,6 @@
#define to_fltr_conf_from_desc(p) \
container_of(p, struct virtchnl_fdir_fltr_conf, input)
-#define ICE_FLOW_PROF_TYPE_S 0
-#define ICE_FLOW_PROF_TYPE_M (0xFFFFFFFFULL << ICE_FLOW_PROF_TYPE_S)
-#define ICE_FLOW_PROF_VSI_S 32
-#define ICE_FLOW_PROF_VSI_M (0xFFFFFFFFULL << ICE_FLOW_PROF_VSI_S)
-
-/* Flow profile ID format:
- * [0:31] - flow type, flow + tun_offs
- * [32:63] - VSI index
- */
-#define ICE_FLOW_PROF_FD(vsi, flow, tun_offs) \
- ((u64)(((((flow) + (tun_offs)) & ICE_FLOW_PROF_TYPE_M)) | \
- (((u64)(vsi) << ICE_FLOW_PROF_VSI_S) & ICE_FLOW_PROF_VSI_M)))
-
#define GTPU_TEID_OFFSET 4
#define GTPU_EH_QFI_OFFSET 1
#define GTPU_EH_QFI_MASK 0x3F
@@ -493,6 +480,7 @@ ice_vc_fdir_rem_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, int tun)
return;
vf_prof = fdir->fdir_prof[flow];
+ prof_id = vf_prof->prof_id[tun];
vf_vsi = ice_get_vf_vsi(vf);
if (!vf_vsi) {
@@ -503,9 +491,6 @@ ice_vc_fdir_rem_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, int tun)
if (!fdir->prof_entry_cnt[flow][tun])
return;
- prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num,
- flow, tun ? ICE_FLTR_PTYPE_MAX : 0);
-
for (i = 0; i < fdir->prof_entry_cnt[flow][tun]; i++)
if (vf_prof->entry_h[i][tun]) {
u16 vsi_num = ice_get_hw_vsi_num(hw, vf_prof->vsi_h[i]);
@@ -647,7 +632,6 @@ ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
struct ice_hw *hw;
u64 entry1_h = 0;
u64 entry2_h = 0;
- u64 prof_id;
int ret;
pf = vf->pf;
@@ -681,18 +665,15 @@ ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
ice_vc_fdir_rem_prof(vf, flow, tun);
}
- prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, flow,
- tun ? ICE_FLTR_PTYPE_MAX : 0);
-
- ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg,
- tun + 1, &prof);
+ ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, seg,
+ tun + 1, false, &prof);
if (ret) {
dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n",
flow, vf->vf_id);
goto err_exit;
}
- ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
+ ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id, vf_vsi->idx,
vf_vsi->idx, ICE_FLOW_PRIO_NORMAL,
seg, &entry1_h);
if (ret) {
@@ -701,7 +682,7 @@ ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
goto err_prof;
}
- ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
+ ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof->id, vf_vsi->idx,
ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,
seg, &entry2_h);
if (ret) {
@@ -725,14 +706,16 @@ ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
vf_prof->cnt++;
fdir->prof_entry_cnt[flow][tun]++;
+ vf_prof->prof_id[tun] = prof->id;
+
return 0;
err_entry_1:
ice_rem_prof_id_flow(hw, ICE_BLK_FD,
- ice_get_hw_vsi_num(hw, vf_vsi->idx), prof_id);
+ ice_get_hw_vsi_num(hw, vf_vsi->idx), prof->id);
ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);
err_prof:
- ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
+ ice_flow_rem_prof(hw, ICE_BLK_FD, prof->id);
err_exit:
return ret;
}
@@ -1480,16 +1463,15 @@ ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
int ret;
stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0);
- if (((stat_err & ICE_FXD_FLTR_WB_QW1_DD_M) >>
- ICE_FXD_FLTR_WB_QW1_DD_S) != ICE_FXD_FLTR_WB_QW1_DD_YES) {
+ if (FIELD_GET(ICE_FXD_FLTR_WB_QW1_DD_M, stat_err) !=
+ ICE_FXD_FLTR_WB_QW1_DD_YES) {
*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
dev_err(dev, "VF %d: Desc Done not set\n", vf->vf_id);
ret = -EINVAL;
goto err_exit;
}
- prog_id = (stat_err & ICE_FXD_FLTR_WB_QW1_PROG_ID_M) >>
- ICE_FXD_FLTR_WB_QW1_PROG_ID_S;
+ prog_id = FIELD_GET(ICE_FXD_FLTR_WB_QW1_PROG_ID_M, stat_err);
if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD &&
ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) {
dev_err(dev, "VF %d: Desc show add, but ctx not",
@@ -1508,8 +1490,7 @@ ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
goto err_exit;
}
- error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_M) >>
- ICE_FXD_FLTR_WB_QW1_FAIL_S;
+ error = FIELD_GET(ICE_FXD_FLTR_WB_QW1_FAIL_M, stat_err);
if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) {
if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) {
dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table",
@@ -1524,8 +1505,7 @@ ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
goto err_exit;
}
- error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M) >>
- ICE_FXD_FLTR_WB_QW1_FAIL_PROF_S;
+ error = FIELD_GET(ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M, stat_err);
if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) {
dev_err(dev, "VF %d: Profile matching error", vf->vf_id);
*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
diff --git a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
index 76266e709a39..2e9ad27cb9d1 100644
--- a/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_vsi_vlan_lib.c
@@ -131,6 +131,7 @@ static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
{
struct ice_hw *hw = &vsi->back->hw;
struct ice_vsi_ctx *ctxt;
+ u8 *ivf;
int err;
/* do not allow modifying VLAN stripping when a port VLAN is configured
@@ -143,19 +144,24 @@ static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
if (!ctxt)
return -ENOMEM;
+ ivf = &ctxt->info.inner_vlan_flags;
+
/* Here we are configuring what the VSI should do with the VLAN tag in
* the Rx packet. We can either leave the tag in the packet or put it in
* the Rx descriptor.
*/
- if (ena)
+ if (ena) {
/* Strip VLAN tag from Rx packet and put it in the desc */
- ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH;
- else
+ *ivf = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M,
+ ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH);
+ } else {
/* Disable stripping. Leave tag in packet */
- ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING;
+ *ivf = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M,
+ ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING);
+ }
/* Allow all packets untagged/tagged */
- ctxt->info.inner_vlan_flags |= ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
+ *ivf |= ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
@@ -481,10 +487,11 @@ int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid)
ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
~(ICE_AQ_VSI_OUTER_VLAN_EMODE_M | ICE_AQ_VSI_OUTER_TAG_TYPE_M);
ctxt->info.outer_vlan_flags |=
- ((ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW_BOTH <<
- ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
- ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
- ICE_AQ_VSI_OUTER_TAG_TYPE_M));
+ /* we want EMODE_SHOW_BOTH, but that value is zero, so the line
+ * above clears it well enough that we don't need to try to set
+ * zero here, so just do the tag type
+ */
+ FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, tag_type);
err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
if (err)
@@ -589,11 +596,9 @@ int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid)
ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M |
ICE_AQ_VSI_OUTER_TAG_TYPE_M);
ctxt->info.outer_vlan_flags |=
- ((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
- ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
- ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M) |
- ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
- ICE_AQ_VSI_OUTER_TAG_TYPE_M);
+ FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M,
+ ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL) |
+ FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, tag_type);
err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
if (err)
@@ -642,9 +647,8 @@ int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi)
ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
ctxt->info.outer_vlan_flags |=
ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
- ((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
- ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
- ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
+ FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M,
+ ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL);
err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
if (err)
@@ -702,8 +706,7 @@ __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
ctxt->info.outer_vlan_flags =
(ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW <<
ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
- ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
- ICE_AQ_VSI_OUTER_TAG_TYPE_M) |
+ FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, tag_type) |
ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED <<
ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) |
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index 99954508184f..2eecd0f39aa6 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -179,6 +179,10 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx)
return -EBUSY;
usleep_range(1000, 2000);
}
+
+ ice_qvec_dis_irq(vsi, rx_ring, q_vector);
+ ice_qvec_toggle_napi(vsi, q_vector, false);
+
netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx));
ice_fill_txq_meta(vsi, tx_ring, &txq_meta);
@@ -195,13 +199,10 @@ static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx)
if (err)
return err;
}
- ice_qvec_dis_irq(vsi, rx_ring, q_vector);
-
err = ice_vsi_ctrl_one_rx_ring(vsi, false, q_idx, true);
if (err)
return err;
- ice_qvec_toggle_napi(vsi, q_vector, false);
ice_qp_clean_rings(vsi, q_idx);
ice_qp_reset_stats(vsi, q_idx);
@@ -259,11 +260,11 @@ static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx)
if (err)
return err;
- clear_bit(ICE_CFG_BUSY, vsi->state);
ice_qvec_toggle_napi(vsi, q_vector, true);
ice_qvec_ena_irq(vsi, q_vector);
netif_tx_start_queue(netdev_get_tx_queue(vsi->netdev, q_idx));
+ clear_bit(ICE_CFG_BUSY, vsi->state);
return 0;
}
@@ -458,6 +459,11 @@ static u16 ice_fill_rx_descs(struct xsk_buff_pool *pool, struct xdp_buff **xdp,
rx_desc->read.pkt_addr = cpu_to_le64(dma);
rx_desc->wb.status_error0 = 0;
+ /* Put private info that changes on a per-packet basis
+ * into xdp_buff_xsk->cb.
+ */
+ ice_xdp_meta_set_desc(*xdp, rx_desc);
+
rx_desc++;
xdp++;
}
@@ -820,7 +826,8 @@ ice_add_xsk_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *first,
}
__skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++,
- virt_to_page(xdp->data_hard_start), 0, size);
+ virt_to_page(xdp->data_hard_start),
+ XDP_PACKET_HEADROOM, size);
sinfo->xdp_frags_size += size;
xsk_buff_add_frag(xdp);
@@ -863,8 +870,7 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
struct xdp_buff *xdp;
struct sk_buff *skb;
u16 stat_err_bits;
- u16 vlan_tag = 0;
- u16 rx_ptype;
+ u16 vlan_tci;
rx_desc = ICE_RX_DESC(rx_ring, ntc);
@@ -891,7 +897,6 @@ int ice_clean_rx_irq_zc(struct ice_rx_ring *rx_ring, int budget)
if (!first) {
first = xdp;
- xdp_buff_clear_frags_flag(first);
} else if (ice_add_xsk_frag(rx_ring, first, xdp, size)) {
break;
}
@@ -942,13 +947,10 @@ construct_skb:
total_rx_bytes += skb->len;
total_rx_packets++;
- vlan_tag = ice_get_vlan_tag_from_rx_desc(rx_desc);
-
- rx_ptype = le16_to_cpu(rx_desc->wb.ptype_flex_flags0) &
- ICE_RX_FLEX_DESC_PTYPE_M;
+ vlan_tci = ice_get_vlan_tci(rx_desc);
- ice_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype);
- ice_receive_skb(rx_ring, skb, vlan_tag);
+ ice_process_skb_fields(rx_ring, rx_desc, skb);
+ ice_receive_skb(rx_ring, skb, vlan_tci);
}
rx_ring->next_to_clean = ntc;
diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h
index bee73353b56a..0acc125decb3 100644
--- a/drivers/net/ethernet/intel/idpf/idpf.h
+++ b/drivers/net/ethernet/intel/idpf/idpf.h
@@ -15,7 +15,7 @@ struct idpf_vport_max_q;
#include <linux/pci.h>
#include <linux/bitfield.h>
#include <linux/sctp.h>
-#include <linux/ethtool.h>
+#include <linux/ethtool_netlink.h>
#include <net/gro.h>
#include <linux/dim.h>
@@ -418,11 +418,13 @@ struct idpf_vport {
/**
* enum idpf_user_flags
+ * @__IDPF_USER_FLAG_HSPLIT: header split state
* @__IDPF_PROMISC_UC: Unicast promiscuous mode
* @__IDPF_PROMISC_MC: Multicast promiscuous mode
* @__IDPF_USER_FLAGS_NBITS: Must be last
*/
enum idpf_user_flags {
+ __IDPF_USER_FLAG_HSPLIT = 0U,
__IDPF_PROMISC_UC = 32,
__IDPF_PROMISC_MC,
@@ -965,4 +967,7 @@ int idpf_send_map_unmap_queue_vector_msg(struct idpf_vport *vport, bool map);
int idpf_send_set_sriov_vfs_msg(struct idpf_adapter *adapter, u16 num_vfs);
int idpf_sriov_configure(struct pci_dev *pdev, int num_vfs);
+u8 idpf_vport_get_hsplit(const struct idpf_vport *vport);
+bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val);
+
#endif /* !_IDPF_H_ */
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index 52ea38669f85..986d429d1175 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -75,14 +75,12 @@ static u32 idpf_get_rxfh_indir_size(struct net_device *netdev)
/**
* idpf_get_rxfh - get the rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function in use
+ * @rxfh: pointer to param struct (indir, key, hfunc)
*
* Reads the indirection table directly from the hardware. Always returns 0.
*/
-static int idpf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int idpf_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_rss_data *rss_data;
@@ -103,15 +101,14 @@ static int idpf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
if (np->state != __IDPF_VPORT_UP)
goto unlock_mutex;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (key)
- memcpy(key, rss_data->rss_key, rss_data->rss_key_size);
+ if (rxfh->key)
+ memcpy(rxfh->key, rss_data->rss_key, rss_data->rss_key_size);
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < rss_data->rss_lut_size; i++)
- indir[i] = rss_data->rss_lut[i];
+ rxfh->indir[i] = rss_data->rss_lut[i];
}
unlock_mutex:
@@ -123,15 +120,15 @@ unlock_mutex:
/**
* idpf_set_rxfh - set the rx flow hash indirection table
* @netdev: network interface device structure
- * @indir: indirection table
- * @key: hash key
- * @hfunc: hash function to use
+ * @rxfh: pointer to param struct (indir, key, hfunc)
+ * @extack: extended ACK from the Netlink message
*
* Returns -EINVAL if the table specifies an invalid queue id, otherwise
* returns 0 after programming the table.
*/
-static int idpf_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int idpf_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct idpf_netdev_priv *np = netdev_priv(netdev);
struct idpf_rss_data *rss_data;
@@ -154,17 +151,18 @@ static int idpf_set_rxfh(struct net_device *netdev, const u32 *indir,
if (np->state != __IDPF_VPORT_UP)
goto unlock_mutex;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) {
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP) {
err = -EOPNOTSUPP;
goto unlock_mutex;
}
- if (key)
- memcpy(rss_data->rss_key, key, rss_data->rss_key_size);
+ if (rxfh->key)
+ memcpy(rss_data->rss_key, rxfh->key, rss_data->rss_key_size);
- if (indir) {
+ if (rxfh->indir) {
for (lut = 0; lut < rss_data->rss_lut_size; lut++)
- rss_data->rss_lut[lut] = indir[lut];
+ rss_data->rss_lut[lut] = rxfh->indir[lut];
}
err = idpf_config_rss(vport);
@@ -320,6 +318,8 @@ static void idpf_get_ringparam(struct net_device *netdev,
ring->rx_pending = vport->rxq_desc_count;
ring->tx_pending = vport->txq_desc_count;
+ kring->tcp_data_split = idpf_vport_get_hsplit(vport);
+
idpf_vport_ctrl_unlock(netdev);
}
@@ -379,6 +379,14 @@ static int idpf_set_ringparam(struct net_device *netdev,
new_rx_count == vport->rxq_desc_count)
goto unlock_mutex;
+ if (!idpf_vport_set_hsplit(vport, kring->tcp_data_split)) {
+ NL_SET_ERR_MSG_MOD(ext_ack,
+ "setting TCP data split is not supported");
+ err = -EOPNOTSUPP;
+
+ goto unlock_mutex;
+ }
+
config_data = &vport->adapter->vport_config[idx]->user_config;
config_data->num_req_txq_desc = new_tx_count;
config_data->num_req_rxq_desc = new_rx_count;
@@ -532,7 +540,7 @@ static void idpf_add_stat_strings(u8 **p, const struct idpf_stats *stats,
unsigned int i;
for (i = 0; i < size; i++)
- ethtool_sprintf(p, "%s", stats[i].stat_string);
+ ethtool_puts(p, stats[i].stat_string);
}
/**
@@ -1334,6 +1342,7 @@ static int idpf_get_link_ksettings(struct net_device *netdev,
static const struct ethtool_ops idpf_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USE_ADAPTIVE,
+ .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT,
.get_msglevel = idpf_get_msglevel,
.set_msglevel = idpf_set_msglevel,
.get_link = ethtool_op_get_link,
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index 19809b0ddcd9..58179bd733ff 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -783,6 +783,8 @@ static int idpf_cfg_netdev(struct idpf_vport *vport)
/* setup watchdog timeout value to be 5 second */
netdev->watchdog_timeo = 5 * HZ;
+ netdev->dev_port = idx;
+
/* configure default MTU size */
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = vport->max_mtu;
@@ -1058,6 +1060,71 @@ static void idpf_vport_dealloc(struct idpf_vport *vport)
}
/**
+ * idpf_is_hsplit_supported - check whether the header split is supported
+ * @vport: virtual port to check the capability for
+ *
+ * Return: true if it's supported by the HW/FW, false if not.
+ */
+static bool idpf_is_hsplit_supported(const struct idpf_vport *vport)
+{
+ return idpf_is_queue_model_split(vport->rxq_model) &&
+ idpf_is_cap_ena_all(vport->adapter, IDPF_HSPLIT_CAPS,
+ IDPF_CAP_HSPLIT);
+}
+
+/**
+ * idpf_vport_get_hsplit - get the current header split feature state
+ * @vport: virtual port to query the state for
+ *
+ * Return: ``ETHTOOL_TCP_DATA_SPLIT_UNKNOWN`` if not supported,
+ * ``ETHTOOL_TCP_DATA_SPLIT_DISABLED`` if disabled,
+ * ``ETHTOOL_TCP_DATA_SPLIT_ENABLED`` if active.
+ */
+u8 idpf_vport_get_hsplit(const struct idpf_vport *vport)
+{
+ const struct idpf_vport_user_config_data *config;
+
+ if (!idpf_is_hsplit_supported(vport))
+ return ETHTOOL_TCP_DATA_SPLIT_UNKNOWN;
+
+ config = &vport->adapter->vport_config[vport->idx]->user_config;
+
+ return test_bit(__IDPF_USER_FLAG_HSPLIT, config->user_flags) ?
+ ETHTOOL_TCP_DATA_SPLIT_ENABLED :
+ ETHTOOL_TCP_DATA_SPLIT_DISABLED;
+}
+
+/**
+ * idpf_vport_set_hsplit - enable or disable header split on a given vport
+ * @vport: virtual port to configure
+ * @val: Ethtool flag controlling the header split state
+ *
+ * Return: true on success, false if not supported by the HW.
+ */
+bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val)
+{
+ struct idpf_vport_user_config_data *config;
+
+ if (!idpf_is_hsplit_supported(vport))
+ return val == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN;
+
+ config = &vport->adapter->vport_config[vport->idx]->user_config;
+
+ switch (val) {
+ case ETHTOOL_TCP_DATA_SPLIT_UNKNOWN:
+ /* Default is to enable */
+ case ETHTOOL_TCP_DATA_SPLIT_ENABLED:
+ __set_bit(__IDPF_USER_FLAG_HSPLIT, config->user_flags);
+ return true;
+ case ETHTOOL_TCP_DATA_SPLIT_DISABLED:
+ __clear_bit(__IDPF_USER_FLAG_HSPLIT, config->user_flags);
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
* idpf_vport_alloc - Allocates the next available struct vport in the adapter
* @adapter: board private structure
* @max_q: vport max queue info
diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
index 20c4b3a64710..27b93592c4ba 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -328,10 +328,9 @@ static void idpf_tx_singleq_build_ctx_desc(struct idpf_queue *txq,
if (offload->tso_segs) {
qw1 |= IDPF_TX_CTX_DESC_TSO << IDPF_TXD_CTX_QW1_CMD_S;
- qw1 |= ((u64)offload->tso_len << IDPF_TXD_CTX_QW1_TSO_LEN_S) &
- IDPF_TXD_CTX_QW1_TSO_LEN_M;
- qw1 |= ((u64)offload->mss << IDPF_TXD_CTX_QW1_MSS_S) &
- IDPF_TXD_CTX_QW1_MSS_M;
+ qw1 |= FIELD_PREP(IDPF_TXD_CTX_QW1_TSO_LEN_M,
+ offload->tso_len);
+ qw1 |= FIELD_PREP(IDPF_TXD_CTX_QW1_MSS_M, offload->mss);
u64_stats_update_begin(&txq->stats_sync);
u64_stats_inc(&txq->q_stats.tx.lso_pkts);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 9e942e5baf39..2f8ad79ae3f0 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -505,9 +505,9 @@ static void idpf_rx_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id)
/* store the buffer ID and the SW maintained GEN bit to the refillq */
refillq->ring[nta] =
- ((buf_id << IDPF_RX_BI_BUFID_S) & IDPF_RX_BI_BUFID_M) |
- (!!(test_bit(__IDPF_Q_GEN_CHK, refillq->flags)) <<
- IDPF_RX_BI_GEN_S);
+ FIELD_PREP(IDPF_RX_BI_BUFID_M, buf_id) |
+ FIELD_PREP(IDPF_RX_BI_GEN_M,
+ test_bit(__IDPF_Q_GEN_CHK, refillq->flags));
if (unlikely(++nta == refillq->desc_count)) {
nta = 0;
@@ -1240,12 +1240,15 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport, u16 num_rxq)
struct idpf_adapter *adapter = vport->adapter;
struct idpf_queue *q;
int i, k, err = 0;
+ bool hs;
vport->rxq_grps = kcalloc(vport->num_rxq_grp,
sizeof(struct idpf_rxq_group), GFP_KERNEL);
if (!vport->rxq_grps)
return -ENOMEM;
+ hs = idpf_vport_get_hsplit(vport) == ETHTOOL_TCP_DATA_SPLIT_ENABLED;
+
for (i = 0; i < vport->num_rxq_grp; i++) {
struct idpf_rxq_group *rx_qgrp = &vport->rxq_grps[i];
int j;
@@ -1298,9 +1301,8 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport, u16 num_rxq)
q->rx_buf_size = vport->bufq_size[j];
q->rx_buffer_low_watermark = IDPF_LOW_WATERMARK;
q->rx_buf_stride = IDPF_RX_BUF_STRIDE;
- if (idpf_is_cap_ena_all(adapter, IDPF_HSPLIT_CAPS,
- IDPF_CAP_HSPLIT) &&
- idpf_is_queue_model_split(vport->rxq_model)) {
+
+ if (hs) {
q->rx_hsplit_en = true;
q->rx_hbuf_size = IDPF_HDR_BUF_SIZE;
}
@@ -1344,9 +1346,7 @@ skip_splitq_rx_init:
rx_qgrp->splitq.rxq_sets[j]->refillq1 =
&rx_qgrp->splitq.bufq_sets[1].refillqs[j];
- if (idpf_is_cap_ena_all(adapter, IDPF_HSPLIT_CAPS,
- IDPF_CAP_HSPLIT) &&
- idpf_is_queue_model_split(vport->rxq_model)) {
+ if (hs) {
q->rx_hsplit_en = true;
q->rx_hbuf_size = IDPF_HDR_BUF_SIZE;
}
@@ -1825,14 +1825,14 @@ static bool idpf_tx_clean_complq(struct idpf_queue *complq, int budget,
u16 gen;
/* if the descriptor isn't done, no work yet to do */
- gen = (le16_to_cpu(tx_desc->qid_comptype_gen) &
- IDPF_TXD_COMPLQ_GEN_M) >> IDPF_TXD_COMPLQ_GEN_S;
+ gen = le16_get_bits(tx_desc->qid_comptype_gen,
+ IDPF_TXD_COMPLQ_GEN_M);
if (test_bit(__IDPF_Q_GEN_CHK, complq->flags) != gen)
break;
/* Find necessary info of TX queue to clean buffers */
- rel_tx_qid = (le16_to_cpu(tx_desc->qid_comptype_gen) &
- IDPF_TXD_COMPLQ_QID_M) >> IDPF_TXD_COMPLQ_QID_S;
+ rel_tx_qid = le16_get_bits(tx_desc->qid_comptype_gen,
+ IDPF_TXD_COMPLQ_QID_M);
if (rel_tx_qid >= complq->txq_grp->num_txq ||
!complq->txq_grp->txqs[rel_tx_qid]) {
dev_err(&complq->vport->adapter->pdev->dev,
@@ -1842,9 +1842,8 @@ static bool idpf_tx_clean_complq(struct idpf_queue *complq, int budget,
tx_q = complq->txq_grp->txqs[rel_tx_qid];
/* Determine completion type */
- ctype = (le16_to_cpu(tx_desc->qid_comptype_gen) &
- IDPF_TXD_COMPLQ_COMPL_TYPE_M) >>
- IDPF_TXD_COMPLQ_COMPL_TYPE_S;
+ ctype = le16_get_bits(tx_desc->qid_comptype_gen,
+ IDPF_TXD_COMPLQ_COMPL_TYPE_M);
switch (ctype) {
case IDPF_TXD_COMPLT_RE:
hw_head = le16_to_cpu(tx_desc->q_head_compl_tag.q_head);
@@ -1945,11 +1944,10 @@ void idpf_tx_splitq_build_ctb(union idpf_tx_flex_desc *desc,
u16 td_cmd, u16 size)
{
desc->q.qw1.cmd_dtype =
- cpu_to_le16(params->dtype & IDPF_FLEX_TXD_QW1_DTYPE_M);
+ le16_encode_bits(params->dtype, IDPF_FLEX_TXD_QW1_DTYPE_M);
desc->q.qw1.cmd_dtype |=
- cpu_to_le16((td_cmd << IDPF_FLEX_TXD_QW1_CMD_S) &
- IDPF_FLEX_TXD_QW1_CMD_M);
- desc->q.qw1.buf_size = cpu_to_le16((u16)size);
+ le16_encode_bits(td_cmd, IDPF_FLEX_TXD_QW1_CMD_M);
+ desc->q.qw1.buf_size = cpu_to_le16(size);
desc->q.qw1.l2tags.l2tag1 = cpu_to_le16(params->td_tag);
}
@@ -2843,8 +2841,9 @@ static void idpf_rx_splitq_extract_csum_bits(struct virtchnl2_rx_flex_desc_adv_n
qword1);
csum->ipv6exadd = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_IPV6EXADD_M,
qword0);
- csum->raw_csum_inv = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_RAW_CSUM_INV_M,
- le16_to_cpu(rx_desc->ptype_err_fflags0));
+ csum->raw_csum_inv =
+ le16_get_bits(rx_desc->ptype_err_fflags0,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_RAW_CSUM_INV_M);
csum->raw_csum = le16_to_cpu(rx_desc->misc.raw_cs);
}
@@ -2938,8 +2937,8 @@ static int idpf_rx_process_skb_fields(struct idpf_queue *rxq,
struct idpf_rx_ptype_decoded decoded;
u16 rx_ptype;
- rx_ptype = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_PTYPE_M,
- le16_to_cpu(rx_desc->ptype_err_fflags0));
+ rx_ptype = le16_get_bits(rx_desc->ptype_err_fflags0,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_PTYPE_M);
decoded = rxq->vport->rx_ptype_lkup[rx_ptype];
/* If we don't know the ptype we can't do anything else with it. Just
@@ -2953,8 +2952,8 @@ static int idpf_rx_process_skb_fields(struct idpf_queue *rxq,
skb->protocol = eth_type_trans(skb, rxq->vport->netdev);
- if (FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_RSC_M,
- le16_to_cpu(rx_desc->hdrlen_flags)))
+ if (le16_get_bits(rx_desc->hdrlen_flags,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_RSC_M))
return idpf_rx_rsc(rxq, skb, rx_desc, &decoded);
idpf_rx_splitq_extract_csum_bits(rx_desc, &csum_bits);
@@ -3148,8 +3147,8 @@ static int idpf_rx_splitq_clean(struct idpf_queue *rxq, int budget)
dma_rmb();
/* if the descriptor isn't done, no work yet to do */
- gen_id = le16_to_cpu(rx_desc->pktlen_gen_bufq_id);
- gen_id = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_M, gen_id);
+ gen_id = le16_get_bits(rx_desc->pktlen_gen_bufq_id,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_GEN_M);
if (test_bit(__IDPF_Q_GEN_CHK, rxq->flags) != gen_id)
break;
@@ -3164,9 +3163,8 @@ static int idpf_rx_splitq_clean(struct idpf_queue *rxq, int budget)
continue;
}
- pkt_len = le16_to_cpu(rx_desc->pktlen_gen_bufq_id);
- pkt_len = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_LEN_PBUF_M,
- pkt_len);
+ pkt_len = le16_get_bits(rx_desc->pktlen_gen_bufq_id,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_LEN_PBUF_M);
hbo = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_STATUS0_HBO_M,
rx_desc->status_err0_qw1);
@@ -3183,14 +3181,12 @@ static int idpf_rx_splitq_clean(struct idpf_queue *rxq, int budget)
goto bypass_hsplit;
}
- hdr_len = le16_to_cpu(rx_desc->hdrlen_flags);
- hdr_len = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_LEN_HDR_M,
- hdr_len);
+ hdr_len = le16_get_bits(rx_desc->hdrlen_flags,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_LEN_HDR_M);
bypass_hsplit:
- bufq_id = le16_to_cpu(rx_desc->pktlen_gen_bufq_id);
- bufq_id = FIELD_GET(VIRTCHNL2_RX_FLEX_DESC_ADV_BUFQ_ID_M,
- bufq_id);
+ bufq_id = le16_get_bits(rx_desc->pktlen_gen_bufq_id,
+ VIRTCHNL2_RX_FLEX_DESC_ADV_BUFQ_ID_M);
rxq_set = container_of(rxq, struct idpf_rxq_set, rxq);
if (!bufq_id)
diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
index 2c1b051fdc0d..390977a76de2 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c
@@ -2087,8 +2087,10 @@ int idpf_send_disable_queues_msg(struct idpf_vport *vport)
set_bit(__IDPF_Q_POLL_MODE, vport->txqs[i]->flags);
/* schedule the napi to receive all the marker packets */
+ local_bh_disable();
for (i = 0; i < vport->num_q_vectors; i++)
napi_schedule(&vport->q_vectors[i].napi);
+ local_bh_enable();
return idpf_wait_for_marker_event(vport);
}
@@ -3285,6 +3287,8 @@ void idpf_vport_init(struct idpf_vport *vport, struct idpf_vport_max_q *max_q)
memcpy(vport->rx_itr_profile, rx_itr, IDPF_DIM_PROFILE_SLOTS);
memcpy(vport->tx_itr_profile, tx_itr, IDPF_DIM_PROFILE_SLOTS);
+ idpf_vport_set_hsplit(vport, ETHTOOL_TCP_DATA_SPLIT_ENABLED);
+
idpf_vport_init_num_qs(vport, vport_msg);
idpf_vport_calc_num_q_desc(vport);
idpf_vport_calc_num_q_groups(vport);
diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/drivers/net/ethernet/intel/idpf/virtchnl2.h
index 8dc837889723..4a3c4454d25a 100644
--- a/drivers/net/ethernet/intel/idpf/virtchnl2.h
+++ b/drivers/net/ethernet/intel/idpf/virtchnl2.h
@@ -978,7 +978,7 @@ struct virtchnl2_ptype {
u8 proto_id_count;
__le16 pad;
__le16 proto_id[];
-};
+} __packed __aligned(2);
VIRTCHNL2_CHECK_STRUCT_LEN(6, virtchnl2_ptype);
/**
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index 8d6e44ee1895..64dfc362d1dc 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -222,8 +222,7 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
}
/* set lan id */
- hw->bus.func = (rd32(E1000_STATUS) & E1000_STATUS_FUNC_MASK) >>
- E1000_STATUS_FUNC_SHIFT;
+ hw->bus.func = FIELD_GET(E1000_STATUS_FUNC_MASK, rd32(E1000_STATUS));
/* Set phy->phy_addr and phy->id. */
ret_val = igb_get_phy_id_82575(hw);
@@ -262,8 +261,8 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
if (ret_val)
goto out;
- data = (data & E1000_M88E1112_MAC_CTRL_1_MODE_MASK) >>
- E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT;
+ data = FIELD_GET(E1000_M88E1112_MAC_CTRL_1_MODE_MASK,
+ data);
if (data == E1000_M88E1112_AUTO_COPPER_SGMII ||
data == E1000_M88E1112_AUTO_COPPER_BASEX)
hw->mac.ops.check_for_link =
@@ -330,8 +329,7 @@ static s32 igb_init_nvm_params_82575(struct e1000_hw *hw)
u32 eecd = rd32(E1000_EECD);
u16 size;
- size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
- E1000_EECD_SIZE_EX_SHIFT);
+ size = FIELD_GET(E1000_EECD_SIZE_EX_MASK, eecd);
/* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
@@ -2798,7 +2796,7 @@ static s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
return 0;
hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
- if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+ if (FIELD_GET(NVM_ETS_TYPE_MASK, ets_cfg)
!= NVM_ETS_TYPE_EMC)
return E1000_NOT_IMPLEMENTED;
@@ -2808,10 +2806,8 @@ static s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
for (i = 1; i < num_sensors; i++) {
hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
- sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
- NVM_ETS_DATA_INDEX_SHIFT);
- sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
- NVM_ETS_DATA_LOC_SHIFT);
+ sensor_index = FIELD_GET(NVM_ETS_DATA_INDEX_MASK, ets_sensor);
+ sensor_location = FIELD_GET(NVM_ETS_DATA_LOC_MASK, ets_sensor);
if (sensor_location != 0)
hw->phy.ops.read_i2c_byte(hw,
@@ -2859,20 +2855,17 @@ static s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
return 0;
hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
- if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
+ if (FIELD_GET(NVM_ETS_TYPE_MASK, ets_cfg)
!= NVM_ETS_TYPE_EMC)
return E1000_NOT_IMPLEMENTED;
- low_thresh_delta = ((ets_cfg & NVM_ETS_LTHRES_DELTA_MASK) >>
- NVM_ETS_LTHRES_DELTA_SHIFT);
+ low_thresh_delta = FIELD_GET(NVM_ETS_LTHRES_DELTA_MASK, ets_cfg);
num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
for (i = 1; i <= num_sensors; i++) {
hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
- sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
- NVM_ETS_DATA_INDEX_SHIFT);
- sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
- NVM_ETS_DATA_LOC_SHIFT);
+ sensor_index = FIELD_GET(NVM_ETS_DATA_INDEX_MASK, ets_sensor);
+ sensor_location = FIELD_GET(NVM_ETS_DATA_LOC_MASK, ets_sensor);
therm_limit = ets_sensor & NVM_ETS_DATA_HTHRESH_MASK;
hw->phy.ops.write_i2c_byte(hw,
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c
index b9b9d35494d2..503b239868e8 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.c
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.c
@@ -5,9 +5,9 @@
* e1000_i211
*/
-#include <linux/types.h>
+#include <linux/bitfield.h>
#include <linux/if_ether.h>
-
+#include <linux/types.h>
#include "e1000_hw.h"
#include "e1000_i210.h"
@@ -473,7 +473,7 @@ s32 igb_read_invm_version(struct e1000_hw *hw,
/* Check if we have second version location used */
else if ((i == 1) &&
((*record & E1000_INVM_VER_FIELD_TWO) == 0)) {
- version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
+ version = FIELD_GET(E1000_INVM_VER_FIELD_ONE, *record);
status = 0;
break;
}
@@ -483,8 +483,8 @@ s32 igb_read_invm_version(struct e1000_hw *hw,
else if ((((*record & E1000_INVM_VER_FIELD_ONE) == 0) &&
((*record & 0x3) == 0)) || (((*record & 0x3) != 0) &&
(i != 1))) {
- version = (*next_record & E1000_INVM_VER_FIELD_TWO)
- >> 13;
+ version = FIELD_GET(E1000_INVM_VER_FIELD_TWO,
+ *next_record);
status = 0;
break;
}
@@ -493,15 +493,15 @@ s32 igb_read_invm_version(struct e1000_hw *hw,
*/
else if (((*record & E1000_INVM_VER_FIELD_TWO) == 0) &&
((*record & 0x3) == 0)) {
- version = (*record & E1000_INVM_VER_FIELD_ONE) >> 3;
+ version = FIELD_GET(E1000_INVM_VER_FIELD_ONE, *record);
status = 0;
break;
}
}
if (!status) {
- invm_ver->invm_major = (version & E1000_INVM_MAJOR_MASK)
- >> E1000_INVM_MAJOR_SHIFT;
+ invm_ver->invm_major = FIELD_GET(E1000_INVM_MAJOR_MASK,
+ version);
invm_ver->invm_minor = version & E1000_INVM_MINOR_MASK;
}
/* Read Image Type */
@@ -520,7 +520,8 @@ s32 igb_read_invm_version(struct e1000_hw *hw,
((*record & E1000_INVM_IMGTYPE_FIELD) == 0)) ||
((((*record & 0x3) != 0) && (i != 1)))) {
invm_ver->invm_img_type =
- (*next_record & E1000_INVM_IMGTYPE_FIELD) >> 23;
+ FIELD_GET(E1000_INVM_IMGTYPE_FIELD,
+ *next_record);
status = 0;
break;
}
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index caf91c6f52b4..fa3dfafd2bb1 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2007 - 2018 Intel Corporation. */
+#include <linux/bitfield.h>
#include <linux/if_ether.h>
#include <linux/delay.h>
#include <linux/pci.h>
@@ -50,13 +51,12 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw)
break;
}
- bus->width = (enum e1000_bus_width)((pcie_link_status &
- PCI_EXP_LNKSTA_NLW) >>
- PCI_EXP_LNKSTA_NLW_SHIFT);
+ bus->width = (enum e1000_bus_width)FIELD_GET(PCI_EXP_LNKSTA_NLW,
+ pcie_link_status);
}
reg = rd32(E1000_STATUS);
- bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
+ bus->func = FIELD_GET(E1000_STATUS_FUNC_MASK, reg);
return 0;
}
diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c
index fa136e6e9328..2dcd64d6dec3 100644
--- a/drivers/net/ethernet/intel/igb/e1000_nvm.c
+++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2007 - 2018 Intel Corporation. */
-#include <linux/if_ether.h>
+#include <linux/bitfield.h>
#include <linux/delay.h>
-
+#include <linux/if_ether.h>
#include "e1000_mac.h"
#include "e1000_nvm.h"
@@ -708,10 +708,10 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
*/
if ((etrack_test & NVM_MAJOR_MASK) != NVM_ETRACK_VALID) {
hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
- fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
- >> NVM_MAJOR_SHIFT;
- fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK)
- >> NVM_MINOR_SHIFT;
+ fw_vers->eep_major = FIELD_GET(NVM_MAJOR_MASK,
+ fw_version);
+ fw_vers->eep_minor = FIELD_GET(NVM_MINOR_MASK,
+ fw_version);
fw_vers->eep_build = (fw_version & NVM_IMAGE_ID_MASK);
goto etrack_id;
}
@@ -753,15 +753,13 @@ void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers)
return;
}
hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version);
- fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK)
- >> NVM_MAJOR_SHIFT;
+ fw_vers->eep_major = FIELD_GET(NVM_MAJOR_MASK, fw_version);
/* check for old style version format in newer images*/
if ((fw_version & NVM_NEW_DEC_MASK) == 0x0) {
eeprom_verl = (fw_version & NVM_COMB_VER_MASK);
} else {
- eeprom_verl = (fw_version & NVM_MINOR_MASK)
- >> NVM_MINOR_SHIFT;
+ eeprom_verl = FIELD_GET(NVM_MINOR_MASK, fw_version);
}
/* Convert minor value to hex before assigning to output struct
* Val to be converted will not be higher than 99, per tool output
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index a018000f7db9..cd65008c7ef5 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2007 - 2018 Intel Corporation. */
-#include <linux/if_ether.h>
+#include <linux/bitfield.h>
#include <linux/delay.h>
-
+#include <linux/if_ether.h>
#include "e1000_mac.h"
#include "e1000_phy.h"
@@ -255,7 +255,7 @@ s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data)
}
/* Need to byte-swap the 16-bit value. */
- *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00);
+ *data = ((i2ccmd >> 8) & 0x00FF) | FIELD_PREP(0xFF00, i2ccmd);
return 0;
}
@@ -282,7 +282,7 @@ s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
}
/* Swap the data bytes for the I2C interface */
- phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00);
+ phy_data_swapped = ((data >> 8) & 0x00FF) | FIELD_PREP(0xFF00, data);
/* Set up Op-code, Phy Address, and register address in the I2CCMD
* register. The MAC will take care of interfacing with the
@@ -1682,8 +1682,7 @@ s32 igb_get_cable_length_m88(struct e1000_hw *hw)
if (ret_val)
goto out;
- index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ index = FIELD_GET(M88E1000_PSSR_CABLE_LENGTH, phy_data);
if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) {
ret_val = -E1000_ERR_PHY;
goto out;
@@ -1796,8 +1795,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw)
if (ret_val)
goto out;
- index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
- M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ index = FIELD_GET(M88E1000_PSSR_CABLE_LENGTH, phy_data);
if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) {
ret_val = -E1000_ERR_PHY;
goto out;
@@ -2578,8 +2576,7 @@ s32 igb_get_cable_length_82580(struct e1000_hw *hw)
if (ret_val)
goto out;
- length = (phy_data & I82580_DSTATUS_CABLE_LENGTH) >>
- I82580_DSTATUS_CABLE_LENGTH_SHIFT;
+ length = FIELD_GET(I82580_DSTATUS_CABLE_LENGTH, phy_data);
if (length == E1000_CABLE_LENGTH_UNDEFINED)
ret_val = -E1000_ERR_PHY;
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index a2b759531cb7..3c2dc7bdebb5 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -637,7 +637,7 @@ struct igb_adapter {
struct timespec64 period;
} perout[IGB_N_PEROUT];
- char fw_version[32];
+ char fw_version[48];
#ifdef CONFIG_IGB_HWMON
struct hwmon_buff *igb_hwmon_buff;
bool ets;
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 16d2a55d5e17..b66199c9bb3a 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -2356,11 +2356,9 @@ static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
break;
case ETH_SS_STATS:
for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- igb_gstrings_stats[i].stat_string);
+ ethtool_puts(&p, igb_gstrings_stats[i].stat_string);
for (i = 0; i < IGB_NETDEV_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- igb_gstrings_net_stats[i].stat_string);
+ ethtool_puts(&p, igb_gstrings_net_stats[i].stat_string);
for (i = 0; i < adapter->num_tx_queues; i++) {
ethtool_sprintf(&p, "tx_queue_%u_packets", i);
ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
@@ -2434,7 +2432,7 @@ static int igb_get_ts_info(struct net_device *dev,
}
}
-#define ETHER_TYPE_FULL_MASK ((__force __be16)~0)
+#define ETHER_TYPE_FULL_MASK cpu_to_be16(FIELD_MAX(U16_MAX))
static int igb_get_ethtool_nfc_entry(struct igb_adapter *adapter,
struct ethtool_rxnfc *cmd)
{
@@ -2713,8 +2711,7 @@ static int igb_rxnfc_write_etype_filter(struct igb_adapter *adapter,
etqf |= (etype & E1000_ETQF_ETYPE_MASK);
etqf &= ~E1000_ETQF_QUEUE_MASK;
- etqf |= ((input->action << E1000_ETQF_QUEUE_SHIFT)
- & E1000_ETQF_QUEUE_MASK);
+ etqf |= FIELD_PREP(E1000_ETQF_QUEUE_MASK, input->action);
etqf |= E1000_ETQF_QUEUE_ENABLE;
wr32(E1000_ETQF(i), etqf);
@@ -2733,8 +2730,8 @@ static int igb_rxnfc_write_vlan_prio_filter(struct igb_adapter *adapter,
u32 vlapqf;
vlapqf = rd32(E1000_VLAPQF);
- vlan_priority = (ntohs(input->filter.vlan_tci) & VLAN_PRIO_MASK)
- >> VLAN_PRIO_SHIFT;
+ vlan_priority = FIELD_GET(VLAN_PRIO_MASK,
+ ntohs(input->filter.vlan_tci));
queue_index = (vlapqf >> (vlan_priority * 4)) & E1000_VLAPQF_QUEUE_MASK;
/* check whether this vlan prio is already set */
@@ -2817,7 +2814,7 @@ static void igb_clear_vlan_prio_filter(struct igb_adapter *adapter,
u8 vlan_priority;
u32 vlapqf;
- vlan_priority = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
+ vlan_priority = FIELD_GET(VLAN_PRIO_MASK, vlan_tci);
vlapqf = rd32(E1000_VLAPQF);
vlapqf &= ~E1000_VLAPQF_P_VALID(vlan_priority);
@@ -3282,18 +3279,17 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev)
return IGB_RETA_SIZE;
}
-static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int igb_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct igb_adapter *adapter = netdev_priv(netdev);
int i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (!rxfh->indir)
return 0;
for (i = 0; i < IGB_RETA_SIZE; i++)
- indir[i] = adapter->rss_indir_tbl[i];
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
return 0;
}
@@ -3333,8 +3329,9 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
}
}
-static int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int igb_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -3342,10 +3339,11 @@ static int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
u32 num_queues;
/* We do not allow change in unsupported parameters */
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
num_queues = adapter->rss_queues;
@@ -3362,12 +3360,12 @@ static int igb_set_rxfh(struct net_device *netdev, const u32 *indir,
/* Verify user input. */
for (i = 0; i < IGB_RETA_SIZE; i++)
- if (indir[i] >= num_queues)
+ if (rxfh->indir[i] >= num_queues)
return -EINVAL;
for (i = 0; i < IGB_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = indir[i];
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
igb_write_rss_indir_tbl(adapter);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index b2295caa2f0a..cebb44f51d5f 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -3069,7 +3069,6 @@ void igb_set_fw_version(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct e1000_fw_version fw;
- char *lbuf;
igb_get_fw_version(hw, &fw);
@@ -3077,34 +3076,36 @@ void igb_set_fw_version(struct igb_adapter *adapter)
case e1000_i210:
case e1000_i211:
if (!(igb_get_flash_presence_i210(hw))) {
- lbuf = kasprintf(GFP_KERNEL, "%2d.%2d-%d",
- fw.invm_major, fw.invm_minor,
- fw.invm_img_type);
+ snprintf(adapter->fw_version,
+ sizeof(adapter->fw_version),
+ "%2d.%2d-%d",
+ fw.invm_major, fw.invm_minor,
+ fw.invm_img_type);
break;
}
fallthrough;
default:
/* if option rom is valid, display its version too */
if (fw.or_valid) {
- lbuf = kasprintf(GFP_KERNEL, "%d.%d, 0x%08x, %d.%d.%d",
- fw.eep_major, fw.eep_minor,
- fw.etrack_id, fw.or_major, fw.or_build,
- fw.or_patch);
+ snprintf(adapter->fw_version,
+ sizeof(adapter->fw_version),
+ "%d.%d, 0x%08x, %d.%d.%d",
+ fw.eep_major, fw.eep_minor, fw.etrack_id,
+ fw.or_major, fw.or_build, fw.or_patch);
/* no option rom */
} else if (fw.etrack_id != 0X0000) {
- lbuf = kasprintf(GFP_KERNEL, "%d.%d, 0x%08x",
- fw.eep_major, fw.eep_minor,
- fw.etrack_id);
+ snprintf(adapter->fw_version,
+ sizeof(adapter->fw_version),
+ "%d.%d, 0x%08x",
+ fw.eep_major, fw.eep_minor, fw.etrack_id);
} else {
- lbuf = kasprintf(GFP_KERNEL, "%d.%d.%d", fw.eep_major,
- fw.eep_minor, fw.eep_build);
+ snprintf(adapter->fw_version,
+ sizeof(adapter->fw_version),
+ "%d.%d.%d",
+ fw.eep_major, fw.eep_minor, fw.eep_build);
}
break;
}
-
- /* the truncate happens here if it doesn't fit */
- strscpy(adapter->fw_version, lbuf, sizeof(adapter->fw_version));
- kfree(lbuf);
}
/**
@@ -7295,7 +7296,7 @@ static int igb_set_vf_promisc(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
static int igb_set_vf_multicasts(struct igb_adapter *adapter,
u32 *msgbuf, u32 vf)
{
- int n = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+ int n = FIELD_GET(E1000_VT_MSGINFO_MASK, msgbuf[0]);
u16 *hash_list = (u16 *)&msgbuf[1];
struct vf_data_storage *vf_data = &adapter->vf_data[vf];
int i;
@@ -7555,7 +7556,7 @@ static int igb_ndo_set_vf_vlan(struct net_device *netdev, int vf,
static int igb_set_vf_vlan_msg(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
{
- int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+ int add = FIELD_GET(E1000_VT_MSGINFO_MASK, msgbuf[0]);
int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
int ret;
@@ -9810,8 +9811,7 @@ static void igb_set_vf_rate_limit(struct e1000_hw *hw, int vf, int tx_rate,
tx_rate;
bcnrc_val = E1000_RTTBCNRC_RS_ENA;
- bcnrc_val |= ((rf_int << E1000_RTTBCNRC_RF_INT_SHIFT) &
- E1000_RTTBCNRC_RF_INT_MASK);
+ bcnrc_val |= FIELD_PREP(E1000_RTTBCNRC_RF_INT_MASK, rf_int);
bcnrc_val |= (rf_dec & E1000_RTTBCNRC_RF_DEC_MASK);
} else {
bcnrc_val = 0;
@@ -10000,8 +10000,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
hwm = 64 * (pba - 6);
reg = rd32(E1000_FCRTC);
reg &= ~E1000_FCRTC_RTH_COAL_MASK;
- reg |= ((hwm << E1000_FCRTC_RTH_COAL_SHIFT)
- & E1000_FCRTC_RTH_COAL_MASK);
+ reg |= FIELD_PREP(E1000_FCRTC_RTH_COAL_MASK, hwm);
wr32(E1000_FCRTC, reg);
/* Set the DMA Coalescing Rx threshold to PBA - 2 * max
@@ -10010,8 +10009,7 @@ static void igb_init_dmac(struct igb_adapter *adapter, u32 pba)
dmac_thr = pba - 10;
reg = rd32(E1000_DMACR);
reg &= ~E1000_DMACR_DMACTHR_MASK;
- reg |= ((dmac_thr << E1000_DMACR_DMACTHR_SHIFT)
- & E1000_DMACR_DMACTHR_MASK);
+ reg |= FIELD_PREP(E1000_DMACR_DMACTHR_MASK, dmac_thr);
/* transition to L0x or L1 if available..*/
reg |= (E1000_DMACR_DMAC_EN | E1000_DMACR_DMAC_LX_MASK);
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 319c544b9f04..f94570556120 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -957,7 +957,7 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
/* adjust timestamp for the TX latency based on link speed */
- if (adapter->hw.mac.type == e1000_i210) {
+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
switch (adapter->link_speed) {
case SPEED_10:
adjust = IGB_I210_TX_LATENCY_10;
@@ -1003,6 +1003,7 @@ int igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
ktime_t *timestamp)
{
struct igb_adapter *adapter = q_vector->adapter;
+ struct e1000_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps ts;
__le64 *regval = (__le64 *)va;
int adjust = 0;
@@ -1022,7 +1023,7 @@ int igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va,
igb_ptp_systim_to_hwtstamp(adapter, &ts, le64_to_cpu(regval[1]));
/* adjust timestamp for the RX latency based on link speed */
- if (adapter->hw.mac.type == e1000_i210) {
+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
switch (adapter->link_speed) {
case SPEED_10:
adjust = IGB_I210_RX_LATENCY_10;
diff --git a/drivers/net/ethernet/intel/igbvf/mbx.c b/drivers/net/ethernet/intel/igbvf/mbx.c
index a3cd7ac48d4b..d15282ee5ea8 100644
--- a/drivers/net/ethernet/intel/igbvf/mbx.c
+++ b/drivers/net/ethernet/intel/igbvf/mbx.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2009 - 2018 Intel Corporation. */
+#include <linux/bitfield.h>
#include "mbx.h"
/**
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index fd712585af27..a4d4f00e6a87 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -3,25 +3,25 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
+#include <linux/bitfield.h>
#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/tcp.h>
-#include <linux/ipv6.h>
-#include <linux/slab.h>
-#include <net/checksum.h>
-#include <net/ip6_checksum.h>
-#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/ipv6.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/pagemap.h>
+#include <linux/pci.h>
#include <linux/prefetch.h>
#include <linux/sctp.h>
-
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
#include "igbvf.h"
char igbvf_driver_name[] = "igbvf";
@@ -273,9 +273,8 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
* that case, it fills the header buffer and spills the rest
* into the page.
*/
- hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.hdr_info)
- & E1000_RXDADV_HDRBUFLEN_MASK) >>
- E1000_RXDADV_HDRBUFLEN_SHIFT;
+ hlen = le16_get_bits(rx_desc->wb.lower.lo_dword.hs_rss.hdr_info,
+ E1000_RXDADV_HDRBUFLEN_MASK);
if (hlen > adapter->rx_ps_hdr_size)
hlen = adapter->rx_ps_hdr_size;
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 85cc16396506..45430e246e9c 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -81,6 +81,21 @@ struct igc_tx_timestamp_request {
u32 flags; /* flags that should be added to the tx_buffer */
};
+struct igc_inline_rx_tstamps {
+ /* Timestamps are saved in little endian at the beginning of the packet
+ * buffer following the layout:
+ *
+ * DWORD: | 0 | 1 | 2 | 3 |
+ * Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH |
+ *
+ * SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds
+ * part of the timestamp.
+ *
+ */
+ __le32 timer1[2];
+ __le32 timer0[2];
+};
+
struct igc_ring_container {
struct igc_ring *ring; /* pointer to linked list of rings */
unsigned int total_bytes; /* total bytes processed this int */
@@ -261,6 +276,8 @@ struct igc_adapter {
unsigned int ptp_flags;
/* System time value lock */
spinlock_t tmreg_lock;
+ /* Free-running timer lock */
+ spinlock_t free_timer_lock;
struct cyclecounter cc;
struct timecounter tc;
struct timespec64 prev_ptp_time; /* Pre-reset PTP clock */
@@ -469,6 +486,8 @@ enum igc_tx_flags {
IGC_TX_FLAGS_TSTAMP_1 = 0x100,
IGC_TX_FLAGS_TSTAMP_2 = 0x200,
IGC_TX_FLAGS_TSTAMP_3 = 0x400,
+
+ IGC_TX_FLAGS_TSTAMP_TIMER_1 = 0x800,
};
enum igc_boards {
@@ -531,7 +550,7 @@ struct igc_rx_buffer {
struct igc_xdp_buff {
struct xdp_buff xdp;
union igc_adv_rx_desc *rx_desc;
- ktime_t rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */
+ struct igc_inline_rx_tstamps *rx_ts; /* data indication bit IGC_RXDADV_STAT_TSIP */
};
struct igc_q_vector {
diff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c
index a1d815af507d..9fae8bdec2a7 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.c
+++ b/drivers/net/ethernet/intel/igc/igc_base.c
@@ -68,8 +68,7 @@ static s32 igc_init_nvm_params_base(struct igc_hw *hw)
u32 eecd = rd32(IGC_EECD);
u16 size;
- size = (u16)((eecd & IGC_EECD_SIZE_EX_MASK) >>
- IGC_EECD_SIZE_EX_SHIFT);
+ size = FIELD_GET(IGC_EECD_SIZE_EX_MASK, eecd);
/* Added to a constant, "size" becomes the left-shift value
* for setting word_size.
@@ -162,8 +161,7 @@ static s32 igc_init_phy_params_base(struct igc_hw *hw)
phy->reset_delay_us = 100;
/* set lan id */
- hw->bus.func = (rd32(IGC_STATUS) & IGC_STATUS_FUNC_MASK) >>
- IGC_STATUS_FUNC_SHIFT;
+ hw->bus.func = FIELD_GET(IGC_STATUS_FUNC_MASK, rd32(IGC_STATUS));
/* Make sure the PHY is in a good state. Several people have reported
* firmware leaving the PHY's page select register set to something
diff --git a/drivers/net/ethernet/intel/igc/igc_base.h b/drivers/net/ethernet/intel/igc/igc_base.h
index f7d6491d4c60..bf8cdfbba9ff 100644
--- a/drivers/net/ethernet/intel/igc/igc_base.h
+++ b/drivers/net/ethernet/intel/igc/igc_base.h
@@ -37,6 +37,10 @@ struct igc_adv_tx_context_desc {
#define IGC_ADVTXD_TSTAMP_REG_1 0x00010000 /* Select register 1 for timestamp */
#define IGC_ADVTXD_TSTAMP_REG_2 0x00020000 /* Select register 2 for timestamp */
#define IGC_ADVTXD_TSTAMP_REG_3 0x00030000 /* Select register 3 for timestamp */
+#define IGC_ADVTXD_TSTAMP_TIMER_1 0x00010000 /* Select timer 1 for timestamp */
+#define IGC_ADVTXD_TSTAMP_TIMER_2 0x00020000 /* Select timer 2 for timestamp */
+#define IGC_ADVTXD_TSTAMP_TIMER_3 0x00030000 /* Select timer 3 for timestamp */
+
#define IGC_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */
#define IGC_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
#define IGC_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */
diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h
index b3037016f31d..5f92b3c7c3d4 100644
--- a/drivers/net/ethernet/intel/igc/igc_defines.h
+++ b/drivers/net/ethernet/intel/igc/igc_defines.h
@@ -317,6 +317,8 @@
#define IGC_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
#define IGC_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */
+#define IGC_TXD_PTP2_TIMER_1 0x00000020
+
/* IPSec Encrypt Enable */
#define IGC_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
#define IGC_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 859b2636f3d9..b95d2c86e803 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -773,11 +773,9 @@ static void igc_ethtool_get_strings(struct net_device *netdev, u32 stringset,
break;
case ETH_SS_STATS:
for (i = 0; i < IGC_GLOBAL_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- igc_gstrings_stats[i].stat_string);
+ ethtool_puts(&p, igc_gstrings_stats[i].stat_string);
for (i = 0; i < IGC_NETDEV_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- igc_gstrings_net_stats[i].stat_string);
+ ethtool_puts(&p, igc_gstrings_net_stats[i].stat_string);
for (i = 0; i < adapter->num_tx_queues; i++) {
ethtool_sprintf(&p, "tx_queue_%u_packets", i);
ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
@@ -1464,45 +1462,46 @@ static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
return IGC_RETA_SIZE;
}
-static int igc_ethtool_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int igc_ethtool_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct igc_adapter *adapter = netdev_priv(netdev);
int i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (!rxfh->indir)
return 0;
for (i = 0; i < IGC_RETA_SIZE; i++)
- indir[i] = adapter->rss_indir_tbl[i];
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
return 0;
}
-static int igc_ethtool_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int igc_ethtool_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct igc_adapter *adapter = netdev_priv(netdev);
u32 num_queues;
int i;
/* We do not allow change in unsupported parameters */
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
num_queues = adapter->rss_queues;
/* Verify user input. */
for (i = 0; i < IGC_RETA_SIZE; i++)
- if (indir[i] >= num_queues)
+ if (rxfh->indir[i] >= num_queues)
return -EINVAL;
for (i = 0; i < IGC_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = indir[i];
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
igc_write_rss_indir_tbl(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_i225.c b/drivers/net/ethernet/intel/igc/igc_i225.c
index 17546a035ab1..0dd61719f1ed 100644
--- a/drivers/net/ethernet/intel/igc/igc_i225.c
+++ b/drivers/net/ethernet/intel/igc/igc_i225.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018 Intel Corporation */
+#include <linux/bitfield.h>
#include <linux/delay.h>
#include "igc_hw.h"
@@ -578,9 +579,8 @@ s32 igc_set_ltr_i225(struct igc_hw *hw, bool link)
/* Calculate tw_system (nsec). */
if (speed == SPEED_100) {
- tw_system = ((rd32(IGC_EEE_SU) &
- IGC_TW_SYSTEM_100_MASK) >>
- IGC_TW_SYSTEM_100_SHIFT) * 500;
+ tw_system = FIELD_GET(IGC_TW_SYSTEM_100_MASK,
+ rd32(IGC_EEE_SU)) * 500;
} else {
tw_system = (rd32(IGC_EEE_SU) &
IGC_TW_SYSTEM_1000_MASK) * 500;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index e9bb403bbacf..81c21a893ede 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -1299,14 +1299,16 @@ static void igc_tx_olinfo_status(struct igc_ring *tx_ring,
u32 olinfo_status = paylen << IGC_ADVTXD_PAYLEN_SHIFT;
/* insert L4 checksum */
- olinfo_status |= (tx_flags & IGC_TX_FLAGS_CSUM) *
- ((IGC_TXD_POPTS_TXSM << 8) /
- IGC_TX_FLAGS_CSUM);
+ olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_CSUM,
+ (IGC_TXD_POPTS_TXSM << 8));
/* insert IPv4 checksum */
- olinfo_status |= (tx_flags & IGC_TX_FLAGS_IPV4) *
- (((IGC_TXD_POPTS_IXSM << 8)) /
- IGC_TX_FLAGS_IPV4);
+ olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_IPV4,
+ (IGC_TXD_POPTS_IXSM << 8));
+
+ /* Use the second timer (free running, in general) for the timestamp */
+ olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_TIMER_1,
+ IGC_TXD_PTP2_TIMER_1);
tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
}
@@ -1651,6 +1653,8 @@ done:
if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags;
+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_USE_CYCLES)
+ tx_flags |= IGC_TX_FLAGS_TSTAMP_TIMER_1;
} else {
adapter->tx_hwtstamp_skipped++;
}
@@ -1963,9 +1967,9 @@ static struct sk_buff *igc_build_skb(struct igc_ring *rx_ring,
static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
struct igc_rx_buffer *rx_buffer,
- struct xdp_buff *xdp,
- ktime_t timestamp)
+ struct igc_xdp_buff *ctx)
{
+ struct xdp_buff *xdp = &ctx->xdp;
unsigned int metasize = xdp->data - xdp->data_meta;
unsigned int size = xdp->data_end - xdp->data;
unsigned int truesize = igc_get_rx_frame_truesize(rx_ring, size);
@@ -1982,8 +1986,10 @@ static struct sk_buff *igc_construct_skb(struct igc_ring *rx_ring,
if (unlikely(!skb))
return NULL;
- if (timestamp)
- skb_hwtstamps(skb)->hwtstamp = timestamp;
+ if (ctx->rx_ts) {
+ skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV;
+ skb_hwtstamps(skb)->netdev_data = ctx->rx_ts;
+ }
/* Determine available headroom for copy */
headlen = size;
@@ -2583,11 +2589,10 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
int xdp_status = 0, rx_buffer_pgcnt;
while (likely(total_packets < budget)) {
- union igc_adv_rx_desc *rx_desc;
+ struct igc_xdp_buff ctx = { .rx_ts = NULL };
struct igc_rx_buffer *rx_buffer;
+ union igc_adv_rx_desc *rx_desc;
unsigned int size, truesize;
- struct igc_xdp_buff ctx;
- ktime_t timestamp = 0;
int pkt_offset = 0;
void *pktbuf;
@@ -2614,9 +2619,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
pktbuf = page_address(rx_buffer->page) + rx_buffer->page_offset;
if (igc_test_staterr(rx_desc, IGC_RXDADV_STAT_TSIP)) {
- timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
- pktbuf);
- ctx.rx_ts = timestamp;
+ ctx.rx_ts = pktbuf;
pkt_offset = IGC_TS_HDR_LEN;
size -= IGC_TS_HDR_LEN;
}
@@ -2653,8 +2656,7 @@ static int igc_clean_rx_irq(struct igc_q_vector *q_vector, const int budget)
else if (ring_uses_build_skb(rx_ring))
skb = igc_build_skb(rx_ring, rx_buffer, &ctx.xdp);
else
- skb = igc_construct_skb(rx_ring, rx_buffer, &ctx.xdp,
- timestamp);
+ skb = igc_construct_skb(rx_ring, rx_buffer, &ctx);
/* exit if we failed to retrieve a buffer */
if (!skb) {
@@ -2803,9 +2805,7 @@ static int igc_clean_rx_irq_zc(struct igc_q_vector *q_vector, const int budget)
ctx->rx_desc = desc;
if (igc_test_staterr(desc, IGC_RXDADV_STAT_TSIP)) {
- timestamp = igc_ptp_rx_pktstamp(q_vector->adapter,
- bi->xdp->data);
- ctx->rx_ts = timestamp;
+ ctx->rx_ts = bi->xdp->data;
bi->xdp->data += IGC_TS_HDR_LEN;
@@ -3452,8 +3452,8 @@ static int igc_write_flex_filter_ll(struct igc_adapter *adapter,
/* Configure filter */
queuing = input->length & IGC_FHFT_LENGTH_MASK;
- queuing |= (input->rx_queue << IGC_FHFT_QUEUE_SHIFT) & IGC_FHFT_QUEUE_MASK;
- queuing |= (input->prio << IGC_FHFT_PRIO_SHIFT) & IGC_FHFT_PRIO_MASK;
+ queuing |= FIELD_PREP(IGC_FHFT_QUEUE_MASK, input->rx_queue);
+ queuing |= FIELD_PREP(IGC_FHFT_PRIO_MASK, input->prio);
if (input->immediate_irq)
queuing |= IGC_FHFT_IMM_INT;
@@ -3712,8 +3712,7 @@ static int igc_enable_nfc_rule(struct igc_adapter *adapter,
}
if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
- int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >>
- VLAN_PRIO_SHIFT;
+ int prio = FIELD_GET(VLAN_PRIO_MASK, rule->filter.vlan_tci);
err = igc_add_vlan_prio_filter(adapter, prio, rule->action);
if (err)
@@ -3735,8 +3734,7 @@ static void igc_disable_nfc_rule(struct igc_adapter *adapter,
igc_del_etype_filter(adapter, rule->filter.etype);
if (rule->filter.match_flags & IGC_FILTER_FLAG_VLAN_TCI) {
- int prio = (rule->filter.vlan_tci & VLAN_PRIO_MASK) >>
- VLAN_PRIO_SHIFT;
+ int prio = FIELD_GET(VLAN_PRIO_MASK, rule->filter.vlan_tci);
igc_del_vlan_prio_filter(adapter, prio);
}
@@ -6489,7 +6487,7 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
int cpu = smp_processor_id();
struct netdev_queue *nq;
struct igc_ring *ring;
- int i, drops;
+ int i, nxmit;
if (unlikely(!netif_carrier_ok(dev)))
return -ENETDOWN;
@@ -6505,16 +6503,15 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
/* Avoid transmit queue timeout since we share it with the slow path */
txq_trans_cond_update(nq);
- drops = 0;
+ nxmit = 0;
for (i = 0; i < num_frames; i++) {
int err;
struct xdp_frame *xdpf = frames[i];
err = igc_xdp_init_tx_descriptor(ring, xdpf);
- if (err) {
- xdp_return_frame_rx_napi(xdpf);
- drops++;
- }
+ if (err)
+ break;
+ nxmit++;
}
if (flags & XDP_XMIT_FLUSH)
@@ -6522,7 +6519,7 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
__netif_tx_unlock(nq);
- return num_frames - drops;
+ return nxmit;
}
static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
@@ -6562,6 +6559,24 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
return 0;
}
+static ktime_t igc_get_tstamp(struct net_device *dev,
+ const struct skb_shared_hwtstamps *hwtstamps,
+ bool cycles)
+{
+ struct igc_adapter *adapter = netdev_priv(dev);
+ struct igc_inline_rx_tstamps *tstamp;
+ ktime_t timestamp;
+
+ tstamp = hwtstamps->netdev_data;
+
+ if (cycles)
+ timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer1);
+ else
+ timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0);
+
+ return timestamp;
+}
+
static const struct net_device_ops igc_netdev_ops = {
.ndo_open = igc_open,
.ndo_stop = igc_close,
@@ -6579,6 +6594,7 @@ static const struct net_device_ops igc_netdev_ops = {
.ndo_bpf = igc_bpf,
.ndo_xdp_xmit = igc_xdp_xmit,
.ndo_xsk_wakeup = igc_xsk_wakeup,
+ .ndo_get_tstamp = igc_get_tstamp,
};
/* PCIe configuration access */
@@ -6682,9 +6698,11 @@ static int igc_xdp_rx_hash(const struct xdp_md *_ctx, u32 *hash,
static int igc_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp)
{
const struct igc_xdp_buff *ctx = (void *)_ctx;
+ struct igc_adapter *adapter = netdev_priv(ctx->xdp.rxq->dev);
+ struct igc_inline_rx_tstamps *tstamp = ctx->rx_ts;
if (igc_test_staterr(ctx->rx_desc, IGC_RXDADV_STAT_TSIP)) {
- *timestamp = ctx->rx_ts;
+ *timestamp = igc_ptp_rx_pktstamp(adapter, tstamp->timer0);
return 0;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_phy.c b/drivers/net/ethernet/intel/igc/igc_phy.c
index 53b77c969c85..861f37076861 100644
--- a/drivers/net/ethernet/intel/igc/igc_phy.c
+++ b/drivers/net/ethernet/intel/igc/igc_phy.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2018 Intel Corporation */
+#include <linux/bitfield.h>
#include "igc_phy.h"
/**
@@ -129,11 +130,7 @@ void igc_power_down_phy_copper(struct igc_hw *hw)
/* The PHY will retain its settings across a power down/up cycle */
hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg);
mii_reg |= MII_CR_POWER_DOWN;
-
- /* Temporary workaround - should be removed when PHY will implement
- * IEEE registers as properly
- */
- /* hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);*/
+ hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg);
usleep_range(1000, 2000);
}
@@ -726,7 +723,7 @@ static s32 igc_write_xmdio_reg(struct igc_hw *hw, u16 addr,
*/
s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
{
- u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
+ u8 dev_addr = FIELD_GET(GPY_MMD_MASK, offset);
s32 ret_val;
offset = offset & GPY_REG_MASK;
@@ -757,7 +754,7 @@ s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
*/
s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
{
- u8 dev_addr = (offset & GPY_MMD_MASK) >> GPY_MMD_SHIFT;
+ u8 dev_addr = FIELD_GET(GPY_MMD_MASK, offset);
s32 ret_val;
offset = offset & GPY_REG_MASK;
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 928f38792203..885faaa7b9de 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -459,12 +459,10 @@ static int igc_ptp_systim_to_hwtstamp(struct igc_adapter *adapter,
/**
* igc_ptp_rx_pktstamp - Retrieve timestamp from Rx packet buffer
* @adapter: Pointer to adapter the packet buffer belongs to
- * @buf: Pointer to packet buffer
+ * @buf: Pointer to start of timestamp in HW format (2 32-bit words)
*
- * This function retrieves the timestamp saved in the beginning of packet
- * buffer. While two timestamps are available, one in timer0 reference and the
- * other in timer1 reference, this function considers only the timestamp in
- * timer0 reference.
+ * This function retrieves and converts the timestamp stored at @buf
+ * to ktime_t, adjusting for hardware latencies.
*
* Returns timestamp value.
*/
@@ -474,17 +472,8 @@ ktime_t igc_ptp_rx_pktstamp(struct igc_adapter *adapter, __le32 *buf)
u32 secs, nsecs;
int adjust;
- /* Timestamps are saved in little endian at the beginning of the packet
- * buffer following the layout:
- *
- * DWORD: | 0 | 1 | 2 | 3 |
- * Field: | Timer1 SYSTIML | Timer1 SYSTIMH | Timer0 SYSTIML | Timer0 SYSTIMH |
- *
- * SYSTIML holds the nanoseconds part while SYSTIMH holds the seconds
- * part of the timestamp.
- */
- nsecs = le32_to_cpu(buf[2]);
- secs = le32_to_cpu(buf[3]);
+ nsecs = le32_to_cpu(buf[0]);
+ secs = le32_to_cpu(buf[1]);
timestamp = ktime_set(secs, nsecs);
@@ -542,10 +531,11 @@ static void igc_ptp_enable_rx_timestamp(struct igc_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++) {
val = rd32(IGC_SRRCTL(i));
- /* FIXME: For now, only support retrieving RX timestamps from
- * timer 0.
+ /* Enable retrieving timestamps from timer 0, the
+ * "adjustable clock" and timer 1 the "free running
+ * clock".
*/
- val |= IGC_SRRCTL_TIMER1SEL(0) | IGC_SRRCTL_TIMER0SEL(0) |
+ val |= IGC_SRRCTL_TIMER1SEL(1) | IGC_SRRCTL_TIMER0SEL(0) |
IGC_SRRCTL_TIMESTAMP;
wr32(IGC_SRRCTL(i), val);
}
@@ -1035,6 +1025,26 @@ static int igc_ptp_getcrosststamp(struct ptp_clock_info *ptp,
adapter, &adapter->snapshot, cts);
}
+static int igc_ptp_getcyclesx64(struct ptp_clock_info *ptp,
+ struct timespec64 *ts,
+ struct ptp_system_timestamp *sts)
+{
+ struct igc_adapter *igc = container_of(ptp, struct igc_adapter, ptp_caps);
+ struct igc_hw *hw = &igc->hw;
+ unsigned long flags;
+
+ spin_lock_irqsave(&igc->free_timer_lock, flags);
+
+ ptp_read_system_prets(sts);
+ ts->tv_nsec = rd32(IGC_SYSTIML_1);
+ ts->tv_sec = rd32(IGC_SYSTIMH_1);
+ ptp_read_system_postts(sts);
+
+ spin_unlock_irqrestore(&igc->free_timer_lock, flags);
+
+ return 0;
+}
+
/**
* igc_ptp_init - Initialize PTP functionality
* @adapter: Board private structure
@@ -1088,6 +1098,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
adapter->ptp_caps.adjfine = igc_ptp_adjfine_i225;
adapter->ptp_caps.adjtime = igc_ptp_adjtime_i225;
adapter->ptp_caps.gettimex64 = igc_ptp_gettimex64_i225;
+ adapter->ptp_caps.getcyclesx64 = igc_ptp_getcyclesx64;
adapter->ptp_caps.settime64 = igc_ptp_settime_i225;
adapter->ptp_caps.enable = igc_ptp_feature_enable_i225;
adapter->ptp_caps.pps = 1;
@@ -1108,6 +1119,7 @@ void igc_ptp_init(struct igc_adapter *adapter)
}
spin_lock_init(&adapter->ptp_tx_lock);
+ spin_lock_init(&adapter->free_timer_lock);
spin_lock_init(&adapter->tmreg_lock);
adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h
index 20e17f5fbce3..d38c87d7e5e8 100644
--- a/drivers/net/ethernet/intel/igc/igc_regs.h
+++ b/drivers/net/ethernet/intel/igc/igc_regs.h
@@ -243,6 +243,11 @@
#define IGC_SYSTIMR 0x0B6F8 /* System time register Residue */
#define IGC_TIMINCA 0x0B608 /* Increment attributes register - RW */
+#define IGC_SYSTIML_1 0x0B688 /* System time register Low - RO (timer 1) */
+#define IGC_SYSTIMH_1 0x0B68C /* System time register High - RO (timer 1) */
+#define IGC_SYSTIMR_1 0x0B684 /* System time register Residue (timer 1) */
+#define IGC_TIMINCA_1 0x0B690 /* Increment attributes register - RW (timer 1) */
+
/* TX Timestamp Low */
#define IGC_TXSTMPL_0 0x0B618
#define IGC_TXSTMPL_1 0x0B698
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 100388968e4d..6835d5f18753 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -123,14 +123,14 @@ static s32 ixgbe_init_phy_ops_82598(struct ixgbe_hw *hw)
if (ret_val)
return ret_val;
if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
/* Check to see if SFP+ module is supported */
ret_val = ixgbe_get_sfp_init_sequence_offsets(hw,
&list_offset,
&data_offset);
if (ret_val)
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
break;
default:
break;
@@ -213,7 +213,7 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw,
break;
default:
- return IXGBE_ERR_LINK_SETUP;
+ return -EIO;
}
return 0;
@@ -283,7 +283,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw)
/* Validate the water mark configuration */
if (!hw->fc.pause_time)
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
/* Low water mark of zero causes XOFF floods */
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
@@ -292,7 +292,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw)
if (!hw->fc.low_water[i] ||
hw->fc.low_water[i] >= hw->fc.high_water[i]) {
hw_dbg(hw, "Invalid water mark configuration\n");
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
}
}
@@ -369,7 +369,7 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw)
break;
default:
hw_dbg(hw, "Flow control param set incorrectly\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
/* Set 802.3x based flow control settings. */
@@ -438,7 +438,7 @@ static s32 ixgbe_start_mac_link_82598(struct ixgbe_hw *hw,
msleep(100);
}
if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
- status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+ status = -EIO;
hw_dbg(hw, "Autonegotiation did not complete.\n");
}
}
@@ -478,7 +478,7 @@ static s32 ixgbe_validate_link_ready(struct ixgbe_hw *hw)
if (timeout == IXGBE_VALIDATE_LINK_READY_TIMEOUT) {
hw_dbg(hw, "Link was indicated but link is down\n");
- return IXGBE_ERR_LINK_SETUP;
+ return -EIO;
}
return 0;
@@ -594,7 +594,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw,
speed &= link_capabilities;
if (speed == IXGBE_LINK_SPEED_UNKNOWN)
- return IXGBE_ERR_LINK_SETUP;
+ return -EINVAL;
/* Set KX4/KX support according to speed requested */
else if (link_mode == IXGBE_AUTOC_LMS_KX4_AN ||
@@ -701,9 +701,9 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
/* Init PHY and function pointers, perform SFP setup */
phy_status = hw->phy.ops.init(hw);
- if (phy_status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ if (phy_status == -EOPNOTSUPP)
return phy_status;
- if (phy_status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (phy_status == -ENOENT)
goto mac_reset_top;
hw->phy.ops.reset(hw);
@@ -727,7 +727,7 @@ mac_reset_top:
udelay(1);
}
if (ctrl & IXGBE_CTRL_RST) {
- status = IXGBE_ERR_RESET_FAILED;
+ status = -EIO;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
@@ -789,12 +789,12 @@ static s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
/* Make sure we are using a valid rar index range */
if (rar >= rar_entries) {
hw_dbg(hw, "RAR index %d is out of range.\n", rar);
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar));
rar_high &= ~IXGBE_RAH_VIND_MASK;
- rar_high |= ((vmdq << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK);
+ rar_high |= FIELD_PREP(IXGBE_RAH_VIND_MASK, vmdq);
IXGBE_WRITE_REG(hw, IXGBE_RAH(rar), rar_high);
return 0;
}
@@ -814,7 +814,7 @@ static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
/* Make sure we are using a valid rar index range */
if (rar >= rar_entries) {
hw_dbg(hw, "RAR index %d is out of range.\n", rar);
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(rar));
@@ -845,7 +845,7 @@ static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind,
u32 vftabyte;
if (vlan > 4095)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* Determine 32-bit word position in array */
regindex = (vlan >> 5) & 0x7F; /* upper seven bits */
@@ -964,7 +964,7 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
gssr = IXGBE_GSSR_PHY0_SM;
if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != 0)
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
if (hw->phy.type == ixgbe_phy_nl) {
/*
@@ -993,7 +993,7 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) {
hw_dbg(hw, "EEPROM read did not pass.\n");
- status = IXGBE_ERR_SFP_NOT_PRESENT;
+ status = -ENOENT;
goto out;
}
@@ -1003,7 +1003,7 @@ static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr,
*eeprom_data = (u8)(sfp_data >> 8);
} else {
- status = IXGBE_ERR_PHY;
+ status = -EIO;
}
out:
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 58ea959a4482..339e106a5732 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -117,7 +117,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
ret_val = hw->mac.ops.acquire_swfw_sync(hw,
IXGBE_GSSR_MAC_CSR_SM);
if (ret_val)
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
if (hw->eeprom.ops.read(hw, ++data_offset, &data_value))
goto setup_sfp_err;
@@ -144,7 +144,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
if (ret_val) {
hw_dbg(hw, " sfp module setup not complete\n");
- return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
+ return -EIO;
}
}
@@ -159,7 +159,7 @@ setup_sfp_err:
usleep_range(hw->eeprom.semaphore_delay * 1000,
hw->eeprom.semaphore_delay * 2000);
hw_err(hw, "eeprom read at offset %d failed\n", data_offset);
- return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
+ return -EIO;
}
/**
@@ -184,7 +184,7 @@ static s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked,
ret_val = hw->mac.ops.acquire_swfw_sync(hw,
IXGBE_GSSR_MAC_CSR_SM);
if (ret_val)
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
*locked = true;
}
@@ -219,7 +219,7 @@ static s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked)
ret_val = hw->mac.ops.acquire_swfw_sync(hw,
IXGBE_GSSR_MAC_CSR_SM);
if (ret_val)
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
locked = true;
}
@@ -400,7 +400,7 @@ static s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
break;
default:
- return IXGBE_ERR_LINK_SETUP;
+ return -EIO;
}
if (hw->phy.multispeed_fiber) {
@@ -541,7 +541,7 @@ static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw,
msleep(100);
}
if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
- status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+ status = -EIO;
hw_dbg(hw, "Autoneg did not complete.\n");
}
}
@@ -794,7 +794,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
speed &= link_capabilities;
if (speed == IXGBE_LINK_SPEED_UNKNOWN)
- return IXGBE_ERR_LINK_SETUP;
+ return -EINVAL;
/* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
if (hw->mac.orig_link_settings_stored)
@@ -861,8 +861,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
msleep(100);
}
if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
- status =
- IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+ status = -EIO;
hw_dbg(hw, "Autoneg did not complete.\n");
}
}
@@ -927,7 +926,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
/* Identify PHY and related function pointers */
status = hw->phy.ops.init(hw);
- if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ if (status == -EOPNOTSUPP)
return status;
/* Setup SFP module if there is one present. */
@@ -936,7 +935,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
hw->phy.sfp_setup_needed = false;
}
- if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ if (status == -EOPNOTSUPP)
return status;
/* Reset PHY */
@@ -974,7 +973,7 @@ mac_reset_top:
}
if (ctrl & IXGBE_CTRL_RST_MASK) {
- status = IXGBE_ERR_RESET_FAILED;
+ status = -EIO;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
@@ -1093,7 +1092,7 @@ static s32 ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd)
udelay(10);
}
- return IXGBE_ERR_FDIR_CMD_INCOMPLETE;
+ return -EIO;
}
/**
@@ -1155,7 +1154,7 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw)
}
if (i >= IXGBE_FDIR_INIT_DONE_POLL) {
hw_dbg(hw, "Flow Director Signature poll time exceeded!\n");
- return IXGBE_ERR_FDIR_REINIT_FAILED;
+ return -EIO;
}
/* Clear FDIR statistics registers (read to clear) */
@@ -1387,7 +1386,7 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw,
break;
default:
hw_dbg(hw, " Error on flow type input\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
/* configure FDIRCMD register */
@@ -1546,7 +1545,7 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
break;
default:
hw_dbg(hw, " Error on vm pool mask\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
switch (input_mask->formatted.flow_type & IXGBE_ATR_L4TYPE_MASK) {
@@ -1555,14 +1554,14 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
if (input_mask->formatted.dst_port ||
input_mask->formatted.src_port) {
hw_dbg(hw, " Error on src/dst port mask\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
break;
case IXGBE_ATR_L4TYPE_MASK:
break;
default:
hw_dbg(hw, " Error on flow type mask\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
switch (ntohs(input_mask->formatted.vlan_id) & 0xEFFF) {
@@ -1583,7 +1582,7 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
break;
default:
hw_dbg(hw, " Error on VLAN mask\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
switch ((__force u16)input_mask->formatted.flex_bytes & 0xFFFF) {
@@ -1595,7 +1594,7 @@ s32 ixgbe_fdir_set_input_mask_82599(struct ixgbe_hw *hw,
break;
default:
hw_dbg(hw, " Error on flexible byte mask\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
/* Now mask VM pool and destination IPv6 - bits 5 and 2 */
@@ -1824,7 +1823,7 @@ static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw)
/* Return error if SFP module has been detected but is not supported */
if (hw->phy.type == ixgbe_phy_sfp_unsupported)
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
return status;
}
@@ -1863,13 +1862,13 @@ static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval)
* Verifies that installed the firmware version is 0.6 or higher
* for SFI devices. All 82599 SFI devices should have version 0.6 or higher.
*
- * Returns IXGBE_ERR_EEPROM_VERSION if the FW is not present or
- * if the FW version is not supported.
+ * Return: -EACCES if the FW is not present or if the FW version is
+ * not supported.
**/
static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
{
- s32 status = IXGBE_ERR_EEPROM_VERSION;
u16 fw_offset, fw_ptp_cfg_offset;
+ s32 status = -EACCES;
u16 offset;
u16 fw_version = 0;
@@ -1883,7 +1882,7 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
goto fw_version_err;
if (fw_offset == 0 || fw_offset == 0xFFFF)
- return IXGBE_ERR_EEPROM_VERSION;
+ return -EACCES;
/* get the offset to the Pass Through Patch Configuration block */
offset = fw_offset + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR;
@@ -1891,7 +1890,7 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
goto fw_version_err;
if (fw_ptp_cfg_offset == 0 || fw_ptp_cfg_offset == 0xFFFF)
- return IXGBE_ERR_EEPROM_VERSION;
+ return -EACCES;
/* get the firmware version */
offset = fw_ptp_cfg_offset + IXGBE_FW_PATCH_VERSION_4;
@@ -1905,7 +1904,7 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw)
fw_version_err:
hw_err(hw, "eeprom read at offset %d failed\n", offset);
- return IXGBE_ERR_EEPROM_VERSION;
+ return -EACCES;
}
/**
@@ -2038,7 +2037,7 @@ static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
if (!(anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK)) {
hw_dbg(hw, "auto negotiation not completed\n");
- ret_val = IXGBE_ERR_RESET_FAILED;
+ ret_val = -EIO;
goto reset_pipeline_out;
}
@@ -2087,7 +2086,7 @@ static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
if (!timeout) {
hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
- status = IXGBE_ERR_I2C;
+ status = -EIO;
goto release_i2c_access;
}
}
@@ -2141,7 +2140,7 @@ static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
if (!timeout) {
hw_dbg(hw, "Driver can't access resource, acquiring I2C bus timeout.\n");
- status = IXGBE_ERR_I2C;
+ status = -EIO;
goto release_i2c_access;
}
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 878dd8dff528..2e6e0365154a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -124,7 +124,7 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw)
*/
if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
/*
@@ -215,7 +215,7 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw)
break;
default:
hw_dbg(hw, "Flow control param set incorrectly\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
if (hw->mac.type != ixgbe_mac_X540) {
@@ -500,7 +500,7 @@ s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
if (pba_num == NULL) {
hw_dbg(hw, "PBA string buffer was null\n");
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
ret_val = hw->eeprom.ops.read(hw, IXGBE_PBANUM0_PTR, &data);
@@ -526,7 +526,7 @@ s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
/* we will need 11 characters to store the PBA */
if (pba_num_size < 11) {
hw_dbg(hw, "PBA string buffer too small\n");
- return IXGBE_ERR_NO_SPACE;
+ return -ENOSPC;
}
/* extract hex string from data and pba_ptr */
@@ -563,13 +563,13 @@ s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
if (length == 0xFFFF || length == 0) {
hw_dbg(hw, "NVM PBA number section invalid length\n");
- return IXGBE_ERR_PBA_SECTION;
+ return -EIO;
}
/* check if pba_num buffer is big enough */
if (pba_num_size < (((u32)length * 2) - 1)) {
hw_dbg(hw, "PBA string buffer too small\n");
- return IXGBE_ERR_NO_SPACE;
+ return -ENOSPC;
}
/* trim pba length from start of string */
@@ -684,7 +684,7 @@ void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw)
u32 reg;
reg = IXGBE_READ_REG(hw, IXGBE_STATUS);
- bus->func = (reg & IXGBE_STATUS_LAN_ID) >> IXGBE_STATUS_LAN_ID_SHIFT;
+ bus->func = FIELD_GET(IXGBE_STATUS_LAN_ID, reg);
bus->lan_id = bus->func;
/* check for a port swap */
@@ -695,8 +695,8 @@ void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw)
/* Get MAC instance from EEPROM for configuring CS4227 */
if (hw->device_id == IXGBE_DEV_ID_X550EM_A_SFP) {
hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_4, &ee_ctrl_4);
- bus->instance_id = (ee_ctrl_4 & IXGBE_EE_CTRL_4_INST_ID) >>
- IXGBE_EE_CTRL_4_INST_ID_SHIFT;
+ bus->instance_id = FIELD_GET(IXGBE_EE_CTRL_4_INST_ID,
+ ee_ctrl_4);
}
}
@@ -805,7 +805,7 @@ s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index)
u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
if (index > 3)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* To turn on the LED, set mode to ON. */
led_reg &= ~IXGBE_LED_MODE_MASK(index);
@@ -826,7 +826,7 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index)
u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
if (index > 3)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* To turn off the LED, set mode to OFF. */
led_reg &= ~IXGBE_LED_MODE_MASK(index);
@@ -870,10 +870,9 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
* SPI EEPROM is assumed here. This code would need to
* change if a future EEPROM is not SPI.
*/
- eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
- IXGBE_EEC_SIZE_SHIFT);
+ eeprom_size = FIELD_GET(IXGBE_EEC_SIZE, eec);
eeprom->word_size = BIT(eeprom_size +
- IXGBE_EEPROM_WORD_SIZE_SHIFT);
+ IXGBE_EEPROM_WORD_SIZE_SHIFT);
}
if (eec & IXGBE_EEC_ADDR_SIZE)
@@ -904,11 +903,8 @@ s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
hw->eeprom.ops.init_params(hw);
- if (words == 0)
- return IXGBE_ERR_INVALID_ARGUMENT;
-
- if (offset + words > hw->eeprom.word_size)
- return IXGBE_ERR_EEPROM;
+ if (words == 0 || (offset + words > hw->eeprom.word_size))
+ return -EINVAL;
/*
* The EEPROM page size cannot be queried from the chip. We do lazy
@@ -962,7 +958,7 @@ static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
if (ixgbe_ready_eeprom(hw) != 0) {
ixgbe_release_eeprom(hw);
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
for (i = 0; i < words; i++) {
@@ -1028,7 +1024,7 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
hw->eeprom.ops.init_params(hw);
if (offset >= hw->eeprom.word_size)
- return IXGBE_ERR_EEPROM;
+ return -EINVAL;
return ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data);
}
@@ -1050,11 +1046,8 @@ s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
hw->eeprom.ops.init_params(hw);
- if (words == 0)
- return IXGBE_ERR_INVALID_ARGUMENT;
-
- if (offset + words > hw->eeprom.word_size)
- return IXGBE_ERR_EEPROM;
+ if (words == 0 || (offset + words > hw->eeprom.word_size))
+ return -EINVAL;
/*
* We cannot hold synchronization semaphores for too long
@@ -1099,7 +1092,7 @@ static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
if (ixgbe_ready_eeprom(hw) != 0) {
ixgbe_release_eeprom(hw);
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
for (i = 0; i < words; i++) {
@@ -1142,7 +1135,7 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
hw->eeprom.ops.init_params(hw);
if (offset >= hw->eeprom.word_size)
- return IXGBE_ERR_EEPROM;
+ return -EINVAL;
return ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data);
}
@@ -1165,11 +1158,8 @@ s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset,
hw->eeprom.ops.init_params(hw);
- if (words == 0)
- return IXGBE_ERR_INVALID_ARGUMENT;
-
- if (offset >= hw->eeprom.word_size)
- return IXGBE_ERR_EEPROM;
+ if (words == 0 || offset >= hw->eeprom.word_size)
+ return -EINVAL;
for (i = 0; i < words; i++) {
eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
@@ -1262,11 +1252,8 @@ s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset,
hw->eeprom.ops.init_params(hw);
- if (words == 0)
- return IXGBE_ERR_INVALID_ARGUMENT;
-
- if (offset >= hw->eeprom.word_size)
- return IXGBE_ERR_EEPROM;
+ if (words == 0 || offset >= hw->eeprom.word_size)
+ return -EINVAL;
for (i = 0; i < words; i++) {
eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
@@ -1328,7 +1315,7 @@ static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
}
udelay(5);
}
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/**
@@ -1344,7 +1331,7 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
u32 i;
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0)
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
@@ -1366,7 +1353,7 @@ static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
hw_dbg(hw, "Could not acquire EEPROM grant\n");
hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/* Setup EEPROM for Read/Write */
@@ -1419,7 +1406,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
swsm = IXGBE_READ_REG(hw, IXGBE_SWSM(hw));
if (swsm & IXGBE_SWSM_SMBI) {
hw_dbg(hw, "Software semaphore SMBI between device drivers not granted.\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
}
@@ -1447,7 +1434,7 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
if (i >= timeout) {
hw_dbg(hw, "SWESMBI Software EEPROM semaphore not granted.\n");
ixgbe_release_eeprom_semaphore(hw);
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
return 0;
@@ -1503,7 +1490,7 @@ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw)
*/
if (i >= IXGBE_EEPROM_MAX_RETRY_SPI) {
hw_dbg(hw, "SPI EEPROM Status error\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
return 0;
@@ -1715,7 +1702,7 @@ s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw)
for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
if (hw->eeprom.ops.read(hw, i, &pointer)) {
hw_dbg(hw, "EEPROM read failed\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/* If the pointer seems invalid */
@@ -1724,7 +1711,7 @@ s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw)
if (hw->eeprom.ops.read(hw, pointer, &length)) {
hw_dbg(hw, "EEPROM read failed\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
if (length == 0xFFFF || length == 0)
@@ -1733,7 +1720,7 @@ s32 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw)
for (j = pointer + 1; j <= pointer + length; j++) {
if (hw->eeprom.ops.read(hw, j, &word)) {
hw_dbg(hw, "EEPROM read failed\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
checksum += word;
}
@@ -1786,7 +1773,7 @@ s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
* calculated checksum
*/
if (read_checksum != checksum)
- status = IXGBE_ERR_EEPROM_CHECKSUM;
+ status = -EIO;
/* If the user cares, return the calculated checksum */
if (checksum_val)
@@ -1845,7 +1832,7 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
/* Make sure we are using a valid rar index range */
if (index >= rar_entries) {
hw_dbg(hw, "RAR index %d is out of range.\n", index);
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
/* setup VMDq pool selection before this RAR gets enabled */
@@ -1897,7 +1884,7 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index)
/* Make sure we are using a valid rar index range */
if (index >= rar_entries) {
hw_dbg(hw, "RAR index %d is out of range.\n", index);
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
/*
@@ -2146,7 +2133,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw)
/* Validate the water mark configuration. */
if (!hw->fc.pause_time)
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
/* Low water mark of zero causes XOFF floods */
for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
@@ -2155,7 +2142,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw)
if (!hw->fc.low_water[i] ||
hw->fc.low_water[i] >= hw->fc.high_water[i]) {
hw_dbg(hw, "Invalid water mark configuration\n");
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
}
}
@@ -2212,7 +2199,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw)
break;
default:
hw_dbg(hw, "Flow control param set incorrectly\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
/* Set 802.3x based flow control settings. */
@@ -2269,7 +2256,7 @@ s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm)
{
if ((!(adv_reg)) || (!(lp_reg)))
- return IXGBE_ERR_FC_NOT_NEGOTIATED;
+ return -EINVAL;
if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) {
/*
@@ -2321,7 +2308,7 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw)
linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) ||
(!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1))
- return IXGBE_ERR_FC_NOT_NEGOTIATED;
+ return -EIO;
pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
@@ -2353,12 +2340,12 @@ static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw)
*/
links = IXGBE_READ_REG(hw, IXGBE_LINKS);
if ((links & IXGBE_LINKS_KX_AN_COMP) == 0)
- return IXGBE_ERR_FC_NOT_NEGOTIATED;
+ return -EIO;
if (hw->mac.type == ixgbe_mac_82599EB) {
links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2);
if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0)
- return IXGBE_ERR_FC_NOT_NEGOTIATED;
+ return -EIO;
}
/*
* Read the 10g AN autoc and LP ability registers and resolve
@@ -2407,8 +2394,8 @@ static s32 ixgbe_fc_autoneg_copper(struct ixgbe_hw *hw)
**/
void ixgbe_fc_autoneg(struct ixgbe_hw *hw)
{
- s32 ret_val = IXGBE_ERR_FC_NOT_NEGOTIATED;
ixgbe_link_speed speed;
+ s32 ret_val = -EIO;
bool link_up;
/*
@@ -2510,7 +2497,7 @@ static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw)
* @hw: pointer to hardware structure
*
* Disables PCI-Express primary access and verifies there are no pending
- * requests. IXGBE_ERR_PRIMARY_REQUESTS_PENDING is returned if primary disable
+ * requests. -EALREADY is returned if primary disable
* bit hasn't caused the primary requests to be disabled, else 0
* is returned signifying primary requests disabled.
**/
@@ -2575,7 +2562,7 @@ gio_disable_fail:
}
hw_dbg(hw, "PCIe transaction pending bit also did not clear.\n");
- return IXGBE_ERR_PRIMARY_REQUESTS_PENDING;
+ return -EALREADY;
}
/**
@@ -2600,7 +2587,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask)
* SW_FW_SYNC bits (not just NVM)
*/
if (ixgbe_get_eeprom_semaphore(hw))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
if (!(gssr & (fwmask | swmask))) {
@@ -2620,7 +2607,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u32 mask)
ixgbe_release_swfw_sync(hw, gssr & (fwmask | swmask));
usleep_range(5000, 10000);
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
/**
@@ -2757,7 +2744,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
s32 ret_val;
if (index > 3)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/*
* Link must be up to auto-blink the LEDs;
@@ -2803,7 +2790,7 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index)
s32 ret_val;
if (index > 3)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg);
if (ret_val)
@@ -2963,7 +2950,7 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
/* Make sure we are using a valid rar index range */
if (rar >= rar_entries) {
hw_dbg(hw, "RAR index %d is out of range.\n", rar);
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
@@ -3014,7 +3001,7 @@ s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
/* Make sure we are using a valid rar index range */
if (rar >= rar_entries) {
hw_dbg(hw, "RAR index %d is out of range.\n", rar);
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
if (vmdq < 32) {
@@ -3091,7 +3078,7 @@ static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass)
* will simply bypass the VLVF if there are no entries present in the
* VLVF that contain our VLAN
*/
- first_empty_slot = vlvf_bypass ? IXGBE_ERR_NO_SPACE : 0;
+ first_empty_slot = vlvf_bypass ? -ENOSPC : 0;
/* add VLAN enable bit for comparison */
vlan |= IXGBE_VLVF_VIEN;
@@ -3115,7 +3102,7 @@ static s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan, bool vlvf_bypass)
if (!first_empty_slot)
hw_dbg(hw, "No space in VLVF.\n");
- return first_empty_slot ? : IXGBE_ERR_NO_SPACE;
+ return first_empty_slot ? : -ENOSPC;
}
/**
@@ -3135,7 +3122,7 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
s32 vlvf_index;
if ((vlan > 4095) || (vind > 63))
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/*
* this is a 2 part operation - first the VFTA, then the
@@ -3611,7 +3598,8 @@ u8 ixgbe_calculate_checksum(u8 *buffer, u32 length)
*
* Communicates with the manageability block. On success return 0
* else returns semaphore error when encountering an error acquiring
- * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ * semaphore, -EINVAL when incorrect parameters passed or -EIO when
+ * command fails.
*
* This function assumes that the IXGBE_GSSR_SW_MNG_SM semaphore is held
* by the caller.
@@ -3624,7 +3612,7 @@ s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length,
if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) {
hw_dbg(hw, "Buffer length failure buffersize-%d.\n", length);
- return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ return -EINVAL;
}
/* Set bit 9 of FWSTS clearing FW reset indication */
@@ -3635,13 +3623,13 @@ s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length,
hicr = IXGBE_READ_REG(hw, IXGBE_HICR);
if (!(hicr & IXGBE_HICR_EN)) {
hw_dbg(hw, "IXGBE_HOST_EN bit disabled.\n");
- return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ return -EIO;
}
/* Calculate length in DWORDs. We must be DWORD aligned */
if (length % sizeof(u32)) {
hw_dbg(hw, "Buffer length failure, not aligned to dword");
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
}
dword_len = length >> 2;
@@ -3666,7 +3654,7 @@ s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length,
/* Check command successful completion. */
if ((timeout && i == timeout) ||
!(IXGBE_READ_REG(hw, IXGBE_HICR) & IXGBE_HICR_SV))
- return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ return -EIO;
return 0;
}
@@ -3686,7 +3674,7 @@ s32 ixgbe_hic_unlocked(struct ixgbe_hw *hw, u32 *buffer, u32 length,
* in these cases.
*
* Communicates with the manageability block. On success return 0
- * else return IXGBE_ERR_HOST_INTERFACE_COMMAND.
+ * else return -EIO or -EINVAL.
**/
s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
u32 length, u32 timeout,
@@ -3701,7 +3689,7 @@ s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
if (!length || length > IXGBE_HI_MAX_BLOCK_BYTE_LENGTH) {
hw_dbg(hw, "Buffer length failure buffersize-%d.\n", length);
- return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ return -EINVAL;
}
/* Take management host interface semaphore */
status = hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_SW_MNG_SM);
@@ -3731,7 +3719,7 @@ s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, void *buffer,
if (length < round_up(buf_len, 4) + hdr_size) {
hw_dbg(hw, "Buffer not large enough for reply message.\n");
- status = IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ status = -EIO;
goto rel_out;
}
@@ -3762,8 +3750,8 @@ rel_out:
*
* Sends driver version number to firmware through the manageability
* block. On success return 0
- * else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring
- * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ * else returns -EBUSY when encountering an error acquiring
+ * semaphore or -EIO when command fails.
**/
s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
u8 build, u8 sub, __always_unused u16 len,
@@ -3799,7 +3787,7 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
FW_CEM_RESP_STATUS_SUCCESS)
ret_val = 0;
else
- ret_val = IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ ret_val = -EIO;
break;
}
@@ -3897,14 +3885,14 @@ static s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg,
return status;
if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF))
- return IXGBE_NOT_IMPLEMENTED;
+ return -EOPNOTSUPP;
status = hw->eeprom.ops.read(hw, *ets_offset, ets_cfg);
if (status)
return status;
if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED)
- return IXGBE_NOT_IMPLEMENTED;
+ return -EOPNOTSUPP;
return 0;
}
@@ -3927,7 +3915,7 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw)
/* Only support thermal sensors attached to physical port 0 */
if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1))
- return IXGBE_NOT_IMPLEMENTED;
+ return -EOPNOTSUPP;
status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset);
if (status)
@@ -3946,10 +3934,10 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw)
if (status)
return status;
- sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >>
- IXGBE_ETS_DATA_INDEX_SHIFT);
- sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >>
- IXGBE_ETS_DATA_LOC_SHIFT);
+ sensor_index = FIELD_GET(IXGBE_ETS_DATA_INDEX_MASK,
+ ets_sensor);
+ sensor_location = FIELD_GET(IXGBE_ETS_DATA_LOC_MASK,
+ ets_sensor);
if (sensor_location != 0) {
status = hw->phy.ops.read_i2c_byte(hw,
@@ -3987,14 +3975,13 @@ s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw)
/* Only support thermal sensors attached to physical port 0 */
if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1))
- return IXGBE_NOT_IMPLEMENTED;
+ return -EOPNOTSUPP;
status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset);
if (status)
return status;
- low_thresh_delta = ((ets_cfg & IXGBE_ETS_LTHRES_DELTA_MASK) >>
- IXGBE_ETS_LTHRES_DELTA_SHIFT);
+ low_thresh_delta = FIELD_GET(IXGBE_ETS_LTHRES_DELTA_MASK, ets_cfg);
num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK);
if (num_sensors > IXGBE_MAX_SENSORS)
num_sensors = IXGBE_MAX_SENSORS;
@@ -4008,10 +3995,10 @@ s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw)
ets_offset + 1 + i);
continue;
}
- sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >>
- IXGBE_ETS_DATA_INDEX_SHIFT);
- sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >>
- IXGBE_ETS_DATA_LOC_SHIFT);
+ sensor_index = FIELD_GET(IXGBE_ETS_DATA_INDEX_MASK,
+ ets_sensor);
+ sensor_location = FIELD_GET(IXGBE_ETS_DATA_LOC_MASK,
+ ets_sensor);
therm_limit = ets_sensor & IXGBE_ETS_DATA_HTHRESH_MASK;
hw->phy.ops.write_i2c_byte(hw,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 4dd897806fa5..9a63457712c7 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1413,12 +1413,11 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
switch (stringset) {
case ETH_SS_TEST:
for (i = 0; i < IXGBE_TEST_LEN; i++)
- ethtool_sprintf(&p, "%s", ixgbe_gstrings_test[i]);
+ ethtool_puts(&p, ixgbe_gstrings_test[i]);
break;
case ETH_SS_STATS:
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++)
- ethtool_sprintf(&p, "%s",
- ixgbe_gstrings_stats[i].stat_string);
+ ethtool_puts(&p, ixgbe_gstrings_stats[i].stat_string);
for (i = 0; i < netdev->num_tx_queues; i++) {
ethtool_sprintf(&p, "tx_queue_%u_packets", i);
ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
@@ -3108,35 +3107,37 @@ static void ixgbe_get_reta(struct ixgbe_adapter *adapter, u32 *indir)
indir[i] = adapter->rss_indir_tbl[i] & rss_m;
}
-static int ixgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int ixgbe_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (indir)
- ixgbe_get_reta(adapter, indir);
+ if (rxfh->indir)
+ ixgbe_get_reta(adapter, rxfh->indir);
- if (key)
- memcpy(key, adapter->rss_key, ixgbe_get_rxfh_key_size(netdev));
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key,
+ ixgbe_get_rxfh_key_size(netdev));
return 0;
}
-static int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int ixgbe_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
int i;
u32 reta_entries = ixgbe_rss_indir_tbl_entries(adapter);
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
/* Fill out the redirection table */
- if (indir) {
+ if (rxfh->indir) {
int max_queues = min_t(int, adapter->num_rx_queues,
ixgbe_rss_indir_tbl_max(adapter));
@@ -3147,18 +3148,19 @@ static int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir,
/* Verify user input. */
for (i = 0; i < reta_entries; i++)
- if (indir[i] >= max_queues)
+ if (rxfh->indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
- adapter->rss_indir_tbl[i] = indir[i];
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
ixgbe_store_reta(adapter);
}
/* Fill out the rss hash key */
- if (key) {
- memcpy(adapter->rss_key, key, ixgbe_get_rxfh_key_size(netdev));
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key,
+ ixgbe_get_rxfh_key_size(netdev));
ixgbe_store_key(adapter);
}
@@ -3370,7 +3372,7 @@ static int ixgbe_get_module_eeprom(struct net_device *dev,
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
struct ixgbe_hw *hw = &adapter->hw;
- s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+ s32 status = -EFAULT;
u8 databyte = 0xFF;
int i = 0;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
index 7311bd545acf..18d63c8c2ff4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
@@ -670,8 +670,8 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
int fcoe_i_h = fcoe->offset + ((i + fcreta_size) %
fcoe->indices);
fcoe_q_h = adapter->rx_ring[fcoe_i_h]->reg_idx;
- fcoe_q_h = (fcoe_q_h << IXGBE_FCRETA_ENTRY_HIGH_SHIFT) &
- IXGBE_FCRETA_ENTRY_HIGH_MASK;
+ fcoe_q_h = FIELD_PREP(IXGBE_FCRETA_ENTRY_HIGH_MASK,
+ fcoe_q_h);
}
fcoe_i = fcoe->offset + (i % fcoe->indices);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 94bde2cad0f4..99876b765b08 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -2756,7 +2756,6 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 eicr = adapter->interrupt_event;
- s32 rc;
if (test_bit(__IXGBE_DOWN, &adapter->state))
return;
@@ -2790,14 +2789,13 @@ static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
}
/* Check if this is not due to overtemp */
- if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP)
+ if (!hw->phy.ops.check_overtemp(hw))
return;
break;
case IXGBE_DEV_ID_X550EM_A_1G_T:
case IXGBE_DEV_ID_X550EM_A_1G_T_L:
- rc = hw->phy.ops.check_overtemp(hw);
- if (rc != IXGBE_ERR_OVERTEMP)
+ if (!hw->phy.ops.check_overtemp(hw))
return;
break;
default:
@@ -2941,8 +2939,8 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter,
u64 qmask)
{
- u32 mask;
struct ixgbe_hw *hw = &adapter->hw;
+ u32 mask;
switch (hw->mac.type) {
case ixgbe_mac_82598EB:
@@ -5512,7 +5510,7 @@ static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
{
u32 speed;
bool autoneg, link_up = false;
- int ret = IXGBE_ERR_LINK_SETUP;
+ int ret = -EIO;
if (hw->mac.ops.check_link)
ret = hw->mac.ops.check_link(hw, &speed, &link_up, false);
@@ -5983,13 +5981,13 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
err = hw->mac.ops.init_hw(hw);
switch (err) {
case 0:
- case IXGBE_ERR_SFP_NOT_PRESENT:
- case IXGBE_ERR_SFP_NOT_SUPPORTED:
+ case -ENOENT:
+ case -EOPNOTSUPP:
break;
- case IXGBE_ERR_PRIMARY_REQUESTS_PENDING:
+ case -EALREADY:
e_dev_err("primary disable timed out\n");
break;
- case IXGBE_ERR_EEPROM_VERSION:
+ case -EACCES:
/* We are running on a pre-production device, log a warning */
e_dev_warn("This device is a pre-production adapter/LOM. "
"Please be aware there may be issues associated with "
@@ -7829,10 +7827,10 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
adapter->sfp_poll_time = jiffies + IXGBE_SFP_POLL_JIFFIES - 1;
err = hw->phy.ops.identify_sfp(hw);
- if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ if (err == -EOPNOTSUPP)
goto sfp_out;
- if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+ if (err == -ENOENT) {
/* If no cable is present, then we need to reset
* the next time we find a good cable. */
adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
@@ -7858,7 +7856,7 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
else
err = hw->mac.ops.setup_sfp(hw);
- if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ if (err == -EOPNOTSUPP)
goto sfp_out;
adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
@@ -7867,8 +7865,8 @@ static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
sfp_out:
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
- if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) &&
- (adapter->netdev->reg_state == NETREG_REGISTERED)) {
+ if (err == -EOPNOTSUPP &&
+ adapter->netdev->reg_state == NETREG_REGISTERED) {
e_dev_err("failed to initialize because an unsupported "
"SFP+ module type was detected.\n");
e_dev_err("Reload the driver after installing a "
@@ -7938,7 +7936,7 @@ static void ixgbe_service_timer(struct timer_list *t)
static void ixgbe_phy_interrupt_subtask(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
- u32 status;
+ bool overtemp;
if (!(adapter->flags2 & IXGBE_FLAG2_PHY_INTERRUPT))
return;
@@ -7948,11 +7946,9 @@ static void ixgbe_phy_interrupt_subtask(struct ixgbe_adapter *adapter)
if (!hw->phy.ops.handle_lasi)
return;
- status = hw->phy.ops.handle_lasi(&adapter->hw);
- if (status != IXGBE_ERR_OVERTEMP)
- return;
-
- e_crit(drv, "%s\n", ixgbe_overheat_msg);
+ hw->phy.ops.handle_lasi(&adapter->hw, &overtemp);
+ if (overtemp)
+ e_crit(drv, "%s\n", ixgbe_overheat_msg);
}
static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
@@ -10529,6 +10525,44 @@ static void ixgbe_reset_rxr_stats(struct ixgbe_ring *rx_ring)
}
/**
+ * ixgbe_irq_disable_single - Disable single IRQ vector
+ * @adapter: adapter structure
+ * @ring: ring index
+ **/
+static void ixgbe_irq_disable_single(struct ixgbe_adapter *adapter, u32 ring)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 qmask = BIT_ULL(ring);
+ u32 mask;
+
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82598EB:
+ mask = qmask & IXGBE_EIMC_RTX_QUEUE;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, mask);
+ break;
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ case ixgbe_mac_x550em_a:
+ mask = (qmask & 0xFFFFFFFF);
+ if (mask)
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
+ mask = (qmask >> 32);
+ if (mask)
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask);
+ break;
+ default:
+ break;
+ }
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ synchronize_irq(adapter->msix_entries[ring].vector);
+ else
+ synchronize_irq(adapter->pdev->irq);
+}
+
+/**
* ixgbe_txrx_ring_disable - Disable Rx/Tx/XDP Tx rings
* @adapter: adapter structure
* @ring: ring index
@@ -10544,6 +10578,11 @@ void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring)
tx_ring = adapter->tx_ring[ring];
xdp_ring = adapter->xdp_ring[ring];
+ ixgbe_irq_disable_single(adapter, ring);
+
+ /* Rx/Tx/XDP Tx share the same napi context. */
+ napi_disable(&rx_ring->q_vector->napi);
+
ixgbe_disable_txr(adapter, tx_ring);
if (xdp_ring)
ixgbe_disable_txr(adapter, xdp_ring);
@@ -10552,9 +10591,6 @@ void ixgbe_txrx_ring_disable(struct ixgbe_adapter *adapter, int ring)
if (xdp_ring)
synchronize_rcu();
- /* Rx/Tx/XDP Tx share the same napi context. */
- napi_disable(&rx_ring->q_vector->napi);
-
ixgbe_clean_tx_ring(tx_ring);
if (xdp_ring)
ixgbe_clean_tx_ring(xdp_ring);
@@ -10582,9 +10618,6 @@ void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring)
tx_ring = adapter->tx_ring[ring];
xdp_ring = adapter->xdp_ring[ring];
- /* Rx/Tx/XDP Tx share the same napi context. */
- napi_enable(&rx_ring->q_vector->napi);
-
ixgbe_configure_tx_ring(adapter, tx_ring);
if (xdp_ring)
ixgbe_configure_tx_ring(adapter, xdp_ring);
@@ -10593,6 +10626,11 @@ void ixgbe_txrx_ring_enable(struct ixgbe_adapter *adapter, int ring)
clear_bit(__IXGBE_TX_DISABLED, &tx_ring->state);
if (xdp_ring)
clear_bit(__IXGBE_TX_DISABLED, &xdp_ring->state);
+
+ /* Rx/Tx/XDP Tx share the same napi context. */
+ napi_enable(&rx_ring->q_vector->napi);
+ ixgbe_irq_enable_queues(adapter, BIT_ULL(ring));
+ IXGBE_WRITE_FLUSH(&adapter->hw);
}
/**
@@ -10922,9 +10960,9 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = hw->mac.ops.reset_hw(hw);
hw->phy.reset_if_overtemp = false;
ixgbe_set_eee_capable(adapter);
- if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+ if (err == -ENOENT) {
err = 0;
- } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+ } else if (err == -EOPNOTSUPP) {
e_dev_err("failed to load because an unsupported SFP+ or QSFP module type was detected.\n");
e_dev_err("Reload the driver after installing a supported module.\n");
goto err_sw_init;
@@ -11143,7 +11181,7 @@ skip_sriov:
/* reset the hardware with the new settings */
err = hw->mac.ops.start_hw(hw);
- if (err == IXGBE_ERR_EEPROM_VERSION) {
+ if (err == -EACCES) {
/* We are running on a pre-production device, log a warning */
e_dev_warn("This device is a pre-production adapter/LOM. "
"Please be aware there may be issues associated "
@@ -11371,7 +11409,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
if ((pf_func & 1) == (pdev->devfn & 1)) {
unsigned int device_id;
- vf = (req_id & 0x7F) >> 1;
+ vf = FIELD_GET(0x7F, req_id);
e_dev_err("VF %d has caused a PCIe error\n", vf);
e_dev_err("TLP: dw0: %8.8x\tdw1: %8.8x\tdw2: "
"%8.8x\tdw3: %8.8x\n",
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
index 5679293e53f7..fe7ef5773369 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
@@ -24,7 +24,7 @@ s32 ixgbe_read_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
size = mbx->size;
if (!mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
return mbx->ops->read(hw, msg, size, mbx_id);
}
@@ -43,10 +43,10 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
struct ixgbe_mbx_info *mbx = &hw->mbx;
if (size > mbx->size)
- return IXGBE_ERR_MBX;
+ return -EINVAL;
if (!mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
return mbx->ops->write(hw, msg, size, mbx_id);
}
@@ -63,7 +63,7 @@ s32 ixgbe_check_for_msg(struct ixgbe_hw *hw, u16 mbx_id)
struct ixgbe_mbx_info *mbx = &hw->mbx;
if (!mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
return mbx->ops->check_for_msg(hw, mbx_id);
}
@@ -80,7 +80,7 @@ s32 ixgbe_check_for_ack(struct ixgbe_hw *hw, u16 mbx_id)
struct ixgbe_mbx_info *mbx = &hw->mbx;
if (!mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
return mbx->ops->check_for_ack(hw, mbx_id);
}
@@ -97,7 +97,7 @@ s32 ixgbe_check_for_rst(struct ixgbe_hw *hw, u16 mbx_id)
struct ixgbe_mbx_info *mbx = &hw->mbx;
if (!mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
return mbx->ops->check_for_rst(hw, mbx_id);
}
@@ -115,12 +115,12 @@ static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id)
int countdown = mbx->timeout;
if (!countdown || !mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
while (mbx->ops->check_for_msg(hw, mbx_id)) {
countdown--;
if (!countdown)
- return IXGBE_ERR_MBX;
+ return -EIO;
udelay(mbx->usec_delay);
}
@@ -140,12 +140,12 @@ static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id)
int countdown = mbx->timeout;
if (!countdown || !mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
while (mbx->ops->check_for_ack(hw, mbx_id)) {
countdown--;
if (!countdown)
- return IXGBE_ERR_MBX;
+ return -EIO;
udelay(mbx->usec_delay);
}
@@ -169,7 +169,7 @@ static s32 ixgbe_read_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
s32 ret_val;
if (!mbx->ops)
- return IXGBE_ERR_MBX;
+ return -EIO;
ret_val = ixgbe_poll_for_msg(hw, mbx_id);
if (ret_val)
@@ -197,7 +197,7 @@ static s32 ixgbe_write_posted_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size,
/* exit if either we can't write or there isn't a defined timeout */
if (!mbx->ops || !mbx->timeout)
- return IXGBE_ERR_MBX;
+ return -EIO;
/* send msg */
ret_val = mbx->ops->write(hw, msg, size, mbx_id);
@@ -217,7 +217,7 @@ static s32 ixgbe_check_for_bit_pf(struct ixgbe_hw *hw, u32 mask, s32 index)
return 0;
}
- return IXGBE_ERR_MBX;
+ return -EIO;
}
/**
@@ -238,7 +238,7 @@ static s32 ixgbe_check_for_msg_pf(struct ixgbe_hw *hw, u16 vf_number)
return 0;
}
- return IXGBE_ERR_MBX;
+ return -EIO;
}
/**
@@ -259,7 +259,7 @@ static s32 ixgbe_check_for_ack_pf(struct ixgbe_hw *hw, u16 vf_number)
return 0;
}
- return IXGBE_ERR_MBX;
+ return -EIO;
}
/**
@@ -295,7 +295,7 @@ static s32 ixgbe_check_for_rst_pf(struct ixgbe_hw *hw, u16 vf_number)
return 0;
}
- return IXGBE_ERR_MBX;
+ return -EIO;
}
/**
@@ -317,7 +317,7 @@ static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number)
if (p2v_mailbox & IXGBE_PFMAILBOX_PFU)
return 0;
- return IXGBE_ERR_MBX;
+ return -EIO;
}
/**
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
index 8f4316b19278..6434c190e7a4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
@@ -7,7 +7,6 @@
#include "ixgbe_type.h"
#define IXGBE_VFMAILBOX_SIZE 16 /* 16 32 bit words - 64 bytes */
-#define IXGBE_ERR_MBX -100
#define IXGBE_VFMAILBOX 0x002FC
#define IXGBE_VFMBMEM 0x00200
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
index 689470c1e8ad..f28140a05f09 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
@@ -102,7 +102,7 @@ s32 ixgbe_read_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
csum = ~csum;
do {
if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
ixgbe_i2c_start(hw);
/* Device Address and write indication */
if (ixgbe_out_i2c_byte_ack(hw, addr))
@@ -150,7 +150,7 @@ fail:
hw_dbg(hw, "I2C byte read combined error.\n");
} while (retry < max_retry);
- return IXGBE_ERR_I2C;
+ return -EIO;
}
/**
@@ -179,7 +179,7 @@ s32 ixgbe_write_i2c_combined_generic_int(struct ixgbe_hw *hw, u8 addr,
csum = ~csum;
do {
if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
ixgbe_i2c_start(hw);
/* Device Address and write indication */
if (ixgbe_out_i2c_byte_ack(hw, addr))
@@ -215,7 +215,7 @@ fail:
hw_dbg(hw, "I2C byte write combined error.\n");
} while (retry < max_retry);
- return IXGBE_ERR_I2C;
+ return -EIO;
}
/**
@@ -262,8 +262,8 @@ static bool ixgbe_probe_phy(struct ixgbe_hw *hw, u16 phy_addr)
**/
s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
{
+ u32 status = -EFAULT;
u32 phy_addr;
- u32 status = IXGBE_ERR_PHY_ADDR_INVALID;
if (!hw->phy.phy_semaphore_mask) {
if (hw->bus.lan_id)
@@ -276,13 +276,12 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
return 0;
if (hw->phy.nw_mng_if_sel) {
- phy_addr = (hw->phy.nw_mng_if_sel &
- IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
- IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
+ phy_addr = FIELD_GET(IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD,
+ hw->phy.nw_mng_if_sel);
if (ixgbe_probe_phy(hw, phy_addr))
return 0;
else
- return IXGBE_ERR_PHY_ADDR_INVALID;
+ return -EFAULT;
}
for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
@@ -408,8 +407,7 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
return status;
/* Don't reset PHY if it's shut down due to overtemp. */
- if (!hw->phy.reset_if_overtemp &&
- (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
+ if (!hw->phy.reset_if_overtemp && hw->phy.ops.check_overtemp(hw))
return 0;
/* Blocked by MNG FW so bail */
@@ -457,7 +455,7 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
if (ctrl & MDIO_CTRL1_RESET) {
hw_dbg(hw, "PHY reset polling failed to complete.\n");
- return IXGBE_ERR_RESET_FAILED;
+ return -EIO;
}
return 0;
@@ -500,7 +498,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
hw_dbg(hw, "PHY address command did not complete.\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
/* Address cycle complete, setup and write the read
@@ -527,7 +525,7 @@ s32 ixgbe_read_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type,
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
hw_dbg(hw, "PHY read command didn't complete\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
/* Read operation is complete. Get the data
@@ -559,7 +557,7 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
phy_data);
hw->mac.ops.release_swfw_sync(hw, gssr);
} else {
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
return status;
@@ -604,7 +602,7 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
hw_dbg(hw, "PHY address cmd didn't complete\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
/*
@@ -632,7 +630,7 @@ s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr,
if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
hw_dbg(hw, "PHY write cmd didn't complete\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
return 0;
@@ -657,7 +655,7 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
phy_data);
hw->mac.ops.release_swfw_sync(hw, gssr);
} else {
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
return status;
@@ -1430,7 +1428,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
if ((phy_data & MDIO_CTRL1_RESET) != 0) {
hw_dbg(hw, "PHY reset did not complete.\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
/* Get init offsets */
@@ -1448,8 +1446,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
if (ret_val)
goto err_eeprom;
- control = (eword & IXGBE_CONTROL_MASK_NL) >>
- IXGBE_CONTROL_SHIFT_NL;
+ control = FIELD_GET(IXGBE_CONTROL_MASK_NL, eword);
edata = eword & IXGBE_DATA_MASK_NL;
switch (control) {
case IXGBE_DELAY_NL:
@@ -1487,12 +1484,12 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
hw_dbg(hw, "SOL\n");
} else {
hw_dbg(hw, "Bad control value\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
break;
default:
hw_dbg(hw, "Bad control type\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
}
@@ -1500,7 +1497,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
err_eeprom:
hw_err(hw, "eeprom read at offset %d failed\n", data_offset);
- return IXGBE_ERR_PHY;
+ return -EIO;
}
/**
@@ -1518,10 +1515,10 @@ s32 ixgbe_identify_module_generic(struct ixgbe_hw *hw)
return ixgbe_identify_qsfp_module_generic(hw);
default:
hw->phy.sfp_type = ixgbe_sfp_type_not_present;
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
}
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
}
/**
@@ -1546,7 +1543,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
hw->phy.sfp_type = ixgbe_sfp_type_not_present;
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
}
/* LAN ID is needed for sfp_type determination */
@@ -1561,7 +1558,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
if (identifier != IXGBE_SFF_IDENTIFIER_SFP) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_1GBE_COMP_CODES,
@@ -1752,7 +1749,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 ||
hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
/* Anything else 82598-based is supported */
@@ -1776,7 +1773,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
}
hw_dbg(hw, "SFP+ module not supported\n");
hw->phy.type = ixgbe_phy_sfp_unsupported;
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
return 0;
@@ -1786,7 +1783,7 @@ err_read_i2c_eeprom:
hw->phy.id = 0;
hw->phy.type = ixgbe_phy_unknown;
}
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
}
/**
@@ -1813,7 +1810,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber_qsfp) {
hw->phy.sfp_type = ixgbe_sfp_type_not_present;
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
}
/* LAN ID is needed for sfp_type determination */
@@ -1827,7 +1824,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
if (identifier != IXGBE_SFF_IDENTIFIER_QSFP_PLUS) {
hw->phy.type = ixgbe_phy_sfp_unsupported;
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
hw->phy.id = identifier;
@@ -1895,7 +1892,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
} else {
/* unsupported module type */
hw->phy.type = ixgbe_phy_sfp_unsupported;
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
}
@@ -1955,7 +1952,7 @@ static s32 ixgbe_identify_qsfp_module_generic(struct ixgbe_hw *hw)
}
hw_dbg(hw, "QSFP module not supported\n");
hw->phy.type = ixgbe_phy_sfp_unsupported;
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
return 0;
}
@@ -1966,7 +1963,7 @@ err_read_i2c_eeprom:
hw->phy.id = 0;
hw->phy.type = ixgbe_phy_unknown;
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
}
/**
@@ -1986,14 +1983,14 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
u16 sfp_type = hw->phy.sfp_type;
if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
(hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
/*
* Limiting active cables and 1G Phys must be initialized as
@@ -2014,11 +2011,11 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) {
hw_err(hw, "eeprom read at %d failed\n",
IXGBE_PHY_INIT_OFFSET_NL);
- return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
+ return -EIO;
}
if ((!*list_offset) || (*list_offset == 0xFFFF))
- return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
+ return -EIO;
/* Shift offset to first ID word */
(*list_offset)++;
@@ -2037,7 +2034,7 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
goto err_phy;
if ((!*data_offset) || (*data_offset == 0xFFFF)) {
hw_dbg(hw, "SFP+ module not supported\n");
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
} else {
break;
}
@@ -2050,14 +2047,14 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
if (sfp_id == IXGBE_PHY_INIT_END_NL) {
hw_dbg(hw, "No matching SFP+ module found\n");
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
return 0;
err_phy:
hw_err(hw, "eeprom read at offset %d failed\n", *list_offset);
- return IXGBE_ERR_PHY;
+ return -EIO;
}
/**
@@ -2152,7 +2149,7 @@ static s32 ixgbe_read_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
do {
if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
ixgbe_i2c_start(hw);
@@ -2268,7 +2265,7 @@ static s32 ixgbe_write_i2c_byte_generic_int(struct ixgbe_hw *hw, u8 byte_offset,
u32 swfw_mask = hw->phy.phy_semaphore_mask;
if (lock && hw->mac.ops.acquire_swfw_sync(hw, swfw_mask))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
do {
ixgbe_i2c_start(hw);
@@ -2510,7 +2507,7 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
if (ack == 1) {
hw_dbg(hw, "I2C ack was not received.\n");
- status = IXGBE_ERR_I2C;
+ status = -EIO;
}
ixgbe_lower_i2c_clk(hw, &i2cctl);
@@ -2582,7 +2579,7 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
udelay(IXGBE_I2C_T_LOW);
} else {
hw_dbg(hw, "I2C data was not set to %X\n", data);
- return IXGBE_ERR_I2C;
+ return -EIO;
}
return 0;
@@ -2678,7 +2675,7 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
*i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL(hw));
if (data != ixgbe_get_i2c_data(hw, i2cctl)) {
hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
- return IXGBE_ERR_I2C;
+ return -EIO;
}
return 0;
@@ -2748,22 +2745,24 @@ static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
* @hw: pointer to hardware structure
*
* Checks if the LASI temp alarm status was triggered due to overtemp
+ *
+ * Return true when an overtemp event detected, otherwise false.
**/
-s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
+bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw)
{
u16 phy_data = 0;
+ u32 status;
if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM)
- return 0;
+ return false;
/* Check that the LASI temp alarm status was triggered */
- hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
- MDIO_MMD_PMAPMD, &phy_data);
-
- if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM))
- return 0;
+ status = hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG,
+ MDIO_MMD_PMAPMD, &phy_data);
+ if (status)
+ return false;
- return IXGBE_ERR_OVERTEMP;
+ return !!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM);
}
/** ixgbe_set_copper_phy_power - Control power for copper phy
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
index 6544c4539c0d..ef72729d7c93 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
@@ -155,7 +155,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
u16 *list_offset,
u16 *data_offset);
-s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
+bool ixgbe_tn_check_overtemp(struct ixgbe_hw *hw);
s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
u8 dev_addr, u8 *data);
s32 ixgbe_read_i2c_byte_generic_unlocked(struct ixgbe_hw *hw, u8 byte_offset,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index 9cfdfa8a4355..7299a830f6e4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -363,8 +363,7 @@ int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
u32 *msgbuf, u32 vf)
{
- int entries = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK)
- >> IXGBE_VT_MSGINFO_SHIFT;
+ int entries = FIELD_GET(IXGBE_VT_MSGINFO_MASK, msgbuf[0]);
u16 *hash_list = (u16 *)&msgbuf[1];
struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
struct ixgbe_hw *hw = &adapter->hw;
@@ -969,7 +968,7 @@ static int ixgbe_set_vf_mac_addr(struct ixgbe_adapter *adapter,
static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
u32 *msgbuf, u32 vf)
{
- u32 add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
+ u32 add = FIELD_GET(IXGBE_VT_MSGINFO_MASK, msgbuf[0]);
u32 vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
u8 tcs = adapter->hw_tcs;
@@ -992,8 +991,7 @@ static int ixgbe_set_vf_macvlan_msg(struct ixgbe_adapter *adapter,
u32 *msgbuf, u32 vf)
{
u8 *new_mac = ((u8 *)(&msgbuf[1]));
- int index = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >>
- IXGBE_VT_MSGINFO_SHIFT;
+ int index = FIELD_GET(IXGBE_VT_MSGINFO_MASK, msgbuf[0]);
int err;
if (adapter->vfinfo[vf].pf_set_mac && !adapter->vfinfo[vf].trusted &&
@@ -1327,7 +1325,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
break;
default:
e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
- retval = IXGBE_ERR_MBX;
+ retval = -EIO;
break;
}
@@ -1849,5 +1847,6 @@ int ixgbe_ndo_get_vf_config(struct net_device *netdev,
ivi->spoofchk = adapter->vfinfo[vf].spoofchk_enabled;
ivi->rss_query_en = adapter->vfinfo[vf].rss_query_enabled;
ivi->trusted = adapter->vfinfo[vf].trusted;
+ ivi->linkstate = adapter->vfinfo[vf].link_state;
return 0;
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index 2b00db92b08f..61b9774b3d31 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -3509,10 +3509,10 @@ struct ixgbe_phy_operations {
s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *);
s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *);
s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8);
- s32 (*check_overtemp)(struct ixgbe_hw *);
+ bool (*check_overtemp)(struct ixgbe_hw *);
s32 (*set_phy_power)(struct ixgbe_hw *, bool on);
s32 (*enter_lplu)(struct ixgbe_hw *);
- s32 (*handle_lasi)(struct ixgbe_hw *hw);
+ s32 (*handle_lasi)(struct ixgbe_hw *hw, bool *);
s32 (*read_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr,
u8 *value);
s32 (*write_i2c_byte_unlocked)(struct ixgbe_hw *, u8 offset, u8 addr,
@@ -3665,45 +3665,6 @@ struct ixgbe_info {
const u32 *mvals;
};
-
-/* Error Codes */
-#define IXGBE_ERR_EEPROM -1
-#define IXGBE_ERR_EEPROM_CHECKSUM -2
-#define IXGBE_ERR_PHY -3
-#define IXGBE_ERR_CONFIG -4
-#define IXGBE_ERR_PARAM -5
-#define IXGBE_ERR_MAC_TYPE -6
-#define IXGBE_ERR_UNKNOWN_PHY -7
-#define IXGBE_ERR_LINK_SETUP -8
-#define IXGBE_ERR_ADAPTER_STOPPED -9
-#define IXGBE_ERR_INVALID_MAC_ADDR -10
-#define IXGBE_ERR_DEVICE_NOT_SUPPORTED -11
-#define IXGBE_ERR_PRIMARY_REQUESTS_PENDING -12
-#define IXGBE_ERR_INVALID_LINK_SETTINGS -13
-#define IXGBE_ERR_AUTONEG_NOT_COMPLETE -14
-#define IXGBE_ERR_RESET_FAILED -15
-#define IXGBE_ERR_SWFW_SYNC -16
-#define IXGBE_ERR_PHY_ADDR_INVALID -17
-#define IXGBE_ERR_I2C -18
-#define IXGBE_ERR_SFP_NOT_SUPPORTED -19
-#define IXGBE_ERR_SFP_NOT_PRESENT -20
-#define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT -21
-#define IXGBE_ERR_NO_SAN_ADDR_PTR -22
-#define IXGBE_ERR_FDIR_REINIT_FAILED -23
-#define IXGBE_ERR_EEPROM_VERSION -24
-#define IXGBE_ERR_NO_SPACE -25
-#define IXGBE_ERR_OVERTEMP -26
-#define IXGBE_ERR_FC_NOT_NEGOTIATED -27
-#define IXGBE_ERR_FC_NOT_SUPPORTED -28
-#define IXGBE_ERR_SFP_SETUP_NOT_COMPLETE -30
-#define IXGBE_ERR_PBA_SECTION -31
-#define IXGBE_ERR_INVALID_ARGUMENT -32
-#define IXGBE_ERR_HOST_INTERFACE_COMMAND -33
-#define IXGBE_ERR_FDIR_CMD_INCOMPLETE -38
-#define IXGBE_ERR_FW_RESP_INVALID -39
-#define IXGBE_ERR_TOKEN_RETRY -40
-#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF
-
#define IXGBE_FUSES0_GROUP(_i) (0x11158 + ((_i) * 4))
#define IXGBE_FUSES0_300MHZ BIT(5)
#define IXGBE_FUSES0_REV_MASK (3u << 6)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index d5cfb51ff648..57a912e4653f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -84,7 +84,7 @@ mac_reset_top:
status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
if (status) {
hw_dbg(hw, "semaphore failed with %d", status);
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
ctrl = IXGBE_CTRL_RST;
@@ -103,7 +103,7 @@ mac_reset_top:
}
if (ctrl & IXGBE_CTRL_RST_MASK) {
- status = IXGBE_ERR_RESET_FAILED;
+ status = -EIO;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
msleep(100);
@@ -187,16 +187,16 @@ s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw)
s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw)
{
struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
- u32 eec;
- u16 eeprom_size;
if (eeprom->type == ixgbe_eeprom_uninitialized) {
+ u16 eeprom_size;
+ u32 eec;
+
eeprom->semaphore_delay = 10;
eeprom->type = ixgbe_flash;
eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
- eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
- IXGBE_EEC_SIZE_SHIFT);
+ eeprom_size = FIELD_GET(IXGBE_EEC_SIZE, eec);
eeprom->word_size = BIT(eeprom_size +
IXGBE_EEPROM_WORD_SIZE_SHIFT);
@@ -220,7 +220,7 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
s32 status;
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = ixgbe_read_eerd_generic(hw, offset, data);
@@ -243,7 +243,7 @@ static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw,
s32 status;
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = ixgbe_read_eerd_buffer_generic(hw, offset, words, data);
@@ -264,7 +264,7 @@ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data)
s32 status;
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = ixgbe_write_eewr_generic(hw, offset, data);
@@ -287,7 +287,7 @@ static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw,
s32 status;
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = ixgbe_write_eewr_buffer_generic(hw, offset, words, data);
@@ -324,7 +324,7 @@ static s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
for (i = 0; i < checksum_last_word; i++) {
if (ixgbe_read_eerd_generic(hw, i, &word)) {
hw_dbg(hw, "EEPROM read failed\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
checksum += word;
}
@@ -349,7 +349,7 @@ static s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
if (ixgbe_read_eerd_generic(hw, pointer, &length)) {
hw_dbg(hw, "EEPROM read failed\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/* Skip pointer section if length is invalid. */
@@ -360,7 +360,7 @@ static s32 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
for (j = pointer + 1; j <= pointer + length; j++) {
if (ixgbe_read_eerd_generic(hw, j, &word)) {
hw_dbg(hw, "EEPROM read failed\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
checksum += word;
}
@@ -397,7 +397,7 @@ static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw,
}
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = hw->eeprom.ops.calc_checksum(hw);
if (status < 0)
@@ -418,7 +418,7 @@ static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw,
*/
if (read_checksum != checksum) {
hw_dbg(hw, "Invalid EEPROM checksum");
- status = IXGBE_ERR_EEPROM_CHECKSUM;
+ status = -EIO;
}
/* If the user cares, return the calculated checksum */
@@ -455,7 +455,7 @@ static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw)
}
if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = hw->eeprom.ops.calc_checksum(hw);
if (status < 0)
@@ -490,7 +490,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw)
s32 status;
status = ixgbe_poll_flash_update_done_X540(hw);
- if (status == IXGBE_ERR_EEPROM) {
+ if (status == -EIO) {
hw_dbg(hw, "Flash update time out\n");
return status;
}
@@ -540,7 +540,7 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw)
return 0;
udelay(5);
}
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/**
@@ -575,7 +575,7 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
* SW_FW_SYNC bits (not just NVM)
*/
if (ixgbe_get_swfw_sync_semaphore(hw))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (!(swfw_sync & (fwmask | swmask | hwmask))) {
@@ -599,7 +599,7 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
* bits in the SW_FW_SYNC register.
*/
if (ixgbe_get_swfw_sync_semaphore(hw))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
swfw_sync = IXGBE_READ_REG(hw, IXGBE_SWFW_SYNC(hw));
if (swfw_sync & (fwmask | hwmask)) {
swfw_sync |= swmask;
@@ -622,11 +622,11 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u32 mask)
rmask |= IXGBE_GSSR_I2C_MASK;
ixgbe_release_swfw_sync_X540(hw, rmask);
ixgbe_release_swfw_sync_semaphore(hw);
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
ixgbe_release_swfw_sync_semaphore(hw);
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
/**
@@ -680,7 +680,7 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw)
if (i == timeout) {
hw_dbg(hw,
"Software semaphore SMBI between device drivers not granted.\n");
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/* Now get the semaphore between SW/FW through the REGSMP bit */
@@ -697,7 +697,7 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw)
*/
hw_dbg(hw, "REGSMP Software NVM semaphore not granted\n");
ixgbe_release_swfw_sync_semaphore(hw);
- return IXGBE_ERR_EEPROM;
+ return -EIO;
}
/**
@@ -768,7 +768,7 @@ s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index)
bool link_up;
if (index > 3)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* Link should be up in order for the blink bit in the LED control
* register to work. Force link and speed in the MAC if link is down.
@@ -804,7 +804,7 @@ s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index)
u32 ledctl_reg;
if (index > 3)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* Restore the LED to its default value. */
ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index aa4bf6c9a2f7..c1adc94a5a65 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -206,13 +206,13 @@ static s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw)
}
if (retry == IXGBE_CS4227_RETRIES) {
hw_err(hw, "CS4227 reset did not complete\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value);
if (status || !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) {
hw_err(hw, "CS4227 EEPROM did not load successfully\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
return 0;
@@ -350,13 +350,13 @@ static s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw)
static s32 ixgbe_read_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u16 *phy_data)
{
- return IXGBE_NOT_IMPLEMENTED;
+ return -EOPNOTSUPP;
}
static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
u32 device_type, u16 phy_data)
{
- return IXGBE_NOT_IMPLEMENTED;
+ return -EOPNOTSUPP;
}
/**
@@ -463,7 +463,7 @@ s32 ixgbe_fw_phy_activity(struct ixgbe_hw *hw, u16 activity,
--retries;
} while (retries > 0);
- return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ return -EIO;
}
static const struct {
@@ -511,7 +511,7 @@ static s32 ixgbe_get_phy_id_fw(struct ixgbe_hw *hw)
hw->phy.id |= phy_id_lo & IXGBE_PHY_REVISION_MASK;
hw->phy.revision = phy_id_lo & ~IXGBE_PHY_REVISION_MASK;
if (!hw->phy.id || hw->phy.id == IXGBE_PHY_REVISION_MASK)
- return IXGBE_ERR_PHY_ADDR_INVALID;
+ return -EFAULT;
hw->phy.autoneg_advertised = hw->phy.speeds_supported;
hw->phy.eee_speeds_supported = IXGBE_LINK_SPEED_100_FULL |
@@ -568,7 +568,7 @@ static s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw)
if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
hw_err(hw, "rx_pause not valid in strict IEEE mode\n");
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
switch (hw->fc.requested_mode) {
@@ -600,8 +600,10 @@ static s32 ixgbe_setup_fw_link(struct ixgbe_hw *hw)
rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_SETUP_LINK, &setup);
if (rc)
return rc;
+
if (setup[0] == FW_PHY_ACT_SETUP_LINK_RSP_DOWN)
- return IXGBE_ERR_OVERTEMP;
+ return -EIO;
+
return 0;
}
@@ -628,16 +630,16 @@ static s32 ixgbe_fc_autoneg_fw(struct ixgbe_hw *hw)
static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
{
struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
- u32 eec;
- u16 eeprom_size;
if (eeprom->type == ixgbe_eeprom_uninitialized) {
+ u16 eeprom_size;
+ u32 eec;
+
eeprom->semaphore_delay = 10;
eeprom->type = ixgbe_flash;
eec = IXGBE_READ_REG(hw, IXGBE_EEC(hw));
- eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
- IXGBE_EEC_SIZE_SHIFT);
+ eeprom_size = FIELD_GET(IXGBE_EEC_SIZE, eec);
eeprom->word_size = BIT(eeprom_size +
IXGBE_EEPROM_WORD_SIZE_SHIFT);
@@ -675,7 +677,7 @@ static s32 ixgbe_iosf_wait(struct ixgbe_hw *hw, u32 *ctrl)
*ctrl = command;
if (i == IXGBE_MDIO_COMMAND_TIMEOUT) {
hw_dbg(hw, "IOSF wait timed out\n");
- return IXGBE_ERR_PHY;
+ return -EIO;
}
return 0;
@@ -712,10 +714,10 @@ static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
ret = ixgbe_iosf_wait(hw, &command);
if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
- error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
- IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
+ error = FIELD_GET(IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK, command);
hw_dbg(hw, "Failed to read, error %x\n", error);
- return IXGBE_ERR_PHY;
+ ret = -EIO;
+ goto out;
}
if (!ret)
@@ -750,9 +752,9 @@ static s32 ixgbe_get_phy_token(struct ixgbe_hw *hw)
if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
return 0;
if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY)
- return IXGBE_ERR_FW_RESP_INVALID;
+ return -EIO;
- return IXGBE_ERR_TOKEN_RETRY;
+ return -EAGAIN;
}
/**
@@ -778,7 +780,7 @@ static s32 ixgbe_put_phy_token(struct ixgbe_hw *hw)
return status;
if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
return 0;
- return IXGBE_ERR_FW_RESP_INVALID;
+ return -EIO;
}
/**
@@ -942,7 +944,7 @@ static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
local_buffer = buf;
} else {
if (buffer_size < ptr)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
local_buffer = &buffer[ptr];
}
@@ -960,7 +962,7 @@ static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
}
if (buffer && ((u32)start + (u32)length > buffer_size))
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
for (i = start; length; i++, length--) {
if (i == bufsz && !buffer) {
@@ -1012,7 +1014,7 @@ static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer,
local_buffer = eeprom_ptrs;
} else {
if (buffer_size < IXGBE_EEPROM_LAST_WORD)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
local_buffer = buffer;
}
@@ -1148,7 +1150,7 @@ static s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw,
* calculated checksum
*/
if (read_checksum != checksum) {
- status = IXGBE_ERR_EEPROM_CHECKSUM;
+ status = -EIO;
hw_dbg(hw, "Invalid EEPROM checksum");
}
@@ -1203,7 +1205,7 @@ static s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
} else {
hw_dbg(hw, "write ee hostif failed to get semaphore");
- status = IXGBE_ERR_SWFW_SYNC;
+ status = -EBUSY;
}
return status;
@@ -1412,10 +1414,9 @@ static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
ret = ixgbe_iosf_wait(hw, &command);
if ((command & IXGBE_SB_IOSF_CTRL_RESP_STAT_MASK) != 0) {
- error = (command & IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK) >>
- IXGBE_SB_IOSF_CTRL_CMPL_ERR_SHIFT;
+ error = FIELD_GET(IXGBE_SB_IOSF_CTRL_CMPL_ERR_MASK, command);
hw_dbg(hw, "Failed to write, error %x\n", error);
- return IXGBE_ERR_PHY;
+ return -EIO;
}
out:
@@ -1558,7 +1559,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
/* iXFI is only supported with X552 */
if (mac->type != ixgbe_mac_X550EM_x)
- return IXGBE_ERR_LINK_SETUP;
+ return -EIO;
/* Disable AN and force speed to 10G Serial. */
status = ixgbe_read_iosf_sb_reg_x550(hw,
@@ -1580,7 +1581,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
break;
default:
/* Other link speeds are not supported by internal KR PHY. */
- return IXGBE_ERR_LINK_SETUP;
+ return -EINVAL;
}
status = ixgbe_write_iosf_sb_reg_x550(hw,
@@ -1611,7 +1612,7 @@ static s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear)
{
switch (hw->phy.sfp_type) {
case ixgbe_sfp_type_not_present:
- return IXGBE_ERR_SFP_NOT_PRESENT;
+ return -ENOENT;
case ixgbe_sfp_type_da_cu_core0:
case ixgbe_sfp_type_da_cu_core1:
*linear = true;
@@ -1630,7 +1631,7 @@ static s32 ixgbe_supported_sfp_modules_X550em(struct ixgbe_hw *hw, bool *linear)
case ixgbe_sfp_type_1g_cu_core0:
case ixgbe_sfp_type_1g_cu_core1:
default:
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
+ return -EOPNOTSUPP;
}
return 0;
@@ -1660,7 +1661,7 @@ ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw,
* there is no reason to configure CS4227 and SFP not present error is
* not accepted in the setup MAC link flow.
*/
- if (status == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (status == -ENOENT)
return 0;
if (status)
@@ -1718,7 +1719,7 @@ static s32 ixgbe_setup_sfi_x550a(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
break;
default:
/* Other link speeds are not supported by internal PHY. */
- return IXGBE_ERR_LINK_SETUP;
+ return -EINVAL;
}
(void)mac->ops.write_iosf_sb_reg(hw,
@@ -1803,7 +1804,7 @@ ixgbe_setup_mac_link_sfp_n(struct ixgbe_hw *hw, ixgbe_link_speed speed,
/* If no SFP module present, then return success. Return success since
* SFP not present error is not excepted in the setup MAC link flow.
*/
- if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (ret_val == -ENOENT)
return 0;
if (ret_val)
@@ -1853,7 +1854,7 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed,
/* If no SFP module present, then return success. Return success since
* SFP not present error is not excepted in the setup MAC link flow.
*/
- if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT)
+ if (ret_val == -ENOENT)
return 0;
if (ret_val)
@@ -1863,7 +1864,7 @@ ixgbe_setup_mac_link_sfp_x550a(struct ixgbe_hw *hw, ixgbe_link_speed speed,
ixgbe_setup_kr_speed_x550em(hw, speed);
if (hw->phy.mdio.prtad == MDIO_PRTAD_NONE)
- return IXGBE_ERR_PHY_ADDR_INVALID;
+ return -EFAULT;
/* Get external PHY SKU id */
ret_val = hw->phy.ops.read_reg(hw, IXGBE_CS4227_EFUSE_PDF_SKU,
@@ -1962,7 +1963,7 @@ static s32 ixgbe_check_link_t_X550em(struct ixgbe_hw *hw,
u16 i, autoneg_status;
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
- return IXGBE_ERR_CONFIG;
+ return -EIO;
status = ixgbe_check_mac_link_generic(hw, speed, link_up,
link_up_wait_to_complete);
@@ -2145,9 +2146,9 @@ static s32 ixgbe_setup_sgmii_fw(struct ixgbe_hw *hw, ixgbe_link_speed speed,
*/
static void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw)
{
- s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 };
ixgbe_link_speed speed;
+ s32 status = -EIO;
bool link_up;
/* AN should have completed when the cable was plugged in.
@@ -2165,7 +2166,7 @@ static void ixgbe_fc_autoneg_sgmii_x550em_a(struct ixgbe_hw *hw)
/* Check if auto-negotiation has completed */
status = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &info);
if (status || !(info[0] & FW_PHY_ACT_GET_LINK_INFO_AN_COMPLETE)) {
- status = IXGBE_ERR_FC_NOT_NEGOTIATED;
+ status = -EIO;
goto out;
}
@@ -2369,18 +2370,18 @@ static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
* @hw: pointer to hardware structure
* @lsc: pointer to boolean flag which indicates whether external Base T
* PHY interrupt is lsc
+ * @is_overtemp: indicate whether an overtemp event encountered
*
* Determime if external Base T PHY interrupt cause is high temperature
* failure alarm or link status change.
- *
- * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
- * failure alarm, else return PHY access status.
**/
-static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
+static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc,
+ bool *is_overtemp)
{
u32 status;
u16 reg;
+ *is_overtemp = false;
*lsc = false;
/* Vendor alarm triggered */
@@ -2412,7 +2413,8 @@ static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
if (reg & IXGBE_MDIO_GLOBAL_ALM_1_HI_TMP_FAIL) {
/* power down the PHY in case the PHY FW didn't already */
ixgbe_set_copper_phy_power(hw, false);
- return IXGBE_ERR_OVERTEMP;
+ *is_overtemp = true;
+ return -EIO;
}
if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) {
/* device fault alarm triggered */
@@ -2426,7 +2428,8 @@ static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
if (reg == IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP) {
/* power down the PHY in case the PHY FW didn't */
ixgbe_set_copper_phy_power(hw, false);
- return IXGBE_ERR_OVERTEMP;
+ *is_overtemp = true;
+ return -EIO;
}
}
@@ -2462,12 +2465,12 @@ static s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc)
**/
static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
{
+ bool lsc, overtemp;
u32 status;
u16 reg;
- bool lsc;
/* Clear interrupt flags */
- status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc, &overtemp);
/* Enable link status change alarm */
@@ -2546,21 +2549,20 @@ static s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw)
/**
* ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt
* @hw: pointer to hardware structure
+ * @is_overtemp: indicate whether an overtemp event encountered
*
* Handle external Base T PHY interrupt. If high temperature
* failure alarm then return error, else if link status change
* then setup internal/external PHY link
- *
- * Return IXGBE_ERR_OVERTEMP if interrupt is high temperature
- * failure alarm, else return PHY access status.
**/
-static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_handle_lasi_ext_t_x550em(struct ixgbe_hw *hw,
+ bool *is_overtemp)
{
struct ixgbe_phy_info *phy = &hw->phy;
bool lsc;
u32 status;
- status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc);
+ status = ixgbe_get_lasi_ext_t_x550em(hw, &lsc, is_overtemp);
if (status)
return status;
@@ -2692,7 +2694,7 @@ static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
u16 speed;
if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper)
- return IXGBE_ERR_CONFIG;
+ return -EIO;
if (!(hw->mac.type == ixgbe_mac_X550EM_x &&
!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE))) {
@@ -2735,7 +2737,7 @@ static s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw)
break;
default:
/* Internal PHY does not support anything else */
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
return ixgbe_setup_ixfi_x550em(hw, &force_speed);
@@ -2767,7 +2769,7 @@ static s32 ixgbe_led_on_t_x550em(struct ixgbe_hw *hw, u32 led_idx)
u16 phy_data;
if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* To turn on the LED, set mode to ON. */
hw->phy.ops.read_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
@@ -2789,7 +2791,7 @@ static s32 ixgbe_led_off_t_x550em(struct ixgbe_hw *hw, u32 led_idx)
u16 phy_data;
if (led_idx >= IXGBE_X557_MAX_LED_INDEX)
- return IXGBE_ERR_PARAM;
+ return -EINVAL;
/* To turn on the LED, set mode to ON. */
hw->phy.ops.read_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx,
@@ -2813,8 +2815,9 @@ static s32 ixgbe_led_off_t_x550em(struct ixgbe_hw *hw, u32 led_idx)
*
* Sends driver version number to firmware through the manageability
* block. On success return 0
- * else returns IXGBE_ERR_SWFW_SYNC when encountering an error acquiring
- * semaphore or IXGBE_ERR_HOST_INTERFACE_COMMAND when command fails.
+ * else returns -EBUSY when encountering an error acquiring
+ * semaphore, -EIO when command fails or -ENIVAL when incorrect
+ * params passed.
**/
static s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
u8 build, u8 sub, u16 len,
@@ -2825,7 +2828,7 @@ static s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
int i;
if (!len || !driver_ver || (len > sizeof(fw_cmd.driver_string)))
- return IXGBE_ERR_INVALID_ARGUMENT;
+ return -EINVAL;
fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO;
fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN + len;
@@ -2850,7 +2853,7 @@ static s32 ixgbe_set_fw_drv_ver_x550(struct ixgbe_hw *hw, u8 maj, u8 min,
if (fw_cmd.hdr.cmd_or_resp.ret_status !=
FW_CEM_RESP_STATUS_SUCCESS)
- return IXGBE_ERR_HOST_INTERFACE_COMMAND;
+ return -EIO;
return 0;
}
@@ -2907,7 +2910,7 @@ static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *hw)
/* Validate the requested mode */
if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
hw_err(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
/* 10gig parts do not have a word in the EEPROM to determine the
@@ -2942,7 +2945,7 @@ static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *hw)
break;
default:
hw_err(hw, "Flow control param set incorrectly\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
switch (hw->device_id) {
@@ -2986,8 +2989,8 @@ static s32 ixgbe_setup_fc_x550em(struct ixgbe_hw *hw)
static void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw)
{
u32 link_s1, lp_an_page_low, an_cntl_1;
- s32 status = IXGBE_ERR_FC_NOT_NEGOTIATED;
ixgbe_link_speed speed;
+ s32 status = -EIO;
bool link_up;
/* AN should have completed when the cable was plugged in.
@@ -3013,7 +3016,7 @@ static void ixgbe_fc_autoneg_backplane_x550em_a(struct ixgbe_hw *hw)
if (status || (link_s1 & IXGBE_KRM_LINK_S1_MAC_AN_COMPLETE) == 0) {
hw_dbg(hw, "Auto-Negotiation did not complete\n");
- status = IXGBE_ERR_FC_NOT_NEGOTIATED;
+ status = -EIO;
goto out;
}
@@ -3187,21 +3190,23 @@ static s32 ixgbe_reset_phy_fw(struct ixgbe_hw *hw)
/**
* ixgbe_check_overtemp_fw - Check firmware-controlled PHYs for overtemp
* @hw: pointer to hardware structure
+ *
+ * Return true when an overtemp event detected, otherwise false.
*/
-static s32 ixgbe_check_overtemp_fw(struct ixgbe_hw *hw)
+static bool ixgbe_check_overtemp_fw(struct ixgbe_hw *hw)
{
u32 store[FW_PHY_ACT_DATA_COUNT] = { 0 };
s32 rc;
rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_GET_LINK_INFO, &store);
if (rc)
- return rc;
+ return false;
if (store[0] & FW_PHY_ACT_GET_LINK_INFO_TEMP) {
ixgbe_shutdown_fw_phy(hw);
- return IXGBE_ERR_OVERTEMP;
+ return true;
}
- return 0;
+ return false;
}
/**
@@ -3222,9 +3227,8 @@ static void ixgbe_read_mng_if_sel_x550em(struct ixgbe_hw *hw)
*/
if (hw->mac.type == ixgbe_mac_x550em_a &&
hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_MDIO_ACT) {
- hw->phy.mdio.prtad = (hw->phy.nw_mng_if_sel &
- IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD) >>
- IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD_SHIFT;
+ hw->phy.mdio.prtad = FIELD_GET(IXGBE_NW_MNG_IF_SEL_MDIO_PHY_ADD,
+ hw->phy.nw_mng_if_sel);
}
}
@@ -3251,8 +3255,7 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
/* Identify the PHY or SFP module */
ret_val = phy->ops.identify(hw);
- if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED ||
- ret_val == IXGBE_ERR_PHY_ADDR_INVALID)
+ if (ret_val == -EOPNOTSUPP || ret_val == -EFAULT)
return ret_val;
/* Setup function pointers based on detected hardware */
@@ -3460,8 +3463,7 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
/* PHY ops must be identified and initialized prior to reset */
status = hw->phy.ops.init(hw);
- if (status == IXGBE_ERR_SFP_NOT_SUPPORTED ||
- status == IXGBE_ERR_PHY_ADDR_INVALID)
+ if (status == -EOPNOTSUPP || status == -EFAULT)
return status;
/* start the external PHY */
@@ -3477,7 +3479,7 @@ static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
hw->phy.sfp_setup_needed = false;
}
- if (status == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ if (status == -EOPNOTSUPP)
return status;
/* Reset PHY */
@@ -3501,7 +3503,7 @@ mac_reset_top:
status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask);
if (status) {
hw_dbg(hw, "semaphore failed with %d", status);
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
}
ctrl |= IXGBE_READ_REG(hw, IXGBE_CTRL);
@@ -3519,7 +3521,7 @@ mac_reset_top:
}
if (ctrl & IXGBE_CTRL_RST_MASK) {
- status = IXGBE_ERR_RESET_FAILED;
+ status = -EIO;
hw_dbg(hw, "Reset polling failed to complete.\n");
}
@@ -3615,7 +3617,7 @@ static s32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw)
/* Validate the requested mode */
if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
hw_err(hw, "ixgbe_fc_rx_pause not valid in strict IEEE mode\n");
- return IXGBE_ERR_INVALID_LINK_SETTINGS;
+ return -EINVAL;
}
if (hw->fc.requested_mode == ixgbe_fc_default)
@@ -3672,7 +3674,7 @@ static s32 ixgbe_setup_fc_backplane_x550em_a(struct ixgbe_hw *hw)
break;
default:
hw_err(hw, "Flow control param set incorrectly\n");
- return IXGBE_ERR_CONFIG;
+ return -EIO;
}
status = hw->mac.ops.write_iosf_sb_reg(hw,
@@ -3768,7 +3770,7 @@ static s32 ixgbe_acquire_swfw_sync_x550em_a(struct ixgbe_hw *hw, u32 mask)
return 0;
if (hmask)
ixgbe_release_swfw_sync_X540(hw, hmask);
- if (status != IXGBE_ERR_TOKEN_RETRY)
+ if (status != -EAGAIN)
return status;
msleep(FW_PHY_TOKEN_DELAY);
}
@@ -3812,7 +3814,7 @@ static s32 ixgbe_read_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
s32 status;
if (hw->mac.ops.acquire_swfw_sync(hw, mask))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = hw->phy.ops.read_reg_mdi(hw, reg_addr, device_type, phy_data);
@@ -3838,7 +3840,7 @@ static s32 ixgbe_write_phy_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
s32 status;
if (hw->mac.ops.acquire_swfw_sync(hw, mask))
- return IXGBE_ERR_SWFW_SYNC;
+ return -EBUSY;
status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, phy_data);
hw->mac.ops.release_swfw_sync(hw, mask);
diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
index 296915414a7c..7ac53171b041 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c
@@ -897,40 +897,41 @@ static u32 ixgbevf_get_rxfh_key_size(struct net_device *netdev)
return IXGBEVF_RSS_HASH_KEY_SIZE;
}
-static int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int ixgbevf_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
int err = 0;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) {
- if (key)
- memcpy(key, adapter->rss_key,
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key,
ixgbevf_get_rxfh_key_size(netdev));
- if (indir) {
+ if (rxfh->indir) {
int i;
for (i = 0; i < IXGBEVF_X550_VFRETA_SIZE; i++)
- indir[i] = adapter->rss_indir_tbl[i];
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
}
} else {
/* If neither indirection table nor hash key was requested
* - just return a success avoiding taking any locks.
*/
- if (!indir && !key)
+ if (!rxfh->indir && !rxfh->key)
return 0;
spin_lock_bh(&adapter->mbx_lock);
- if (indir)
- err = ixgbevf_get_reta_locked(&adapter->hw, indir,
+ if (rxfh->indir)
+ err = ixgbevf_get_reta_locked(&adapter->hw,
+ rxfh->indir,
adapter->num_rx_queues);
- if (!err && key)
- err = ixgbevf_get_rss_key_locked(&adapter->hw, key);
+ if (!err && rxfh->key)
+ err = ixgbevf_get_rss_key_locked(&adapter->hw,
+ rxfh->key);
spin_unlock_bh(&adapter->mbx_lock);
}
diff --git a/drivers/net/ethernet/litex/litex_liteeth.c b/drivers/net/ethernet/litex/litex_liteeth.c
index 5182fe737c37..ff54fbe41bcc 100644
--- a/drivers/net/ethernet/litex/litex_liteeth.c
+++ b/drivers/net/ethernet/litex/litex_liteeth.c
@@ -318,4 +318,5 @@ static struct platform_driver liteeth_driver = {
module_platform_driver(liteeth_driver);
MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
+MODULE_DESCRIPTION("LiteX Liteeth Ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c
index 89f26402f8fb..9190eff6c0bb 100644
--- a/drivers/net/ethernet/marvell/mvmdio.c
+++ b/drivers/net/ethernet/marvell/mvmdio.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -52,17 +53,19 @@
#define MVMDIO_XSMI_BUSY BIT(30)
#define MVMDIO_XSMI_ADDR_REG 0x8
+#define MVMDIO_XSMI_CFG_REG 0xc
+#define MVMDIO_XSMI_CLKDIV_MASK 0x3
+#define MVMDIO_XSMI_CLKDIV_256 0x0
+#define MVMDIO_XSMI_CLKDIV_64 0x1
+#define MVMDIO_XSMI_CLKDIV_32 0x2
+#define MVMDIO_XSMI_CLKDIV_8 0x3
+
/*
* SMI Timeout measurements:
* - Kirkwood 88F6281 (Globalscale Dreamplug): 45us to 95us (Interrupt)
* - Armada 370 (Globalscale Mirabox): 41us to 43us (Polled)
*/
#define MVMDIO_SMI_TIMEOUT 1000 /* 1000us = 1ms */
-#define MVMDIO_SMI_POLL_INTERVAL_MIN 45
-#define MVMDIO_SMI_POLL_INTERVAL_MAX 55
-
-#define MVMDIO_XSMI_POLL_INTERVAL_MIN 150
-#define MVMDIO_XSMI_POLL_INTERVAL_MAX 160
struct orion_mdio_dev {
void __iomem *regs;
@@ -84,8 +87,6 @@ enum orion_mdio_bus_type {
struct orion_mdio_ops {
int (*is_done)(struct orion_mdio_dev *);
- unsigned int poll_interval_min;
- unsigned int poll_interval_max;
};
/* Wait for the SMI unit to be ready for another operation
@@ -94,34 +95,23 @@ static int orion_mdio_wait_ready(const struct orion_mdio_ops *ops,
struct mii_bus *bus)
{
struct orion_mdio_dev *dev = bus->priv;
- unsigned long timeout = usecs_to_jiffies(MVMDIO_SMI_TIMEOUT);
- unsigned long end = jiffies + timeout;
- int timedout = 0;
+ unsigned long timeout;
+ int done;
- while (1) {
- if (ops->is_done(dev))
+ if (dev->err_interrupt <= 0) {
+ if (!read_poll_timeout_atomic(ops->is_done, done, done, 2,
+ MVMDIO_SMI_TIMEOUT, false, dev))
+ return 0;
+ } else {
+ /* wait_event_timeout does not guarantee a delay of at
+ * least one whole jiffie, so timeout must be no less
+ * than two.
+ */
+ timeout = max(usecs_to_jiffies(MVMDIO_SMI_TIMEOUT), 2);
+
+ if (wait_event_timeout(dev->smi_busy_wait,
+ ops->is_done(dev), timeout))
return 0;
- else if (timedout)
- break;
-
- if (dev->err_interrupt <= 0) {
- usleep_range(ops->poll_interval_min,
- ops->poll_interval_max);
-
- if (time_is_before_jiffies(end))
- ++timedout;
- } else {
- /* wait_event_timeout does not guarantee a delay of at
- * least one whole jiffie, so timeout must be no less
- * than two.
- */
- if (timeout < 2)
- timeout = 2;
- wait_event_timeout(dev->smi_busy_wait,
- ops->is_done(dev), timeout);
-
- ++timedout;
- }
}
dev_err(bus->parent, "Timeout: SMI busy for too long\n");
@@ -135,8 +125,6 @@ static int orion_mdio_smi_is_done(struct orion_mdio_dev *dev)
static const struct orion_mdio_ops orion_mdio_smi_ops = {
.is_done = orion_mdio_smi_is_done,
- .poll_interval_min = MVMDIO_SMI_POLL_INTERVAL_MIN,
- .poll_interval_max = MVMDIO_SMI_POLL_INTERVAL_MAX,
};
static int orion_mdio_smi_read(struct mii_bus *bus, int mii_id,
@@ -194,8 +182,6 @@ static int orion_mdio_xsmi_is_done(struct orion_mdio_dev *dev)
static const struct orion_mdio_ops orion_mdio_xsmi_ops = {
.is_done = orion_mdio_xsmi_is_done,
- .poll_interval_min = MVMDIO_XSMI_POLL_INTERVAL_MIN,
- .poll_interval_max = MVMDIO_XSMI_POLL_INTERVAL_MAX,
};
static int orion_mdio_xsmi_read_c45(struct mii_bus *bus, int mii_id,
@@ -246,6 +232,40 @@ static int orion_mdio_xsmi_write_c45(struct mii_bus *bus, int mii_id,
return 0;
}
+static void orion_mdio_xsmi_set_mdc_freq(struct mii_bus *bus)
+{
+ struct orion_mdio_dev *dev = bus->priv;
+ struct clk *mg_core;
+ u32 div, freq, cfg;
+
+ if (device_property_read_u32(bus->parent, "clock-frequency", &freq))
+ return;
+
+ mg_core = of_clk_get_by_name(bus->parent->of_node, "mg_core_clk");
+ if (IS_ERR(mg_core)) {
+ dev_err(bus->parent,
+ "MG core clock unknown, not changing MDC frequency");
+ return;
+ }
+
+ div = clk_get_rate(mg_core) / (freq + 1) + 1;
+ clk_put(mg_core);
+
+ if (div <= 8)
+ div = MVMDIO_XSMI_CLKDIV_8;
+ else if (div <= 32)
+ div = MVMDIO_XSMI_CLKDIV_32;
+ else if (div <= 64)
+ div = MVMDIO_XSMI_CLKDIV_64;
+ else
+ div = MVMDIO_XSMI_CLKDIV_256;
+
+ cfg = readl(dev->regs + MVMDIO_XSMI_CFG_REG);
+ cfg &= ~MVMDIO_XSMI_CLKDIV_MASK;
+ cfg |= div;
+ writel(cfg, dev->regs + MVMDIO_XSMI_CFG_REG);
+}
+
static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
{
struct orion_mdio_dev *dev = dev_id;
@@ -324,6 +344,9 @@ static int orion_mdio_probe(struct platform_device *pdev)
dev_warn(&pdev->dev,
"unsupported number of clocks, limiting to the first "
__stringify(ARRAY_SIZE(dev->clk)) "\n");
+
+ if (type == BUS_TYPE_XSMI)
+ orion_mdio_xsmi_set_mdc_freq(bus);
} else {
dev->clk[0] = clk_get(&pdev->dev, NULL);
if (PTR_ERR(dev->clk[0]) == -EPROBE_DEFER) {
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 29aac327574d..a641b3534ca3 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -5030,8 +5030,9 @@ static int mvneta_config_rss(struct mvneta_port *pp)
return 0;
}
-static int mvneta_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int mvneta_ethtool_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct mvneta_port *pp = netdev_priv(dev);
@@ -5042,20 +5043,21 @@ static int mvneta_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
/* We require at least one supported parameter to be changed
* and no change in any of the unsupported parameters
*/
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
- memcpy(pp->indir, indir, MVNETA_RSS_LU_TABLE_SIZE);
+ memcpy(pp->indir, rxfh->indir, MVNETA_RSS_LU_TABLE_SIZE);
return mvneta_config_rss(pp);
}
-static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int mvneta_ethtool_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct mvneta_port *pp = netdev_priv(dev);
@@ -5063,13 +5065,12 @@ static int mvneta_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
if (pp->neta_armada3700)
return -EOPNOTSUPP;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
- memcpy(indir, pp->indir, MVNETA_RSS_LU_TABLE_SIZE);
+ memcpy(rxfh->indir, pp->indir, MVNETA_RSS_LU_TABLE_SIZE);
return 0;
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 93137606869e..23adf53c2aa1 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -614,12 +614,38 @@ static void mvpp23_bm_set_8pool_mode(struct mvpp2 *priv)
mvpp2_write(priv, MVPP22_BM_POOL_BASE_ADDR_HIGH_REG, val);
}
+/* Cleanup pool before actual initialization in the OS */
+static void mvpp2_bm_pool_cleanup(struct mvpp2 *priv, int pool_id)
+{
+ unsigned int thread = mvpp2_cpu_to_thread(priv, get_cpu());
+ u32 val;
+ int i;
+
+ /* Drain the BM from all possible residues left by firmware */
+ for (i = 0; i < MVPP2_BM_POOL_SIZE_MAX; i++)
+ mvpp2_thread_read(priv, thread, MVPP2_BM_PHY_ALLOC_REG(pool_id));
+
+ put_cpu();
+
+ /* Stop the BM pool */
+ val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(pool_id));
+ val |= MVPP2_BM_STOP_MASK;
+ mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(pool_id), val);
+}
+
static int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv)
{
enum dma_data_direction dma_dir = DMA_FROM_DEVICE;
int i, err, poolnum = MVPP2_BM_POOLS_NUM;
struct mvpp2_port *port;
+ if (priv->percpu_pools)
+ poolnum = mvpp2_get_nrxqs(priv) * 2;
+
+ /* Clean up the pool state in case it contains stale state */
+ for (i = 0; i < poolnum; i++)
+ mvpp2_bm_pool_cleanup(priv, i);
+
if (priv->percpu_pools) {
for (i = 0; i < priv->port_count; i++) {
port = priv->port_list[i];
@@ -629,7 +655,6 @@ static int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv)
}
}
- poolnum = mvpp2_get_nrxqs(priv) * 2;
for (i = 0; i < poolnum; i++) {
/* the pool in use */
int pn = i / (poolnum / 2);
@@ -1513,10 +1538,21 @@ static void mvpp22_gop_init_rgmii(struct mvpp2_port *port)
regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val);
- if (port->gop_id == 2)
+ if (port->gop_id == 2) {
val |= GENCONF_CTRL0_PORT2_RGMII;
- else if (port->gop_id == 3)
+ } else if (port->gop_id == 3) {
val |= GENCONF_CTRL0_PORT3_RGMII_MII;
+
+ /* According to the specification, GENCONF_CTRL0_PORT3_RGMII
+ * should be set to 1 for RGMII and 0 for MII. However, tests
+ * show that it is the other way around. This is also what
+ * U-Boot does for mvpp2, so it is assumed to be correct.
+ */
+ if (port->phy_interface == PHY_INTERFACE_MODE_MII)
+ val |= GENCONF_CTRL0_PORT3_RGMII;
+ else
+ val &= ~GENCONF_CTRL0_PORT3_RGMII;
+ }
regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val);
}
@@ -1615,6 +1651,7 @@ static int mvpp22_gop_init(struct mvpp2_port *port, phy_interface_t interface)
return 0;
switch (interface) {
+ case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -5634,49 +5671,11 @@ static u32 mvpp2_ethtool_get_rxfh_indir_size(struct net_device *dev)
return mvpp22_rss_is_supported(port) ? MVPP22_RSS_TABLE_ENTRIES : 0;
}
-static int mvpp2_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
- u8 *hfunc)
-{
- struct mvpp2_port *port = netdev_priv(dev);
- int ret = 0;
-
- if (!mvpp22_rss_is_supported(port))
- return -EOPNOTSUPP;
-
- if (indir)
- ret = mvpp22_port_rss_ctx_indir_get(port, 0, indir);
-
- if (hfunc)
- *hfunc = ETH_RSS_HASH_CRC32;
-
- return ret;
-}
-
-static int mvpp2_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
-{
- struct mvpp2_port *port = netdev_priv(dev);
- int ret = 0;
-
- if (!mvpp22_rss_is_supported(port))
- return -EOPNOTSUPP;
-
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_CRC32)
- return -EOPNOTSUPP;
-
- if (key)
- return -EOPNOTSUPP;
-
- if (indir)
- ret = mvpp22_port_rss_ctx_indir_set(port, 0, indir);
-
- return ret;
-}
-
-static int mvpp2_ethtool_get_rxfh_context(struct net_device *dev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context)
+static int mvpp2_ethtool_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct mvpp2_port *port = netdev_priv(dev);
+ u32 rss_context = rxfh->rss_context;
int ret = 0;
if (!mvpp22_rss_is_supported(port))
@@ -5684,33 +5683,34 @@ static int mvpp2_ethtool_get_rxfh_context(struct net_device *dev, u32 *indir,
if (rss_context >= MVPP22_N_RSS_TABLES)
return -EINVAL;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_CRC32;
+ rxfh->hfunc = ETH_RSS_HASH_CRC32;
- if (indir)
- ret = mvpp22_port_rss_ctx_indir_get(port, rss_context, indir);
+ if (rxfh->indir)
+ ret = mvpp22_port_rss_ctx_indir_get(port, rss_context,
+ rxfh->indir);
return ret;
}
-static int mvpp2_ethtool_set_rxfh_context(struct net_device *dev,
- const u32 *indir, const u8 *key,
- const u8 hfunc, u32 *rss_context,
- bool delete)
+static int mvpp2_ethtool_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct mvpp2_port *port = netdev_priv(dev);
- int ret;
+ u32 *rss_context = &rxfh->rss_context;
+ int ret = 0;
if (!mvpp22_rss_is_supported(port))
return -EOPNOTSUPP;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_CRC32)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_CRC32)
return -EOPNOTSUPP;
- if (key)
+ if (rxfh->key)
return -EOPNOTSUPP;
- if (delete)
+ if (*rss_context && rxfh->rss_delete)
return mvpp22_port_rss_ctx_delete(port, *rss_context);
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
@@ -5719,8 +5719,13 @@ static int mvpp2_ethtool_set_rxfh_context(struct net_device *dev,
return ret;
}
- return mvpp22_port_rss_ctx_indir_set(port, *rss_context, indir);
+ if (rxfh->indir)
+ ret = mvpp22_port_rss_ctx_indir_set(port, *rss_context,
+ rxfh->indir);
+
+ return ret;
}
+
/* Device ops */
static const struct net_device_ops mvpp2_netdev_ops = {
@@ -5740,6 +5745,7 @@ static const struct net_device_ops mvpp2_netdev_ops = {
};
static const struct ethtool_ops mvpp2_eth_tool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES,
.nway_reset = mvpp2_ethtool_nway_reset,
@@ -5762,8 +5768,6 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
.get_rxfh_indir_size = mvpp2_ethtool_get_rxfh_indir_size,
.get_rxfh = mvpp2_ethtool_get_rxfh,
.set_rxfh = mvpp2_ethtool_set_rxfh,
- .get_rxfh_context = mvpp2_ethtool_get_rxfh_context,
- .set_rxfh_context = mvpp2_ethtool_set_rxfh_context,
};
/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
@@ -6898,7 +6902,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
dev->min_mtu = ETH_MIN_MTU;
/* 9704 == 9728 - 20 and rounding to 8 */
dev->max_mtu = MVPP2_BM_JUMBO_PKT_SIZE;
- dev->dev.of_node = port_node;
+ device_set_node(&dev->dev, port_fwnode);
port->pcs_gmac.ops = &mvpp2_phylink_gmac_pcs_ops;
port->pcs_gmac.neg_mode = true;
@@ -6948,8 +6952,11 @@ static int mvpp2_port_probe(struct platform_device *pdev,
MAC_10000FD;
}
- if (mvpp2_port_supports_rgmii(port))
+ if (mvpp2_port_supports_rgmii(port)) {
phy_interface_set_rgmii(port->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_MII,
+ port->phylink_config.supported_interfaces);
+ }
if (comphy) {
/* If a COMPHY is present, we can support any of the
diff --git a/drivers/net/ethernet/marvell/octeon_ep/Makefile b/drivers/net/ethernet/marvell/octeon_ep/Makefile
index 2026c8118158..62162ed63f34 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/Makefile
+++ b/drivers/net/ethernet/marvell/octeon_ep/Makefile
@@ -6,4 +6,5 @@
obj-$(CONFIG_OCTEON_EP) += octeon_ep.o
octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \
- octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o
+ octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o \
+ octep_pfvf_mbox.o octep_cnxk_pf.o
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
index d4ee2454675b..b5805969404f 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
@@ -216,16 +216,21 @@ static void octep_init_config_cn93_pf(struct octep_device *oct)
conf->sriov_cfg.vf_srn = CN93_SDP_EPF_RINFO_SRN(val);
val = octep_read_csr64(oct, CN93_SDP_MAC_PF_RING_CTL(oct->pcie_port));
- conf->pf_ring_cfg.srn = CN93_SDP_MAC_PF_RING_CTL_SRN(val);
- conf->pf_ring_cfg.max_io_rings = CN93_SDP_MAC_PF_RING_CTL_RPPF(val);
- conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings;
+ if (oct->chip_id == OCTEP_PCI_DEVICE_ID_CN98_PF) {
+ conf->pf_ring_cfg.srn = CN98_SDP_MAC_PF_RING_CTL_SRN(val);
+ conf->pf_ring_cfg.max_io_rings = CN98_SDP_MAC_PF_RING_CTL_RPPF(val);
+ conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings;
+ } else {
+ conf->pf_ring_cfg.srn = CN93_SDP_MAC_PF_RING_CTL_SRN(val);
+ conf->pf_ring_cfg.max_io_rings = CN93_SDP_MAC_PF_RING_CTL_RPPF(val);
+ conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings;
+ }
dev_info(&pdev->dev, "pf_srn=%u rpvf=%u nvfs=%u rppf=%u\n",
conf->pf_ring_cfg.srn, conf->sriov_cfg.active_rings_per_vf,
conf->sriov_cfg.active_vfs, conf->pf_ring_cfg.active_io_rings);
conf->iq.num_descs = OCTEP_IQ_MAX_DESCRIPTORS;
conf->iq.instr_type = OCTEP_64BYTE_INSTR;
- conf->iq.pkind = 0;
conf->iq.db_min = OCTEP_DB_MIN;
conf->iq.intr_threshold = OCTEP_IQ_INTR_THRESHOLD;
@@ -357,16 +362,55 @@ static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no)
{
struct octep_mbox *mbox = oct->mbox[q_no];
- mbox->q_no = q_no;
-
- /* PF mbox interrupt reg */
- mbox->mbox_int_reg = oct->mmio[0].hw_addr + CN93_SDP_EPF_MBOX_RINT(0);
-
/* PF to VF DATA reg. PF writes into this reg */
- mbox->mbox_write_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_PF_VF_DATA(q_no);
+ mbox->pf_vf_data_reg = oct->mmio[0].hw_addr + CN93_SDP_MBOX_PF_VF_DATA(q_no);
/* VF to PF DATA reg. PF reads from this reg */
- mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
+ mbox->vf_pf_data_reg = oct->mmio[0].hw_addr + CN93_SDP_MBOX_VF_PF_DATA(q_no);
+}
+
+/* Poll for mailbox messages from VF */
+static void octep_poll_pfvf_mailbox(struct octep_device *oct)
+{
+ u32 vf, active_vfs, active_rings_per_vf, vf_mbox_queue;
+ u64 reg0, reg1;
+
+ reg0 = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0));
+ reg1 = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(1));
+ if (reg0 || reg1) {
+ active_vfs = CFG_GET_ACTIVE_VFS(oct->conf);
+ active_rings_per_vf = CFG_GET_ACTIVE_RPVF(oct->conf);
+ for (vf = 0; vf < active_vfs; vf++) {
+ vf_mbox_queue = vf * active_rings_per_vf;
+
+ if (vf_mbox_queue < 64) {
+ if (!(reg0 & (0x1UL << vf_mbox_queue)))
+ continue;
+ } else {
+ if (!(reg1 & (0x1UL << (vf_mbox_queue - 64))))
+ continue;
+ }
+
+ if (!oct->mbox[vf_mbox_queue]) {
+ dev_err(&oct->pdev->dev, "bad mbox vf %d\n", vf);
+ continue;
+ }
+ schedule_work(&oct->mbox[vf_mbox_queue]->wk.work);
+ }
+ if (reg0)
+ octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0), reg0);
+ if (reg1)
+ octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT(1), reg1);
+ }
+}
+
+/* PF-VF mailbox interrupt handler */
+static irqreturn_t octep_pfvf_mbox_intr_handler_cn93_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+
+ octep_poll_pfvf_mailbox(oct);
+ return IRQ_HANDLED;
}
/* Poll OEI events like heartbeat */
@@ -398,6 +442,7 @@ static irqreturn_t octep_oei_intr_handler_cn93_pf(void *dev)
*/
static void octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
{
+ octep_poll_pfvf_mailbox(oct);
octep_poll_oei_cn93_pf(oct);
}
@@ -578,6 +623,13 @@ static irqreturn_t octep_ioq_intr_handler_cn93_pf(void *data)
return IRQ_HANDLED;
}
+/* soft reset of 98xx */
+static int octep_soft_reset_cn98_pf(struct octep_device *oct)
+{
+ dev_info(&oct->pdev->dev, "CN98XX: skip soft reset\n");
+ return 0;
+}
+
/* soft reset of 93xx */
static int octep_soft_reset_cn93_pf(struct octep_device *oct)
{
@@ -634,6 +686,8 @@ static void octep_enable_interrupts_cn93_pf(struct octep_device *oct)
octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
+ octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1S(0), -1ULL);
+ octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1S(1), -1ULL);
octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL);
octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL);
@@ -660,6 +714,8 @@ static void octep_disable_interrupts_cn93_pf(struct octep_device *oct)
octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask);
octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask);
+ octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1C(0), -1ULL);
+ octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1C(1), -1ULL);
octep_write_csr64(oct, CN93_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL);
octep_write_csr64(oct, CN93_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL);
@@ -795,6 +851,7 @@ void octep_device_setup_cn93_pf(struct octep_device *oct)
oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cn93_pf;
oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cn93_pf;
+ oct->hw_ops.mbox_intr_handler = octep_pfvf_mbox_intr_handler_cn93_pf;
oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cn93_pf;
oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cn93_pf;
oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cn93_pf;
@@ -806,7 +863,10 @@ void octep_device_setup_cn93_pf(struct octep_device *oct)
oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cn93_pf;
oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cn93_pf;
oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cn93_pf;
- oct->hw_ops.soft_reset = octep_soft_reset_cn93_pf;
+ if (oct->chip_id == OCTEP_PCI_DEVICE_ID_CN98_PF)
+ oct->hw_ops.soft_reset = octep_soft_reset_cn98_pf;
+ else
+ oct->hw_ops.soft_reset = octep_soft_reset_cn93_pf;
oct->hw_ops.reinit_regs = octep_reinit_regs_cn93_pf;
oct->hw_ops.enable_interrupts = octep_enable_interrupts_cn93_pf;
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c
new file mode 100644
index 000000000000..5de0b5ecbc5f
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cnxk_pf.c
@@ -0,0 +1,925 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
+ *
+ * Copyright (C) 2020 Marvell.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include "octep_config.h"
+#include "octep_main.h"
+#include "octep_regs_cnxk_pf.h"
+
+/* We will support 128 pf's in control mbox */
+#define CTRL_MBOX_MAX_PF 128
+#define CTRL_MBOX_SZ ((size_t)(0x400000 / CTRL_MBOX_MAX_PF))
+
+/* Names of Hardware non-queue generic interrupts */
+static char *cnxk_non_ioq_msix_names[] = {
+ "epf_ire_rint",
+ "epf_ore_rint",
+ "epf_vfire_rint",
+ "epf_rsvd0",
+ "epf_vfore_rint",
+ "epf_rsvd1",
+ "epf_mbox_rint",
+ "epf_rsvd2_0",
+ "epf_rsvd2_1",
+ "epf_dma_rint",
+ "epf_dma_vf_rint",
+ "epf_rsvd3",
+ "epf_pp_vf_rint",
+ "epf_rsvd3",
+ "epf_misc_rint",
+ "epf_rsvd5",
+ /* Next 16 are for OEI_RINT */
+ "epf_oei_rint0",
+ "epf_oei_rint1",
+ "epf_oei_rint2",
+ "epf_oei_rint3",
+ "epf_oei_rint4",
+ "epf_oei_rint5",
+ "epf_oei_rint6",
+ "epf_oei_rint7",
+ "epf_oei_rint8",
+ "epf_oei_rint9",
+ "epf_oei_rint10",
+ "epf_oei_rint11",
+ "epf_oei_rint12",
+ "epf_oei_rint13",
+ "epf_oei_rint14",
+ "epf_oei_rint15",
+ /* IOQ interrupt */
+ "octeon_ep"
+};
+
+/* Dump useful hardware CSRs for debug purpose */
+static void cnxk_dump_regs(struct octep_device *oct, int qno)
+{
+ struct device *dev = &oct->pdev->dev;
+
+ dev_info(dev, "IQ-%d register dump\n", qno);
+ dev_info(dev, "R[%d]_IN_INSTR_DBELL[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_INSTR_DBELL(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(qno)));
+ dev_info(dev, "R[%d]_IN_CONTROL[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_CONTROL(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(qno)));
+ dev_info(dev, "R[%d]_IN_ENABLE[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_ENABLE(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(qno)));
+ dev_info(dev, "R[%d]_IN_INSTR_BADDR[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_INSTR_BADDR(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(qno)));
+ dev_info(dev, "R[%d]_IN_INSTR_RSIZE[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_INSTR_RSIZE(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(qno)));
+ dev_info(dev, "R[%d]_IN_CNTS[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_CNTS(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_CNTS(qno)));
+ dev_info(dev, "R[%d]_IN_INT_LEVELS[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_INT_LEVELS(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(qno)));
+ dev_info(dev, "R[%d]_IN_PKT_CNT[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_PKT_CNT(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(qno)));
+ dev_info(dev, "R[%d]_IN_BYTE_CNT[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_IN_BYTE_CNT(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(qno)));
+
+ dev_info(dev, "OQ-%d register dump\n", qno);
+ dev_info(dev, "R[%d]_OUT_SLIST_DBELL[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_SLIST_DBELL(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(qno)));
+ dev_info(dev, "R[%d]_OUT_CONTROL[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_CONTROL(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(qno)));
+ dev_info(dev, "R[%d]_OUT_ENABLE[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_ENABLE(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(qno)));
+ dev_info(dev, "R[%d]_OUT_SLIST_BADDR[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_SLIST_BADDR(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(qno)));
+ dev_info(dev, "R[%d]_OUT_SLIST_RSIZE[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_SLIST_RSIZE(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(qno)));
+ dev_info(dev, "R[%d]_OUT_CNTS[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_CNTS(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_CNTS(qno)));
+ dev_info(dev, "R[%d]_OUT_INT_LEVELS[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_INT_LEVELS(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(qno)));
+ dev_info(dev, "R[%d]_OUT_PKT_CNT[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_PKT_CNT(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(qno)));
+ dev_info(dev, "R[%d]_OUT_BYTE_CNT[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_OUT_BYTE_CNT(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_OUT_BYTE_CNT(qno)));
+ dev_info(dev, "R[%d]_ERR_TYPE[0x%llx]: 0x%016llx\n",
+ qno, CNXK_SDP_R_ERR_TYPE(qno),
+ octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(qno)));
+}
+
+/* Reset Hardware Tx queue */
+static int cnxk_reset_iq(struct octep_device *oct, int q_no)
+{
+ struct octep_config *conf = oct->conf;
+ u64 val = 0ULL;
+
+ dev_dbg(&oct->pdev->dev, "Reset PF IQ-%d\n", q_no);
+
+ /* Get absolute queue number */
+ q_no += conf->pf_ring_cfg.srn;
+
+ /* Disable the Tx/Instruction Ring */
+ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(q_no), val);
+
+ /* clear the Instruction Ring packet/byte counts and doorbell CSRs */
+ octep_write_csr64(oct, CNXK_SDP_R_IN_CNTS(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_PKT_CNT(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_BYTE_CNT(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(q_no), val);
+
+ val = 0xFFFFFFFF;
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(q_no), val);
+
+ return 0;
+}
+
+/* Reset Hardware Rx queue */
+static void cnxk_reset_oq(struct octep_device *oct, int q_no)
+{
+ u64 val = 0ULL;
+
+ q_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+
+ /* Disable Output (Rx) Ring */
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(q_no), val);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(q_no), val);
+
+ /* Clear count CSRs */
+ val = octep_read_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no));
+ octep_write_csr(oct, CNXK_SDP_R_OUT_CNTS(q_no), val);
+
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_PKT_CNT(q_no), 0xFFFFFFFFFULL);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(q_no), 0xFFFFFFFF);
+}
+
+/* Reset all hardware Tx/Rx queues */
+static void octep_reset_io_queues_cnxk_pf(struct octep_device *oct)
+{
+ struct pci_dev *pdev = oct->pdev;
+ int q;
+
+ dev_dbg(&pdev->dev, "Reset OCTEP_CNXK PF IO Queues\n");
+
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
+ cnxk_reset_iq(oct, q);
+ cnxk_reset_oq(oct, q);
+ }
+}
+
+/* Initialize windowed addresses to access some hardware registers */
+static void octep_setup_pci_window_regs_cnxk_pf(struct octep_device *oct)
+{
+ u8 __iomem *bar0_pciaddr = oct->mmio[0].hw_addr;
+
+ oct->pci_win_regs.pci_win_wr_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_ADDR64);
+ oct->pci_win_regs.pci_win_rd_addr = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_ADDR64);
+ oct->pci_win_regs.pci_win_wr_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_WR_DATA64);
+ oct->pci_win_regs.pci_win_rd_data = (u8 __iomem *)(bar0_pciaddr + CNXK_SDP_WIN_RD_DATA64);
+}
+
+/* Configure Hardware mapping: inform hardware which rings belong to PF. */
+static void octep_configure_ring_mapping_cnxk_pf(struct octep_device *oct)
+{
+ struct octep_config *conf = oct->conf;
+ struct pci_dev *pdev = oct->pdev;
+ u64 pf_srn = CFG_GET_PORTS_PF_SRN(oct->conf);
+ int q;
+
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(conf); q++) {
+ u64 regval = 0;
+
+ if (oct->pcie_port)
+ regval = 8 << CNXK_SDP_FUNC_SEL_EPF_BIT_POS;
+
+ octep_write_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q), regval);
+
+ regval = octep_read_csr64(oct, CNXK_SDP_EPVF_RING(pf_srn + q));
+ dev_dbg(&pdev->dev, "Write SDP_EPVF_RING[0x%llx] = 0x%llx\n",
+ CNXK_SDP_EPVF_RING(pf_srn + q), regval);
+ }
+}
+
+/* Initialize configuration limits and initial active config */
+static void octep_init_config_cnxk_pf(struct octep_device *oct)
+{
+ struct octep_config *conf = oct->conf;
+ struct pci_dev *pdev = oct->pdev;
+ u8 link = 0;
+ u64 val;
+ int pos;
+
+ /* Read ring configuration:
+ * PF ring count, number of VFs and rings per VF supported
+ */
+ val = octep_read_csr64(oct, CNXK_SDP_EPF_RINFO);
+ dev_info(&pdev->dev, "SDP_EPF_RINFO[0x%x]:0x%llx\n", CNXK_SDP_EPF_RINFO, val);
+ conf->sriov_cfg.max_rings_per_vf = CNXK_SDP_EPF_RINFO_RPVF(val);
+ conf->sriov_cfg.active_rings_per_vf = conf->sriov_cfg.max_rings_per_vf;
+ conf->sriov_cfg.max_vfs = CNXK_SDP_EPF_RINFO_NVFS(val);
+ conf->sriov_cfg.active_vfs = conf->sriov_cfg.max_vfs;
+ conf->sriov_cfg.vf_srn = CNXK_SDP_EPF_RINFO_SRN(val);
+
+ val = octep_read_csr64(oct, CNXK_SDP_MAC_PF_RING_CTL(oct->pcie_port));
+ dev_info(&pdev->dev, "SDP_MAC_PF_RING_CTL[%d]:0x%llx\n", oct->pcie_port, val);
+ conf->pf_ring_cfg.srn = CNXK_SDP_MAC_PF_RING_CTL_SRN(val);
+ conf->pf_ring_cfg.max_io_rings = CNXK_SDP_MAC_PF_RING_CTL_RPPF(val);
+ conf->pf_ring_cfg.active_io_rings = conf->pf_ring_cfg.max_io_rings;
+ dev_info(&pdev->dev, "pf_srn=%u rpvf=%u nvfs=%u rppf=%u\n",
+ conf->pf_ring_cfg.srn, conf->sriov_cfg.active_rings_per_vf,
+ conf->sriov_cfg.active_vfs, conf->pf_ring_cfg.active_io_rings);
+
+ conf->iq.num_descs = OCTEP_IQ_MAX_DESCRIPTORS;
+ conf->iq.instr_type = OCTEP_64BYTE_INSTR;
+ conf->iq.db_min = OCTEP_DB_MIN;
+ conf->iq.intr_threshold = OCTEP_IQ_INTR_THRESHOLD;
+
+ conf->oq.num_descs = OCTEP_OQ_MAX_DESCRIPTORS;
+ conf->oq.buf_size = OCTEP_OQ_BUF_SIZE;
+ conf->oq.refill_threshold = OCTEP_OQ_REFILL_THRESHOLD;
+ conf->oq.oq_intr_pkt = OCTEP_OQ_INTR_PKT_THRESHOLD;
+ conf->oq.oq_intr_time = OCTEP_OQ_INTR_TIME_THRESHOLD;
+ conf->oq.wmark = OCTEP_OQ_WMARK_MIN;
+
+ conf->msix_cfg.non_ioq_msix = CNXK_NUM_NON_IOQ_INTR;
+ conf->msix_cfg.ioq_msix = conf->pf_ring_cfg.active_io_rings;
+ conf->msix_cfg.non_ioq_msix_names = cnxk_non_ioq_msix_names;
+
+ pos = pci_find_ext_capability(oct->pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (pos) {
+ pci_read_config_byte(oct->pdev,
+ pos + PCI_SRIOV_FUNC_LINK,
+ &link);
+ link = PCI_DEVFN(PCI_SLOT(oct->pdev->devfn), link);
+ }
+ conf->ctrl_mbox_cfg.barmem_addr = (void __iomem *)oct->mmio[2].hw_addr +
+ CNXK_PEM_BAR4_INDEX_OFFSET +
+ (link * CTRL_MBOX_SZ);
+
+ conf->fw_info.hb_interval = OCTEP_DEFAULT_FW_HB_INTERVAL;
+ conf->fw_info.hb_miss_count = OCTEP_DEFAULT_FW_HB_MISS_COUNT;
+}
+
+/* Setup registers for a hardware Tx Queue */
+static void octep_setup_iq_regs_cnxk_pf(struct octep_device *oct, int iq_no)
+{
+ struct octep_iq *iq = oct->iq[iq_no];
+ u32 reset_instr_cnt;
+ u64 reg_val;
+
+ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no));
+
+ /* wait for IDLE to set to 1 */
+ if (!(reg_val & CNXK_R_IN_CTL_IDLE)) {
+ do {
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no));
+ } while (!(reg_val & CNXK_R_IN_CTL_IDLE));
+ }
+
+ reg_val |= CNXK_R_IN_CTL_RDSIZE;
+ reg_val |= CNXK_R_IN_CTL_IS_64B;
+ reg_val |= CNXK_R_IN_CTL_ESR;
+ octep_write_csr64(oct, CNXK_SDP_R_IN_CONTROL(iq_no), reg_val);
+
+ /* Write the start of the input queue's ring and its size */
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_BADDR(iq_no),
+ iq->desc_ring_dma);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_RSIZE(iq_no),
+ iq->max_count);
+
+ /* Remember the doorbell & instruction count register addr
+ * for this queue
+ */
+ iq->doorbell_reg = oct->mmio[0].hw_addr +
+ CNXK_SDP_R_IN_INSTR_DBELL(iq_no);
+ iq->inst_cnt_reg = oct->mmio[0].hw_addr +
+ CNXK_SDP_R_IN_CNTS(iq_no);
+ iq->intr_lvl_reg = oct->mmio[0].hw_addr +
+ CNXK_SDP_R_IN_INT_LEVELS(iq_no);
+
+ /* Store the current instruction counter (used in flush_iq calculation) */
+ reset_instr_cnt = readl(iq->inst_cnt_reg);
+ writel(reset_instr_cnt, iq->inst_cnt_reg);
+
+ /* INTR_THRESHOLD is set to max(FFFFFFFF) to disable the INTR */
+ reg_val = CFG_GET_IQ_INTR_THRESHOLD(oct->conf) & 0xffffffff;
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
+}
+
+/* Setup registers for a hardware Rx Queue */
+static void octep_setup_oq_regs_cnxk_pf(struct octep_device *oct, int oq_no)
+{
+ u64 reg_val;
+ u64 oq_ctl = 0ULL;
+ u32 time_threshold = 0;
+ struct octep_oq *oq = oct->oq[oq_no];
+
+ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no));
+
+ /* wait for IDLE to set to 1 */
+ if (!(reg_val & CNXK_R_OUT_CTL_IDLE)) {
+ do {
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no));
+ } while (!(reg_val & CNXK_R_OUT_CTL_IDLE));
+ }
+
+ reg_val &= ~(CNXK_R_OUT_CTL_IMODE);
+ reg_val &= ~(CNXK_R_OUT_CTL_ROR_P);
+ reg_val &= ~(CNXK_R_OUT_CTL_NSR_P);
+ reg_val &= ~(CNXK_R_OUT_CTL_ROR_I);
+ reg_val &= ~(CNXK_R_OUT_CTL_NSR_I);
+ reg_val &= ~(CNXK_R_OUT_CTL_ES_I);
+ reg_val &= ~(CNXK_R_OUT_CTL_ROR_D);
+ reg_val &= ~(CNXK_R_OUT_CTL_NSR_D);
+ reg_val &= ~(CNXK_R_OUT_CTL_ES_D);
+ reg_val |= (CNXK_R_OUT_CTL_ES_P);
+
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), reg_val);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_BADDR(oq_no),
+ oq->desc_ring_dma);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_RSIZE(oq_no),
+ oq->max_count);
+
+ oq_ctl = octep_read_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no));
+
+ /* Clear the ISIZE and BSIZE (22-0) */
+ oq_ctl &= ~0x7fffffULL;
+
+ /* Populate the BSIZE (15-0) */
+ oq_ctl |= (oq->buffer_size & 0xffff);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_CONTROL(oq_no), oq_ctl);
+
+ /* Get the mapped address of the pkt_sent and pkts_credit regs */
+ oq->pkts_sent_reg = oct->mmio[0].hw_addr + CNXK_SDP_R_OUT_CNTS(oq_no);
+ oq->pkts_credit_reg = oct->mmio[0].hw_addr +
+ CNXK_SDP_R_OUT_SLIST_DBELL(oq_no);
+
+ time_threshold = CFG_GET_OQ_INTR_TIME(oct->conf);
+ reg_val = ((u64)time_threshold << 32) |
+ CFG_GET_OQ_INTR_PKT(oct->conf);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
+
+ /* set watermark for backpressure */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no));
+ reg_val &= ~0xFFFFFFFFULL;
+ reg_val |= CFG_GET_OQ_WMARK(oct->conf);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_WMARK(oq_no), reg_val);
+}
+
+/* Setup registers for a PF mailbox */
+static void octep_setup_mbox_regs_cnxk_pf(struct octep_device *oct, int q_no)
+{
+ struct octep_mbox *mbox = oct->mbox[q_no];
+
+ /* PF to VF DATA reg. PF writes into this reg */
+ mbox->pf_vf_data_reg = oct->mmio[0].hw_addr + CNXK_SDP_MBOX_PF_VF_DATA(q_no);
+
+ /* VF to PF DATA reg. PF reads from this reg */
+ mbox->vf_pf_data_reg = oct->mmio[0].hw_addr + CNXK_SDP_MBOX_VF_PF_DATA(q_no);
+}
+
+static void octep_poll_pfvf_mailbox_cnxk_pf(struct octep_device *oct)
+{
+ u32 vf, active_vfs, active_rings_per_vf, vf_mbox_queue;
+ u64 reg0;
+
+ reg0 = octep_read_csr64(oct, CNXK_SDP_EPF_MBOX_RINT(0));
+ if (reg0) {
+ active_vfs = CFG_GET_ACTIVE_VFS(oct->conf);
+ active_rings_per_vf = CFG_GET_ACTIVE_RPVF(oct->conf);
+ for (vf = 0; vf < active_vfs; vf++) {
+ vf_mbox_queue = vf * active_rings_per_vf;
+ if (!(reg0 & (0x1UL << vf_mbox_queue)))
+ continue;
+
+ if (!oct->mbox[vf_mbox_queue]) {
+ dev_err(&oct->pdev->dev, "bad mbox vf %d\n", vf);
+ continue;
+ }
+ schedule_work(&oct->mbox[vf_mbox_queue]->wk.work);
+ }
+ if (reg0)
+ octep_write_csr64(oct, CNXK_SDP_EPF_MBOX_RINT(0), reg0);
+ }
+}
+
+static irqreturn_t octep_pfvf_mbox_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+
+ octep_poll_pfvf_mailbox_cnxk_pf(oct);
+ return IRQ_HANDLED;
+}
+
+/* Poll OEI events like heartbeat */
+static void octep_poll_oei_cnxk_pf(struct octep_device *oct)
+{
+ u64 reg0;
+
+ /* Check for OEI INTR */
+ reg0 = octep_read_csr64(oct, CNXK_SDP_EPF_OEI_RINT);
+ if (reg0) {
+ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT, reg0);
+ if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX)
+ queue_work(octep_wq, &oct->ctrl_mbox_task);
+ if (reg0 & CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT)
+ atomic_set(&oct->hb_miss_cnt, 0);
+ }
+}
+
+/* OEI interrupt handler */
+static irqreturn_t octep_oei_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+
+ octep_poll_oei_cnxk_pf(oct);
+ return IRQ_HANDLED;
+}
+
+/* Process non-ioq interrupts required to keep pf interface running.
+ * OEI_RINT is needed for control mailbox
+ * MBOX_RINT is needed for pfvf mailbox
+ */
+static void octep_poll_non_ioq_interrupts_cnxk_pf(struct octep_device *oct)
+{
+ octep_poll_pfvf_mailbox_cnxk_pf(oct);
+ octep_poll_oei_cnxk_pf(oct);
+}
+
+/* Interrupt handler for input ring error interrupts. */
+static irqreturn_t octep_ire_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+ int i = 0;
+
+ /* Check for IRERR INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_IRERR_RINT);
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "received IRERR_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT, reg_val);
+
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
+ reg_val = octep_read_csr64(oct,
+ CNXK_SDP_R_ERR_TYPE(i));
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received err type on IQ-%d: 0x%llx\n",
+ i, reg_val);
+ octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i),
+ reg_val);
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for output ring error interrupts. */
+static irqreturn_t octep_ore_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+ int i = 0;
+
+ /* Check for ORERR INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_ORERR_RINT);
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received ORERR_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT, reg_val);
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++) {
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_ERR_TYPE(i));
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received err type on OQ-%d: 0x%llx\n",
+ i, reg_val);
+ octep_write_csr64(oct, CNXK_SDP_R_ERR_TYPE(i),
+ reg_val);
+ }
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for vf input ring error interrupts. */
+static irqreturn_t octep_vfire_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+
+ /* Check for VFIRE INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0));
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received VFIRE_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT(0), reg_val);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for vf output ring error interrupts. */
+static irqreturn_t octep_vfore_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+
+ /* Check for VFORE INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0));
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received VFORE_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT(0), reg_val);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for dpi dma related interrupts. */
+static irqreturn_t octep_dma_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ u64 reg_val = 0;
+
+ /* Check for DMA INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_RINT);
+ if (reg_val)
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT, reg_val);
+
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for dpi dma transaction error interrupts for VFs */
+static irqreturn_t octep_dma_vf_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+
+ /* Check for DMA VF INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0));
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received DMA_VF_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT(0), reg_val);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for pp transaction error interrupts for VFs */
+static irqreturn_t octep_pp_vf_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+
+ /* Check for PPVF INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0));
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received PP_VF_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT(0), reg_val);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupt handler for mac related interrupts. */
+static irqreturn_t octep_misc_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+ u64 reg_val = 0;
+
+ /* Check for MISC INTR */
+ reg_val = octep_read_csr64(oct, CNXK_SDP_EPF_MISC_RINT);
+ if (reg_val) {
+ dev_info(&pdev->dev,
+ "Received MISC_RINT intr: 0x%llx\n", reg_val);
+ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT, reg_val);
+ }
+ return IRQ_HANDLED;
+}
+
+/* Interrupts handler for all reserved interrupts. */
+static irqreturn_t octep_rsvd_intr_handler_cnxk_pf(void *dev)
+{
+ struct octep_device *oct = (struct octep_device *)dev;
+ struct pci_dev *pdev = oct->pdev;
+
+ dev_info(&pdev->dev, "Reserved interrupts raised; Ignore\n");
+ return IRQ_HANDLED;
+}
+
+/* Tx/Rx queue interrupt handler */
+static irqreturn_t octep_ioq_intr_handler_cnxk_pf(void *data)
+{
+ struct octep_ioq_vector *vector = (struct octep_ioq_vector *)data;
+ struct octep_oq *oq = vector->oq;
+
+ napi_schedule_irqoff(oq->napi);
+ return IRQ_HANDLED;
+}
+
+/* soft reset */
+static int octep_soft_reset_cnxk_pf(struct octep_device *oct)
+{
+ dev_info(&oct->pdev->dev, "CNXKXX: Doing soft reset\n");
+
+ octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF);
+
+ /* Firmware status CSR is supposed to be cleared by
+ * core domain reset, but due to a hw bug, it is not.
+ * Set it to RUNNING right before reset so that it is not
+ * left in READY (1) state after a reset. This is required
+ * in addition to the early setting to handle the case where
+ * the OcteonTX is unexpectedly reset, reboots, and then
+ * the module is removed.
+ */
+ OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL),
+ FW_STATUS_RUNNING);
+
+ /* Set chip domain reset bit */
+ OCTEP_PCI_WIN_WRITE(oct, CNXK_RST_CHIP_DOMAIN_W1S, 1);
+ /* Wait till Octeon resets. */
+ mdelay(10);
+ /* restore the reset value */
+ octep_write_csr64(oct, CNXK_SDP_WIN_WR_MASK_REG, 0xFF);
+
+ return 0;
+}
+
+/* Re-initialize Octeon hardware registers */
+static void octep_reinit_regs_cnxk_pf(struct octep_device *oct)
+{
+ u32 i;
+
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
+ oct->hw_ops.setup_iq_regs(oct, i);
+
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
+ oct->hw_ops.setup_oq_regs(oct, i);
+
+ oct->hw_ops.enable_interrupts(oct);
+ oct->hw_ops.enable_io_queues(oct);
+
+ for (i = 0; i < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); i++)
+ writel(oct->oq[i]->max_count, oct->oq[i]->pkts_credit_reg);
+}
+
+/* Enable all interrupts */
+static void octep_enable_interrupts_cnxk_pf(struct octep_device *oct)
+{
+ u64 intr_mask = 0ULL;
+ int srn, num_rings, i;
+
+ srn = CFG_GET_PORTS_PF_SRN(oct->conf);
+ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
+
+ for (i = 0; i < num_rings; i++)
+ intr_mask |= (0x1ULL << (srn + i));
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1S, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1S, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL);
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(0), -1ULL);
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(0), -1ULL);
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_MBOX_RINT_ENA_W1S(0), -1ULL);
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(0), -1ULL);
+ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(0), -1ULL);
+}
+
+/* Disable all interrupts */
+static void octep_disable_interrupts_cnxk_pf(struct octep_device *oct)
+{
+ u64 intr_mask = 0ULL;
+ int srn, num_rings, i;
+
+ srn = CFG_GET_PORTS_PF_SRN(oct->conf);
+ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
+
+ for (i = 0; i < num_rings; i++)
+ intr_mask |= (0x1ULL << (srn + i));
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_IRERR_RINT_ENA_W1C, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_ORERR_RINT_ENA_W1C, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_OEI_RINT_ENA_W1C, -1ULL);
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(0), -1ULL);
+ octep_write_csr64(oct, CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(0), -1ULL);
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_MISC_RINT_ENA_W1C, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_RINT_ENA_W1C, intr_mask);
+ octep_write_csr64(oct, CNXK_SDP_EPF_MBOX_RINT_ENA_W1C(0), -1ULL);
+
+ octep_write_csr64(oct, CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(0), -1ULL);
+ octep_write_csr64(oct, CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(0), -1ULL);
+}
+
+/* Get new Octeon Read Index: index of descriptor that Octeon reads next. */
+static u32 octep_update_iq_read_index_cnxk_pf(struct octep_iq *iq)
+{
+ u32 pkt_in_done = readl(iq->inst_cnt_reg);
+ u32 last_done, new_idx;
+
+ last_done = pkt_in_done - iq->pkt_in_done;
+ iq->pkt_in_done = pkt_in_done;
+
+ new_idx = (iq->octep_read_index + last_done) % iq->max_count;
+
+ return new_idx;
+}
+
+/* Enable a hardware Tx Queue */
+static void octep_enable_iq_cnxk_pf(struct octep_device *oct, int iq_no)
+{
+ u64 loop = HZ;
+ u64 reg_val;
+
+ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no), 0xFFFFFFFF);
+
+ while (octep_read_csr64(oct, CNXK_SDP_R_IN_INSTR_DBELL(iq_no)) &&
+ loop--) {
+ schedule_timeout_interruptible(1);
+ }
+
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no));
+ reg_val |= (0x1ULL << 62);
+ octep_write_csr64(oct, CNXK_SDP_R_IN_INT_LEVELS(iq_no), reg_val);
+
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no));
+ reg_val |= 0x1ULL;
+ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val);
+}
+
+/* Enable a hardware Rx Queue */
+static void octep_enable_oq_cnxk_pf(struct octep_device *oct, int oq_no)
+{
+ u64 reg_val = 0ULL;
+
+ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no));
+ reg_val |= (0x1ULL << 62);
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_INT_LEVELS(oq_no), reg_val);
+
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_SLIST_DBELL(oq_no), 0xFFFFFFFF);
+
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no));
+ reg_val |= 0x1ULL;
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val);
+}
+
+/* Enable all hardware Tx/Rx Queues assined to PF */
+static void octep_enable_io_queues_cnxk_pf(struct octep_device *oct)
+{
+ u8 q;
+
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
+ octep_enable_iq_cnxk_pf(oct, q);
+ octep_enable_oq_cnxk_pf(oct, q);
+ }
+}
+
+/* Disable a hardware Tx Queue assined to PF */
+static void octep_disable_iq_cnxk_pf(struct octep_device *oct, int iq_no)
+{
+ u64 reg_val = 0ULL;
+
+ iq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no));
+ reg_val &= ~0x1ULL;
+ octep_write_csr64(oct, CNXK_SDP_R_IN_ENABLE(iq_no), reg_val);
+}
+
+/* Disable a hardware Rx Queue assined to PF */
+static void octep_disable_oq_cnxk_pf(struct octep_device *oct, int oq_no)
+{
+ u64 reg_val = 0ULL;
+
+ oq_no += CFG_GET_PORTS_PF_SRN(oct->conf);
+ reg_val = octep_read_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no));
+ reg_val &= ~0x1ULL;
+ octep_write_csr64(oct, CNXK_SDP_R_OUT_ENABLE(oq_no), reg_val);
+}
+
+/* Disable all hardware Tx/Rx Queues assined to PF */
+static void octep_disable_io_queues_cnxk_pf(struct octep_device *oct)
+{
+ int q = 0;
+
+ for (q = 0; q < CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf); q++) {
+ octep_disable_iq_cnxk_pf(oct, q);
+ octep_disable_oq_cnxk_pf(oct, q);
+ }
+}
+
+/* Dump hardware registers (including Tx/Rx queues) for debugging. */
+static void octep_dump_registers_cnxk_pf(struct octep_device *oct)
+{
+ u8 srn, num_rings, q;
+
+ srn = CFG_GET_PORTS_PF_SRN(oct->conf);
+ num_rings = CFG_GET_PORTS_ACTIVE_IO_RINGS(oct->conf);
+
+ for (q = srn; q < srn + num_rings; q++)
+ cnxk_dump_regs(oct, q);
+}
+
+/**
+ * octep_device_setup_cnxk_pf() - Setup Octeon device.
+ *
+ * @oct: Octeon device private data structure.
+ *
+ * - initialize hardware operations.
+ * - get target side pcie port number for the device.
+ * - setup window access to hardware registers.
+ * - set initial configuration and max limits.
+ * - setup hardware mapping of rings to the PF device.
+ */
+void octep_device_setup_cnxk_pf(struct octep_device *oct)
+{
+ oct->hw_ops.setup_iq_regs = octep_setup_iq_regs_cnxk_pf;
+ oct->hw_ops.setup_oq_regs = octep_setup_oq_regs_cnxk_pf;
+ oct->hw_ops.setup_mbox_regs = octep_setup_mbox_regs_cnxk_pf;
+
+ oct->hw_ops.mbox_intr_handler = octep_pfvf_mbox_intr_handler_cnxk_pf;
+ oct->hw_ops.oei_intr_handler = octep_oei_intr_handler_cnxk_pf;
+ oct->hw_ops.ire_intr_handler = octep_ire_intr_handler_cnxk_pf;
+ oct->hw_ops.ore_intr_handler = octep_ore_intr_handler_cnxk_pf;
+ oct->hw_ops.vfire_intr_handler = octep_vfire_intr_handler_cnxk_pf;
+ oct->hw_ops.vfore_intr_handler = octep_vfore_intr_handler_cnxk_pf;
+ oct->hw_ops.dma_intr_handler = octep_dma_intr_handler_cnxk_pf;
+ oct->hw_ops.dma_vf_intr_handler = octep_dma_vf_intr_handler_cnxk_pf;
+ oct->hw_ops.pp_vf_intr_handler = octep_pp_vf_intr_handler_cnxk_pf;
+ oct->hw_ops.misc_intr_handler = octep_misc_intr_handler_cnxk_pf;
+ oct->hw_ops.rsvd_intr_handler = octep_rsvd_intr_handler_cnxk_pf;
+ oct->hw_ops.ioq_intr_handler = octep_ioq_intr_handler_cnxk_pf;
+ oct->hw_ops.soft_reset = octep_soft_reset_cnxk_pf;
+ oct->hw_ops.reinit_regs = octep_reinit_regs_cnxk_pf;
+
+ oct->hw_ops.enable_interrupts = octep_enable_interrupts_cnxk_pf;
+ oct->hw_ops.disable_interrupts = octep_disable_interrupts_cnxk_pf;
+ oct->hw_ops.poll_non_ioq_interrupts = octep_poll_non_ioq_interrupts_cnxk_pf;
+
+ oct->hw_ops.update_iq_read_idx = octep_update_iq_read_index_cnxk_pf;
+
+ oct->hw_ops.enable_iq = octep_enable_iq_cnxk_pf;
+ oct->hw_ops.enable_oq = octep_enable_oq_cnxk_pf;
+ oct->hw_ops.enable_io_queues = octep_enable_io_queues_cnxk_pf;
+
+ oct->hw_ops.disable_iq = octep_disable_iq_cnxk_pf;
+ oct->hw_ops.disable_oq = octep_disable_oq_cnxk_pf;
+ oct->hw_ops.disable_io_queues = octep_disable_io_queues_cnxk_pf;
+ oct->hw_ops.reset_io_queues = octep_reset_io_queues_cnxk_pf;
+
+ oct->hw_ops.dump_registers = octep_dump_registers_cnxk_pf;
+
+ octep_setup_pci_window_regs_cnxk_pf(oct);
+
+ oct->pcie_port = octep_read_csr64(oct, CNXK_SDP_MAC_NUMBER) & 0xff;
+ dev_info(&oct->pdev->dev,
+ "Octeon device using PCIE Port %d\n", oct->pcie_port);
+
+ octep_init_config_cnxk_pf(oct);
+ octep_configure_ring_mapping_cnxk_pf(oct);
+
+ /* Firmware status CSR is supposed to be cleared by
+ * core domain reset, but due to IPBUPEM-38842, it is not.
+ * Set it to RUNNING early in boot, so that unexpected resets
+ * leave it in a state that is not READY (1).
+ */
+ OCTEP_PCI_WIN_WRITE(oct, CNXK_PEMX_PFX_CSX_PFCFGX(0, 0, CNXK_PCIEEP_VSECST_CTL),
+ FW_STATUS_RUNNING);
+}
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h
index 1622a6ebf036..1627660175c2 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_config.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_config.h
@@ -13,12 +13,16 @@
#define OCTEP_64BYTE_INSTR 64
/* Tx Queue: maximum descriptors per ring */
+/* This needs to be a power of 2 */
#define OCTEP_IQ_MAX_DESCRIPTORS 1024
/* Minimum input (Tx) requests to be enqueued to ring doorbell */
-#define OCTEP_DB_MIN 1
+#define OCTEP_DB_MIN 8
/* Packet threshold for Tx queue interrupt */
#define OCTEP_IQ_INTR_THRESHOLD 0x0
+/* Minimum watermark for backpressure */
+#define OCTEP_OQ_WMARK_MIN 256
+
/* Rx Queue: maximum descriptors per ring */
#define OCTEP_OQ_MAX_DESCRIPTORS 1024
@@ -44,8 +48,6 @@
/* Minimum MTU supported by Octeon network interface */
#define OCTEP_MIN_MTU ETH_MIN_MTU
-/* Maximum MTU supported by Octeon interface*/
-#define OCTEP_MAX_MTU (10000 - (ETH_HLEN + ETH_FCS_LEN))
/* Default MTU */
#define OCTEP_DEFAULT_MTU 1500
@@ -58,7 +60,6 @@
#define CFG_GET_IQ_CFG(cfg) ((cfg)->iq)
#define CFG_GET_IQ_NUM_DESC(cfg) ((cfg)->iq.num_descs)
#define CFG_GET_IQ_INSTR_TYPE(cfg) ((cfg)->iq.instr_type)
-#define CFG_GET_IQ_PKIND(cfg) ((cfg)->iq.pkind)
#define CFG_GET_IQ_INSTR_SIZE(cfg) (64)
#define CFG_GET_IQ_DB_MIN(cfg) ((cfg)->iq.db_min)
#define CFG_GET_IQ_INTR_THRESHOLD(cfg) ((cfg)->iq.intr_threshold)
@@ -68,12 +69,12 @@
#define CFG_GET_OQ_REFILL_THRESHOLD(cfg) ((cfg)->oq.refill_threshold)
#define CFG_GET_OQ_INTR_PKT(cfg) ((cfg)->oq.oq_intr_pkt)
#define CFG_GET_OQ_INTR_TIME(cfg) ((cfg)->oq.oq_intr_time)
+#define CFG_GET_OQ_WMARK(cfg) ((cfg)->oq.wmark)
#define CFG_GET_PORTS_MAX_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.max_io_rings)
#define CFG_GET_PORTS_ACTIVE_IO_RINGS(cfg) ((cfg)->pf_ring_cfg.active_io_rings)
#define CFG_GET_PORTS_PF_SRN(cfg) ((cfg)->pf_ring_cfg.srn)
-#define CFG_GET_DPI_PKIND(cfg) ((cfg)->core_cfg.dpi_pkind)
#define CFG_GET_CORE_TICS_PER_US(cfg) ((cfg)->core_cfg.core_tics_per_us)
#define CFG_GET_COPROC_TICS_PER_US(cfg) ((cfg)->core_cfg.coproc_tics_per_us)
@@ -97,9 +98,6 @@ struct octep_iq_config {
/* Command size - 32 or 64 bytes */
u16 instr_type;
- /* pkind for packets sent to Octeon */
- u16 pkind;
-
/* Minimum number of commands pending to be posted to Octeon before driver
* hits the Input queue doorbell.
*/
@@ -137,6 +135,12 @@ struct octep_oq_config {
* default. The time is specified in microseconds.
*/
u32 oq_intr_time;
+
+ /* Water mark for backpressure.
+ * Output queue sends backpressure signal to source when
+ * free buffer count falls below wmark.
+ */
+ u32 wmark;
};
/* Tx/Rx configuration */
@@ -189,11 +193,37 @@ struct octep_ctrl_mbox_config {
/* Info from firmware */
struct octep_fw_info {
/* interface pkind */
- u16 pkind;
+ u8 pkind;
+
+ /* front size data */
+ u8 fsz;
+
/* heartbeat interval in milliseconds */
u16 hb_interval;
+
/* heartbeat miss count */
u16 hb_miss_count;
+
+ /* reserved */
+ u16 reserved1;
+
+ /* supported rx offloads OCTEP_ETH_RX_OFFLOAD_* */
+ u16 rx_ol_flags;
+
+ /* supported tx offloads OCTEP_ETH_TX_OFFLOAD_* */
+ u16 tx_ol_flags;
+
+ /* reserved */
+ u32 reserved_offloads;
+
+ /* extra offload flags */
+ u64 ext_ol_flags;
+
+ /* supported features */
+ u64 features[2];
+
+ /* reserved */
+ u64 reserved2[3];
};
/* Data Structure to hold configuration limits and active config */
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
index 7f8135788efc..6da32d40f926 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_mbox.h
@@ -16,10 +16,12 @@
* |reserved (4 bytes) |
* |-------------------------------------------|
* |host version (8 bytes) |
+ * | low 32 bits |
* |host status (8 bytes) |
* |host reserved (104 bytes) |
* |-------------------------------------------|
- * |fw version (8 bytes) |
+ * |fw version's (8 bytes) |
+ * | min=high 32 bits, max=low 32 bits |
* |fw status (8 bytes) |
* |fw reserved (104 bytes) |
* |===========================================|
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
index 0594607a2585..01b7be154c38 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
@@ -13,6 +13,7 @@
#include "octep_config.h"
#include "octep_main.h"
#include "octep_ctrl_net.h"
+#include "octep_pfvf_mbox.h"
/* Control plane version */
#define OCTEP_CP_VERSION_CURRENT OCTEP_CP_VERSION(1, 0, 0)
@@ -22,12 +23,15 @@ static const u32 mtu_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mtu);
static const u32 mac_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_mac);
static const u32 state_sz = sizeof(struct octep_ctrl_net_h2f_req_cmd_state);
static const u32 link_info_sz = sizeof(struct octep_ctrl_net_link_info);
+static const u32 offloads_sz = sizeof(struct octep_ctrl_net_offloads);
static atomic_t ctrl_net_msg_id;
/* Control plane version in which OCTEP_CTRL_NET_H2F_CMD was added */
static const u32 octep_ctrl_net_h2f_cmd_versions[OCTEP_CTRL_NET_H2F_CMD_MAX] = {
- [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_GET_INFO] =
- OCTEP_CP_VERSION(1, 0, 0)
+ [OCTEP_CTRL_NET_H2F_CMD_INVALID ... OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE] =
+ OCTEP_CP_VERSION(1, 0, 0),
+ [OCTEP_CTRL_NET_H2F_CMD_OFFLOADS] = OCTEP_CP_VERSION(1, 0, 1)
+
};
/* Control plane version in which OCTEP_CTRL_NET_F2H_CMD was added */
@@ -122,7 +126,7 @@ int octep_ctrl_net_init(struct octep_device *oct)
int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
int err;
@@ -139,7 +143,7 @@ int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid)
int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up,
bool wait_for_response)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
init_send_req(&d.msg, req, state_sz, vfid);
@@ -154,7 +158,7 @@ int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up,
int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up,
bool wait_for_response)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
init_send_req(&d.msg, req, state_sz, vfid);
@@ -168,7 +172,7 @@ int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up,
int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
int err;
@@ -187,7 +191,7 @@ int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr)
int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr,
bool wait_for_response)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
init_send_req(&d.msg, req, mac_sz, vfid);
@@ -198,10 +202,28 @@ int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr,
return octep_send_mbox_req(oct, &d, wait_for_response);
}
+int octep_ctrl_net_get_mtu(struct octep_device *oct, int vfid)
+{
+ struct octep_ctrl_net_wait_data d = {};
+ struct octep_ctrl_net_h2f_req *req;
+ int err;
+
+ req = &d.data.req;
+ init_send_req(&d.msg, req, mtu_sz, vfid);
+ req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_MTU;
+ req->mtu.cmd = OCTEP_CTRL_NET_CMD_GET;
+
+ err = octep_send_mbox_req(oct, &d, true);
+ if (err < 0)
+ return err;
+
+ return d.data.resp.mtu.val;
+}
+
int octep_ctrl_net_set_mtu(struct octep_device *oct, int vfid, int mtu,
bool wait_for_response)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
init_send_req(&d.msg, req, mtu_sz, vfid);
@@ -216,7 +238,7 @@ int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid,
struct octep_iface_rx_stats *rx_stats,
struct octep_iface_tx_stats *tx_stats)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
struct octep_ctrl_net_h2f_resp *resp;
int err;
@@ -236,7 +258,7 @@ int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid,
int octep_ctrl_net_get_link_info(struct octep_device *oct, int vfid,
struct octep_iface_link_info *link_info)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
struct octep_ctrl_net_h2f_resp *resp;
int err;
@@ -262,7 +284,7 @@ int octep_ctrl_net_set_link_info(struct octep_device *oct, int vfid,
struct octep_iface_link_info *link_info,
bool wait_for_response)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_req *req = &d.data.req;
init_send_req(&d.msg, req, link_info_sz, vfid);
@@ -308,6 +330,11 @@ static int process_mbox_notify(struct octep_device *oct,
octep_ctrl_net_f2h_cmd_versions[cmd] < OCTEP_CP_VERSION_CURRENT)
return -EOPNOTSUPP;
+ if (msg->hdr.s.is_vf) {
+ octep_pfvf_notify(oct, msg);
+ return 0;
+ }
+
switch (cmd) {
case OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS:
if (netif_running(netdev)) {
@@ -331,8 +358,8 @@ static int process_mbox_notify(struct octep_device *oct,
void octep_ctrl_net_recv_fw_messages(struct octep_device *oct)
{
static u16 msg_sz = sizeof(union octep_ctrl_net_max_data);
- union octep_ctrl_net_max_data data = {0};
- struct octep_ctrl_mbox_msg msg = {0};
+ union octep_ctrl_net_max_data data = {};
+ struct octep_ctrl_mbox_msg msg = {};
int ret;
msg.hdr.s.sz = msg_sz;
@@ -356,7 +383,7 @@ void octep_ctrl_net_recv_fw_messages(struct octep_device *oct)
int octep_ctrl_net_get_info(struct octep_device *oct, int vfid,
struct octep_fw_info *info)
{
- struct octep_ctrl_net_wait_data d = {0};
+ struct octep_ctrl_net_wait_data d = {};
struct octep_ctrl_net_h2f_resp *resp;
struct octep_ctrl_net_h2f_req *req;
int err;
@@ -375,10 +402,41 @@ int octep_ctrl_net_get_info(struct octep_device *oct, int vfid,
return 0;
}
+int octep_ctrl_net_dev_remove(struct octep_device *oct, int vfid)
+{
+ struct octep_ctrl_net_wait_data d = {};
+ struct octep_ctrl_net_h2f_req *req;
+
+ req = &d.data.req;
+ dev_dbg(&oct->pdev->dev, "Sending dev_unload msg to fw\n");
+ init_send_req(&d.msg, req, sizeof(int), vfid);
+ req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE;
+
+ return octep_send_mbox_req(oct, &d, false);
+}
+
+int octep_ctrl_net_set_offloads(struct octep_device *oct, int vfid,
+ struct octep_ctrl_net_offloads *offloads,
+ bool wait_for_response)
+{
+ struct octep_ctrl_net_wait_data d = {};
+ struct octep_ctrl_net_h2f_req *req;
+
+ req = &d.data.req;
+ init_send_req(&d.msg, req, offloads_sz, vfid);
+ req->hdr.s.cmd = OCTEP_CTRL_NET_H2F_CMD_OFFLOADS;
+ req->offloads.cmd = OCTEP_CTRL_NET_CMD_SET;
+ req->offloads.offloads = *offloads;
+
+ return octep_send_mbox_req(oct, &d, wait_for_response);
+}
+
int octep_ctrl_net_uninit(struct octep_device *oct)
{
struct octep_ctrl_net_wait_data *pos, *n;
+ octep_ctrl_net_dev_remove(oct, OCTEP_CTRL_NET_INVALID_VFID);
+
list_for_each_entry_safe(pos, n, &oct->ctrl_req_wait_list, list)
pos->done = 1;
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
index b330f370131b..0b823bea9cd8 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.h
@@ -42,6 +42,8 @@ enum octep_ctrl_net_h2f_cmd {
OCTEP_CTRL_NET_H2F_CMD_RX_STATE,
OCTEP_CTRL_NET_H2F_CMD_LINK_INFO,
OCTEP_CTRL_NET_H2F_CMD_GET_INFO,
+ OCTEP_CTRL_NET_H2F_CMD_DEV_REMOVE,
+ OCTEP_CTRL_NET_H2F_CMD_OFFLOADS,
OCTEP_CTRL_NET_H2F_CMD_MAX
};
@@ -112,6 +114,26 @@ struct octep_ctrl_net_h2f_req_cmd_link_info {
struct octep_ctrl_net_link_info info;
};
+/* offloads */
+struct octep_ctrl_net_offloads {
+ /* supported rx offloads OCTEP_RX_OFFLOAD_* */
+ u16 rx_offloads;
+ /* supported tx offloads OCTEP_TX_OFFLOAD_* */
+ u16 tx_offloads;
+ /* reserved */
+ u32 reserved_offloads;
+ /* extra offloads */
+ u64 ext_offloads;
+};
+
+/* get/set offloads */
+struct octep_ctrl_net_h2f_req_cmd_offloads {
+ /* enum octep_ctrl_net_cmd */
+ u16 cmd;
+ /* struct octep_ctrl_net_offloads */
+ struct octep_ctrl_net_offloads offloads;
+};
+
/* Host to fw request data */
struct octep_ctrl_net_h2f_req {
union octep_ctrl_net_req_hdr hdr;
@@ -121,6 +143,7 @@ struct octep_ctrl_net_h2f_req {
struct octep_ctrl_net_h2f_req_cmd_state link;
struct octep_ctrl_net_h2f_req_cmd_state rx;
struct octep_ctrl_net_h2f_req_cmd_link_info link_info;
+ struct octep_ctrl_net_h2f_req_cmd_offloads offloads;
};
} __packed;
@@ -178,6 +201,7 @@ struct octep_ctrl_net_h2f_resp {
struct octep_ctrl_net_h2f_resp_cmd_state rx;
struct octep_ctrl_net_link_info link_info;
struct octep_ctrl_net_h2f_resp_cmd_get_info info;
+ struct octep_ctrl_net_offloads offloads;
};
} __packed;
@@ -218,87 +242,105 @@ struct octep_ctrl_net_wait_data {
} data;
};
-/** Initialize data for ctrl net.
+/**
+ * octep_ctrl_net_init() - Initialize data for ctrl net.
*
- * @param oct: non-null pointer to struct octep_device.
+ * @oct: non-null pointer to struct octep_device.
*
* return value: 0 on success, -errno on error.
*/
int octep_ctrl_net_init(struct octep_device *oct);
-/** Get link status from firmware.
+/**
+ * octep_ctrl_net_get_link_status() - Get link status from firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
*
* return value: link status 0=down, 1=up.
*/
int octep_ctrl_net_get_link_status(struct octep_device *oct, int vfid);
-/** Set link status in firmware.
+/**
+ * octep_ctrl_net_set_link_status() - Set link status in firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param up: boolean status.
- * @param wait_for_response: poll for response.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @up: boolean status.
+ * @wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure
*/
int octep_ctrl_net_set_link_status(struct octep_device *oct, int vfid, bool up,
bool wait_for_response);
-/** Set rx state in firmware.
+/**
+ * octep_ctrl_net_set_rx_state() - Set rx state in firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param up: boolean status.
- * @param wait_for_response: poll for response.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @up: boolean status.
+ * @wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_set_rx_state(struct octep_device *oct, int vfid, bool up,
bool wait_for_response);
-/** Get mac address from firmware.
+/**
+ * octep_ctrl_net_get_mac_addr() - Get mac address from firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param addr: non-null pointer to mac address.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @addr: non-null pointer to mac address.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_get_mac_addr(struct octep_device *oct, int vfid, u8 *addr);
-/** Set mac address in firmware.
+/**
+ * octep_ctrl_net_set_mac_addr() - Set mac address in firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param addr: non-null pointer to mac address.
- * @param wait_for_response: poll for response.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @addr: non-null pointer to mac address.
+ * @wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_set_mac_addr(struct octep_device *oct, int vfid, u8 *addr,
bool wait_for_response);
-/** Set mtu in firmware.
+/**
+ * octep_ctrl_net_get_mtu() - Get max MTU from firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param mtu: mtu.
- * @param wait_for_response: poll for response.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ *
+ * return value: mtu on success, -errno on failure.
+ */
+int octep_ctrl_net_get_mtu(struct octep_device *oct, int vfid);
+
+/**
+ * octep_ctrl_net_set_mtu() - Set mtu in firmware.
+ *
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @mtu: mtu.
+ * @wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_set_mtu(struct octep_device *oct, int vfid, int mtu,
bool wait_for_response);
-/** Get interface statistics from firmware.
+/**
+ * octep_ctrl_net_get_if_stats() - Get interface statistics from firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param rx_stats: non-null pointer struct octep_iface_rx_stats.
- * @param tx_stats: non-null pointer struct octep_iface_tx_stats.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @rx_stats: non-null pointer struct octep_iface_rx_stats.
+ * @tx_stats: non-null pointer struct octep_iface_tx_stats.
*
* return value: 0 on success, -errno on failure.
*/
@@ -306,23 +348,25 @@ int octep_ctrl_net_get_if_stats(struct octep_device *oct, int vfid,
struct octep_iface_rx_stats *rx_stats,
struct octep_iface_tx_stats *tx_stats);
-/** Get link info from firmware.
+/**
+ * octep_ctrl_net_get_link_info() - Get link info from firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param link_info: non-null pointer to struct octep_iface_link_info.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @link_info: non-null pointer to struct octep_iface_link_info.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_get_link_info(struct octep_device *oct, int vfid,
struct octep_iface_link_info *link_info);
-/** Set link info in firmware.
+/**
+ * octep_ctrl_net_set_link_info() - Set link info in firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param link_info: non-null pointer to struct octep_iface_link_info.
- * @param wait_for_response: poll for response.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @link_info: non-null pointer to struct octep_iface_link_info.
+ * @wait_for_response: poll for response.
*
* return value: 0 on success, -errno on failure.
*/
@@ -331,26 +375,53 @@ int octep_ctrl_net_set_link_info(struct octep_device *oct,
struct octep_iface_link_info *link_info,
bool wait_for_response);
-/** Poll for firmware messages and process them.
+/**
+ * octep_ctrl_net_recv_fw_messages() - Poll for firmware messages and process them.
*
- * @param oct: non-null pointer to struct octep_device.
+ * @oct: non-null pointer to struct octep_device.
*/
void octep_ctrl_net_recv_fw_messages(struct octep_device *oct);
-/** Get info from firmware.
+/**
+ * octep_ctrl_net_get_info() - Get info from firmware.
*
- * @param oct: non-null pointer to struct octep_device.
- * @param vfid: Index of virtual function.
- * @param info: non-null pointer to struct octep_fw_info.
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @info: non-null pointer to struct octep_fw_info.
*
* return value: 0 on success, -errno on failure.
*/
int octep_ctrl_net_get_info(struct octep_device *oct, int vfid,
struct octep_fw_info *info);
-/** Uninitialize data for ctrl net.
+/**
+ * octep_ctrl_net_dev_remove() - Indicate to firmware that a device unload has happened.
+ *
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ *
+ * return value: 0 on success, -errno on failure.
+ */
+int octep_ctrl_net_dev_remove(struct octep_device *oct, int vfid);
+
+/**
+ * octep_ctrl_net_set_offloads() - Set offloads in firmware.
+ *
+ * @oct: non-null pointer to struct octep_device.
+ * @vfid: Index of virtual function.
+ * @offloads: non-null pointer to struct octep_ctrl_net_offloads.
+ * @wait_for_response: poll for response.
+ *
+ * return value: 0 on success, -errno on failure.
+ */
+int octep_ctrl_net_set_offloads(struct octep_device *oct, int vfid,
+ struct octep_ctrl_net_offloads *offloads,
+ bool wait_for_response);
+
+/**
+ * octep_ctrl_net_uninit() - Uninitialize data for ctrl net.
*
- * @param oct: non-null pointer to struct octep_device.
+ * @oct: non-null pointer to struct octep_device.
*
* return value: 0 on success, -errno on error.
*/
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
index a9bdf3283a85..7c9faa714a10 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
@@ -16,14 +16,20 @@
#include "octep_config.h"
#include "octep_main.h"
#include "octep_ctrl_net.h"
+#include "octep_pfvf_mbox.h"
#define OCTEP_INTR_POLL_TIME_MSECS 100
struct workqueue_struct *octep_wq;
/* Supported Devices */
static const struct pci_device_id octep_pci_id_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN98_PF)},
{PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN93_PF)},
{PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF95N_PF)},
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KA_PF)},
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KA_PF)},
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CNF10KB_PF)},
+ {PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, OCTEP_PCI_DEVICE_ID_CN10KB_PF)},
{0, },
};
MODULE_DEVICE_TABLE(pci, octep_pci_id_tbl);
@@ -155,6 +161,21 @@ static void octep_disable_msix(struct octep_device *oct)
}
/**
+ * octep_mbox_intr_handler() - common handler for pfvf mbox interrupts.
+ *
+ * @irq: Interrupt number.
+ * @data: interrupt data.
+ *
+ * this is common handler for pfvf mbox interrupts.
+ */
+static irqreturn_t octep_mbox_intr_handler(int irq, void *data)
+{
+ struct octep_device *oct = data;
+
+ return oct->hw_ops.mbox_intr_handler(oct);
+}
+
+/**
* octep_oei_intr_handler() - common handler for output endpoint interrupts.
*
* @irq: Interrupt number.
@@ -357,8 +378,12 @@ static int octep_request_irqs(struct octep_device *oct)
snprintf(irq_name, OCTEP_MSIX_NAME_SIZE,
"%s-%s", netdev->name, non_ioq_msix_names[i]);
- if (!strncmp(non_ioq_msix_names[i], "epf_oei_rint",
- strlen("epf_oei_rint"))) {
+ if (!strncmp(non_ioq_msix_names[i], "epf_mbox_rint", strlen("epf_mbox_rint"))) {
+ ret = request_irq(msix_entry->vector,
+ octep_mbox_intr_handler, 0,
+ irq_name, oct);
+ } else if (!strncmp(non_ioq_msix_names[i], "epf_oei_rint",
+ strlen("epf_oei_rint"))) {
ret = request_irq(msix_entry->vector,
octep_oei_intr_handler, 0,
irq_name, oct);
@@ -777,17 +802,24 @@ static int octep_stop(struct net_device *netdev)
*/
static inline int octep_iq_full_check(struct octep_iq *iq)
{
- if (likely((iq->max_count - atomic_read(&iq->instr_pending)) >=
+ if (likely((IQ_INSTR_SPACE(iq)) >
OCTEP_WAKE_QUEUE_THRESHOLD))
return 0;
/* Stop the queue if unable to send */
netif_stop_subqueue(iq->netdev, iq->q_no);
+ /* Allow for pending updates in write index
+ * from iq_process_completion in other cpus
+ * to reflect, in case queue gets free
+ * entries.
+ */
+ smp_mb();
+
/* check again and restart the queue, in case NAPI has just freed
* enough Tx ring entries.
*/
- if (unlikely((iq->max_count - atomic_read(&iq->instr_pending)) >=
+ if (unlikely(IQ_INSTR_SPACE(iq) >
OCTEP_WAKE_QUEUE_THRESHOLD)) {
netif_start_subqueue(iq->netdev, iq->q_no);
iq->stats.restart_cnt++;
@@ -810,6 +842,7 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct octep_device *oct = netdev_priv(netdev);
+ netdev_features_t feat = netdev->features;
struct octep_tx_sglist_desc *sglist;
struct octep_tx_buffer *tx_buffer;
struct octep_tx_desc_hw *hw_desc;
@@ -818,8 +851,12 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
struct octep_iq *iq;
skb_frag_t *frag;
u16 nr_frags, si;
+ int xmit_more;
u16 q_no, wi;
+ if (skb_put_padto(skb, ETH_ZLEN))
+ return NETDEV_TX_OK;
+
q_no = skb_get_queue_mapping(skb);
if (q_no >= oct->num_iqs) {
netdev_err(netdev, "Invalid Tx skb->queue_mapping=%d\n", q_no);
@@ -827,10 +864,6 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
}
iq = oct->iq[q_no];
- if (octep_iq_full_check(iq)) {
- iq->stats.tx_busy++;
- return NETDEV_TX_BUSY;
- }
shinfo = skb_shinfo(skb);
nr_frags = shinfo->nr_frags;
@@ -843,8 +876,9 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
tx_buffer->skb = skb;
ih = &hw_desc->ih;
- ih->tlen = skb->len;
- ih->pkind = oct->pkind;
+ ih->pkind = oct->conf->fw_info.pkind;
+ ih->fsz = oct->conf->fw_info.fsz;
+ ih->tlen = skb->len + ih->fsz;
if (!nr_frags) {
tx_buffer->gather = 0;
@@ -869,9 +903,6 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
if (dma_mapping_error(iq->dev, dma))
goto dma_map_err;
- dma_sync_single_for_cpu(iq->dev, tx_buffer->sglist_dma,
- OCTEP_SGLIST_SIZE_PER_PKT,
- DMA_TO_DEVICE);
memset(sglist, 0, OCTEP_SGLIST_SIZE_PER_PKT);
sglist[0].len[3] = len;
sglist[0].dma_ptr[0] = dma;
@@ -891,26 +922,46 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb,
frag++;
si++;
}
- dma_sync_single_for_device(iq->dev, tx_buffer->sglist_dma,
- OCTEP_SGLIST_SIZE_PER_PKT,
- DMA_TO_DEVICE);
-
hw_desc->dptr = tx_buffer->sglist_dma;
}
- netdev_tx_sent_queue(iq->netdev_q, skb->len);
+ if (oct->conf->fw_info.tx_ol_flags) {
+ if ((feat & (NETIF_F_TSO)) && (skb_is_gso(skb))) {
+ hw_desc->txm.ol_flags = OCTEP_TX_OFFLOAD_CKSUM;
+ hw_desc->txm.ol_flags |= OCTEP_TX_OFFLOAD_TSO;
+ hw_desc->txm.gso_size = skb_shinfo(skb)->gso_size;
+ hw_desc->txm.gso_segs = skb_shinfo(skb)->gso_segs;
+ } else if (feat & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) {
+ hw_desc->txm.ol_flags = OCTEP_TX_OFFLOAD_CKSUM;
+ }
+ /* due to ESR txm will be swapped by hw */
+ hw_desc->txm64[0] = (__force u64)cpu_to_be64(hw_desc->txm64[0]);
+ }
+
+ xmit_more = netdev_xmit_more();
+
+ __netdev_tx_sent_queue(iq->netdev_q, skb->len, xmit_more);
+
skb_tx_timestamp(skb);
- atomic_inc(&iq->instr_pending);
+ iq->fill_cnt++;
wi++;
- if (wi == iq->max_count)
- wi = 0;
- iq->host_write_index = wi;
+ iq->host_write_index = wi & iq->ring_size_mask;
+
+ /* octep_iq_full_check stops the queue and returns
+ * true if so, in case the queue has become full
+ * by inserting current packet. If so, we can
+ * go ahead and ring doorbell.
+ */
+ if (!octep_iq_full_check(iq) && xmit_more &&
+ iq->fill_cnt < iq->fill_threshold)
+ return NETDEV_TX_OK;
+
/* Flush the hw descriptor before writing to doorbell */
wmb();
-
- /* Ring Doorbell to notify the NIC there is a new packet */
- writel(1, iq->doorbell_reg);
- iq->stats.instr_posted++;
+ /* Ring Doorbell to notify the NIC of new packets */
+ writel(iq->fill_cnt, iq->doorbell_reg);
+ iq->stats.instr_posted += iq->fill_cnt;
+ iq->fill_cnt = 0;
return NETDEV_TX_OK;
dma_map_sg_err:
@@ -1051,6 +1102,41 @@ static int octep_change_mtu(struct net_device *netdev, int new_mtu)
return err;
}
+static int octep_set_features(struct net_device *dev, netdev_features_t features)
+{
+ struct octep_ctrl_net_offloads offloads = { 0 };
+ struct octep_device *oct = netdev_priv(dev);
+ int err;
+
+ /* We only support features received from firmware */
+ if ((features & dev->hw_features) != features)
+ return -EINVAL;
+
+ if (features & NETIF_F_TSO)
+ offloads.tx_offloads |= OCTEP_TX_OFFLOAD_TSO;
+
+ if (features & NETIF_F_TSO6)
+ offloads.tx_offloads |= OCTEP_TX_OFFLOAD_TSO;
+
+ if (features & NETIF_F_IP_CSUM)
+ offloads.tx_offloads |= OCTEP_TX_OFFLOAD_CKSUM;
+
+ if (features & NETIF_F_IPV6_CSUM)
+ offloads.tx_offloads |= OCTEP_TX_OFFLOAD_CKSUM;
+
+ if (features & NETIF_F_RXCSUM)
+ offloads.rx_offloads |= OCTEP_RX_OFFLOAD_CKSUM;
+
+ err = octep_ctrl_net_set_offloads(oct,
+ OCTEP_CTRL_NET_INVALID_VFID,
+ &offloads,
+ true);
+ if (!err)
+ dev->features = features;
+
+ return err;
+}
+
static const struct net_device_ops octep_netdev_ops = {
.ndo_open = octep_open,
.ndo_stop = octep_stop,
@@ -1059,6 +1145,7 @@ static const struct net_device_ops octep_netdev_ops = {
.ndo_tx_timeout = octep_tx_timeout,
.ndo_set_mac_address = octep_set_mac,
.ndo_change_mtu = octep_change_mtu,
+ .ndo_set_features = octep_set_features,
};
/**
@@ -1132,10 +1219,20 @@ static void octep_ctrl_mbox_task(struct work_struct *work)
static const char *octep_devid_to_str(struct octep_device *oct)
{
switch (oct->chip_id) {
+ case OCTEP_PCI_DEVICE_ID_CN98_PF:
+ return "CN98XX";
case OCTEP_PCI_DEVICE_ID_CN93_PF:
return "CN93XX";
case OCTEP_PCI_DEVICE_ID_CNF95N_PF:
return "CNF95N";
+ case OCTEP_PCI_DEVICE_ID_CN10KA_PF:
+ return "CN10KA";
+ case OCTEP_PCI_DEVICE_ID_CNF10KA_PF:
+ return "CNF10KA";
+ case OCTEP_PCI_DEVICE_ID_CNF10KB_PF:
+ return "CNF10KB";
+ case OCTEP_PCI_DEVICE_ID_CN10KB_PF:
+ return "CN10KB";
default:
return "Unsupported";
}
@@ -1174,6 +1271,7 @@ int octep_device_setup(struct octep_device *oct)
dev_info(&pdev->dev, "chip_id = 0x%x\n", pdev->device);
switch (oct->chip_id) {
+ case OCTEP_PCI_DEVICE_ID_CN98_PF:
case OCTEP_PCI_DEVICE_ID_CN93_PF:
case OCTEP_PCI_DEVICE_ID_CNF95N_PF:
dev_info(&pdev->dev, "Setting up OCTEON %s PF PASS%d.%d\n",
@@ -1181,13 +1279,20 @@ int octep_device_setup(struct octep_device *oct)
OCTEP_MINOR_REV(oct));
octep_device_setup_cn93_pf(oct);
break;
+ case OCTEP_PCI_DEVICE_ID_CNF10KA_PF:
+ case OCTEP_PCI_DEVICE_ID_CN10KA_PF:
+ case OCTEP_PCI_DEVICE_ID_CNF10KB_PF:
+ case OCTEP_PCI_DEVICE_ID_CN10KB_PF:
+ dev_info(&pdev->dev, "Setting up OCTEON %s PF PASS%d.%d\n",
+ octep_devid_to_str(oct), OCTEP_MAJOR_REV(oct), OCTEP_MINOR_REV(oct));
+ octep_device_setup_cnxk_pf(oct);
+ break;
default:
dev_err(&pdev->dev,
"%s: unsupported device\n", __func__);
goto unsupported_dev;
}
- oct->pkind = CFG_GET_IQ_PKIND(oct->conf);
ret = octep_ctrl_net_init(oct);
if (ret)
@@ -1237,6 +1342,7 @@ static void octep_device_cleanup(struct octep_device *oct)
oct->mbox[i] = NULL;
}
+ octep_delete_pfvf_mbox(oct);
octep_ctrl_net_uninit(oct);
cancel_delayed_work_sync(&oct->hb_task);
@@ -1284,6 +1390,7 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct octep_device *octep_dev = NULL;
struct net_device *netdev;
+ int max_rx_pktlen;
int err;
err = pci_enable_device(pdev);
@@ -1333,6 +1440,12 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_octep_config;
}
+ err = octep_setup_pfvf_mbox(octep_dev);
+ if (err) {
+ dev_err(&pdev->dev, "PF-VF mailbox setup failed\n");
+ goto register_dev_err;
+ }
+
err = octep_ctrl_net_get_info(octep_dev, OCTEP_CTRL_NET_INVALID_VFID,
&octep_dev->conf->fw_info);
if (err) {
@@ -1350,11 +1463,29 @@ static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netif_carrier_off(netdev);
netdev->hw_features = NETIF_F_SG;
- netdev->features |= netdev->hw_features;
+ if (OCTEP_TX_IP_CSUM(octep_dev->conf->fw_info.tx_ol_flags))
+ netdev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+
+ if (OCTEP_RX_IP_CSUM(octep_dev->conf->fw_info.rx_ol_flags))
+ netdev->hw_features |= NETIF_F_RXCSUM;
+
+ max_rx_pktlen = octep_ctrl_net_get_mtu(octep_dev, OCTEP_CTRL_NET_INVALID_VFID);
+ if (max_rx_pktlen < 0) {
+ dev_err(&octep_dev->pdev->dev,
+ "Failed to get max receive packet size; err = %d\n", max_rx_pktlen);
+ err = max_rx_pktlen;
+ goto register_dev_err;
+ }
netdev->min_mtu = OCTEP_MIN_MTU;
- netdev->max_mtu = OCTEP_MAX_MTU;
+ netdev->max_mtu = max_rx_pktlen - (ETH_HLEN + ETH_FCS_LEN);
netdev->mtu = OCTEP_DEFAULT_MTU;
+ if (OCTEP_TX_TSO(octep_dev->conf->fw_info.tx_ol_flags)) {
+ netdev->hw_features |= NETIF_F_TSO;
+ netif_set_tso_max_size(netdev, netdev->max_mtu);
+ }
+
+ netdev->features |= netdev->hw_features;
err = octep_ctrl_net_get_mac_addr(octep_dev, OCTEP_CTRL_NET_INVALID_VFID,
octep_dev->mac_addr);
if (err) {
@@ -1383,6 +1514,21 @@ err_dma_mask:
return err;
}
+static int octep_sriov_disable(struct octep_device *oct)
+{
+ struct pci_dev *pdev = oct->pdev;
+
+ if (pci_vfs_assigned(oct->pdev)) {
+ dev_warn(&pdev->dev, "Can't disable SRIOV while VFs are assigned\n");
+ return -EPERM;
+ }
+
+ pci_disable_sriov(pdev);
+ CFG_GET_ACTIVE_VFS(oct->conf) = 0;
+
+ return 0;
+}
+
/**
* octep_remove() - Remove Octeon PCI device from driver control.
*
@@ -1400,6 +1546,7 @@ static void octep_remove(struct pci_dev *pdev)
return;
netdev = oct->netdev;
+ octep_sriov_disable(oct);
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
@@ -1410,11 +1557,47 @@ static void octep_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
+static int octep_sriov_enable(struct octep_device *oct, int num_vfs)
+{
+ struct pci_dev *pdev = oct->pdev;
+ int err;
+
+ CFG_GET_ACTIVE_VFS(oct->conf) = num_vfs;
+ err = pci_enable_sriov(pdev, num_vfs);
+ if (err) {
+ dev_warn(&pdev->dev, "Failed to enable SRIOV err=%d\n", err);
+ CFG_GET_ACTIVE_VFS(oct->conf) = 0;
+ return err;
+ }
+
+ return num_vfs;
+}
+
+static int octep_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ struct octep_device *oct = pci_get_drvdata(pdev);
+ int max_nvfs;
+
+ if (num_vfs == 0)
+ return octep_sriov_disable(oct);
+
+ max_nvfs = CFG_GET_MAX_VFS(oct->conf);
+
+ if (num_vfs > max_nvfs) {
+ dev_err(&pdev->dev, "Invalid VF count Max supported VFs = %d\n",
+ max_nvfs);
+ return -EINVAL;
+ }
+
+ return octep_sriov_enable(oct, num_vfs);
+}
+
static struct pci_driver octep_driver = {
.name = OCTEP_DRV_NAME,
.id_table = octep_pci_id_tbl,
.probe = octep_probe,
.remove = octep_remove,
+ .sriov_configure = octep_sriov_configure,
};
/**
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
index 6df902ebb7f3..fee59e0e0138 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
@@ -18,11 +18,17 @@
#define OCTEP_PCIID_CN93_PF 0xB200177d
#define OCTEP_PCIID_CN93_VF 0xB203177d
+#define OCTEP_PCI_DEVICE_ID_CN98_PF 0xB100
#define OCTEP_PCI_DEVICE_ID_CN93_PF 0xB200
#define OCTEP_PCI_DEVICE_ID_CN93_VF 0xB203
#define OCTEP_PCI_DEVICE_ID_CNF95N_PF 0xB400 //95N PF
+#define OCTEP_PCI_DEVICE_ID_CN10KA_PF 0xB900 //CN10KA PF
+#define OCTEP_PCI_DEVICE_ID_CNF10KA_PF 0xBA00 //CNF10KA PF
+#define OCTEP_PCI_DEVICE_ID_CNF10KB_PF 0xBC00 //CNF10KB PF
+#define OCTEP_PCI_DEVICE_ID_CN10KB_PF 0xBD00 //CN10KB PF
+
#define OCTEP_MAX_QUEUES 63
#define OCTEP_MAX_IQ OCTEP_MAX_QUEUES
#define OCTEP_MAX_OQ OCTEP_MAX_QUEUES
@@ -40,6 +46,15 @@
#define OCTEP_OQ_INTR_RESEND_BIT 59
#define OCTEP_MMIO_REGIONS 3
+
+#define IQ_INSTR_PENDING(iq) ({ typeof(iq) iq__ = (iq); \
+ ((iq__)->host_write_index - (iq__)->flush_index) & \
+ (iq__)->ring_size_mask; \
+ })
+#define IQ_INSTR_SPACE(iq) ({ typeof(iq) iq_ = (iq); \
+ (iq_)->max_count - IQ_INSTR_PENDING(iq_); \
+ })
+
/* PCI address space mapping information.
* Each of the 3 address spaces given by BAR0, BAR2 and BAR4 of
* Octeon gets mapped to different physical address spaces in
@@ -65,6 +80,7 @@ struct octep_hw_ops {
void (*setup_oq_regs)(struct octep_device *oct, int q);
void (*setup_mbox_regs)(struct octep_device *oct, int mbox);
+ irqreturn_t (*mbox_intr_handler)(void *ioq_vector);
irqreturn_t (*oei_intr_handler)(void *ioq_vector);
irqreturn_t (*ire_intr_handler)(void *ioq_vector);
irqreturn_t (*ore_intr_handler)(void *ioq_vector);
@@ -103,28 +119,27 @@ struct octep_mbox_data {
u64 *data;
};
+#define MAX_VF_PF_MBOX_DATA_SIZE 384
+/* wrappers around work structs */
+struct octep_pfvf_mbox_wk {
+ struct work_struct work;
+ void *ctxptr;
+ u64 ctxul;
+};
+
/* Octeon device mailbox */
struct octep_mbox {
- /* A spinlock to protect access to this q_mbox. */
- spinlock_t lock;
-
- u32 q_no;
- u32 state;
-
- /* SLI_MAC_PF_MBOX_INT for PF, SLI_PKT_MBOX_INT for VF. */
- u8 __iomem *mbox_int_reg;
-
- /* SLI_PKT_PF_VF_MBOX_SIG(0) for PF,
- * SLI_PKT_PF_VF_MBOX_SIG(1) for VF.
- */
- u8 __iomem *mbox_write_reg;
-
- /* SLI_PKT_PF_VF_MBOX_SIG(1) for PF,
- * SLI_PKT_PF_VF_MBOX_SIG(0) for VF.
- */
- u8 __iomem *mbox_read_reg;
-
+ /* A mutex to protect access to this q_mbox. */
+ struct mutex lock;
+ u32 vf_id;
+ u32 config_data_index;
+ u32 message_len;
+ u8 __iomem *pf_vf_data_reg;
+ u8 __iomem *vf_pf_data_reg;
+ struct octep_pfvf_mbox_wk wk;
+ struct octep_device *oct;
struct octep_mbox_data mbox_data;
+ u8 config_data[MAX_VF_PF_MBOX_DATA_SIZE];
};
/* Tx/Rx queue vector per interrupt. */
@@ -202,6 +217,12 @@ struct octep_iface_link_info {
u8 oper_up;
};
+/* The Octeon VF device specific info data structure.*/
+struct octep_pfvf_info {
+ u8 mac_addr[ETH_ALEN];
+ u32 mbox_version;
+};
+
/* The Octeon device specific private data structure.
* Each Octeon device has this structure to represent all its components.
*/
@@ -232,8 +253,7 @@ struct octep_device {
/* Tx queues (IQ: Instruction Queue) */
u16 num_iqs;
- /* pkind value to be used in every Tx hardware descriptor */
- u8 pkind;
+
/* Pointers to Octeon Tx queues */
struct octep_iq *iq[OCTEP_MAX_IQ];
@@ -268,6 +288,8 @@ struct octep_device {
/* Mailbox to talk to VFs */
struct octep_mbox *mbox[OCTEP_MAX_VF];
+ /* VFs info */
+ struct octep_pfvf_info vf_info[OCTEP_MAX_VF];
/* Work entry to handle Tx timeout */
struct work_struct tx_timeout_task;
@@ -377,6 +399,7 @@ int octep_setup_oqs(struct octep_device *oct);
void octep_free_oqs(struct octep_device *oct);
void octep_oq_dbell_init(struct octep_device *oct);
void octep_device_setup_cn93_pf(struct octep_device *oct);
+void octep_device_setup_cnxk_pf(struct octep_device *oct);
int octep_iq_process_completions(struct octep_iq *iq, u16 budget);
int octep_oq_process_rx(struct octep_oq *oq, int budget);
void octep_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c
new file mode 100644
index 000000000000..2e2c3be8a0b4
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c
@@ -0,0 +1,449 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
+ *
+ * Copyright (C) 2020 Marvell.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+
+#include "octep_config.h"
+#include "octep_main.h"
+#include "octep_pfvf_mbox.h"
+#include "octep_ctrl_net.h"
+
+/* When a new command is implemented, the below table should be updated
+ * with new command and it's version info.
+ */
+static u32 pfvf_cmd_versions[OCTEP_PFVF_MBOX_CMD_MAX] = {
+ [0 ... OCTEP_PFVF_MBOX_CMD_DEV_REMOVE] = OCTEP_PFVF_MBOX_VERSION_V1,
+ [OCTEP_PFVF_MBOX_CMD_GET_FW_INFO ... OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS] =
+ OCTEP_PFVF_MBOX_VERSION_V2
+};
+
+static void octep_pfvf_validate_version(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ u32 vf_version = (u32)cmd.s_version.version;
+
+ dev_dbg(&oct->pdev->dev, "VF id:%d VF version:%d PF version:%d\n",
+ vf_id, vf_version, OCTEP_PFVF_MBOX_VERSION_CURRENT);
+ if (vf_version < OCTEP_PFVF_MBOX_VERSION_CURRENT)
+ rsp->s_version.version = vf_version;
+ else
+ rsp->s_version.version = OCTEP_PFVF_MBOX_VERSION_CURRENT;
+
+ oct->vf_info[vf_id].mbox_version = rsp->s_version.version;
+ dev_dbg(&oct->pdev->dev, "VF id:%d negotiated VF version:%d\n",
+ vf_id, oct->vf_info[vf_id].mbox_version);
+
+ rsp->s_version.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_get_link_status(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int status;
+
+ status = octep_ctrl_net_get_link_status(oct, vf_id);
+ if (status < 0) {
+ rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Get VF link status failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+ rsp->s_link_status.status = status;
+}
+
+static void octep_pfvf_set_link_status(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int err;
+
+ err = octep_ctrl_net_set_link_status(oct, vf_id, cmd.s_link_status.status, true);
+ if (err) {
+ rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Set VF link status failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_set_rx_state(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int err;
+
+ err = octep_ctrl_net_set_rx_state(oct, vf_id, cmd.s_link_state.state, true);
+ if (err) {
+ rsp->s_link_state.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Set VF Rx link state failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_link_state.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static int octep_send_notification(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd)
+{
+ u32 max_rings_per_vf, vf_mbox_queue;
+ struct octep_mbox *mbox;
+
+ /* check if VF PF Mailbox is compatible for this notification */
+ if (pfvf_cmd_versions[cmd.s.opcode] > oct->vf_info[vf_id].mbox_version) {
+ dev_dbg(&oct->pdev->dev, "VF Mbox doesn't support Notification:%d on VF ver:%d\n",
+ cmd.s.opcode, oct->vf_info[vf_id].mbox_version);
+ return -EOPNOTSUPP;
+ }
+
+ max_rings_per_vf = CFG_GET_MAX_RPVF(oct->conf);
+ vf_mbox_queue = vf_id * max_rings_per_vf;
+ if (!oct->mbox[vf_mbox_queue]) {
+ dev_err(&oct->pdev->dev, "Notif obtained for bad mbox vf %d\n", vf_id);
+ return -EINVAL;
+ }
+ mbox = oct->mbox[vf_mbox_queue];
+
+ mutex_lock(&mbox->lock);
+ writeq(cmd.u64, mbox->pf_vf_data_reg);
+ mutex_unlock(&mbox->lock);
+
+ return 0;
+}
+
+static void octep_pfvf_set_mtu(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int err;
+
+ err = octep_ctrl_net_set_mtu(oct, vf_id, cmd.s_set_mtu.mtu, true);
+ if (err) {
+ rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Set VF MTU failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_get_mtu(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int max_rx_pktlen = oct->netdev->max_mtu + (ETH_HLEN + ETH_FCS_LEN);
+
+ rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+ rsp->s_get_mtu.mtu = max_rx_pktlen;
+}
+
+static void octep_pfvf_set_mac_addr(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int err;
+
+ err = octep_ctrl_net_set_mac_addr(oct, vf_id, cmd.s_set_mac.mac_addr, true);
+ if (err) {
+ rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Set VF MAC address failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_get_mac_addr(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int err;
+
+ err = octep_ctrl_net_get_mac_addr(oct, vf_id, rsp->s_set_mac.mac_addr);
+ if (err) {
+ rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Get VF MAC address failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_dev_remove(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int err;
+
+ err = octep_ctrl_net_dev_remove(oct, vf_id);
+ if (err) {
+ rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Failed to acknowledge fw of vf %d removal\n",
+ vf_id);
+ return;
+ }
+ rsp->s.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_get_fw_info(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ struct octep_fw_info fw_info;
+ int err;
+
+ err = octep_ctrl_net_get_info(oct, vf_id, &fw_info);
+ if (err) {
+ rsp->s_fw_info.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Get VF info failed via host control Mbox\n");
+ return;
+ }
+
+ rsp->s_fw_info.pkind = fw_info.pkind;
+ rsp->s_fw_info.fsz = fw_info.fsz;
+ rsp->s_fw_info.rx_ol_flags = fw_info.rx_ol_flags;
+ rsp->s_fw_info.tx_ol_flags = fw_info.tx_ol_flags;
+
+ rsp->s_fw_info.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_set_offloads(struct octep_device *oct, u32 vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ struct octep_ctrl_net_offloads offloads = {
+ .rx_offloads = cmd.s_offloads.rx_ol_flags,
+ .tx_offloads = cmd.s_offloads.tx_ol_flags
+ };
+ int err;
+
+ err = octep_ctrl_net_set_offloads(oct, vf_id, &offloads, true);
+ if (err) {
+ rsp->s_offloads.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ dev_err(&oct->pdev->dev, "Set VF offloads failed via host control Mbox\n");
+ return;
+ }
+ rsp->s_offloads.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+int octep_setup_pfvf_mbox(struct octep_device *oct)
+{
+ int i = 0, num_vfs = 0, rings_per_vf = 0;
+ int ring = 0;
+
+ num_vfs = oct->conf->sriov_cfg.active_vfs;
+ rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;
+
+ for (i = 0; i < num_vfs; i++) {
+ ring = rings_per_vf * i;
+ oct->mbox[ring] = vzalloc(sizeof(*oct->mbox[ring]));
+
+ if (!oct->mbox[ring])
+ goto free_mbox;
+
+ memset(oct->mbox[ring], 0, sizeof(struct octep_mbox));
+ memset(&oct->vf_info[i], 0, sizeof(struct octep_pfvf_info));
+ mutex_init(&oct->mbox[ring]->lock);
+ INIT_WORK(&oct->mbox[ring]->wk.work, octep_pfvf_mbox_work);
+ oct->mbox[ring]->wk.ctxptr = oct->mbox[ring];
+ oct->mbox[ring]->oct = oct;
+ oct->mbox[ring]->vf_id = i;
+ oct->hw_ops.setup_mbox_regs(oct, ring);
+ }
+ return 0;
+
+free_mbox:
+ while (i) {
+ i--;
+ ring = rings_per_vf * i;
+ cancel_work_sync(&oct->mbox[ring]->wk.work);
+ mutex_destroy(&oct->mbox[ring]->lock);
+ vfree(oct->mbox[ring]);
+ oct->mbox[ring] = NULL;
+ }
+ return -ENOMEM;
+}
+
+void octep_delete_pfvf_mbox(struct octep_device *oct)
+{
+ int rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;
+ int num_vfs = oct->conf->sriov_cfg.active_vfs;
+ int i = 0, ring = 0, vf_srn = 0;
+
+ for (i = 0; i < num_vfs; i++) {
+ ring = vf_srn + rings_per_vf * i;
+ if (!oct->mbox[ring])
+ continue;
+
+ if (work_pending(&oct->mbox[ring]->wk.work))
+ cancel_work_sync(&oct->mbox[ring]->wk.work);
+
+ mutex_destroy(&oct->mbox[ring]->lock);
+ vfree(oct->mbox[ring]);
+ oct->mbox[ring] = NULL;
+ }
+}
+
+static void octep_pfvf_pf_get_data(struct octep_device *oct,
+ struct octep_mbox *mbox, int vf_id,
+ union octep_pfvf_mbox_word cmd,
+ union octep_pfvf_mbox_word *rsp)
+{
+ int length = 0;
+ int i = 0;
+ int err;
+ struct octep_iface_link_info link_info;
+ struct octep_iface_rx_stats rx_stats;
+ struct octep_iface_tx_stats tx_stats;
+
+ rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+
+ if (cmd.s_data.frag != OCTEP_PFVF_MBOX_MORE_FRAG_FLAG) {
+ mbox->config_data_index = 0;
+ memset(mbox->config_data, 0, MAX_VF_PF_MBOX_DATA_SIZE);
+ /* Based on the OPCODE CMD the PF driver
+ * specific API should be called to fetch
+ * the requested data
+ */
+ switch (cmd.s.opcode) {
+ case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:
+ memset(&link_info, 0, sizeof(link_info));
+ err = octep_ctrl_net_get_link_info(oct, vf_id, &link_info);
+ if (!err) {
+ mbox->message_len = sizeof(link_info);
+ *((int32_t *)rsp->s_data.data) = mbox->message_len;
+ memcpy(mbox->config_data, (u8 *)&link_info, sizeof(link_info));
+ } else {
+ rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ return;
+ }
+ break;
+ case OCTEP_PFVF_MBOX_CMD_GET_STATS:
+ memset(&rx_stats, 0, sizeof(rx_stats));
+ memset(&tx_stats, 0, sizeof(tx_stats));
+ err = octep_ctrl_net_get_if_stats(oct, vf_id, &rx_stats, &tx_stats);
+ if (!err) {
+ mbox->message_len = sizeof(rx_stats) + sizeof(tx_stats);
+ *((int32_t *)rsp->s_data.data) = mbox->message_len;
+ memcpy(mbox->config_data, (u8 *)&rx_stats, sizeof(rx_stats));
+ memcpy(mbox->config_data + sizeof(rx_stats), (u8 *)&tx_stats,
+ sizeof(tx_stats));
+
+ } else {
+ rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ return;
+ }
+ break;
+ }
+ *((int32_t *)rsp->s_data.data) = mbox->message_len;
+ return;
+ }
+
+ if (mbox->message_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE)
+ length = OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
+ else
+ length = mbox->message_len;
+
+ mbox->message_len -= length;
+
+ for (i = 0; i < length; i++) {
+ rsp->s_data.data[i] =
+ mbox->config_data[mbox->config_data_index];
+ mbox->config_data_index++;
+ }
+}
+
+void octep_pfvf_notify(struct octep_device *oct, struct octep_ctrl_mbox_msg *msg)
+{
+ union octep_pfvf_mbox_word notif = { 0 };
+ struct octep_ctrl_net_f2h_req *req;
+
+ req = (struct octep_ctrl_net_f2h_req *)msg->sg_list[0].msg;
+ switch (req->hdr.s.cmd) {
+ case OCTEP_CTRL_NET_F2H_CMD_LINK_STATUS:
+ notif.s_link_status.opcode = OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS;
+ notif.s_link_status.status = req->link.state;
+ break;
+ default:
+ pr_info("Unknown mbox notif for vf: %u\n",
+ req->hdr.s.cmd);
+ return;
+ }
+
+ notif.s.type = OCTEP_PFVF_MBOX_TYPE_CMD;
+ octep_send_notification(oct, msg->hdr.s.vf_idx, notif);
+}
+
+void octep_pfvf_mbox_work(struct work_struct *work)
+{
+ struct octep_pfvf_mbox_wk *wk = container_of(work, struct octep_pfvf_mbox_wk, work);
+ union octep_pfvf_mbox_word cmd = { 0 };
+ union octep_pfvf_mbox_word rsp = { 0 };
+ struct octep_mbox *mbox = NULL;
+ struct octep_device *oct = NULL;
+ int vf_id;
+
+ mbox = (struct octep_mbox *)wk->ctxptr;
+ oct = (struct octep_device *)mbox->oct;
+ vf_id = mbox->vf_id;
+
+ mutex_lock(&mbox->lock);
+ cmd.u64 = readq(mbox->vf_pf_data_reg);
+ rsp.u64 = 0;
+
+ switch (cmd.s.opcode) {
+ case OCTEP_PFVF_MBOX_CMD_VERSION:
+ octep_pfvf_validate_version(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS:
+ octep_pfvf_get_link_status(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS:
+ octep_pfvf_set_link_status(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_SET_RX_STATE:
+ octep_pfvf_set_rx_state(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_SET_MTU:
+ octep_pfvf_set_mtu(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR:
+ octep_pfvf_set_mac_addr(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR:
+ octep_pfvf_get_mac_addr(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:
+ case OCTEP_PFVF_MBOX_CMD_GET_STATS:
+ octep_pfvf_pf_get_data(oct, mbox, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_GET_MTU:
+ octep_pfvf_get_mtu(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_DEV_REMOVE:
+ octep_pfvf_dev_remove(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_GET_FW_INFO:
+ octep_pfvf_get_fw_info(oct, vf_id, cmd, &rsp);
+ break;
+ case OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS:
+ octep_pfvf_set_offloads(oct, vf_id, cmd, &rsp);
+ break;
+ default:
+ dev_err(&oct->pdev->dev, "PF-VF mailbox: invalid opcode %d\n", cmd.s.opcode);
+ rsp.s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+ break;
+ }
+ writeq(rsp.u64, mbox->vf_pf_data_reg);
+ mutex_unlock(&mbox->lock);
+}
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h
new file mode 100644
index 000000000000..0dc6eead292a
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
+ *
+ * Copyright (C) 2020 Marvell.
+ *
+ */
+
+#ifndef _OCTEP_PFVF_MBOX_H_
+#define _OCTEP_PFVF_MBOX_H_
+
+/* VF flags */
+#define OCTEON_PFVF_FLAG_MAC_SET_BY_PF BIT_ULL(0) /* PF has set VF MAC address */
+#define OCTEON_SDP_16K_HW_FRS 16380UL
+#define OCTEON_SDP_64K_HW_FRS 65531UL
+
+/* When a new command is implemented,PF Mbox version should be bumped.
+ */
+enum octep_pfvf_mbox_version {
+ OCTEP_PFVF_MBOX_VERSION_V0,
+ OCTEP_PFVF_MBOX_VERSION_V1,
+ OCTEP_PFVF_MBOX_VERSION_V2,
+};
+
+#define OCTEP_PFVF_MBOX_VERSION_CURRENT OCTEP_PFVF_MBOX_VERSION_V2
+
+enum octep_pfvf_mbox_opcode {
+ OCTEP_PFVF_MBOX_CMD_VERSION,
+ OCTEP_PFVF_MBOX_CMD_SET_MTU,
+ OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR,
+ OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR,
+ OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO,
+ OCTEP_PFVF_MBOX_CMD_GET_STATS,
+ OCTEP_PFVF_MBOX_CMD_SET_RX_STATE,
+ OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS,
+ OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS,
+ OCTEP_PFVF_MBOX_CMD_GET_MTU,
+ OCTEP_PFVF_MBOX_CMD_DEV_REMOVE,
+ OCTEP_PFVF_MBOX_CMD_GET_FW_INFO,
+ OCTEP_PFVF_MBOX_CMD_SET_OFFLOADS,
+ OCTEP_PFVF_MBOX_NOTIF_LINK_STATUS,
+ OCTEP_PFVF_MBOX_CMD_MAX,
+};
+
+enum octep_pfvf_mbox_word_type {
+ OCTEP_PFVF_MBOX_TYPE_CMD,
+ OCTEP_PFVF_MBOX_TYPE_RSP_ACK,
+ OCTEP_PFVF_MBOX_TYPE_RSP_NACK,
+};
+
+enum octep_pfvf_mbox_cmd_status {
+ OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP = 1,
+ OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT = 2,
+ OCTEP_PFVF_MBOX_CMD_STATUS_NACK = 3,
+ OCTEP_PFVF_MBOX_CMD_STATUS_BUSY = 4
+};
+
+enum octep_pfvf_mbox_state {
+ OCTEP_PFVF_MBOX_STATE_IDLE = 0,
+ OCTEP_PFVF_MBOX_STATE_BUSY = 1,
+};
+
+enum octep_pfvf_link_status {
+ OCTEP_PFVF_LINK_STATUS_DOWN,
+ OCTEP_PFVF_LINK_STATUS_UP,
+};
+
+enum octep_pfvf_link_speed {
+ OCTEP_PFVF_LINK_SPEED_NONE,
+ OCTEP_PFVF_LINK_SPEED_1000,
+ OCTEP_PFVF_LINK_SPEED_10000,
+ OCTEP_PFVF_LINK_SPEED_25000,
+ OCTEP_PFVF_LINK_SPEED_40000,
+ OCTEP_PFVF_LINK_SPEED_50000,
+ OCTEP_PFVF_LINK_SPEED_100000,
+ OCTEP_PFVF_LINK_SPEED_LAST,
+};
+
+enum octep_pfvf_link_duplex {
+ OCTEP_PFVF_LINK_HALF_DUPLEX,
+ OCTEP_PFVF_LINK_FULL_DUPLEX,
+};
+
+enum octep_pfvf_link_autoneg {
+ OCTEP_PFVF_LINK_AUTONEG,
+ OCTEP_PFVF_LINK_FIXED,
+};
+
+#define OCTEP_PFVF_MBOX_TIMEOUT_MS 500
+#define OCTEP_PFVF_MBOX_MAX_RETRIES 2
+#define OCTEP_PFVF_MBOX_MAX_DATA_SIZE 6
+#define OCTEP_PFVF_MBOX_MORE_FRAG_FLAG 1
+#define OCTEP_PFVF_MBOX_WRITE_WAIT_TIME msecs_to_jiffies(1)
+
+union octep_pfvf_mbox_word {
+ u64 u64;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 rsvd:6;
+ u64 data:48;
+ } s;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 frag:1;
+ u64 rsvd:5;
+ u8 data[6];
+ } s_data;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 rsvd:6;
+ u64 version:48;
+ } s_version;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 rsvd:6;
+ u8 mac_addr[6];
+ } s_set_mac;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 rsvd:6;
+ u64 mtu:48;
+ } s_set_mtu;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 rsvd:6;
+ u64 mtu:48;
+ } s_get_mtu;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 state:1;
+ u64 rsvd:53;
+ } s_link_state;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 status:1;
+ u64 rsvd:53;
+ } s_link_status;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 pkind:8;
+ u64 fsz:8;
+ u64 rx_ol_flags:16;
+ u64 tx_ol_flags:16;
+ u64 rsvd:6;
+ } s_fw_info;
+ struct {
+ u64 opcode:8;
+ u64 type:2;
+ u64 rsvd:22;
+ u64 rx_ol_flags:16;
+ u64 tx_ol_flags:16;
+ } s_offloads;
+} __packed;
+
+void octep_pfvf_mbox_work(struct work_struct *work);
+int octep_setup_pfvf_mbox(struct octep_device *oct);
+void octep_delete_pfvf_mbox(struct octep_device *oct);
+void octep_pfvf_notify(struct octep_device *oct, struct octep_ctrl_mbox_msg *msg);
+#endif
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
index 0a43983e9101..ca473502d7a0 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
@@ -208,6 +208,9 @@
#define CN93_SDP_R_MBOX_PF_VF_INT_START 0x10220
#define CN93_SDP_R_MBOX_VF_PF_DATA_START 0x10230
+#define CN93_SDP_MBOX_VF_PF_DATA_START 0x24000
+#define CN93_SDP_MBOX_PF_VF_DATA_START 0x22000
+
#define CN93_SDP_R_MBOX_PF_VF_DATA(ring) \
(CN93_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CN93_RING_OFFSET))
@@ -217,6 +220,12 @@
#define CN93_SDP_R_MBOX_VF_PF_DATA(ring) \
(CN93_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CN93_RING_OFFSET))
+#define CN93_SDP_MBOX_VF_PF_DATA(ring) \
+ (CN93_SDP_MBOX_VF_PF_DATA_START + ((ring) * CN93_EPVF_RING_OFFSET))
+
+#define CN93_SDP_MBOX_PF_VF_DATA(ring) \
+ (CN93_SDP_MBOX_PF_VF_DATA_START + ((ring) * CN93_EPVF_RING_OFFSET))
+
/* ##################### Interrupt Registers ########################## */
#define CN93_SDP_R_ERR_TYPE_START 0x10400
@@ -362,6 +371,10 @@
#define CN93_SDP_MAC_PF_RING_CTL_SRN(val) (((val) >> 8) & 0xFF)
#define CN93_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 16) & 0x3F)
+#define CN98_SDP_MAC_PF_RING_CTL_NPFS(val) (((val) >> 48) & 0xF)
+#define CN98_SDP_MAC_PF_RING_CTL_SRN(val) ((val) & 0xFF)
+#define CN98_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 32) & 0x3F)
+
/* Number of non-queue interrupts in CN93xx */
#define CN93_NUM_NON_IOQ_INTR 16
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h
new file mode 100644
index 000000000000..e637d7c8224d
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cnxk_pf.h
@@ -0,0 +1,416 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
+ *
+ * Copyright (C) 2020 Marvell.
+ *
+ */
+
+#ifndef _OCTEP_REGS_CNXK_PF_H_
+#define _OCTEP_REGS_CNXK_PF_H_
+
+/* ############################ RST ######################### */
+#define CNXK_RST_BOOT 0x000087E006001600ULL
+#define CNXK_RST_CHIP_DOMAIN_W1S 0x000087E006001810ULL
+#define CNXK_RST_CORE_DOMAIN_W1S 0x000087E006001820ULL
+#define CNXK_RST_CORE_DOMAIN_W1C 0x000087E006001828ULL
+
+#define CNXK_CONFIG_XPANSION_BAR 0x38
+#define CNXK_CONFIG_PCIE_CAP 0x70
+#define CNXK_CONFIG_PCIE_DEVCAP 0x74
+#define CNXK_CONFIG_PCIE_DEVCTL 0x78
+#define CNXK_CONFIG_PCIE_LINKCAP 0x7C
+#define CNXK_CONFIG_PCIE_LINKCTL 0x80
+#define CNXK_CONFIG_PCIE_SLOTCAP 0x84
+#define CNXK_CONFIG_PCIE_SLOTCTL 0x88
+
+#define CNXK_PCIE_SRIOV_FDL 0x188 /* 0x98 */
+#define CNXK_PCIE_SRIOV_FDL_BIT_POS 0x10
+#define CNXK_PCIE_SRIOV_FDL_MASK 0xFF
+
+#define CNXK_CONFIG_PCIE_FLTMSK 0x720
+
+/* ################# Offsets of RING, EPF, MAC ######################### */
+#define CNXK_RING_OFFSET (0x1ULL << 17)
+#define CNXK_EPF_OFFSET (0x1ULL << 25)
+#define CNXK_MAC_OFFSET (0x1ULL << 4)
+#define CNXK_BIT_ARRAY_OFFSET (0x1ULL << 4)
+#define CNXK_EPVF_RING_OFFSET (0x1ULL << 4)
+
+/* ################# Scratch Registers ######################### */
+#define CNXK_SDP_EPF_SCRATCH 0x209E0
+
+/* ################# Window Registers ######################### */
+#define CNXK_SDP_WIN_WR_ADDR64 0x20000
+#define CNXK_SDP_WIN_RD_ADDR64 0x20010
+#define CNXK_SDP_WIN_WR_DATA64 0x20020
+#define CNXK_SDP_WIN_WR_MASK_REG 0x20030
+#define CNXK_SDP_WIN_RD_DATA64 0x20040
+
+#define CNXK_SDP_MAC_NUMBER 0x2C100
+
+/* ################# Global Previliged registers ######################### */
+#define CNXK_SDP_EPF_RINFO 0x209F0
+
+#define CNXK_SDP_EPF_RINFO_SRN(val) ((val) & 0x7F)
+#define CNXK_SDP_EPF_RINFO_RPVF(val) (((val) >> 32) & 0xF)
+#define CNXK_SDP_EPF_RINFO_NVFS(val) (((val) >> 48) & 0x7F)
+
+/* SDP Function select */
+#define CNXK_SDP_FUNC_SEL_EPF_BIT_POS 7
+#define CNXK_SDP_FUNC_SEL_FUNC_BIT_POS 0
+
+/* ##### RING IN (Into device from PCI: Tx Ring) REGISTERS #### */
+#define CNXK_SDP_R_IN_CONTROL_START 0x10000
+#define CNXK_SDP_R_IN_ENABLE_START 0x10010
+#define CNXK_SDP_R_IN_INSTR_BADDR_START 0x10020
+#define CNXK_SDP_R_IN_INSTR_RSIZE_START 0x10030
+#define CNXK_SDP_R_IN_INSTR_DBELL_START 0x10040
+#define CNXK_SDP_R_IN_CNTS_START 0x10050
+#define CNXK_SDP_R_IN_INT_LEVELS_START 0x10060
+#define CNXK_SDP_R_IN_PKT_CNT_START 0x10080
+#define CNXK_SDP_R_IN_BYTE_CNT_START 0x10090
+
+#define CNXK_SDP_R_IN_CONTROL(ring) \
+ (CNXK_SDP_R_IN_CONTROL_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_ENABLE(ring) \
+ (CNXK_SDP_R_IN_ENABLE_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_INSTR_BADDR(ring) \
+ (CNXK_SDP_R_IN_INSTR_BADDR_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_INSTR_RSIZE(ring) \
+ (CNXK_SDP_R_IN_INSTR_RSIZE_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_INSTR_DBELL(ring) \
+ (CNXK_SDP_R_IN_INSTR_DBELL_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_CNTS(ring) \
+ (CNXK_SDP_R_IN_CNTS_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_INT_LEVELS(ring) \
+ (CNXK_SDP_R_IN_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_PKT_CNT(ring) \
+ (CNXK_SDP_R_IN_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_BYTE_CNT(ring) \
+ (CNXK_SDP_R_IN_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET))
+
+/* Rings per Virtual Function */
+#define CNXK_R_IN_CTL_RPVF_MASK (0xF)
+#define CNXK_R_IN_CTL_RPVF_POS (48)
+
+/* Number of instructions to be read in one MAC read request.
+ * setting to Max value(4)
+ */
+#define CNXK_R_IN_CTL_IDLE (0x1ULL << 28)
+#define CNXK_R_IN_CTL_RDSIZE (0x3ULL << 25)
+#define CNXK_R_IN_CTL_IS_64B (0x1ULL << 24)
+#define CNXK_R_IN_CTL_D_NSR (0x1ULL << 8)
+#define CNXK_R_IN_CTL_D_ESR (0x1ULL << 6)
+#define CNXK_R_IN_CTL_D_ROR (0x1ULL << 5)
+#define CNXK_R_IN_CTL_NSR (0x1ULL << 3)
+#define CNXK_R_IN_CTL_ESR (0x1ULL << 1)
+#define CNXK_R_IN_CTL_ROR (0x1ULL << 0)
+
+#define CNXK_R_IN_CTL_MASK (CNXK_R_IN_CTL_RDSIZE | CNXK_R_IN_CTL_IS_64B)
+
+/* ##### RING OUT (out from device to PCI host: Rx Ring) REGISTERS #### */
+#define CNXK_SDP_R_OUT_CNTS_START 0x10100
+#define CNXK_SDP_R_OUT_INT_LEVELS_START 0x10110
+#define CNXK_SDP_R_OUT_SLIST_BADDR_START 0x10120
+#define CNXK_SDP_R_OUT_SLIST_RSIZE_START 0x10130
+#define CNXK_SDP_R_OUT_SLIST_DBELL_START 0x10140
+#define CNXK_SDP_R_OUT_CONTROL_START 0x10150
+#define CNXK_SDP_R_OUT_WMARK_START 0x10160
+#define CNXK_SDP_R_OUT_ENABLE_START 0x10170
+#define CNXK_SDP_R_OUT_PKT_CNT_START 0x10180
+#define CNXK_SDP_R_OUT_BYTE_CNT_START 0x10190
+
+#define CNXK_SDP_R_OUT_CONTROL(ring) \
+ (CNXK_SDP_R_OUT_CONTROL_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_ENABLE(ring) \
+ (CNXK_SDP_R_OUT_ENABLE_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_SLIST_BADDR(ring) \
+ (CNXK_SDP_R_OUT_SLIST_BADDR_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_SLIST_RSIZE(ring) \
+ (CNXK_SDP_R_OUT_SLIST_RSIZE_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_SLIST_DBELL(ring) \
+ (CNXK_SDP_R_OUT_SLIST_DBELL_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_WMARK(ring) \
+ (CNXK_SDP_R_OUT_WMARK_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_CNTS(ring) \
+ (CNXK_SDP_R_OUT_CNTS_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_INT_LEVELS(ring) \
+ (CNXK_SDP_R_OUT_INT_LEVELS_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_PKT_CNT(ring) \
+ (CNXK_SDP_R_OUT_PKT_CNT_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_BYTE_CNT(ring) \
+ (CNXK_SDP_R_OUT_BYTE_CNT_START + ((ring) * CNXK_RING_OFFSET))
+
+/*------------------ R_OUT Masks ----------------*/
+#define CNXK_R_OUT_INT_LEVELS_BMODE BIT_ULL(63)
+#define CNXK_R_OUT_INT_LEVELS_TIMET (32)
+
+#define CNXK_R_OUT_CTL_IDLE BIT_ULL(40)
+#define CNXK_R_OUT_CTL_ES_I BIT_ULL(34)
+#define CNXK_R_OUT_CTL_NSR_I BIT_ULL(33)
+#define CNXK_R_OUT_CTL_ROR_I BIT_ULL(32)
+#define CNXK_R_OUT_CTL_ES_D BIT_ULL(30)
+#define CNXK_R_OUT_CTL_NSR_D BIT_ULL(29)
+#define CNXK_R_OUT_CTL_ROR_D BIT_ULL(28)
+#define CNXK_R_OUT_CTL_ES_P BIT_ULL(26)
+#define CNXK_R_OUT_CTL_NSR_P BIT_ULL(25)
+#define CNXK_R_OUT_CTL_ROR_P BIT_ULL(24)
+#define CNXK_R_OUT_CTL_IMODE BIT_ULL(23)
+
+/* ############### Interrupt Moderation Registers ############### */
+#define CNXK_SDP_R_IN_INT_MDRT_CTL0_START 0x10280
+#define CNXK_SDP_R_IN_INT_MDRT_CTL1_START 0x102A0
+#define CNXK_SDP_R_IN_INT_MDRT_DBG_START 0x102C0
+
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL0_START 0x10380
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL1_START 0x103A0
+#define CNXK_SDP_R_OUT_INT_MDRT_DBG_START 0x103C0
+
+#define CNXK_SDP_R_MBOX_ISM_START 0x10500
+#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510
+#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520
+
+#define CNXK_SDP_R_IN_INT_MDRT_CTL0(ring) \
+ (CNXK_SDP_R_IN_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_INT_MDRT_CTL1(ring) \
+ (CNXK_SDP_R_IN_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_INT_MDRT_DBG(ring) \
+ (CNXK_SDP_R_IN_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL0(ring) \
+ (CNXK_SDP_R_OUT_INT_MDRT_CTL0_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_INT_MDRT_CTL1(ring) \
+ (CNXK_SDP_R_OUT_INT_MDRT_CTL1_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_INT_MDRT_DBG(ring) \
+ (CNXK_SDP_R_OUT_INT_MDRT_DBG_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_MBOX_ISM(ring) \
+ (CNXK_SDP_R_MBOX_ISM_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \
+ (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_CNTS_ISM(ring) \
+ (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
+
+/* ##################### Mail Box Registers ########################## */
+/* INT register for VF. when a MBOX write from PF happed to a VF,
+ * corresponding bit will be set in this register as well as in
+ * PF_VF_INT register.
+ *
+ * This is a RO register, the int can be cleared by writing 1 to PF_VF_INT
+ */
+/* Basically first 3 are from PF to VF. The last one is data from VF to PF */
+#define CNXK_SDP_R_MBOX_PF_VF_DATA_START 0x10210
+#define CNXK_SDP_R_MBOX_PF_VF_INT_START 0x10220
+#define CNXK_SDP_R_MBOX_VF_PF_DATA_START 0x10230
+
+#define CNXK_SDP_MBOX_VF_PF_DATA_START 0x24000
+#define CNXK_SDP_MBOX_PF_VF_DATA_START 0x22000
+
+#define CNXK_SDP_R_MBOX_PF_VF_DATA(ring) \
+ (CNXK_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_MBOX_PF_VF_INT(ring) \
+ (CNXK_SDP_R_MBOX_PF_VF_INT_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_MBOX_VF_PF_DATA(ring) \
+ (CNXK_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_MBOX_VF_PF_DATA(ring) \
+ (CNXK_SDP_MBOX_VF_PF_DATA_START + ((ring) * CNXK_EPVF_RING_OFFSET))
+
+#define CNXK_SDP_MBOX_PF_VF_DATA(ring) \
+ (CNXK_SDP_MBOX_PF_VF_DATA_START + ((ring) * CNXK_EPVF_RING_OFFSET))
+
+/* ##################### Interrupt Registers ########################## */
+#define CNXK_SDP_R_ERR_TYPE_START 0x10400
+
+#define CNXK_SDP_R_ERR_TYPE(ring) \
+ (CNXK_SDP_R_ERR_TYPE_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_MBOX_ISM_START 0x10500
+#define CNXK_SDP_R_OUT_CNTS_ISM_START 0x10510
+#define CNXK_SDP_R_IN_CNTS_ISM_START 0x10520
+
+#define CNXK_SDP_R_MBOX_ISM(ring) \
+ (CNXK_SDP_R_MBOX_ISM_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_OUT_CNTS_ISM(ring) \
+ (CNXK_SDP_R_OUT_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_R_IN_CNTS_ISM(ring) \
+ (CNXK_SDP_R_IN_CNTS_ISM_START + ((ring) * CNXK_RING_OFFSET))
+
+#define CNXK_SDP_EPF_MBOX_RINT_START 0x20100
+#define CNXK_SDP_EPF_MBOX_RINT_W1S_START 0x20120
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START 0x20140
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START 0x20160
+
+#define CNXK_SDP_EPF_VFIRE_RINT_START 0x20180
+#define CNXK_SDP_EPF_VFIRE_RINT_W1S_START 0x201A0
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START 0x201C0
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START 0x201E0
+
+#define CNXK_SDP_EPF_IRERR_RINT 0x20200
+#define CNXK_SDP_EPF_IRERR_RINT_W1S 0x20210
+#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1C 0x20220
+#define CNXK_SDP_EPF_IRERR_RINT_ENA_W1S 0x20230
+
+#define CNXK_SDP_EPF_VFORE_RINT_START 0x20240
+#define CNXK_SDP_EPF_VFORE_RINT_W1S_START 0x20260
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START 0x20280
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START 0x202A0
+
+#define CNXK_SDP_EPF_ORERR_RINT 0x20320
+#define CNXK_SDP_EPF_ORERR_RINT_W1S 0x20330
+#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1C 0x20340
+#define CNXK_SDP_EPF_ORERR_RINT_ENA_W1S 0x20350
+
+#define CNXK_SDP_EPF_OEI_RINT 0x20400
+#define CNXK_SDP_EPF_OEI_RINT_W1S 0x20500
+#define CNXK_SDP_EPF_OEI_RINT_ENA_W1C 0x20600
+#define CNXK_SDP_EPF_OEI_RINT_ENA_W1S 0x20700
+
+#define CNXK_SDP_EPF_DMA_RINT 0x20800
+#define CNXK_SDP_EPF_DMA_RINT_W1S 0x20810
+#define CNXK_SDP_EPF_DMA_RINT_ENA_W1C 0x20820
+#define CNXK_SDP_EPF_DMA_RINT_ENA_W1S 0x20830
+
+#define CNXK_SDP_EPF_DMA_INT_LEVEL_START 0x20840
+#define CNXK_SDP_EPF_DMA_CNT_START 0x20860
+#define CNXK_SDP_EPF_DMA_TIM_START 0x20880
+
+#define CNXK_SDP_EPF_MISC_RINT 0x208A0
+#define CNXK_SDP_EPF_MISC_RINT_W1S 0x208B0
+#define CNXK_SDP_EPF_MISC_RINT_ENA_W1C 0x208C0
+#define CNXK_SDP_EPF_MISC_RINT_ENA_W1S 0x208D0
+
+#define CNXK_SDP_EPF_DMA_VF_RINT_START 0x208E0
+#define CNXK_SDP_EPF_DMA_VF_RINT_W1S_START 0x20900
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START 0x20920
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START 0x20940
+
+#define CNXK_SDP_EPF_PP_VF_RINT_START 0x20960
+#define CNXK_SDP_EPF_PP_VF_RINT_W1S_START 0x20980
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START 0x209A0
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START 0x209C0
+
+#define CNXK_SDP_EPF_MBOX_RINT(index) \
+ (CNXK_SDP_EPF_MBOX_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_MBOX_RINT_W1S(index) \
+ (CNXK_SDP_EPF_MBOX_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1C(index) \
+ (CNXK_SDP_EPF_MBOX_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_MBOX_RINT_ENA_W1S(index) \
+ (CNXK_SDP_EPF_MBOX_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+
+#define CNXK_SDP_EPF_VFIRE_RINT(index) \
+ (CNXK_SDP_EPF_VFIRE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_VFIRE_RINT_W1S(index) \
+ (CNXK_SDP_EPF_VFIRE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C(index) \
+ (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S(index) \
+ (CNXK_SDP_EPF_VFIRE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+
+#define CNXK_SDP_EPF_VFORE_RINT(index) \
+ (CNXK_SDP_EPF_VFORE_RINT_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_VFORE_RINT_W1S(index) \
+ (CNXK_SDP_EPF_VFORE_RINT_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1C(index) \
+ (CNXK_SDP_EPF_VFORE_RINT_ENA_W1C_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_VFORE_RINT_ENA_W1S(index) \
+ (CNXK_SDP_EPF_VFORE_RINT_ENA_W1S_START + ((index) * CNXK_BIT_ARRAY_OFFSET))
+
+#define CNXK_SDP_EPF_DMA_VF_RINT(index) \
+ (CNXK_SDP_EPF_DMA_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_DMA_VF_RINT_W1S(index) \
+ (CNXK_SDP_EPF_DMA_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C(index) \
+ (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S(index) \
+ (CNXK_SDP_EPF_DMA_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+
+#define CNXK_SDP_EPF_PP_VF_RINT(index) \
+ (CNXK_SDP_EPF_PP_VF_RINT_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_PP_VF_RINT_W1S(index) \
+ (CNXK_SDP_EPF_PP_VF_RINT_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C(index) \
+ (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1C_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+#define CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S(index) \
+ (CNXK_SDP_EPF_PP_VF_RINT_ENA_W1S_START + ((index) + CNXK_BIT_ARRAY_OFFSET))
+
+/*------------------ Interrupt Masks ----------------*/
+#define CNXK_INTR_R_SEND_ISM BIT_ULL(63)
+#define CNXK_INTR_R_OUT_INT BIT_ULL(62)
+#define CNXK_INTR_R_IN_INT BIT_ULL(61)
+#define CNXK_INTR_R_MBOX_INT BIT_ULL(60)
+#define CNXK_INTR_R_RESEND BIT_ULL(59)
+#define CNXK_INTR_R_CLR_TIM BIT_ULL(58)
+
+/* ####################### Ring Mapping Registers ################################## */
+#define CNXK_SDP_EPVF_RING_START 0x26000
+#define CNXK_SDP_IN_RING_TB_MAP_START 0x28000
+#define CNXK_SDP_IN_RATE_LIMIT_START 0x2A000
+#define CNXK_SDP_MAC_PF_RING_CTL_START 0x2C000
+
+#define CNXK_SDP_EPVF_RING(ring) \
+ (CNXK_SDP_EPVF_RING_START + ((ring) * CNXK_EPVF_RING_OFFSET))
+#define CNXK_SDP_IN_RING_TB_MAP(ring) \
+ (CNXK_SDP_N_RING_TB_MAP_START + ((ring) * CNXK_EPVF_RING_OFFSET))
+#define CNXK_SDP_IN_RATE_LIMIT(ring) \
+ (CNXK_SDP_IN_RATE_LIMIT_START + ((ring) * CNXK_EPVF_RING_OFFSET))
+#define CNXK_SDP_MAC_PF_RING_CTL(mac) \
+ (CNXK_SDP_MAC_PF_RING_CTL_START + ((mac) * CNXK_MAC_OFFSET))
+
+#define CNXK_SDP_MAC_PF_RING_CTL_NPFS(val) ((val) & 0x3)
+#define CNXK_SDP_MAC_PF_RING_CTL_SRN(val) (((val) >> 8) & 0x7F)
+#define CNXK_SDP_MAC_PF_RING_CTL_RPPF(val) (((val) >> 16) & 0x3F)
+
+/* Number of non-queue interrupts in CNXKxx */
+#define CNXK_NUM_NON_IOQ_INTR 32
+
+/* bit 0 for control mbox interrupt */
+#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_MBOX BIT_ULL(0)
+/* bit 1 for firmware heartbeat interrupt */
+#define CNXK_SDP_EPF_OEI_RINT_DATA_BIT_HBEAT BIT_ULL(1)
+#define FW_STATUS_RUNNING 2ULL
+#define CNXK_PEMX_PFX_CSX_PFCFGX(pem, pf, offset) ({ typeof(offset) _off = (offset); \
+ ((0x8e0000008000 | \
+ (uint64_t)(pem) << 36 \
+ | (pf) << 18 \
+ | ((_off >> 16) & 1) << 16 \
+ | (_off >> 3) << 3) \
+ + (((_off >> 2) & 1) << 2)); \
+ })
+
+/* Register defines for use with CNXK_PEMX_PFX_CSX_PFCFGX */
+#define CNXK_PCIEEP_VSECST_CTL 0x418
+
+#define CNXK_PEM_BAR4_INDEX 7
+#define CNXK_PEM_BAR4_INDEX_SIZE 0x400000ULL
+#define CNXK_PEM_BAR4_INDEX_OFFSET (CNXK_PEM_BAR4_INDEX * CNXK_PEM_BAR4_INDEX_SIZE)
+
+#endif /* _OCTEP_REGS_CNXK_PF_H_ */
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
index 3c43f8078528..4746a6b258f0 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
@@ -143,7 +143,7 @@ static int octep_setup_oq(struct octep_device *oct, int q_no)
* additional header is filled-in by Octeon after length field in
* Rx packets. this header contains additional packet information.
*/
- if (oct->caps_enabled)
+ if (oct->conf->fw_info.rx_ol_flags)
oq->max_single_buffer_size -= OCTEP_OQ_RESP_HW_EXT_SIZE;
oq->refill_threshold = CFG_GET_OQ_REFILL_THRESHOLD(oct->conf);
@@ -353,11 +353,13 @@ static int __octep_oq_process_rx(struct octep_device *oct,
struct octep_oq *oq, u16 pkts_to_process)
{
struct octep_oq_resp_hw_ext *resp_hw_ext = NULL;
+ netdev_features_t feat = oq->netdev->features;
struct octep_rx_buffer *buff_info;
struct octep_oq_resp_hw *resp_hw;
u32 pkt, rx_bytes, desc_used;
struct sk_buff *skb;
u16 data_offset;
+ u16 rx_ol_flags;
u32 read_idx;
read_idx = oq->host_read_idx;
@@ -372,7 +374,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
/* Swap the length field that is in Big-Endian to CPU */
buff_info->len = be64_to_cpu(resp_hw->length);
- if (oct->caps_enabled & OCTEP_CAP_RX_CHECKSUM) {
+ if (oct->conf->fw_info.rx_ol_flags) {
/* Extended response header is immediately after
* response header (resp_hw)
*/
@@ -384,11 +386,13 @@ static int __octep_oq_process_rx(struct octep_device *oct,
*/
data_offset = OCTEP_OQ_RESP_HW_SIZE +
OCTEP_OQ_RESP_HW_EXT_SIZE;
+ rx_ol_flags = resp_hw_ext->rx_ol_flags;
} else {
/* Data is immediately after
* Hardware Rx response header.
*/
data_offset = OCTEP_OQ_RESP_HW_SIZE;
+ rx_ol_flags = 0;
}
rx_bytes += buff_info->len;
@@ -444,8 +448,8 @@ static int __octep_oq_process_rx(struct octep_device *oct,
skb->dev = oq->netdev;
skb->protocol = eth_type_trans(skb, skb->dev);
- if (resp_hw_ext &&
- resp_hw_ext->csum_verified == OCTEP_CSUM_VERIFIED)
+ if (feat & NETIF_F_RXCSUM &&
+ OCTEP_RX_CSUM_VERIFIED(rx_ol_flags))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h
index 49feae80d7d2..3b08e2d560dc 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.h
@@ -20,13 +20,33 @@ struct octep_oq_desc_hw {
dma_addr_t buffer_ptr;
u64 info_ptr;
};
+
static_assert(sizeof(struct octep_oq_desc_hw) == 16);
#define OCTEP_OQ_DESC_SIZE (sizeof(struct octep_oq_desc_hw))
-#define OCTEP_CSUM_L4_VERIFIED 0x1
-#define OCTEP_CSUM_IP_VERIFIED 0x2
-#define OCTEP_CSUM_VERIFIED (OCTEP_CSUM_L4_VERIFIED | OCTEP_CSUM_IP_VERIFIED)
+/* Rx offload flags */
+#define OCTEP_RX_OFFLOAD_VLAN_STRIP BIT(0)
+#define OCTEP_RX_OFFLOAD_IPV4_CKSUM BIT(1)
+#define OCTEP_RX_OFFLOAD_UDP_CKSUM BIT(2)
+#define OCTEP_RX_OFFLOAD_TCP_CKSUM BIT(3)
+
+#define OCTEP_RX_OFFLOAD_CKSUM (OCTEP_RX_OFFLOAD_IPV4_CKSUM | \
+ OCTEP_RX_OFFLOAD_UDP_CKSUM | \
+ OCTEP_RX_OFFLOAD_TCP_CKSUM)
+
+#define OCTEP_RX_IP_CSUM(flags) ((flags) & \
+ (OCTEP_RX_OFFLOAD_IPV4_CKSUM | \
+ OCTEP_RX_OFFLOAD_TCP_CKSUM | \
+ OCTEP_RX_OFFLOAD_UDP_CKSUM))
+
+/* bit 0 is vlan strip */
+#define OCTEP_RX_CSUM_IP_VERIFIED BIT(1)
+#define OCTEP_RX_CSUM_L4_VERIFIED BIT(2)
+
+#define OCTEP_RX_CSUM_VERIFIED(flags) ((flags) & \
+ (OCTEP_RX_CSUM_L4_VERIFIED | \
+ OCTEP_RX_CSUM_IP_VERIFIED))
/* Extended Response Header in packet data received from Hardware.
* Includes metadata like checksum status.
@@ -35,11 +55,12 @@ static_assert(sizeof(struct octep_oq_desc_hw) == 16);
*/
struct octep_oq_resp_hw_ext {
/* Reserved. */
- u64 reserved:62;
+ u64 rsvd:48;
- /* checksum verified. */
- u64 csum_verified:2;
+ /* offload flags */
+ u16 rx_ol_flags;
};
+
static_assert(sizeof(struct octep_oq_resp_hw_ext) == 8);
#define OCTEP_OQ_RESP_HW_EXT_SIZE (sizeof(struct octep_oq_resp_hw_ext))
@@ -52,6 +73,7 @@ struct octep_oq_resp_hw {
/* The Length of the packet. */
__be64 length;
};
+
static_assert(sizeof(struct octep_oq_resp_hw) == 8);
#define OCTEP_OQ_RESP_HW_SIZE (sizeof(struct octep_oq_resp_hw))
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c
index d0adb82d65c3..06851b78aa28 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c
@@ -21,7 +21,6 @@ static void octep_iq_reset_indices(struct octep_iq *iq)
iq->flush_index = 0;
iq->pkts_processed = 0;
iq->pkt_in_done = 0;
- atomic_set(&iq->instr_pending, 0);
}
/**
@@ -82,7 +81,6 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget)
}
iq->pkts_processed += compl_pkts;
- atomic_sub(compl_pkts, &iq->instr_pending);
iq->stats.instr_completed += compl_pkts;
iq->stats.bytes_sent += compl_bytes;
iq->stats.sgentry_sent += compl_sg;
@@ -91,7 +89,7 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget)
netdev_tx_completed_queue(iq->netdev_q, compl_pkts, compl_bytes);
if (unlikely(__netif_subqueue_stopped(iq->netdev, iq->q_no)) &&
- ((iq->max_count - atomic_read(&iq->instr_pending)) >
+ (IQ_INSTR_SPACE(iq) >
OCTEP_WAKE_QUEUE_THRESHOLD))
netif_wake_subqueue(iq->netdev, iq->q_no);
return !budget;
@@ -144,7 +142,6 @@ static void octep_iq_free_pending(struct octep_iq *iq)
dev_kfree_skb_any(skb);
}
- atomic_set(&iq->instr_pending, 0);
iq->flush_index = fi;
netdev_tx_reset_queue(netdev_get_tx_queue(iq->netdev, iq->q_no));
}
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
index 86c98b13fc44..875a2c34091f 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
@@ -36,6 +36,7 @@ struct octep_tx_sglist_desc {
u16 len[4];
dma_addr_t dma_ptr[4];
};
+
static_assert(sizeof(struct octep_tx_sglist_desc) == 40);
/* Each Scatter/Gather entry sent to hardwar hold four pointers.
@@ -60,6 +61,18 @@ struct octep_tx_buffer {
/* Hardware interface Tx statistics */
struct octep_iface_tx_stats {
+ /* Total frames sent on the interface */
+ u64 pkts;
+
+ /* Total octets sent on the interface */
+ u64 octs;
+
+ /* Packets sent to a broadcast DMAC */
+ u64 bcst;
+
+ /* Packets sent to the multicast DMAC */
+ u64 mcst;
+
/* Packets dropped due to excessive collisions */
u64 xscol;
@@ -76,12 +89,6 @@ struct octep_iface_tx_stats {
*/
u64 scol;
- /* Total octets sent on the interface */
- u64 octs;
-
- /* Total frames sent on the interface */
- u64 pkts;
-
/* Packets sent with an octet count < 64 */
u64 hist_lt64;
@@ -106,12 +113,6 @@ struct octep_iface_tx_stats {
/* Packets sent with an octet count of > 1518 */
u64 hist_gt1518;
- /* Packets sent to a broadcast DMAC */
- u64 bcst;
-
- /* Packets sent to the multicast DMAC */
- u64 mcst;
-
/* Packets sent that experienced a transmit underflow and were
* truncated
*/
@@ -172,9 +173,6 @@ struct octep_iq {
/* Statistics for this input queue. */
struct octep_iq_stats stats;
- /* This field keeps track of the instructions pending in this queue. */
- atomic_t instr_pending;
-
/* Pointer to the Virtual Base addr of the input ring. */
struct octep_tx_desc_hw *desc_ring;
@@ -240,32 +238,53 @@ struct octep_instr_hdr {
/* Reserved3 */
u64 reserved3:1;
};
+
static_assert(sizeof(struct octep_instr_hdr) == 8);
-/* Hardware Tx completion response header */
-struct octep_instr_resp_hdr {
- /* Request ID */
- u64 rid:16;
+/* Tx offload flags */
+#define OCTEP_TX_OFFLOAD_VLAN_INSERT BIT(0)
+#define OCTEP_TX_OFFLOAD_IPV4_CKSUM BIT(1)
+#define OCTEP_TX_OFFLOAD_UDP_CKSUM BIT(2)
+#define OCTEP_TX_OFFLOAD_TCP_CKSUM BIT(3)
+#define OCTEP_TX_OFFLOAD_SCTP_CKSUM BIT(4)
+#define OCTEP_TX_OFFLOAD_TCP_TSO BIT(5)
+#define OCTEP_TX_OFFLOAD_UDP_TSO BIT(6)
+
+#define OCTEP_TX_OFFLOAD_CKSUM (OCTEP_TX_OFFLOAD_IPV4_CKSUM | \
+ OCTEP_TX_OFFLOAD_UDP_CKSUM | \
+ OCTEP_TX_OFFLOAD_TCP_CKSUM)
+
+#define OCTEP_TX_OFFLOAD_TSO (OCTEP_TX_OFFLOAD_TCP_TSO | \
+ OCTEP_TX_OFFLOAD_UDP_TSO)
+
+#define OCTEP_TX_IP_CSUM(flags) ((flags) & \
+ (OCTEP_TX_OFFLOAD_IPV4_CKSUM | \
+ OCTEP_TX_OFFLOAD_TCP_CKSUM | \
+ OCTEP_TX_OFFLOAD_UDP_CKSUM))
- /* PCIe port to use for response */
- u64 pcie_port:3;
+#define OCTEP_TX_TSO(flags) ((flags) & \
+ (OCTEP_TX_OFFLOAD_TCP_TSO | \
+ OCTEP_TX_OFFLOAD_UDP_TSO))
- /* Scatter indicator 1=scatter */
- u64 scatter:1;
+struct tx_mdata {
- /* Size of Expected result OR no. of entries in scatter list */
- u64 rlenssz:14;
+ /* offload flags */
+ u16 ol_flags;
- /* Desired destination port for result */
- u64 dport:6;
+ /* gso size */
+ u16 gso_size;
- /* Opcode Specific parameters */
- u64 param:8;
+ /* gso flags */
+ u16 gso_segs;
- /* Opcode for the return packet */
- u64 opcode:16;
+ /* reserved */
+ u16 rsvd1;
+
+ /* reserved */
+ u64 rsvd2;
};
-static_assert(sizeof(struct octep_instr_hdr) == 8);
+
+static_assert(sizeof(struct tx_mdata) == 16);
/* 64-byte Tx instruction format.
* Format of instruction for a 64-byte mode input queue.
@@ -284,18 +303,14 @@ struct octep_tx_desc_hw {
struct octep_instr_hdr ih;
u64 ih64;
};
-
- /* Pointer where the response for a RAW mode packet will be written
- * by Octeon.
- */
- u64 rptr;
-
- /* Input Instruction Response Header. */
- struct octep_instr_resp_hdr irh;
-
+ union {
+ u64 txm64[2];
+ struct tx_mdata txm;
+ };
/* Additional headers available in a 64-byte instruction. */
- u64 exhdr[4];
+ u64 exthdr[4];
};
+
static_assert(sizeof(struct octep_tx_desc_hw) == 64);
#define OCTEP_IQ_DESC_SIZE (sizeof(struct octep_tx_desc_hw))
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
index 9690ac01f02c..b92264d0a77e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c
@@ -413,4 +413,5 @@ const char *otx2_mbox_id2name(u16 id)
EXPORT_SYMBOL(otx2_mbox_id2name);
MODULE_AUTHOR("Marvell.");
+MODULE_DESCRIPTION("Marvell RVU NIC Mbox helpers");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index 5df42634ceb8..edeb0f737312 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -304,6 +304,13 @@ M(NIX_BANDPROF_GET_HWINFO, 0x801f, nix_bandprof_get_hwinfo, msg_req, \
nix_bandprof_get_hwinfo_rsp) \
M(NIX_READ_INLINE_IPSEC_CFG, 0x8023, nix_read_inline_ipsec_cfg, \
msg_req, nix_inline_ipsec_cfg) \
+M(NIX_MCAST_GRP_CREATE, 0x802b, nix_mcast_grp_create, nix_mcast_grp_create_req, \
+ nix_mcast_grp_create_rsp) \
+M(NIX_MCAST_GRP_DESTROY, 0x802c, nix_mcast_grp_destroy, nix_mcast_grp_destroy_req, \
+ msg_rsp) \
+M(NIX_MCAST_GRP_UPDATE, 0x802d, nix_mcast_grp_update, \
+ nix_mcast_grp_update_req, \
+ nix_mcast_grp_update_rsp) \
/* MCS mbox IDs (range 0xA000 - 0xBFFF) */ \
M(MCS_ALLOC_RESOURCES, 0xa000, mcs_alloc_resources, mcs_alloc_rsrc_req, \
mcs_alloc_rsrc_rsp) \
@@ -830,6 +837,9 @@ enum nix_af_status {
NIX_AF_ERR_CQ_CTX_WRITE_ERR = -429,
NIX_AF_ERR_AQ_CTX_RETRY_WRITE = -430,
NIX_AF_ERR_LINK_CREDITS = -431,
+ NIX_AF_ERR_INVALID_MCAST_GRP = -436,
+ NIX_AF_ERR_INVALID_MCAST_DEL_REQ = -437,
+ NIX_AF_ERR_NON_CONTIG_MCE_LIST = -438,
};
/* For NIX RX vtag action */
@@ -1204,6 +1214,68 @@ struct nix_bp_cfg_rsp {
u8 chan_cnt; /* Number of channel for which bpids are assigned */
};
+struct nix_mcast_grp_create_req {
+ struct mbox_msghdr hdr;
+#define NIX_MCAST_INGRESS 0
+#define NIX_MCAST_EGRESS 1
+ u8 dir;
+ u8 reserved[11];
+ /* Reserving few bytes for future requirement */
+};
+
+struct nix_mcast_grp_create_rsp {
+ struct mbox_msghdr hdr;
+ /* This mcast_grp_idx should be passed during MCAM
+ * write entry for multicast. AF will identify the
+ * corresponding multicast table index associated
+ * with the group id and program the same to MCAM entry.
+ * This group id is also needed during group delete
+ * and update request.
+ */
+ u32 mcast_grp_idx;
+};
+
+struct nix_mcast_grp_destroy_req {
+ struct mbox_msghdr hdr;
+ /* Group id returned by nix_mcast_grp_create_rsp */
+ u32 mcast_grp_idx;
+ /* If AF is requesting for destroy, then set
+ * it to '1'. Otherwise keep it to '0'
+ */
+ u8 is_af;
+};
+
+struct nix_mcast_grp_update_req {
+ struct mbox_msghdr hdr;
+ /* Group id returned by nix_mcast_grp_create_rsp */
+ u32 mcast_grp_idx;
+ /* Number of multicast/mirror entries requested */
+ u32 num_mce_entry;
+#define NIX_MCE_ENTRY_MAX 64
+#define NIX_RX_RQ 0
+#define NIX_RX_RSS 1
+ /* Receive queue or RSS index within pf_func */
+ u32 rq_rss_index[NIX_MCE_ENTRY_MAX];
+ /* pcifunc is required for both ingress and egress multicast */
+ u16 pcifunc[NIX_MCE_ENTRY_MAX];
+ /* channel is required for egress multicast */
+ u16 channel[NIX_MCE_ENTRY_MAX];
+#define NIX_MCAST_OP_ADD_ENTRY 0
+#define NIX_MCAST_OP_DEL_ENTRY 1
+ /* Destination type. 0:Receive queue, 1:RSS*/
+ u8 dest_type[NIX_MCE_ENTRY_MAX];
+ u8 op;
+ /* If AF is requesting for update, then set
+ * it to '1'. Otherwise keep it to '0'
+ */
+ u8 is_af;
+};
+
+struct nix_mcast_grp_update_rsp {
+ struct mbox_msghdr hdr;
+ u32 mce_start_index;
+};
+
/* Global NIX inline IPSec configuration */
struct nix_inline_ipsec_cfg {
struct mbox_msghdr hdr;
@@ -1479,6 +1551,8 @@ struct flow_msg {
#define OTX2_FLOWER_MASK_MPLS_TTL GENMASK(7, 0)
#define OTX2_FLOWER_MASK_MPLS_NON_TTL GENMASK(31, 8)
u32 mpls_lse[4];
+ u8 icmp_type;
+ u8 icmp_code;
};
struct npc_install_flow_req {
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
index 8c0732c9a7ee..b0b4dea548e1 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h
@@ -214,6 +214,8 @@ enum key_fields {
NPC_MPLS3_TTL,
NPC_MPLS4_LBTCBOS,
NPC_MPLS4_TTL,
+ NPC_TYPE_ICMP,
+ NPC_CODE_ICMP,
NPC_HEADER_FIELDS_MAX,
NPC_CHAN = NPC_HEADER_FIELDS_MAX, /* Valid when Rx */
NPC_PF_FUNC, /* Valid when Tx */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c
index 4728ba34b0e3..76218f1cb459 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rpm.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rpm.c
@@ -506,6 +506,7 @@ u32 rpm2_get_lmac_fifo_len(void *rpmd, int lmac_id)
rpm_t *rpm = rpmd;
u8 num_lmacs;
u32 fifo_len;
+ u16 max_lmac;
lmac_info = rpm_read(rpm, 0, RPM2_CMRX_RX_LMACS);
/* LMACs are divided into two groups and each group
@@ -513,7 +514,11 @@ u32 rpm2_get_lmac_fifo_len(void *rpmd, int lmac_id)
* Group0 lmac_id range {0..3}
* Group1 lmac_id range {4..7}
*/
- fifo_len = rpm->mac_ops->fifo_len / 2;
+ max_lmac = (rpm_read(rpm, 0, CGX_CONST) >> 24) & 0xFF;
+ if (max_lmac > 4)
+ fifo_len = rpm->mac_ops->fifo_len / 2;
+ else
+ fifo_len = rpm->mac_ops->fifo_len;
if (lmac_id < 4) {
num_lmacs = hweight8(lmac_info & 0xF);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
index 731bb82b577c..5c1d04a3c559 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
@@ -156,7 +156,7 @@ int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc)
return start;
}
-static void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start)
+void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start)
{
if (!rsrc->bmap)
return;
@@ -935,6 +935,9 @@ static int rvu_setup_hw_resources(struct rvu *rvu)
hw->total_vfs = (cfg >> 20) & 0xFFF;
hw->max_vfs_per_pf = (cfg >> 40) & 0xFF;
+ if (!is_rvu_otx2(rvu))
+ rvu_apr_block_cn10k_init(rvu);
+
/* Init NPA LF's bitmap */
block = &hw->block[BLKADDR_NPA];
if (!block->implemented)
@@ -2614,6 +2617,10 @@ static void __rvu_flr_handler(struct rvu *rvu, u16 pcifunc)
* 2. Flush and reset SSO/SSOW
* 3. Cleanup pools (NPA)
*/
+
+ /* Free multicast/mirror node associated with the 'pcifunc' */
+ rvu_nix_mcast_flr_free_entries(rvu, pcifunc);
+
rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NIX0);
rvu_blklf_teardown(rvu, pcifunc, BLKADDR_NIX1);
rvu_blklf_teardown(rvu, pcifunc, BLKADDR_CPT0);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
index 8802961b8889..43be37dd1f32 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
@@ -116,11 +116,12 @@ struct rvu_block {
};
struct nix_mcast {
- struct qmem *mce_ctx;
- struct qmem *mcast_buf;
- int replay_pkind;
- int next_free_mce;
- struct mutex mce_lock; /* Serialize MCE updates */
+ struct qmem *mce_ctx;
+ struct qmem *mcast_buf;
+ int replay_pkind;
+ struct rsrc_bmap mce_counter[2];
+ /* Counters for both ingress and egress mcast lists */
+ struct mutex mce_lock; /* Serialize MCE updates */
};
struct nix_mce_list {
@@ -129,6 +130,23 @@ struct nix_mce_list {
int max;
};
+struct nix_mcast_grp_elem {
+ struct nix_mce_list mcast_mce_list;
+ u32 mcast_grp_idx;
+ u32 pcifunc;
+ int mcam_index;
+ int mce_start_index;
+ struct list_head list;
+ u8 dir;
+};
+
+struct nix_mcast_grp {
+ struct list_head mcast_grp_head;
+ int count;
+ int next_grp_index;
+ struct mutex mcast_grp_lock; /* Serialize MCE updates */
+};
+
/* layer metadata to uniquely identify a packet header field */
struct npc_layer_mdata {
u8 lid;
@@ -339,6 +357,7 @@ struct nix_hw {
struct rvu *rvu;
struct nix_txsch txsch[NIX_TXSCH_LVL_CNT]; /* Tx schedulers */
struct nix_mcast mcast;
+ struct nix_mcast_grp mcast_grp;
struct nix_flowkey flowkey;
struct nix_mark_format mark_format;
struct nix_lso lso;
@@ -742,6 +761,7 @@ void rvu_free_rsrc(struct rsrc_bmap *rsrc, int id);
bool is_rsrc_free(struct rsrc_bmap *rsrc, int id);
int rvu_rsrc_free_count(struct rsrc_bmap *rsrc);
int rvu_alloc_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc);
+void rvu_free_rsrc_contig(struct rsrc_bmap *rsrc, int nrsrc, int start);
bool rvu_rsrc_check_contig(struct rsrc_bmap *rsrc, int nrsrc);
u16 rvu_get_rsrc_mapcount(struct rvu_pfvf *pfvf, int blkaddr);
int rvu_get_pf(u16 pcifunc);
@@ -848,6 +868,11 @@ u32 convert_dwrr_mtu_to_bytes(u8 dwrr_mtu);
u32 convert_bytes_to_dwrr_mtu(u32 bytes);
void rvu_nix_tx_tl2_cfg(struct rvu *rvu, int blkaddr, u16 pcifunc,
struct nix_txsch *txsch, bool enable);
+void rvu_nix_mcast_flr_free_entries(struct rvu *rvu, u16 pcifunc);
+int rvu_nix_mcast_get_mce_index(struct rvu *rvu, u16 pcifunc,
+ u32 mcast_grp_idx);
+int rvu_nix_mcast_update_mcam_entry(struct rvu *rvu, u16 pcifunc,
+ u32 mcast_grp_idx, u16 mcam_index);
/* NPC APIs */
void rvu_npc_freemem(struct rvu *rvu);
@@ -896,6 +921,10 @@ void npc_mcam_enable_flows(struct rvu *rvu, u16 target);
void npc_mcam_disable_flows(struct rvu *rvu, u16 target);
void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, int index, bool enable);
+u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index);
+void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, u64 cfg);
void npc_read_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, u16 src, struct mcam_entry *entry,
u8 *intf, u8 *ena);
@@ -921,6 +950,8 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int mcam_idx, u16 *counter_idx,
u64 bcast_mcast_val, u64 bcast_mcast_mask);
void npc_mcam_rsrcs_reserve(struct rvu *rvu, int blkaddr, int entry_idx);
bool npc_is_feature_supported(struct rvu *rvu, u64 features, u8 intf);
+int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr);
+void npc_mcam_rsrcs_deinit(struct rvu *rvu);
/* CPT APIs */
int rvu_cpt_register_interrupts(struct rvu *rvu);
@@ -942,6 +973,7 @@ void rvu_nix_block_cn10k_init(struct rvu *rvu, struct nix_hw *nix_hw);
/* CN10K RVU - LMT*/
void rvu_reset_lmt_map_tbl(struct rvu *rvu, u16 pcifunc);
+void rvu_apr_block_cn10k_init(struct rvu *rvu);
#ifdef CONFIG_DEBUG_FS
void rvu_dbg_init(struct rvu *rvu);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
index 0e74c5a2231e..7fa98aeb3663 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
@@ -559,3 +559,12 @@ void rvu_nix_block_cn10k_init(struct rvu *rvu, struct nix_hw *nix_hw)
cfg |= BIT_ULL(1) | BIT_ULL(2);
rvu_write64(rvu, blkaddr, NIX_AF_CFG, cfg);
}
+
+void rvu_apr_block_cn10k_init(struct rvu *rvu)
+{
+ u64 reg;
+
+ reg = rvu_read64(rvu, BLKADDR_APR, APR_AF_LMT_CFG);
+ reg |= FIELD_PREP(LMTST_THROTTLE_MASK, LMTST_WR_PEND_MAX);
+ rvu_write64(rvu, BLKADDR_APR, APR_AF_LMT_CFG, reg);
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
index bd817ee88735..e6d7914ce61c 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c
@@ -1825,6 +1825,8 @@ static void print_nix_rq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp)
static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp)
{
struct nix_cq_ctx_s *cq_ctx = &rsp->cq;
+ struct nix_hw *nix_hw = m->private;
+ struct rvu *rvu = nix_hw->rvu;
seq_printf(m, "W0: base \t\t\t%llx\n\n", cq_ctx->base);
@@ -1836,6 +1838,16 @@ static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp)
seq_printf(m, "W1: bpid \t\t\t%d\nW1: bp_ena \t\t\t%d\n\n",
cq_ctx->bpid, cq_ctx->bp_ena);
+ if (!is_rvu_otx2(rvu)) {
+ seq_printf(m, "W1: lbpid_high \t\t\t0x%03x\n", cq_ctx->lbpid_high);
+ seq_printf(m, "W1: lbpid_med \t\t\t0x%03x\n", cq_ctx->lbpid_med);
+ seq_printf(m, "W1: lbpid_low \t\t\t0x%03x\n", cq_ctx->lbpid_low);
+ seq_printf(m, "(W1: lbpid) \t\t\t0x%03x\n",
+ cq_ctx->lbpid_high << 6 | cq_ctx->lbpid_med << 3 |
+ cq_ctx->lbpid_low);
+ seq_printf(m, "W1: lbp_ena \t\t\t\t%d\n\n", cq_ctx->lbp_ena);
+ }
+
seq_printf(m, "W2: update_time \t\t%d\nW2:avg_level \t\t\t%d\n",
cq_ctx->update_time, cq_ctx->avg_level);
seq_printf(m, "W2: head \t\t\t%d\nW2:tail \t\t\t%d\n\n",
@@ -1847,6 +1859,11 @@ static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp)
cq_ctx->qsize, cq_ctx->caching);
seq_printf(m, "W3: substream \t\t\t0x%03x\nW3: ena \t\t\t%d\n",
cq_ctx->substream, cq_ctx->ena);
+ if (!is_rvu_otx2(rvu)) {
+ seq_printf(m, "W3: lbp_frac \t\t\t%d\n", cq_ctx->lbp_frac);
+ seq_printf(m, "W3: cpt_drop_err_en \t\t\t%d\n",
+ cq_ctx->cpt_drop_err_en);
+ }
seq_printf(m, "W3: drop_ena \t\t\t%d\nW3: drop \t\t\t%d\n",
cq_ctx->drop_ena, cq_ctx->drop);
seq_printf(m, "W3: bp \t\t\t\t%d\n\n", cq_ctx->bp);
@@ -2889,6 +2906,14 @@ static void rvu_dbg_npc_mcam_show_flows(struct seq_file *s,
RVU_DBG_PRINT_MPLS_TTL(rule->packet.mpls_lse[3],
rule->mask.mpls_lse[3]);
break;
+ case NPC_TYPE_ICMP:
+ seq_printf(s, "%d ", rule->packet.icmp_type);
+ seq_printf(s, "mask 0x%x\n", rule->mask.icmp_type);
+ break;
+ case NPC_CODE_ICMP:
+ seq_printf(s, "%d ", rule->packet.icmp_code);
+ seq_printf(s, "mask 0x%x\n", rule->mask.icmp_code);
+ break;
default:
seq_puts(s, "\n");
break;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index 21b5d71c1e37..1e6fbd98423d 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -5,7 +5,7 @@
*
*/
-#include<linux/bitfield.h>
+#include <linux/bitfield.h>
#include "rvu.h"
#include "rvu_reg.h"
@@ -1237,6 +1237,7 @@ enum rvu_af_dl_param_id {
RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU,
RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
RVU_AF_DEVLINK_PARAM_ID_NPC_MCAM_ZONE_PERCENT,
+ RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
};
static int rvu_af_npc_exact_feature_get(struct devlink *devlink, u32 id,
@@ -1354,6 +1355,79 @@ static int rvu_af_dl_npc_mcam_high_zone_percent_validate(struct devlink *devlink
return 0;
}
+static int rvu_af_dl_nix_maxlf_get(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+ struct rvu *rvu = rvu_dl->rvu;
+
+ ctx->val.vu16 = (u16)rvu_get_nixlf_count(rvu);
+
+ return 0;
+}
+
+static int rvu_af_dl_nix_maxlf_set(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx)
+{
+ struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+ struct rvu *rvu = rvu_dl->rvu;
+ struct rvu_block *block;
+ int blkaddr = 0;
+
+ npc_mcam_rsrcs_deinit(rvu);
+ blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr);
+ while (blkaddr) {
+ block = &rvu->hw->block[blkaddr];
+ block->lf.max = ctx->val.vu16;
+ blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr);
+ }
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ npc_mcam_rsrcs_init(rvu, blkaddr);
+
+ return 0;
+}
+
+static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id,
+ union devlink_param_value val,
+ struct netlink_ext_ack *extack)
+{
+ struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+ struct rvu *rvu = rvu_dl->rvu;
+ u16 max_nix0_lf, max_nix1_lf;
+ struct npc_mcam *mcam;
+ u64 cfg;
+
+ cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2);
+ max_nix0_lf = cfg & 0xFFF;
+ cfg = rvu_read64(rvu, BLKADDR_NIX1, NIX_AF_CONST2);
+ max_nix1_lf = cfg & 0xFFF;
+
+ /* Do not allow user to modify maximum NIX LFs while mcam entries
+ * have already been assigned.
+ */
+ mcam = &rvu->hw->mcam;
+ if (mcam->bmap_fcnt < mcam->bmap_entries) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "mcam entries have already been assigned, can't resize");
+ return -EPERM;
+ }
+
+ if (max_nix0_lf && val.vu16 > max_nix0_lf) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "requested nixlf is greater than the max supported nix0_lf");
+ return -EPERM;
+ }
+
+ if (max_nix1_lf && val.vu16 > max_nix1_lf) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "requested nixlf is greater than the max supported nix1_lf");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct devlink_param rvu_af_dl_params[] = {
DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_DWRR_MTU,
"dwrr_mtu", DEVLINK_PARAM_TYPE_U32,
@@ -1375,6 +1449,12 @@ static const struct devlink_param rvu_af_dl_param_exact_match[] = {
rvu_af_dl_npc_mcam_high_zone_percent_get,
rvu_af_dl_npc_mcam_high_zone_percent_set,
rvu_af_dl_npc_mcam_high_zone_percent_validate),
+ DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
+ "nix_maxlf", DEVLINK_PARAM_TYPE_U16,
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+ rvu_af_dl_nix_maxlf_get,
+ rvu_af_dl_nix_maxlf_set,
+ rvu_af_dl_nix_maxlf_validate),
};
/* Devlink switch mode */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index 58744313f0eb..66203a90f052 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -72,12 +72,19 @@ enum nix_makr_fmt_indexes {
/* For now considering MC resources needed for broadcast
* pkt replication only. i.e 256 HWVFs + 12 PFs.
*/
-#define MC_TBL_SIZE MC_TBL_SZ_512
-#define MC_BUF_CNT MC_BUF_CNT_128
+#define MC_TBL_SIZE MC_TBL_SZ_2K
+#define MC_BUF_CNT MC_BUF_CNT_1024
+
+#define MC_TX_MAX 2048
struct mce {
struct hlist_node node;
+ u32 rq_rss_index;
u16 pcifunc;
+ u16 channel;
+ u8 dest_type;
+ u8 is_active;
+ u8 reserved[2];
};
int rvu_get_next_nix_blkaddr(struct rvu *rvu, int blkaddr)
@@ -165,18 +172,33 @@ static void nix_mce_list_init(struct nix_mce_list *list, int max)
list->max = max;
}
-static u16 nix_alloc_mce_list(struct nix_mcast *mcast, int count)
+static int nix_alloc_mce_list(struct nix_mcast *mcast, int count, u8 dir)
{
+ struct rsrc_bmap *mce_counter;
int idx;
if (!mcast)
- return 0;
+ return -EINVAL;
- idx = mcast->next_free_mce;
- mcast->next_free_mce += count;
+ mce_counter = &mcast->mce_counter[dir];
+ if (!rvu_rsrc_check_contig(mce_counter, count))
+ return -ENOSPC;
+
+ idx = rvu_alloc_rsrc_contig(mce_counter, count);
return idx;
}
+static void nix_free_mce_list(struct nix_mcast *mcast, int count, int start, u8 dir)
+{
+ struct rsrc_bmap *mce_counter;
+
+ if (!mcast)
+ return;
+
+ mce_counter = &mcast->mce_counter[dir];
+ rvu_free_rsrc_contig(mce_counter, count, start);
+}
+
struct nix_hw *get_nix_hw(struct rvu_hwinfo *hw, int blkaddr)
{
int nix_blkaddr = 0, i = 0;
@@ -2956,7 +2978,8 @@ int rvu_mbox_handler_nix_vtag_cfg(struct rvu *rvu,
}
static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw,
- int mce, u8 op, u16 pcifunc, int next, bool eol)
+ int mce, u8 op, u16 pcifunc, int next,
+ int index, u8 mce_op, bool eol)
{
struct nix_aq_enq_req aq_req;
int err;
@@ -2967,8 +2990,8 @@ static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw,
aq_req.qidx = mce;
/* Use RSS with RSS index 0 */
- aq_req.mce.op = 1;
- aq_req.mce.index = 0;
+ aq_req.mce.op = mce_op;
+ aq_req.mce.index = index;
aq_req.mce.eol = eol;
aq_req.mce.pf_func = pcifunc;
aq_req.mce.next = next;
@@ -2985,6 +3008,206 @@ static int nix_blk_setup_mce(struct rvu *rvu, struct nix_hw *nix_hw,
return 0;
}
+static void nix_delete_mcast_mce_list(struct nix_mce_list *mce_list)
+{
+ struct hlist_node *tmp;
+ struct mce *mce;
+
+ /* Scan through the current list */
+ hlist_for_each_entry_safe(mce, tmp, &mce_list->head, node) {
+ hlist_del(&mce->node);
+ kfree(mce);
+ }
+
+ mce_list->count = 0;
+ mce_list->max = 0;
+}
+
+static int nix_get_last_mce_list_index(struct nix_mcast_grp_elem *elem)
+{
+ return elem->mce_start_index + elem->mcast_mce_list.count - 1;
+}
+
+static int nix_update_ingress_mce_list_hw(struct rvu *rvu,
+ struct nix_hw *nix_hw,
+ struct nix_mcast_grp_elem *elem)
+{
+ int idx, last_idx, next_idx, err;
+ struct nix_mce_list *mce_list;
+ struct mce *mce, *prev_mce;
+
+ mce_list = &elem->mcast_mce_list;
+ idx = elem->mce_start_index;
+ last_idx = nix_get_last_mce_list_index(elem);
+ hlist_for_each_entry(mce, &mce_list->head, node) {
+ if (idx > last_idx)
+ break;
+
+ if (!mce->is_active) {
+ if (idx == elem->mce_start_index) {
+ idx++;
+ prev_mce = mce;
+ elem->mce_start_index = idx;
+ continue;
+ } else if (idx == last_idx) {
+ err = nix_blk_setup_mce(rvu, nix_hw, idx - 1, NIX_AQ_INSTOP_WRITE,
+ prev_mce->pcifunc, next_idx,
+ prev_mce->rq_rss_index,
+ prev_mce->dest_type,
+ false);
+ if (err)
+ return err;
+
+ break;
+ }
+ }
+
+ next_idx = idx + 1;
+ /* EOL should be set in last MCE */
+ err = nix_blk_setup_mce(rvu, nix_hw, idx, NIX_AQ_INSTOP_WRITE,
+ mce->pcifunc, next_idx,
+ mce->rq_rss_index, mce->dest_type,
+ (next_idx > last_idx) ? true : false);
+ if (err)
+ return err;
+
+ idx++;
+ prev_mce = mce;
+ }
+
+ return 0;
+}
+
+static void nix_update_egress_mce_list_hw(struct rvu *rvu,
+ struct nix_hw *nix_hw,
+ struct nix_mcast_grp_elem *elem)
+{
+ struct nix_mce_list *mce_list;
+ int idx, last_idx, next_idx;
+ struct mce *mce, *prev_mce;
+ u64 regval;
+ u8 eol;
+
+ mce_list = &elem->mcast_mce_list;
+ idx = elem->mce_start_index;
+ last_idx = nix_get_last_mce_list_index(elem);
+ hlist_for_each_entry(mce, &mce_list->head, node) {
+ if (idx > last_idx)
+ break;
+
+ if (!mce->is_active) {
+ if (idx == elem->mce_start_index) {
+ idx++;
+ prev_mce = mce;
+ elem->mce_start_index = idx;
+ continue;
+ } else if (idx == last_idx) {
+ regval = (next_idx << 16) | (1 << 12) | prev_mce->channel;
+ rvu_write64(rvu, nix_hw->blkaddr,
+ NIX_AF_TX_MCASTX(idx - 1),
+ regval);
+ break;
+ }
+ }
+
+ eol = 0;
+ next_idx = idx + 1;
+ /* EOL should be set in last MCE */
+ if (next_idx > last_idx)
+ eol = 1;
+
+ regval = (next_idx << 16) | (eol << 12) | mce->channel;
+ rvu_write64(rvu, nix_hw->blkaddr,
+ NIX_AF_TX_MCASTX(idx),
+ regval);
+ idx++;
+ prev_mce = mce;
+ }
+}
+
+static int nix_del_mce_list_entry(struct rvu *rvu,
+ struct nix_hw *nix_hw,
+ struct nix_mcast_grp_elem *elem,
+ struct nix_mcast_grp_update_req *req)
+{
+ u32 num_entry = req->num_mce_entry;
+ struct nix_mce_list *mce_list;
+ struct mce *mce;
+ bool is_found;
+ int i;
+
+ mce_list = &elem->mcast_mce_list;
+ for (i = 0; i < num_entry; i++) {
+ is_found = false;
+ hlist_for_each_entry(mce, &mce_list->head, node) {
+ /* If already exists, then delete */
+ if (mce->pcifunc == req->pcifunc[i]) {
+ hlist_del(&mce->node);
+ kfree(mce);
+ mce_list->count--;
+ is_found = true;
+ break;
+ }
+ }
+
+ if (!is_found)
+ return NIX_AF_ERR_INVALID_MCAST_DEL_REQ;
+ }
+
+ mce_list->max = mce_list->count;
+ /* Dump the updated list to HW */
+ if (elem->dir == NIX_MCAST_INGRESS)
+ return nix_update_ingress_mce_list_hw(rvu, nix_hw, elem);
+
+ nix_update_egress_mce_list_hw(rvu, nix_hw, elem);
+ return 0;
+}
+
+static int nix_add_mce_list_entry(struct rvu *rvu,
+ struct nix_hw *nix_hw,
+ struct nix_mcast_grp_elem *elem,
+ struct nix_mcast_grp_update_req *req)
+{
+ u32 num_entry = req->num_mce_entry;
+ struct nix_mce_list *mce_list;
+ struct hlist_node *tmp;
+ struct mce *mce;
+ int i;
+
+ mce_list = &elem->mcast_mce_list;
+ for (i = 0; i < num_entry; i++) {
+ mce = kzalloc(sizeof(*mce), GFP_KERNEL);
+ if (!mce)
+ goto free_mce;
+
+ mce->pcifunc = req->pcifunc[i];
+ mce->channel = req->channel[i];
+ mce->rq_rss_index = req->rq_rss_index[i];
+ mce->dest_type = req->dest_type[i];
+ mce->is_active = 1;
+ hlist_add_head(&mce->node, &mce_list->head);
+ mce_list->count++;
+ }
+
+ mce_list->max += num_entry;
+
+ /* Dump the updated list to HW */
+ if (elem->dir == NIX_MCAST_INGRESS)
+ return nix_update_ingress_mce_list_hw(rvu, nix_hw, elem);
+
+ nix_update_egress_mce_list_hw(rvu, nix_hw, elem);
+ return 0;
+
+free_mce:
+ hlist_for_each_entry_safe(mce, tmp, &mce_list->head, node) {
+ hlist_del(&mce->node);
+ kfree(mce);
+ mce_list->count--;
+ }
+
+ return -ENOMEM;
+}
+
static int nix_update_mce_list_entry(struct nix_mce_list *mce_list,
u16 pcifunc, bool add)
{
@@ -3080,6 +3303,7 @@ int nix_update_mce_list(struct rvu *rvu, u16 pcifunc,
/* EOL should be set in last MCE */
err = nix_blk_setup_mce(rvu, nix_hw, idx, NIX_AQ_INSTOP_WRITE,
mce->pcifunc, next_idx,
+ 0, 1,
(next_idx > last_idx) ? true : false);
if (err)
goto end;
@@ -3160,6 +3384,16 @@ static int nix_update_mce_rule(struct rvu *rvu, u16 pcifunc,
return err;
}
+static void nix_setup_mcast_grp(struct nix_hw *nix_hw)
+{
+ struct nix_mcast_grp *mcast_grp = &nix_hw->mcast_grp;
+
+ INIT_LIST_HEAD(&mcast_grp->mcast_grp_head);
+ mutex_init(&mcast_grp->mcast_grp_lock);
+ mcast_grp->next_grp_index = 1;
+ mcast_grp->count = 0;
+}
+
static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw)
{
struct nix_mcast *mcast = &nix_hw->mcast;
@@ -3184,15 +3418,15 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw)
continue;
/* save start idx of broadcast mce list */
- pfvf->bcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
+ pfvf->bcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1, NIX_MCAST_INGRESS);
nix_mce_list_init(&pfvf->bcast_mce_list, numvfs + 1);
/* save start idx of multicast mce list */
- pfvf->mcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
+ pfvf->mcast_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1, NIX_MCAST_INGRESS);
nix_mce_list_init(&pfvf->mcast_mce_list, numvfs + 1);
/* save the start idx of promisc mce list */
- pfvf->promisc_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1);
+ pfvf->promisc_mce_idx = nix_alloc_mce_list(mcast, numvfs + 1, NIX_MCAST_INGRESS);
nix_mce_list_init(&pfvf->promisc_mce_list, numvfs + 1);
for (idx = 0; idx < (numvfs + 1); idx++) {
@@ -3207,7 +3441,7 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw)
err = nix_blk_setup_mce(rvu, nix_hw,
pfvf->bcast_mce_idx + idx,
NIX_AQ_INSTOP_INIT,
- pcifunc, 0, true);
+ pcifunc, 0, 0, 1, true);
if (err)
return err;
@@ -3215,7 +3449,7 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw)
err = nix_blk_setup_mce(rvu, nix_hw,
pfvf->mcast_mce_idx + idx,
NIX_AQ_INSTOP_INIT,
- pcifunc, 0, true);
+ pcifunc, 0, 0, 1, true);
if (err)
return err;
@@ -3223,7 +3457,7 @@ static int nix_setup_mce_tables(struct rvu *rvu, struct nix_hw *nix_hw)
err = nix_blk_setup_mce(rvu, nix_hw,
pfvf->promisc_mce_idx + idx,
NIX_AQ_INSTOP_INIT,
- pcifunc, 0, true);
+ pcifunc, 0, 0, 1, true);
if (err)
return err;
}
@@ -3238,13 +3472,30 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
int err, size;
size = (rvu_read64(rvu, blkaddr, NIX_AF_CONST3) >> 16) & 0x0F;
- size = (1ULL << size);
+ size = BIT_ULL(size);
+
+ /* Allocate bitmap for rx mce entries */
+ mcast->mce_counter[NIX_MCAST_INGRESS].max = 256UL << MC_TBL_SIZE;
+ err = rvu_alloc_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]);
+ if (err)
+ return -ENOMEM;
+
+ /* Allocate bitmap for tx mce entries */
+ mcast->mce_counter[NIX_MCAST_EGRESS].max = MC_TX_MAX;
+ err = rvu_alloc_bitmap(&mcast->mce_counter[NIX_MCAST_EGRESS]);
+ if (err) {
+ rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]);
+ return -ENOMEM;
+ }
/* Alloc memory for multicast/mirror replication entries */
err = qmem_alloc(rvu->dev, &mcast->mce_ctx,
- (256UL << MC_TBL_SIZE), size);
- if (err)
+ mcast->mce_counter[NIX_MCAST_INGRESS].max, size);
+ if (err) {
+ rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]);
+ rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_EGRESS]);
return -ENOMEM;
+ }
rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BASE,
(u64)mcast->mce_ctx->iova);
@@ -3257,8 +3508,11 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
size = rvu_read64(rvu, blkaddr, NIX_AF_MC_MIRROR_CONST) & 0xFFFF;
err = qmem_alloc(rvu->dev, &mcast->mcast_buf,
(8UL << MC_BUF_CNT), size);
- if (err)
+ if (err) {
+ rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_INGRESS]);
+ rvu_free_bitmap(&mcast->mce_counter[NIX_MCAST_EGRESS]);
return -ENOMEM;
+ }
rvu_write64(rvu, blkaddr, NIX_AF_RX_MCAST_BUF_BASE,
(u64)mcast->mcast_buf->iova);
@@ -3272,6 +3526,8 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr)
mutex_init(&mcast->mce_lock);
+ nix_setup_mcast_grp(nix_hw);
+
return nix_setup_mce_tables(rvu, nix_hw);
}
@@ -4698,6 +4954,74 @@ void rvu_nix_freemem(struct rvu *rvu)
}
}
+static void nix_mcast_update_action(struct rvu *rvu,
+ struct nix_mcast_grp_elem *elem)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct nix_rx_action rx_action = { 0 };
+ struct nix_tx_action tx_action = { 0 };
+ int npc_blkaddr;
+
+ npc_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (elem->dir == NIX_MCAST_INGRESS) {
+ *(u64 *)&rx_action = npc_get_mcam_action(rvu, mcam,
+ npc_blkaddr,
+ elem->mcam_index);
+ rx_action.index = elem->mce_start_index;
+ npc_set_mcam_action(rvu, mcam, npc_blkaddr, elem->mcam_index,
+ *(u64 *)&rx_action);
+ } else {
+ *(u64 *)&tx_action = npc_get_mcam_action(rvu, mcam,
+ npc_blkaddr,
+ elem->mcam_index);
+ tx_action.index = elem->mce_start_index;
+ npc_set_mcam_action(rvu, mcam, npc_blkaddr, elem->mcam_index,
+ *(u64 *)&tx_action);
+ }
+}
+
+static void nix_mcast_update_mce_entry(struct rvu *rvu, u16 pcifunc, u8 is_active)
+{
+ struct nix_mcast_grp_elem *elem;
+ struct nix_mcast_grp *mcast_grp;
+ struct nix_hw *nix_hw;
+ int blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return;
+
+ mcast_grp = &nix_hw->mcast_grp;
+
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+ list_for_each_entry(elem, &mcast_grp->mcast_grp_head, list) {
+ struct nix_mce_list *mce_list;
+ struct mce *mce;
+
+ /* Iterate the group elements and disable the element which
+ * received the disable request.
+ */
+ mce_list = &elem->mcast_mce_list;
+ hlist_for_each_entry(mce, &mce_list->head, node) {
+ if (mce->pcifunc == pcifunc) {
+ mce->is_active = is_active;
+ break;
+ }
+ }
+
+ /* Dump the updated list to HW */
+ if (elem->dir == NIX_MCAST_INGRESS)
+ nix_update_ingress_mce_list_hw(rvu, nix_hw, elem);
+ else
+ nix_update_egress_mce_list_hw(rvu, nix_hw, elem);
+
+ /* Update the multicast index in NPC rule */
+ nix_mcast_update_action(rvu, elem);
+ }
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+}
+
int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
struct msg_rsp *rsp)
{
@@ -4709,6 +5033,9 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req,
if (err)
return err;
+ /* Enable the interface if it is in any multicast list */
+ nix_mcast_update_mce_entry(rvu, pcifunc, 1);
+
rvu_npc_enable_default_entries(rvu, pcifunc, nixlf);
npc_mcam_enable_flows(rvu, pcifunc);
@@ -4733,6 +5060,9 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req,
return err;
rvu_npc_disable_mcam_entries(rvu, pcifunc, nixlf);
+ /* Disable the interface if it is in any multicast list */
+ nix_mcast_update_mce_entry(rvu, pcifunc, 0);
+
pfvf = rvu_get_pfvf(rvu, pcifunc);
clear_bit(NIXLF_INITIALIZED, &pfvf->flags);
@@ -5707,3 +6037,361 @@ int rvu_mbox_handler_nix_bandprof_get_hwinfo(struct rvu *rvu, struct msg_req *re
return 0;
}
+
+static struct nix_mcast_grp_elem *rvu_nix_mcast_find_grp_elem(struct nix_mcast_grp *mcast_grp,
+ u32 mcast_grp_idx)
+{
+ struct nix_mcast_grp_elem *iter;
+ bool is_found = false;
+
+ list_for_each_entry(iter, &mcast_grp->mcast_grp_head, list) {
+ if (iter->mcast_grp_idx == mcast_grp_idx) {
+ is_found = true;
+ break;
+ }
+ }
+
+ if (is_found)
+ return iter;
+
+ return NULL;
+}
+
+int rvu_nix_mcast_get_mce_index(struct rvu *rvu, u16 pcifunc, u32 mcast_grp_idx)
+{
+ struct nix_mcast_grp_elem *elem;
+ struct nix_mcast_grp *mcast_grp;
+ struct nix_hw *nix_hw;
+ int blkaddr, ret;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return NIX_AF_ERR_INVALID_NIXBLK;
+
+ mcast_grp = &nix_hw->mcast_grp;
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+ elem = rvu_nix_mcast_find_grp_elem(mcast_grp, mcast_grp_idx);
+ if (!elem)
+ ret = NIX_AF_ERR_INVALID_MCAST_GRP;
+ else
+ ret = elem->mce_start_index;
+
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+ return ret;
+}
+
+void rvu_nix_mcast_flr_free_entries(struct rvu *rvu, u16 pcifunc)
+{
+ struct nix_mcast_grp_destroy_req dreq = { 0 };
+ struct nix_mcast_grp_update_req ureq = { 0 };
+ struct nix_mcast_grp_update_rsp ursp = { 0 };
+ struct nix_mcast_grp_elem *elem, *tmp;
+ struct nix_mcast_grp *mcast_grp;
+ struct nix_hw *nix_hw;
+ int blkaddr;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return;
+
+ mcast_grp = &nix_hw->mcast_grp;
+
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+ list_for_each_entry_safe(elem, tmp, &mcast_grp->mcast_grp_head, list) {
+ struct nix_mce_list *mce_list;
+ struct hlist_node *tmp;
+ struct mce *mce;
+
+ /* If the pcifunc which created the multicast/mirror
+ * group received an FLR, then delete the entire group.
+ */
+ if (elem->pcifunc == pcifunc) {
+ /* Delete group */
+ dreq.hdr.pcifunc = elem->pcifunc;
+ dreq.mcast_grp_idx = elem->mcast_grp_idx;
+ dreq.is_af = 1;
+ rvu_mbox_handler_nix_mcast_grp_destroy(rvu, &dreq, NULL);
+ continue;
+ }
+
+ /* Iterate the group elements and delete the element which
+ * received the FLR.
+ */
+ mce_list = &elem->mcast_mce_list;
+ hlist_for_each_entry_safe(mce, tmp, &mce_list->head, node) {
+ if (mce->pcifunc == pcifunc) {
+ ureq.hdr.pcifunc = pcifunc;
+ ureq.num_mce_entry = 1;
+ ureq.mcast_grp_idx = elem->mcast_grp_idx;
+ ureq.op = NIX_MCAST_OP_DEL_ENTRY;
+ ureq.pcifunc[0] = pcifunc;
+ ureq.is_af = 1;
+ rvu_mbox_handler_nix_mcast_grp_update(rvu, &ureq, &ursp);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+}
+
+int rvu_nix_mcast_update_mcam_entry(struct rvu *rvu, u16 pcifunc,
+ u32 mcast_grp_idx, u16 mcam_index)
+{
+ struct nix_mcast_grp_elem *elem;
+ struct nix_mcast_grp *mcast_grp;
+ struct nix_hw *nix_hw;
+ int blkaddr, ret = 0;
+
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc);
+ nix_hw = get_nix_hw(rvu->hw, blkaddr);
+ if (!nix_hw)
+ return NIX_AF_ERR_INVALID_NIXBLK;
+
+ mcast_grp = &nix_hw->mcast_grp;
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+ elem = rvu_nix_mcast_find_grp_elem(mcast_grp, mcast_grp_idx);
+ if (!elem)
+ ret = NIX_AF_ERR_INVALID_MCAST_GRP;
+ else
+ elem->mcam_index = mcam_index;
+
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+ return ret;
+}
+
+int rvu_mbox_handler_nix_mcast_grp_create(struct rvu *rvu,
+ struct nix_mcast_grp_create_req *req,
+ struct nix_mcast_grp_create_rsp *rsp)
+{
+ struct nix_mcast_grp_elem *elem;
+ struct nix_mcast_grp *mcast_grp;
+ struct nix_hw *nix_hw;
+ int blkaddr, err;
+
+ err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mcast_grp = &nix_hw->mcast_grp;
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ INIT_HLIST_HEAD(&elem->mcast_mce_list.head);
+ elem->mcam_index = -1;
+ elem->mce_start_index = -1;
+ elem->pcifunc = req->hdr.pcifunc;
+ elem->dir = req->dir;
+ elem->mcast_grp_idx = mcast_grp->next_grp_index++;
+
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+ list_add_tail(&elem->list, &mcast_grp->mcast_grp_head);
+ mcast_grp->count++;
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+
+ rsp->mcast_grp_idx = elem->mcast_grp_idx;
+ return 0;
+}
+
+int rvu_mbox_handler_nix_mcast_grp_destroy(struct rvu *rvu,
+ struct nix_mcast_grp_destroy_req *req,
+ struct msg_rsp *rsp)
+{
+ struct npc_delete_flow_req uninstall_req = { 0 };
+ struct npc_delete_flow_rsp uninstall_rsp = { 0 };
+ struct nix_mcast_grp_elem *elem;
+ struct nix_mcast_grp *mcast_grp;
+ int blkaddr, err, ret = 0;
+ struct nix_mcast *mcast;
+ struct nix_hw *nix_hw;
+
+ err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mcast_grp = &nix_hw->mcast_grp;
+
+ /* If AF is requesting for the deletion,
+ * then AF is already taking the lock
+ */
+ if (!req->is_af)
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+
+ elem = rvu_nix_mcast_find_grp_elem(mcast_grp, req->mcast_grp_idx);
+ if (!elem) {
+ ret = NIX_AF_ERR_INVALID_MCAST_GRP;
+ goto unlock_grp;
+ }
+
+ /* If no mce entries are associated with the group
+ * then just remove it from the global list.
+ */
+ if (!elem->mcast_mce_list.count)
+ goto delete_grp;
+
+ /* Delete the associated mcam entry and
+ * remove all mce entries from the group
+ */
+ mcast = &nix_hw->mcast;
+ mutex_lock(&mcast->mce_lock);
+ if (elem->mcam_index != -1) {
+ uninstall_req.hdr.pcifunc = req->hdr.pcifunc;
+ uninstall_req.entry = elem->mcam_index;
+ rvu_mbox_handler_npc_delete_flow(rvu, &uninstall_req, &uninstall_rsp);
+ }
+
+ nix_free_mce_list(mcast, elem->mcast_mce_list.count,
+ elem->mce_start_index, elem->dir);
+ nix_delete_mcast_mce_list(&elem->mcast_mce_list);
+ mutex_unlock(&mcast->mce_lock);
+
+delete_grp:
+ list_del(&elem->list);
+ kfree(elem);
+ mcast_grp->count--;
+
+unlock_grp:
+ if (!req->is_af)
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+
+ return ret;
+}
+
+int rvu_mbox_handler_nix_mcast_grp_update(struct rvu *rvu,
+ struct nix_mcast_grp_update_req *req,
+ struct nix_mcast_grp_update_rsp *rsp)
+{
+ struct nix_mcast_grp_destroy_req dreq = { 0 };
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct nix_mcast_grp_elem *elem;
+ struct nix_mcast_grp *mcast_grp;
+ int blkaddr, err, npc_blkaddr;
+ u16 prev_count, new_count;
+ struct nix_mcast *mcast;
+ struct nix_hw *nix_hw;
+ int i, ret;
+
+ if (!req->num_mce_entry)
+ return 0;
+
+ err = nix_get_struct_ptrs(rvu, req->hdr.pcifunc, &nix_hw, &blkaddr);
+ if (err)
+ return err;
+
+ mcast_grp = &nix_hw->mcast_grp;
+
+ /* If AF is requesting for the updation,
+ * then AF is already taking the lock
+ */
+ if (!req->is_af)
+ mutex_lock(&mcast_grp->mcast_grp_lock);
+
+ elem = rvu_nix_mcast_find_grp_elem(mcast_grp, req->mcast_grp_idx);
+ if (!elem) {
+ ret = NIX_AF_ERR_INVALID_MCAST_GRP;
+ goto unlock_grp;
+ }
+
+ /* If any pcifunc matches the group's pcifunc, then we can
+ * delete the entire group.
+ */
+ if (req->op == NIX_MCAST_OP_DEL_ENTRY) {
+ for (i = 0; i < req->num_mce_entry; i++) {
+ if (elem->pcifunc == req->pcifunc[i]) {
+ /* Delete group */
+ dreq.hdr.pcifunc = elem->pcifunc;
+ dreq.mcast_grp_idx = elem->mcast_grp_idx;
+ dreq.is_af = 1;
+ rvu_mbox_handler_nix_mcast_grp_destroy(rvu, &dreq, NULL);
+ ret = 0;
+ goto unlock_grp;
+ }
+ }
+ }
+
+ mcast = &nix_hw->mcast;
+ mutex_lock(&mcast->mce_lock);
+ npc_blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (elem->mcam_index != -1)
+ npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, elem->mcam_index, false);
+
+ prev_count = elem->mcast_mce_list.count;
+ if (req->op == NIX_MCAST_OP_ADD_ENTRY) {
+ new_count = prev_count + req->num_mce_entry;
+ if (prev_count)
+ nix_free_mce_list(mcast, prev_count, elem->mce_start_index, elem->dir);
+
+ elem->mce_start_index = nix_alloc_mce_list(mcast, new_count, elem->dir);
+
+ /* It is possible not to get contiguous memory */
+ if (elem->mce_start_index < 0) {
+ if (elem->mcam_index != -1) {
+ npc_enable_mcam_entry(rvu, mcam, npc_blkaddr,
+ elem->mcam_index, true);
+ ret = NIX_AF_ERR_NON_CONTIG_MCE_LIST;
+ goto unlock_mce;
+ }
+ }
+
+ ret = nix_add_mce_list_entry(rvu, nix_hw, elem, req);
+ if (ret) {
+ nix_free_mce_list(mcast, new_count, elem->mce_start_index, elem->dir);
+ if (prev_count)
+ elem->mce_start_index = nix_alloc_mce_list(mcast,
+ prev_count,
+ elem->dir);
+
+ if (elem->mcam_index != -1)
+ npc_enable_mcam_entry(rvu, mcam, npc_blkaddr,
+ elem->mcam_index, true);
+
+ goto unlock_mce;
+ }
+ } else {
+ if (!prev_count || prev_count < req->num_mce_entry) {
+ if (elem->mcam_index != -1)
+ npc_enable_mcam_entry(rvu, mcam, npc_blkaddr,
+ elem->mcam_index, true);
+ ret = NIX_AF_ERR_INVALID_MCAST_DEL_REQ;
+ goto unlock_mce;
+ }
+
+ nix_free_mce_list(mcast, prev_count, elem->mce_start_index, elem->dir);
+ new_count = prev_count - req->num_mce_entry;
+ elem->mce_start_index = nix_alloc_mce_list(mcast, new_count, elem->dir);
+ ret = nix_del_mce_list_entry(rvu, nix_hw, elem, req);
+ if (ret) {
+ nix_free_mce_list(mcast, new_count, elem->mce_start_index, elem->dir);
+ elem->mce_start_index = nix_alloc_mce_list(mcast, prev_count, elem->dir);
+ if (elem->mcam_index != -1)
+ npc_enable_mcam_entry(rvu, mcam,
+ npc_blkaddr,
+ elem->mcam_index,
+ true);
+
+ goto unlock_mce;
+ }
+ }
+
+ if (elem->mcam_index == -1) {
+ rsp->mce_start_index = elem->mce_start_index;
+ ret = 0;
+ goto unlock_mce;
+ }
+
+ nix_mcast_update_action(rvu, elem);
+ npc_enable_mcam_entry(rvu, mcam, npc_blkaddr, elem->mcam_index, true);
+ rsp->mce_start_index = elem->mce_start_index;
+ ret = 0;
+
+unlock_mce:
+ mutex_unlock(&mcast->mce_lock);
+
+unlock_grp:
+ if (!req->is_af)
+ mutex_unlock(&mcast_grp->mcast_grp_lock);
+
+ return ret;
+}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index 0bcf3e559280..516adb50f9f6 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -61,28 +61,6 @@ int rvu_npc_get_tx_nibble_cfg(struct rvu *rvu, u64 nibble_ena)
return 0;
}
-static int npc_mcam_verify_pf_func(struct rvu *rvu,
- struct mcam_entry *entry_data, u8 intf,
- u16 pcifunc)
-{
- u16 pf_func, pf_func_mask;
-
- if (is_npc_intf_rx(intf))
- return 0;
-
- pf_func_mask = (entry_data->kw_mask[0] >> 32) &
- NPC_KEX_PF_FUNC_MASK;
- pf_func = (entry_data->kw[0] >> 32) & NPC_KEX_PF_FUNC_MASK;
-
- pf_func = be16_to_cpu((__force __be16)pf_func);
- if (pf_func_mask != NPC_KEX_PF_FUNC_MASK ||
- ((pf_func & ~RVU_PFVF_FUNC_MASK) !=
- (pcifunc & ~RVU_PFVF_FUNC_MASK)))
- return -EINVAL;
-
- return 0;
-}
-
void rvu_npc_set_pkind(struct rvu *rvu, int pkind, struct rvu_pfvf *pfvf)
{
int blkaddr;
@@ -437,6 +415,10 @@ static void npc_fixup_vf_rule(struct rvu *rvu, struct npc_mcam *mcam,
return;
}
+ /* AF modifies given action iff PF/VF has requested for it */
+ if ((entry->action & 0xFULL) != NIX_RX_ACTION_DEFAULT)
+ return;
+
/* copy VF default entry action to the VF mcam entry */
rx_action = npc_get_default_entry_action(rvu, mcam, blkaddr,
target_func);
@@ -595,8 +577,8 @@ static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_CFG(dest, dbank), cfg);
}
-static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
- int blkaddr, int index)
+u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index)
{
int bank = npc_get_bank(mcam, index);
@@ -605,6 +587,16 @@ static u64 npc_get_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
NPC_AF_MCAMEX_BANKX_ACTION(index, bank));
}
+void npc_set_mcam_action(struct rvu *rvu, struct npc_mcam *mcam,
+ int blkaddr, int index, u64 cfg)
+{
+ int bank = npc_get_bank(mcam, index);
+
+ index &= (mcam->banksize - 1);
+ return rvu_write64(rvu, blkaddr,
+ NPC_AF_MCAMEX_BANKX_ACTION(index, bank), cfg);
+}
+
void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc,
int nixlf, u64 chan, u8 *mac_addr)
{
@@ -1836,7 +1828,21 @@ static void npc_parser_profile_init(struct rvu *rvu, int blkaddr)
npc_program_kpu_profile(rvu, blkaddr, idx, &rvu->kpu.kpu[idx]);
}
-static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
+void npc_mcam_rsrcs_deinit(struct rvu *rvu)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+
+ bitmap_free(mcam->bmap);
+ bitmap_free(mcam->bmap_reverse);
+ kfree(mcam->entry2pfvf_map);
+ kfree(mcam->cntr2pfvf_map);
+ kfree(mcam->entry2cntr_map);
+ kfree(mcam->cntr_refcnt);
+ kfree(mcam->entry2target_pffunc);
+ kfree(mcam->counters.bmap);
+}
+
+int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
{
int nixlf_count = rvu_get_nixlf_count(rvu);
struct npc_mcam *mcam = &rvu->hw->mcam;
@@ -1880,24 +1886,22 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
mcam->pf_offset = mcam->nixlf_offset + nixlf_count;
/* Allocate bitmaps for managing MCAM entries */
- mcam->bmap = devm_kcalloc(rvu->dev, BITS_TO_LONGS(mcam->bmap_entries),
- sizeof(long), GFP_KERNEL);
+ mcam->bmap = bitmap_zalloc(mcam->bmap_entries, GFP_KERNEL);
if (!mcam->bmap)
return -ENOMEM;
- mcam->bmap_reverse = devm_kcalloc(rvu->dev,
- BITS_TO_LONGS(mcam->bmap_entries),
- sizeof(long), GFP_KERNEL);
+ mcam->bmap_reverse = bitmap_zalloc(mcam->bmap_entries, GFP_KERNEL);
if (!mcam->bmap_reverse)
- return -ENOMEM;
+ goto free_bmap;
mcam->bmap_fcnt = mcam->bmap_entries;
/* Alloc memory for saving entry to RVU PFFUNC allocation mapping */
- mcam->entry2pfvf_map = devm_kcalloc(rvu->dev, mcam->bmap_entries,
- sizeof(u16), GFP_KERNEL);
+ mcam->entry2pfvf_map = kcalloc(mcam->bmap_entries, sizeof(u16),
+ GFP_KERNEL);
+
if (!mcam->entry2pfvf_map)
- return -ENOMEM;
+ goto free_bmap_reverse;
/* Reserve 1/8th of MCAM entries at the bottom for low priority
* allocations and another 1/8th at the top for high priority
@@ -1916,31 +1920,31 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
*/
err = rvu_alloc_bitmap(&mcam->counters);
if (err)
- return err;
+ goto free_entry_map;
- mcam->cntr2pfvf_map = devm_kcalloc(rvu->dev, mcam->counters.max,
- sizeof(u16), GFP_KERNEL);
+ mcam->cntr2pfvf_map = kcalloc(mcam->counters.max, sizeof(u16),
+ GFP_KERNEL);
if (!mcam->cntr2pfvf_map)
- goto free_mem;
+ goto free_cntr_bmap;
/* Alloc memory for MCAM entry to counter mapping and for tracking
* counter's reference count.
*/
- mcam->entry2cntr_map = devm_kcalloc(rvu->dev, mcam->bmap_entries,
- sizeof(u16), GFP_KERNEL);
+ mcam->entry2cntr_map = kcalloc(mcam->bmap_entries, sizeof(u16),
+ GFP_KERNEL);
if (!mcam->entry2cntr_map)
- goto free_mem;
+ goto free_cntr_map;
- mcam->cntr_refcnt = devm_kcalloc(rvu->dev, mcam->counters.max,
- sizeof(u16), GFP_KERNEL);
+ mcam->cntr_refcnt = kcalloc(mcam->counters.max, sizeof(u16),
+ GFP_KERNEL);
if (!mcam->cntr_refcnt)
- goto free_mem;
+ goto free_entry_cntr_map;
/* Alloc memory for saving target device of mcam rule */
- mcam->entry2target_pffunc = devm_kcalloc(rvu->dev, mcam->total_entries,
- sizeof(u16), GFP_KERNEL);
+ mcam->entry2target_pffunc = kmalloc_array(mcam->total_entries,
+ sizeof(u16), GFP_KERNEL);
if (!mcam->entry2target_pffunc)
- goto free_mem;
+ goto free_cntr_refcnt;
for (index = 0; index < mcam->bmap_entries; index++) {
mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
@@ -1954,8 +1958,21 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr)
return 0;
-free_mem:
+free_cntr_refcnt:
+ kfree(mcam->cntr_refcnt);
+free_entry_cntr_map:
+ kfree(mcam->entry2cntr_map);
+free_cntr_map:
+ kfree(mcam->cntr2pfvf_map);
+free_cntr_bmap:
kfree(mcam->counters.bmap);
+free_entry_map:
+ kfree(mcam->entry2pfvf_map);
+free_bmap_reverse:
+ bitmap_free(mcam->bmap_reverse);
+free_bmap:
+ bitmap_free(mcam->bmap);
+
return -ENOMEM;
}
@@ -2163,6 +2180,7 @@ void rvu_npc_freemem(struct rvu *rvu)
struct npc_mcam *mcam = &rvu->hw->mcam;
kfree(pkind->rsrc.bmap);
+ npc_mcam_rsrcs_deinit(rvu);
kfree(mcam->counters.bmap);
if (rvu->kpu_prfl_addr)
iounmap(rvu->kpu_prfl_addr);
@@ -2678,18 +2696,17 @@ int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu,
rsp->entry = NPC_MCAM_ENTRY_INVALID;
rsp->free_count = 0;
- /* Check if ref_entry is within range */
- if (req->priority && req->ref_entry >= mcam->bmap_entries) {
- dev_err(rvu->dev, "%s: reference entry %d is out of range\n",
- __func__, req->ref_entry);
- return NPC_MCAM_INVALID_REQ;
- }
+ /* Check if ref_entry is greater that the range
+ * then set it to max value.
+ */
+ if (req->ref_entry > mcam->bmap_entries)
+ req->ref_entry = mcam->bmap_entries;
/* ref_entry can't be '0' if requested priority is high.
* Can't be last entry if requested priority is low.
*/
if ((!req->ref_entry && req->priority == NPC_MCAM_HIGHER_PRIO) ||
- ((req->ref_entry == (mcam->bmap_entries - 1)) &&
+ ((req->ref_entry == mcam->bmap_entries) &&
req->priority == NPC_MCAM_LOWER_PRIO))
return NPC_MCAM_INVALID_REQ;
@@ -2816,12 +2833,6 @@ int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu,
else
nix_intf = pfvf->nix_rx_intf;
- if (!is_pffunc_af(pcifunc) &&
- npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf, pcifunc)) {
- rc = NPC_MCAM_INVALID_REQ;
- goto exit;
- }
-
/* For AF installed rules, the nix_intf should be set to target NIX */
if (is_pffunc_af(req->hdr.pcifunc))
nix_intf = req->intf;
@@ -3173,10 +3184,6 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu,
if (!is_npc_interface_valid(rvu, req->intf))
return NPC_MCAM_INVALID_REQ;
- if (npc_mcam_verify_pf_func(rvu, &req->entry_data, req->intf,
- req->hdr.pcifunc))
- return NPC_MCAM_INVALID_REQ;
-
/* Try to allocate a MCAM entry */
entry_req.hdr.pcifunc = req->hdr.pcifunc;
entry_req.contig = true;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
index 114e4ec21802..c75669c8fde7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_fs.c
@@ -51,6 +51,8 @@ static const char * const npc_flow_names[] = {
[NPC_MPLS3_TTL] = "lse depth 3 ttl",
[NPC_MPLS4_LBTCBOS] = "lse depth 4 label tc bos",
[NPC_MPLS4_TTL] = "lse depth 4",
+ [NPC_TYPE_ICMP] = "icmp type",
+ [NPC_CODE_ICMP] = "icmp code",
[NPC_UNKNOWN] = "unknown",
};
@@ -526,6 +528,8 @@ do { \
NPC_SCAN_HDR(NPC_DPORT_TCP, NPC_LID_LD, NPC_LT_LD_TCP, 2, 2);
NPC_SCAN_HDR(NPC_SPORT_SCTP, NPC_LID_LD, NPC_LT_LD_SCTP, 0, 2);
NPC_SCAN_HDR(NPC_DPORT_SCTP, NPC_LID_LD, NPC_LT_LD_SCTP, 2, 2);
+ NPC_SCAN_HDR(NPC_TYPE_ICMP, NPC_LID_LD, NPC_LT_LD_ICMP, 0, 1);
+ NPC_SCAN_HDR(NPC_CODE_ICMP, NPC_LID_LD, NPC_LT_LD_ICMP, 1, 1);
NPC_SCAN_HDR(NPC_ETYPE_ETHER, NPC_LID_LA, NPC_LT_LA_ETHER, 12, 2);
NPC_SCAN_HDR(NPC_ETYPE_TAG1, NPC_LID_LB, NPC_LT_LB_CTAG, 4, 2);
NPC_SCAN_HDR(NPC_ETYPE_TAG2, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 8, 2);
@@ -555,7 +559,7 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 *features = &mcam->rx_features;
- u64 tcp_udp_sctp;
+ u64 proto_flags;
int hdr;
if (is_npc_intf_tx(intf))
@@ -566,18 +570,21 @@ static void npc_set_features(struct rvu *rvu, int blkaddr, u8 intf)
*features |= BIT_ULL(hdr);
}
- tcp_udp_sctp = BIT_ULL(NPC_SPORT_TCP) | BIT_ULL(NPC_SPORT_UDP) |
+ proto_flags = BIT_ULL(NPC_SPORT_TCP) | BIT_ULL(NPC_SPORT_UDP) |
BIT_ULL(NPC_DPORT_TCP) | BIT_ULL(NPC_DPORT_UDP) |
- BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP);
+ BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP) |
+ BIT_ULL(NPC_SPORT_SCTP) | BIT_ULL(NPC_DPORT_SCTP) |
+ BIT_ULL(NPC_TYPE_ICMP) | BIT_ULL(NPC_CODE_ICMP);
/* for tcp/udp/sctp corresponding layer type should be in the key */
- if (*features & tcp_udp_sctp) {
+ if (*features & proto_flags) {
if (!npc_check_field(rvu, blkaddr, NPC_LD, intf))
- *features &= ~tcp_udp_sctp;
+ *features &= ~proto_flags;
else
*features |= BIT_ULL(NPC_IPPROTO_TCP) |
BIT_ULL(NPC_IPPROTO_UDP) |
- BIT_ULL(NPC_IPPROTO_SCTP);
+ BIT_ULL(NPC_IPPROTO_SCTP) |
+ BIT_ULL(NPC_IPPROTO_ICMP);
}
/* for AH/ICMP/ICMPv6/, check if corresponding layer type is present in the key */
@@ -971,6 +978,10 @@ do { \
ntohs(mask->sport), 0);
NPC_WRITE_FLOW(NPC_DPORT_SCTP, dport, ntohs(pkt->dport), 0,
ntohs(mask->dport), 0);
+ NPC_WRITE_FLOW(NPC_TYPE_ICMP, icmp_type, pkt->icmp_type, 0,
+ mask->icmp_type, 0);
+ NPC_WRITE_FLOW(NPC_CODE_ICMP, icmp_code, pkt->icmp_code, 0,
+ mask->icmp_code, 0);
NPC_WRITE_FLOW(NPC_IPSEC_SPI, spi, ntohl(pkt->spi), 0,
ntohl(mask->spi), 0);
@@ -1106,13 +1117,40 @@ static void rvu_mcam_add_counter_to_rule(struct rvu *rvu, u16 pcifunc,
}
}
-static void npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
- struct mcam_entry *entry,
- struct npc_install_flow_req *req,
- u16 target, bool pf_set_vfs_mac)
+static int npc_mcast_update_action_index(struct rvu *rvu, struct npc_install_flow_req *req,
+ u64 op, void *action)
+{
+ int mce_index;
+
+ /* If a PF/VF is installing a multicast rule then it is expected
+ * that the PF/VF should have created a group for the multicast/mirror
+ * list. Otherwise reject the configuration.
+ * During this scenario, req->index is set as multicast/mirror
+ * group index.
+ */
+ if (req->hdr.pcifunc &&
+ (op == NIX_RX_ACTIONOP_MCAST || op == NIX_TX_ACTIONOP_MCAST)) {
+ mce_index = rvu_nix_mcast_get_mce_index(rvu, req->hdr.pcifunc, req->index);
+ if (mce_index < 0)
+ return mce_index;
+
+ if (op == NIX_RX_ACTIONOP_MCAST)
+ ((struct nix_rx_action *)action)->index = mce_index;
+ else
+ ((struct nix_tx_action *)action)->index = mce_index;
+ }
+
+ return 0;
+}
+
+static int npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct mcam_entry *entry,
+ struct npc_install_flow_req *req,
+ u16 target, bool pf_set_vfs_mac)
{
struct rvu_switch *rswitch = &rvu->rswitch;
struct nix_rx_action action;
+ int ret;
if (rswitch->mode == DEVLINK_ESWITCH_MODE_SWITCHDEV && pf_set_vfs_mac)
req->chan_mask = 0x0; /* Do not care channel */
@@ -1124,6 +1162,11 @@ static void npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
action.pf_func = target;
action.op = req->op;
action.index = req->index;
+
+ ret = npc_mcast_update_action_index(rvu, req, action.op, (void *)&action);
+ if (ret)
+ return ret;
+
action.match_id = req->match_id;
action.flow_key_alg = req->flow_key_alg;
@@ -1155,14 +1198,17 @@ static void npc_update_rx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
FIELD_PREP(RX_VTAG1_TYPE_MASK, req->vtag1_type) |
FIELD_PREP(RX_VTAG1_LID_MASK, NPC_LID_LB) |
FIELD_PREP(RX_VTAG1_RELPTR_MASK, 4);
+
+ return 0;
}
-static void npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
- struct mcam_entry *entry,
- struct npc_install_flow_req *req, u16 target)
+static int npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
+ struct mcam_entry *entry,
+ struct npc_install_flow_req *req, u16 target)
{
struct nix_tx_action action;
u64 mask = ~0ULL;
+ int ret;
/* If AF is installing then do not care about
* PF_FUNC in Send Descriptor
@@ -1176,6 +1222,11 @@ static void npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
*(u64 *)&action = 0x00;
action.op = req->op;
action.index = req->index;
+
+ ret = npc_mcast_update_action_index(rvu, req, action.op, (void *)&action);
+ if (ret)
+ return ret;
+
action.match_id = req->match_id;
entry->action = *(u64 *)&action;
@@ -1191,6 +1242,8 @@ static void npc_update_tx_entry(struct rvu *rvu, struct rvu_pfvf *pfvf,
FIELD_PREP(TX_VTAG1_OP_MASK, req->vtag1_op) |
FIELD_PREP(TX_VTAG1_LID_MASK, NPC_LID_LA) |
FIELD_PREP(TX_VTAG1_RELPTR_MASK, 24);
+
+ return 0;
}
static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
@@ -1220,10 +1273,15 @@ static int npc_install_flow(struct rvu *rvu, int blkaddr, u16 target,
npc_update_flow(rvu, entry, features, &req->packet, &req->mask, &dummy,
req->intf, blkaddr);
- if (is_npc_intf_rx(req->intf))
- npc_update_rx_entry(rvu, pfvf, entry, req, target, pf_set_vfs_mac);
- else
- npc_update_tx_entry(rvu, pfvf, entry, req, target);
+ if (is_npc_intf_rx(req->intf)) {
+ err = npc_update_rx_entry(rvu, pfvf, entry, req, target, pf_set_vfs_mac);
+ if (err)
+ return err;
+ } else {
+ err = npc_update_tx_entry(rvu, pfvf, entry, req, target);
+ if (err)
+ return err;
+ }
/* Default unicast rules do not exist for TX */
if (is_npc_intf_tx(req->intf))
@@ -1340,6 +1398,10 @@ find_rule:
return rvu_nix_setup_ratelimit_aggr(rvu, req->hdr.pcifunc,
req->index, req->match_id);
+ if (owner && req->op == NIX_RX_ACTIONOP_MCAST)
+ return rvu_nix_mcast_update_mcam_entry(rvu, req->hdr.pcifunc,
+ req->index, entry_index);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
index 18c1c9f361cc..6f73ad9807f0 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h
@@ -734,5 +734,7 @@
#define APR_LMT_MAP_ENT_DIS_SCH_CMP_SHIFT 23
#define APR_LMT_MAP_ENT_SCH_ENA_SHIFT 22
#define APR_LMT_MAP_ENT_DIS_LINE_PREF_SHIFT 21
+#define LMTST_THROTTLE_MASK GENMASK_ULL(38, 35)
+#define LMTST_WR_PEND_MAX 15
#endif /* RVU_REG_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
index edc9367b1b95..5ef406c7e8a4 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h
@@ -340,11 +340,12 @@ struct nix_aq_res_s {
/* NIX Completion queue context structure */
struct nix_cq_ctx_s {
u64 base;
- u64 rsvd_64_67 : 4;
+ u64 lbp_ena : 1;
+ u64 lbpid_low : 3;
u64 bp_ena : 1;
- u64 rsvd_69_71 : 3;
+ u64 lbpid_med : 3;
u64 bpid : 9;
- u64 rsvd_81_83 : 3;
+ u64 lbpid_high : 3;
u64 qint_idx : 7;
u64 cq_err : 1;
u64 cint_idx : 7;
@@ -358,10 +359,14 @@ struct nix_cq_ctx_s {
u64 drop : 8;
u64 drop_ena : 1;
u64 ena : 1;
- u64 rsvd_210_211 : 2;
- u64 substream : 20;
+ u64 cpt_drop_err_en : 1;
+ u64 rsvd_211 : 1;
+ u64 substream : 12;
+ u64 stash_thresh : 4;
+ u64 lbp_frac : 4;
u64 caching : 1;
- u64 rsvd_233_235 : 3;
+ u64 stashing : 1;
+ u64 rsvd_234_235 : 2;
u64 qsize : 4;
u64 cq_err_int : 8;
u64 cq_err_int_ena : 8;
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
index 7ca6941ea0b9..02d0b707aea5 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
@@ -951,8 +951,11 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
if (pfvf->ptp && qidx < pfvf->hw.tx_queues) {
err = qmem_alloc(pfvf->dev, &sq->timestamps, qset->sqe_cnt,
sizeof(*sq->timestamps));
- if (err)
+ if (err) {
+ kfree(sq->sg);
+ sq->sg = NULL;
return err;
+ }
}
sq->head = 0;
@@ -968,7 +971,14 @@ int otx2_sq_init(struct otx2_nic *pfvf, u16 qidx, u16 sqb_aura)
sq->stats.bytes = 0;
sq->stats.pkts = 0;
- return pfvf->hw_ops->sq_aq_init(pfvf, qidx, sqb_aura);
+ err = pfvf->hw_ops->sq_aq_init(pfvf, qidx, sqb_aura);
+ if (err) {
+ kfree(sq->sg);
+ sq->sg = NULL;
+ return err;
+ }
+
+ return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
index 53f6258a973c..7f786de61014 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
@@ -314,7 +314,6 @@ static int otx2_set_channels(struct net_device *dev,
pfvf->hw.tx_queues = channel->tx_count;
if (pfvf->xdp_prog)
pfvf->hw.xdp_queues = channel->rx_count;
- pfvf->hw.non_qos_queues = pfvf->hw.tx_queues + pfvf->hw.xdp_queues;
if (if_up)
err = dev->netdev_ops->ndo_open(dev);
@@ -835,21 +834,26 @@ static int otx2_rss_ctx_create(struct otx2_nic *pfvf,
return 0;
}
-/* RSS context configuration */
-static int otx2_set_rxfh_context(struct net_device *dev, const u32 *indir,
- const u8 *hkey, const u8 hfunc,
- u32 *rss_context, bool delete)
+/* Configure RSS table and hash key */
+static int otx2_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
+ u32 rss_context = DEFAULT_RSS_CONTEXT_GROUP;
struct otx2_nic *pfvf = netdev_priv(dev);
struct otx2_rss_ctx *rss_ctx;
struct otx2_rss_info *rss;
int ret, idx;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (*rss_context != ETH_RXFH_CONTEXT_ALLOC &&
- *rss_context >= MAX_RSS_GROUPS)
+ if (rxfh->rss_context)
+ rss_context = rxfh->rss_context;
+
+ if (rss_context != ETH_RXFH_CONTEXT_ALLOC &&
+ rss_context >= MAX_RSS_GROUPS)
return -EINVAL;
rss = &pfvf->hw.rss_info;
@@ -859,40 +863,45 @@ static int otx2_set_rxfh_context(struct net_device *dev, const u32 *indir,
return -EIO;
}
- if (hkey) {
- memcpy(rss->key, hkey, sizeof(rss->key));
+ if (rxfh->key) {
+ memcpy(rss->key, rxfh->key, sizeof(rss->key));
otx2_set_rss_key(pfvf);
}
- if (delete)
- return otx2_rss_ctx_delete(pfvf, *rss_context);
+ if (rxfh->rss_delete)
+ return otx2_rss_ctx_delete(pfvf, rss_context);
- if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
- ret = otx2_rss_ctx_create(pfvf, rss_context);
+ if (rss_context == ETH_RXFH_CONTEXT_ALLOC) {
+ ret = otx2_rss_ctx_create(pfvf, &rss_context);
+ rxfh->rss_context = rss_context;
if (ret)
return ret;
}
- if (indir) {
- rss_ctx = rss->rss_ctx[*rss_context];
+ if (rxfh->indir) {
+ rss_ctx = rss->rss_ctx[rss_context];
for (idx = 0; idx < rss->rss_size; idx++)
- rss_ctx->ind_tbl[idx] = indir[idx];
+ rss_ctx->ind_tbl[idx] = rxfh->indir[idx];
}
- otx2_set_rss_table(pfvf, *rss_context);
+ otx2_set_rss_table(pfvf, rss_context);
return 0;
}
-static int otx2_get_rxfh_context(struct net_device *dev, u32 *indir,
- u8 *hkey, u8 *hfunc, u32 rss_context)
+/* Get RSS configuration */
+static int otx2_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
+ u32 rss_context = DEFAULT_RSS_CONTEXT_GROUP;
struct otx2_nic *pfvf = netdev_priv(dev);
struct otx2_rss_ctx *rss_ctx;
struct otx2_rss_info *rss;
+ u32 *indir = rxfh->indir;
int idx, rx_queues;
rss = &pfvf->hw.rss_info;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->rss_context)
+ rss_context = rxfh->rss_context;
if (!indir)
return 0;
@@ -914,30 +923,12 @@ static int otx2_get_rxfh_context(struct net_device *dev, u32 *indir,
for (idx = 0; idx < rss->rss_size; idx++)
indir[idx] = rss_ctx->ind_tbl[idx];
}
- if (hkey)
- memcpy(hkey, rss->key, sizeof(rss->key));
+ if (rxfh->key)
+ memcpy(rxfh->key, rss->key, sizeof(rss->key));
return 0;
}
-/* Get RSS configuration */
-static int otx2_get_rxfh(struct net_device *dev, u32 *indir,
- u8 *hkey, u8 *hfunc)
-{
- return otx2_get_rxfh_context(dev, indir, hkey, hfunc,
- DEFAULT_RSS_CONTEXT_GROUP);
-}
-
-/* Configure RSS table and hash key */
-static int otx2_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *hkey, const u8 hfunc)
-{
-
- u32 rss_context = DEFAULT_RSS_CONTEXT_GROUP;
-
- return otx2_set_rxfh_context(dev, indir, hkey, hfunc, &rss_context, 0);
-}
-
static u32 otx2_get_msglevel(struct net_device *netdev)
{
struct otx2_nic *pfvf = netdev_priv(netdev);
@@ -1318,6 +1309,7 @@ static void otx2_get_fec_stats(struct net_device *netdev,
}
static const struct ethtool_ops otx2_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
ETHTOOL_COALESCE_USE_ADAPTIVE,
@@ -1340,8 +1332,6 @@ static const struct ethtool_ops otx2_ethtool_ops = {
.get_rxfh_indir_size = otx2_get_rxfh_indir_size,
.get_rxfh = otx2_get_rxfh,
.set_rxfh = otx2_set_rxfh,
- .get_rxfh_context = otx2_get_rxfh_context,
- .set_rxfh_context = otx2_set_rxfh_context,
.get_msglevel = otx2_get_msglevel,
.set_msglevel = otx2_set_msglevel,
.get_pauseparam = otx2_get_pauseparam,
@@ -1441,6 +1431,7 @@ static int otx2vf_get_link_ksettings(struct net_device *netdev,
}
static const struct ethtool_ops otx2vf_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
ETHTOOL_COALESCE_USE_ADAPTIVE,
@@ -1459,8 +1450,6 @@ static const struct ethtool_ops otx2vf_ethtool_ops = {
.get_rxfh_indir_size = otx2_get_rxfh_indir_size,
.get_rxfh = otx2_get_rxfh,
.set_rxfh = otx2_set_rxfh,
- .get_rxfh_context = otx2_get_rxfh_context,
- .set_rxfh_context = otx2_set_rxfh_context,
.get_ringparam = otx2_get_ringparam,
.set_ringparam = otx2_set_ringparam,
.get_coalesce = otx2_get_coalesce,
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index a57455aebff6..e5fe67e73865 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1744,6 +1744,7 @@ int otx2_open(struct net_device *netdev)
/* RQ and SQs are mapped to different CQs,
* so find out max CQ IRQs (i.e CINTs) needed.
*/
+ pf->hw.non_qos_queues = pf->hw.tx_queues + pf->hw.xdp_queues;
pf->hw.cint_cnt = max3(pf->hw.rx_queues, pf->hw.tx_queues,
pf->hw.tc_tx_queues);
@@ -2643,8 +2644,6 @@ static int otx2_xdp_setup(struct otx2_nic *pf, struct bpf_prog *prog)
xdp_features_clear_redirect_target(dev);
}
- pf->hw.non_qos_queues += pf->hw.xdp_queues;
-
if (if_up)
otx2_open(pf->netdev);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
index db1e0e0e812d..4fd44b6eecea 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
@@ -29,6 +29,8 @@
#define OTX2_UNSUPP_LSE_DEPTH GENMASK(6, 4)
+#define MCAST_INVALID_GRP (-1U)
+
struct otx2_tc_flow_stats {
u64 bytes;
u64 pkts;
@@ -47,6 +49,7 @@ struct otx2_tc_flow {
bool is_act_police;
u32 prio;
struct npc_install_flow_req req;
+ u32 mcast_grp_idx;
u64 rate;
u32 burst;
bool is_pps;
@@ -355,22 +358,96 @@ static int otx2_tc_act_set_police(struct otx2_nic *nic,
return rc;
}
+static int otx2_tc_update_mcast(struct otx2_nic *nic,
+ struct npc_install_flow_req *req,
+ struct netlink_ext_ack *extack,
+ struct otx2_tc_flow *node,
+ struct nix_mcast_grp_update_req *ureq,
+ u8 num_intf)
+{
+ struct nix_mcast_grp_update_req *grp_update_req;
+ struct nix_mcast_grp_create_req *creq;
+ struct nix_mcast_grp_create_rsp *crsp;
+ u32 grp_index;
+ int rc;
+
+ mutex_lock(&nic->mbox.lock);
+ creq = otx2_mbox_alloc_msg_nix_mcast_grp_create(&nic->mbox);
+ if (!creq) {
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ creq->dir = NIX_MCAST_INGRESS;
+ /* Send message to AF */
+ rc = otx2_sync_mbox_msg(&nic->mbox);
+ if (rc) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to create multicast group");
+ goto error;
+ }
+
+ crsp = (struct nix_mcast_grp_create_rsp *)otx2_mbox_get_rsp(&nic->mbox.mbox,
+ 0,
+ &creq->hdr);
+ if (IS_ERR(crsp)) {
+ rc = PTR_ERR(crsp);
+ goto error;
+ }
+
+ grp_index = crsp->mcast_grp_idx;
+ grp_update_req = otx2_mbox_alloc_msg_nix_mcast_grp_update(&nic->mbox);
+ if (!grp_update_req) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to update multicast group");
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ ureq->op = NIX_MCAST_OP_ADD_ENTRY;
+ ureq->mcast_grp_idx = grp_index;
+ ureq->num_mce_entry = num_intf;
+ ureq->pcifunc[0] = nic->pcifunc;
+ ureq->channel[0] = nic->hw.tx_chan_base;
+
+ ureq->dest_type[0] = NIX_RX_RSS;
+ ureq->rq_rss_index[0] = 0;
+ memcpy(&ureq->hdr, &grp_update_req->hdr, sizeof(struct mbox_msghdr));
+ memcpy(grp_update_req, ureq, sizeof(struct nix_mcast_grp_update_req));
+
+ /* Send message to AF */
+ rc = otx2_sync_mbox_msg(&nic->mbox);
+ if (rc) {
+ NL_SET_ERR_MSG_MOD(extack, "Failed to update multicast group");
+ goto error;
+ }
+
+ mutex_unlock(&nic->mbox.lock);
+ req->op = NIX_RX_ACTIONOP_MCAST;
+ req->index = grp_index;
+ node->mcast_grp_idx = grp_index;
+ return 0;
+
+error:
+ mutex_unlock(&nic->mbox.lock);
+ return rc;
+}
+
static int otx2_tc_parse_actions(struct otx2_nic *nic,
struct flow_action *flow_action,
struct npc_install_flow_req *req,
struct flow_cls_offload *f,
struct otx2_tc_flow *node)
{
+ struct nix_mcast_grp_update_req dummy_grp_update_req = { 0 };
struct netlink_ext_ack *extack = f->common.extack;
+ bool pps = false, mcast = false;
struct flow_action_entry *act;
struct net_device *target;
struct otx2_nic *priv;
u32 burst, mark = 0;
u8 nr_police = 0;
- bool pps = false;
+ u8 num_intf = 1;
+ int err, i;
u64 rate;
- int err;
- int i;
if (!flow_action_has_entries(flow_action)) {
NL_SET_ERR_MSG_MOD(extack, "no tc actions specified");
@@ -442,11 +519,30 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
req->index = act->rx_queue;
break;
+ case FLOW_ACTION_MIRRED_INGRESS:
+ target = act->dev;
+ priv = netdev_priv(target);
+ dummy_grp_update_req.pcifunc[num_intf] = priv->pcifunc;
+ dummy_grp_update_req.channel[num_intf] = priv->hw.tx_chan_base;
+ dummy_grp_update_req.dest_type[num_intf] = NIX_RX_RSS;
+ dummy_grp_update_req.rq_rss_index[num_intf] = 0;
+ mcast = true;
+ num_intf++;
+ break;
+
default:
return -EOPNOTSUPP;
}
}
+ if (mcast) {
+ err = otx2_tc_update_mcast(nic, req, extack, node,
+ &dummy_grp_update_req,
+ num_intf);
+ if (err)
+ return err;
+ }
+
if (nr_police > 1) {
NL_SET_ERR_MSG_MOD(extack,
"rate limit police offload requires a single action");
@@ -541,6 +637,7 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
BIT(FLOW_DISSECTOR_KEY_IPSEC) |
BIT_ULL(FLOW_DISSECTOR_KEY_MPLS) |
+ BIT_ULL(FLOW_DISSECTOR_KEY_ICMP) |
BIT_ULL(FLOW_DISSECTOR_KEY_IP)))) {
netdev_info(nic->netdev, "unsupported flow used key 0x%llx",
dissector->used_keys);
@@ -815,6 +912,19 @@ static int otx2_tc_prepare_flow(struct otx2_nic *nic, struct otx2_tc_flow *node,
}
}
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP)) {
+ struct flow_match_icmp match;
+
+ flow_rule_match_icmp(rule, &match);
+
+ flow_spec->icmp_type = match.key->type;
+ flow_mask->icmp_type = match.mask->type;
+ req->features |= BIT_ULL(NPC_TYPE_ICMP);
+
+ flow_spec->icmp_code = match.key->code;
+ flow_mask->icmp_code = match.mask->code;
+ req->features |= BIT_ULL(NPC_CODE_ICMP);
+ }
return otx2_tc_parse_actions(nic, &rule->action, req, f, node);
}
@@ -1052,6 +1162,7 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
struct flow_cls_offload *tc_flow_cmd)
{
struct otx2_flow_config *flow_cfg = nic->flow_cfg;
+ struct nix_mcast_grp_destroy_req *grp_destroy_req;
struct otx2_tc_flow *flow_node;
int err;
@@ -1085,6 +1196,15 @@ static int otx2_tc_del_flow(struct otx2_nic *nic,
mutex_unlock(&nic->mbox.lock);
}
+ /* Remove the multicast/mirror related nodes */
+ if (flow_node->mcast_grp_idx != MCAST_INVALID_GRP) {
+ mutex_lock(&nic->mbox.lock);
+ grp_destroy_req = otx2_mbox_alloc_msg_nix_mcast_grp_destroy(&nic->mbox);
+ grp_destroy_req->mcast_grp_idx = flow_node->mcast_grp_idx;
+ otx2_sync_mbox_msg(&nic->mbox);
+ mutex_unlock(&nic->mbox.lock);
+ }
+
free_mcam_flow:
otx2_del_mcam_flow_entry(nic, flow_node->entry, NULL);
@@ -1124,6 +1244,7 @@ static int otx2_tc_add_flow(struct otx2_nic *nic,
spin_lock_init(&new_node->lock);
new_node->cookie = tc_flow_cmd->cookie;
new_node->prio = tc_flow_cmd->common.prio;
+ new_node->mcast_grp_idx = MCAST_INVALID_GRP;
memset(&dummy, 0, sizeof(struct npc_install_flow_req));
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
index 4d519ea833b2..f828d32737af 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c
@@ -1403,7 +1403,7 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
struct otx2_cq_queue *cq,
bool *need_xdp_flush)
{
- unsigned char *hard_start, *data;
+ unsigned char *hard_start;
int qidx = cq->cq_idx;
struct xdp_buff xdp;
struct page *page;
@@ -1417,9 +1417,8 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf,
xdp_init_buff(&xdp, pfvf->rbsize, &cq->xdp_rxq);
- data = (unsigned char *)phys_to_virt(pa);
- hard_start = page_address(page);
- xdp_prepare_buff(&xdp, hard_start, data - hard_start,
+ hard_start = (unsigned char *)phys_to_virt(pa);
+ xdp_prepare_buff(&xdp, hard_start, OTX2_HEAD_ROOM,
cqe->sg.seg_size, false);
act = bpf_prog_run_xdp(prog, &xdp);
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 3cf6589cfdac..de123350bd46 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -1159,15 +1159,18 @@ static int mtk_init_fq_dma(struct mtk_eth *eth)
phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1);
for (i = 0; i < cnt; i++) {
+ dma_addr_t addr = dma_addr + i * MTK_QDMA_PAGE_SIZE;
struct mtk_tx_dma_v2 *txd;
txd = eth->scratch_ring + i * soc->txrx.txd_size;
- txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE;
+ txd->txd1 = addr;
if (i < cnt - 1)
txd->txd2 = eth->phy_scratch_ring +
(i + 1) * soc->txrx.txd_size;
txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE);
+ if (MTK_HAS_CAPS(soc->caps, MTK_36BIT_DMA))
+ txd->txd3 |= TX_DMA_PREP_ADDR64(addr);
txd->txd4 = 0;
if (mtk_is_netsys_v2_or_greater(eth)) {
txd->txd5 = 0;
@@ -4758,7 +4761,10 @@ static int mtk_probe(struct platform_device *pdev)
}
if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) {
- err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(36));
+ err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
+ if (!err)
+ err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
if (err) {
dev_err(&pdev->dev, "Wrong DMA config\n");
return -EINVAL;
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index 9a6744c0d458..c895e265ae0e 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -670,7 +670,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
void *buf;
int s;
- page = __dev_alloc_pages(GFP_KERNEL, 0);
+ page = __dev_alloc_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
@@ -691,10 +691,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
struct mtk_wdma_desc *desc = desc_ptr;
+ u32 ctrl;
desc->buf0 = cpu_to_le32(buf_phys);
if (!mtk_wed_is_v3_or_greater(dev->hw)) {
- u32 txd_size, ctrl;
+ u32 txd_size;
txd_size = dev->wlan.init_buf(buf, buf_phys,
token++);
@@ -708,11 +709,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 |
FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
MTK_WED_BUF_SIZE - txd_size);
- desc->ctrl = cpu_to_le32(ctrl);
desc->info = 0;
} else {
- desc->ctrl = cpu_to_le32(token << 16);
+ ctrl = token << 16 | TX_DMA_PREP_ADDR64(buf_phys);
}
+ desc->ctrl = cpu_to_le32(ctrl);
desc_ptr += desc_size;
buf += MTK_WED_BUF_SIZE;
@@ -811,6 +812,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
buf_phys = page_phys;
for (s = 0; s < MTK_WED_RX_BUF_PER_PAGE; s++) {
desc->buf0 = cpu_to_le32(buf_phys);
+ desc->token = cpu_to_le32(RX_DMA_PREP_ADDR64(buf_phys));
buf_phys += MTK_WED_PAGE_BUF_SIZE;
desc++;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
index ae44ad5f8ce8..d58b07e7e123 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
@@ -142,7 +142,8 @@ mtk_wed_wo_queue_refill(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
dma_addr_t addr;
void *buf;
- buf = page_frag_alloc(&q->cache, q->buf_size, GFP_ATOMIC);
+ buf = page_frag_alloc(&q->cache, q->buf_size,
+ GFP_ATOMIC | GFP_DMA32);
if (!buf)
break;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 164a13272faa..619e1c3ef7f9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1258,8 +1258,8 @@ static int mlx4_en_check_rxfh_func(struct net_device *dev, u8 hfunc)
return -EINVAL;
}
-static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
- u8 *hfunc)
+static int mlx4_en_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
u32 n = mlx4_en_get_rxfh_indir_size(dev);
@@ -1269,19 +1269,19 @@ static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key,
rss_rings = rounddown_pow_of_two(rss_rings);
for (i = 0; i < n; i++) {
- if (!ring_index)
+ if (!rxfh->indir)
break;
- ring_index[i] = i % rss_rings;
+ rxfh->indir[i] = i % rss_rings;
}
- if (key)
- memcpy(key, priv->rss_key, MLX4_EN_RSS_KEY_SIZE);
- if (hfunc)
- *hfunc = priv->rss_hash_fn;
+ if (rxfh->key)
+ memcpy(rxfh->key, priv->rss_key, MLX4_EN_RSS_KEY_SIZE);
+ rxfh->hfunc = priv->rss_hash_fn;
return 0;
}
-static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
- const u8 *key, const u8 hfunc)
+static int mlx4_en_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
u32 n = mlx4_en_get_rxfh_indir_size(dev);
@@ -1295,12 +1295,12 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
* between rings
*/
for (i = 0; i < n; i++) {
- if (!ring_index)
+ if (!rxfh->indir)
break;
- if (i > 0 && !ring_index[i] && !rss_rings)
+ if (i > 0 && !rxfh->indir[i] && !rss_rings)
rss_rings = i;
- if (ring_index[i] != (i % (rss_rings ?: n)))
+ if (rxfh->indir[i] != (i % (rss_rings ?: n)))
return -EINVAL;
}
@@ -1311,8 +1311,8 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
if (!is_power_of_2(rss_rings))
return -EINVAL;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE) {
- err = mlx4_en_check_rxfh_func(dev, hfunc);
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE) {
+ err = mlx4_en_check_rxfh_func(dev, rxfh->hfunc);
if (err)
return err;
}
@@ -1323,12 +1323,12 @@ static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index,
mlx4_en_stop_port(dev, 1);
}
- if (ring_index)
+ if (rxfh->indir)
priv->prof->rss_rings = rss_rings;
- if (key)
- memcpy(priv->rss_key, key, MLX4_EN_RSS_KEY_SIZE);
- if (hfunc != ETH_RSS_HASH_NO_CHANGE)
- priv->rss_hash_fn = hfunc;
+ if (rxfh->key)
+ memcpy(priv->rss_key, rxfh->key, MLX4_EN_RSS_KEY_SIZE);
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE)
+ priv->rss_hash_fn = rxfh->hfunc;
if (port_up) {
err = mlx4_en_start_port(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
index a7b1f9686c09..4957412ff1f6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c
@@ -1923,6 +1923,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status,
{
const char *namep = mlx5_command_str(opcode);
struct mlx5_cmd_stats *stats;
+ unsigned long flags;
if (!err || !(strcmp(namep, "unknown command opcode")))
return;
@@ -1930,7 +1931,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status,
stats = xa_load(&dev->cmd.stats, opcode);
if (!stats)
return;
- spin_lock_irq(&stats->lock);
+ spin_lock_irqsave(&stats->lock, flags);
stats->failed++;
if (err < 0)
stats->last_failed_errno = -err;
@@ -1939,7 +1940,7 @@ static void cmd_status_log(struct mlx5_core_dev *dev, u16 opcode, u8 status,
stats->last_failed_mbox_status = status;
stats->last_failed_syndrome = syndrome;
}
- spin_unlock_irq(&stats->lock);
+ spin_unlock_irqrestore(&stats->lock, flags);
}
/* preserve -EREMOTEIO for outbox.status != OK, otherwise return err as is */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 3e064234f6fe..98d4306929f3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -157,6 +157,12 @@ static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change,
return -EOPNOTSUPP;
}
+ if (action == DEVLINK_RELOAD_ACTION_FW_ACTIVATE &&
+ !dev->priv.fw_reset) {
+ NL_SET_ERR_MSG_MOD(extack, "FW activate is unsupported for this function");
+ return -EOPNOTSUPP;
+ }
+
if (mlx5_core_is_pf(dev) && pci_num_vf(pdev))
NL_SET_ERR_MSG_MOD(extack, "reload while VFs are present is unfavorable");
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c
index 28d02749d3c4..7659ad21e6e5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/crdump.c
@@ -55,7 +55,10 @@ int mlx5_crdump_collect(struct mlx5_core_dev *dev, u32 *cr_data)
ret = mlx5_vsc_sem_set_space(dev, MLX5_SEMAPHORE_SW_RESET,
MLX5_VSC_LOCK);
if (ret) {
- mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
+ if (ret == -EBUSY)
+ mlx5_core_info(dev, "SW reset semaphore is already in use\n");
+ else
+ mlx5_core_warn(dev, "Failed to lock SW reset semaphore\n");
goto unlock_gw;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
index 2cd81bb32c66..d74a5aaf4268 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c
@@ -36,11 +36,17 @@ static int mlx5_dpll_clock_id_get(struct mlx5_core_dev *mdev, u64 *clock_id)
return 0;
}
+struct mlx5_dpll_synce_status {
+ enum mlx5_msees_admin_status admin_status;
+ enum mlx5_msees_oper_status oper_status;
+ bool ho_acq;
+ bool oper_freq_measure;
+ s32 frequency_diff;
+};
+
static int
mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev,
- enum mlx5_msees_admin_status *admin_status,
- enum mlx5_msees_oper_status *oper_status,
- bool *ho_acq)
+ struct mlx5_dpll_synce_status *synce_status)
{
u32 out[MLX5_ST_SZ_DW(msees_reg)] = {};
u32 in[MLX5_ST_SZ_DW(msees_reg)] = {};
@@ -50,11 +56,11 @@ mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev,
MLX5_REG_MSEES, 0, 0);
if (err)
return err;
- if (admin_status)
- *admin_status = MLX5_GET(msees_reg, out, admin_status);
- *oper_status = MLX5_GET(msees_reg, out, oper_status);
- if (ho_acq)
- *ho_acq = MLX5_GET(msees_reg, out, ho_acq);
+ synce_status->admin_status = MLX5_GET(msees_reg, out, admin_status);
+ synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status);
+ synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq);
+ synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure);
+ synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff);
return 0;
}
@@ -67,21 +73,23 @@ mlx5_dpll_synce_status_set(struct mlx5_core_dev *mdev,
MLX5_SET(msees_reg, in, field_select,
MLX5_MSEES_FIELD_SELECT_ENABLE |
+ MLX5_MSEES_FIELD_SELECT_ADMIN_FREQ_MEASURE |
MLX5_MSEES_FIELD_SELECT_ADMIN_STATUS);
MLX5_SET(msees_reg, in, admin_status, admin_status);
+ MLX5_SET(msees_reg, in, admin_freq_measure, true);
return mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out),
MLX5_REG_MSEES, 0, 1);
}
static enum dpll_lock_status
-mlx5_dpll_lock_status_get(enum mlx5_msees_oper_status oper_status, bool ho_acq)
+mlx5_dpll_lock_status_get(struct mlx5_dpll_synce_status *synce_status)
{
- switch (oper_status) {
+ switch (synce_status->oper_status) {
case MLX5_MSEES_OPER_STATUS_SELF_TRACK:
fallthrough;
case MLX5_MSEES_OPER_STATUS_OTHER_TRACK:
- return ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ :
- DPLL_LOCK_STATUS_LOCKED;
+ return synce_status->ho_acq ? DPLL_LOCK_STATUS_LOCKED_HO_ACQ :
+ DPLL_LOCK_STATUS_LOCKED;
case MLX5_MSEES_OPER_STATUS_HOLDOVER:
fallthrough;
case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER:
@@ -92,31 +100,37 @@ mlx5_dpll_lock_status_get(enum mlx5_msees_oper_status oper_status, bool ho_acq)
}
static enum dpll_pin_state
-mlx5_dpll_pin_state_get(enum mlx5_msees_admin_status admin_status,
- enum mlx5_msees_oper_status oper_status)
+mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status)
{
- return (admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK &&
- (oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK ||
- oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ?
+ return (synce_status->admin_status == MLX5_MSEES_ADMIN_STATUS_TRACK &&
+ (synce_status->oper_status == MLX5_MSEES_OPER_STATUS_SELF_TRACK ||
+ synce_status->oper_status == MLX5_MSEES_OPER_STATUS_OTHER_TRACK)) ?
DPLL_PIN_STATE_CONNECTED : DPLL_PIN_STATE_DISCONNECTED;
}
+static int
+mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status,
+ s64 *ffo)
+{
+ if (!synce_status->oper_freq_measure)
+ return -ENODATA;
+ *ffo = synce_status->frequency_diff;
+ return 0;
+}
+
static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll,
void *priv,
enum dpll_lock_status *status,
struct netlink_ext_ack *extack)
{
- enum mlx5_msees_oper_status oper_status;
+ struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = priv;
- bool ho_acq;
int err;
- err = mlx5_dpll_synce_status_get(mdpll->mdev, NULL,
- &oper_status, &ho_acq);
+ err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
-
- *status = mlx5_dpll_lock_status_get(oper_status, ho_acq);
+ *status = mlx5_dpll_lock_status_get(&synce_status);
return 0;
}
@@ -128,18 +142,9 @@ static int mlx5_dpll_device_mode_get(const struct dpll_device *dpll,
return 0;
}
-static bool mlx5_dpll_device_mode_supported(const struct dpll_device *dpll,
- void *priv,
- enum dpll_mode mode,
- struct netlink_ext_ack *extack)
-{
- return mode == DPLL_MODE_MANUAL;
-}
-
static const struct dpll_device_ops mlx5_dpll_device_ops = {
.lock_status_get = mlx5_dpll_device_lock_status_get,
.mode_get = mlx5_dpll_device_mode_get,
- .mode_supported = mlx5_dpll_device_mode_supported,
};
static int mlx5_dpll_pin_direction_get(const struct dpll_pin *pin,
@@ -160,16 +165,14 @@ static int mlx5_dpll_state_on_dpll_get(const struct dpll_pin *pin,
enum dpll_pin_state *state,
struct netlink_ext_ack *extack)
{
- enum mlx5_msees_admin_status admin_status;
- enum mlx5_msees_oper_status oper_status;
+ struct mlx5_dpll_synce_status synce_status;
struct mlx5_dpll *mdpll = pin_priv;
int err;
- err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status,
- &oper_status, NULL);
+ err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
return err;
- *state = mlx5_dpll_pin_state_get(admin_status, oper_status);
+ *state = mlx5_dpll_pin_state_get(&synce_status);
return 0;
}
@@ -188,10 +191,25 @@ static int mlx5_dpll_state_on_dpll_set(const struct dpll_pin *pin,
MLX5_MSEES_ADMIN_STATUS_FREE_RUNNING);
}
+static int mlx5_dpll_ffo_get(const struct dpll_pin *pin, void *pin_priv,
+ const struct dpll_device *dpll, void *dpll_priv,
+ s64 *ffo, struct netlink_ext_ack *extack)
+{
+ struct mlx5_dpll_synce_status synce_status;
+ struct mlx5_dpll *mdpll = pin_priv;
+ int err;
+
+ err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
+ if (err)
+ return err;
+ return mlx5_dpll_pin_ffo_get(&synce_status, ffo);
+}
+
static const struct dpll_pin_ops mlx5_dpll_pins_ops = {
.direction_get = mlx5_dpll_pin_direction_get,
.state_on_dpll_get = mlx5_dpll_state_on_dpll_get,
.state_on_dpll_set = mlx5_dpll_state_on_dpll_set,
+ .ffo_get = mlx5_dpll_ffo_get,
};
static const struct dpll_pin_properties mlx5_dpll_pin_properties = {
@@ -211,19 +229,16 @@ static void mlx5_dpll_periodic_work(struct work_struct *work)
{
struct mlx5_dpll *mdpll = container_of(work, struct mlx5_dpll,
work.work);
- enum mlx5_msees_admin_status admin_status;
- enum mlx5_msees_oper_status oper_status;
+ struct mlx5_dpll_synce_status synce_status;
enum dpll_lock_status lock_status;
enum dpll_pin_state pin_state;
- bool ho_acq;
int err;
- err = mlx5_dpll_synce_status_get(mdpll->mdev, &admin_status,
- &oper_status, &ho_acq);
+ err = mlx5_dpll_synce_status_get(mdpll->mdev, &synce_status);
if (err)
goto err_out;
- lock_status = mlx5_dpll_lock_status_get(oper_status, ho_acq);
- pin_state = mlx5_dpll_pin_state_get(admin_status, oper_status);
+ lock_status = mlx5_dpll_lock_status_get(&synce_status);
+ pin_state = mlx5_dpll_pin_state_get(&synce_status);
if (!mdpll->last.valid)
goto invalid_out;
@@ -246,7 +261,7 @@ static void mlx5_dpll_netdev_dpll_pin_set(struct mlx5_dpll *mdpll,
{
if (mdpll->tracking_netdev)
return;
- netdev_dpll_pin_set(netdev, mdpll->dpll_pin);
+ dpll_netdev_pin_set(netdev, mdpll->dpll_pin);
mdpll->tracking_netdev = netdev;
}
@@ -254,7 +269,7 @@ static void mlx5_dpll_netdev_dpll_pin_clear(struct mlx5_dpll *mdpll)
{
if (!mdpll->tracking_netdev)
return;
- netdev_dpll_pin_clear(mdpll->tracking_netdev);
+ dpll_netdev_pin_clear(mdpll->tracking_netdev);
mdpll->tracking_netdev = NULL;
}
@@ -374,7 +389,7 @@ static void mlx5_dpll_remove(struct auxiliary_device *adev)
struct mlx5_dpll *mdpll = auxiliary_get_drvdata(adev);
struct mlx5_core_dev *mdev = mdpll->mdev;
- cancel_delayed_work(&mdpll->work);
+ cancel_delayed_work_sync(&mdpll->work);
mlx5_dpll_mdev_netdev_untrack(mdpll, mdev);
destroy_workqueue(mdpll->wq);
dpll_pin_unregister(mdpll->dpll, mdpll->dpll_pin,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 729a11b5fb25..55c6ace0acd5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -72,7 +72,6 @@ struct page_pool;
#define MLX5E_HW2SW_MTU(params, hwmtu) ((hwmtu) - ((params)->hard_mtu))
#define MLX5E_SW2HW_MTU(params, swmtu) ((swmtu) + ((params)->hard_mtu))
-#define MLX5E_MAX_NUM_TC 8
#define MLX5E_MAX_NUM_MQPRIO_CH_TC TC_QOPT_MAX_QUEUE
#define MLX5_RX_HEADROOM NET_SKB_PAD
@@ -364,7 +363,7 @@ struct mlx5e_cq {
/* control */
struct net_device *netdev;
struct mlx5_core_dev *mdev;
- struct mlx5e_priv *priv;
+ struct workqueue_struct *workqueue;
struct mlx5_wq_ctrl wq_ctrl;
} ____cacheline_aligned_in_smp;
@@ -484,10 +483,12 @@ struct mlx5e_xdp_info_fifo {
struct mlx5e_xdpsq;
struct mlx5e_xmit_data;
+struct xsk_tx_metadata;
typedef int (*mlx5e_fp_xmit_xdp_frame_check)(struct mlx5e_xdpsq *);
typedef bool (*mlx5e_fp_xmit_xdp_frame)(struct mlx5e_xdpsq *,
struct mlx5e_xmit_data *,
- int);
+ int,
+ struct xsk_tx_metadata *);
struct mlx5e_xdpsq {
/* data path */
@@ -756,7 +757,7 @@ struct mlx5e_channel {
/* data path */
struct mlx5e_rq rq;
struct mlx5e_xdpsq rq_xdpsq;
- struct mlx5e_txqsq sq[MLX5E_MAX_NUM_TC];
+ struct mlx5e_txqsq sq[MLX5_MAX_NUM_TC];
struct mlx5e_icosq icosq; /* internal control operations */
struct mlx5e_txqsq __rcu * __rcu *qos_sqs;
bool xdp;
@@ -806,7 +807,7 @@ struct mlx5e_channels {
struct mlx5e_channel_stats {
struct mlx5e_ch_stats ch;
- struct mlx5e_sq_stats sq[MLX5E_MAX_NUM_TC];
+ struct mlx5e_sq_stats sq[MLX5_MAX_NUM_TC];
struct mlx5e_rq_stats rq;
struct mlx5e_rq_stats xskrq;
struct mlx5e_xdpsq_stats rq_xdpsq;
@@ -816,8 +817,8 @@ struct mlx5e_channel_stats {
struct mlx5e_ptp_stats {
struct mlx5e_ch_stats ch;
- struct mlx5e_sq_stats sq[MLX5E_MAX_NUM_TC];
- struct mlx5e_ptp_cq_stats cq[MLX5E_MAX_NUM_TC];
+ struct mlx5e_sq_stats sq[MLX5_MAX_NUM_TC];
+ struct mlx5e_ptp_cq_stats cq[MLX5_MAX_NUM_TC];
struct mlx5e_rq_stats rq;
} ____cacheline_aligned_in_smp;
@@ -885,7 +886,6 @@ struct mlx5e_priv {
struct mlx5e_rq drop_rq;
struct mlx5e_channels channels;
- u32 tisn[MLX5_MAX_PORTS][MLX5E_MAX_NUM_TC];
struct mlx5e_rx_res *rx_res;
u32 *tx_rates;
@@ -983,6 +983,8 @@ struct mlx5e_profile {
void (*update_stats)(struct mlx5e_priv *priv);
void (*update_carrier)(struct mlx5e_priv *priv);
int (*max_nch_limit)(struct mlx5_core_dev *mdev);
+ u32 (*get_tisn)(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv,
+ u8 lag_port, u8 tc);
unsigned int (*stats_grps_num)(struct mlx5e_priv *priv);
mlx5e_stats_grp_t *stats_grps;
const struct mlx5e_rx_handlers *rx_handlers;
@@ -990,6 +992,11 @@ struct mlx5e_profile {
u32 features;
};
+u32 mlx5e_profile_get_tisn(struct mlx5_core_dev *mdev,
+ struct mlx5e_priv *priv,
+ const struct mlx5e_profile *profile,
+ u8 lag_port, u8 tc);
+
#define mlx5e_profile_feature_cap(profile, feature) \
((profile)->features & BIT(MLX5E_PROFILE_FEATURE_##feature))
@@ -1037,6 +1044,8 @@ int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq);
struct mlx5e_create_cq_param {
+ struct net_device *netdev;
+ struct workqueue_struct *wq;
struct napi_struct *napi;
struct mlx5e_ch_stats *ch_stats;
int node;
@@ -1044,7 +1053,7 @@ struct mlx5e_create_cq_param {
};
struct mlx5e_cq_param;
-int mlx5e_open_cq(struct mlx5e_priv *priv, struct dim_cq_moder moder,
+int mlx5e_open_cq(struct mlx5_core_dev *mdev, struct dim_cq_moder moder,
struct mlx5e_cq_param *param, struct mlx5e_create_cq_param *ccp,
struct mlx5e_cq *cq);
void mlx5e_close_cq(struct mlx5e_cq *cq);
@@ -1115,7 +1124,7 @@ static inline bool mlx5_tx_swp_supported(struct mlx5_core_dev *mdev)
extern const struct ethtool_ops mlx5e_ethtool_ops;
int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *mkey);
-int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev);
+int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises);
void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev);
int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb,
bool enable_mc_lb);
@@ -1131,8 +1140,6 @@ void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq);
int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn);
void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn);
-int mlx5e_create_tises(struct mlx5e_priv *priv);
-void mlx5e_destroy_tises(struct mlx5e_priv *priv);
int mlx5e_update_nic_rx(struct mlx5e_priv *priv);
void mlx5e_update_carrier(struct mlx5e_priv *priv);
int mlx5e_close(struct net_device *netdev);
@@ -1174,9 +1181,9 @@ int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
struct ethtool_link_ksettings *link_ksettings);
int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
const struct ethtool_link_ksettings *link_ksettings);
-int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc);
-int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key,
- const u8 hfunc);
+int mlx5e_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh);
+int mlx5e_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack);
u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c b/drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c
index e1283531e0b8..671adbad0a40 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/fs_tt_redirect.c
@@ -436,6 +436,7 @@ static int fs_any_create_groups(struct mlx5e_flow_table *ft)
in = kvzalloc(inlen, GFP_KERNEL);
if (!in || !ft->g) {
kfree(ft->g);
+ ft->g = NULL;
kvfree(in);
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
index 254c84739046..40c8df111754 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
@@ -36,7 +36,7 @@ int mlx5e_monitor_counter_supported(struct mlx5e_priv *priv)
return true;
}
-void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv)
+static void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv)
{
u32 in[MLX5_ST_SZ_DW(arm_monitor_counter_in)] = {};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h
index e1ac4b3d22fb..6beba7f075c1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.h
@@ -7,6 +7,5 @@
int mlx5e_monitor_counter_supported(struct mlx5e_priv *priv);
void mlx5e_monitor_counter_init(struct mlx5e_priv *priv);
void mlx5e_monitor_counter_cleanup(struct mlx5e_priv *priv);
-void mlx5e_monitor_counter_arm(struct mlx5e_priv *priv);
#endif /* __MLX5_MONITOR_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
index e097f336e1c4..5d213a9886f1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/params.c
@@ -669,6 +669,8 @@ void mlx5e_build_rq_params(struct mlx5_core_dev *mdev,
void mlx5e_build_create_cq_param(struct mlx5e_create_cq_param *ccp, struct mlx5e_channel *c)
{
*ccp = (struct mlx5e_create_cq_param) {
+ .netdev = c->netdev,
+ .wq = c->priv->wq,
.napi = &c->napi,
.ch_stats = c->stats,
.node = cpu_to_node(c->cpu),
@@ -1062,8 +1064,8 @@ void mlx5e_build_sq_param(struct mlx5_core_dev *mdev,
void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
bool allow_swp;
- allow_swp =
- mlx5_geneve_tx_allowed(mdev) || !!mlx5_ipsec_device_caps(mdev);
+ allow_swp = mlx5_geneve_tx_allowed(mdev) ||
+ (mlx5_ipsec_device_caps(mdev) & MLX5_IPSEC_CAP_CRYPTO);
mlx5e_build_sq_param_common(mdev, param);
MLX5_SET(wq, wq, log_wq_sz, params->log_sq_size);
MLX5_SET(sqc, sqc, allow_swp, allow_swp);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
index af3928eddafd..ca05b3252a1b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c
@@ -42,9 +42,9 @@ mlx5e_ptp_port_ts_cqe_list_add(struct mlx5e_ptp_port_ts_cqe_list *list, u8 metad
WARN_ON_ONCE(tracker->inuse);
tracker->inuse = true;
- spin_lock(&list->tracker_list_lock);
+ spin_lock_bh(&list->tracker_list_lock);
list_add_tail(&tracker->entry, &list->tracker_list_head);
- spin_unlock(&list->tracker_list_lock);
+ spin_unlock_bh(&list->tracker_list_lock);
}
static void
@@ -54,9 +54,9 @@ mlx5e_ptp_port_ts_cqe_list_remove(struct mlx5e_ptp_port_ts_cqe_list *list, u8 me
WARN_ON_ONCE(!tracker->inuse);
tracker->inuse = false;
- spin_lock(&list->tracker_list_lock);
+ spin_lock_bh(&list->tracker_list_lock);
list_del(&tracker->entry);
- spin_unlock(&list->tracker_list_lock);
+ spin_unlock_bh(&list->tracker_list_lock);
}
void mlx5e_ptpsq_track_metadata(struct mlx5e_ptpsq *ptpsq, u8 metadata)
@@ -155,7 +155,7 @@ static void mlx5e_ptpsq_mark_ts_cqes_undelivered(struct mlx5e_ptpsq *ptpsq,
struct mlx5e_ptp_metadata_map *metadata_map = &ptpsq->metadata_map;
struct mlx5e_ptp_port_ts_cqe_tracker *pos, *n;
- spin_lock(&cqe_list->tracker_list_lock);
+ spin_lock_bh(&cqe_list->tracker_list_lock);
list_for_each_entry_safe(pos, n, &cqe_list->tracker_list_head, entry) {
struct sk_buff *skb =
mlx5e_ptp_metadata_map_lookup(metadata_map, pos->metadata_id);
@@ -170,7 +170,7 @@ static void mlx5e_ptpsq_mark_ts_cqes_undelivered(struct mlx5e_ptpsq *ptpsq,
pos->inuse = false;
list_del(&pos->entry);
}
- spin_unlock(&cqe_list->tracker_list_lock);
+ spin_unlock_bh(&cqe_list->tracker_list_lock);
}
#define PTP_WQE_CTR2IDX(val) ((val) & ptpsq->ts_cqe_ctr_mask)
@@ -213,7 +213,7 @@ static void mlx5e_ptp_handle_ts_cqe(struct mlx5e_ptpsq *ptpsq,
mlx5e_ptpsq_mark_ts_cqes_undelivered(ptpsq, hwtstamp);
out:
napi_consume_skb(skb, budget);
- md_buff[*md_buff_sz++] = metadata_id;
+ md_buff[(*md_buff_sz)++] = metadata_id;
if (unlikely(mlx5e_ptp_metadata_map_unhealthy(&ptpsq->metadata_map)) &&
!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state))
queue_work(ptpsq->txqsq.priv->wq, &ptpsq->report_unhealthy_work);
@@ -518,9 +518,11 @@ static int mlx5e_ptp_open_txqsqs(struct mlx5e_ptp *c,
for (tc = 0; tc < num_tc; tc++) {
int txq_ix = ix_base + tc;
+ u32 tisn;
- err = mlx5e_ptp_open_txqsq(c, c->priv->tisn[c->lag_port][tc], txq_ix,
- cparams, tc, &c->ptpsq[tc]);
+ tisn = mlx5e_profile_get_tisn(c->mdev, c->priv, c->priv->profile,
+ c->lag_port, tc);
+ err = mlx5e_ptp_open_txqsq(c, tisn, txq_ix, cparams, tc, &c->ptpsq[tc]);
if (err)
goto close_txqsq;
}
@@ -555,6 +557,8 @@ static int mlx5e_ptp_open_tx_cqs(struct mlx5e_ptp *c,
num_tc = mlx5e_get_dcb_num_tc(params);
+ ccp.netdev = c->netdev;
+ ccp.wq = c->priv->wq;
ccp.node = dev_to_node(mlx5_core_dma_dev(c->mdev));
ccp.ch_stats = c->stats;
ccp.napi = &c->napi;
@@ -565,7 +569,7 @@ static int mlx5e_ptp_open_tx_cqs(struct mlx5e_ptp *c,
for (tc = 0; tc < num_tc; tc++) {
struct mlx5e_cq *cq = &c->ptpsq[tc].txqsq.cq;
- err = mlx5e_open_cq(c->priv, ptp_moder, cq_param, &ccp, cq);
+ err = mlx5e_open_cq(c->mdev, ptp_moder, cq_param, &ccp, cq);
if (err)
goto out_err_txqsq_cq;
}
@@ -574,7 +578,7 @@ static int mlx5e_ptp_open_tx_cqs(struct mlx5e_ptp *c,
struct mlx5e_cq *cq = &c->ptpsq[tc].ts_cq;
struct mlx5e_ptpsq *ptpsq = &c->ptpsq[tc];
- err = mlx5e_open_cq(c->priv, ptp_moder, cq_param, &ccp, cq);
+ err = mlx5e_open_cq(c->mdev, ptp_moder, cq_param, &ccp, cq);
if (err)
goto out_err_ts_cq;
@@ -602,6 +606,8 @@ static int mlx5e_ptp_open_rx_cq(struct mlx5e_ptp *c,
struct mlx5e_cq_param *cq_param;
struct mlx5e_cq *cq = &c->rq.cq;
+ ccp.netdev = c->netdev;
+ ccp.wq = c->priv->wq;
ccp.node = dev_to_node(mlx5_core_dma_dev(c->mdev));
ccp.ch_stats = c->stats;
ccp.napi = &c->napi;
@@ -609,7 +615,7 @@ static int mlx5e_ptp_open_rx_cq(struct mlx5e_ptp *c,
cq_param = &cparams->rq_param.cqp;
- return mlx5e_open_cq(c->priv, ptp_moder, cq_param, &ccp, cq);
+ return mlx5e_open_cq(c->mdev, ptp_moder, cq_param, &ccp, cq);
}
static void mlx5e_ptp_close_tx_cqs(struct mlx5e_ptp *c)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
index 7b700d0f956a..86f1854698b4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/ptp.h
@@ -49,7 +49,7 @@ enum {
struct mlx5e_ptp {
/* data path */
- struct mlx5e_ptpsq ptpsq[MLX5E_MAX_NUM_TC];
+ struct mlx5e_ptpsq ptpsq[MLX5_MAX_NUM_TC];
struct mlx5e_rq rq;
struct napi_struct napi;
struct device *pdev;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
index 244bc15a42ab..34adf8c3f81a 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/qos.c
@@ -77,6 +77,7 @@ int mlx5e_open_qos_sq(struct mlx5e_priv *priv, struct mlx5e_channels *chs,
struct mlx5e_params *params;
struct mlx5e_channel *c;
struct mlx5e_txqsq *sq;
+ u32 tisn;
params = &chs->params;
@@ -123,11 +124,13 @@ int mlx5e_open_qos_sq(struct mlx5e_priv *priv, struct mlx5e_channels *chs,
memset(&param_cq, 0, sizeof(param_cq));
mlx5e_build_sq_param(priv->mdev, params, &param_sq);
mlx5e_build_tx_cq_param(priv->mdev, params, &param_cq);
- err = mlx5e_open_cq(priv, params->tx_cq_moderation, &param_cq, &ccp, &sq->cq);
+ err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &param_cq, &ccp, &sq->cq);
if (err)
goto err_free_sq;
- err = mlx5e_open_txqsq(c, priv->tisn[c->lag_port][0], txq_ix, params,
- &param_sq, sq, 0, hw_id,
+
+ tisn = mlx5e_profile_get_tisn(c->mdev, c->priv, c->priv->profile,
+ c->lag_port, 0);
+ err = mlx5e_open_txqsq(c, tisn, txq_ix, params, &param_sq, sq, 0, hw_id,
priv->htb_qos_sq_stats[node_qid]);
if (err)
goto err_close_cq;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
index b12fe3c5a258..a55452c69f06 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rep/tc.c
@@ -147,6 +147,20 @@ mlx5e_rep_setup_tc_cls_flower(struct mlx5e_priv *priv,
}
}
+static void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv,
+ struct tc_cls_matchall_offload *ma)
+{
+ struct mlx5e_rep_priv *rpriv = priv->ppriv;
+ u64 dbytes;
+ u64 dpkts;
+
+ dpkts = priv->stats.rep_stats.vport_rx_packets - rpriv->prev_vf_vport_stats.rx_packets;
+ dbytes = priv->stats.rep_stats.vport_rx_bytes - rpriv->prev_vf_vport_stats.rx_bytes;
+ mlx5e_stats_copy_rep_stats(&rpriv->prev_vf_vport_stats, &priv->stats.rep_stats);
+ flow_stats_update(&ma->stats, dbytes, dpkts, 0, jiffies,
+ FLOW_ACTION_HW_STATS_DELAYED);
+}
+
static
int mlx5e_rep_setup_tc_cls_matchall(struct mlx5e_priv *priv,
struct tc_cls_matchall_offload *ma)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c
index 368a95fa77d3..b14cd62edffc 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c
@@ -48,7 +48,8 @@ mlx5e_tc_act_pedit_parse_action(struct mlx5e_priv *priv,
struct pedit_headers_action *hdrs,
struct netlink_ext_ack *extack)
{
- u8 cmd = (act->id == FLOW_ACTION_MANGLE) ? 0 : 1;
+ u8 cmd = (act->id == FLOW_ACTION_MANGLE) ? TCA_PEDIT_KEY_EX_CMD_SET :
+ TCA_PEDIT_KEY_EX_CMD_ADD;
u8 htype = act->mangle.htype;
int err = -EOPNOTSUPP;
u32 mask, val, offset;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c
index 86bf007fd05b..b500cc2c9689 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_act.c
@@ -37,7 +37,7 @@ mlx5e_tc_post_act_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
if (!MLX5_CAP_FLOWTABLE_TYPE(priv->mdev, ignore_flow_level, table_type)) {
if (priv->mdev->coredev_type == MLX5_COREDEV_PF)
- mlx5_core_warn(priv->mdev, "firmware level support is missing\n");
+ mlx5_core_dbg(priv->mdev, "firmware flow level support is missing\n");
err = -EOPNOTSUPP;
goto err_check;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c b/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
index 5620d9f97518..ac458a8d10e0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/trap.c
@@ -68,11 +68,13 @@ static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t)
node = dev_to_node(mdev->device);
+ ccp.netdev = priv->netdev;
+ ccp.wq = priv->wq;
ccp.node = node;
ccp.ch_stats = t->stats;
ccp.napi = &t->napi;
ccp.ix = 0;
- err = mlx5e_open_cq(priv, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
+ err = mlx5e_open_cq(priv->mdev, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
if (err)
return err;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
index 13c7ed1bb37e..82b5ca1be4f3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c
@@ -103,7 +103,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
xdptxd->dma_addr = dma_addr;
if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
- mlx5e_xmit_xdp_frame, sq, xdptxd, 0)))
+ mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL)))
return false;
/* xmit_mode == MLX5E_XDP_XMIT_MODE_FRAME */
@@ -145,7 +145,7 @@ mlx5e_xmit_xdp_buff(struct mlx5e_xdpsq *sq, struct mlx5e_rq *rq,
xdptxd->dma_addr = dma_addr;
if (unlikely(!INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
- mlx5e_xmit_xdp_frame, sq, xdptxd, 0)))
+ mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL)))
return false;
/* xmit_mode == MLX5E_XDP_XMIT_MODE_PAGE */
@@ -256,9 +256,55 @@ static int mlx5e_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash,
return 0;
}
+static int mlx5e_xdp_rx_vlan_tag(const struct xdp_md *ctx, __be16 *vlan_proto,
+ u16 *vlan_tci)
+{
+ const struct mlx5e_xdp_buff *_ctx = (void *)ctx;
+ const struct mlx5_cqe64 *cqe = _ctx->cqe;
+
+ if (!cqe_has_vlan(cqe))
+ return -ENODATA;
+
+ *vlan_proto = htons(ETH_P_8021Q);
+ *vlan_tci = be16_to_cpu(cqe->vlan_info);
+ return 0;
+}
+
const struct xdp_metadata_ops mlx5e_xdp_metadata_ops = {
.xmo_rx_timestamp = mlx5e_xdp_rx_timestamp,
.xmo_rx_hash = mlx5e_xdp_rx_hash,
+ .xmo_rx_vlan_tag = mlx5e_xdp_rx_vlan_tag,
+};
+
+struct mlx5e_xsk_tx_complete {
+ struct mlx5_cqe64 *cqe;
+ struct mlx5e_cq *cq;
+};
+
+static u64 mlx5e_xsk_fill_timestamp(void *_priv)
+{
+ struct mlx5e_xsk_tx_complete *priv = _priv;
+ u64 ts;
+
+ ts = get_cqe_ts(priv->cqe);
+
+ if (mlx5_is_real_time_rq(priv->cq->mdev) || mlx5_is_real_time_sq(priv->cq->mdev))
+ return mlx5_real_time_cyc2time(&priv->cq->mdev->clock, ts);
+
+ return mlx5_timecounter_cyc2time(&priv->cq->mdev->clock, ts);
+}
+
+static void mlx5e_xsk_request_checksum(u16 csum_start, u16 csum_offset, void *priv)
+{
+ struct mlx5_wqe_eth_seg *eseg = priv;
+
+ /* HW/FW is doing parsing, so offsets are largely ignored. */
+ eseg->cs_flags |= MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM;
+}
+
+const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops = {
+ .tmo_fill_timestamp = mlx5e_xsk_fill_timestamp,
+ .tmo_request_checksum = mlx5e_xsk_request_checksum,
};
/* returns true if packet was consumed by xdp */
@@ -398,11 +444,11 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq
INDIRECT_CALLABLE_SCOPE bool
mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
- int check_result);
+ int check_result, struct xsk_tx_metadata *meta);
INDIRECT_CALLABLE_SCOPE bool
mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
- int check_result)
+ int check_result, struct xsk_tx_metadata *meta)
{
struct mlx5e_tx_mpwqe *session = &sq->mpwqe;
struct mlx5e_xdpsq_stats *stats = sq->stats;
@@ -420,7 +466,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
*/
if (unlikely(sq->mpwqe.wqe))
mlx5e_xdp_mpwqe_complete(sq);
- return mlx5e_xmit_xdp_frame(sq, xdptxd, 0);
+ return mlx5e_xmit_xdp_frame(sq, xdptxd, 0, meta);
}
if (!xdptxd->len) {
skb_frag_t *frag = &xdptxdf->sinfo->frags[0];
@@ -450,6 +496,7 @@ mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptx
* and it's safe to complete it at any time.
*/
mlx5e_xdp_mpwqe_session_start(sq);
+ xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, &session->wqe->eth);
}
mlx5e_xdp_mpwqe_add_dseg(sq, p, stats);
@@ -480,7 +527,7 @@ INDIRECT_CALLABLE_SCOPE int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq)
INDIRECT_CALLABLE_SCOPE bool
mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
- int check_result)
+ int check_result, struct xsk_tx_metadata *meta)
{
struct mlx5e_xmit_data_frags *xdptxdf =
container_of(xdptxd, struct mlx5e_xmit_data_frags, xd);
@@ -601,6 +648,8 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
sq->pc++;
}
+ xsk_tx_metadata_request(meta, &mlx5e_xsk_tx_metadata_ops, eseg);
+
sq->doorbell_cseg = cseg;
stats->xmit++;
@@ -610,7 +659,9 @@ mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq, struct mlx5e_xmit_data *xdptxd,
static void mlx5e_free_xdpsq_desc(struct mlx5e_xdpsq *sq,
struct mlx5e_xdp_wqe_info *wi,
u32 *xsk_frames,
- struct xdp_frame_bulk *bq)
+ struct xdp_frame_bulk *bq,
+ struct mlx5e_cq *cq,
+ struct mlx5_cqe64 *cqe)
{
struct mlx5e_xdp_info_fifo *xdpi_fifo = &sq->db.xdpi_fifo;
u16 i;
@@ -670,10 +721,24 @@ static void mlx5e_free_xdpsq_desc(struct mlx5e_xdpsq *sq,
break;
}
- case MLX5E_XDP_XMIT_MODE_XSK:
+ case MLX5E_XDP_XMIT_MODE_XSK: {
/* AF_XDP send */
+ struct xsk_tx_metadata_compl *compl = NULL;
+ struct mlx5e_xsk_tx_complete priv = {
+ .cqe = cqe,
+ .cq = cq,
+ };
+
+ if (xp_tx_metadata_enabled(sq->xsk_pool)) {
+ xdpi = mlx5e_xdpi_fifo_pop(xdpi_fifo);
+ compl = &xdpi.xsk_meta;
+
+ xsk_tx_metadata_complete(compl, &mlx5e_xsk_tx_metadata_ops, &priv);
+ }
+
(*xsk_frames)++;
break;
+ }
default:
WARN_ON_ONCE(true);
}
@@ -722,7 +787,7 @@ bool mlx5e_poll_xdpsq_cq(struct mlx5e_cq *cq)
sqcc += wi->num_wqebbs;
- mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq);
+ mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq, cq, cqe);
} while (!last_wqe);
if (unlikely(get_cqe_opcode(cqe) != MLX5_CQE_REQ)) {
@@ -769,7 +834,7 @@ void mlx5e_free_xdpsq_descs(struct mlx5e_xdpsq *sq)
sq->cc += wi->num_wqebbs;
- mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq);
+ mlx5e_free_xdpsq_desc(sq, wi, &xsk_frames, &bq, NULL, NULL);
}
xdp_flush_frame_bulk(&bq);
@@ -842,7 +907,7 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
}
ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
- mlx5e_xmit_xdp_frame, sq, xdptxd, 0);
+ mlx5e_xmit_xdp_frame, sq, xdptxd, 0, NULL);
if (unlikely(!ret)) {
int j;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
index ecfe93a479da..e054db1e10f8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
@@ -33,6 +33,7 @@
#define __MLX5_EN_XDP_H__
#include <linux/indirect_call_wrapper.h>
+#include <net/xdp_sock.h>
#include "en.h"
#include "en/txrx.h"
@@ -82,7 +83,7 @@ enum mlx5e_xdp_xmit_mode {
* num, page_1, page_2, ... , page_num.
*
* MLX5E_XDP_XMIT_MODE_XSK:
- * none.
+ * frame.xsk_meta.
*/
#define MLX5E_XDP_FIFO_ENTRIES2DS_MAX_RATIO 4
@@ -97,6 +98,7 @@ union mlx5e_xdp_info {
u8 num;
struct page *page;
} page;
+ struct xsk_tx_metadata_compl xsk_meta;
};
struct mlx5e_xsk_param;
@@ -112,13 +114,16 @@ int mlx5e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
u32 flags);
extern const struct xdp_metadata_ops mlx5e_xdp_metadata_ops;
+extern const struct xsk_tx_metadata_ops mlx5e_xsk_tx_metadata_ops;
INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame_mpwqe(struct mlx5e_xdpsq *sq,
struct mlx5e_xmit_data *xdptxd,
- int check_result));
+ int check_result,
+ struct xsk_tx_metadata *meta));
INDIRECT_CALLABLE_DECLARE(bool mlx5e_xmit_xdp_frame(struct mlx5e_xdpsq *sq,
struct mlx5e_xmit_data *xdptxd,
- int check_result));
+ int check_result,
+ struct xsk_tx_metadata *meta));
INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check_mpwqe(struct mlx5e_xdpsq *sq));
INDIRECT_CALLABLE_DECLARE(int mlx5e_xmit_xdp_frame_check(struct mlx5e_xdpsq *sq));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
index 36826b582484..82e6abbc1734 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/setup.c
@@ -127,7 +127,7 @@ int mlx5e_open_xsk(struct mlx5e_priv *priv, struct mlx5e_params *params,
mlx5e_build_xsk_cparam(priv->mdev, params, xsk, priv->q_counter, cparam);
- err = mlx5e_open_cq(c->priv, params->rx_cq_moderation, &cparam->rq.cqp, &ccp,
+ err = mlx5e_open_cq(c->mdev, params->rx_cq_moderation, &cparam->rq.cqp, &ccp,
&c->xskrq.cq);
if (unlikely(err))
goto err_free_cparam;
@@ -136,7 +136,7 @@ int mlx5e_open_xsk(struct mlx5e_priv *priv, struct mlx5e_params *params,
if (unlikely(err))
goto err_close_rx_cq;
- err = mlx5e_open_cq(c->priv, params->tx_cq_moderation, &cparam->xdp_sq.cqp, &ccp,
+ err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->xdp_sq.cqp, &ccp,
&c->xsksq.cq);
if (unlikely(err))
goto err_close_rq;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
index 597f319d4770..a59199ed590d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xsk/tx.c
@@ -55,12 +55,16 @@ static void mlx5e_xsk_tx_post_err(struct mlx5e_xdpsq *sq,
nopwqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, *xdpi);
+ if (xp_tx_metadata_enabled(sq->xsk_pool))
+ mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo,
+ (union mlx5e_xdp_info) { .xsk_meta = {} });
sq->doorbell_cseg = &nopwqe->ctrl;
}
bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
{
struct xsk_buff_pool *pool = sq->xsk_pool;
+ struct xsk_tx_metadata *meta = NULL;
union mlx5e_xdp_info xdpi;
bool work_done = true;
bool flush = false;
@@ -93,12 +97,13 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
xdptxd.dma_addr = xsk_buff_raw_get_dma(pool, desc.addr);
xdptxd.data = xsk_buff_raw_get_data(pool, desc.addr);
xdptxd.len = desc.len;
+ meta = xsk_buff_get_metadata(pool, desc.addr);
xsk_buff_raw_dma_sync_for_device(pool, xdptxd.dma_addr, xdptxd.len);
ret = INDIRECT_CALL_2(sq->xmit_xdp_frame, mlx5e_xmit_xdp_frame_mpwqe,
mlx5e_xmit_xdp_frame, sq, &xdptxd,
- check_result);
+ check_result, meta);
if (unlikely(!ret)) {
if (sq->mpwqe.wqe)
mlx5e_xdp_mpwqe_complete(sq);
@@ -106,6 +111,16 @@ bool mlx5e_xsk_tx(struct mlx5e_xdpsq *sq, unsigned int budget)
mlx5e_xsk_tx_post_err(sq, &xdpi);
} else {
mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo, xdpi);
+ if (xp_tx_metadata_enabled(sq->xsk_pool)) {
+ struct xsk_tx_metadata_compl compl;
+
+ xsk_tx_metadata_to_compl(meta, &compl);
+ XSK_TX_COMPL_FITS(void *);
+
+ mlx5e_xdpi_fifo_push(&sq->db.xdpi_fifo,
+ (union mlx5e_xdp_info)
+ { .xsk_meta = compl });
+ }
}
flush = true;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
index 161c5190c236..05612d9c6080 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/ipsec.c
@@ -336,12 +336,17 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
/* iv len */
aes_gcm->icv_len = x->aead->alg_icv_len;
+ attrs->dir = x->xso.dir;
+
/* esn */
if (x->props.flags & XFRM_STATE_ESN) {
attrs->replay_esn.trigger = true;
attrs->replay_esn.esn = sa_entry->esn_state.esn;
attrs->replay_esn.esn_msb = sa_entry->esn_state.esn_msb;
attrs->replay_esn.overlap = sa_entry->esn_state.overlap;
+ if (attrs->dir == XFRM_DEV_OFFLOAD_OUT)
+ goto skip_replay_window;
+
switch (x->replay_esn->replay_window) {
case 32:
attrs->replay_esn.replay_window =
@@ -365,7 +370,7 @@ void mlx5e_ipsec_build_accel_xfrm_attrs(struct mlx5e_ipsec_sa_entry *sa_entry,
}
}
- attrs->dir = x->xso.dir;
+skip_replay_window:
/* spi */
attrs->spi = be32_to_cpu(x->id.spi);
@@ -501,7 +506,8 @@ static int mlx5e_xfrm_validate_state(struct mlx5_core_dev *mdev,
return -EINVAL;
}
- if (x->replay_esn && x->replay_esn->replay_window != 32 &&
+ if (x->replay_esn && x->xso.dir == XFRM_DEV_OFFLOAD_IN &&
+ x->replay_esn->replay_window != 32 &&
x->replay_esn->replay_window != 64 &&
x->replay_esn->replay_window != 128 &&
x->replay_esn->replay_window != 256) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
index d4ebd8743114..b2cabd6ab86c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -310,9 +310,9 @@ static void mlx5e_macsec_destroy_object(struct mlx5_core_dev *mdev, u32 macsec_o
mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
}
-static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
- struct mlx5e_macsec_sa *sa,
- bool is_tx, struct net_device *netdev, u32 fs_id)
+static void mlx5e_macsec_cleanup_sa_fs(struct mlx5e_macsec *macsec,
+ struct mlx5e_macsec_sa *sa, bool is_tx,
+ struct net_device *netdev, u32 fs_id)
{
int action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
@@ -322,20 +322,49 @@ static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
mlx5_macsec_fs_del_rule(macsec->mdev->macsec_fs, sa->macsec_rule, action, netdev,
fs_id);
- mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
sa->macsec_rule = NULL;
}
+static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec,
+ struct mlx5e_macsec_sa *sa, bool is_tx,
+ struct net_device *netdev, u32 fs_id)
+{
+ mlx5e_macsec_cleanup_sa_fs(macsec, sa, is_tx, netdev, fs_id);
+ mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id);
+}
+
+static int mlx5e_macsec_init_sa_fs(struct macsec_context *ctx,
+ struct mlx5e_macsec_sa *sa, bool encrypt,
+ bool is_tx, u32 *fs_id)
+{
+ struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
+ struct mlx5_macsec_fs *macsec_fs = priv->mdev->macsec_fs;
+ struct mlx5_macsec_rule_attrs rule_attrs;
+ union mlx5_macsec_rule *macsec_rule;
+
+ rule_attrs.macsec_obj_id = sa->macsec_obj_id;
+ rule_attrs.sci = sa->sci;
+ rule_attrs.assoc_num = sa->assoc_num;
+ rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
+ MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
+
+ macsec_rule = mlx5_macsec_fs_add_rule(macsec_fs, ctx, &rule_attrs, fs_id);
+ if (!macsec_rule)
+ return -ENOMEM;
+
+ sa->macsec_rule = macsec_rule;
+
+ return 0;
+}
+
static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
struct mlx5e_macsec_sa *sa,
bool encrypt, bool is_tx, u32 *fs_id)
{
struct mlx5e_priv *priv = macsec_netdev_priv(ctx->netdev);
struct mlx5e_macsec *macsec = priv->macsec;
- struct mlx5_macsec_rule_attrs rule_attrs;
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5_macsec_obj_attrs obj_attrs;
- union mlx5_macsec_rule *macsec_rule;
int err;
obj_attrs.next_pn = sa->next_pn;
@@ -357,20 +386,12 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx,
if (err)
return err;
- rule_attrs.macsec_obj_id = sa->macsec_obj_id;
- rule_attrs.sci = sa->sci;
- rule_attrs.assoc_num = sa->assoc_num;
- rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT :
- MLX5_ACCEL_MACSEC_ACTION_DECRYPT;
-
- macsec_rule = mlx5_macsec_fs_add_rule(mdev->macsec_fs, ctx, &rule_attrs, fs_id);
- if (!macsec_rule) {
- err = -ENOMEM;
- goto destroy_macsec_object;
+ if (sa->active) {
+ err = mlx5e_macsec_init_sa_fs(ctx, sa, encrypt, is_tx, fs_id);
+ if (err)
+ goto destroy_macsec_object;
}
- sa->macsec_rule = macsec_rule;
-
return 0;
destroy_macsec_object:
@@ -526,9 +547,7 @@ static int mlx5e_macsec_add_txsa(struct macsec_context *ctx)
goto destroy_sa;
macsec_device->tx_sa[assoc_num] = tx_sa;
- if (!secy->operational ||
- assoc_num != tx_sc->encoding_sa ||
- !tx_sa->active)
+ if (!secy->operational)
goto out;
err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
@@ -595,7 +614,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
goto out;
if (ctx_tx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
+ err = mlx5e_macsec_init_sa_fs(ctx, tx_sa, tx_sc->encrypt, true, NULL);
if (err)
goto out;
} else {
@@ -604,7 +623,7 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx)
goto out;
}
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
+ mlx5e_macsec_cleanup_sa_fs(macsec, tx_sa, true, ctx->secy->netdev, 0);
}
out:
mutex_unlock(&macsec->lock);
@@ -1030,8 +1049,9 @@ static int mlx5e_macsec_del_rxsa(struct macsec_context *ctx)
goto out;
}
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
- rx_sc->sc_xarray_element->fs_id);
+ if (rx_sa->active)
+ mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
+ rx_sc->sc_xarray_element->fs_id);
mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id);
kfree(rx_sa);
rx_sc->rx_sa[assoc_num] = NULL;
@@ -1112,8 +1132,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
if (!rx_sa || !rx_sa->macsec_rule)
continue;
- mlx5e_macsec_cleanup_sa(macsec, rx_sa, false, ctx->secy->netdev,
- rx_sc->sc_xarray_element->fs_id);
+ mlx5e_macsec_cleanup_sa_fs(macsec, rx_sa, false, ctx->secy->netdev,
+ rx_sc->sc_xarray_element->fs_id);
}
}
@@ -1124,8 +1144,8 @@ static int macsec_upd_secy_hw_address(struct macsec_context *ctx,
continue;
if (rx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false,
- &rx_sc->sc_xarray_element->fs_id);
+ err = mlx5e_macsec_init_sa_fs(ctx, rx_sa, true, false,
+ &rx_sc->sc_xarray_element->fs_id);
if (err)
goto out;
}
@@ -1178,7 +1198,7 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
if (!tx_sa)
continue;
- mlx5e_macsec_cleanup_sa(macsec, tx_sa, true, ctx->secy->netdev, 0);
+ mlx5e_macsec_cleanup_sa_fs(macsec, tx_sa, true, ctx->secy->netdev, 0);
}
for (i = 0; i < MACSEC_NUM_AN; ++i) {
@@ -1187,7 +1207,7 @@ static int mlx5e_macsec_upd_secy(struct macsec_context *ctx)
continue;
if (tx_sa->assoc_num == tx_sc->encoding_sa && tx_sa->active) {
- err = mlx5e_macsec_init_sa(ctx, tx_sa, tx_sc->encrypt, true, NULL);
+ err = mlx5e_macsec_init_sa_fs(ctx, tx_sa, tx_sc->encrypt, true, NULL);
if (err)
goto out;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
index bb7f86c993e5..e66f486faafe 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_arfs.c
@@ -254,11 +254,13 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,
ft->g = kcalloc(MLX5E_ARFS_NUM_GROUPS,
sizeof(*ft->g), GFP_KERNEL);
- in = kvzalloc(inlen, GFP_KERNEL);
- if (!in || !ft->g) {
- kfree(ft->g);
- kvfree(in);
+ if (!ft->g)
return -ENOMEM;
+
+ in = kvzalloc(inlen, GFP_KERNEL);
+ if (!in) {
+ err = -ENOMEM;
+ goto err_free_g;
}
mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria);
@@ -278,7 +280,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,
break;
default:
err = -EINVAL;
- goto out;
+ goto err_free_in;
}
switch (type) {
@@ -300,7 +302,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,
break;
default:
err = -EINVAL;
- goto out;
+ goto err_free_in;
}
MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
@@ -309,7 +311,7 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,
MLX5_SET_CFG(in, end_flow_index, ix - 1);
ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
+ goto err_clean_group;
ft->num_groups++;
memset(in, 0, inlen);
@@ -318,18 +320,20 @@ static int arfs_create_groups(struct mlx5e_flow_table *ft,
MLX5_SET_CFG(in, end_flow_index, ix - 1);
ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in);
if (IS_ERR(ft->g[ft->num_groups]))
- goto err;
+ goto err_clean_group;
ft->num_groups++;
kvfree(in);
return 0;
-err:
+err_clean_group:
err = PTR_ERR(ft->g[ft->num_groups]);
ft->g[ft->num_groups] = NULL;
-out:
+err_free_in:
kvfree(in);
-
+err_free_g:
+ kfree(ft->g);
+ ft->g = NULL;
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
index 41c396e76457..6ed3a32b7e22 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_common.c
@@ -74,7 +74,73 @@ int mlx5e_create_mkey(struct mlx5_core_dev *mdev, u32 pdn, u32 *mkey)
return err;
}
-int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev)
+int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn)
+{
+ void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+
+ MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.hw_objs.td.tdn);
+
+ if (mlx5_lag_is_lacp_owner(mdev))
+ MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
+
+ return mlx5_core_create_tis(mdev, in, tisn);
+}
+
+void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
+{
+ mlx5_core_destroy_tis(mdev, tisn);
+}
+
+static void mlx5e_destroy_tises(struct mlx5_core_dev *mdev, u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC])
+{
+ int tc, i;
+
+ for (i = 0; i < mlx5e_get_num_lag_ports(mdev); i++)
+ for (tc = 0; tc < MLX5_MAX_NUM_TC; tc++)
+ mlx5e_destroy_tis(mdev, tisn[i][tc]);
+}
+
+static bool mlx5_lag_should_assign_affinity(struct mlx5_core_dev *mdev)
+{
+ return MLX5_CAP_GEN(mdev, lag_tx_port_affinity) && mlx5e_get_num_lag_ports(mdev) > 1;
+}
+
+static int mlx5e_create_tises(struct mlx5_core_dev *mdev, u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC])
+{
+ int tc, i;
+ int err;
+
+ for (i = 0; i < mlx5e_get_num_lag_ports(mdev); i++) {
+ for (tc = 0; tc < MLX5_MAX_NUM_TC; tc++) {
+ u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
+ void *tisc;
+
+ tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
+
+ MLX5_SET(tisc, tisc, prio, tc << 1);
+
+ if (mlx5_lag_should_assign_affinity(mdev))
+ MLX5_SET(tisc, tisc, lag_tx_port_affinity, i + 1);
+
+ err = mlx5e_create_tis(mdev, in, &tisn[i][tc]);
+ if (err)
+ goto err_close_tises;
+ }
+ }
+
+ return 0;
+
+err_close_tises:
+ for (; i >= 0; i--) {
+ for (tc--; tc >= 0; tc--)
+ mlx5e_destroy_tis(mdev, tisn[i][tc]);
+ tc = MLX5_MAX_NUM_TC;
+ }
+
+ return err;
+}
+
+int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
{
struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
int err;
@@ -103,6 +169,15 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev)
goto err_destroy_mkey;
}
+ if (create_tises) {
+ err = mlx5e_create_tises(mdev, res->tisn);
+ if (err) {
+ mlx5_core_err(mdev, "alloc tises failed, %d\n", err);
+ goto err_destroy_bfreg;
+ }
+ res->tisn_valid = true;
+ }
+
INIT_LIST_HEAD(&res->td.tirs_list);
mutex_init(&res->td.list_lock);
@@ -115,6 +190,8 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev)
return 0;
+err_destroy_bfreg:
+ mlx5_free_bfreg(mdev, &res->bfreg);
err_destroy_mkey:
mlx5_core_destroy_mkey(mdev, res->mkey);
err_dealloc_transport_domain:
@@ -130,6 +207,8 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
mlx5_crypto_dek_cleanup(mdev->mlx5e_res.dek_priv);
mdev->mlx5e_res.dek_priv = NULL;
+ if (res->tisn_valid)
+ mlx5e_destroy_tises(mdev, res->tisn);
mlx5_free_bfreg(mdev, &res->bfreg);
mlx5_core_destroy_mkey(mdev, res->mkey);
mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index c7c1b667b105..cc51ce16df14 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -1262,27 +1262,29 @@ static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev)
return mlx5e_ethtool_get_rxfh_indir_size(priv);
}
-static int mlx5e_get_rxfh_context(struct net_device *dev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context)
+int mlx5e_get_rxfh(struct net_device *netdev, struct ethtool_rxfh_param *rxfh)
{
- struct mlx5e_priv *priv = netdev_priv(dev);
+ struct mlx5e_priv *priv = netdev_priv(netdev);
+ u32 rss_context = rxfh->rss_context;
int err;
mutex_lock(&priv->state_lock);
- err = mlx5e_rx_res_rss_get_rxfh(priv->rx_res, rss_context, indir, key, hfunc);
+ err = mlx5e_rx_res_rss_get_rxfh(priv->rx_res, rss_context,
+ rxfh->indir, rxfh->key, &rxfh->hfunc);
mutex_unlock(&priv->state_lock);
return err;
}
-static int mlx5e_set_rxfh_context(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc,
- u32 *rss_context, bool delete)
+int mlx5e_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct mlx5e_priv *priv = netdev_priv(dev);
+ u32 *rss_context = &rxfh->rss_context;
+ u8 hfunc = rxfh->hfunc;
int err;
mutex_lock(&priv->state_lock);
- if (delete) {
+ if (*rss_context && rxfh->rss_delete) {
err = mlx5e_rx_res_rss_destroy(priv->rx_res, *rss_context);
goto unlock;
}
@@ -1295,7 +1297,8 @@ static int mlx5e_set_rxfh_context(struct net_device *dev, const u32 *indir,
goto unlock;
}
- err = mlx5e_rx_res_rss_set_rxfh(priv->rx_res, *rss_context, indir, key,
+ err = mlx5e_rx_res_rss_set_rxfh(priv->rx_res, *rss_context,
+ rxfh->indir, rxfh->key,
hfunc == ETH_RSS_HASH_NO_CHANGE ? NULL : &hfunc);
unlock:
@@ -1303,25 +1306,6 @@ unlock:
return err;
}
-int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
-{
- return mlx5e_get_rxfh_context(netdev, indir, key, hfunc, 0);
-}
-
-int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
- int err;
-
- mutex_lock(&priv->state_lock);
- err = mlx5e_rx_res_rss_set_rxfh(priv->rx_res, 0, indir, key,
- hfunc == ETH_RSS_HASH_NO_CHANGE ? NULL : &hfunc);
- mutex_unlock(&priv->state_lock);
- return err;
-}
-
#define MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC 100
#define MLX5E_PFC_PREVEN_TOUT_MAX_MSEC 8000
#define MLX5E_PFC_PREVEN_MINOR_PRECENT 85
@@ -2398,6 +2382,7 @@ static void mlx5e_get_rmon_stats(struct net_device *netdev,
}
const struct ethtool_ops mlx5e_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_MAX_FRAMES |
ETHTOOL_COALESCE_USE_ADAPTIVE |
@@ -2420,8 +2405,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
.get_rxfh_indir_size = mlx5e_get_rxfh_indir_size,
.get_rxfh = mlx5e_get_rxfh,
.set_rxfh = mlx5e_set_rxfh,
- .get_rxfh_context = mlx5e_get_rxfh_context,
- .set_rxfh_context = mlx5e_set_rxfh_context,
.get_rxnfc = mlx5e_get_rxnfc,
.set_rxnfc = mlx5e_set_rxnfc,
.get_tunable = mlx5e_get_tunable,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 0c87ddb8a7a2..c8e8f512803e 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -902,6 +902,7 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params,
pp_params.nid = node;
pp_params.dev = rq->pdev;
pp_params.napi = rq->cq.napi;
+ pp_params.netdev = rq->netdev;
pp_params.dma_dir = rq->buff.map_dir;
pp_params.max_len = PAGE_SIZE;
@@ -1351,6 +1352,17 @@ void mlx5e_close_rq(struct mlx5e_rq *rq)
mlx5e_free_rq(rq);
}
+u32 mlx5e_profile_get_tisn(struct mlx5_core_dev *mdev,
+ struct mlx5e_priv *priv,
+ const struct mlx5e_profile *profile,
+ u8 lag_port, u8 tc)
+{
+ if (profile->get_tisn)
+ return profile->get_tisn(mdev, priv, lag_port, tc);
+
+ return mdev->mlx5e_res.hw_objs.tisn[lag_port][tc];
+}
+
static void mlx5e_free_xdpsq_db(struct mlx5e_xdpsq *sq)
{
kvfree(sq->db.xdpi_fifo.xi);
@@ -1919,7 +1931,8 @@ int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
return err;
csp.tis_lst_sz = 1;
- csp.tisn = c->priv->tisn[c->lag_port][0]; /* tc = 0 */
+ csp.tisn = mlx5e_profile_get_tisn(c->mdev, c->priv, c->priv->profile,
+ c->lag_port, 0); /* tc = 0 */
csp.cqn = sq->cq.mcq.cqn;
csp.wq_ctrl = &sq->wq_ctrl;
csp.min_inline_mode = sq->min_inline_mode;
@@ -1981,11 +1994,12 @@ void mlx5e_close_xdpsq(struct mlx5e_xdpsq *sq)
mlx5e_free_xdpsq(sq);
}
-static int mlx5e_alloc_cq_common(struct mlx5e_priv *priv,
+static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
+ struct net_device *netdev,
+ struct workqueue_struct *workqueue,
struct mlx5e_cq_param *param,
struct mlx5e_cq *cq)
{
- struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5_core_cq *mcq = &cq->mcq;
int err;
u32 i;
@@ -2012,13 +2026,13 @@ static int mlx5e_alloc_cq_common(struct mlx5e_priv *priv,
}
cq->mdev = mdev;
- cq->netdev = priv->netdev;
- cq->priv = priv;
+ cq->netdev = netdev;
+ cq->workqueue = workqueue;
return 0;
}
-static int mlx5e_alloc_cq(struct mlx5e_priv *priv,
+static int mlx5e_alloc_cq(struct mlx5_core_dev *mdev,
struct mlx5e_cq_param *param,
struct mlx5e_create_cq_param *ccp,
struct mlx5e_cq *cq)
@@ -2029,7 +2043,7 @@ static int mlx5e_alloc_cq(struct mlx5e_priv *priv,
param->wq.db_numa_node = ccp->node;
param->eq_ix = ccp->ix;
- err = mlx5e_alloc_cq_common(priv, param, cq);
+ err = mlx5e_alloc_cq_common(mdev, ccp->netdev, ccp->wq, param, cq);
cq->napi = ccp->napi;
cq->ch_stats = ccp->ch_stats;
@@ -2095,14 +2109,13 @@ static void mlx5e_destroy_cq(struct mlx5e_cq *cq)
mlx5_core_destroy_cq(cq->mdev, &cq->mcq);
}
-int mlx5e_open_cq(struct mlx5e_priv *priv, struct dim_cq_moder moder,
+int mlx5e_open_cq(struct mlx5_core_dev *mdev, struct dim_cq_moder moder,
struct mlx5e_cq_param *param, struct mlx5e_create_cq_param *ccp,
struct mlx5e_cq *cq)
{
- struct mlx5_core_dev *mdev = priv->mdev;
int err;
- err = mlx5e_alloc_cq(priv, param, ccp, cq);
+ err = mlx5e_alloc_cq(mdev, param, ccp, cq);
if (err)
return err;
@@ -2135,7 +2148,7 @@ static int mlx5e_open_tx_cqs(struct mlx5e_channel *c,
int tc;
for (tc = 0; tc < c->num_tc; tc++) {
- err = mlx5e_open_cq(c->priv, params->tx_cq_moderation, &cparam->txq_sq.cqp,
+ err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->txq_sq.cqp,
ccp, &c->sq[tc].cq);
if (err)
goto err_close_tx_cqs;
@@ -2203,12 +2216,15 @@ static int mlx5e_open_sqs(struct mlx5e_channel *c,
for (tc = 0; tc < mlx5e_get_dcb_num_tc(params); tc++) {
int txq_ix = c->ix + tc * params->num_channels;
u32 qos_queue_group_id;
+ u32 tisn;
+ tisn = mlx5e_profile_get_tisn(c->mdev, c->priv, c->priv->profile,
+ c->lag_port, tc);
err = mlx5e_txq_get_qos_node_hw_id(params, txq_ix, &qos_queue_group_id);
if (err)
goto err_close_sqs;
- err = mlx5e_open_txqsq(c, c->priv->tisn[c->lag_port][tc], txq_ix,
+ err = mlx5e_open_txqsq(c, tisn, txq_ix,
params, &cparam->txq_sq, &c->sq[tc], tc,
qos_queue_group_id,
&c->priv->channel_stats[c->ix]->sq[tc]);
@@ -2336,12 +2352,12 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
mlx5e_build_create_cq_param(&ccp, c);
- err = mlx5e_open_cq(c->priv, icocq_moder, &cparam->async_icosq.cqp, &ccp,
+ err = mlx5e_open_cq(c->mdev, icocq_moder, &cparam->async_icosq.cqp, &ccp,
&c->async_icosq.cq);
if (err)
return err;
- err = mlx5e_open_cq(c->priv, icocq_moder, &cparam->icosq.cqp, &ccp,
+ err = mlx5e_open_cq(c->mdev, icocq_moder, &cparam->icosq.cqp, &ccp,
&c->icosq.cq);
if (err)
goto err_close_async_icosq_cq;
@@ -2350,17 +2366,17 @@ static int mlx5e_open_queues(struct mlx5e_channel *c,
if (err)
goto err_close_icosq_cq;
- err = mlx5e_open_cq(c->priv, params->tx_cq_moderation, &cparam->xdp_sq.cqp, &ccp,
+ err = mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->xdp_sq.cqp, &ccp,
&c->xdpsq.cq);
if (err)
goto err_close_tx_cqs;
- err = mlx5e_open_cq(c->priv, params->rx_cq_moderation, &cparam->rq.cqp, &ccp,
+ err = mlx5e_open_cq(c->mdev, params->rx_cq_moderation, &cparam->rq.cqp, &ccp,
&c->rq.cq);
if (err)
goto err_close_xdp_tx_cqs;
- err = c->xdp ? mlx5e_open_cq(c->priv, params->tx_cq_moderation, &cparam->xdp_sq.cqp,
+ err = c->xdp ? mlx5e_open_cq(c->mdev, params->tx_cq_moderation, &cparam->xdp_sq.cqp,
&ccp, &c->rq_xdpsq.cq) : 0;
if (err)
goto err_close_rx_cq;
@@ -3307,7 +3323,7 @@ static int mlx5e_alloc_drop_cq(struct mlx5e_priv *priv,
param->wq.buf_numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
param->wq.db_numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
- return mlx5e_alloc_cq_common(priv, param, cq);
+ return mlx5e_alloc_cq_common(priv->mdev, priv->netdev, priv->wq, param, cq);
}
int mlx5e_open_drop_rq(struct mlx5e_priv *priv,
@@ -3363,75 +3379,6 @@ void mlx5e_close_drop_rq(struct mlx5e_rq *drop_rq)
mlx5e_free_cq(&drop_rq->cq);
}
-int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn)
-{
- void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
-
- MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.hw_objs.td.tdn);
-
- if (MLX5_GET(tisc, tisc, tls_en))
- MLX5_SET(tisc, tisc, pd, mdev->mlx5e_res.hw_objs.pdn);
-
- if (mlx5_lag_is_lacp_owner(mdev))
- MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
-
- return mlx5_core_create_tis(mdev, in, tisn);
-}
-
-void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
-{
- mlx5_core_destroy_tis(mdev, tisn);
-}
-
-void mlx5e_destroy_tises(struct mlx5e_priv *priv)
-{
- int tc, i;
-
- for (i = 0; i < mlx5e_get_num_lag_ports(priv->mdev); i++)
- for (tc = 0; tc < priv->profile->max_tc; tc++)
- mlx5e_destroy_tis(priv->mdev, priv->tisn[i][tc]);
-}
-
-static bool mlx5e_lag_should_assign_affinity(struct mlx5_core_dev *mdev)
-{
- return MLX5_CAP_GEN(mdev, lag_tx_port_affinity) && mlx5e_get_num_lag_ports(mdev) > 1;
-}
-
-int mlx5e_create_tises(struct mlx5e_priv *priv)
-{
- int tc, i;
- int err;
-
- for (i = 0; i < mlx5e_get_num_lag_ports(priv->mdev); i++) {
- for (tc = 0; tc < priv->profile->max_tc; tc++) {
- u32 in[MLX5_ST_SZ_DW(create_tis_in)] = {};
- void *tisc;
-
- tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
-
- MLX5_SET(tisc, tisc, prio, tc << 1);
-
- if (mlx5e_lag_should_assign_affinity(priv->mdev))
- MLX5_SET(tisc, tisc, lag_tx_port_affinity, i + 1);
-
- err = mlx5e_create_tis(priv->mdev, in, &priv->tisn[i][tc]);
- if (err)
- goto err_close_tises;
- }
- }
-
- return 0;
-
-err_close_tises:
- for (; i >= 0; i--) {
- for (tc--; tc >= 0; tc--)
- mlx5e_destroy_tis(priv->mdev, priv->tisn[i][tc]);
- tc = priv->profile->max_tc;
- }
-
- return err;
-}
-
static void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv)
{
if (priv->mqprio_rl) {
@@ -3440,7 +3387,6 @@ static void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv)
priv->mqprio_rl = NULL;
}
mlx5e_accel_cleanup_tx(priv);
- mlx5e_destroy_tises(priv);
}
static int mlx5e_modify_channels_vsd(struct mlx5e_channels *chs, bool vsd)
@@ -3542,7 +3488,7 @@ static int mlx5e_setup_tc_mqprio_dcb(struct mlx5e_priv *priv,
mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
- if (tc && tc != MLX5E_MAX_NUM_TC)
+ if (tc && tc != MLX5_MAX_NUM_TC)
return -EINVAL;
new_params = priv->channels.params;
@@ -5185,6 +5131,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
netdev->netdev_ops = &mlx5e_netdev_ops;
netdev->xdp_metadata_ops = &mlx5e_xdp_metadata_ops;
+ netdev->xsk_tx_metadata_ops = &mlx5e_xsk_tx_metadata_ops;
mlx5e_dcbnl_build_netdev(netdev);
@@ -5265,7 +5212,6 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
netdev->gso_partial_features |= NETIF_F_GSO_UDP_L4;
netdev->hw_features |= NETIF_F_GSO_UDP_L4;
- netdev->features |= NETIF_F_GSO_UDP_L4;
mlx5_query_port_fcs(mdev, &fcs_supported, &fcs_enabled);
@@ -5505,23 +5451,13 @@ static int mlx5e_init_nic_tx(struct mlx5e_priv *priv)
{
int err;
- err = mlx5e_create_tises(priv);
- if (err) {
- mlx5_core_warn(priv->mdev, "create tises failed, %d\n", err);
- return err;
- }
-
err = mlx5e_accel_init_tx(priv);
if (err)
- goto err_destroy_tises;
+ return err;
mlx5e_set_mqprio_rl(priv);
mlx5e_dcbnl_initialize(priv);
return 0;
-
-err_destroy_tises:
- mlx5e_destroy_tises(priv);
- return err;
}
static void mlx5e_nic_enable(struct mlx5e_priv *priv)
@@ -5616,7 +5552,7 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
.update_stats = mlx5e_stats_update_ndo_stats,
.update_carrier = mlx5e_update_carrier,
.rx_handlers = &mlx5e_rx_handlers_nic,
- .max_tc = MLX5E_MAX_NUM_TC,
+ .max_tc = MLX5_MAX_NUM_TC,
.stats_grps = mlx5e_nic_stats_grps,
.stats_grps_num = mlx5e_nic_stats_grps_num,
.features = BIT(MLX5E_PROFILE_FEATURE_PTP_RX) |
@@ -6056,7 +5992,7 @@ static int mlx5e_resume(struct auxiliary_device *adev)
if (netif_device_present(netdev))
return 0;
- err = mlx5e_create_mdev_resources(mdev);
+ err = mlx5e_create_mdev_resources(mdev, true);
if (err)
return err;
@@ -6069,7 +6005,7 @@ static int mlx5e_resume(struct auxiliary_device *adev)
return 0;
}
-static int mlx5e_suspend(struct auxiliary_device *adev, pm_message_t state)
+static int _mlx5e_suspend(struct auxiliary_device *adev)
{
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
@@ -6087,15 +6023,18 @@ static int mlx5e_suspend(struct auxiliary_device *adev, pm_message_t state)
return 0;
}
-static int mlx5e_probe(struct auxiliary_device *adev,
- const struct auxiliary_device_id *id)
+static int mlx5e_suspend(struct auxiliary_device *adev, pm_message_t state)
+{
+ return _mlx5e_suspend(adev);
+}
+
+static int _mlx5e_probe(struct auxiliary_device *adev)
{
struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
const struct mlx5e_profile *profile = &mlx5e_nic_profile;
struct mlx5_core_dev *mdev = edev->mdev;
struct mlx5e_dev *mlx5e_dev;
struct net_device *netdev;
- pm_message_t state = {};
struct mlx5e_priv *priv;
int err;
@@ -6150,7 +6089,7 @@ static int mlx5e_probe(struct auxiliary_device *adev,
return 0;
err_resume:
- mlx5e_suspend(adev, state);
+ _mlx5e_suspend(adev);
err_profile_cleanup:
profile->cleanup(priv);
err_destroy_netdev:
@@ -6162,16 +6101,21 @@ err_devlink_unregister:
return err;
}
+static int mlx5e_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ return _mlx5e_probe(adev);
+}
+
static void mlx5e_remove(struct auxiliary_device *adev)
{
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
- pm_message_t state = {};
mlx5_core_uplink_netdev_set(priv->mdev, NULL);
mlx5e_dcbnl_delete_app(priv);
unregister_netdev(priv->netdev);
- mlx5e_suspend(adev, state);
+ _mlx5e_suspend(adev);
priv->profile->cleanup(priv);
mlx5e_destroy_netdev(priv);
mlx5e_devlink_port_unregister(mlx5e_dev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index e92d4f83592e..05527418fa64 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -112,8 +112,18 @@ static const struct counter_desc vport_rep_stats_desc[] = {
tx_vport_rdma_multicast_bytes) },
};
+static const struct counter_desc vport_rep_loopback_stats_desc[] = {
+ { MLX5E_DECLARE_STAT(struct mlx5e_rep_stats,
+ vport_loopback_packets) },
+ { MLX5E_DECLARE_STAT(struct mlx5e_rep_stats,
+ vport_loopback_bytes) },
+};
+
#define NUM_VPORT_REP_SW_COUNTERS ARRAY_SIZE(sw_rep_stats_desc)
#define NUM_VPORT_REP_HW_COUNTERS ARRAY_SIZE(vport_rep_stats_desc)
+#define NUM_VPORT_REP_LOOPBACK_COUNTERS(dev) \
+ (MLX5_CAP_GEN(dev, vport_counter_local_loopback) ? \
+ ARRAY_SIZE(vport_rep_loopback_stats_desc) : 0)
static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(sw_rep)
{
@@ -157,7 +167,8 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(sw_rep)
static MLX5E_DECLARE_STATS_GRP_OP_NUM_STATS(vport_rep)
{
- return NUM_VPORT_REP_HW_COUNTERS;
+ return NUM_VPORT_REP_HW_COUNTERS +
+ NUM_VPORT_REP_LOOPBACK_COUNTERS(priv->mdev);
}
static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport_rep)
@@ -166,6 +177,9 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STRS(vport_rep)
for (i = 0; i < NUM_VPORT_REP_HW_COUNTERS; i++)
strcpy(data + (idx++) * ETH_GSTRING_LEN, vport_rep_stats_desc[i].format);
+ for (i = 0; i < NUM_VPORT_REP_LOOPBACK_COUNTERS(priv->mdev); i++)
+ strcpy(data + (idx++) * ETH_GSTRING_LEN,
+ vport_rep_loopback_stats_desc[i].format);
return idx;
}
@@ -176,6 +190,9 @@ static MLX5E_DECLARE_STATS_GRP_OP_FILL_STATS(vport_rep)
for (i = 0; i < NUM_VPORT_REP_HW_COUNTERS; i++)
data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.rep_stats,
vport_rep_stats_desc, i);
+ for (i = 0; i < NUM_VPORT_REP_LOOPBACK_COUNTERS(priv->mdev); i++)
+ data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.rep_stats,
+ vport_rep_loopback_stats_desc, i);
return idx;
}
@@ -247,6 +264,13 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vport_rep)
rep_stats->tx_vport_rdma_multicast_bytes =
MLX5_GET_CTR(out, received_ib_multicast.octets);
+ if (MLX5_CAP_GEN(priv->mdev, vport_counter_local_loopback)) {
+ rep_stats->vport_loopback_packets =
+ MLX5_GET_CTR(out, local_loopback.packets);
+ rep_stats->vport_loopback_bytes =
+ MLX5_GET_CTR(out, local_loopback.octets);
+ }
+
out:
kvfree(out);
}
@@ -1156,12 +1180,6 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
struct mlx5e_rep_priv *rpriv = priv->ppriv;
int err;
- err = mlx5e_create_tises(priv);
- if (err) {
- mlx5_core_warn(priv->mdev, "create tises failed, %d\n", err);
- return err;
- }
-
err = mlx5e_rep_neigh_init(rpriv);
if (err)
goto err_neigh_init;
@@ -1184,7 +1202,6 @@ err_ht_init:
err_init_tx:
mlx5e_rep_neigh_cleanup(rpriv);
err_neigh_init:
- mlx5e_destroy_tises(priv);
return err;
}
@@ -1198,7 +1215,6 @@ static void mlx5e_cleanup_rep_tx(struct mlx5e_priv *priv)
mlx5e_cleanup_uplink_rep_tx(rpriv);
mlx5e_rep_neigh_cleanup(rpriv);
- mlx5e_destroy_tises(priv);
}
static void mlx5e_rep_enable(struct mlx5e_priv *priv)
@@ -1428,7 +1444,7 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
.update_stats = mlx5e_stats_update_ndo_stats,
.update_carrier = mlx5e_update_carrier,
.rx_handlers = &mlx5e_rx_handlers_rep,
- .max_tc = MLX5E_MAX_NUM_TC,
+ .max_tc = MLX5_MAX_NUM_TC,
.stats_grps = mlx5e_ul_rep_stats_grps,
.stats_grps_num = mlx5e_ul_rep_stats_grps_num,
};
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index 8d9743a5e42c..d601b5faaed5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -298,8 +298,8 @@ static void mlx5e_page_release_fragmented(struct mlx5e_rq *rq,
u16 drain_count = MLX5E_PAGECNT_BIAS_MAX - frag_page->frags;
struct page *page = frag_page->page;
- if (page_pool_defrag_page(page, drain_count) == 0)
- page_pool_put_defragged_page(rq->page_pool, page, -1, true);
+ if (page_pool_unref_page(page, drain_count) == 0)
+ page_pool_put_unrefed_page(rq->page_pool, page, -1, true);
}
static inline int mlx5e_get_rx_frag(struct mlx5e_rq *rq,
@@ -1039,7 +1039,7 @@ int mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
(struct mlx5_err_cqe *)cqe);
mlx5_wq_cyc_wqe_dump(&sq->wq, ci, wi->num_wqebbs);
if (!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state))
- queue_work(cq->priv->wq, &sq->recover_work);
+ queue_work(cq->workqueue, &sq->recover_work);
break;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
index 477c547dcc04..12b3607afecd 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h
@@ -476,6 +476,8 @@ struct mlx5e_rep_stats {
u64 tx_vport_rdma_multicast_packets;
u64 rx_vport_rdma_multicast_bytes;
u64 tx_vport_rdma_multicast_bytes;
+ u64 vport_loopback_packets;
+ u64 vport_loopback_bytes;
};
struct mlx5e_stats {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 96af9e2ab1d8..9fb2c057bd78 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -761,7 +761,7 @@ static int mlx5e_hairpin_create_indirect_rqt(struct mlx5e_hairpin *hp)
err = mlx5e_rss_params_indir_init(&indir, mdev,
mlx5e_rqt_size(mdev, hp->num_channels),
- mlx5e_rqt_size(mdev, priv->max_nch));
+ mlx5e_rqt_size(mdev, hp->num_channels));
if (err)
return err;
@@ -2014,9 +2014,10 @@ static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow,
list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows) {
if (peer_index != mlx5_get_dev_index(peer_flow->priv->mdev))
continue;
+
+ list_del(&peer_flow->peer_flows);
if (refcount_dec_and_test(&peer_flow->refcnt)) {
mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow);
- list_del(&peer_flow->peer_flows);
kfree(peer_flow);
}
}
@@ -3209,10 +3210,10 @@ static int offload_pedit_fields(struct mlx5e_priv *priv,
headers_c = mlx5e_get_match_headers_criteria(*action_flags, &parse_attr->spec);
headers_v = mlx5e_get_match_headers_value(*action_flags, &parse_attr->spec);
- set_masks = &hdrs[0].masks;
- add_masks = &hdrs[1].masks;
- set_vals = &hdrs[0].vals;
- add_vals = &hdrs[1].vals;
+ set_masks = &hdrs[TCA_PEDIT_KEY_EX_CMD_SET].masks;
+ add_masks = &hdrs[TCA_PEDIT_KEY_EX_CMD_ADD].masks;
+ set_vals = &hdrs[TCA_PEDIT_KEY_EX_CMD_SET].vals;
+ add_vals = &hdrs[TCA_PEDIT_KEY_EX_CMD_ADD].vals;
for (i = 0; i < ARRAY_SIZE(fields); i++) {
bool skip;
@@ -5030,22 +5031,6 @@ int mlx5e_tc_delete_matchall(struct mlx5e_priv *priv,
return apply_police_params(priv, 0, extack);
}
-void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv,
- struct tc_cls_matchall_offload *ma)
-{
- struct mlx5e_rep_priv *rpriv = priv->ppriv;
- struct rtnl_link_stats64 cur_stats;
- u64 dbytes;
- u64 dpkts;
-
- mlx5e_stats_copy_rep_stats(&cur_stats, &priv->stats.rep_stats);
- dpkts = cur_stats.rx_packets - rpriv->prev_vf_vport_stats.rx_packets;
- dbytes = cur_stats.rx_bytes - rpriv->prev_vf_vport_stats.rx_bytes;
- rpriv->prev_vf_vport_stats = cur_stats;
- flow_stats_update(&ma->stats, dbytes, dpkts, 0, jiffies,
- FLOW_ACTION_HW_STATS_DELAYED);
-}
-
static void mlx5e_tc_hairpin_update_dead_peer(struct mlx5e_priv *priv,
struct mlx5e_priv *peer_priv)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
index adb39e30f90f..c24bda56b2b5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
@@ -203,8 +203,6 @@ int mlx5e_tc_configure_matchall(struct mlx5e_priv *priv,
struct tc_cls_matchall_offload *f);
int mlx5e_tc_delete_matchall(struct mlx5e_priv *priv,
struct tc_cls_matchall_offload *f);
-void mlx5e_tc_stats_matchall(struct mlx5e_priv *priv,
- struct tc_cls_matchall_offload *ma);
struct mlx5e_encap_entry;
void mlx5e_tc_encap_flows_add(struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index f0b506e562df..2fa076b23fbe 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -401,6 +401,8 @@ mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
mlx5e_skb_cb_hwtstamp_init(skb);
mlx5e_ptp_metadata_map_put(&sq->ptpsq->metadata_map, skb,
metadata_index);
+ /* ensure skb is put on metadata_map before tracking the index */
+ wmb();
mlx5e_ptpsq_track_metadata(sq->ptpsq, metadata_index);
if (!netif_tx_queue_stopped(sq->txq) &&
mlx5e_ptpsq_metadata_freelist_empty(sq->ptpsq)) {
@@ -861,7 +863,7 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
mlx5e_dump_error_cqe(&sq->cq, sq->sqn,
(struct mlx5_err_cqe *)cqe);
mlx5_wq_cyc_wqe_dump(&sq->wq, ci, wi->num_wqebbs);
- queue_work(cq->priv->wq, &sq->recover_work);
+ queue_work(cq->workqueue, &sq->recover_work);
}
stats->cqe_err++;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c
index a7ed87e9d842..22dd30cf8033 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/bridge_mcast.c
@@ -83,6 +83,7 @@ mlx5_esw_bridge_mdb_flow_create(u16 esw_owner_vhca_id, struct mlx5_esw_bridge_md
i++;
}
+ rule_spec->flow_context.flags |= FLOW_CONTEXT_UPLINK_HAIRPIN_EN;
rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
dmac_v = MLX5_ADDR_OF(fte_match_param, rule_spec->match_value, outer_headers.dmac_47_16);
ether_addr_copy(dmac_v, entry->key.addr);
@@ -587,6 +588,7 @@ mlx5_esw_bridge_mcast_vlan_flow_create(u16 vlan_proto, struct mlx5_esw_bridge_po
if (!rule_spec)
return ERR_PTR(-ENOMEM);
+ rule_spec->flow_context.flags |= FLOW_CONTEXT_UPLINK_HAIRPIN_EN;
rule_spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
@@ -662,6 +664,7 @@ mlx5_esw_bridge_mcast_fwd_flow_create(struct mlx5_esw_bridge_port *port)
dest.vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID;
dest.vport.vhca_id = port->esw_owner_vhca_id;
}
+ rule_spec->flow_context.flags |= FLOW_CONTEXT_UPLINK_HAIRPIN_EN;
handle = mlx5_add_flow_rules(port->mcast.ft, rule_spec, &flow_act, &dest, 1);
kvfree(rule_spec);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
index 190f10aba170..5a0047bdcb51 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/ipsec_fs.c
@@ -152,7 +152,7 @@ void mlx5_esw_ipsec_restore_dest_uplink(struct mlx5_core_dev *mdev)
xa_for_each(&esw->offloads.vport_reps, i, rep) {
rpriv = rep->rep_data[REP_ETH].priv;
- if (!rpriv || !rpriv->netdev || !atomic_read(&rpriv->tc_ht.nelems))
+ if (!rpriv || !rpriv->netdev)
continue;
rhashtable_walk_enter(&rpriv->tc_ht, &iter);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index b4eb17141edf..349e28a6dd8d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -618,13 +618,6 @@ static inline bool mlx5_esw_allowed(const struct mlx5_eswitch *esw)
return esw && MLX5_ESWITCH_MANAGER(esw->dev);
}
-/* The returned number is valid only when the dev is eswitch manager. */
-static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev)
-{
- return mlx5_core_is_ecpf_esw_manager(dev) ?
- MLX5_VPORT_ECPF : MLX5_VPORT_PF;
-}
-
static inline bool
mlx5_esw_is_manager_vport(const struct mlx5_eswitch *esw, u16 vport_num)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
index b0455134c98e..baaae628b0a0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
@@ -535,21 +535,26 @@ esw_src_port_rewrite_supported(struct mlx5_eswitch *esw)
}
static bool
-esw_dests_to_vf_pf_vports(struct mlx5_flow_destination *dests, int max_dest)
+esw_dests_to_int_external(struct mlx5_flow_destination *dests, int max_dest)
{
- bool vf_dest = false, pf_dest = false;
+ bool internal_dest = false, external_dest = false;
int i;
for (i = 0; i < max_dest; i++) {
- if (dests[i].type != MLX5_FLOW_DESTINATION_TYPE_VPORT)
+ if (dests[i].type != MLX5_FLOW_DESTINATION_TYPE_VPORT &&
+ dests[i].type != MLX5_FLOW_DESTINATION_TYPE_UPLINK)
continue;
- if (dests[i].vport.num == MLX5_VPORT_UPLINK)
- pf_dest = true;
+ /* Uplink dest is external, but considered as internal
+ * if there is reformat because firmware uses LB+hairpin to support it.
+ */
+ if (dests[i].vport.num == MLX5_VPORT_UPLINK &&
+ !(dests[i].vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID))
+ external_dest = true;
else
- vf_dest = true;
+ internal_dest = true;
- if (vf_dest && pf_dest)
+ if (internal_dest && external_dest)
return true;
}
@@ -695,9 +700,9 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
/* Header rewrite with combined wire+loopback in FDB is not allowed */
if ((flow_act.action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR) &&
- esw_dests_to_vf_pf_vports(dest, i)) {
+ esw_dests_to_int_external(dest, i)) {
esw_warn(esw->dev,
- "FDB: Header rewrite with forwarding to both PF and VF is not allowed\n");
+ "FDB: Header rewrite with forwarding to both internal and external dests is not allowed\n");
rule = ERR_PTR(-EINVAL);
goto err_esw_get;
}
@@ -3658,22 +3663,6 @@ static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
return 0;
}
-static bool esw_offloads_devlink_ns_eq_netdev_ns(struct devlink *devlink)
-{
- struct mlx5_core_dev *dev = devlink_priv(devlink);
- struct net *devl_net, *netdev_net;
- bool ret = false;
-
- mutex_lock(&dev->mlx5e_res.uplink_netdev_lock);
- if (dev->mlx5e_res.uplink_netdev) {
- netdev_net = dev_net(dev->mlx5e_res.uplink_netdev);
- devl_net = devlink_net(devlink);
- ret = net_eq(devl_net, netdev_net);
- }
- mutex_unlock(&dev->mlx5e_res.uplink_netdev_lock);
- return ret;
-}
-
int mlx5_eswitch_block_mode(struct mlx5_core_dev *dev)
{
struct mlx5_eswitch *esw = dev->priv.eswitch;
@@ -3718,13 +3707,6 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
if (esw_mode_from_devlink(mode, &mlx5_mode))
return -EINVAL;
- if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV &&
- !esw_offloads_devlink_ns_eq_netdev_ns(devlink)) {
- NL_SET_ERR_MSG_MOD(extack,
- "Can't change E-Switch mode to switchdev when netdev net namespace has diverged from the devlink's.");
- return -EPERM;
- }
-
mlx5_lag_disable_change(esw->dev);
err = mlx5_esw_try_lock(esw);
if (err < 0) {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
index a4b925331661..9b8599c200e2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
@@ -566,6 +566,8 @@ static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
fte->flow_context.flow_tag);
MLX5_SET(flow_context, in_flow_context, flow_source,
fte->flow_context.flow_source);
+ MLX5_SET(flow_context, in_flow_context, uplink_hairpin_en,
+ !!(fte->flow_context.flags & FLOW_CONTEXT_UPLINK_HAIRPIN_EN));
MLX5_SET(flow_context, in_flow_context, extended_destination,
extended_dest);
@@ -1144,3 +1146,37 @@ const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type typ
return mlx5_fs_cmd_get_stub_cmds();
}
}
+
+int mlx5_fs_cmd_set_l2table_entry_silent(struct mlx5_core_dev *dev, u8 silent_mode)
+{
+ u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)] = {};
+
+ if (silent_mode && !MLX5_CAP_GEN(dev, silent_mode))
+ return -EOPNOTSUPP;
+
+ MLX5_SET(set_l2_table_entry_in, in, opcode, MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
+ MLX5_SET(set_l2_table_entry_in, in, silent_mode_valid, 1);
+ MLX5_SET(set_l2_table_entry_in, in, silent_mode, silent_mode);
+
+ return mlx5_cmd_exec_in(dev, set_l2_table_entry, in);
+}
+
+int mlx5_fs_cmd_set_tx_flow_table_root(struct mlx5_core_dev *dev, u32 ft_id, bool disconnect)
+{
+ u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)] = {};
+
+ if (disconnect && MLX5_CAP_FLOWTABLE_NIC_TX(dev, reset_root_to_default))
+ return -EOPNOTSUPP;
+
+ MLX5_SET(set_flow_table_root_in, in, opcode,
+ MLX5_CMD_OP_SET_FLOW_TABLE_ROOT);
+ MLX5_SET(set_flow_table_root_in, in, table_type,
+ FS_FT_NIC_TX);
+ if (disconnect)
+ MLX5_SET(set_flow_table_root_in, in, op_mod, 1);
+ else
+ MLX5_SET(set_flow_table_root_in, in, table_id, ft_id);
+
+ return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
index 7790ae5531e1..53e0e5137d3f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
@@ -122,4 +122,6 @@ int mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, u32 base_id, int bulk_len,
const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type type);
const struct mlx5_flow_cmds *mlx5_fs_cmd_get_fw_cmds(void);
+int mlx5_fs_cmd_set_l2table_entry_silent(struct mlx5_core_dev *dev, u8 silent_mode);
+int mlx5_fs_cmd_set_tx_flow_table_root(struct mlx5_core_dev *dev, u32 ft_id, bool disconnect);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
index 4aed1768b85f..78eb6b7097e1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
@@ -181,7 +181,7 @@ struct mlx5_flow_rule {
struct mlx5_flow_handle {
int num_rules;
- struct mlx5_flow_rule *rule[];
+ struct mlx5_flow_rule *rule[] __counted_by(num_rules);
};
/* Type of children is mlx5_flow_group */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
index 17fe30a4c06c..0c26d707eed2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
@@ -539,7 +539,7 @@ struct mlx5_fc_bulk {
u32 base_id;
int bulk_len;
unsigned long *bitmask;
- struct mlx5_fc fcs[];
+ struct mlx5_fc fcs[] __counted_by(bulk_len);
};
static void mlx5_fc_init(struct mlx5_fc *counter, struct mlx5_fc_bulk *bulk,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
index c4e19d627da2..2911aa34a5be 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c
@@ -348,6 +348,25 @@ static int mlx5_check_hotplug_interrupt(struct mlx5_core_dev *dev)
}
#endif
+static const struct pci_device_id mgt_ifc_device_ids[] = {
+ { PCI_VDEVICE(MELLANOX, 0xc2d2) }, /* BlueField1 MGT interface device ID */
+ { PCI_VDEVICE(MELLANOX, 0xc2d3) }, /* BlueField2 MGT interface device ID */
+ { PCI_VDEVICE(MELLANOX, 0xc2d4) }, /* BlueField3-Lx MGT interface device ID */
+ { PCI_VDEVICE(MELLANOX, 0xc2d5) }, /* BlueField3 MGT interface device ID */
+ { PCI_VDEVICE(MELLANOX, 0xc2d6) }, /* BlueField4 MGT interface device ID */
+};
+
+static bool mlx5_is_mgt_ifc_pci_device(struct mlx5_core_dev *dev, u16 dev_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mgt_ifc_device_ids); ++i)
+ if (mgt_ifc_device_ids[i].device == dev_id)
+ return true;
+
+ return false;
+}
+
static int mlx5_check_dev_ids(struct mlx5_core_dev *dev, u16 dev_id)
{
struct pci_bus *bridge_bus = dev->pdev->bus;
@@ -362,10 +381,15 @@ static int mlx5_check_dev_ids(struct mlx5_core_dev *dev, u16 dev_id)
err = pci_read_config_word(sdev, PCI_DEVICE_ID, &sdev_id);
if (err)
return pcibios_err_to_errno(err);
- if (sdev_id != dev_id) {
- mlx5_core_warn(dev, "unrecognized dev_id (0x%x)\n", sdev_id);
- return -EPERM;
- }
+
+ if (sdev_id == dev_id)
+ continue;
+
+ if (mlx5_is_mgt_ifc_pci_device(dev, sdev_id))
+ continue;
+
+ mlx5_core_warn(dev, "unrecognized dev_id (0x%x)\n", sdev_id);
+ return -EPERM;
}
return 0;
}
@@ -679,19 +703,30 @@ void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev)
{
struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
+ if (!fw_reset)
+ return;
+
MLX5_NB_INIT(&fw_reset->nb, fw_reset_event_notifier, GENERAL_EVENT);
mlx5_eq_notifier_register(dev, &fw_reset->nb);
}
void mlx5_fw_reset_events_stop(struct mlx5_core_dev *dev)
{
- mlx5_eq_notifier_unregister(dev, &dev->priv.fw_reset->nb);
+ struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
+
+ if (!fw_reset)
+ return;
+
+ mlx5_eq_notifier_unregister(dev, &fw_reset->nb);
}
void mlx5_drain_fw_reset(struct mlx5_core_dev *dev)
{
struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
+ if (!fw_reset)
+ return;
+
set_bit(MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, &fw_reset->reset_flags);
cancel_work_sync(&fw_reset->fw_live_patch_work);
cancel_work_sync(&fw_reset->reset_request_work);
@@ -709,9 +744,13 @@ static const struct devlink_param mlx5_fw_reset_devlink_params[] = {
int mlx5_fw_reset_init(struct mlx5_core_dev *dev)
{
- struct mlx5_fw_reset *fw_reset = kzalloc(sizeof(*fw_reset), GFP_KERNEL);
+ struct mlx5_fw_reset *fw_reset;
int err;
+ if (!MLX5_CAP_MCAM_REG(dev, mfrl))
+ return 0;
+
+ fw_reset = kzalloc(sizeof(*fw_reset), GFP_KERNEL);
if (!fw_reset)
return -ENOMEM;
fw_reset->wq = create_singlethread_workqueue("mlx5_fw_reset_events");
@@ -747,6 +786,9 @@ void mlx5_fw_reset_cleanup(struct mlx5_core_dev *dev)
{
struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset;
+ if (!fw_reset)
+ return;
+
devl_params_unregister(priv_to_devlink(dev),
mlx5_fw_reset_devlink_params,
ARRAY_SIZE(mlx5_fw_reset_devlink_params));
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c
index 8ff6dc9bc803..b5c709bba155 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/health.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c
@@ -452,10 +452,10 @@ mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
struct health_buffer __iomem *h = health->health;
u8 synd = ioread8(&h->synd);
+ devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
if (!synd)
return 0;
- devlink_fmsg_u8_pair_put(fmsg, "Syndrome", synd);
devlink_fmsg_string_pair_put(fmsg, "Description", hsynd_str(synd));
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
index 2bf77a5251b4..d77be1b4dd9c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c
@@ -339,7 +339,7 @@ static int mlx5i_init_tx(struct mlx5e_priv *priv)
return err;
}
- err = mlx5i_create_tis(priv->mdev, ipriv->qpn, &priv->tisn[0][0]);
+ err = mlx5i_create_tis(priv->mdev, ipriv->qpn, &ipriv->tisn);
if (err) {
mlx5_core_warn(priv->mdev, "create tis failed, %d\n", err);
goto err_destroy_underlay_qp;
@@ -356,7 +356,7 @@ static void mlx5i_cleanup_tx(struct mlx5e_priv *priv)
{
struct mlx5i_priv *ipriv = priv->ppriv;
- mlx5e_destroy_tis(priv->mdev, priv->tisn[0][0]);
+ mlx5e_destroy_tis(priv->mdev, ipriv->tisn);
mlx5i_destroy_underlay_qp(priv->mdev, ipriv->qpn);
}
@@ -483,6 +483,18 @@ static unsigned int mlx5i_stats_grps_num(struct mlx5e_priv *priv)
return ARRAY_SIZE(mlx5i_stats_grps);
}
+u32 mlx5i_get_tisn(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv, u8 lag_port, u8 tc)
+{
+ struct mlx5i_priv *ipriv = priv->ppriv;
+
+ if (WARN(lag_port || tc,
+ "IPoIB unexpected non-zero value: lag_port (%u), tc (%u)\n",
+ lag_port, tc))
+ return 0;
+
+ return ipriv->tisn;
+}
+
static const struct mlx5e_profile mlx5i_nic_profile = {
.init = mlx5i_init,
.cleanup = mlx5i_cleanup,
@@ -499,6 +511,7 @@ static const struct mlx5e_profile mlx5i_nic_profile = {
.max_tc = MLX5I_MAX_NUM_TC,
.stats_grps = mlx5i_stats_grps,
.stats_grps_num = mlx5i_stats_grps_num,
+ .get_tisn = mlx5i_get_tisn,
};
/* mlx5i netdev NDos */
@@ -770,7 +783,7 @@ static int mlx5_rdma_setup_rn(struct ib_device *ibdev, u32 port_num,
}
/* This should only be called once per mdev */
- err = mlx5e_create_mdev_resources(mdev);
+ err = mlx5e_create_mdev_resources(mdev, false);
if (err)
goto destroy_ht;
}
@@ -829,7 +842,7 @@ int mlx5_rdma_rn_get_params(struct mlx5_core_dev *mdev,
*params = (struct rdma_netdev_alloc_params){
.sizeof_priv = sizeof(struct mlx5i_priv) +
sizeof(struct mlx5e_priv),
- .txqs = nch * MLX5E_MAX_NUM_TC,
+ .txqs = nch * MLX5_MAX_NUM_TC,
.rxqs = nch,
.param = mdev,
.initialize_rdma_netdev = mlx5_rdma_setup_rn,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
index f3f2af972020..2ab6437a1c49 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib.h
@@ -53,6 +53,7 @@ extern const struct mlx5e_rx_handlers mlx5i_rx_handlers;
struct mlx5i_priv {
struct rdma_netdev rn; /* keep this first */
u32 qpn;
+ u32 tisn;
bool sub_interface;
u32 num_sub_interfaces;
u32 qkey;
@@ -63,6 +64,7 @@ struct mlx5i_priv {
};
int mlx5i_create_tis(struct mlx5_core_dev *mdev, u32 underlay_qpn, u32 *tisn);
+u32 mlx5i_get_tisn(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv, u8 lag_port, u8 tc);
/* Underlay QP create/destroy functions */
int mlx5i_create_underlay_qp(struct mlx5e_priv *priv);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
index 03e681297937..f87471306f6b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c
@@ -218,7 +218,7 @@ static int mlx5i_pkey_open(struct net_device *netdev)
goto err_unint_underlay_qp;
}
- err = mlx5i_create_tis(mdev, ipriv->qpn, &epriv->tisn[0][0]);
+ err = mlx5i_create_tis(mdev, ipriv->qpn, &ipriv->tisn);
if (err) {
mlx5_core_warn(mdev, "create child tis failed, %d\n", err);
goto err_remove_rx_uderlay_qp;
@@ -240,7 +240,7 @@ static int mlx5i_pkey_open(struct net_device *netdev)
err_close_channels:
mlx5e_close_channels(&epriv->channels);
err_clear_state_opened_flag:
- mlx5e_destroy_tis(mdev, epriv->tisn[0][0]);
+ mlx5e_destroy_tis(mdev, ipriv->tisn);
err_remove_rx_uderlay_qp:
mlx5_fs_remove_rx_underlay_qpn(mdev, ipriv->qpn);
err_unint_underlay_qp:
@@ -269,7 +269,7 @@ static int mlx5i_pkey_close(struct net_device *netdev)
mlx5i_uninit_underlay_qp(priv);
mlx5e_deactivate_priv_channels(priv);
mlx5e_close_channels(&priv->channels);
- mlx5e_destroy_tis(mdev, priv->tisn[0][0]);
+ mlx5e_destroy_tis(mdev, ipriv->tisn);
unlock:
mutex_unlock(&priv->state_lock);
return 0;
@@ -361,6 +361,7 @@ static const struct mlx5e_profile mlx5i_pkey_nic_profile = {
.update_stats = NULL,
.rx_handlers = &mlx5i_rx_handlers,
.max_tc = MLX5I_MAX_NUM_TC,
+ .get_tisn = mlx5i_get_tisn,
};
const struct mlx5e_profile *mlx5i_pkey_get_profile(void)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
index 40c7be124041..58bd749b5e4d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/aso.c
@@ -98,7 +98,7 @@ static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)
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, cq_period_mode, MLX5_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 -
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
index 0c83ef174275..0361741632a6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
@@ -266,9 +266,6 @@ static int mlx5_ptp_settime_real_time(struct mlx5_core_dev *mdev,
{
u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {};
- if (!mlx5_modify_mtutc_allowed(mdev))
- return 0;
-
if (ts->tv_sec < 0 || ts->tv_sec > U32_MAX ||
ts->tv_nsec < 0 || ts->tv_nsec > NSEC_PER_SEC)
return -EINVAL;
@@ -286,12 +283,15 @@ static int mlx5_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64
struct mlx5_timer *timer = &clock->timer;
struct mlx5_core_dev *mdev;
unsigned long flags;
- int err;
mdev = container_of(clock, struct mlx5_core_dev, clock);
- err = mlx5_ptp_settime_real_time(mdev, ts);
- if (err)
- return err;
+
+ if (mlx5_modify_mtutc_allowed(mdev)) {
+ int err = mlx5_ptp_settime_real_time(mdev, ts);
+
+ if (err)
+ return err;
+ }
write_seqlock_irqsave(&clock->lock, flags);
timecounter_init(&timer->tc, &timer->cycles, timespec64_to_ns(ts));
@@ -341,9 +341,6 @@ static int mlx5_ptp_adjtime_real_time(struct mlx5_core_dev *mdev, s64 delta)
{
u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {};
- if (!mlx5_modify_mtutc_allowed(mdev))
- return 0;
-
/* HW time adjustment range is checked. If out of range, settime instead */
if (!mlx5_is_mtutc_time_adj_cap(mdev, delta)) {
struct timespec64 ts;
@@ -367,13 +364,16 @@ static int mlx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
struct mlx5_timer *timer = &clock->timer;
struct mlx5_core_dev *mdev;
unsigned long flags;
- int err;
mdev = container_of(clock, struct mlx5_core_dev, clock);
- err = mlx5_ptp_adjtime_real_time(mdev, delta);
- if (err)
- return err;
+ if (mlx5_modify_mtutc_allowed(mdev)) {
+ int err = mlx5_ptp_adjtime_real_time(mdev, delta);
+
+ if (err)
+ return err;
+ }
+
write_seqlock_irqsave(&clock->lock, flags);
timecounter_adjtime(&timer->tc, delta);
mlx5_update_clock_info_page(mdev);
@@ -396,15 +396,14 @@ static int mlx5_ptp_freq_adj_real_time(struct mlx5_core_dev *mdev, long scaled_p
{
u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {};
- if (!mlx5_modify_mtutc_allowed(mdev))
- return 0;
-
MLX5_SET(mtutc_reg, in, operation, MLX5_MTUTC_OPERATION_ADJUST_FREQ_UTC);
- if (MLX5_CAP_MCAM_FEATURE(mdev, mtutc_freq_adj_units)) {
+ if (MLX5_CAP_MCAM_FEATURE(mdev, mtutc_freq_adj_units) &&
+ scaled_ppm <= S32_MAX && scaled_ppm >= S32_MIN) {
+ /* HW scaled_ppm support on mlx5 devices only supports a 32-bit value */
MLX5_SET(mtutc_reg, in, freq_adj_units,
MLX5_MTUTC_FREQ_ADJ_UNITS_SCALED_PPM);
- MLX5_SET(mtutc_reg, in, freq_adjustment, scaled_ppm);
+ MLX5_SET(mtutc_reg, in, freq_adjustment, (s32)scaled_ppm);
} else {
MLX5_SET(mtutc_reg, in, freq_adj_units, MLX5_MTUTC_FREQ_ADJ_UNITS_PPB);
MLX5_SET(mtutc_reg, in, freq_adjustment, scaled_ppm_to_ppb(scaled_ppm));
@@ -420,13 +419,15 @@ static int mlx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
struct mlx5_core_dev *mdev;
unsigned long flags;
u32 mult;
- int err;
mdev = container_of(clock, struct mlx5_core_dev, clock);
- err = mlx5_ptp_freq_adj_real_time(mdev, scaled_ppm);
- if (err)
- return err;
+ if (mlx5_modify_mtutc_allowed(mdev)) {
+ int err = mlx5_ptp_freq_adj_real_time(mdev, scaled_ppm);
+
+ if (err)
+ return err;
+ }
mult = (u32)adjust_by_scaled_ppm(timer->nominal_c_mult, scaled_ppm);
@@ -1004,14 +1005,38 @@ static void mlx5_init_clock_info(struct mlx5_core_dev *mdev)
info->frac = timer->tc.frac;
}
+static void mlx5_init_timer_max_freq_adjustment(struct mlx5_core_dev *mdev)
+{
+ struct mlx5_clock *clock = &mdev->clock;
+ u32 out[MLX5_ST_SZ_DW(mtutc_reg)] = {};
+ u32 in[MLX5_ST_SZ_DW(mtutc_reg)] = {};
+ u8 log_max_freq_adjustment = 0;
+ int err;
+
+ err = mlx5_core_access_reg(mdev, in, sizeof(in), out, sizeof(out),
+ MLX5_REG_MTUTC, 0, 0);
+ if (!err)
+ log_max_freq_adjustment =
+ MLX5_GET(mtutc_reg, out, log_max_freq_adjustment);
+
+ if (log_max_freq_adjustment)
+ clock->ptp_info.max_adj =
+ min(S32_MAX, 1 << log_max_freq_adjustment);
+}
+
static void mlx5_init_timer_clock(struct mlx5_core_dev *mdev)
{
struct mlx5_clock *clock = &mdev->clock;
+ /* Configure the PHC */
+ clock->ptp_info = mlx5_ptp_clock_info;
+
+ if (MLX5_CAP_MCAM_REG(mdev, mtutc))
+ mlx5_init_timer_max_freq_adjustment(mdev);
+
mlx5_timecounter_init(mdev);
mlx5_init_clock_info(mdev);
mlx5_init_overflow_period(clock);
- clock->ptp_info = mlx5_ptp_clock_info;
if (mlx5_real_time_mode(mdev)) {
struct timespec64 ts;
@@ -1042,11 +1067,10 @@ void mlx5_init_clock(struct mlx5_core_dev *mdev)
}
seqlock_init(&clock->lock);
- mlx5_init_timer_clock(mdev);
INIT_WORK(&clock->pps_info.out_work, mlx5_pps_out);
- /* Configure the PHC */
- clock->ptp_info = mlx5_ptp_clock_info;
+ /* Initialize the device clock */
+ mlx5_init_timer_clock(mdev);
/* Initialize 1PPS data structures */
mlx5_init_pps(mdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
index e8e50563e956..e7d59cfa8708 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.c
@@ -256,6 +256,13 @@ void mlx5_devcom_unregister_component(struct mlx5_devcom_comp_dev *devcom)
devcom_free_comp_dev(devcom);
}
+int mlx5_devcom_comp_get_size(struct mlx5_devcom_comp_dev *devcom)
+{
+ struct mlx5_devcom_comp *comp = devcom->comp;
+
+ return kref_read(&comp->ref);
+}
+
int mlx5_devcom_send_event(struct mlx5_devcom_comp_dev *devcom,
int event, int rollback_event,
void *event_data)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
index fc23bbef87b4..ec32b686f586 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/devcom.h
@@ -31,6 +31,7 @@ void mlx5_devcom_unregister_component(struct mlx5_devcom_comp_dev *devcom);
int mlx5_devcom_send_event(struct mlx5_devcom_comp_dev *devcom,
int event, int rollback_event,
void *event_data);
+int mlx5_devcom_comp_get_size(struct mlx5_devcom_comp_dev *devcom);
void mlx5_devcom_comp_set_ready(struct mlx5_devcom_comp_dev *devcom, bool ready);
bool mlx5_devcom_comp_is_ready(struct mlx5_devcom_comp_dev *devcom);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
index 9482e51ac82a..7c5516b0a844 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
@@ -13,11 +13,13 @@ struct mlx5_dm {
unsigned long *steering_sw_icm_alloc_blocks;
unsigned long *header_modify_sw_icm_alloc_blocks;
unsigned long *header_modify_pattern_sw_icm_alloc_blocks;
+ unsigned long *header_encap_sw_icm_alloc_blocks;
};
struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
{
u64 header_modify_pattern_icm_blocks = 0;
+ u64 header_sw_encap_icm_blocks = 0;
u64 header_modify_icm_blocks = 0;
u64 steering_icm_blocks = 0;
struct mlx5_dm *dm;
@@ -54,6 +56,17 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
goto err_modify_hdr;
}
+ if (MLX5_CAP_DEV_MEM(dev, log_indirect_encap_sw_icm_size)) {
+ header_sw_encap_icm_blocks =
+ BIT(MLX5_CAP_DEV_MEM(dev, log_indirect_encap_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
+
+ dm->header_encap_sw_icm_alloc_blocks =
+ bitmap_zalloc(header_sw_encap_icm_blocks, GFP_KERNEL);
+ if (!dm->header_encap_sw_icm_alloc_blocks)
+ goto err_pattern;
+ }
+
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);
@@ -66,11 +79,14 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
dm->header_modify_pattern_sw_icm_alloc_blocks =
bitmap_zalloc(header_modify_pattern_icm_blocks, GFP_KERNEL);
if (!dm->header_modify_pattern_sw_icm_alloc_blocks)
- goto err_pattern;
+ goto err_sw_encap;
}
return dm;
+err_sw_encap:
+ bitmap_free(dm->header_encap_sw_icm_alloc_blocks);
+
err_pattern:
bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
@@ -105,6 +121,14 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
}
+ if (dm->header_encap_sw_icm_alloc_blocks) {
+ WARN_ON(!bitmap_empty(dm->header_encap_sw_icm_alloc_blocks,
+ BIT(MLX5_CAP_DEV_MEM(dev,
+ log_indirect_encap_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
+ bitmap_free(dm->header_encap_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,
@@ -164,6 +188,13 @@ int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
log_header_modify_pattern_sw_icm_size);
block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
break;
+ case MLX5_SW_ICM_TYPE_SW_ENCAP:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
+ indirect_encap_sw_icm_start_address);
+ log_icm_size = MLX5_CAP_DEV_MEM(dev,
+ log_indirect_encap_sw_icm_size);
+ block_map = dm->header_encap_sw_icm_alloc_blocks;
+ break;
default:
return -EINVAL;
}
@@ -242,6 +273,11 @@ int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type
header_modify_pattern_sw_icm_start_address);
block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
break;
+ case MLX5_SW_ICM_TYPE_SW_ENCAP:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
+ indirect_encap_sw_icm_start_address);
+ block_map = dm->header_encap_sw_icm_alloc_blocks;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index a17152c1cbb2..bccf6e53556c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -219,7 +219,6 @@ static void mlx5_set_driver_version(struct mlx5_core_dev *dev)
int driver_ver_sz = MLX5_FLD_SZ_BYTES(set_driver_version_in,
driver_version);
u8 in[MLX5_ST_SZ_BYTES(set_driver_version_in)] = {};
- int remaining_size = driver_ver_sz;
char *string;
if (!MLX5_CAP_GEN(dev, driver_version))
@@ -227,22 +226,9 @@ static void mlx5_set_driver_version(struct mlx5_core_dev *dev)
string = MLX5_ADDR_OF(set_driver_version_in, in, driver_version);
- strncpy(string, "Linux", remaining_size);
-
- remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
- strncat(string, ",", remaining_size);
-
- remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
- strncat(string, KBUILD_MODNAME, remaining_size);
-
- remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
- strncat(string, ",", remaining_size);
-
- remaining_size = max_t(int, 0, driver_ver_sz - strlen(string));
-
- snprintf(string + strlen(string), remaining_size, "%u.%u.%u",
- LINUX_VERSION_MAJOR, LINUX_VERSION_PATCHLEVEL,
- LINUX_VERSION_SUBLEVEL);
+ snprintf(string, driver_ver_sz, "Linux,%s,%u.%u.%u",
+ KBUILD_MODNAME, LINUX_VERSION_MAJOR,
+ LINUX_VERSION_PATCHLEVEL, LINUX_VERSION_SUBLEVEL);
/*Send the command*/
MLX5_SET(set_driver_version_in, in, opcode,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 6b14e347d914..a79b7959361b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -243,6 +243,7 @@ int mlx5_query_mcam_reg(struct mlx5_core_dev *dev, u32 *mcap, u8 feature_group,
u8 access_reg_group);
int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
u8 feature_group, u8 access_reg_group);
+int mlx5_query_mpir_reg(struct mlx5_core_dev *dev, u32 *mpir);
void mlx5_lag_add_netdev(struct mlx5_core_dev *dev, struct net_device *netdev);
void mlx5_lag_remove_netdev(struct mlx5_core_dev *dev, struct net_device *netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c
index 7d8c732818f2..7fba1c46e2ac 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/port.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c
@@ -1206,3 +1206,13 @@ int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed)
*speed = max_speed;
return 0;
}
+
+int mlx5_query_mpir_reg(struct mlx5_core_dev *dev, u32 *mpir)
+{
+ u32 in[MLX5_ST_SZ_DW(mpir_reg)] = {};
+ int sz = MLX5_ST_SZ_BYTES(mpir_reg);
+
+ MLX5_SET(mpir_reg, in, local_port, 1);
+
+ return mlx5_core_access_reg(dev, in, sz, mpir, sz, MLX5_REG_MPIR, 0, 0);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
index e3ec559369fa..2ebb61ef3ea9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
@@ -788,6 +788,7 @@ int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher,
switch (action_type) {
case DR_ACTION_TYP_DROP:
attr.final_icm_addr = nic_dmn->drop_icm_addr;
+ attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48;
break;
case DR_ACTION_TYP_FT:
dest_action = action;
@@ -873,11 +874,17 @@ int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher,
action->sampler->tx_icm_addr;
break;
case DR_ACTION_TYP_VPORT:
- attr.hit_gvmi = action->vport->caps->vhca_gvmi;
- dest_action = action;
- attr.final_icm_addr = rx_rule ?
- action->vport->caps->icm_address_rx :
- action->vport->caps->icm_address_tx;
+ if (unlikely(rx_rule && action->vport->caps->num == MLX5_VPORT_UPLINK)) {
+ /* can't go to uplink on RX rule - dropping instead */
+ attr.final_icm_addr = nic_dmn->drop_icm_addr;
+ attr.hit_gvmi = nic_dmn->drop_icm_addr >> 48;
+ } else {
+ attr.hit_gvmi = action->vport->caps->vhca_gvmi;
+ dest_action = action;
+ attr.final_icm_addr = rx_rule ?
+ action->vport->caps->icm_address_rx :
+ action->vport->caps->icm_address_tx;
+ }
break;
case DR_ACTION_TYP_POP_VLAN:
if (!rx_rule && !(dmn->ste_ctx->actions_caps &
@@ -1170,7 +1177,6 @@ mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
bool ignore_flow_level,
u32 flow_source)
{
- struct mlx5dr_cmd_flow_destination_hw_info tmp_hw_dest;
struct mlx5dr_cmd_flow_destination_hw_info *hw_dests;
struct mlx5dr_action **ref_actions;
struct mlx5dr_action *action;
@@ -1249,11 +1255,8 @@ mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
* one that done in the TX.
* So, if one of the ft target is wire, put it at the end of the dest list.
*/
- if (is_ft_wire && num_dst_ft > 1) {
- tmp_hw_dest = hw_dests[last_dest];
- hw_dests[last_dest] = hw_dests[num_of_dests - 1];
- hw_dests[num_of_dests - 1] = tmp_hw_dest;
- }
+ if (is_ft_wire && num_dst_ft > 1)
+ swap(hw_dests[last_dest], hw_dests[num_of_dests - 1]);
action = dr_action_create_generic(DR_ACTION_TYP_FT);
if (!action)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
index 21753f327868..1005bb6935b6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
@@ -440,6 +440,27 @@ out:
}
EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_system_image_guid);
+int mlx5_query_nic_vport_sd_group(struct mlx5_core_dev *mdev, u8 *sd_group)
+{
+ int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
+ u32 *out;
+ int err;
+
+ out = kvzalloc(outlen, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ err = mlx5_query_nic_vport_context(mdev, 0, out);
+ if (err)
+ goto out;
+
+ *sd_group = MLX5_GET(query_nic_vport_context_out, out,
+ nic_vport_context.sd_group);
+out:
+ kvfree(out);
+ return err;
+}
+
int mlx5_query_nic_vport_node_guid(struct mlx5_core_dev *mdev, u64 *node_guid)
{
u32 *out;
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
index 954ba0826c61..3d09fa54598f 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
@@ -130,9 +130,15 @@ static int mlxbf_gige_open(struct net_device *netdev)
{
struct mlxbf_gige *priv = netdev_priv(netdev);
struct phy_device *phydev = netdev->phydev;
+ u64 control;
u64 int_en;
int err;
+ /* Perform general init of GigE block */
+ control = readq(priv->base + MLXBF_GIGE_CONTROL);
+ control |= MLXBF_GIGE_CONTROL_PORT_EN;
+ writeq(control, priv->base + MLXBF_GIGE_CONTROL);
+
err = mlxbf_gige_request_irqs(priv);
if (err)
return err;
@@ -147,14 +153,14 @@ static int mlxbf_gige_open(struct net_device *netdev)
*/
priv->valid_polarity = 0;
- err = mlxbf_gige_rx_init(priv);
+ phy_start(phydev);
+
+ err = mlxbf_gige_tx_init(priv);
if (err)
goto free_irqs;
- err = mlxbf_gige_tx_init(priv);
+ err = mlxbf_gige_rx_init(priv);
if (err)
- goto rx_deinit;
-
- phy_start(phydev);
+ goto tx_deinit;
netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll);
napi_enable(&priv->napi);
@@ -176,8 +182,8 @@ static int mlxbf_gige_open(struct net_device *netdev)
return 0;
-rx_deinit:
- mlxbf_gige_rx_deinit(priv);
+tx_deinit:
+ mlxbf_gige_tx_deinit(priv);
free_irqs:
mlxbf_gige_free_irqs(priv);
@@ -365,7 +371,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
void __iomem *plu_base;
void __iomem *base;
int addr, phy_irq;
- u64 control;
int err;
base = devm_platform_ioremap_resource(pdev, MLXBF_GIGE_RES_MAC);
@@ -380,11 +385,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
if (IS_ERR(plu_base))
return PTR_ERR(plu_base);
- /* Perform general init of GigE block */
- control = readq(base + MLXBF_GIGE_CONTROL);
- control |= MLXBF_GIGE_CONTROL_PORT_EN;
- writeq(control, base + MLXBF_GIGE_CONTROL);
-
netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv));
if (!netdev)
return -ENOMEM;
diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
index 227d01cace3f..699984358493 100644
--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
+++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
@@ -142,6 +142,9 @@ int mlxbf_gige_rx_init(struct mlxbf_gige *priv)
writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN,
priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS);
+ writeq(ilog2(priv->rx_q_entries),
+ priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2);
+
/* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to
* indicate readiness to receive interrupts
*/
@@ -154,9 +157,6 @@ int mlxbf_gige_rx_init(struct mlxbf_gige *priv)
data |= MLXBF_GIGE_RX_DMA_EN;
writeq(data, priv->base + MLXBF_GIGE_RX_DMA);
- writeq(ilog2(priv->rx_q_entries),
- priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2);
-
return 0;
free_wqe_and_skb:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/cmd.h b/drivers/net/ethernet/mellanox/mlxsw/cmd.h
index e827c78be114..e3271c845ee6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/cmd.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/cmd.h
@@ -282,6 +282,12 @@ MLXSW_ITEM32(cmd_mbox, query_fw, fw_day, 0x14, 0, 8);
*/
MLXSW_ITEM32(cmd_mbox, query_fw, lag_mode_support, 0x18, 1, 1);
+/* cmd_mbox_query_fw_cff_support
+ * 0: CONFIG_PROFILE.flood_mode = 5 (CFF) is not supported by FW
+ * 1: CONFIG_PROFILE.flood_mode = 5 (CFF) is supported by FW
+ */
+MLXSW_ITEM32(cmd_mbox, query_fw, cff_support, 0x18, 2, 1);
+
/* cmd_mbox_query_fw_clr_int_base_offset
* Clear Interrupt register's offset from clr_int_bar register
* in PCI address space.
@@ -779,6 +785,11 @@ enum mlxsw_cmd_mbox_config_profile_flood_mode {
* used.
*/
MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED = 4,
+ /* CFF - Compressed FID Flood (CFF) mode.
+ * Reserved when legacy bridge model is used.
+ * Supported only by Spectrum-2+.
+ */
+ MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF = 5,
};
/* cmd_mbox_config_profile_flood_mode
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index f23421f038f3..e4d7739bd7c8 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -211,6 +211,13 @@ mlxsw_core_lag_mode(struct mlxsw_core *mlxsw_core)
}
EXPORT_SYMBOL(mlxsw_core_lag_mode);
+enum mlxsw_cmd_mbox_config_profile_flood_mode
+mlxsw_core_flood_mode(struct mlxsw_core *mlxsw_core)
+{
+ return mlxsw_core->bus->flood_mode(mlxsw_core->bus_priv);
+}
+EXPORT_SYMBOL(mlxsw_core_flood_mode);
+
void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core)
{
return mlxsw_core->driver_priv;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index 764d14bd5bc0..6d11225594dd 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -38,6 +38,8 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core);
int mlxsw_core_max_lag(struct mlxsw_core *mlxsw_core, u16 *p_max_lag);
enum mlxsw_cmd_mbox_config_profile_lag_mode
mlxsw_core_lag_mode(struct mlxsw_core *mlxsw_core);
+enum mlxsw_cmd_mbox_config_profile_flood_mode
+mlxsw_core_flood_mode(struct mlxsw_core *mlxsw_core);
void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core);
@@ -322,7 +324,12 @@ struct mlxsw_config_profile {
u16 max_regions;
u8 max_flood_tables;
u8 max_vid_flood_tables;
+
+ /* Flood mode to use if used_flood_mode. If flood_mode_prefer_cff,
+ * the backup flood mode (if any) when CFF unsupported.
+ */
u8 flood_mode;
+
u8 max_fid_offset_flood_tables;
u16 fid_offset_flood_table_size;
u8 max_fid_flood_tables;
@@ -338,6 +345,7 @@ struct mlxsw_config_profile {
u8 kvd_hash_double_parts;
u8 cqe_time_stamp_type;
bool lag_mode_prefer_sw;
+ bool flood_mode_prefer_cff;
struct mlxsw_swid_config swid_config[MLXSW_CONFIG_PROFILE_SWID_COUNT];
};
@@ -489,6 +497,7 @@ struct mlxsw_bus {
u32 (*read_utc_sec)(void *bus_priv);
u32 (*read_utc_nsec)(void *bus_priv);
enum mlxsw_cmd_mbox_config_profile_lag_mode (*lag_mode)(void *bus_priv);
+ enum mlxsw_cmd_mbox_config_profile_flood_mode (*flood_mode)(void *priv);
u8 features;
};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index e4b25e187467..af99bf17eb36 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -106,7 +106,9 @@ struct mlxsw_pci {
u64 utc_sec_offset;
u64 utc_nsec_offset;
bool lag_mode_support;
+ bool cff_support;
enum mlxsw_cmd_mbox_config_profile_lag_mode lag_mode;
+ enum mlxsw_cmd_mbox_config_profile_flood_mode flood_mode;
struct mlxsw_pci_queue_type_group queues[MLXSW_PCI_QUEUE_TYPE_COUNT];
u32 doorbell_offset;
struct mlxsw_core *core;
@@ -130,6 +132,7 @@ struct mlxsw_pci {
const struct pci_device_id *id;
enum mlxsw_pci_cqe_v max_cqe_ver; /* Maximal supported CQE version */
u8 num_sdq_cqs; /* Number of CQs used for SDQs */
+ bool skip_reset;
};
static void mlxsw_pci_queue_tasklet_schedule(struct mlxsw_pci_queue *q)
@@ -1245,11 +1248,22 @@ static int mlxsw_pci_config_profile(struct mlxsw_pci *mlxsw_pci, char *mbox,
mlxsw_cmd_mbox_config_profile_fid_flood_table_size_set(
mbox, profile->fid_flood_table_size);
}
- if (profile->used_flood_mode) {
+ if (profile->flood_mode_prefer_cff && mlxsw_pci->cff_support) {
+ enum mlxsw_cmd_mbox_config_profile_flood_mode flood_mode =
+ MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF;
+
+ mlxsw_cmd_mbox_config_profile_set_flood_mode_set(mbox, 1);
+ mlxsw_cmd_mbox_config_profile_flood_mode_set(mbox, flood_mode);
+ mlxsw_pci->flood_mode = flood_mode;
+ } else if (profile->used_flood_mode) {
mlxsw_cmd_mbox_config_profile_set_flood_mode_set(
mbox, 1);
mlxsw_cmd_mbox_config_profile_flood_mode_set(
mbox, profile->flood_mode);
+ mlxsw_pci->flood_mode = profile->flood_mode;
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
}
if (profile->used_max_ib_mc) {
mlxsw_cmd_mbox_config_profile_set_max_ib_mc_set(
@@ -1476,11 +1490,47 @@ static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci,
return -EBUSY;
}
-static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
- const struct pci_device_id *id)
+static int mlxsw_pci_reset_at_pci_disable(struct mlxsw_pci *mlxsw_pci)
{
struct pci_dev *pdev = mlxsw_pci->pdev;
char mrsr_pl[MLXSW_REG_MRSR_LEN];
+ int err;
+
+ mlxsw_reg_mrsr_pack(mrsr_pl,
+ MLXSW_REG_MRSR_COMMAND_RESET_AT_PCI_DISABLE);
+ err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
+ if (err)
+ return err;
+
+ device_lock_assert(&pdev->dev);
+
+ pci_cfg_access_lock(pdev);
+ pci_save_state(pdev);
+
+ err = __pci_reset_function_locked(pdev);
+ if (err)
+ pci_err(pdev, "PCI function reset failed with %d\n", err);
+
+ pci_restore_state(pdev);
+ pci_cfg_access_unlock(pdev);
+
+ return err;
+}
+
+static int mlxsw_pci_reset_sw(struct mlxsw_pci *mlxsw_pci)
+{
+ char mrsr_pl[MLXSW_REG_MRSR_LEN];
+
+ mlxsw_reg_mrsr_pack(mrsr_pl, MLXSW_REG_MRSR_COMMAND_SOFTWARE_RESET);
+ return mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
+}
+
+static int
+mlxsw_pci_reset(struct mlxsw_pci *mlxsw_pci, const struct pci_device_id *id)
+{
+ struct pci_dev *pdev = mlxsw_pci->pdev;
+ char mcam_pl[MLXSW_REG_MCAM_LEN];
+ bool pci_reset_supported;
u32 sys_status;
int err;
@@ -1491,8 +1541,26 @@ static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
return err;
}
- mlxsw_reg_mrsr_pack(mrsr_pl);
- err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
+ /* PCI core already issued a PCI reset, do not issue another reset. */
+ if (mlxsw_pci->skip_reset)
+ return 0;
+
+ mlxsw_reg_mcam_pack(mcam_pl,
+ MLXSW_REG_MCAM_FEATURE_GROUP_ENHANCED_FEATURES);
+ err = mlxsw_reg_query(mlxsw_pci->core, MLXSW_REG(mcam), mcam_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mcam_unpack(mcam_pl, MLXSW_REG_MCAM_PCI_RESET,
+ &pci_reset_supported);
+
+ if (pci_reset_supported) {
+ pci_dbg(pdev, "Starting PCI reset flow\n");
+ err = mlxsw_pci_reset_at_pci_disable(mlxsw_pci);
+ } else {
+ pci_dbg(pdev, "Starting software reset flow\n");
+ err = mlxsw_pci_reset_sw(mlxsw_pci);
+ }
if (err)
return err;
@@ -1537,9 +1605,9 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
if (!mbox)
return -ENOMEM;
- err = mlxsw_pci_sw_reset(mlxsw_pci, mlxsw_pci->id);
+ err = mlxsw_pci_reset(mlxsw_pci, mlxsw_pci->id);
if (err)
- goto err_sw_reset;
+ goto err_reset;
err = mlxsw_pci_alloc_irq_vectors(mlxsw_pci);
if (err < 0) {
@@ -1601,6 +1669,9 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core,
mlxsw_pci->lag_mode_support =
mlxsw_cmd_mbox_query_fw_lag_mode_support_get(mbox);
+ mlxsw_pci->cff_support =
+ mlxsw_cmd_mbox_query_fw_cff_support_get(mbox);
+
num_pages = mlxsw_cmd_mbox_query_fw_fw_pages_get(mbox);
err = mlxsw_pci_fw_area_init(mlxsw_pci, mbox, num_pages);
if (err)
@@ -1672,7 +1743,7 @@ err_iface_rev:
err_query_fw:
mlxsw_pci_free_irq_vectors(mlxsw_pci);
err_alloc_irq:
-err_sw_reset:
+err_reset:
mbox_put:
mlxsw_cmd_mbox_free(mbox);
return err;
@@ -1917,6 +1988,14 @@ mlxsw_pci_lag_mode(void *bus_priv)
return mlxsw_pci->lag_mode;
}
+static enum mlxsw_cmd_mbox_config_profile_flood_mode
+mlxsw_pci_flood_mode(void *bus_priv)
+{
+ struct mlxsw_pci *mlxsw_pci = bus_priv;
+
+ return mlxsw_pci->flood_mode;
+}
+
static const struct mlxsw_bus mlxsw_pci_bus = {
.kind = "pci",
.init = mlxsw_pci_init,
@@ -1929,6 +2008,7 @@ static const struct mlxsw_bus mlxsw_pci_bus = {
.read_utc_sec = mlxsw_pci_read_utc_sec,
.read_utc_nsec = mlxsw_pci_read_utc_nsec,
.lag_mode = mlxsw_pci_lag_mode,
+ .flood_mode = mlxsw_pci_flood_mode,
.features = MLXSW_BUS_F_TXRX | MLXSW_BUS_F_RESET,
};
@@ -2059,11 +2139,34 @@ static void mlxsw_pci_remove(struct pci_dev *pdev)
kfree(mlxsw_pci);
}
+static void mlxsw_pci_reset_prepare(struct pci_dev *pdev)
+{
+ struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);
+
+ mlxsw_core_bus_device_unregister(mlxsw_pci->core, false);
+}
+
+static void mlxsw_pci_reset_done(struct pci_dev *pdev)
+{
+ struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);
+
+ mlxsw_pci->skip_reset = true;
+ mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, &mlxsw_pci_bus,
+ mlxsw_pci, false, NULL, NULL);
+ mlxsw_pci->skip_reset = false;
+}
+
+static const struct pci_error_handlers mlxsw_pci_err_handler = {
+ .reset_prepare = mlxsw_pci_reset_prepare,
+ .reset_done = mlxsw_pci_reset_done,
+};
+
int mlxsw_pci_driver_register(struct pci_driver *pci_driver)
{
pci_driver->probe = mlxsw_pci_probe;
pci_driver->remove = mlxsw_pci_remove;
pci_driver->shutdown = mlxsw_pci_remove;
+ pci_driver->err_handler = &mlxsw_pci_err_handler;
return pci_register_driver(pci_driver);
}
EXPORT_SYMBOL(mlxsw_pci_driver_register);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 25b294fdeb3d..8892654c685f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -1024,6 +1024,8 @@ static inline void mlxsw_reg_spaft_pack(char *payload, u16 local_port,
* ------------------------------------------
* The following register controls the association of flooding tables and MIDs
* to packet types used for flooding.
+ *
+ * Reserved when CONFIG_PROFILE.flood_mode = CFF.
*/
#define MLXSW_REG_SFGC_ID 0x2011
#define MLXSW_REG_SFGC_LEN 0x14
@@ -1862,6 +1864,7 @@ MLXSW_ITEM32(reg, sfmr, fid, 0x00, 0, 16);
* Access: RW
*
* Note: Reserved when legacy bridge model is used.
+ * Reserved when CONFIG_PROFILE.flood_mode = CFF.
*/
MLXSW_ITEM32(reg, sfmr, flood_rsp, 0x08, 31, 1);
@@ -1872,6 +1875,7 @@ MLXSW_ITEM32(reg, sfmr, flood_rsp, 0x08, 31, 1);
* Access: RW
*
* Note: Reserved when legacy bridge model is used and when flood_rsp=1.
+ * Reserved when CONFIG_PROFILE.flood_mode = CFF
*/
MLXSW_ITEM32(reg, sfmr, flood_bridge_type, 0x08, 28, 1);
@@ -1880,6 +1884,8 @@ MLXSW_ITEM32(reg, sfmr, flood_bridge_type, 0x08, 28, 1);
* Used to point into the flooding table selected by SFGC register if
* the table is of type FID-Offset. Otherwise, this field is reserved.
* Access: RW
+ *
+ * Note: Reserved when CONFIG_PROFILE.flood_mode = CFF
*/
MLXSW_ITEM32(reg, sfmr, fid_offset, 0x08, 0, 16);
@@ -1938,6 +1944,35 @@ MLXSW_ITEM32(reg, sfmr, irif_v, 0x14, 24, 1);
*/
MLXSW_ITEM32(reg, sfmr, irif, 0x14, 0, 16);
+/* reg_sfmr_cff_mid_base
+ * Pointer to PGT table.
+ * Range: 0..(cap_max_pgt-1)
+ * Access: RW
+ *
+ * Note: Reserved when SwitchX/-2 and Spectrum-1.
+ * Supported when CONFIG_PROFILE.flood_mode = CFF.
+ */
+MLXSW_ITEM32(reg, sfmr, cff_mid_base, 0x20, 0, 16);
+
+/* reg_sfmr_nve_flood_prf_id
+ * FID flooding profile_id for NVE Encap
+ * Range 0..(max_cap_nve_flood_prf-1)
+ * Access: RW
+ *
+ * Note: Reserved when SwitchX/-2 and Spectrum-1
+ */
+MLXSW_ITEM32(reg, sfmr, nve_flood_prf_id, 0x24, 8, 2);
+
+/* reg_sfmr_cff_prf_id
+ * Compressed Fid Flooding profile_id
+ * Range 0..(max_cap_nve_flood_prf-1)
+ * Access: RW
+ *
+ * Note: Reserved when SwitchX/-2 and Spectrum-1
+ * Supported only when CONFIG_PROFLE.flood_mode = CFF.
+ */
+MLXSW_ITEM32(reg, sfmr, cff_prf_id, 0x24, 0, 2);
+
/* reg_sfmr_smpe_valid
* SMPE is valid.
* Access: RW
@@ -1959,18 +1994,11 @@ 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, 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);
mlxsw_reg_sfmr_fid_set(payload, fid);
- 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);
}
@@ -2168,6 +2196,50 @@ static inline void mlxsw_reg_spvc_pack(char *payload, u16 local_port, bool et1,
mlxsw_reg_spvc_et0_set(payload, et0);
}
+/* SFFP - Switch FID Flooding Profiles Register
+ * --------------------------------------------
+ * The SFFP register populates the fid flooding profile tables used for the NVE
+ * flooding and Compressed-FID Flooding (CFF).
+ *
+ * Reserved on Spectrum-1.
+ */
+#define MLXSW_REG_SFFP_ID 0x2029
+#define MLXSW_REG_SFFP_LEN 0x0C
+
+MLXSW_REG_DEFINE(sffp, MLXSW_REG_SFFP_ID, MLXSW_REG_SFFP_LEN);
+
+/* reg_sffp_profile_id
+ * Profile ID a.k.a. SFMR.nve_flood_prf_id or SFMR.cff_prf_id
+ * Range 0..max_cap_nve_flood_prf-1
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, sffp, profile_id, 0x00, 16, 2);
+
+/* reg_sffp_type
+ * The traffic type to reach the flooding table.
+ * Same as SFGC.type
+ * Access: Index
+ */
+MLXSW_ITEM32(reg, sffp, type, 0x00, 0, 4);
+
+/* reg_sffp_flood_offset
+ * Flood offset. Offset to add to SFMR.cff_mid_base to get the final PGT address
+ * for FID flood; or offset to add to SFMR.nve_tunnel_flood_ptr to get KVD
+ * pointer for NVE underlay.
+ * Access: RW
+ */
+MLXSW_ITEM32(reg, sffp, flood_offset, 0x04, 0, 3);
+
+static inline void mlxsw_reg_sffp_pack(char *payload, u8 profile_id,
+ enum mlxsw_reg_sfgc_type type,
+ u8 flood_offset)
+{
+ MLXSW_REG_ZERO(sffp, payload);
+ mlxsw_reg_sffp_profile_id_set(payload, profile_id);
+ mlxsw_reg_sffp_type_set(payload, type);
+ mlxsw_reg_sffp_flood_offset_set(payload, flood_offset);
+}
+
/* SPEVET - Switch Port Egress VLAN EtherType
* ------------------------------------------
* The switch port egress VLAN EtherType configures which EtherType to push at
@@ -10122,6 +10194,15 @@ mlxsw_reg_mgir_unpack(char *payload, u32 *hw_rev, char *fw_info_psid,
MLXSW_REG_DEFINE(mrsr, MLXSW_REG_MRSR_ID, MLXSW_REG_MRSR_LEN);
+enum mlxsw_reg_mrsr_command {
+ /* Switch soft reset, does not reset PCI firmware. */
+ MLXSW_REG_MRSR_COMMAND_SOFTWARE_RESET = 1,
+ /* Reset will be done when PCI link will be disabled.
+ * This command will reset PCI firmware also.
+ */
+ MLXSW_REG_MRSR_COMMAND_RESET_AT_PCI_DISABLE = 6,
+};
+
/* reg_mrsr_command
* Reset/shutdown command
* 0 - do nothing
@@ -10130,10 +10211,11 @@ MLXSW_REG_DEFINE(mrsr, MLXSW_REG_MRSR_ID, MLXSW_REG_MRSR_LEN);
*/
MLXSW_ITEM32(reg, mrsr, command, 0x00, 0, 4);
-static inline void mlxsw_reg_mrsr_pack(char *payload)
+static inline void mlxsw_reg_mrsr_pack(char *payload,
+ enum mlxsw_reg_mrsr_command command)
{
MLXSW_REG_ZERO(mrsr, payload);
- mlxsw_reg_mrsr_command_set(payload, 1);
+ mlxsw_reg_mrsr_command_set(payload, command);
}
/* MLCR - Management LED Control Register
@@ -10584,6 +10666,8 @@ MLXSW_ITEM32(reg, mcam, feature_group, 0x00, 16, 8);
enum mlxsw_reg_mcam_mng_feature_cap_mask_bits {
/* If set, MCIA supports 128 bytes payloads. Otherwise, 48 bytes. */
MLXSW_REG_MCAM_MCIA_128B = 34,
+ /* If set, MRSR.command=6 is supported. */
+ MLXSW_REG_MCAM_PCI_RESET = 48,
};
#define MLXSW_REG_BYTES_PER_DWORD 0x4
@@ -12934,6 +13018,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = {
MLXSW_REG(spvmlr),
MLXSW_REG(spfsr),
MLXSW_REG(spvc),
+ MLXSW_REG(sffp),
MLXSW_REG(spevet),
MLXSW_REG(smpe),
MLXSW_REG(smid2),
diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h
index 89dd2777ec4d..9d7977ebe186 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/resources.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h
@@ -27,6 +27,7 @@ enum mlxsw_res_id {
MLXSW_RES_ID_FID,
MLXSW_RES_ID_MAX_LAG,
MLXSW_RES_ID_MAX_LAG_MEMBERS,
+ MLXSW_RES_ID_MAX_NVE_FLOOD_PRF,
MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER,
MLXSW_RES_ID_CELL_SIZE,
MLXSW_RES_ID_MAX_HEADROOM_SIZE,
@@ -88,6 +89,7 @@ static u16 mlxsw_res_ids[] = {
[MLXSW_RES_ID_FID] = 0x2512,
[MLXSW_RES_ID_MAX_LAG] = 0x2520,
[MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521,
+ [MLXSW_RES_ID_MAX_NVE_FLOOD_PRF] = 0x2522,
[MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */
[MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */
[MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index cec72d99d9c9..5d3413636a62 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3190,10 +3190,10 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
goto err_lag_init;
}
- err = mlxsw_sp_fids_init(mlxsw_sp);
+ err = mlxsw_sp->fid_core_ops->init(mlxsw_sp);
if (err) {
dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n");
- goto err_fids_init;
+ goto err_fid_core_init;
}
err = mlxsw_sp_policers_init(mlxsw_sp);
@@ -3379,8 +3379,8 @@ err_devlink_traps_init:
err_traps_init:
mlxsw_sp_policers_fini(mlxsw_sp);
err_policers_init:
- mlxsw_sp_fids_fini(mlxsw_sp);
-err_fids_init:
+ mlxsw_sp->fid_core_ops->fini(mlxsw_sp);
+err_fid_core_init:
mlxsw_sp_lag_fini(mlxsw_sp);
err_lag_init:
mlxsw_sp_pgt_fini(mlxsw_sp);
@@ -3416,7 +3416,7 @@ 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->fid_core_ops = &mlxsw_sp1_fid_core_ops;
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP1;
mlxsw_sp->pgt_smpe_index_valid = true;
@@ -3450,7 +3450,7 @@ 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->fid_core_ops = &mlxsw_sp2_fid_core_ops;
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP2;
mlxsw_sp->pgt_smpe_index_valid = false;
@@ -3484,7 +3484,7 @@ 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->fid_core_ops = &mlxsw_sp2_fid_core_ops;
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP3;
mlxsw_sp->pgt_smpe_index_valid = false;
@@ -3518,7 +3518,7 @@ 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->fid_core_ops = &mlxsw_sp2_fid_core_ops;
mlxsw_sp->lowest_shaper_bs = MLXSW_REG_QEEC_LOWEST_SHAPER_BS_SP4;
mlxsw_sp->pgt_smpe_index_valid = false;
@@ -3552,7 +3552,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
mlxsw_sp_devlink_traps_fini(mlxsw_sp);
mlxsw_sp_traps_fini(mlxsw_sp);
mlxsw_sp_policers_fini(mlxsw_sp);
- mlxsw_sp_fids_fini(mlxsw_sp);
+ mlxsw_sp->fid_core_ops->fini(mlxsw_sp);
mlxsw_sp_lag_fini(mlxsw_sp);
mlxsw_sp_pgt_fini(mlxsw_sp);
mlxsw_sp_kvdl_fini(mlxsw_sp);
@@ -3598,6 +3598,7 @@ static const struct mlxsw_config_profile mlxsw_sp2_config_profile = {
.used_cqe_time_stamp_type = 1,
.cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC,
.lag_mode_prefer_sw = true,
+ .flood_mode_prefer_cff = true,
};
/* Reduce number of LAGs from full capacity (256) to the maximum supported LAGs
@@ -3626,6 +3627,7 @@ static const struct mlxsw_config_profile mlxsw_sp4_config_profile = {
.used_cqe_time_stamp_type = 1,
.cqe_time_stamp_type = MLXSW_CMD_MBOX_CONFIG_PROFILE_CQE_TIME_STAMP_TYPE_UTC,
.lag_mode_prefer_sw = true,
+ .flood_mode_prefer_cff = true,
};
static void
@@ -4515,6 +4517,10 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port->lagged = 1;
lag->ref_count++;
+ err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port);
+ if (err)
+ goto err_fid_port_join_lag;
+
/* Port is no longer usable as a router interface */
if (mlxsw_sp_port->default_vlan->fid)
mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port->default_vlan);
@@ -4534,6 +4540,8 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
err_replay:
mlxsw_sp_router_port_leave_lag(mlxsw_sp_port, lag_dev);
err_router_join:
+ mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port);
+err_fid_port_join_lag:
lag->ref_count--;
mlxsw_sp_port->lagged = 0;
mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id,
@@ -4569,6 +4577,8 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port,
*/
mlxsw_sp_port_lag_uppers_cleanup(mlxsw_sp_port, lag_dev);
+ mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port);
+
if (lag->ref_count == 1)
mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index c70333b460ea..a0c9775fa955 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -205,7 +205,7 @@ 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;
+ const struct mlxsw_sp_fid_core_ops *fid_core_ops;
size_t listeners_count;
u32 lowest_shaper_bs;
struct rhashtable ipv6_addr_ht;
@@ -252,6 +252,11 @@ struct mlxsw_sp_ptp_ops {
const struct mlxsw_tx_info *tx_info);
};
+struct mlxsw_sp_fid_core_ops {
+ int (*init)(struct mlxsw_sp *mlxsw_sp);
+ void (*fini)(struct mlxsw_sp *mlxsw_sp);
+};
+
static inline struct mlxsw_sp_upper *
mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
{
@@ -508,6 +513,10 @@ enum mlxsw_sp_flood_type {
MLXSW_SP_FLOOD_TYPE_UC,
MLXSW_SP_FLOOD_TYPE_BC,
MLXSW_SP_FLOOD_TYPE_MC,
+ /* For RSP FIDs in CFF mode. */
+ MLXSW_SP_FLOOD_TYPE_NOT_UC,
+ /* For NVE traffic. */
+ MLXSW_SP_FLOOD_TYPE_ANY,
};
int mlxsw_sp_port_get_stats_raw(struct net_device *dev, int grp,
@@ -753,6 +762,8 @@ union mlxsw_sp_l3addr {
};
u16 mlxsw_sp_rif_index(const struct mlxsw_sp_rif *rif);
+int mlxsw_sp_rif_subport_port(const struct mlxsw_sp_rif *rif,
+ u16 *port, bool *is_lag);
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);
@@ -1319,11 +1330,11 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid);
int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port);
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);
+int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port);
+void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port);
-extern const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[];
-extern const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[];
+extern const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops;
+extern const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops;
/* spectrum_mr.c */
enum mlxsw_sp_mr_route_prio {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
index 4c98950380d5..d231f4d2888b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
@@ -301,6 +301,7 @@ mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
unsigned long *p_index)
{
unsigned int num_rows, entry_size;
+ unsigned long index;
/* We only allow allocations of entire rows */
if (num_erps % erp_core->num_erp_banks != 0)
@@ -309,10 +310,11 @@ mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
entry_size = erp_core->erpt_entries_size[region_type];
num_rows = num_erps / erp_core->num_erp_banks;
- *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
- if (*p_index == 0)
+ index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
+ if (!index)
return -ENOBUFS;
- *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
+
+ *p_index = index - MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index d50786b0a6ce..50ea1eff02b2 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -681,13 +681,13 @@ static void
mlxsw_sp_acl_tcam_region_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_tcam_region *region)
{
+ struct mlxsw_sp_acl_tcam *tcam = mlxsw_sp_acl_to_tcam(mlxsw_sp->acl);
const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
ops->region_fini(mlxsw_sp, region->priv);
mlxsw_sp_acl_tcam_region_disable(mlxsw_sp, region);
mlxsw_sp_acl_tcam_region_free(mlxsw_sp, region);
- mlxsw_sp_acl_tcam_region_id_put(region->group->tcam,
- region->id);
+ mlxsw_sp_acl_tcam_region_id_put(tcam, region->id);
kfree(region);
}
@@ -1564,6 +1564,8 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
tcam->max_groups = max_groups;
tcam->max_group_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
ACL_MAX_GROUP_SIZE);
+ tcam->max_group_size = min_t(unsigned int, tcam->max_group_size,
+ MLXSW_REG_PAGT_ACL_MAX_NUM);
err = ops->init(mlxsw_sp, tcam->priv, tcam);
if (err)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
index e954b8cd2ee8..65562ab208b3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
@@ -11,6 +11,7 @@
#include <linux/refcount.h>
#include "spectrum.h"
+#include "spectrum_router.h"
#include "reg.h"
struct mlxsw_sp_fid_family;
@@ -71,12 +72,12 @@ 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_flood_table_type table_type;
+ enum mlxsw_flood_table_type table_type; /* For flood_mode!=CFF. */
int table_index;
};
struct mlxsw_sp_fid_ops {
- void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
+ int (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
int (*configure)(struct mlxsw_sp_fid *fid);
void (*deconfigure)(struct mlxsw_sp_fid *fid);
int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
@@ -95,6 +96,34 @@ struct mlxsw_sp_fid_ops {
const struct net_device *nve_dev);
int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
const struct mlxsw_sp_rif *rif);
+ int (*flood_table_init)(struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_flood_table *flood_table);
+ int (*pgt_size)(const struct mlxsw_sp_fid_family *fid_family,
+ u16 *p_pgt_size);
+ u16 (*fid_mid)(const struct mlxsw_sp_fid *fid,
+ const struct mlxsw_sp_flood_table *flood_table);
+ void (*fid_pack)(char *sfmr_pl, const struct mlxsw_sp_fid *fid,
+ enum mlxsw_reg_sfmr_op op);
+
+ /* These are specific to RFID families and we assume are only
+ * implemented by RFID families, if at all.
+ */
+ int (*fid_port_init)(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_port *mlxsw_sp_port);
+ void (*fid_port_fini)(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_port *mlxsw_sp_port);
+};
+
+enum mlxsw_sp_fid_flood_profile_id {
+ MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE = 1,
+ MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP,
+ MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE,
+};
+
+struct mlxsw_sp_fid_flood_profile {
+ const struct mlxsw_sp_flood_table *flood_tables;
+ int nr_flood_tables;
+ const enum mlxsw_sp_fid_flood_profile_id profile_id; /* For CFF mode. */
};
struct mlxsw_sp_fid_family {
@@ -104,12 +133,11 @@ struct mlxsw_sp_fid_family {
u16 end_index;
struct list_head fids_list;
unsigned long *fids_bitmap;
- const struct mlxsw_sp_flood_table *flood_tables;
- int nr_flood_tables;
+ const struct mlxsw_sp_fid_flood_profile *flood_profile;
enum mlxsw_sp_rif_type rif_type;
const struct mlxsw_sp_fid_ops *ops;
struct mlxsw_sp *mlxsw_sp;
- bool flood_rsp;
+ bool flood_rsp; /* For flood_mode!=CFF. */
enum mlxsw_reg_bridge_type bridge_type;
u16 pgt_base;
bool smpe_index_valid;
@@ -131,10 +159,31 @@ static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
};
+static const int mlxsw_sp_sfgc_not_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
+ [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
+ [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
+ [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
+};
+
+static const int mlxsw_sp_sfgc_any_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
+ [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
+ [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
+ [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
+ [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
+ [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
+};
+
static const int *mlxsw_sp_packet_type_sfgc_types[] = {
[MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
[MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
[MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
+ [MLXSW_SP_FLOOD_TYPE_NOT_UC] = mlxsw_sp_sfgc_not_uc_packet_types,
+ [MLXSW_SP_FLOOD_TYPE_ANY] = mlxsw_sp_sfgc_any_packet_types,
};
struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
@@ -305,10 +354,13 @@ mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
int i;
- for (i = 0; i < fid_family->nr_flood_tables; i++) {
- if (fid_family->flood_tables[i].packet_type != packet_type)
+ for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {
+ const struct mlxsw_sp_flood_table *flood_table;
+
+ flood_table = &fid_family->flood_profile->flood_tables[i];
+ if (flood_table->packet_type != packet_type)
continue;
- return &fid_family->flood_tables[i];
+ return flood_table;
}
return NULL;
@@ -320,24 +372,62 @@ 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_family_pgt_size(const struct mlxsw_sp_fid_family *fid_family)
+static int
+mlxsw_sp_fid_8021d_pgt_size(const struct mlxsw_sp_fid_family *fid_family,
+ u16 *p_pgt_size)
{
u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
- return num_fids * fid_family->nr_flood_tables;
+ *p_pgt_size = num_fids * fid_family->flood_profile->nr_flood_tables;
+ return 0;
+}
+
+static unsigned int mlxsw_sp_fid_rfid_port_offset_cff(unsigned int local_port)
+{
+ /* Port 0 is the CPU port. Since we never create RIFs based off that
+ * port, we don't need to count it.
+ */
+ return WARN_ON_ONCE(!local_port) ? 0 : local_port - 1;
+}
+
+static int
+mlxsw_sp_fid_rfid_pgt_size_cff(const struct mlxsw_sp_fid_family *fid_family,
+ u16 *p_pgt_size)
+{
+ struct mlxsw_core *core = fid_family->mlxsw_sp->core;
+ unsigned int max_ports;
+ u16 pgt_size;
+ u16 max_lags;
+ int err;
+
+ max_ports = mlxsw_core_max_ports(core);
+
+ err = mlxsw_core_max_lag(core, &max_lags);
+ if (err)
+ return err;
+
+ pgt_size = (mlxsw_sp_fid_rfid_port_offset_cff(max_ports) + max_lags) *
+ fid_family->flood_profile->nr_flood_tables;
+ *p_pgt_size = pgt_size;
+ return 0;
}
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)
+mlxsw_sp_fid_pgt_base_ctl(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_flood_table *flood_table)
{
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;
+ return fid_family->pgt_base + num_fids * flood_table->table_index;
+}
+
+static u16
+mlxsw_sp_fid_fid_mid_ctl(const struct mlxsw_sp_fid *fid,
+ const struct mlxsw_sp_flood_table *flood_table)
+{
+ return mlxsw_sp_fid_pgt_base_ctl(fid->fid_family, flood_table) +
+ fid->fid_offset;
}
int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
@@ -348,15 +438,14 @@ int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
const struct mlxsw_sp_flood_table *flood_table;
u16 mid_index;
- if (WARN_ON(!fid_family->flood_tables))
+ if (WARN_ON(!fid_family->flood_profile))
return -EINVAL;
flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
if (!flood_table)
return -ESRCH;
- mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
- fid->fid_offset);
+ mid_index = fid_family->ops->fid_mid(fid, flood_table);
return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
fid->fid_index, local_port, member);
}
@@ -410,12 +499,13 @@ u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
return mlxsw_sp_fid_8021q_fid(fid)->vid;
}
-static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
+static int 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;
+ return 0;
}
static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
@@ -424,18 +514,76 @@ static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
MLXSW_REG_SFMR_OP_DESTROY_FID;
}
-static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
+static void mlxsw_sp_fid_pack(char *sfmr_pl,
+ const struct mlxsw_sp_fid *fid,
+ enum mlxsw_reg_sfmr_op op)
{
- 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->fid_index,
- fid->fid_offset, fid->fid_family->flood_rsp,
- fid->fid_family->bridge_type,
+ mlxsw_reg_sfmr_pack(sfmr_pl, op, fid->fid_index,
fid->fid_family->smpe_index_valid, smpe);
+}
+
+static void mlxsw_sp_fid_pack_ctl(char *sfmr_pl,
+ const struct mlxsw_sp_fid *fid,
+ enum mlxsw_reg_sfmr_op op)
+{
+ mlxsw_sp_fid_pack(sfmr_pl, fid, op);
+ mlxsw_reg_sfmr_fid_offset_set(sfmr_pl, fid->fid_offset);
+ mlxsw_reg_sfmr_flood_rsp_set(sfmr_pl, fid->fid_family->flood_rsp);
+ mlxsw_reg_sfmr_flood_bridge_type_set(sfmr_pl,
+ fid->fid_family->bridge_type);
+}
+
+static u16
+mlxsw_sp_fid_off_pgt_base_cff(const struct mlxsw_sp_fid_family *fid_family,
+ u16 fid_offset)
+{
+ return fid_family->pgt_base +
+ fid_offset * fid_family->flood_profile->nr_flood_tables;
+}
+
+static u16 mlxsw_sp_fid_pgt_base_cff(const struct mlxsw_sp_fid *fid)
+{
+ return mlxsw_sp_fid_off_pgt_base_cff(fid->fid_family, fid->fid_offset);
+}
+
+static void mlxsw_sp_fid_fid_pack_cff(char *sfmr_pl,
+ const struct mlxsw_sp_fid *fid,
+ enum mlxsw_reg_sfmr_op op)
+{
+ struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
+ u16 pgt_base = mlxsw_sp_fid_pgt_base_cff(fid);
+
+ mlxsw_sp_fid_pack(sfmr_pl, fid, op);
+ mlxsw_reg_sfmr_cff_mid_base_set(sfmr_pl, pgt_base);
+ mlxsw_reg_sfmr_cff_prf_id_set(sfmr_pl,
+ fid_family->flood_profile->profile_id);
+ mlxsw_reg_sfmr_nve_flood_prf_id_set(sfmr_pl,
+ MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE);
+}
+
+static u16 mlxsw_sp_fid_rfid_fid_offset_cff(struct mlxsw_sp *mlxsw_sp,
+ u16 port_lag_id, bool is_lag)
+{
+ u16 max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
+
+ if (is_lag)
+ return mlxsw_sp_fid_rfid_port_offset_cff(max_ports) +
+ port_lag_id;
+ else
+ return mlxsw_sp_fid_rfid_port_offset_cff(port_lag_id);
+}
+
+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];
+
+ fid->fid_family->ops->fid_pack(sfmr_pl, fid,
+ mlxsw_sp_sfmr_op(valid));
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
}
@@ -444,15 +592,10 @@ static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
{
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;
+ fid->fid_family->ops->fid_pack(sfmr_pl, fid,
+ MLXSW_REG_SFMR_OP_CREATE_FID);
- 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);
@@ -768,12 +911,13 @@ mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
return container_of(fid, struct mlxsw_sp_fid_8021d, common);
}
-static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
+static int 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;
+ return 0;
}
static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
@@ -1058,7 +1202,37 @@ mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
return 0;
}
-static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
+static int
+mlxsw_sp_fid_flood_table_init_ctl(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;
+ u16 mid_base;
+ int err, i;
+
+ mid_base = mlxsw_sp_fid_pgt_base_ctl(fid_family, flood_table);
+
+ sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
+ for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
+ char sfgc_pl[MLXSW_REG_SFGC_LEN];
+
+ if (!sfgc_packet_types[i])
+ continue;
+
+ 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;
+ }
+
+ return 0;
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_ctl = {
.setup = mlxsw_sp_fid_8021d_setup,
.configure = mlxsw_sp_fid_8021d_configure,
.deconfigure = mlxsw_sp_fid_8021d_deconfigure,
@@ -1072,6 +1246,36 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
.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,
+ .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl,
+ .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
+ .fid_mid = mlxsw_sp_fid_fid_mid_ctl,
+ .fid_pack = mlxsw_sp_fid_pack_ctl,
+};
+
+static u16
+mlxsw_sp_fid_fid_mid_cff(const struct mlxsw_sp_fid *fid,
+ const struct mlxsw_sp_flood_table *flood_table)
+{
+ return mlxsw_sp_fid_pgt_base_cff(fid) + flood_table->table_index;
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops_cff = {
+ .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,
+ .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_8021d_fdb_clear_offload,
+ .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
+ .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
+ .fid_mid = mlxsw_sp_fid_fid_mid_cff,
+ .fid_pack = mlxsw_sp_fid_fid_pack_cff,
};
#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
@@ -1095,6 +1299,45 @@ static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
},
};
+static const
+struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_8021d_flood_profile = {
+ .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
+ .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
+ .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_BRIDGE,
+};
+
+static const struct mlxsw_sp_flood_table mlxsw_sp_fid_rsp_flood_tables_cff[] = {
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
+ .table_index = 0,
+ },
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_NOT_UC,
+ .table_index = 1,
+ },
+};
+
+static const
+struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_rsp_flood_profile_cff = {
+ .flood_tables = mlxsw_sp_fid_rsp_flood_tables_cff,
+ .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_rsp_flood_tables_cff),
+ .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_RSP,
+};
+
+static const struct mlxsw_sp_flood_table mlxsw_sp_fid_nve_flood_tables_cff[] = {
+ {
+ .packet_type = MLXSW_SP_FLOOD_TYPE_ANY,
+ .table_index = 0,
+ },
+};
+
+static const
+struct mlxsw_sp_fid_flood_profile mlxsw_sp_fid_nve_flood_profile_cff = {
+ .flood_tables = mlxsw_sp_fid_nve_flood_tables_cff,
+ .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_nve_flood_tables_cff),
+ .profile_id = MLXSW_SP_FID_FLOOD_PROFILE_ID_NVE,
+};
+
static bool
mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
{
@@ -1110,9 +1353,35 @@ 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 void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
+static int mlxsw_sp_fid_rfid_setup_ctl(struct mlxsw_sp_fid *fid,
+ const void *arg)
{
+ /* In controlled mode, the FW takes care of FID placement. */
fid->fid_offset = 0;
+ return 0;
+}
+
+static int mlxsw_sp_fid_rfid_setup_cff(struct mlxsw_sp_fid *fid,
+ const void *arg)
+{
+ struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
+ u16 rif_index = *(const u16 *)arg;
+ struct mlxsw_sp_rif *rif;
+ bool is_lag;
+ u16 port;
+ int err;
+
+ rif = mlxsw_sp_rif_by_index(mlxsw_sp, rif_index);
+ if (!rif)
+ return -ENOENT;
+
+ err = mlxsw_sp_rif_subport_port(rif, &port, &is_lag);
+ if (err)
+ return err;
+
+ fid->fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port,
+ is_lag);
+ return 0;
}
static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
@@ -1238,8 +1507,8 @@ mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
return 0;
}
-static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
- .setup = mlxsw_sp_fid_rfid_setup,
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_ctl = {
+ .setup = mlxsw_sp_fid_rfid_setup_ctl,
.configure = mlxsw_sp_fid_rfid_configure,
.deconfigure = mlxsw_sp_fid_rfid_deconfigure,
.index_alloc = mlxsw_sp_fid_rfid_index_alloc,
@@ -1251,11 +1520,146 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
.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,
+ .fid_pack = mlxsw_sp_fid_pack_ctl,
+};
+
+static int
+mlxsw_sp_fid_rfid_port_add_cff(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_flood_table *flood_table,
+ u16 pgt_addr, u16 smpe, unsigned int local_port)
+{
+ int err;
+
+ err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,
+ local_port, true);
+ if (err)
+ return err;
+
+ if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) {
+ u16 router_port = mlxsw_sp_router_port(mlxsw_sp);
+
+ err = mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,
+ router_port, true);
+ if (err)
+ goto err_entry_port_set;
+ }
+
+ return 0;
+
+err_entry_port_set:
+ mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port,
+ false);
+ return err;
+}
+
+static void
+mlxsw_sp_fid_rfid_port_del_cff(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_flood_table *flood_table,
+ u16 pgt_addr, u16 smpe, u16 local_port)
+{
+ if (flood_table->packet_type == MLXSW_SP_FLOOD_TYPE_NOT_UC) {
+ u16 router_port = mlxsw_sp_router_port(mlxsw_sp);
+
+ mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe,
+ router_port, false);
+ }
+ mlxsw_sp_pgt_entry_port_set(mlxsw_sp, pgt_addr, smpe, local_port,
+ false);
+}
+
+static int
+mlxsw_sp_fid_rfid_port_memb_ft_cff(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_flood_table *flood_table,
+ const struct mlxsw_sp_port *mlxsw_sp_port,
+ bool member)
+{
+ struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
+ u16 local_port = mlxsw_sp_port->local_port;
+ u16 fid_pgt_base;
+ u16 fid_offset;
+ u16 pgt_addr;
+ u16 smpe;
+ u16 port;
+
+ /* In-PGT SMPE is only valid on Spectrum-1, CFF only on Spectrum>1. */
+ smpe = 0;
+
+ port = mlxsw_sp_port->lagged ? mlxsw_sp_port->lag_id : local_port;
+ fid_offset = mlxsw_sp_fid_rfid_fid_offset_cff(mlxsw_sp, port,
+ mlxsw_sp_port->lagged);
+ fid_pgt_base = mlxsw_sp_fid_off_pgt_base_cff(fid_family, fid_offset);
+ pgt_addr = fid_pgt_base + flood_table->table_index;
+
+ if (member)
+ return mlxsw_sp_fid_rfid_port_add_cff(mlxsw_sp, flood_table,
+ pgt_addr, smpe,
+ local_port);
+
+ mlxsw_sp_fid_rfid_port_del_cff(mlxsw_sp, flood_table, pgt_addr, smpe,
+ local_port);
+ return 0;
+}
+
+static int
+mlxsw_sp_fid_rfid_port_memb_cff(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_port *mlxsw_sp_port,
+ bool member)
+{
+ int i;
+
+ for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {
+ const struct mlxsw_sp_flood_table *flood_table =
+ &fid_family->flood_profile->flood_tables[i];
+ int err;
+
+ err = mlxsw_sp_fid_rfid_port_memb_ft_cff(fid_family,
+ flood_table,
+ mlxsw_sp_port, member);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+mlxsw_sp_fid_rfid_port_init_cff(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ return mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, true);
+}
+
+static void
+mlxsw_sp_fid_rfid_port_fini_cff(const struct mlxsw_sp_fid_family *fid_family,
+ const struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ mlxsw_sp_fid_rfid_port_memb_cff(fid_family, mlxsw_sp_port, false);
+}
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops_cff = {
+ .setup = mlxsw_sp_fid_rfid_setup_cff,
+ .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,
+ .pgt_size = mlxsw_sp_fid_rfid_pgt_size_cff,
+ .fid_port_init = mlxsw_sp_fid_rfid_port_init_cff,
+ .fid_port_fini = mlxsw_sp_fid_rfid_port_fini_cff,
+ .fid_mid = mlxsw_sp_fid_fid_mid_cff,
+ .fid_pack = mlxsw_sp_fid_fid_pack_cff,
};
-static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
+static int mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
{
fid->fid_offset = 0;
+ return 0;
}
static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
@@ -1312,6 +1716,7 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
.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,
+ .fid_pack = mlxsw_sp_fid_pack,
};
static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
@@ -1395,7 +1800,7 @@ mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
}
-static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_ctl = {
.setup = mlxsw_sp_fid_8021q_setup,
.configure = mlxsw_sp_fid_8021q_configure,
.deconfigure = mlxsw_sp_fid_8021q_deconfigure,
@@ -1409,6 +1814,29 @@ static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
.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,
+ .flood_table_init = mlxsw_sp_fid_flood_table_init_ctl,
+ .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
+ .fid_mid = mlxsw_sp_fid_fid_mid_ctl,
+ .fid_pack = mlxsw_sp_fid_pack_ctl,
+};
+
+static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops_cff = {
+ .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,
+ .pgt_size = mlxsw_sp_fid_8021d_pgt_size,
+ .fid_mid = mlxsw_sp_fid_fid_mid_cff,
+ .fid_pack = mlxsw_sp_fid_fid_pack_cff,
};
/* There are 4K-2 802.1Q FIDs */
@@ -1434,10 +1862,9 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
.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),
+ .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
.rif_type = MLXSW_SP_RIF_TYPE_VLAN,
- .ops = &mlxsw_sp_fid_8021q_ops,
+ .ops = &mlxsw_sp_fid_8021q_ops_ctl,
.flood_rsp = false,
.bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
.smpe_index_valid = false,
@@ -1448,10 +1875,9 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
.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),
+ .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
.rif_type = MLXSW_SP_RIF_TYPE_FID,
- .ops = &mlxsw_sp_fid_8021d_ops,
+ .ops = &mlxsw_sp_fid_8021d_ops_ctl,
.bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
.smpe_index_valid = false,
};
@@ -1465,47 +1891,45 @@ static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
.smpe_index_valid = false,
};
-static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_ctl = {
.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,
+ .ops = &mlxsw_sp_fid_rfid_ops_ctl,
.flood_rsp = true,
.smpe_index_valid = false,
};
-const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
+static 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,
+ [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl,
};
-static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_ctl = {
.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),
+ .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
.rif_type = MLXSW_SP_RIF_TYPE_VLAN,
- .ops = &mlxsw_sp_fid_8021q_ops,
+ .ops = &mlxsw_sp_fid_8021q_ops_ctl,
.flood_rsp = false,
.bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
.smpe_index_valid = true,
};
-static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_ctl = {
.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),
+ .flood_profile = &mlxsw_sp_fid_8021d_flood_profile,
.rif_type = MLXSW_SP_RIF_TYPE_FID,
- .ops = &mlxsw_sp_fid_8021d_ops,
+ .ops = &mlxsw_sp_fid_8021d_ops_ctl,
.bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
.smpe_index_valid = true,
};
@@ -1519,11 +1943,51 @@ static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
.smpe_index_valid = false,
};
-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,
+static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_ctl[] = {
+ [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_ctl,
+ [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_ctl,
[MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family,
- [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
+ [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_ctl,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family_cff = {
+ .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_profile = &mlxsw_sp_fid_8021d_flood_profile,
+ .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
+ .ops = &mlxsw_sp_fid_8021q_ops_cff,
+ .smpe_index_valid = true,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family_cff = {
+ .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_profile = &mlxsw_sp_fid_8021d_flood_profile,
+ .rif_type = MLXSW_SP_RIF_TYPE_FID,
+ .ops = &mlxsw_sp_fid_8021d_ops_cff,
+ .smpe_index_valid = true,
+};
+
+static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family_cff = {
+ .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,
+ .flood_profile = &mlxsw_sp_fid_rsp_flood_profile_cff,
+ .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
+ .ops = &mlxsw_sp_fid_rfid_ops_cff,
+ .smpe_index_valid = false,
+};
+
+static const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr_cff[] = {
+ [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family_cff,
+ [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family_cff,
+ [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family,
+ [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family_cff,
};
static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
@@ -1571,7 +2035,9 @@ 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);
- fid->fid_family->ops->setup(fid, arg);
+ err = fid->fid_family->ops->setup(fid, arg);
+ if (err)
+ goto err_setup;
err = fid->fid_family->ops->configure(fid);
if (err)
@@ -1589,6 +2055,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
err_rhashtable_insert:
fid->fid_family->ops->deconfigure(fid);
err_configure:
+err_setup:
__clear_bit(fid_index - fid_family->start_index,
fid_family->fids_bitmap);
err_index_alloc:
@@ -1650,36 +2117,6 @@ struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
}
static int
-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;
- u16 mid_base;
- int err, i;
-
- mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
-
- sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
- for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
- char sfgc_pl[MLXSW_REG_SFGC_LEN];
-
- if (!sfgc_packet_types[i])
- continue;
-
- 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;
- }
-
- return 0;
-}
-
-static int
mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
{
struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
@@ -1687,22 +2124,28 @@ mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
int err;
int i;
- if (!fid_family->nr_flood_tables)
- return 0;
+ err = fid_family->ops->pgt_size(fid_family, &pgt_size);
+ if (err)
+ return err;
- pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family);
err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &fid_family->pgt_base,
pgt_size);
if (err)
return err;
- for (i = 0; i < fid_family->nr_flood_tables; i++) {
+ if (!fid_family->flood_profile)
+ return 0;
+
+ for (i = 0; i < fid_family->flood_profile->nr_flood_tables; i++) {
const struct mlxsw_sp_flood_table *flood_table;
- flood_table = &fid_family->flood_tables[i];
- err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
- if (err)
- goto err_flood_table_init;
+ flood_table = &fid_family->flood_profile->flood_tables[i];
+ if (fid_family->ops->flood_table_init) {
+ err = fid_family->ops->flood_table_init(fid_family,
+ flood_table);
+ if (err)
+ goto err_flood_table_init;
+ }
}
return 0;
@@ -1717,11 +2160,12 @@ mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
{
struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
u16 pgt_size;
+ int err;
- if (!fid_family->nr_flood_tables)
+ err = fid_family->ops->pgt_size(fid_family, &pgt_size);
+ if (WARN_ON_ONCE(err))
return;
- pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family);
mlxsw_sp_pgt_mid_free_range(mlxsw_sp, fid_family->pgt_base, pgt_size);
}
@@ -1744,7 +2188,7 @@ static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
goto err_alloc_fids_bitmap;
}
- if (fid_family->flood_tables) {
+ if (fid_family->flood_profile) {
err = mlxsw_sp_fid_flood_tables_init(fid_family);
if (err)
goto err_fid_flood_tables_init;
@@ -1767,7 +2211,7 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
{
mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
- if (fid_family->flood_tables)
+ if (fid_family->flood_profile)
mlxsw_sp_fid_flood_tables_fini(fid_family);
bitmap_free(fid_family->fids_bitmap);
@@ -1775,9 +2219,34 @@ mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
kfree(fid_family);
}
+static int mlxsw_sp_fid_port_init(const struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID;
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_fid_family *rfid_family;
+
+ rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid];
+ if (rfid_family->ops->fid_port_init)
+ return rfid_family->ops->fid_port_init(rfid_family,
+ mlxsw_sp_port);
+ return 0;
+}
+
+static void mlxsw_sp_fid_port_fini(const struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ const enum mlxsw_sp_fid_type type_rfid = MLXSW_SP_FID_TYPE_RFID;
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ struct mlxsw_sp_fid_family *rfid_family;
+
+ rfid_family = mlxsw_sp->fid_core->fid_family_arr[type_rfid];
+ if (rfid_family->ops->fid_port_fini)
+ rfid_family->ops->fid_port_fini(rfid_family, mlxsw_sp_port);
+}
+
int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ int err;
/* Track number of FIDs configured on the port with mapping type
* PORT_VID_TO_FID, so that we know when to transition the port
@@ -1785,17 +2254,42 @@ int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
*/
mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
- return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
+ err = mlxsw_sp_fid_port_init(mlxsw_sp_port);
+ if (err)
+ return err;
+
+ err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
+ if (err)
+ goto err_vp_mode_set;
+
+ return 0;
+
+err_vp_mode_set:
+ mlxsw_sp_fid_port_fini(mlxsw_sp_port);
+ return err;
}
void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+ mlxsw_sp_fid_port_fini(mlxsw_sp_port);
mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
}
-int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
+int mlxsw_sp_fid_port_join_lag(const struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ return mlxsw_sp_fid_port_init(mlxsw_sp_port);
+}
+
+void mlxsw_sp_fid_port_leave_lag(const struct mlxsw_sp_port *mlxsw_sp_port)
+{
+ mlxsw_sp_fid_port_fini(mlxsw_sp_port);
+}
+
+static int
+mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_fid_family *fid_family_arr[])
{
unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
struct mlxsw_sp_fid_core *fid_core;
@@ -1822,8 +2316,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]);
+ err = mlxsw_sp_fid_family_register(mlxsw_sp, fid_family_arr[i]);
if (err)
goto err_fid_ops_register;
@@ -1848,7 +2341,7 @@ err_rhashtable_fid_init:
return err;
}
-void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
+static void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
{
struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
int i;
@@ -1861,3 +2354,143 @@ void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
rhashtable_destroy(&fid_core->fid_ht);
kfree(fid_core);
}
+
+static int mlxsw_sp1_fids_init(struct mlxsw_sp *mlxsw_sp)
+{
+ return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp1_fid_family_arr);
+}
+
+const struct mlxsw_sp_fid_core_ops mlxsw_sp1_fid_core_ops = {
+ .init = mlxsw_sp1_fids_init,
+ .fini = mlxsw_sp_fids_fini,
+};
+
+static int mlxsw_sp_fid_check_flood_profile_id(struct mlxsw_sp *mlxsw_sp,
+ int profile_id)
+{
+ u32 max_profiles;
+
+ if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_NVE_FLOOD_PRF))
+ return -EIO;
+
+ max_profiles = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_NVE_FLOOD_PRF);
+ if (WARN_ON_ONCE(!profile_id) ||
+ WARN_ON_ONCE(profile_id >= max_profiles))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+mlxsw_sp2_fids_init_flood_table(struct mlxsw_sp *mlxsw_sp,
+ enum mlxsw_sp_fid_flood_profile_id profile_id,
+ const struct mlxsw_sp_flood_table *flood_table)
+{
+ enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
+ const int *sfgc_packet_types;
+ int err;
+ int i;
+
+ sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
+ for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
+ char sffp_pl[MLXSW_REG_SFFP_LEN];
+
+ if (!sfgc_packet_types[i])
+ continue;
+
+ mlxsw_reg_sffp_pack(sffp_pl, profile_id, i,
+ flood_table->table_index);
+ err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sffp), sffp_pl);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int
+mlxsw_sp2_fids_init_flood_profile(struct mlxsw_sp *mlxsw_sp,
+ const struct mlxsw_sp_fid_flood_profile *
+ flood_profile)
+{
+ int err;
+ int i;
+
+ err = mlxsw_sp_fid_check_flood_profile_id(mlxsw_sp,
+ flood_profile->profile_id);
+ if (err)
+ return err;
+
+ for (i = 0; i < flood_profile->nr_flood_tables; i++) {
+ const struct mlxsw_sp_flood_table *flood_table;
+
+ flood_table = &flood_profile->flood_tables[i];
+ err = mlxsw_sp2_fids_init_flood_table(mlxsw_sp,
+ flood_profile->profile_id,
+ flood_table);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static const
+struct mlxsw_sp_fid_flood_profile *mlxsw_sp_fid_flood_profiles[] = {
+ &mlxsw_sp_fid_8021d_flood_profile,
+ &mlxsw_sp_fid_rsp_flood_profile_cff,
+ &mlxsw_sp_fid_nve_flood_profile_cff,
+};
+
+static int
+mlxsw_sp2_fids_init_flood_profiles(struct mlxsw_sp *mlxsw_sp)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mlxsw_sp_fid_flood_profiles); i++) {
+ const struct mlxsw_sp_fid_flood_profile *flood_profile;
+
+ flood_profile = mlxsw_sp_fid_flood_profiles[i];
+ err = mlxsw_sp2_fids_init_flood_profile(mlxsw_sp,
+ flood_profile);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int mlxsw_sp2_fids_init_ctl(struct mlxsw_sp *mlxsw_sp)
+{
+ return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_ctl);
+}
+
+static int mlxsw_sp2_fids_init_cff(struct mlxsw_sp *mlxsw_sp)
+{
+ int err;
+
+ err = mlxsw_sp2_fids_init_flood_profiles(mlxsw_sp);
+ if (err)
+ return err;
+
+ return mlxsw_sp_fids_init(mlxsw_sp, mlxsw_sp2_fid_family_arr_cff);
+}
+
+static int mlxsw_sp2_fids_init(struct mlxsw_sp *mlxsw_sp)
+{
+ switch (mlxsw_core_flood_mode(mlxsw_sp->core)) {
+ case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CONTROLLED:
+ return mlxsw_sp2_fids_init_ctl(mlxsw_sp);
+ case MLXSW_CMD_MBOX_CONFIG_PROFILE_FLOOD_MODE_CFF:
+ return mlxsw_sp2_fids_init_cff(mlxsw_sp);
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+}
+
+const struct mlxsw_sp_fid_core_ops mlxsw_sp2_fid_core_ops = {
+ .init = mlxsw_sp2_fids_init,
+ .fini = mlxsw_sp_fids_fini,
+};
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 82a95125d9ca..7164f9e6370f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -8419,6 +8419,9 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
rif->ops = ops;
rif->rif_entries = rif_entries;
+ if (ops->setup)
+ ops->setup(rif, params);
+
if (ops->fid_get) {
fid = ops->fid_get(rif, params, extack);
if (IS_ERR(fid)) {
@@ -8428,9 +8431,6 @@ mlxsw_sp_rif_create(struct mlxsw_sp *mlxsw_sp,
rif->fid = fid;
}
- if (ops->setup)
- ops->setup(rif, params);
-
err = ops->configure(rif, extack);
if (err)
goto err_configure;
@@ -8660,6 +8660,20 @@ mlxsw_sp_rif_subport_rif(const struct mlxsw_sp_rif *rif)
return container_of(rif, struct mlxsw_sp_rif_subport, common);
}
+int mlxsw_sp_rif_subport_port(const struct mlxsw_sp_rif *rif,
+ u16 *port, bool *is_lag)
+{
+ struct mlxsw_sp_rif_subport *rif_subport;
+
+ if (WARN_ON(rif->ops->type != MLXSW_SP_RIF_TYPE_SUBPORT))
+ return -EINVAL;
+
+ rif_subport = mlxsw_sp_rif_subport_rif(rif);
+ *is_lag = rif_subport->lag;
+ *port = *is_lag ? rif_subport->lag_id : rif_subport->system_port;
+ return 0;
+}
+
static struct mlxsw_sp_rif *
mlxsw_sp_rif_subport_get(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_rif_params *params,
@@ -11458,6 +11472,13 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_register_netevent_notifier;
+ mlxsw_sp->router->netdevice_nb.notifier_call =
+ mlxsw_sp_router_netdevice_event;
+ err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
+ &mlxsw_sp->router->netdevice_nb);
+ if (err)
+ goto err_register_netdev_notifier;
+
mlxsw_sp->router->nexthop_nb.notifier_call =
mlxsw_sp_nexthop_obj_event;
err = register_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
@@ -11473,22 +11494,15 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp,
if (err)
goto err_register_fib_notifier;
- mlxsw_sp->router->netdevice_nb.notifier_call =
- mlxsw_sp_router_netdevice_event;
- err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
- &mlxsw_sp->router->netdevice_nb);
- if (err)
- goto err_register_netdev_notifier;
-
return 0;
-err_register_netdev_notifier:
- unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp),
- &mlxsw_sp->router->fib_nb);
err_register_fib_notifier:
unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
&mlxsw_sp->router->nexthop_nb);
err_register_nexthop_notifier:
+ unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
+ &router->netdevice_nb);
+err_register_netdev_notifier:
unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb);
err_register_netevent_notifier:
unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb);
@@ -11536,11 +11550,11 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
{
struct mlxsw_sp_router *router = mlxsw_sp->router;
- unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
- &router->netdevice_nb);
unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), &router->fib_nb);
unregister_nexthop_notifier(mlxsw_sp_net(mlxsw_sp),
&router->nexthop_nb);
+ unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp),
+ &router->netdevice_nb);
unregister_netevent_notifier(&router->netevent_nb);
unregister_inet6addr_validator_notifier(&router->inet6addr_valid_nb);
unregister_inetaddr_validator_notifier(&router->inetaddr_valid_nb);
diff --git a/drivers/net/ethernet/micrel/ks8851_spi.c b/drivers/net/ethernet/micrel/ks8851_spi.c
index 88e26c120b48..54f2eac11a63 100644
--- a/drivers/net/ethernet/micrel/ks8851_spi.c
+++ b/drivers/net/ethernet/micrel/ks8851_spi.c
@@ -156,7 +156,7 @@ static void ks8851_rdreg(struct ks8851_net *ks, unsigned int op,
txb[0] = cpu_to_le16(op | KS_SPIOP_RD);
- if (kss->spidev->master->flags & SPI_MASTER_HALF_DUPLEX) {
+ if (kss->spidev->master->flags & SPI_CONTROLLER_HALF_DUPLEX) {
msg = &kss->spi_msg2;
xfer = kss->spi_xfer2;
@@ -180,7 +180,7 @@ static void ks8851_rdreg(struct ks8851_net *ks, unsigned int op,
ret = spi_sync(kss->spidev, msg);
if (ret < 0)
netdev_err(ks->netdev, "read: spi_sync() failed\n");
- else if (kss->spidev->master->flags & SPI_MASTER_HALF_DUPLEX)
+ else if (kss->spidev->master->flags & SPI_CONTROLLER_HALF_DUPLEX)
memcpy(rxb, trx, rxl);
else
memcpy(rxb, trx + 2, rxl);
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 6961cfc55fb9..a2b3f4433ca8 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -934,11 +934,11 @@ static u32 lan743x_ethtool_get_rxfh_indir_size(struct net_device *netdev)
}
static int lan743x_ethtool_get_rxfh(struct net_device *netdev,
- u32 *indir, u8 *key, u8 *hfunc)
+ struct ethtool_rxfh_param *rxfh)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
- if (indir) {
+ if (rxfh->indir) {
int dw_index;
int byte_index = 0;
@@ -947,17 +947,17 @@ static int lan743x_ethtool_get_rxfh(struct net_device *netdev,
lan743x_csr_read(adapter, RFE_INDX(dw_index));
byte_index = dw_index << 2;
- indir[byte_index + 0] =
+ rxfh->indir[byte_index + 0] =
((four_entries >> 0) & 0x000000FF);
- indir[byte_index + 1] =
+ rxfh->indir[byte_index + 1] =
((four_entries >> 8) & 0x000000FF);
- indir[byte_index + 2] =
+ rxfh->indir[byte_index + 2] =
((four_entries >> 16) & 0x000000FF);
- indir[byte_index + 3] =
+ rxfh->indir[byte_index + 3] =
((four_entries >> 24) & 0x000000FF);
}
}
- if (key) {
+ if (rxfh->key) {
int dword_index;
int byte_index = 0;
@@ -967,28 +967,30 @@ static int lan743x_ethtool_get_rxfh(struct net_device *netdev,
RFE_HASH_KEY(dword_index));
byte_index = dword_index << 2;
- key[byte_index + 0] =
+ rxfh->key[byte_index + 0] =
((four_entries >> 0) & 0x000000FF);
- key[byte_index + 1] =
+ rxfh->key[byte_index + 1] =
((four_entries >> 8) & 0x000000FF);
- key[byte_index + 2] =
+ rxfh->key[byte_index + 2] =
((four_entries >> 16) & 0x000000FF);
- key[byte_index + 3] =
+ rxfh->key[byte_index + 3] =
((four_entries >> 24) & 0x000000FF);
}
}
- if (hfunc)
- (*hfunc) = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
static int lan743x_ethtool_set_rxfh(struct net_device *netdev,
- const u32 *indir, const u8 *key,
- const u8 hfunc)
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
+ u32 *indir = rxfh->indir;
+ u8 *key = rxfh->key;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
if (indir) {
@@ -1075,7 +1077,6 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev,
buf = lan743x_csr_read(adapter, MAC_CR);
if (buf & MAC_CR_EEE_EN_) {
eee->eee_enabled = true;
- eee->eee_active = !!(eee->advertised & eee->lp_advertised);
eee->tx_lpi_enabled = true;
/* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT);
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index b648461787d2..be79cb0ae5af 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -1075,7 +1075,7 @@ struct lan743x_adapter {
#define DMA_DESCRIPTOR_SPACING_32 (32)
#define DMA_DESCRIPTOR_SPACING_64 (64)
#define DMA_DESCRIPTOR_SPACING_128 (128)
-#define DEFAULT_DMA_DESCRIPTOR_SPACING (L1_CACHE_BYTES)
+#define DEFAULT_DMA_DESCRIPTOR_SPACING (DMA_DESCRIPTOR_SPACING_16)
#define DMAC_CHANNEL_STATE_SET(start_bit, stop_bit) \
(((start_bit) ? 2 : 0) | ((stop_bit) ? 1 : 0))
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c b/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c
index 41fa2523d91d..5f2cd9a8cf8f 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_lag.c
@@ -37,19 +37,24 @@ static void lan966x_lag_set_aggr_pgids(struct lan966x *lan966x)
/* Now, set PGIDs for each active LAG */
for (lag = 0; lag < lan966x->num_phys_ports; ++lag) {
- struct net_device *bond = lan966x->ports[lag]->bond;
+ struct lan966x_port *port = lan966x->ports[lag];
int num_active_ports = 0;
+ struct net_device *bond;
unsigned long bond_mask;
u8 aggr_idx[16];
- if (!bond || (visited & BIT(lag)))
+ if (!port || !port->bond || (visited & BIT(lag)))
continue;
+ bond = port->bond;
bond_mask = lan966x_lag_get_mask(lan966x, bond);
for_each_set_bit(p, &bond_mask, lan966x->num_phys_ports) {
struct lan966x_port *port = lan966x->ports[p];
+ if (!port)
+ continue;
+
lan_wr(ANA_PGID_PGID_SET(bond_mask),
lan966x, ANA_PGID(p));
if (port->lag_tx_active)
diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c
index 92108d354051..2e83bbb9477e 100644
--- a/drivers/net/ethernet/microchip/lan966x/lan966x_port.c
+++ b/drivers/net/ethernet/microchip/lan966x/lan966x_port.c
@@ -168,9 +168,10 @@ static void lan966x_port_link_up(struct lan966x_port *port)
lan966x_taprio_speed_set(port, config->speed);
/* Also the GIGA_MODE_ENA(1) needs to be set regardless of the
- * port speed for QSGMII ports.
+ * port speed for QSGMII or SGMII ports.
*/
- if (phy_interface_num_ports(config->portmode) == 4)
+ if (phy_interface_num_ports(config->portmode) == 4 ||
+ config->portmode == PHY_INTERFACE_MODE_SGMII)
mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);
lan_wr(config->duplex | mode,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
index 37d2584b48a7..a06dc5a9b355 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
@@ -1012,7 +1012,7 @@ static void sparx5_get_sset_strings(struct net_device *ndev, u32 sset, u8 *data)
return;
for (idx = 0; idx < sparx5->num_ethtool_stats; idx++)
- ethtool_sprintf(&data, "%s", sparx5->stats_layout[idx]);
+ ethtool_puts(&data, sparx5->stats_layout[idx]);
}
static void sparx5_get_sset_data(struct net_device *ndev,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
index 4af285918ea2..75868b3f548e 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c
@@ -347,10 +347,10 @@ int sparx5_del_mact_entry(struct sparx5 *sparx5,
list) {
if ((vid == 0 || mact_entry->vid == vid) &&
ether_addr_equal(addr, mact_entry->mac)) {
+ sparx5_mact_forget(sparx5, addr, mact_entry->vid);
+
list_del(&mact_entry->list);
devm_kfree(sparx5->dev, mact_entry);
-
- sparx5_mact_forget(sparx5, addr, mact_entry->vid);
}
}
mutex_unlock(&sparx5->mact_lock);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
index d1f7fc8b1b71..3c066b62e689 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
@@ -757,6 +757,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sparx5);
sparx5->pdev = pdev;
sparx5->dev = &pdev->dev;
+ spin_lock_init(&sparx5->tx_lock);
/* Do switch core reset if available */
reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch");
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
index 6f565c0c0c3d..316fed5f2735 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -280,6 +280,7 @@ struct sparx5 {
int xtr_irq;
/* Frame DMA */
int fdma_irq;
+ spinlock_t tx_lock; /* lock for frame transmission */
struct sparx5_rx rx;
struct sparx5_tx tx;
/* PTP */
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
index 6db6ac6a3bbc..ac7e1cffbcec 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_packet.c
@@ -244,10 +244,12 @@ netdev_tx_t sparx5_port_xmit_impl(struct sk_buff *skb, struct net_device *dev)
}
skb_tx_timestamp(skb);
+ spin_lock(&sparx5->tx_lock);
if (sparx5->fdma_irq > 0)
ret = sparx5_fdma_xmit(sparx5, ifh, skb);
else
ret = sparx5_inject(sparx5, ifh, skb, dev);
+ spin_unlock(&sparx5->tx_lock);
if (ret == -EBUSY)
goto busy;
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index 6367de0c2c2e..d33b27214539 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -158,6 +158,9 @@ static int mana_gd_detect_devices(struct pci_dev *pdev)
if (dev_type == GDMA_DEVICE_MANA) {
gc->mana.gdma_context = gc;
gc->mana.dev_id = dev;
+ } else if (dev_type == GDMA_DEVICE_MANA_IB) {
+ gc->mana_ib.dev_id = dev;
+ gc->mana_ib.gdma_context = gc;
}
}
@@ -414,8 +417,12 @@ static void mana_gd_process_eq_events(void *arg)
old_bits = (eq->head / num_eqe - 1) & GDMA_EQE_OWNER_MASK;
/* No more entries */
- if (owner_bits == old_bits)
+ if (owner_bits == old_bits) {
+ /* return here without ringing the doorbell */
+ if (i == 0)
+ return;
break;
+ }
new_bits = (eq->head / num_eqe) & GDMA_EQE_OWNER_MASK;
if (owner_bits != new_bits) {
@@ -445,42 +452,29 @@ static int mana_gd_register_irq(struct gdma_queue *queue,
struct gdma_dev *gd = queue->gdma_dev;
struct gdma_irq_context *gic;
struct gdma_context *gc;
- struct gdma_resource *r;
unsigned int msi_index;
unsigned long flags;
struct device *dev;
int err = 0;
gc = gd->gdma_context;
- r = &gc->msix_resource;
dev = gc->dev;
+ msi_index = spec->eq.msix_index;
- spin_lock_irqsave(&r->lock, flags);
-
- msi_index = find_first_zero_bit(r->map, r->size);
- if (msi_index >= r->size || msi_index >= gc->num_msix_usable) {
+ if (msi_index >= gc->num_msix_usable) {
err = -ENOSPC;
- } else {
- bitmap_set(r->map, msi_index, 1);
- queue->eq.msix_index = msi_index;
- }
-
- spin_unlock_irqrestore(&r->lock, flags);
-
- if (err) {
- dev_err(dev, "Register IRQ err:%d, msi:%u rsize:%u, nMSI:%u",
- err, msi_index, r->size, gc->num_msix_usable);
+ dev_err(dev, "Register IRQ err:%d, msi:%u nMSI:%u",
+ err, msi_index, gc->num_msix_usable);
return err;
}
+ queue->eq.msix_index = msi_index;
gic = &gc->irq_contexts[msi_index];
- WARN_ON(gic->handler || gic->arg);
-
- gic->arg = queue;
-
- gic->handler = mana_gd_process_eq_events;
+ spin_lock_irqsave(&gic->lock, flags);
+ list_add_rcu(&queue->entry, &gic->eq_list);
+ spin_unlock_irqrestore(&gic->lock, flags);
return 0;
}
@@ -490,12 +484,11 @@ static void mana_gd_deregiser_irq(struct gdma_queue *queue)
struct gdma_dev *gd = queue->gdma_dev;
struct gdma_irq_context *gic;
struct gdma_context *gc;
- struct gdma_resource *r;
unsigned int msix_index;
unsigned long flags;
+ struct gdma_queue *eq;
gc = gd->gdma_context;
- r = &gc->msix_resource;
/* At most num_online_cpus() + 1 interrupts are used. */
msix_index = queue->eq.msix_index;
@@ -503,14 +496,17 @@ static void mana_gd_deregiser_irq(struct gdma_queue *queue)
return;
gic = &gc->irq_contexts[msix_index];
- gic->handler = NULL;
- gic->arg = NULL;
-
- spin_lock_irqsave(&r->lock, flags);
- bitmap_clear(r->map, msix_index, 1);
- spin_unlock_irqrestore(&r->lock, flags);
+ spin_lock_irqsave(&gic->lock, flags);
+ list_for_each_entry_rcu(eq, &gic->eq_list, entry) {
+ if (queue == eq) {
+ list_del_rcu(&eq->entry);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&gic->lock, flags);
queue->eq.msix_index = INVALID_PCI_MSIX_INDEX;
+ synchronize_rcu();
}
int mana_gd_test_eq(struct gdma_context *gc, struct gdma_queue *eq)
@@ -588,6 +584,7 @@ static int mana_gd_create_eq(struct gdma_dev *gd,
int err;
queue->eq.msix_index = INVALID_PCI_MSIX_INDEX;
+ queue->id = INVALID_QUEUE_ID;
log2_num_entries = ilog2(queue->queue_size / GDMA_EQE_SIZE);
@@ -819,6 +816,7 @@ free_q:
kfree(queue);
return err;
}
+EXPORT_SYMBOL_NS(mana_gd_create_mana_eq, NET_MANA);
int mana_gd_create_mana_wq_cq(struct gdma_dev *gd,
const struct gdma_queue_spec *spec,
@@ -895,6 +893,7 @@ void mana_gd_destroy_queue(struct gdma_context *gc, struct gdma_queue *queue)
mana_gd_free_memory(gmi);
kfree(queue);
}
+EXPORT_SYMBOL_NS(mana_gd_destroy_queue, NET_MANA);
int mana_gd_verify_vf_version(struct pci_dev *pdev)
{
@@ -971,6 +970,7 @@ int mana_gd_register_device(struct gdma_dev *gd)
return 0;
}
+EXPORT_SYMBOL_NS(mana_gd_register_device, NET_MANA);
int mana_gd_deregister_device(struct gdma_dev *gd)
{
@@ -1001,6 +1001,7 @@ int mana_gd_deregister_device(struct gdma_dev *gd)
return err;
}
+EXPORT_SYMBOL_NS(mana_gd_deregister_device, NET_MANA);
u32 mana_gd_wq_avail_space(struct gdma_queue *wq)
{
@@ -1217,9 +1218,14 @@ int mana_gd_poll_cq(struct gdma_queue *cq, struct gdma_comp *comp, int num_cqe)
static irqreturn_t mana_gd_intr(int irq, void *arg)
{
struct gdma_irq_context *gic = arg;
+ struct list_head *eq_list = &gic->eq_list;
+ struct gdma_queue *eq;
- if (gic->handler)
- gic->handler(gic->arg);
+ rcu_read_lock();
+ list_for_each_entry_rcu(eq, eq_list, entry) {
+ gic->handler(eq);
+ }
+ rcu_read_unlock();
return IRQ_HANDLED;
}
@@ -1271,8 +1277,9 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
for (i = 0; i < nvec; i++) {
gic = &gc->irq_contexts[i];
- gic->handler = NULL;
- gic->arg = NULL;
+ gic->handler = mana_gd_process_eq_events;
+ INIT_LIST_HEAD(&gic->eq_list);
+ spin_lock_init(&gic->lock);
if (!i)
snprintf(gic->name, MANA_IRQ_NAME_SZ, "mana_hwc@pci:%s",
@@ -1295,10 +1302,6 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev)
irq_set_affinity_and_hint(irq, cpumask_of(cpu));
}
- err = mana_gd_alloc_res_map(nvec, &gc->msix_resource);
- if (err)
- goto free_irq;
-
gc->max_num_msix = nvec;
gc->num_msix_usable = nvec;
@@ -1329,8 +1332,6 @@ static void mana_gd_remove_irqs(struct pci_dev *pdev)
if (gc->max_num_msix < 1)
return;
- mana_gd_free_res_map(&gc->msix_resource);
-
for (i = 0; i < gc->max_num_msix; i++) {
irq = pci_irq_vector(pdev, i);
if (irq < 0)
diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c
index 9d1cd3bfcf66..2729a2c5acf9 100644
--- a/drivers/net/ethernet/microsoft/mana/hw_channel.c
+++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c
@@ -300,6 +300,7 @@ static int mana_hwc_create_gdma_eq(struct hw_channel_context *hwc,
spec.eq.context = ctx;
spec.eq.callback = cb;
spec.eq.log2_throttle_limit = DEFAULT_LOG2_THROTTLING_FOR_ERROR_EQ;
+ spec.eq.msix_index = 0;
return mana_gd_create_hwc_queue(hwc->gdma_dev, &spec, queue);
}
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index fc3d2903a80f..59287c6e6cee 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1244,6 +1244,7 @@ static int mana_create_eq(struct mana_context *ac)
spec.eq.log2_throttle_limit = LOG2_EQ_THROTTLE;
for (i = 0; i < gc->max_num_queues; i++) {
+ spec.eq.msix_index = (i + 1) % gc->num_msix_usable;
err = mana_gd_create_mana_eq(gd, &spec, &ac->eqs[i].eq);
if (err)
goto out;
@@ -2137,6 +2138,7 @@ static int mana_create_page_pool(struct mana_rxq *rxq, struct gdma_context *gc)
pprm.pool_size = RX_BUFFERS_PER_QUEUE;
pprm.nid = gc->numa_node;
pprm.napi = &rxq->rx_cq.napi;
+ pprm.netdev = rxq->ndev;
rxq->page_pool = page_pool_create(&pprm);
@@ -2385,13 +2387,33 @@ void mana_query_gf_stats(struct mana_port_context *apc)
mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT,
sizeof(req), sizeof(resp));
- req.req_stats = STATISTICS_FLAGS_HC_TX_BYTES |
+ req.req_stats = STATISTICS_FLAGS_RX_DISCARDS_NO_WQE |
+ STATISTICS_FLAGS_RX_ERRORS_VPORT_DISABLED |
+ STATISTICS_FLAGS_HC_RX_BYTES |
+ STATISTICS_FLAGS_HC_RX_UCAST_PACKETS |
+ STATISTICS_FLAGS_HC_RX_UCAST_BYTES |
+ STATISTICS_FLAGS_HC_RX_MCAST_PACKETS |
+ STATISTICS_FLAGS_HC_RX_MCAST_BYTES |
+ STATISTICS_FLAGS_HC_RX_BCAST_PACKETS |
+ STATISTICS_FLAGS_HC_RX_BCAST_BYTES |
+ STATISTICS_FLAGS_TX_ERRORS_GF_DISABLED |
+ STATISTICS_FLAGS_TX_ERRORS_VPORT_DISABLED |
+ STATISTICS_FLAGS_TX_ERRORS_INVAL_VPORT_OFFSET_PACKETS |
+ STATISTICS_FLAGS_TX_ERRORS_VLAN_ENFORCEMENT |
+ STATISTICS_FLAGS_TX_ERRORS_ETH_TYPE_ENFORCEMENT |
+ STATISTICS_FLAGS_TX_ERRORS_SA_ENFORCEMENT |
+ STATISTICS_FLAGS_TX_ERRORS_SQPDID_ENFORCEMENT |
+ STATISTICS_FLAGS_TX_ERRORS_CQPDID_ENFORCEMENT |
+ STATISTICS_FLAGS_TX_ERRORS_MTU_VIOLATION |
+ STATISTICS_FLAGS_TX_ERRORS_INVALID_OOB |
+ STATISTICS_FLAGS_HC_TX_BYTES |
STATISTICS_FLAGS_HC_TX_UCAST_PACKETS |
STATISTICS_FLAGS_HC_TX_UCAST_BYTES |
STATISTICS_FLAGS_HC_TX_MCAST_PACKETS |
STATISTICS_FLAGS_HC_TX_MCAST_BYTES |
STATISTICS_FLAGS_HC_TX_BCAST_PACKETS |
- STATISTICS_FLAGS_HC_TX_BCAST_BYTES;
+ STATISTICS_FLAGS_HC_TX_BCAST_BYTES |
+ STATISTICS_FLAGS_TX_ERRORS_GDMA_ERROR;
err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
sizeof(resp));
@@ -2407,6 +2429,30 @@ void mana_query_gf_stats(struct mana_port_context *apc)
return;
}
+ apc->eth_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe;
+ apc->eth_stats.hc_rx_err_vport_disabled = resp.rx_err_vport_disabled;
+ apc->eth_stats.hc_rx_bytes = resp.hc_rx_bytes;
+ apc->eth_stats.hc_rx_ucast_pkts = resp.hc_rx_ucast_pkts;
+ apc->eth_stats.hc_rx_ucast_bytes = resp.hc_rx_ucast_bytes;
+ apc->eth_stats.hc_rx_bcast_pkts = resp.hc_rx_bcast_pkts;
+ apc->eth_stats.hc_rx_bcast_bytes = resp.hc_rx_bcast_bytes;
+ apc->eth_stats.hc_rx_mcast_pkts = resp.hc_rx_mcast_pkts;
+ apc->eth_stats.hc_rx_mcast_bytes = resp.hc_rx_mcast_bytes;
+ apc->eth_stats.hc_tx_err_gf_disabled = resp.tx_err_gf_disabled;
+ apc->eth_stats.hc_tx_err_vport_disabled = resp.tx_err_vport_disabled;
+ apc->eth_stats.hc_tx_err_inval_vportoffset_pkt =
+ resp.tx_err_inval_vport_offset_pkt;
+ apc->eth_stats.hc_tx_err_vlan_enforcement =
+ resp.tx_err_vlan_enforcement;
+ apc->eth_stats.hc_tx_err_eth_type_enforcement =
+ resp.tx_err_ethtype_enforcement;
+ apc->eth_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement;
+ apc->eth_stats.hc_tx_err_sqpdid_enforcement =
+ resp.tx_err_SQPDID_enforcement;
+ apc->eth_stats.hc_tx_err_cqpdid_enforcement =
+ resp.tx_err_CQPDID_enforcement;
+ apc->eth_stats.hc_tx_err_mtu_violation = resp.tx_err_mtu_violation;
+ apc->eth_stats.hc_tx_err_inval_oob = resp.tx_err_inval_oob;
apc->eth_stats.hc_tx_bytes = resp.hc_tx_bytes;
apc->eth_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts;
apc->eth_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes;
@@ -2414,6 +2460,7 @@ void mana_query_gf_stats(struct mana_port_context *apc)
apc->eth_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes;
apc->eth_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts;
apc->eth_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes;
+ apc->eth_stats.hc_tx_err_gdma = resp.tx_err_gdma;
}
static int mana_init_port(struct net_device *ndev)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 607150165ab4..ab2413d71f6c 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -13,6 +13,46 @@ static const struct {
} mana_eth_stats[] = {
{"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)},
{"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)},
+ {"hc_rx_discards_no_wqe", offsetof(struct mana_ethtool_stats,
+ hc_rx_discards_no_wqe)},
+ {"hc_rx_err_vport_disabled", offsetof(struct mana_ethtool_stats,
+ hc_rx_err_vport_disabled)},
+ {"hc_rx_bytes", offsetof(struct mana_ethtool_stats, hc_rx_bytes)},
+ {"hc_rx_ucast_pkts", offsetof(struct mana_ethtool_stats,
+ hc_rx_ucast_pkts)},
+ {"hc_rx_ucast_bytes", offsetof(struct mana_ethtool_stats,
+ hc_rx_ucast_bytes)},
+ {"hc_rx_bcast_pkts", offsetof(struct mana_ethtool_stats,
+ hc_rx_bcast_pkts)},
+ {"hc_rx_bcast_bytes", offsetof(struct mana_ethtool_stats,
+ hc_rx_bcast_bytes)},
+ {"hc_rx_mcast_pkts", offsetof(struct mana_ethtool_stats,
+ hc_rx_mcast_pkts)},
+ {"hc_rx_mcast_bytes", offsetof(struct mana_ethtool_stats,
+ hc_rx_mcast_bytes)},
+ {"hc_tx_err_gf_disabled", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_gf_disabled)},
+ {"hc_tx_err_vport_disabled", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_vport_disabled)},
+ {"hc_tx_err_inval_vportoffset_pkt",
+ offsetof(struct mana_ethtool_stats,
+ hc_tx_err_inval_vportoffset_pkt)},
+ {"hc_tx_err_vlan_enforcement", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_vlan_enforcement)},
+ {"hc_tx_err_eth_type_enforcement",
+ offsetof(struct mana_ethtool_stats, hc_tx_err_eth_type_enforcement)},
+ {"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_sa_enforcement)},
+ {"hc_tx_err_sqpdid_enforcement",
+ offsetof(struct mana_ethtool_stats, hc_tx_err_sqpdid_enforcement)},
+ {"hc_tx_err_cqpdid_enforcement",
+ offsetof(struct mana_ethtool_stats, hc_tx_err_cqpdid_enforcement)},
+ {"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_mtu_violation)},
+ {"hc_tx_err_inval_oob", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_inval_oob)},
+ {"hc_tx_err_gdma", offsetof(struct mana_ethtool_stats,
+ hc_tx_err_gdma)},
{"hc_tx_bytes", offsetof(struct mana_ethtool_stats, hc_tx_bytes)},
{"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_stats,
hc_tx_ucast_pkts)},
@@ -208,28 +248,28 @@ static u32 mana_rss_indir_size(struct net_device *ndev)
return MANA_INDIRECT_TABLE_SIZE;
}
-static int mana_get_rxfh(struct net_device *ndev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int mana_get_rxfh(struct net_device *ndev,
+ struct ethtool_rxfh_param *rxfh)
{
struct mana_port_context *apc = netdev_priv(ndev);
int i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
+ rxfh->hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++)
- indir[i] = apc->indir_table[i];
+ rxfh->indir[i] = apc->indir_table[i];
}
- if (key)
- memcpy(key, apc->hashkey, MANA_HASH_KEY_SIZE);
+ if (rxfh->key)
+ memcpy(rxfh->key, apc->hashkey, MANA_HASH_KEY_SIZE);
return 0;
}
-static int mana_set_rxfh(struct net_device *ndev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int mana_set_rxfh(struct net_device *ndev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct mana_port_context *apc = netdev_priv(ndev);
bool update_hash = false, update_table = false;
@@ -240,25 +280,26 @@ static int mana_set_rxfh(struct net_device *ndev, const u32 *indir,
if (!apc->port_is_up)
return -EOPNOTSUPP;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++)
- if (indir[i] >= apc->num_queues)
+ if (rxfh->indir[i] >= apc->num_queues)
return -EINVAL;
update_table = true;
for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) {
save_table[i] = apc->indir_table[i];
- apc->indir_table[i] = indir[i];
+ apc->indir_table[i] = rxfh->indir[i];
}
}
- if (key) {
+ if (rxfh->key) {
update_hash = true;
memcpy(save_key, apc->hashkey, MANA_HASH_KEY_SIZE);
- memcpy(apc->hashkey, key, MANA_HASH_KEY_SIZE);
+ memcpy(apc->hashkey, rxfh->key, MANA_HASH_KEY_SIZE);
}
err = mana_config_rss(apc, TRI_STATE_TRUE, update_hash, update_table);
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index 61d8bfd12d5f..55408f16fbbc 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -414,6 +414,7 @@ static const u64 fix_mac[] = {
END_SIGN
};
+MODULE_DESCRIPTION("Neterion 10GbE driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
index 2967bab72505..15180538b80a 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c
@@ -1424,10 +1424,30 @@ static void nfp_nft_ct_translate_mangle_action(struct flow_action_entry *mangle_
mangle_action->mangle.mask = (__force u32)cpu_to_be32(mangle_action->mangle.mask);
return;
+ /* Both struct tcphdr and struct udphdr start with
+ * __be16 source;
+ * __be16 dest;
+ * so we can use the same code for both.
+ */
case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
- mangle_action->mangle.val = (__force u16)cpu_to_be16(mangle_action->mangle.val);
- mangle_action->mangle.mask = (__force u16)cpu_to_be16(mangle_action->mangle.mask);
+ if (mangle_action->mangle.offset == offsetof(struct tcphdr, source)) {
+ mangle_action->mangle.val =
+ (__force u32)cpu_to_be32(mangle_action->mangle.val << 16);
+ /* The mask of mangle action is inverse mask,
+ * so clear the dest tp port with 0xFFFF to
+ * instead of rotate-left operation.
+ */
+ mangle_action->mangle.mask =
+ (__force u32)cpu_to_be32(mangle_action->mangle.mask << 16 | 0xFFFF);
+ }
+ if (mangle_action->mangle.offset == offsetof(struct tcphdr, dest)) {
+ mangle_action->mangle.offset = 0;
+ mangle_action->mangle.val =
+ (__force u32)cpu_to_be32(mangle_action->mangle.val);
+ mangle_action->mangle.mask =
+ (__force u32)cpu_to_be32(mangle_action->mangle.mask);
+ }
return;
default:
@@ -1864,10 +1884,30 @@ int nfp_fl_ct_handle_post_ct(struct nfp_flower_priv *priv,
{
struct flow_rule *rule = flow_cls_offload_flow_rule(flow);
struct nfp_fl_ct_flow_entry *ct_entry;
+ struct flow_action_entry *ct_goto;
struct nfp_fl_ct_zone_entry *zt;
+ struct flow_action_entry *act;
bool wildcarded = false;
struct flow_match_ct ct;
- struct flow_action_entry *ct_goto;
+ int i;
+
+ flow_action_for_each(i, act, &rule->action) {
+ switch (act->id) {
+ case FLOW_ACTION_REDIRECT:
+ case FLOW_ACTION_REDIRECT_INGRESS:
+ case FLOW_ACTION_MIRRED:
+ case FLOW_ACTION_MIRRED_INGRESS:
+ if (act->dev->rtnl_link_ops &&
+ !strcmp(act->dev->rtnl_link_ops->kind, "openvswitch")) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "unsupported offload: out port is openvswitch internal port");
+ return -EOPNOTSUPP;
+ }
+ break;
+ default:
+ break;
+ }
+ }
flow_rule_match_ct(rule, &ct);
if (!ct.mask->ct_zone) {
diff --git a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
index 88d6d992e7d0..361d7c495e2d 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/lag_conf.c
@@ -76,7 +76,7 @@ struct nfp_fl_lag_group {
/* Use this ID with zero members to ack a batch config */
#define NFP_FL_LAG_SYNC_ID 0
#define NFP_FL_LAG_GROUP_MIN 1 /* ID 0 reserved */
-#define NFP_FL_LAG_GROUP_MAX 32 /* IDs 1 to 31 are valid */
+#define NFP_FL_LAG_GROUP_MAX 31 /* IDs 1 to 31 are valid */
/* wait for more config */
#define NFP_FL_LAG_DELAY (msecs_to_jiffies(2))
@@ -111,8 +111,8 @@ nfp_fl_lag_group_create(struct nfp_fl_lag *lag, struct net_device *master)
priv = container_of(lag, struct nfp_flower_priv, nfp_lag);
- id = ida_simple_get(&lag->ida_handle, NFP_FL_LAG_GROUP_MIN,
- NFP_FL_LAG_GROUP_MAX, GFP_KERNEL);
+ id = ida_alloc_range(&lag->ida_handle, NFP_FL_LAG_GROUP_MIN,
+ NFP_FL_LAG_GROUP_MAX, GFP_KERNEL);
if (id < 0) {
nfp_flower_cmsg_warn(priv->app,
"No more bonding groups available\n");
@@ -121,7 +121,7 @@ nfp_fl_lag_group_create(struct nfp_fl_lag *lag, struct net_device *master)
group = kmalloc(sizeof(*group), GFP_KERNEL);
if (!group) {
- ida_simple_remove(&lag->ida_handle, id);
+ ida_free(&lag->ida_handle, id);
return ERR_PTR(-ENOMEM);
}
@@ -328,8 +328,7 @@ static void nfp_fl_lag_do_work(struct work_struct *work)
}
if (entry->to_destroy) {
- ida_simple_remove(&lag->ida_handle,
- entry->group_id);
+ ida_free(&lag->ida_handle, entry->group_id);
list_del(&entry->list);
kfree(entry);
}
@@ -415,7 +414,7 @@ nfp_fl_lag_put_unprocessed(struct nfp_fl_lag *lag, struct sk_buff *skb)
struct nfp_flower_cmsg_lag_config *cmsg_payload;
cmsg_payload = nfp_flower_cmsg_get_data(skb);
- if (be32_to_cpu(cmsg_payload->group_id) >= NFP_FL_LAG_GROUP_MAX)
+ if (be32_to_cpu(cmsg_payload->group_id) > NFP_FL_LAG_GROUP_MAX)
return -EINVAL;
/* Drop cmsg retrans if storage limit is exceeded to prevent
diff --git a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
index e522845c7c21..0d7d138d6e0d 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
@@ -1084,7 +1084,7 @@ nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev,
u16 nfp_mac_idx = 0;
entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr);
- if (entry && nfp_tunnel_is_mac_idx_global(entry->index)) {
+ if (entry && (nfp_tunnel_is_mac_idx_global(entry->index) || netif_is_lag_port(netdev))) {
if (entry->bridge_count ||
!nfp_flower_is_supported_bridge(netdev)) {
nfp_tunnel_offloaded_macs_inc_ref_and_link(entry,
diff --git a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c
index 17381bfc15d7..d215efc6cad0 100644
--- a/drivers/net/ethernet/netronome/nfp/nfd3/dp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfd3/dp.c
@@ -74,7 +74,7 @@ static void
nfp_nfd3_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfd3_tx_buf *txbuf,
struct nfp_nfd3_tx_desc *txd, struct sk_buff *skb, u32 md_bytes)
{
- u32 l3_offset, l4_offset, hdrlen;
+ u32 l3_offset, l4_offset, hdrlen, l4_hdrlen;
u16 mss;
if (!skb_is_gso(skb))
@@ -83,13 +83,16 @@ 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_tcp_all_headers(skb);
+ l4_hdrlen = (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ?
+ sizeof(struct udphdr) : tcp_hdrlen(skb);
} else {
l3_offset = skb_inner_network_offset(skb);
l4_offset = skb_inner_transport_offset(skb);
- hdrlen = skb_inner_tcp_all_headers(skb);
+ l4_hdrlen = (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ?
+ sizeof(struct udphdr) : inner_tcp_hdrlen(skb);
}
+ hdrlen = l4_offset + l4_hdrlen;
txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs;
txbuf->real_len += hdrlen * (txbuf->pkt_cnt - 1);
diff --git a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
index 8d78c6faefa8..dae5af7d1845 100644
--- a/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
+++ b/drivers/net/ethernet/netronome/nfp/nfdk/dp.c
@@ -40,20 +40,23 @@ static __le64
nfp_nfdk_tx_tso(struct nfp_net_r_vector *r_vec, struct nfp_nfdk_tx_buf *txbuf,
struct sk_buff *skb)
{
- u32 segs, hdrlen, l3_offset, l4_offset;
+ u32 segs, hdrlen, l3_offset, l4_offset, l4_hdrlen;
struct nfp_nfdk_tx_desc txd;
u16 mss;
if (!skb->encapsulation) {
l3_offset = skb_network_offset(skb);
l4_offset = skb_transport_offset(skb);
- hdrlen = skb_tcp_all_headers(skb);
+ l4_hdrlen = (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ?
+ sizeof(struct udphdr) : tcp_hdrlen(skb);
} else {
l3_offset = skb_inner_network_offset(skb);
l4_offset = skb_inner_transport_offset(skb);
- hdrlen = skb_inner_tcp_all_headers(skb);
+ l4_hdrlen = (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ?
+ sizeof(struct udphdr) : inner_tcp_hdrlen(skb);
}
+ hdrlen = l4_offset + l4_hdrlen;
segs = skb_shinfo(skb)->gso_segs;
mss = skb_shinfo(skb)->gso_size & NFDK_DESC_TX_MSS_MASK;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
index 8c6954c58a88..635d33c0d6d3 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c
@@ -75,8 +75,10 @@ nfp_devlink_port_split(struct devlink *devlink, struct devlink_port *port,
if (ret)
return ret;
- if (eth_port.port_lanes % count)
+ if (eth_port.port_lanes % count) {
+ NL_SET_ERR_MSG_MOD(extack, "invalid count");
return -EINVAL;
+ }
/* Special case the 100G CXP -> 2x40G split */
lanes = eth_port.port_lanes / count;
@@ -101,8 +103,10 @@ nfp_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port,
if (ret)
return ret;
- if (!eth_port.is_split)
+ if (!eth_port.is_split) {
+ NL_SET_ERR_MSG_MOD(extack, "port is not split");
return -EINVAL;
+ }
/* Special case the 100G CXP -> 2x40G unsplit */
lanes = eth_port.port_lanes;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index 939cfce15830..46764aeccb37 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -621,6 +621,9 @@ struct nfp_net_dp {
* @mbox_amsg.lock: Protect message list
* @mbox_amsg.list: List of message to process
* @mbox_amsg.work: Work to process message asynchronously
+ * @fs: Flow steering
+ * @fs.count: Flow count
+ * @fs.list: List of flows
* @app_priv: APP private data for this vNIC
*/
struct nfp_net {
@@ -728,9 +731,39 @@ struct nfp_net {
struct work_struct work;
} mbox_amsg;
+ struct {
+ u16 count;
+ struct list_head list;
+ } fs;
+
void *app_priv;
};
+struct nfp_fs_entry {
+ struct list_head node;
+ u32 flow_type;
+ u32 loc;
+ struct {
+ union {
+ struct {
+ __be32 sip4;
+ __be32 dip4;
+ };
+ struct {
+ __be32 sip6[4];
+ __be32 dip6[4];
+ };
+ };
+ union {
+ __be16 l3_proto;
+ u8 l4_proto;
+ };
+ __be16 sport;
+ __be16 dport;
+ } key, msk;
+ u64 action;
+};
+
struct nfp_mbox_amsg_entry {
struct list_head list;
int (*cfg)(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry);
@@ -933,9 +966,9 @@ static inline bool nfp_netdev_is_nfp_net(struct net_device *netdev)
netdev->netdev_ops == &nfp_nfdk_netdev_ops;
}
-static inline int nfp_net_coalesce_para_check(u32 usecs, u32 pkts)
+static inline int nfp_net_coalesce_para_check(u32 param)
{
- if ((usecs >= ((1 << 16) - 1)) || (pkts >= ((1 << 16) - 1)))
+ if (param >= ((1 << 16) - 1))
return -EINVAL;
return 0;
@@ -987,6 +1020,9 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn);
int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new,
struct netlink_ext_ack *extack);
+int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry);
+int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry);
+
#ifdef CONFIG_NFP_DEBUG
void nfp_net_debugfs_create(void);
void nfp_net_debugfs_destroy(void);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index de0a5d5ded30..f28e769e6fda 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -1176,7 +1176,8 @@ static void nfp_net_rx_dim_work(struct work_struct *work)
* count.
*/
factor = nn->tlv_caps.me_freq_mhz / 16;
- if (nfp_net_coalesce_para_check(factor * moder.usec, moder.pkts))
+ if (nfp_net_coalesce_para_check(factor * moder.usec) ||
+ nfp_net_coalesce_para_check(moder.pkts))
return;
/* copy RX interrupt coalesce parameters */
@@ -1205,7 +1206,8 @@ static void nfp_net_tx_dim_work(struct work_struct *work)
* count.
*/
factor = nn->tlv_caps.me_freq_mhz / 16;
- if (nfp_net_coalesce_para_check(factor * moder.usec, moder.pkts))
+ if (nfp_net_coalesce_para_check(factor * moder.usec) ||
+ nfp_net_coalesce_para_check(moder.pkts))
return;
/* copy TX interrupt coalesce parameters */
@@ -1763,6 +1765,186 @@ nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
}
+static void
+nfp_net_fs_fill_v4(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr)
+{
+ unsigned int i;
+
+ union {
+ struct {
+ __be16 loc;
+ u8 k_proto, m_proto;
+ __be32 k_sip, m_sip, k_dip, m_dip;
+ __be16 k_sport, m_sport, k_dport, m_dport;
+ };
+ __be32 val[7];
+ } v4_rule;
+
+ nn_writel(nn, *addr, op);
+ *addr += sizeof(u32);
+
+ v4_rule.loc = cpu_to_be16(entry->loc);
+ v4_rule.k_proto = entry->key.l4_proto;
+ v4_rule.m_proto = entry->msk.l4_proto;
+ v4_rule.k_sip = entry->key.sip4;
+ v4_rule.m_sip = entry->msk.sip4;
+ v4_rule.k_dip = entry->key.dip4;
+ v4_rule.m_dip = entry->msk.dip4;
+ v4_rule.k_sport = entry->key.sport;
+ v4_rule.m_sport = entry->msk.sport;
+ v4_rule.k_dport = entry->key.dport;
+ v4_rule.m_dport = entry->msk.dport;
+
+ for (i = 0; i < ARRAY_SIZE(v4_rule.val); i++, *addr += sizeof(__be32))
+ nn_writel(nn, *addr, be32_to_cpu(v4_rule.val[i]));
+}
+
+static void
+nfp_net_fs_fill_v6(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr)
+{
+ unsigned int i;
+
+ union {
+ struct {
+ __be16 loc;
+ u8 k_proto, m_proto;
+ __be32 k_sip[4], m_sip[4], k_dip[4], m_dip[4];
+ __be16 k_sport, m_sport, k_dport, m_dport;
+ };
+ __be32 val[19];
+ } v6_rule;
+
+ nn_writel(nn, *addr, op);
+ *addr += sizeof(u32);
+
+ v6_rule.loc = cpu_to_be16(entry->loc);
+ v6_rule.k_proto = entry->key.l4_proto;
+ v6_rule.m_proto = entry->msk.l4_proto;
+ for (i = 0; i < 4; i++) {
+ v6_rule.k_sip[i] = entry->key.sip6[i];
+ v6_rule.m_sip[i] = entry->msk.sip6[i];
+ v6_rule.k_dip[i] = entry->key.dip6[i];
+ v6_rule.m_dip[i] = entry->msk.dip6[i];
+ }
+ v6_rule.k_sport = entry->key.sport;
+ v6_rule.m_sport = entry->msk.sport;
+ v6_rule.k_dport = entry->key.dport;
+ v6_rule.m_dport = entry->msk.dport;
+
+ for (i = 0; i < ARRAY_SIZE(v6_rule.val); i++, *addr += sizeof(__be32))
+ nn_writel(nn, *addr, be32_to_cpu(v6_rule.val[i]));
+}
+
+#define NFP_FS_QUEUE_ID GENMASK(22, 16)
+#define NFP_FS_ACT GENMASK(15, 0)
+#define NFP_FS_ACT_DROP BIT(0)
+#define NFP_FS_ACT_Q BIT(1)
+static void
+nfp_net_fs_fill_act(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 addr)
+{
+ u32 action = 0; /* 0 means default passthrough */
+
+ if (entry->action == RX_CLS_FLOW_DISC)
+ action = NFP_FS_ACT_DROP;
+ else if (!(entry->flow_type & FLOW_RSS))
+ action = FIELD_PREP(NFP_FS_QUEUE_ID, entry->action) | NFP_FS_ACT_Q;
+
+ nn_writel(nn, addr, action);
+}
+
+int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry)
+{
+ u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
+ int err;
+
+ err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ);
+ if (err)
+ return err;
+
+ switch (entry->flow_type & ~FLOW_RSS) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ case IPV4_USER_FLOW:
+ nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V4, &addr);
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ case IPV6_USER_FLOW:
+ nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V6, &addr);
+ break;
+ case ETHER_FLOW:
+ nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE);
+ addr += sizeof(u32);
+ nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto));
+ addr += sizeof(u32);
+ break;
+ }
+
+ nfp_net_fs_fill_act(nn, entry, addr);
+
+ err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER);
+ if (err) {
+ nn_err(nn, "Add new fs rule failed with %d\n", err);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry)
+{
+ u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
+ int err;
+
+ err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ);
+ if (err)
+ return err;
+
+ switch (entry->flow_type & ~FLOW_RSS) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ case IPV4_USER_FLOW:
+ nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V4, &addr);
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ case IPV6_USER_FLOW:
+ nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V6, &addr);
+ break;
+ case ETHER_FLOW:
+ nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE);
+ addr += sizeof(u32);
+ nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto));
+ addr += sizeof(u32);
+ break;
+ }
+
+ nfp_net_fs_fill_act(nn, entry, addr);
+
+ err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER);
+ if (err) {
+ nn_err(nn, "Delete fs rule failed with %d\n", err);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void nfp_net_fs_clean(struct nfp_net *nn)
+{
+ struct nfp_fs_entry *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &nn->fs.list, node) {
+ nfp_net_fs_del_hw(nn, entry);
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
static void nfp_net_stat64(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
@@ -1934,7 +2116,10 @@ nfp_net_features_check(struct sk_buff *skb, struct net_device *dev,
if (skb_is_gso(skb)) {
u32 hdrlen;
- hdrlen = skb_inner_tcp_all_headers(skb);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)
+ hdrlen = skb_inner_transport_offset(skb) + sizeof(struct udphdr);
+ else
+ hdrlen = skb_inner_tcp_all_headers(skb);
/* Assume worst case scenario of having longest possible
* metadata prepend - 8B
@@ -2237,7 +2422,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%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%s%s\n",
nn->cap,
nn->cap & NFP_NET_CFG_CTRL_PROMISC ? "PROMISC " : "",
nn->cap & NFP_NET_CFG_CTRL_L2BC ? "L2BCFILT " : "",
@@ -2266,6 +2451,7 @@ void nfp_net_info(struct nfp_net *nn)
"RXCSUM_COMPLETE " : "",
nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "",
nn->cap_w1 & NFP_NET_CFG_CTRL_MCAST_FILTER ? "MULTICAST_FILTER " : "",
+ nn->cap_w1 & NFP_NET_CFG_CTRL_USO ? "USO " : "",
nfp_app_extra_cap(nn->app, nn));
}
@@ -2514,6 +2700,8 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
if ((nn->cap & NFP_NET_CFG_CTRL_LSO && nn->fw_ver.major > 2) ||
nn->cap & NFP_NET_CFG_CTRL_LSO2) {
netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
+ if (nn->cap_w1 & NFP_NET_CFG_CTRL_USO)
+ netdev->hw_features |= NETIF_F_GSO_UDP_L4;
nn->dp.ctrl |= nn->cap & NFP_NET_CFG_CTRL_LSO2 ?:
NFP_NET_CFG_CTRL_LSO;
}
@@ -2588,6 +2776,7 @@ static void nfp_net_netdev_init(struct nfp_net *nn)
case NFP_NFD_VER_NFD3:
netdev->netdev_ops = &nfp_nfd3_netdev_ops;
netdev->xdp_features |= NETDEV_XDP_ACT_XSK_ZEROCOPY;
+ netdev->xdp_features |= NETDEV_XDP_ACT_REDIRECT;
break;
case NFP_NFD_VER_NFDK:
netdev->netdev_ops = &nfp_nfdk_netdev_ops;
@@ -2740,6 +2929,8 @@ int nfp_net_init(struct nfp_net *nn)
INIT_LIST_HEAD(&nn->mbox_amsg.list);
INIT_WORK(&nn->mbox_amsg.work, nfp_net_mbox_amsg_work);
+ INIT_LIST_HEAD(&nn->fs.list);
+
return register_netdev(nn->dp.netdev);
err_clean_mbox:
@@ -2759,6 +2950,7 @@ void nfp_net_clean(struct nfp_net *nn)
unregister_netdev(nn->dp.netdev);
nfp_net_ipsec_clean(nn);
nfp_ccm_mbox_clean(nn);
+ nfp_net_fs_clean(nn);
flush_work(&nn->mbox_amsg.work);
nfp_net_reconfig_wait_posted(nn);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
index 3e63f6d6a563..634c63c7f7eb 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
@@ -269,6 +269,8 @@
#define NFP_NET_CFG_CTRL_IPSEC (0x1 << 1) /* IPsec offload */
#define NFP_NET_CFG_CTRL_MCAST_FILTER (0x1 << 2) /* Multicast Filter */
#define NFP_NET_CFG_CTRL_FREELIST_EN (0x1 << 6) /* Freelist enable flag bit */
+#define NFP_NET_CFG_CTRL_FLOW_STEER (0x1 << 8) /* Flow steering */
+#define NFP_NET_CFG_CTRL_USO (0x1 << 16) /* UDP segmentation offload */
#define NFP_NET_CFG_CAP_WORD1 0x00a4
@@ -418,6 +420,8 @@
#define NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD 8
#define NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL 9
+#define NFP_NET_CFG_MBOX_CMD_FLOW_STEER 10
+
/* VLAN filtering using general use mailbox
* %NFP_NET_CFG_VLAN_FILTER: Base address of VLAN filter mailbox
* %NFP_NET_CFG_VLAN_FILTER_VID: VLAN ID to filter
@@ -440,6 +444,18 @@
#define NFP_NET_CFG_MULTICAST_MAC_LO (NFP_NET_CFG_MULTICAST + 6)
#define NFP_NET_CFG_MULTICAST_SZ 0x0006
+/* Max size of FS rules in bytes */
+#define NFP_NET_CFG_FS_SZ 0x0054
+/* Sub commands for FS */
+enum {
+ NFP_NET_CFG_MBOX_CMD_FS_ADD_V4,
+ NFP_NET_CFG_MBOX_CMD_FS_DEL_V4,
+ NFP_NET_CFG_MBOX_CMD_FS_ADD_V6,
+ NFP_NET_CFG_MBOX_CMD_FS_DEL_V6,
+ NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE,
+ NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE,
+};
+
/* TLV capabilities
* %NFP_NET_CFG_TLV_TYPE: Offset of type within the TLV
* %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index e75cbb287625..fbca8d0efd85 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -633,7 +633,8 @@ static void nfp_net_get_ringparam(struct net_device *netdev,
ring->tx_pending = nn->dp.txd_cnt;
}
-static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
+static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt,
+ struct netlink_ext_ack *extack)
{
struct nfp_net_dp *dp;
@@ -644,7 +645,7 @@ static int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt)
dp->rxd_cnt = rxd_cnt;
dp->txd_cnt = txd_cnt;
- return nfp_net_ring_reconfig(nn, dp, NULL);
+ return nfp_net_ring_reconfig(nn, dp, extack);
}
static int nfp_net_set_ringparam(struct net_device *netdev,
@@ -657,7 +658,7 @@ static int nfp_net_set_ringparam(struct net_device *netdev,
/* We don't have separate queues/rings for small/large frames. */
if (ring->rx_mini_pending || ring->rx_jumbo_pending)
- return -EINVAL;
+ return -EOPNOTSUPP;
qc_min = nn->dev_info->min_qc_size;
qc_max = nn->dev_info->max_qc_size;
@@ -666,9 +667,15 @@ static int nfp_net_set_ringparam(struct net_device *netdev,
rxd_cnt = roundup_pow_of_two(ring->rx_pending);
txd_cnt = roundup_pow_of_two(ring->tx_pending);
- if (rxd_cnt < qc_min || rxd_cnt > qc_max ||
- txd_cnt < qc_min / tx_dpp || txd_cnt > qc_max / tx_dpp)
+ if (rxd_cnt < qc_min || rxd_cnt > qc_max) {
+ NL_SET_ERR_MSG_MOD(extack, "rx parameter out of bounds");
return -EINVAL;
+ }
+
+ if (txd_cnt < qc_min / tx_dpp || txd_cnt > qc_max / tx_dpp) {
+ NL_SET_ERR_MSG_MOD(extack, "tx parameter out of bounds");
+ return -EINVAL;
+ }
if (nn->dp.rxd_cnt == rxd_cnt && nn->dp.txd_cnt == txd_cnt)
return 0;
@@ -676,7 +683,7 @@ static int nfp_net_set_ringparam(struct net_device *netdev,
nn_dbg(nn, "Change ring size: RxQ %u->%u, TxQ %u->%u\n",
nn->dp.rxd_cnt, rxd_cnt, nn->dp.txd_cnt, txd_cnt);
- return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt);
+ return nfp_net_set_ring_size(nn, rxd_cnt, txd_cnt, extack);
}
static int nfp_test_link(struct net_device *netdev)
@@ -800,7 +807,7 @@ static void nfp_get_self_test_strings(struct net_device *netdev, u8 *data)
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);
+ ethtool_puts(&data, nfp_self_test[i].name);
}
static int nfp_get_self_test_count(struct net_device *netdev)
@@ -852,24 +859,24 @@ static u8 *nfp_vnic_get_sw_stats_strings(struct net_device *netdev, u8 *data)
ethtool_sprintf(&data, "rvec_%u_tx_busy", i);
}
- ethtool_sprintf(&data, "hw_rx_csum_ok");
- ethtool_sprintf(&data, "hw_rx_csum_inner_ok");
- ethtool_sprintf(&data, "hw_rx_csum_complete");
- ethtool_sprintf(&data, "hw_rx_csum_err");
- ethtool_sprintf(&data, "rx_replace_buf_alloc_fail");
- ethtool_sprintf(&data, "rx_tls_decrypted_packets");
- ethtool_sprintf(&data, "hw_tx_csum");
- ethtool_sprintf(&data, "hw_tx_inner_csum");
- ethtool_sprintf(&data, "tx_gather");
- ethtool_sprintf(&data, "tx_lso");
- ethtool_sprintf(&data, "tx_tls_encrypted_packets");
- ethtool_sprintf(&data, "tx_tls_ooo");
- ethtool_sprintf(&data, "tx_tls_drop_no_sync_data");
-
- ethtool_sprintf(&data, "hw_tls_no_space");
- ethtool_sprintf(&data, "rx_tls_resync_req_ok");
- ethtool_sprintf(&data, "rx_tls_resync_req_ign");
- ethtool_sprintf(&data, "rx_tls_resync_sent");
+ ethtool_puts(&data, "hw_rx_csum_ok");
+ ethtool_puts(&data, "hw_rx_csum_inner_ok");
+ ethtool_puts(&data, "hw_rx_csum_complete");
+ ethtool_puts(&data, "hw_rx_csum_err");
+ ethtool_puts(&data, "rx_replace_buf_alloc_fail");
+ ethtool_puts(&data, "rx_tls_decrypted_packets");
+ ethtool_puts(&data, "hw_tx_csum");
+ ethtool_puts(&data, "hw_tx_inner_csum");
+ ethtool_puts(&data, "tx_gather");
+ ethtool_puts(&data, "tx_lso");
+ ethtool_puts(&data, "tx_tls_encrypted_packets");
+ ethtool_puts(&data, "tx_tls_ooo");
+ ethtool_puts(&data, "tx_tls_drop_no_sync_data");
+
+ ethtool_puts(&data, "hw_tls_no_space");
+ ethtool_puts(&data, "rx_tls_resync_req_ok");
+ ethtool_puts(&data, "rx_tls_resync_req_ign");
+ ethtool_puts(&data, "rx_tls_resync_sent");
return data;
}
@@ -943,13 +950,13 @@ nfp_vnic_get_hw_stats_strings(u8 *data, unsigned int num_vecs, bool repr)
swap_off = repr * NN_ET_SWITCH_STATS_LEN;
for (i = 0; i < NN_ET_SWITCH_STATS_LEN; i++)
- ethtool_sprintf(&data, nfp_net_et_stats[i + swap_off].name);
+ ethtool_puts(&data, nfp_net_et_stats[i + swap_off].name);
for (i = NN_ET_SWITCH_STATS_LEN; i < NN_ET_SWITCH_STATS_LEN * 2; i++)
- ethtool_sprintf(&data, nfp_net_et_stats[i - swap_off].name);
+ ethtool_puts(&data, nfp_net_et_stats[i - swap_off].name);
for (i = NN_ET_SWITCH_STATS_LEN * 2; i < NN_ET_GLOBAL_STATS_LEN; i++)
- ethtool_sprintf(&data, nfp_net_et_stats[i].name);
+ ethtool_puts(&data, nfp_net_et_stats[i].name);
for (i = 0; i < num_vecs; i++) {
ethtool_sprintf(&data, "rxq_%u_pkts", i);
@@ -1317,6 +1324,116 @@ static int nfp_net_get_rss_hash_opts(struct nfp_net *nn,
return 0;
}
+#define NFP_FS_MAX_ENTRY 1024
+
+static int nfp_net_fs_to_ethtool(struct nfp_fs_entry *entry, struct ethtool_rxnfc *cmd)
+{
+ struct ethtool_rx_flow_spec *fs = &cmd->fs;
+ unsigned int i;
+
+ switch (entry->flow_type & ~FLOW_RSS) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ fs->h_u.tcp_ip4_spec.ip4src = entry->key.sip4;
+ fs->h_u.tcp_ip4_spec.ip4dst = entry->key.dip4;
+ fs->h_u.tcp_ip4_spec.psrc = entry->key.sport;
+ fs->h_u.tcp_ip4_spec.pdst = entry->key.dport;
+ fs->m_u.tcp_ip4_spec.ip4src = entry->msk.sip4;
+ fs->m_u.tcp_ip4_spec.ip4dst = entry->msk.dip4;
+ fs->m_u.tcp_ip4_spec.psrc = entry->msk.sport;
+ fs->m_u.tcp_ip4_spec.pdst = entry->msk.dport;
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ for (i = 0; i < 4; i++) {
+ fs->h_u.tcp_ip6_spec.ip6src[i] = entry->key.sip6[i];
+ fs->h_u.tcp_ip6_spec.ip6dst[i] = entry->key.dip6[i];
+ fs->m_u.tcp_ip6_spec.ip6src[i] = entry->msk.sip6[i];
+ fs->m_u.tcp_ip6_spec.ip6dst[i] = entry->msk.dip6[i];
+ }
+ fs->h_u.tcp_ip6_spec.psrc = entry->key.sport;
+ fs->h_u.tcp_ip6_spec.pdst = entry->key.dport;
+ fs->m_u.tcp_ip6_spec.psrc = entry->msk.sport;
+ fs->m_u.tcp_ip6_spec.pdst = entry->msk.dport;
+ break;
+ case IPV4_USER_FLOW:
+ fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+ fs->h_u.usr_ip4_spec.ip4src = entry->key.sip4;
+ fs->h_u.usr_ip4_spec.ip4dst = entry->key.dip4;
+ fs->h_u.usr_ip4_spec.proto = entry->key.l4_proto;
+ fs->m_u.usr_ip4_spec.ip4src = entry->msk.sip4;
+ fs->m_u.usr_ip4_spec.ip4dst = entry->msk.dip4;
+ fs->m_u.usr_ip4_spec.proto = entry->msk.l4_proto;
+ break;
+ case IPV6_USER_FLOW:
+ for (i = 0; i < 4; i++) {
+ fs->h_u.usr_ip6_spec.ip6src[i] = entry->key.sip6[i];
+ fs->h_u.usr_ip6_spec.ip6dst[i] = entry->key.dip6[i];
+ fs->m_u.usr_ip6_spec.ip6src[i] = entry->msk.sip6[i];
+ fs->m_u.usr_ip6_spec.ip6dst[i] = entry->msk.dip6[i];
+ }
+ fs->h_u.usr_ip6_spec.l4_proto = entry->key.l4_proto;
+ fs->m_u.usr_ip6_spec.l4_proto = entry->msk.l4_proto;
+ break;
+ case ETHER_FLOW:
+ fs->h_u.ether_spec.h_proto = entry->key.l3_proto;
+ fs->m_u.ether_spec.h_proto = entry->msk.l3_proto;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ fs->flow_type = entry->flow_type;
+ fs->ring_cookie = entry->action;
+
+ if (fs->flow_type & FLOW_RSS) {
+ /* Only rss_context of 0 is supported. */
+ cmd->rss_context = 0;
+ /* RSS is used, mask the ring. */
+ fs->ring_cookie |= ETHTOOL_RX_FLOW_SPEC_RING;
+ }
+
+ return 0;
+}
+
+static int nfp_net_get_fs_rule(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
+{
+ struct nfp_fs_entry *entry;
+
+ if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
+ return -EOPNOTSUPP;
+
+ if (cmd->fs.location >= NFP_FS_MAX_ENTRY)
+ return -EINVAL;
+
+ list_for_each_entry(entry, &nn->fs.list, node) {
+ if (entry->loc == cmd->fs.location)
+ return nfp_net_fs_to_ethtool(entry, cmd);
+
+ if (entry->loc > cmd->fs.location)
+ /* no need to continue */
+ return -ENOENT;
+ }
+
+ return -ENOENT;
+}
+
+static int nfp_net_get_fs_loc(struct nfp_net *nn, u32 *rule_locs)
+{
+ struct nfp_fs_entry *entry;
+ u32 count = 0;
+
+ if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
+ return -EOPNOTSUPP;
+
+ list_for_each_entry(entry, &nn->fs.list, node)
+ rule_locs[count++] = entry->loc;
+
+ return 0;
+}
+
static int nfp_net_get_rxnfc(struct net_device *netdev,
struct ethtool_rxnfc *cmd, u32 *rule_locs)
{
@@ -1326,6 +1443,14 @@ static int nfp_net_get_rxnfc(struct net_device *netdev,
case ETHTOOL_GRXRINGS:
cmd->data = nn->dp.num_rx_rings;
return 0;
+ case ETHTOOL_GRXCLSRLCNT:
+ cmd->rule_cnt = nn->fs.count;
+ return 0;
+ case ETHTOOL_GRXCLSRULE:
+ return nfp_net_get_fs_rule(nn, cmd);
+ case ETHTOOL_GRXCLSRLALL:
+ cmd->data = NFP_FS_MAX_ENTRY;
+ return nfp_net_get_fs_loc(nn, rule_locs);
case ETHTOOL_GRXFH:
return nfp_net_get_rss_hash_opts(nn, cmd);
default:
@@ -1385,6 +1510,253 @@ static int nfp_net_set_rss_hash_opt(struct nfp_net *nn,
return 0;
}
+static int nfp_net_fs_from_ethtool(struct nfp_fs_entry *entry, struct ethtool_rx_flow_spec *fs)
+{
+ unsigned int i;
+
+ /* FLOW_EXT/FLOW_MAC_EXT is not supported. */
+ switch (fs->flow_type & ~FLOW_RSS) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ entry->msk.sip4 = fs->m_u.tcp_ip4_spec.ip4src;
+ entry->msk.dip4 = fs->m_u.tcp_ip4_spec.ip4dst;
+ entry->msk.sport = fs->m_u.tcp_ip4_spec.psrc;
+ entry->msk.dport = fs->m_u.tcp_ip4_spec.pdst;
+ entry->key.sip4 = fs->h_u.tcp_ip4_spec.ip4src & entry->msk.sip4;
+ entry->key.dip4 = fs->h_u.tcp_ip4_spec.ip4dst & entry->msk.dip4;
+ entry->key.sport = fs->h_u.tcp_ip4_spec.psrc & entry->msk.sport;
+ entry->key.dport = fs->h_u.tcp_ip4_spec.pdst & entry->msk.dport;
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ for (i = 0; i < 4; i++) {
+ entry->msk.sip6[i] = fs->m_u.tcp_ip6_spec.ip6src[i];
+ entry->msk.dip6[i] = fs->m_u.tcp_ip6_spec.ip6dst[i];
+ entry->key.sip6[i] = fs->h_u.tcp_ip6_spec.ip6src[i] & entry->msk.sip6[i];
+ entry->key.dip6[i] = fs->h_u.tcp_ip6_spec.ip6dst[i] & entry->msk.dip6[i];
+ }
+ entry->msk.sport = fs->m_u.tcp_ip6_spec.psrc;
+ entry->msk.dport = fs->m_u.tcp_ip6_spec.pdst;
+ entry->key.sport = fs->h_u.tcp_ip6_spec.psrc & entry->msk.sport;
+ entry->key.dport = fs->h_u.tcp_ip6_spec.pdst & entry->msk.dport;
+ break;
+ case IPV4_USER_FLOW:
+ entry->msk.sip4 = fs->m_u.usr_ip4_spec.ip4src;
+ entry->msk.dip4 = fs->m_u.usr_ip4_spec.ip4dst;
+ entry->msk.l4_proto = fs->m_u.usr_ip4_spec.proto;
+ entry->key.sip4 = fs->h_u.usr_ip4_spec.ip4src & entry->msk.sip4;
+ entry->key.dip4 = fs->h_u.usr_ip4_spec.ip4dst & entry->msk.dip4;
+ entry->key.l4_proto = fs->h_u.usr_ip4_spec.proto & entry->msk.l4_proto;
+ break;
+ case IPV6_USER_FLOW:
+ for (i = 0; i < 4; i++) {
+ entry->msk.sip6[i] = fs->m_u.usr_ip6_spec.ip6src[i];
+ entry->msk.dip6[i] = fs->m_u.usr_ip6_spec.ip6dst[i];
+ entry->key.sip6[i] = fs->h_u.usr_ip6_spec.ip6src[i] & entry->msk.sip6[i];
+ entry->key.dip6[i] = fs->h_u.usr_ip6_spec.ip6dst[i] & entry->msk.dip6[i];
+ }
+ entry->msk.l4_proto = fs->m_u.usr_ip6_spec.l4_proto;
+ entry->key.l4_proto = fs->h_u.usr_ip6_spec.l4_proto & entry->msk.l4_proto;
+ break;
+ case ETHER_FLOW:
+ entry->msk.l3_proto = fs->m_u.ether_spec.h_proto;
+ entry->key.l3_proto = fs->h_u.ether_spec.h_proto & entry->msk.l3_proto;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fs->flow_type & ~FLOW_RSS) {
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ entry->key.l4_proto = IPPROTO_TCP;
+ entry->msk.l4_proto = 0xff;
+ break;
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ entry->key.l4_proto = IPPROTO_UDP;
+ entry->msk.l4_proto = 0xff;
+ break;
+ case SCTP_V4_FLOW:
+ case SCTP_V6_FLOW:
+ entry->key.l4_proto = IPPROTO_SCTP;
+ entry->msk.l4_proto = 0xff;
+ break;
+ }
+
+ entry->flow_type = fs->flow_type;
+ entry->action = fs->ring_cookie;
+ entry->loc = fs->location;
+
+ return 0;
+}
+
+static int nfp_net_fs_check_existing(struct nfp_net *nn, struct nfp_fs_entry *new)
+{
+ struct nfp_fs_entry *entry;
+
+ list_for_each_entry(entry, &nn->fs.list, node) {
+ if (new->loc != entry->loc &&
+ !((new->flow_type ^ entry->flow_type) & ~FLOW_RSS) &&
+ !memcmp(&new->key, &entry->key, sizeof(new->key)) &&
+ !memcmp(&new->msk, &entry->msk, sizeof(new->msk)))
+ return entry->loc;
+ }
+
+ /* -1 means no duplicates */
+ return -1;
+}
+
+static int nfp_net_fs_add(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
+{
+ struct ethtool_rx_flow_spec *fs = &cmd->fs;
+ struct nfp_fs_entry *new, *entry;
+ bool unsupp_mask;
+ int err, id;
+
+ if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
+ return -EOPNOTSUPP;
+
+ /* Only default RSS context(0) is supported. */
+ if ((fs->flow_type & FLOW_RSS) && cmd->rss_context)
+ return -EOPNOTSUPP;
+
+ if (fs->location >= NFP_FS_MAX_ENTRY)
+ return -EINVAL;
+
+ if (fs->ring_cookie != RX_CLS_FLOW_DISC &&
+ fs->ring_cookie >= nn->dp.num_rx_rings)
+ return -EINVAL;
+
+ /* FLOW_EXT/FLOW_MAC_EXT is not supported. */
+ switch (fs->flow_type & ~FLOW_RSS) {
+ case TCP_V4_FLOW:
+ case UDP_V4_FLOW:
+ case SCTP_V4_FLOW:
+ unsupp_mask = !!fs->m_u.tcp_ip4_spec.tos;
+ break;
+ case TCP_V6_FLOW:
+ case UDP_V6_FLOW:
+ case SCTP_V6_FLOW:
+ unsupp_mask = !!fs->m_u.tcp_ip6_spec.tclass;
+ break;
+ case IPV4_USER_FLOW:
+ unsupp_mask = !!fs->m_u.usr_ip4_spec.l4_4_bytes ||
+ !!fs->m_u.usr_ip4_spec.tos ||
+ !!fs->m_u.usr_ip4_spec.ip_ver;
+ /* ip_ver must be ETH_RX_NFC_IP4. */
+ unsupp_mask |= fs->h_u.usr_ip4_spec.ip_ver != ETH_RX_NFC_IP4;
+ break;
+ case IPV6_USER_FLOW:
+ unsupp_mask = !!fs->m_u.usr_ip6_spec.l4_4_bytes ||
+ !!fs->m_u.usr_ip6_spec.tclass;
+ break;
+ case ETHER_FLOW:
+ if (fs->h_u.ether_spec.h_proto == htons(ETH_P_IP) ||
+ fs->h_u.ether_spec.h_proto == htons(ETH_P_IPV6)) {
+ nn_err(nn, "Please use ip4/ip6 flow type instead.\n");
+ return -EOPNOTSUPP;
+ }
+ /* Only unmasked ethtype is supported. */
+ unsupp_mask = !is_zero_ether_addr(fs->m_u.ether_spec.h_dest) ||
+ !is_zero_ether_addr(fs->m_u.ether_spec.h_source) ||
+ (fs->m_u.ether_spec.h_proto != htons(0xffff));
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (unsupp_mask)
+ return -EOPNOTSUPP;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ nfp_net_fs_from_ethtool(new, fs);
+
+ id = nfp_net_fs_check_existing(nn, new);
+ if (id >= 0) {
+ nn_err(nn, "Identical rule is existing in %d.\n", id);
+ err = -EINVAL;
+ goto err;
+ }
+
+ /* Insert to list in ascending order of location. */
+ list_for_each_entry(entry, &nn->fs.list, node) {
+ if (entry->loc == fs->location) {
+ err = nfp_net_fs_del_hw(nn, entry);
+ if (err)
+ goto err;
+
+ nn->fs.count--;
+ err = nfp_net_fs_add_hw(nn, new);
+ if (err)
+ goto err;
+
+ nn->fs.count++;
+ list_replace(&entry->node, &new->node);
+ kfree(entry);
+
+ return 0;
+ }
+
+ if (entry->loc > fs->location)
+ break;
+ }
+
+ if (nn->fs.count == NFP_FS_MAX_ENTRY) {
+ err = -ENOSPC;
+ goto err;
+ }
+
+ err = nfp_net_fs_add_hw(nn, new);
+ if (err)
+ goto err;
+
+ list_add_tail(&new->node, &entry->node);
+ nn->fs.count++;
+
+ return 0;
+
+err:
+ kfree(new);
+ return err;
+}
+
+static int nfp_net_fs_del(struct nfp_net *nn, struct ethtool_rxnfc *cmd)
+{
+ struct nfp_fs_entry *entry;
+ int err;
+
+ if (!(nn->cap_w1 & NFP_NET_CFG_CTRL_FLOW_STEER))
+ return -EOPNOTSUPP;
+
+ if (!nn->fs.count || cmd->fs.location >= NFP_FS_MAX_ENTRY)
+ return -EINVAL;
+
+ list_for_each_entry(entry, &nn->fs.list, node) {
+ if (entry->loc == cmd->fs.location) {
+ err = nfp_net_fs_del_hw(nn, entry);
+ if (err)
+ return err;
+
+ list_del(&entry->node);
+ kfree(entry);
+ nn->fs.count--;
+
+ return 0;
+ } else if (entry->loc > cmd->fs.location) {
+ /* no need to continue */
+ break;
+ }
+ }
+
+ return -ENOENT;
+}
+
static int nfp_net_set_rxnfc(struct net_device *netdev,
struct ethtool_rxnfc *cmd)
{
@@ -1393,6 +1765,10 @@ static int nfp_net_set_rxnfc(struct net_device *netdev,
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
return nfp_net_set_rss_hash_opt(nn, cmd);
+ case ETHTOOL_SRXCLSRLINS:
+ return nfp_net_fs_add(nn, cmd);
+ case ETHTOOL_SRXCLSRLDEL:
+ return nfp_net_fs_del(nn, cmd);
default:
return -EOPNOTSUPP;
}
@@ -1418,8 +1794,8 @@ static u32 nfp_net_get_rxfh_key_size(struct net_device *netdev)
return nfp_net_rss_key_sz(nn);
}
-static int nfp_net_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int nfp_net_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct nfp_net *nn = netdev_priv(netdev);
int i;
@@ -1427,41 +1803,41 @@ static int nfp_net_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY))
return -EOPNOTSUPP;
- if (indir)
+ if (rxfh->indir)
for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
- indir[i] = nn->rss_itbl[i];
- if (key)
- memcpy(key, nn->rss_key, nfp_net_rss_key_sz(nn));
- if (hfunc) {
- *hfunc = nn->rss_hfunc;
- if (*hfunc >= 1 << ETH_RSS_HASH_FUNCS_COUNT)
- *hfunc = ETH_RSS_HASH_UNKNOWN;
- }
+ rxfh->indir[i] = nn->rss_itbl[i];
+ if (rxfh->key)
+ memcpy(rxfh->key, nn->rss_key, nfp_net_rss_key_sz(nn));
+
+ rxfh->hfunc = nn->rss_hfunc;
+ if (rxfh->hfunc >= 1 << ETH_RSS_HASH_FUNCS_COUNT)
+ rxfh->hfunc = ETH_RSS_HASH_UNKNOWN;
return 0;
}
static int nfp_net_set_rxfh(struct net_device *netdev,
- const u32 *indir, const u8 *key,
- const u8 hfunc)
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct nfp_net *nn = netdev_priv(netdev);
int i;
if (!(nn->cap & NFP_NET_CFG_CTRL_RSS_ANY) ||
- !(hfunc == ETH_RSS_HASH_NO_CHANGE || hfunc == nn->rss_hfunc))
+ !(rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE ||
+ rxfh->hfunc == nn->rss_hfunc))
return -EOPNOTSUPP;
- if (!key && !indir)
+ if (!rxfh->key && !rxfh->indir)
return 0;
- if (key) {
- memcpy(nn->rss_key, key, nfp_net_rss_key_sz(nn));
+ if (rxfh->key) {
+ memcpy(nn->rss_key, rxfh->key, nfp_net_rss_key_sz(nn));
nfp_net_rss_write_key(nn);
}
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < ARRAY_SIZE(nn->rss_itbl); i++)
- nn->rss_itbl[i] = indir[i];
+ nn->rss_itbl[i] = rxfh->indir[i];
nfp_net_rss_write_itbl(nn);
}
@@ -1497,7 +1873,7 @@ static int nfp_net_get_coalesce(struct net_device *netdev,
struct nfp_net *nn = netdev_priv(netdev);
if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
- return -EINVAL;
+ return -EOPNOTSUPP;
ec->use_adaptive_rx_coalesce = nn->rx_coalesce_adapt_on;
ec->use_adaptive_tx_coalesce = nn->tx_coalesce_adapt_on;
@@ -1776,22 +2152,40 @@ static int nfp_net_set_coalesce(struct net_device *netdev,
*/
if (!(nn->cap & NFP_NET_CFG_CTRL_IRQMOD))
- return -EINVAL;
+ return -EOPNOTSUPP;
/* ensure valid configuration */
- if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames)
+ if (!ec->rx_coalesce_usecs && !ec->rx_max_coalesced_frames) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "rx-usecs and rx-frames cannot both be zero");
return -EINVAL;
+ }
- if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames)
+ if (!ec->tx_coalesce_usecs && !ec->tx_max_coalesced_frames) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "tx-usecs and tx-frames cannot both be zero");
return -EINVAL;
+ }
- if (nfp_net_coalesce_para_check(ec->rx_coalesce_usecs * factor,
- ec->rx_max_coalesced_frames))
+ if (nfp_net_coalesce_para_check(ec->rx_coalesce_usecs * factor)) {
+ NL_SET_ERR_MSG_MOD(extack, "rx-usecs too large");
return -EINVAL;
+ }
- if (nfp_net_coalesce_para_check(ec->tx_coalesce_usecs * factor,
- ec->tx_max_coalesced_frames))
+ if (nfp_net_coalesce_para_check(ec->rx_max_coalesced_frames)) {
+ NL_SET_ERR_MSG_MOD(extack, "rx-frames too large");
return -EINVAL;
+ }
+
+ if (nfp_net_coalesce_para_check(ec->tx_coalesce_usecs * factor)) {
+ NL_SET_ERR_MSG_MOD(extack, "tx-usecs too large");
+ return -EINVAL;
+ }
+
+ if (nfp_net_coalesce_para_check(ec->tx_max_coalesced_frames)) {
+ NL_SET_ERR_MSG_MOD(extack, "tx-frames too large");
+ return -EINVAL;
+ }
/* configuration is valid */
nn->rx_coalesce_adapt_on = !!ec->use_adaptive_rx_coalesce;
@@ -1866,6 +2260,30 @@ static int nfp_net_set_channels(struct net_device *netdev,
return nfp_net_set_num_rings(nn, total_rx, total_tx);
}
+static int nfp_port_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ 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;
+
+ if (pause->autoneg != AUTONEG_DISABLE)
+ return -EOPNOTSUPP;
+
+ err = nfp_eth_set_pauseparam(port->app->cpp, eth_port->index,
+ pause->tx_pause, pause->rx_pause);
+ if (!err)
+ /* Only refresh if we did something */
+ nfp_net_refresh_port_table(port);
+
+ return err < 0 ? err : 0;
+}
+
static void nfp_port_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
@@ -1877,10 +2295,10 @@ static void nfp_port_get_pauseparam(struct net_device *netdev,
if (!eth_port)
return;
- /* Currently pause frame support is fixed */
+ /* Currently pause frame autoneg is fixed */
pause->autoneg = AUTONEG_DISABLE;
- pause->rx_pause = 1;
- pause->tx_pause = 1;
+ pause->rx_pause = eth_port->rx_pause;
+ pause->tx_pause = eth_port->tx_pause;
}
static int nfp_net_set_phys_id(struct net_device *netdev,
@@ -2106,8 +2524,10 @@ 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,
+ .set_pauseparam = nfp_port_set_pauseparam,
.get_pauseparam = nfp_port_get_pauseparam,
.set_phys_id = nfp_net_set_phys_id,
+ .get_ts_info = ethtool_op_get_ts_info,
};
const struct ethtool_ops nfp_port_ethtool_ops = {
@@ -2130,6 +2550,7 @@ 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,
+ .set_pauseparam = nfp_port_set_pauseparam,
.get_pauseparam = nfp_port_get_pauseparam,
.set_phys_id = nfp_net_set_phys_id,
};
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
index 33b4c2856316..3f10c5365c80 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
@@ -537,11 +537,13 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
const u32 barcfg_msix_general =
NFP_PCIE_BAR_PCIE2CPP_MapType(
NFP_PCIE_BAR_PCIE2CPP_MapType_GENERAL) |
- NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT;
+ NFP_PCIE_BAR_PCIE2CPP_LengthSelect(
+ NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT);
const u32 barcfg_msix_xpb =
NFP_PCIE_BAR_PCIE2CPP_MapType(
NFP_PCIE_BAR_PCIE2CPP_MapType_BULK) |
- NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT |
+ NFP_PCIE_BAR_PCIE2CPP_LengthSelect(
+ NFP_PCIE_BAR_PCIE2CPP_LengthSelect_32BIT) |
NFP_PCIE_BAR_PCIE2CPP_Target_BaseAddress(
NFP_CPP_TARGET_ISLAND_XPB);
const u32 barcfg_explicit[4] = {
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
index 00264af13b49..dc0e405c1349 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp.h
@@ -189,6 +189,8 @@ enum nfp_ethtool_link_mode_list {
* @ports.enabled: is enabled?
* @ports.tx_enabled: is TX enabled?
* @ports.rx_enabled: is RX enabled?
+ * @ports.rx_pause: Switch of RX pause frame
+ * @ports.tx_pause: Switch of Tx pause frame
* @ports.override_changed: is media reconfig pending?
*
* @ports.port_type: one of %PORT_* defines for ethtool
@@ -227,6 +229,8 @@ struct nfp_eth_table {
bool tx_enabled;
bool rx_enabled;
bool supp_aneg;
+ bool rx_pause;
+ bool tx_pause;
bool override_changed;
@@ -255,6 +259,8 @@ 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);
+int nfp_eth_set_pauseparam(struct nfp_cpp *cpp, unsigned int idx,
+ unsigned int tx_pause, unsigned int rx_pause);
static inline bool nfp_eth_can_support_fec(struct nfp_eth_table_port *eth_port)
{
diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
index 9d62085d772a..5cfddc9a5d87 100644
--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
+++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_nsp_eth.c
@@ -42,6 +42,8 @@
#define NSP_ETH_STATE_ANEG GENMASK_ULL(25, 23)
#define NSP_ETH_STATE_FEC GENMASK_ULL(27, 26)
#define NSP_ETH_STATE_ACT_FEC GENMASK_ULL(29, 28)
+#define NSP_ETH_STATE_TX_PAUSE BIT_ULL(31)
+#define NSP_ETH_STATE_RX_PAUSE BIT_ULL(32)
#define NSP_ETH_CTRL_CONFIGURED BIT_ULL(0)
#define NSP_ETH_CTRL_ENABLED BIT_ULL(1)
@@ -52,6 +54,8 @@
#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)
+#define NSP_ETH_CTRL_SET_TX_PAUSE BIT_ULL(10)
+#define NSP_ETH_CTRL_SET_RX_PAUSE BIT_ULL(11)
enum nfp_eth_raw {
NSP_ETH_RAW_PORT = 0,
@@ -180,6 +184,15 @@ nfp_eth_port_translate(struct nfp_nsp *nsp, const union eth_table_entry *src,
dst->act_fec = FIELD_GET(NSP_ETH_STATE_ACT_FEC, state);
dst->supp_aneg = FIELD_GET(NSP_ETH_PORT_SUPP_ANEG, port);
+
+ if (nfp_nsp_get_abi_ver_minor(nsp) < 37) {
+ dst->tx_pause = true;
+ dst->rx_pause = true;
+ return;
+ }
+
+ dst->tx_pause = FIELD_GET(NSP_ETH_STATE_TX_PAUSE, state);
+ dst->rx_pause = FIELD_GET(NSP_ETH_STATE_RX_PAUSE, state);
}
static void
@@ -497,7 +510,7 @@ int nfp_eth_set_configured(struct nfp_cpp *cpp, unsigned int idx, bool configed)
static int
nfp_eth_set_bit_config(struct nfp_nsp *nsp, unsigned int raw_idx,
const u64 mask, const unsigned int shift,
- unsigned int val, const u64 ctrl_bit)
+ u64 val, const u64 ctrl_bit)
{
union eth_table_entry *entries = nfp_nsp_config_entries(nsp);
unsigned int idx = nfp_nsp_config_idx(nsp);
@@ -630,6 +643,81 @@ nfp_eth_set_fec(struct nfp_cpp *cpp, unsigned int idx, enum nfp_eth_fec mode)
}
/**
+ * __nfp_eth_set_txpause() - set tx pause control bit
+ * @nsp: NFP NSP handle returned from nfp_eth_config_start()
+ * @tx_pause: TX pause switch
+ *
+ * Set TX pause switch.
+ *
+ * Return: 0 or -ERRNO.
+ */
+static int __nfp_eth_set_txpause(struct nfp_nsp *nsp, unsigned int tx_pause)
+{
+ return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, NSP_ETH_STATE_TX_PAUSE,
+ tx_pause, NSP_ETH_CTRL_SET_TX_PAUSE);
+}
+
+/**
+ * __nfp_eth_set_rxpause() - set rx pause control bit
+ * @nsp: NFP NSP handle returned from nfp_eth_config_start()
+ * @rx_pause: RX pause switch
+ *
+ * Set RX pause switch.
+ *
+ * Return: 0 or -ERRNO.
+ */
+static int __nfp_eth_set_rxpause(struct nfp_nsp *nsp, unsigned int rx_pause)
+{
+ return NFP_ETH_SET_BIT_CONFIG(nsp, NSP_ETH_RAW_STATE, NSP_ETH_STATE_RX_PAUSE,
+ rx_pause, NSP_ETH_CTRL_SET_RX_PAUSE);
+}
+
+/**
+ * nfp_eth_set_pauseparam() - Set TX/RX pause switch.
+ * @cpp: NFP CPP handle
+ * @idx: NFP chip-wide port index
+ * @tx_pause: TX pause switch
+ * @rx_pause: RX pause switch
+ *
+ * Return:
+ * 0 - configuration successful;
+ * 1 - no changes were needed;
+ * -ERRNO - configuration failed.
+ */
+int
+nfp_eth_set_pauseparam(struct nfp_cpp *cpp, unsigned int idx,
+ unsigned int tx_pause, unsigned int rx_pause)
+{
+ struct nfp_nsp *nsp;
+ int err;
+
+ nsp = nfp_eth_config_start(cpp, idx);
+ if (IS_ERR(nsp))
+ return PTR_ERR(nsp);
+
+ if (nfp_nsp_get_abi_ver_minor(nsp) < 37) {
+ nfp_err(nfp_nsp_cpp(nsp),
+ "set pause parameter operation not supported, please update flash\n");
+ nfp_eth_config_cleanup_end(nsp);
+ return -EOPNOTSUPP;
+ }
+
+ err = __nfp_eth_set_txpause(nsp, tx_pause);
+ if (err) {
+ nfp_eth_config_cleanup_end(nsp);
+ return err;
+ }
+
+ err = __nfp_eth_set_rxpause(nsp, rx_pause);
+ if (err) {
+ nfp_eth_config_cleanup_end(nsp);
+ return err;
+ }
+
+ return nfp_eth_config_commit_end(nsp);
+}
+
+/**
* __nfp_eth_set_speed() - set interface speed/rate
* @nsp: NFP NSP handle returned from nfp_eth_config_start()
* @speed: Desired speed (per lane)
diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h
index 2453a40f6ee8..9ffef2e06885 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic.h
@@ -91,6 +91,4 @@ int ionic_port_identify(struct ionic *ionic);
int ionic_port_init(struct ionic *ionic);
int ionic_port_reset(struct ionic *ionic);
-const char *ionic_vf_attr_to_str(enum ionic_vf_attr attr);
-
#endif /* _IONIC_H_ */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
index d6ce113a4210..6ba8d4aca0a0 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_bus_pci.c
@@ -93,6 +93,7 @@ static void ionic_unmap_bars(struct ionic *ionic)
bars[i].len = 0;
}
}
+ ionic->num_bars = 0;
}
void __iomem *ionic_bus_map_dbpage(struct ionic *ionic, int page_num)
@@ -215,9 +216,18 @@ out:
static void ionic_clear_pci(struct ionic *ionic)
{
- ionic_unmap_bars(ionic);
- pci_release_regions(ionic->pdev);
- pci_disable_device(ionic->pdev);
+ if (ionic->num_bars) {
+ ionic->idev.dev_info_regs = NULL;
+ ionic->idev.dev_cmd_regs = NULL;
+ ionic->idev.intr_status = NULL;
+ ionic->idev.intr_ctrl = NULL;
+
+ ionic_unmap_bars(ionic);
+ pci_release_regions(ionic->pdev);
+ }
+
+ if (pci_is_enabled(ionic->pdev))
+ pci_disable_device(ionic->pdev);
}
static int ionic_setup_one(struct ionic *ionic)
@@ -389,9 +399,13 @@ static void ionic_remove(struct pci_dev *pdev)
{
struct ionic *ionic = pci_get_drvdata(pdev);
- del_timer_sync(&ionic->watchdog_timer);
+ timer_shutdown_sync(&ionic->watchdog_timer);
if (ionic->lif) {
+ /* prevent adminq cmds if already known as down */
+ if (test_and_clear_bit(IONIC_LIF_F_FW_RESET, ionic->lif->state))
+ set_bit(IONIC_LIF_F_FW_STOPPING, ionic->lif->state);
+
ionic_lif_unregister(ionic->lif);
ionic_devlink_unregister(ionic);
ionic_lif_deinit(ionic->lif);
@@ -416,6 +430,8 @@ static void ionic_reset_prepare(struct pci_dev *pdev)
dev_dbg(ionic->dev, "%s: device stopping\n", __func__);
+ set_bit(IONIC_LIF_F_FW_RESET, lif->state);
+
del_timer_sync(&ionic->watchdog_timer);
cancel_work_sync(&lif->deferred.work);
@@ -424,6 +440,7 @@ static void ionic_reset_prepare(struct pci_dev *pdev)
ionic_txrx_free(lif);
ionic_lif_deinit(lif);
ionic_qcqs_free(lif);
+ ionic_debugfs_del_lif(lif);
mutex_unlock(&lif->queue_lock);
ionic_dev_teardown(ionic);
@@ -455,10 +472,35 @@ err_out:
__func__, err ? "failed" : "done");
}
+static pci_ers_result_t ionic_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t error)
+{
+ if (error == pci_channel_io_frozen) {
+ ionic_reset_prepare(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+
+ return PCI_ERS_RESULT_NONE;
+}
+
+static void ionic_pci_error_resume(struct pci_dev *pdev)
+{
+ struct ionic *ionic = pci_get_drvdata(pdev);
+ struct ionic_lif *lif = ionic->lif;
+
+ if (lif && test_bit(IONIC_LIF_F_FW_RESET, lif->state))
+ pci_reset_function_locked(pdev);
+}
+
static const struct pci_error_handlers ionic_err_handler = {
/* FLR handling */
.reset_prepare = ionic_reset_prepare,
.reset_done = ionic_reset_done,
+
+ /* PCI bus error detected on this device */
+ .error_detected = ionic_pci_error_detected,
+ .resume = ionic_pci_error_resume,
+
};
static struct pci_driver ionic_driver = {
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
index c58217027564..91327ef670c7 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_debugfs.c
@@ -287,6 +287,9 @@ void ionic_debugfs_add_lif(struct ionic_lif *lif)
void ionic_debugfs_del_lif(struct ionic_lif *lif)
{
+ if (!lif->dentry)
+ return;
+
debugfs_remove_recursive(lif->dentry);
lif->dentry = NULL;
}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
index c06576f43916..746072b4dbd0 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
@@ -165,9 +165,19 @@ void ionic_dev_teardown(struct ionic *ionic)
}
/* Devcmd Interface */
-bool ionic_is_fw_running(struct ionic_dev *idev)
+static bool __ionic_is_fw_running(struct ionic_dev *idev, u8 *status_ptr)
{
- u8 fw_status = ioread8(&idev->dev_info_regs->fw_status);
+ u8 fw_status;
+
+ if (!idev->dev_info_regs) {
+ if (status_ptr)
+ *status_ptr = 0xff;
+ return false;
+ }
+
+ fw_status = ioread8(&idev->dev_info_regs->fw_status);
+ if (status_ptr)
+ *status_ptr = fw_status;
/* firmware is useful only if the running bit is set and
* fw_status != 0xff (bad PCI read)
@@ -175,6 +185,11 @@ bool ionic_is_fw_running(struct ionic_dev *idev)
return (fw_status != 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING);
}
+bool ionic_is_fw_running(struct ionic_dev *idev)
+{
+ return __ionic_is_fw_running(idev, NULL);
+}
+
int ionic_heartbeat_check(struct ionic *ionic)
{
unsigned long check_time, last_check_time;
@@ -199,10 +214,8 @@ do_check_time:
goto do_check_time;
}
- fw_status = ioread8(&idev->dev_info_regs->fw_status);
-
/* If fw_status is not ready don't bother with the generation */
- if (!ionic_is_fw_running(idev)) {
+ if (!__ionic_is_fw_running(idev, &fw_status)) {
fw_status_ready = false;
} else {
fw_generation = fw_status & IONIC_FW_STS_F_GENERATION;
@@ -306,21 +319,32 @@ do_check_time:
u8 ionic_dev_cmd_status(struct ionic_dev *idev)
{
+ if (!idev->dev_cmd_regs)
+ return (u8)PCI_ERROR_RESPONSE;
return ioread8(&idev->dev_cmd_regs->comp.comp.status);
}
bool ionic_dev_cmd_done(struct ionic_dev *idev)
{
+ if (!idev->dev_cmd_regs)
+ return false;
return ioread32(&idev->dev_cmd_regs->done) & IONIC_DEV_CMD_DONE;
}
void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp)
{
+ if (!idev->dev_cmd_regs)
+ return;
memcpy_fromio(comp, &idev->dev_cmd_regs->comp, sizeof(*comp));
}
void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
{
+ idev->opcode = cmd->cmd.opcode;
+
+ if (!idev->dev_cmd_regs)
+ return;
+
memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd));
iowrite32(0, &idev->dev_cmd_regs->done);
iowrite32(1, &idev->dev_cmd_regs->doorbell);
@@ -469,46 +493,6 @@ int ionic_set_vf_config(struct ionic *ionic, int vf,
return err;
}
-int ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr,
- struct ionic_vf_getattr_comp *comp)
-{
- union ionic_dev_cmd cmd = {
- .vf_getattr.opcode = IONIC_CMD_VF_GETATTR,
- .vf_getattr.attr = attr,
- .vf_getattr.vf_index = cpu_to_le16(vf),
- };
- int err;
-
- if (vf >= ionic->num_vfs)
- return -EINVAL;
-
- switch (attr) {
- case IONIC_VF_ATTR_SPOOFCHK:
- case IONIC_VF_ATTR_TRUST:
- case IONIC_VF_ATTR_LINKSTATE:
- case IONIC_VF_ATTR_MAC:
- case IONIC_VF_ATTR_VLAN:
- case IONIC_VF_ATTR_RATE:
- break;
- case IONIC_VF_ATTR_STATSADDR:
- default:
- return -EINVAL;
- }
-
- mutex_lock(&ionic->dev_cmd_lock);
- ionic_dev_cmd_go(&ionic->idev, &cmd);
- err = ionic_dev_cmd_wait_nomsg(ionic, DEVCMD_TIMEOUT);
- memcpy_fromio(comp, &ionic->idev.dev_cmd_regs->comp.vf_getattr,
- sizeof(*comp));
- mutex_unlock(&ionic->dev_cmd_lock);
-
- if (err && comp->status != IONIC_RC_ENOSUPP)
- ionic_dev_cmd_dev_err_print(ionic, cmd.vf_getattr.opcode,
- comp->status, err);
-
- return err;
-}
-
void ionic_vf_start(struct ionic *ionic)
{
union ionic_dev_cmd cmd = {
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
index 9b5463040075..2667e1cde16b 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
@@ -153,6 +153,7 @@ struct ionic_dev {
bool fw_hb_ready;
bool fw_status_ready;
u8 fw_generation;
+ u8 opcode;
u64 __iomem *db_pages;
dma_addr_t phy_db_pages;
@@ -269,12 +270,12 @@ struct ionic_queue {
struct ionic_intr_info {
char name[IONIC_INTR_NAME_MAX_SZ];
+ u64 rearm_count;
unsigned int index;
unsigned int vector;
- u64 rearm_count;
unsigned int cpu;
- cpumask_t affinity_mask;
u32 dim_coal_hw;
+ cpumask_t affinity_mask;
};
struct ionic_cq {
@@ -341,8 +342,7 @@ void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);
int ionic_set_vf_config(struct ionic *ionic, int vf,
struct ionic_vf_setattr_cmd *vfc);
-int ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr,
- struct ionic_vf_getattr_comp *comp);
+
void ionic_dev_cmd_queue_identify(struct ionic_dev *idev,
u16 lif_type, u8 qtype, u8 qver);
void ionic_vf_start(struct ionic *ionic);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index 3a6b0a9bc241..0ffc9c4904ac 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -90,18 +90,23 @@ static void ionic_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
void *p)
{
struct ionic_lif *lif = netdev_priv(netdev);
+ struct ionic_dev *idev;
unsigned int offset;
unsigned int size;
regs->version = IONIC_DEV_CMD_REG_VERSION;
+ idev = &lif->ionic->idev;
+ if (!idev->dev_info_regs)
+ return;
+
offset = 0;
size = IONIC_DEV_INFO_REG_COUNT * sizeof(u32);
memcpy_fromio(p + offset, lif->ionic->idev.dev_info_regs->words, size);
offset += size;
size = IONIC_DEV_CMD_REG_COUNT * sizeof(u32);
- memcpy_fromio(p + offset, lif->ionic->idev.dev_cmd_regs->words, size);
+ memcpy_fromio(p + offset, idev->dev_cmd_regs->words, size);
}
static void ionic_get_link_ext_stats(struct net_device *netdev,
@@ -823,36 +828,38 @@ static u32 ionic_get_rxfh_key_size(struct net_device *netdev)
return IONIC_RSS_HASH_KEY_SIZE;
}
-static int ionic_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int ionic_get_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh)
{
struct ionic_lif *lif = netdev_priv(netdev);
unsigned int i, tbl_sz;
- if (indir) {
+ if (rxfh->indir) {
tbl_sz = le16_to_cpu(lif->ionic->ident.lif.eth.rss_ind_tbl_sz);
for (i = 0; i < tbl_sz; i++)
- indir[i] = lif->rss_ind_tbl[i];
+ rxfh->indir[i] = lif->rss_ind_tbl[i];
}
- if (key)
- memcpy(key, lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
+ if (rxfh->key)
+ memcpy(rxfh->key, lif->rss_hash_key, IONIC_RSS_HASH_KEY_SIZE);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int ionic_set_rxfh(struct net_device *netdev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int ionic_set_rxfh(struct net_device *netdev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct ionic_lif *lif = netdev_priv(netdev);
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- return ionic_lif_rss_config(lif, lif->rss_types, key, indir);
+ return ionic_lif_rss_config(lif, lif->rss_types,
+ rxfh->key, rxfh->indir);
}
static int ionic_set_tunable(struct net_device *dev,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_fw.c b/drivers/net/ethernet/pensando/ionic/ionic_fw.c
index 5f40324cd243..3c209c1a2337 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_fw.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_fw.c
@@ -109,6 +109,11 @@ int ionic_firmware_update(struct ionic_lif *lif, const struct firmware *fw,
dl = priv_to_devlink(ionic);
devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0);
+ if (!idev->dev_cmd_regs) {
+ err = -ENXIO;
+ goto err_out;
+ }
+
buf_sz = sizeof(idev->dev_cmd_regs->data);
netdev_dbg(netdev,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index bad919343180..fcb44ceeb6aa 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -424,14 +424,10 @@ static void ionic_qcq_free(struct ionic_lif *lif, struct ionic_qcq *qcq)
ionic_qcq_intr_free(lif, qcq);
- if (qcq->cq.info) {
- vfree(qcq->cq.info);
- qcq->cq.info = NULL;
- }
- if (qcq->q.info) {
- vfree(qcq->q.info);
- qcq->q.info = NULL;
- }
+ vfree(qcq->cq.info);
+ qcq->cq.info = NULL;
+ vfree(qcq->q.info);
+ qcq->q.info = NULL;
}
void ionic_qcqs_free(struct ionic_lif *lif)
@@ -2332,82 +2328,11 @@ static int ionic_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd
}
}
-static int ionic_get_fw_vf_config(struct ionic *ionic, int vf, struct ionic_vf *vfdata)
-{
- struct ionic_vf_getattr_comp comp = { 0 };
- int err;
- u8 attr;
-
- attr = IONIC_VF_ATTR_VLAN;
- err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
- if (err && comp.status != IONIC_RC_ENOSUPP)
- goto err_out;
- if (!err)
- vfdata->vlanid = comp.vlanid;
-
- attr = IONIC_VF_ATTR_SPOOFCHK;
- err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
- if (err && comp.status != IONIC_RC_ENOSUPP)
- goto err_out;
- if (!err)
- vfdata->spoofchk = comp.spoofchk;
-
- attr = IONIC_VF_ATTR_LINKSTATE;
- err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
- if (err && comp.status != IONIC_RC_ENOSUPP)
- goto err_out;
- if (!err) {
- switch (comp.linkstate) {
- case IONIC_VF_LINK_STATUS_UP:
- vfdata->linkstate = IFLA_VF_LINK_STATE_ENABLE;
- break;
- case IONIC_VF_LINK_STATUS_DOWN:
- vfdata->linkstate = IFLA_VF_LINK_STATE_DISABLE;
- break;
- case IONIC_VF_LINK_STATUS_AUTO:
- vfdata->linkstate = IFLA_VF_LINK_STATE_AUTO;
- break;
- default:
- dev_warn(ionic->dev, "Unexpected link state %u\n", comp.linkstate);
- break;
- }
- }
-
- attr = IONIC_VF_ATTR_RATE;
- err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
- if (err && comp.status != IONIC_RC_ENOSUPP)
- goto err_out;
- if (!err)
- vfdata->maxrate = comp.maxrate;
-
- attr = IONIC_VF_ATTR_TRUST;
- err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
- if (err && comp.status != IONIC_RC_ENOSUPP)
- goto err_out;
- if (!err)
- vfdata->trusted = comp.trust;
-
- attr = IONIC_VF_ATTR_MAC;
- err = ionic_dev_cmd_vf_getattr(ionic, vf, attr, &comp);
- if (err && comp.status != IONIC_RC_ENOSUPP)
- goto err_out;
- if (!err)
- ether_addr_copy(vfdata->macaddr, comp.macaddr);
-
-err_out:
- if (err)
- dev_err(ionic->dev, "Failed to get %s for VF %d\n",
- ionic_vf_attr_to_str(attr), vf);
-
- return err;
-}
-
static int ionic_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivf)
{
struct ionic_lif *lif = netdev_priv(netdev);
struct ionic *ionic = lif->ionic;
- struct ionic_vf vfdata = { 0 };
int ret = 0;
if (!netif_device_present(netdev))
@@ -2418,18 +2343,16 @@ static int ionic_get_vf_config(struct net_device *netdev,
if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
ret = -EINVAL;
} else {
- ivf->vf = vf;
- ivf->qos = 0;
-
- ret = ionic_get_fw_vf_config(ionic, vf, &vfdata);
- if (!ret) {
- ivf->vlan = le16_to_cpu(vfdata.vlanid);
- ivf->spoofchk = vfdata.spoofchk;
- ivf->linkstate = vfdata.linkstate;
- ivf->max_tx_rate = le32_to_cpu(vfdata.maxrate);
- ivf->trusted = vfdata.trusted;
- ether_addr_copy(ivf->mac, vfdata.macaddr);
- }
+ struct ionic_vf *vfdata = &ionic->vfs[vf];
+
+ ivf->vf = vf;
+ ivf->qos = 0;
+ ivf->vlan = le16_to_cpu(vfdata->vlanid);
+ ivf->spoofchk = vfdata->spoofchk;
+ ivf->linkstate = vfdata->linkstate;
+ ivf->max_tx_rate = le32_to_cpu(vfdata->maxrate);
+ ivf->trusted = vfdata->trusted;
+ ether_addr_copy(ivf->mac, vfdata->macaddr);
}
up_read(&ionic->vf_op_lock);
@@ -3127,6 +3050,7 @@ int ionic_lif_alloc(struct ionic *ionic)
lif = netdev_priv(netdev);
lif->netdev = netdev;
ionic->lif = lif;
+ lif->ionic = ionic;
netdev->netdev_ops = &ionic_netdev_ops;
ionic_ethtool_set_ops(netdev);
@@ -3149,7 +3073,6 @@ int ionic_lif_alloc(struct ionic *ionic)
lif->neqs = ionic->neqs_per_lif;
lif->nxqs = ionic->ntxqs_per_lif;
- lif->ionic = ionic;
lif->index = 0;
if (is_kdump_kernel()) {
@@ -3238,6 +3161,9 @@ static void ionic_lif_reset(struct ionic_lif *lif)
{
struct ionic_dev *idev = &lif->ionic->idev;
+ if (!ionic_is_fw_running(idev))
+ return;
+
mutex_lock(&lif->ionic->dev_cmd_lock);
ionic_dev_cmd_lif_reset(idev, lif->index);
ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT);
@@ -3633,7 +3559,10 @@ int ionic_lif_init(struct ionic_lif *lif)
goto err_out_notifyq_deinit;
}
- err = ionic_init_nic_features(lif);
+ if (test_bit(IONIC_LIF_F_FW_RESET, lif->state))
+ err = ionic_set_nic_features(lif, lif->netdev->features);
+ else
+ err = ionic_init_nic_features(lif);
if (err)
goto err_out_notifyq_deinit;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index 457c24195ca6..61548b3eea93 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -312,6 +312,11 @@ static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs)
return (usecs * mult) / div;
}
+static inline bool ionic_txq_hwstamp_enabled(struct ionic_queue *q)
+{
+ return unlikely(q->features & IONIC_TXQ_F_HWSTAMP);
+}
+
void ionic_link_status_check_request(struct ionic_lif *lif, bool can_sleep);
void ionic_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *ns);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index 835577392178..2f479de329fe 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -188,28 +188,6 @@ static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
}
}
-const char *ionic_vf_attr_to_str(enum ionic_vf_attr attr)
-{
- switch (attr) {
- case IONIC_VF_ATTR_SPOOFCHK:
- return "IONIC_VF_ATTR_SPOOFCHK";
- case IONIC_VF_ATTR_TRUST:
- return "IONIC_VF_ATTR_TRUST";
- case IONIC_VF_ATTR_LINKSTATE:
- return "IONIC_VF_ATTR_LINKSTATE";
- case IONIC_VF_ATTR_MAC:
- return "IONIC_VF_ATTR_MAC";
- case IONIC_VF_ATTR_VLAN:
- return "IONIC_VF_ATTR_VLAN";
- case IONIC_VF_ATTR_RATE:
- return "IONIC_VF_ATTR_RATE";
- case IONIC_VF_ATTR_STATSADDR:
- return "IONIC_VF_ATTR_STATSADDR";
- default:
- return "IONIC_VF_ATTR_UNKNOWN";
- }
-}
-
static void ionic_adminq_flush(struct ionic_lif *lif)
{
struct ionic_desc_info *desc_info;
@@ -410,28 +388,37 @@ int ionic_adminq_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx,
do_msg);
}
-int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+static int __ionic_adminq_post_wait(struct ionic_lif *lif,
+ struct ionic_admin_ctx *ctx,
+ const bool do_msg)
{
int err;
+ if (!ionic_is_fw_running(&lif->ionic->idev))
+ return 0;
+
err = ionic_adminq_post(lif, ctx);
- return ionic_adminq_wait(lif, ctx, err, true);
+ return ionic_adminq_wait(lif, ctx, err, do_msg);
}
-int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+int ionic_adminq_post_wait(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
{
- int err;
-
- err = ionic_adminq_post(lif, ctx);
+ return __ionic_adminq_post_wait(lif, ctx, true);
+}
- return ionic_adminq_wait(lif, ctx, err, false);
+int ionic_adminq_post_wait_nomsg(struct ionic_lif *lif, struct ionic_admin_ctx *ctx)
+{
+ return __ionic_adminq_post_wait(lif, ctx, false);
}
static void ionic_dev_cmd_clean(struct ionic *ionic)
{
struct ionic_dev *idev = &ionic->idev;
+ if (!idev->dev_cmd_regs)
+ return;
+
iowrite32(0, &idev->dev_cmd_regs->doorbell);
memset_io(&idev->dev_cmd_regs->cmd, 0, sizeof(idev->dev_cmd_regs->cmd));
}
@@ -465,7 +452,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
*/
max_wait = jiffies + (max_seconds * HZ);
try_again:
- opcode = readb(&idev->dev_cmd_regs->cmd.cmd.opcode);
+ opcode = idev->opcode;
start_time = jiffies;
for (fw_up = ionic_is_fw_running(idev);
!done && fw_up && time_before(jiffies, max_wait);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c
index 9859a4432985..1f6022fb7679 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c
@@ -258,10 +258,10 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf)
int i, q_num;
for (i = 0; i < IONIC_NUM_LIF_STATS; i++)
- ethtool_sprintf(buf, ionic_lif_stats_desc[i].name);
+ ethtool_puts(buf, ionic_lif_stats_desc[i].name);
for (i = 0; i < IONIC_NUM_PORT_STATS; i++)
- ethtool_sprintf(buf, ionic_port_stats_desc[i].name);
+ ethtool_puts(buf, ionic_port_stats_desc[i].name);
for (q_num = 0; q_num < MAX_Q(lif); q_num++)
ionic_sw_stats_get_tx_strings(lif, buf, q_num);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
index ccc1b1d407e4..6f4776759863 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
@@ -579,6 +579,9 @@ int ionic_tx_napi(struct napi_struct *napi, int budget)
work_done = ionic_cq_service(cq, budget,
ionic_tx_service, NULL, NULL);
+ if (unlikely(!budget))
+ return budget;
+
if (work_done < budget && napi_complete_done(napi, work_done)) {
ionic_dim_update(qcq, IONIC_LIF_F_TX_DIM_INTR);
flags |= IONIC_INTR_CRED_UNMASK;
@@ -607,6 +610,9 @@ int ionic_rx_napi(struct napi_struct *napi, int budget)
u32 work_done = 0;
u32 flags = 0;
+ if (unlikely(!budget))
+ return budget;
+
lif = cq->bound_q->lif;
idev = &lif->ionic->idev;
@@ -656,6 +662,9 @@ int ionic_txrx_napi(struct napi_struct *napi, int budget)
tx_work_done = ionic_cq_service(txcq, IONIC_TX_BUDGET_DEFAULT,
ionic_tx_service, NULL, NULL);
+ if (unlikely(!budget))
+ return budget;
+
rx_work_done = ionic_cq_service(rxcq, budget,
ionic_rx_service, NULL, NULL);
@@ -803,7 +812,7 @@ static void ionic_tx_clean(struct ionic_queue *q,
qi = skb_get_queue_mapping(skb);
- if (unlikely(q->features & IONIC_TXQ_F_HWSTAMP)) {
+ if (ionic_txq_hwstamp_enabled(q)) {
if (cq_info) {
struct skb_shared_hwtstamps hwts = {};
__le64 *cq_desc_hwstamp;
@@ -870,7 +879,7 @@ bool ionic_tx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info)
desc_info->cb_arg = NULL;
} while (index != le16_to_cpu(comp->comp_index));
- if (pkts && bytes && !unlikely(q->features & IONIC_TXQ_F_HWSTAMP))
+ if (pkts && bytes && !ionic_txq_hwstamp_enabled(q))
netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes);
return true;
@@ -908,7 +917,7 @@ void ionic_tx_empty(struct ionic_queue *q)
desc_info->cb_arg = NULL;
}
- if (pkts && bytes && !unlikely(q->features & IONIC_TXQ_F_HWSTAMP))
+ if (pkts && bytes && !ionic_txq_hwstamp_enabled(q))
netdev_tx_completed_queue(q_to_ndq(q), pkts, bytes);
}
@@ -986,7 +995,7 @@ static void ionic_tx_tso_post(struct ionic_queue *q,
if (start) {
skb_tx_timestamp(skb);
- if (!unlikely(q->features & IONIC_TXQ_F_HWSTAMP))
+ if (!ionic_txq_hwstamp_enabled(q))
netdev_tx_sent_queue(q_to_ndq(q), skb->len);
ionic_txq_post(q, false, ionic_tx_clean, skb);
} else {
@@ -1233,7 +1242,7 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb)
stats->pkts++;
stats->bytes += skb->len;
- if (!unlikely(q->features & IONIC_TXQ_F_HWSTAMP))
+ if (!ionic_txq_hwstamp_enabled(q))
netdev_tx_sent_queue(q_to_ndq(q), skb->len);
ionic_txq_post(q, !netdev_xmit_more(), ionic_tx_clean, skb);
diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
index b6b849a079ed..0e240b5ab8d4 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c
@@ -1370,28 +1370,29 @@ static u32 qede_get_rxfh_key_size(struct net_device *dev)
return sizeof(edev->rss_key);
}
-static int qede_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+static int qede_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct qede_dev *edev = netdev_priv(dev);
int i;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
- indir[i] = edev->rss_ind_table[i];
+ rxfh->indir[i] = edev->rss_ind_table[i];
- if (key)
- memcpy(key, edev->rss_key, qede_get_rxfh_key_size(dev));
+ if (rxfh->key)
+ memcpy(rxfh->key, edev->rss_key, qede_get_rxfh_key_size(dev));
return 0;
}
-static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int qede_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct qed_update_vport_params *vport_update_params;
struct qede_dev *edev = netdev_priv(dev);
@@ -1403,20 +1404,21 @@ static int qede_set_rxfh(struct net_device *dev, const u32 *indir,
return -EOPNOTSUPP;
}
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!indir && !key)
+ if (!rxfh->indir && !rxfh->key)
return 0;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < QED_RSS_IND_TABLE_SIZE; i++)
- edev->rss_ind_table[i] = indir[i];
+ edev->rss_ind_table[i] = rxfh->indir[i];
edev->rss_params_inited |= QEDE_RSS_INDIR_INITED;
}
- if (key) {
- memcpy(&edev->rss_key, key, qede_get_rxfh_key_size(dev));
+ if (rxfh->key) {
+ memcpy(&edev->rss_key, rxfh->key, qede_get_rxfh_key_size(dev));
edev->rss_params_inited |= QEDE_RSS_KEY_INITED;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index c95d56e56c59..b733374b4dc5 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -2092,8 +2092,8 @@ static int qlcnic_83xx_run_post(struct qlcnic_adapter *adapter)
return -EINVAL;
}
- strncpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME,
- QLC_FW_FILE_NAME_LEN);
+ strscpy(fw_info->fw_file_name, QLC_83XX_POST_FW_FILE_NAME,
+ sizeof(fw_info->fw_file_name));
ret = request_firmware(&fw_info->fw, fw_info->fw_file_name, dev);
if (ret) {
@@ -2396,12 +2396,12 @@ static int qlcnic_83xx_get_fw_info(struct qlcnic_adapter *adapter)
switch (pdev->device) {
case PCI_DEVICE_ID_QLOGIC_QLE834X:
case PCI_DEVICE_ID_QLOGIC_QLE8830:
- strncpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME,
- QLC_FW_FILE_NAME_LEN);
+ strscpy(fw_info->fw_file_name, QLC_83XX_FW_FILE_NAME,
+ sizeof(fw_info->fw_file_name));
break;
case PCI_DEVICE_ID_QLOGIC_QLE844X:
- strncpy(fw_info->fw_file_name, QLC_84XX_FW_FILE_NAME,
- QLC_FW_FILE_NAME_LEN);
+ strscpy(fw_info->fw_file_name, QLC_84XX_FW_FILE_NAME,
+ sizeof(fw_info->fw_file_name));
break;
default:
dev_err(&pdev->dev, "%s: Invalid device id\n",
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
index 9adec91f35e9..223321897b96 100644
--- a/drivers/net/ethernet/qualcomm/qca_uart.c
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -58,9 +58,8 @@ struct qcauart {
unsigned char *tx_buffer;
};
-static int
-qca_tty_receive(struct serdev_device *serdev, const unsigned char *data,
- size_t count)
+static ssize_t
+qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
{
struct qcauart *qca = serdev_device_get_drvdata(serdev);
struct net_device *netdev = qca->net_dev;
diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
index 39d24e07f306..5b69b9268c75 100644
--- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
+++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
@@ -396,7 +396,7 @@ nla_put_failure:
struct rtnl_link_ops rmnet_link_ops __read_mostly = {
.kind = "rmnet",
- .maxtype = __IFLA_RMNET_MAX,
+ .maxtype = IFLA_RMNET_MAX,
.priv_size = sizeof(struct rmnet_priv),
.setup = rmnet_vnd_setup,
.validate = rmnet_rtnl_validate,
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index 93d9df55b361..03015b665f4e 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -113,4 +113,11 @@ config R8169
To compile this driver as a module, choose M here: the module
will be called r8169. This is recommended.
+config R8169_LEDS
+ def_bool R8169 && LEDS_TRIGGER_NETDEV
+ depends on !(R8169=y && LEDS_CLASS=m)
+ help
+ Optional support for controlling the NIC LED's with the netdev
+ LED trigger.
+
endif # NET_VENDOR_REALTEK
diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile
index 2e1d78b106b0..635491d8826e 100644
--- a/drivers/net/ethernet/realtek/Makefile
+++ b/drivers/net/ethernet/realtek/Makefile
@@ -6,5 +6,6 @@
obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ATP) += atp.o
-r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o
+r8169-y += r8169_main.o r8169_firmware.o r8169_phy_config.o
+r8169-$(CONFIG_R8169_LEDS) += r8169_leds.o
obj-$(CONFIG_R8169) += r8169.o
diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h
index 55ef8251feb5..81567fcf3957 100644
--- a/drivers/net/ethernet/realtek/r8169.h
+++ b/drivers/net/ethernet/realtek/r8169.h
@@ -8,6 +8,7 @@
* See MAINTAINERS file for support contact information.
*/
+#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/phy.h>
@@ -77,3 +78,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);
+
+void r8169_get_led_name(struct rtl8169_private *tp, int idx,
+ char *buf, int buf_len);
+int rtl8168_get_led_mode(struct rtl8169_private *tp);
+int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val);
+void rtl8168_init_leds(struct net_device *ndev);
diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c
index cbc6b846ded5..ed6e721b1555 100644
--- a/drivers/net/ethernet/realtek/r8169_firmware.c
+++ b/drivers/net/ethernet/realtek/r8169_firmware.c
@@ -151,9 +151,6 @@ void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
- if (!action)
- break;
-
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
diff --git a/drivers/net/ethernet/realtek/r8169_leds.c b/drivers/net/ethernet/realtek/r8169_leds.c
new file mode 100644
index 000000000000..007d077edcad
--- /dev/null
+++ b/drivers/net/ethernet/realtek/r8169_leds.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver.
+ *
+ * Copyright (c) 2023 Heiner Kallweit <hkallweit1@gmail.com>
+ *
+ * See MAINTAINERS file for support contact information.
+ */
+
+#include <linux/leds.h>
+#include <linux/netdevice.h>
+#include <uapi/linux/uleds.h>
+
+#include "r8169.h"
+
+#define RTL8168_LED_CTRL_OPTION2 BIT(15)
+#define RTL8168_LED_CTRL_ACT BIT(3)
+#define RTL8168_LED_CTRL_LINK_1000 BIT(2)
+#define RTL8168_LED_CTRL_LINK_100 BIT(1)
+#define RTL8168_LED_CTRL_LINK_10 BIT(0)
+
+#define RTL8168_NUM_LEDS 3
+
+#define RTL8168_SUPPORTED_MODES \
+ (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \
+ BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \
+ BIT(TRIGGER_NETDEV_TX))
+
+struct r8169_led_classdev {
+ struct led_classdev led;
+ struct net_device *ndev;
+ int index;
+};
+
+#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led)
+
+static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev,
+ unsigned long flags)
+{
+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
+ int shift = ldev->index * 4;
+ bool rx, tx;
+
+ if (flags & ~RTL8168_SUPPORTED_MODES)
+ goto nosupp;
+
+ rx = flags & BIT(TRIGGER_NETDEV_RX);
+ tx = flags & BIT(TRIGGER_NETDEV_TX);
+ if (rx != tx)
+ goto nosupp;
+
+ return 0;
+
+nosupp:
+ /* Switch LED off to indicate that mode isn't supported */
+ rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0);
+ return -EOPNOTSUPP;
+}
+
+static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev,
+ unsigned long flags)
+{
+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
+ int shift = ldev->index * 4;
+ u16 mode = 0;
+
+ if (flags & BIT(TRIGGER_NETDEV_LINK_10))
+ mode |= RTL8168_LED_CTRL_LINK_10;
+ if (flags & BIT(TRIGGER_NETDEV_LINK_100))
+ mode |= RTL8168_LED_CTRL_LINK_100;
+ if (flags & BIT(TRIGGER_NETDEV_LINK_1000))
+ mode |= RTL8168_LED_CTRL_LINK_1000;
+ if (flags & BIT(TRIGGER_NETDEV_TX))
+ mode |= RTL8168_LED_CTRL_ACT;
+
+ return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift);
+}
+
+static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev,
+ unsigned long *flags)
+{
+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
+ struct rtl8169_private *tp = netdev_priv(ldev->ndev);
+ int shift = ldev->index * 4;
+ int mode;
+
+ mode = rtl8168_get_led_mode(tp);
+ if (mode < 0)
+ return mode;
+
+ if (mode & RTL8168_LED_CTRL_OPTION2) {
+ rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0);
+ netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n");
+ }
+
+ mode = (mode >> shift) & 0x000f;
+
+ if (mode & RTL8168_LED_CTRL_ACT)
+ *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
+
+ if (mode & RTL8168_LED_CTRL_LINK_10)
+ *flags |= BIT(TRIGGER_NETDEV_LINK_10);
+ if (mode & RTL8168_LED_CTRL_LINK_100)
+ *flags |= BIT(TRIGGER_NETDEV_LINK_100);
+ if (mode & RTL8168_LED_CTRL_LINK_1000)
+ *flags |= BIT(TRIGGER_NETDEV_LINK_1000);
+
+ return 0;
+}
+
+static struct device *
+ r8169_led_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
+
+ return &ldev->ndev->dev;
+}
+
+static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev,
+ struct net_device *ndev, int index)
+{
+ struct rtl8169_private *tp = netdev_priv(ndev);
+ struct led_classdev *led_cdev = &ldev->led;
+ char led_name[LED_MAX_NAME_SIZE];
+
+ ldev->ndev = ndev;
+ ldev->index = index;
+
+ r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE);
+ led_cdev->name = led_name;
+ led_cdev->default_trigger = "netdev";
+ led_cdev->hw_control_trigger = "netdev";
+ led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
+ led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported;
+ led_cdev->hw_control_set = rtl8168_led_hw_control_set;
+ led_cdev->hw_control_get = rtl8168_led_hw_control_get;
+ led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
+
+ /* ignore errors */
+ devm_led_classdev_register(&ndev->dev, led_cdev);
+}
+
+void rtl8168_init_leds(struct net_device *ndev)
+{
+ /* bind resource mgmt to netdev */
+ struct device *dev = &ndev->dev;
+ struct r8169_led_classdev *leds;
+ int i;
+
+ leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL);
+ if (!leds)
+ return;
+
+ for (i = 0; i < RTL8168_NUM_LEDS; i++)
+ rtl8168_setup_ldev(leds + i, ndev, i);
+}
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 81fd31f6fac4..dd73df6b17b0 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -56,10 +56,6 @@
#define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
#define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-#define MC_FILTER_LIMIT 32
-
#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
@@ -289,6 +285,7 @@ enum rtl8168_8101_registers {
};
enum rtl8168_registers {
+ LED_CTRL = 0x18,
LED_FREQ = 0x1a,
EEE_LED = 0x1b,
ERIDR = 0x70,
@@ -620,6 +617,7 @@ struct rtl8169_private {
raw_spinlock_t config25_lock;
raw_spinlock_t mac_ocp_lock;
+ struct mutex led_lock; /* serialize LED ctrl RMW access */
raw_spinlock_t cfg9346_usage_lock;
int cfg9346_usage_count;
@@ -792,6 +790,62 @@ static const struct rtl_cond name = { \
\
static bool name ## _check(struct rtl8169_private *tp)
+int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val)
+{
+ struct device *dev = tp_to_dev(tp);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tp->led_lock);
+ RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val);
+ mutex_unlock(&tp->led_lock);
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
+int rtl8168_get_led_mode(struct rtl8169_private *tp)
+{
+ struct device *dev = tp_to_dev(tp);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = RTL_R16(tp, LED_CTRL);
+
+ pm_runtime_put_sync(dev);
+
+ return ret;
+}
+
+void r8169_get_led_name(struct rtl8169_private *tp, int idx,
+ char *buf, int buf_len)
+{
+ struct pci_dev *pdev = tp->pci_dev;
+ char pdom[8], pfun[8];
+ int domain;
+
+ domain = pci_domain_nr(pdev->bus);
+ if (domain)
+ snprintf(pdom, sizeof(pdom), "P%d", domain);
+ else
+ pdom[0] = '\0';
+
+ if (pdev->multifunction)
+ snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn));
+ else
+ pfun[0] = '\0';
+
+ snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number,
+ PCI_SLOT(pdev->devfn), pfun, idx);
+}
+
static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)
{
/* based on RTL8168FP_OOBMAC_BASE in vendor driver */
@@ -2233,6 +2287,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp)
static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
{
+ if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
+ return;
+
set_bit(flag, tp->wk.flags);
schedule_work(&tp->wk.work);
}
@@ -2603,8 +2660,7 @@ static void rtl_set_rx_mode(struct net_device *dev)
rx_mode |= AcceptAllPhys;
} else if (!(dev->flags & IFF_MULTICAST)) {
rx_mode &= ~AcceptMulticast;
- } else if (netdev_mc_count(dev) > MC_FILTER_LIMIT ||
- dev->flags & IFF_ALLMULTI ||
+ } else if (dev->flags & IFF_ALLMULTI ||
tp->mac_version == RTL_GIGA_MAC_VER_35) {
/* accept all multicasts */
} else if (netdev_mc_empty(dev)) {
@@ -3106,6 +3162,33 @@ static void rtl_hw_start_8168g_2(struct rtl8169_private *tp)
rtl_ephy_init(tp, e_info_8168g_2);
}
+static void rtl8411b_fix_phy_down(struct rtl8169_private *tp)
+{
+ static const u16 fix_data[] = {
+/* 0xf800 */ 0xe008, 0xe00a, 0xe00c, 0xe00e, 0xe027, 0xe04f, 0xe05e, 0xe065,
+/* 0xf810 */ 0xc602, 0xbe00, 0x0000, 0xc502, 0xbd00, 0x074c, 0xc302, 0xbb00,
+/* 0xf820 */ 0x080a, 0x6420, 0x48c2, 0x8c20, 0xc516, 0x64a4, 0x49c0, 0xf009,
+/* 0xf830 */ 0x74a2, 0x8ca5, 0x74a0, 0xc50e, 0x9ca2, 0x1c11, 0x9ca0, 0xe006,
+/* 0xf840 */ 0x74f8, 0x48c4, 0x8cf8, 0xc404, 0xbc00, 0xc403, 0xbc00, 0x0bf2,
+/* 0xf850 */ 0x0c0a, 0xe434, 0xd3c0, 0x49d9, 0xf01f, 0xc526, 0x64a5, 0x1400,
+/* 0xf860 */ 0xf007, 0x0c01, 0x8ca5, 0x1c15, 0xc51b, 0x9ca0, 0xe013, 0xc519,
+/* 0xf870 */ 0x74a0, 0x48c4, 0x8ca0, 0xc516, 0x74a4, 0x48c8, 0x48ca, 0x9ca4,
+/* 0xf880 */ 0xc512, 0x1b00, 0x9ba0, 0x1b1c, 0x483f, 0x9ba2, 0x1b04, 0xc508,
+/* 0xf890 */ 0x9ba0, 0xc505, 0xbd00, 0xc502, 0xbd00, 0x0300, 0x051e, 0xe434,
+/* 0xf8a0 */ 0xe018, 0xe092, 0xde20, 0xd3c0, 0xc50f, 0x76a4, 0x49e3, 0xf007,
+/* 0xf8b0 */ 0x49c0, 0xf103, 0xc607, 0xbe00, 0xc606, 0xbe00, 0xc602, 0xbe00,
+/* 0xf8c0 */ 0x0c4c, 0x0c28, 0x0c2c, 0xdc00, 0xc707, 0x1d00, 0x8de2, 0x48c1,
+/* 0xf8d0 */ 0xc502, 0xbd00, 0x00aa, 0xe0c0, 0xc502, 0xbd00, 0x0132
+ };
+ unsigned long flags;
+ int i;
+
+ raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(fix_data); i++)
+ __r8168_mac_ocp_write(tp, 0xf800 + 2 * i, fix_data[i]);
+ raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
+}
+
static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
{
static const struct ephy_info e_info_8411_2[] = {
@@ -3139,117 +3222,7 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
mdelay(3);
r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
- r8168_mac_ocp_write(tp, 0xF800, 0xE008);
- r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
- r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
- r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
- r8168_mac_ocp_write(tp, 0xF808, 0xE027);
- r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
- r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
- r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
- r8168_mac_ocp_write(tp, 0xF810, 0xC602);
- r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
- r8168_mac_ocp_write(tp, 0xF814, 0x0000);
- r8168_mac_ocp_write(tp, 0xF816, 0xC502);
- r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
- r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
- r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
- r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
- r8168_mac_ocp_write(tp, 0xF820, 0x080A);
- r8168_mac_ocp_write(tp, 0xF822, 0x6420);
- r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
- r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
- r8168_mac_ocp_write(tp, 0xF828, 0xC516);
- r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
- r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
- r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
- r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
- r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
- r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
- r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
- r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
- r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
- r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
- r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
- r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
- r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
- r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
- r8168_mac_ocp_write(tp, 0xF846, 0xC404);
- r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
- r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
- r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
- r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
- r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
- r8168_mac_ocp_write(tp, 0xF852, 0xE434);
- r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
- r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
- r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
- r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
- r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
- r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
- r8168_mac_ocp_write(tp, 0xF860, 0xF007);
- r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
- r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
- r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
- r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
- r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
- r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
- r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
- r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
- r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
- r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
- r8168_mac_ocp_write(tp, 0xF876, 0xC516);
- r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
- r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
- r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
- r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
- r8168_mac_ocp_write(tp, 0xF880, 0xC512);
- r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
- r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
- r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
- r8168_mac_ocp_write(tp, 0xF888, 0x483F);
- r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
- r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
- r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
- r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
- r8168_mac_ocp_write(tp, 0xF892, 0xC505);
- r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
- r8168_mac_ocp_write(tp, 0xF896, 0xC502);
- r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
- r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
- r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
- r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
- r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
- r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
- r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
- r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
- r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
- r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
- r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
- r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
- r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
- r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
- r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
- r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
- r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
- r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
- r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
- r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
- r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
- r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
- r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
- r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
- r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
- r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
- r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
- r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
- r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
- r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
- r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
- r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
- r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
- r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
- r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
+ rtl8411b_fix_phy_down(tp);
r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
@@ -4561,8 +4534,7 @@ static void rtl_task(struct work_struct *work)
rtnl_lock();
- if (!netif_running(tp->dev) ||
- !test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
+ if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
goto out_unlock;
if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) {
@@ -5227,6 +5199,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
raw_spin_lock_init(&tp->cfg9346_usage_lock);
raw_spin_lock_init(&tp->config25_lock);
raw_spin_lock_init(&tp->mac_ocp_lock);
+ mutex_init(&tp->led_lock);
dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev,
struct pcpu_sw_netstats);
@@ -5383,6 +5356,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
+ if (IS_ENABLED(CONFIG_R8169_LEDS) &&
+ tp->mac_version > RTL_GIGA_MAC_VER_06 &&
+ tp->mac_version < RTL_GIGA_MAC_VER_61)
+ rtl8168_init_leds(dev);
+
netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n",
rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq);
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
index 8ef5b0241e64..d6136fe5c206 100644
--- a/drivers/net/ethernet/renesas/Kconfig
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -40,11 +40,21 @@ config RAVB
config RENESAS_ETHER_SWITCH
tristate "Renesas Ethernet Switch support"
depends on ARCH_RENESAS || COMPILE_TEST
- depends on PTP_1588_CLOCK_OPTIONAL
+ depends on PTP_1588_CLOCK
select CRC32
select MII
select PHYLINK
+ select RENESAS_GEN4_PTP
help
Renesas Ethernet Switch device driver.
+config RENESAS_GEN4_PTP
+ tristate "Renesas R-Car Gen4 gPTP support" if COMPILE_TEST
+ depends on PTP_1588_CLOCK
+ select CRC32
+ select MII
+ select PHYLIB
+ help
+ Renesas R-Car Gen4 gPTP device driver.
+
endif # NET_VENDOR_RENESAS
diff --git a/drivers/net/ethernet/renesas/Makefile b/drivers/net/ethernet/renesas/Makefile
index e8fd85b5fe8f..9070acfd6aaf 100644
--- a/drivers/net/ethernet/renesas/Makefile
+++ b/drivers/net/ethernet/renesas/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_SH_ETH) += sh_eth.o
ravb-objs := ravb_main.o ravb_ptp.o
obj-$(CONFIG_RAVB) += ravb.o
-rswitch_drv-objs := rswitch.o rcar_gen4_ptp.o
-obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch_drv.o
+obj-$(CONFIG_RENESAS_ETHER_SWITCH) += rswitch.o
+
+obj-$(CONFIG_RENESAS_GEN4_PTP) += rcar_gen4_ptp.o
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 8649b3e90edb..f7566cfa45ca 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -772,29 +772,25 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
struct ravb_rx_desc *desc;
struct sk_buff *skb;
dma_addr_t dma_addr;
+ int rx_packets = 0;
u8 desc_status;
- int boguscnt;
u16 pkt_len;
u8 die_dt;
int entry;
int limit;
+ int i;
entry = priv->cur_rx[q] % priv->num_rx_ring[q];
- boguscnt = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q];
+ limit = priv->dirty_rx[q] + priv->num_rx_ring[q] - priv->cur_rx[q];
stats = &priv->stats[q];
- boguscnt = min(boguscnt, *quota);
- limit = boguscnt;
desc = &priv->gbeth_rx_ring[entry];
- while (desc->die_dt != DT_FEMPTY) {
+ for (i = 0; i < limit && rx_packets < *quota && desc->die_dt != DT_FEMPTY; i++) {
/* Descriptor type must be checked before all other reads */
dma_rmb();
desc_status = desc->msc;
pkt_len = le16_to_cpu(desc->ds_cc) & RX_DS;
- if (--boguscnt < 0)
- break;
-
/* We use 0-byte descriptors to mark the DMA mapping errors */
if (!pkt_len)
continue;
@@ -820,7 +816,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, ndev);
napi_gro_receive(&priv->napi[q], skb);
- stats->rx_packets++;
+ rx_packets++;
stats->rx_bytes += pkt_len;
break;
case DT_FSTART:
@@ -848,7 +844,7 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
eth_type_trans(priv->rx_1st_skb, ndev);
napi_gro_receive(&priv->napi[q],
priv->rx_1st_skb);
- stats->rx_packets++;
+ rx_packets++;
stats->rx_bytes += pkt_len;
break;
}
@@ -887,9 +883,9 @@ static bool ravb_rx_gbeth(struct net_device *ndev, int *quota, int q)
desc->die_dt = DT_FEMPTY;
}
- *quota -= limit - (++boguscnt);
-
- return boguscnt <= 0;
+ stats->rx_packets += rx_packets;
+ *quota -= rx_packets;
+ return *quota == 0;
}
/* Packet receive function for Ethernet AVB */
@@ -1949,7 +1945,7 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev)
struct ravb_tstamp_skb *ts_skb;
struct ravb_tx_desc *desc;
unsigned long flags;
- u32 dma_addr;
+ dma_addr_t dma_addr;
void *buffer;
u32 entry;
u32 len;
diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c
index c007e33c47e1..72e7fcc56693 100644
--- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.c
+++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.c
@@ -14,7 +14,7 @@
#include "rcar_gen4_ptp.h"
#define ptp_to_priv(ptp) container_of(ptp, struct rcar_gen4_ptp_private, info)
-static const struct rcar_gen4_ptp_reg_offset s4_offs = {
+static const struct rcar_gen4_ptp_reg_offset gen4_offs = {
.enable = PTPTMEC,
.disable = PTPTMDC,
.increment = PTPTIVC0,
@@ -130,25 +130,42 @@ static struct ptp_clock_info rcar_gen4_ptp_info = {
.enable = rcar_gen4_ptp_enable,
};
-static void rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv,
- enum rcar_gen4_ptp_reg_layout layout)
+static int rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv,
+ enum rcar_gen4_ptp_reg_layout layout)
{
- WARN_ON(layout != RCAR_GEN4_PTP_REG_LAYOUT_S4);
+ if (layout != RCAR_GEN4_PTP_REG_LAYOUT)
+ return -EINVAL;
- ptp_priv->offs = &s4_offs;
+ ptp_priv->offs = &gen4_offs;
+
+ return 0;
+}
+
+static s64 rcar_gen4_ptp_rate_to_increment(u32 rate)
+{
+ /* Timer increment in ns.
+ * bit[31:27] - integer
+ * bit[26:0] - decimal
+ * increment[ns] = perid[ns] * 2^27 => (1ns * 2^27) / rate[hz]
+ */
+ return div_s64(1000000000LL << 27, rate);
}
int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
- enum rcar_gen4_ptp_reg_layout layout, u32 clock)
+ enum rcar_gen4_ptp_reg_layout layout, u32 rate)
{
+ int ret;
+
if (ptp_priv->initialized)
return 0;
spin_lock_init(&ptp_priv->lock);
- rcar_gen4_ptp_set_offs(ptp_priv, layout);
+ ret = rcar_gen4_ptp_set_offs(ptp_priv, layout);
+ if (ret)
+ return ret;
- ptp_priv->default_addend = clock;
+ ptp_priv->default_addend = rcar_gen4_ptp_rate_to_increment(rate);
iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment);
ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL);
if (IS_ERR(ptp_priv->clock))
@@ -159,6 +176,7 @@ int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
return 0;
}
+EXPORT_SYMBOL_GPL(rcar_gen4_ptp_register);
int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv)
{
@@ -166,6 +184,7 @@ int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv)
return ptp_clock_unregister(ptp_priv->clock);
}
+EXPORT_SYMBOL_GPL(rcar_gen4_ptp_unregister);
struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev)
{
@@ -179,3 +198,8 @@ struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev)
return ptp;
}
+EXPORT_SYMBOL_GPL(rcar_gen4_ptp_alloc);
+
+MODULE_AUTHOR("Yoshihiro Shimoda");
+MODULE_DESCRIPTION("Renesas R-Car Gen4 gPTP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h
index b1bbea8d3a52..e22da5acd53d 100644
--- a/drivers/net/ethernet/renesas/rcar_gen4_ptp.h
+++ b/drivers/net/ethernet/renesas/rcar_gen4_ptp.h
@@ -9,13 +9,10 @@
#include <linux/ptp_clock_kernel.h>
-#define PTPTIVC_INIT 0x19000000 /* 320MHz */
-#define RCAR_GEN4_PTP_CLOCK_S4 PTPTIVC_INIT
#define RCAR_GEN4_GPTP_OFFSET_S4 0x00018000
-/* for rcar_gen4_ptp_init */
enum rcar_gen4_ptp_reg_layout {
- RCAR_GEN4_PTP_REG_LAYOUT_S4
+ RCAR_GEN4_PTP_REG_LAYOUT
};
/* driver's definitions */
@@ -28,7 +25,7 @@ enum rcar_gen4_ptp_reg_layout {
#define PTPRO 0
-enum rcar_gen4_ptp_reg_s4 {
+enum rcar_gen4_ptp_reg {
PTPTMEC = PTPRO + 0x0010,
PTPTMDC = PTPRO + 0x0014,
PTPTIVC0 = PTPRO + 0x0020,
@@ -65,7 +62,7 @@ struct rcar_gen4_ptp_private {
};
int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
- enum rcar_gen4_ptp_reg_layout layout, u32 clock);
+ enum rcar_gen4_ptp_reg_layout layout, u32 rate);
int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv);
struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev);
diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c
index e77c6ff93d81..dcab638c57fe 100644
--- a/drivers/net/ethernet/renesas/rswitch.c
+++ b/drivers/net/ethernet/renesas/rswitch.c
@@ -56,7 +56,8 @@ static void rswitch_clock_disable(struct rswitch_private *priv)
iowrite32(RCDC_RCD, priv->addr + RCDC);
}
-static bool rswitch_agent_clock_is_enabled(void __iomem *coma_addr, int port)
+static bool rswitch_agent_clock_is_enabled(void __iomem *coma_addr,
+ unsigned int port)
{
u32 val = ioread32(coma_addr + RCEC);
@@ -66,7 +67,8 @@ static bool rswitch_agent_clock_is_enabled(void __iomem *coma_addr, int port)
return false;
}
-static void rswitch_agent_clock_ctrl(void __iomem *coma_addr, int port, int enable)
+static void rswitch_agent_clock_ctrl(void __iomem *coma_addr, unsigned int port,
+ int enable)
{
u32 val;
@@ -100,7 +102,7 @@ static void rswitch_coma_init(struct rswitch_private *priv)
/* R-Switch-2 block (TOP) */
static void rswitch_top_init(struct rswitch_private *priv)
{
- int i;
+ unsigned int i;
for (i = 0; i < RSWITCH_MAX_NUM_QUEUES; i++)
iowrite32((i / 16) << (GWCA_INDEX * 8), priv->addr + TPEMIMC7(i));
@@ -109,7 +111,7 @@ static void rswitch_top_init(struct rswitch_private *priv)
/* Forwarding engine block (MFWD) */
static void rswitch_fwd_init(struct rswitch_private *priv)
{
- int i;
+ unsigned int i;
/* For ETHA */
for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
@@ -166,7 +168,7 @@ static int rswitch_gwca_axi_ram_reset(struct rswitch_private *priv)
static bool rswitch_is_any_data_irq(struct rswitch_private *priv, u32 *dis, bool tx)
{
u32 *mask = tx ? priv->gwca.tx_irq_bits : priv->gwca.rx_irq_bits;
- int i;
+ unsigned int i;
for (i = 0; i < RSWITCH_NUM_IRQ_REGS; i++) {
if (dis[i] & mask[i])
@@ -178,7 +180,7 @@ static bool rswitch_is_any_data_irq(struct rswitch_private *priv, u32 *dis, bool
static void rswitch_get_data_irq_status(struct rswitch_private *priv, u32 *dis)
{
- int i;
+ unsigned int i;
for (i = 0; i < RSWITCH_NUM_IRQ_REGS; i++) {
dis[i] = ioread32(priv->addr + GWDIS(i));
@@ -186,23 +188,26 @@ static void rswitch_get_data_irq_status(struct rswitch_private *priv, u32 *dis)
}
}
-static void rswitch_enadis_data_irq(struct rswitch_private *priv, int index, bool enable)
+static void rswitch_enadis_data_irq(struct rswitch_private *priv,
+ unsigned int index, bool enable)
{
u32 offs = enable ? GWDIE(index / 32) : GWDID(index / 32);
iowrite32(BIT(index % 32), priv->addr + offs);
}
-static void rswitch_ack_data_irq(struct rswitch_private *priv, int index)
+static void rswitch_ack_data_irq(struct rswitch_private *priv,
+ unsigned int index)
{
u32 offs = GWDIS(index / 32);
iowrite32(BIT(index % 32), priv->addr + offs);
}
-static int rswitch_next_queue_index(struct rswitch_gwca_queue *gq, bool cur, int num)
+static unsigned int rswitch_next_queue_index(struct rswitch_gwca_queue *gq,
+ bool cur, unsigned int num)
{
- int index = cur ? gq->cur : gq->dirty;
+ unsigned int index = cur ? gq->cur : gq->dirty;
if (index + num >= gq->ring_size)
index = (index + num) % gq->ring_size;
@@ -212,7 +217,7 @@ static int rswitch_next_queue_index(struct rswitch_gwca_queue *gq, bool cur, int
return index;
}
-static int rswitch_get_num_cur_queues(struct rswitch_gwca_queue *gq)
+static unsigned int rswitch_get_num_cur_queues(struct rswitch_gwca_queue *gq)
{
if (gq->cur >= gq->dirty)
return gq->cur - gq->dirty;
@@ -230,28 +235,28 @@ static bool rswitch_is_queue_rxed(struct rswitch_gwca_queue *gq)
return false;
}
-static int rswitch_gwca_queue_alloc_skb(struct rswitch_gwca_queue *gq,
- int start_index, int num)
+static int rswitch_gwca_queue_alloc_rx_buf(struct rswitch_gwca_queue *gq,
+ unsigned int start_index,
+ unsigned int num)
{
- int i, index;
+ unsigned int i, index;
for (i = 0; i < num; i++) {
index = (i + start_index) % gq->ring_size;
- if (gq->skbs[index])
+ if (gq->rx_bufs[index])
continue;
- gq->skbs[index] = netdev_alloc_skb_ip_align(gq->ndev,
- PKT_BUF_SZ + RSWITCH_ALIGN - 1);
- if (!gq->skbs[index])
+ gq->rx_bufs[index] = netdev_alloc_frag(RSWITCH_BUF_SIZE);
+ if (!gq->rx_bufs[index])
goto err;
}
return 0;
err:
- for (i--; i >= 0; i--) {
+ for (; i-- > 0; ) {
index = (i + start_index) % gq->ring_size;
- dev_kfree_skb(gq->skbs[index]);
- gq->skbs[index] = NULL;
+ skb_free_frag(gq->rx_bufs[index]);
+ gq->rx_bufs[index] = NULL;
}
return -ENOMEM;
@@ -260,7 +265,7 @@ err:
static void rswitch_gwca_queue_free(struct net_device *ndev,
struct rswitch_gwca_queue *gq)
{
- int i;
+ unsigned int i;
if (!gq->dir_tx) {
dma_free_coherent(ndev->dev.parent,
@@ -269,16 +274,19 @@ static void rswitch_gwca_queue_free(struct net_device *ndev,
gq->rx_ring = NULL;
for (i = 0; i < gq->ring_size; i++)
- dev_kfree_skb(gq->skbs[i]);
+ skb_free_frag(gq->rx_bufs[i]);
+ kfree(gq->rx_bufs);
+ gq->rx_bufs = NULL;
} else {
dma_free_coherent(ndev->dev.parent,
sizeof(struct rswitch_ext_desc) *
(gq->ring_size + 1), gq->tx_ring, gq->ring_dma);
gq->tx_ring = NULL;
+ kfree(gq->skbs);
+ gq->skbs = NULL;
+ kfree(gq->unmap_addrs);
+ gq->unmap_addrs = NULL;
}
-
- kfree(gq->skbs);
- gq->skbs = NULL;
}
static void rswitch_gwca_ts_queue_free(struct rswitch_private *priv)
@@ -294,25 +302,31 @@ static void rswitch_gwca_ts_queue_free(struct rswitch_private *priv)
static int rswitch_gwca_queue_alloc(struct net_device *ndev,
struct rswitch_private *priv,
struct rswitch_gwca_queue *gq,
- bool dir_tx, int ring_size)
+ bool dir_tx, unsigned int ring_size)
{
- int i, bit;
+ unsigned int i, bit;
gq->dir_tx = dir_tx;
gq->ring_size = ring_size;
gq->ndev = ndev;
- gq->skbs = kcalloc(gq->ring_size, sizeof(*gq->skbs), GFP_KERNEL);
- if (!gq->skbs)
- return -ENOMEM;
-
if (!dir_tx) {
- rswitch_gwca_queue_alloc_skb(gq, 0, gq->ring_size);
+ gq->rx_bufs = kcalloc(gq->ring_size, sizeof(*gq->rx_bufs), GFP_KERNEL);
+ if (!gq->rx_bufs)
+ return -ENOMEM;
+ if (rswitch_gwca_queue_alloc_rx_buf(gq, 0, gq->ring_size) < 0)
+ goto out;
gq->rx_ring = dma_alloc_coherent(ndev->dev.parent,
sizeof(struct rswitch_ext_ts_desc) *
(gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
} else {
+ gq->skbs = kcalloc(gq->ring_size, sizeof(*gq->skbs), GFP_KERNEL);
+ if (!gq->skbs)
+ return -ENOMEM;
+ gq->unmap_addrs = kcalloc(gq->ring_size, sizeof(*gq->unmap_addrs), GFP_KERNEL);
+ if (!gq->unmap_addrs)
+ goto out;
gq->tx_ring = dma_alloc_coherent(ndev->dev.parent,
sizeof(struct rswitch_ext_desc) *
(gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
@@ -351,22 +365,23 @@ static int rswitch_gwca_queue_format(struct net_device *ndev,
struct rswitch_private *priv,
struct rswitch_gwca_queue *gq)
{
- int ring_size = sizeof(struct rswitch_ext_desc) * gq->ring_size;
+ unsigned int ring_size = sizeof(struct rswitch_ext_desc) * gq->ring_size;
struct rswitch_ext_desc *desc;
struct rswitch_desc *linkfix;
dma_addr_t dma_addr;
- int i;
+ unsigned int i;
memset(gq->tx_ring, 0, ring_size);
for (i = 0, desc = gq->tx_ring; i < gq->ring_size; i++, desc++) {
if (!gq->dir_tx) {
dma_addr = dma_map_single(ndev->dev.parent,
- gq->skbs[i]->data, PKT_BUF_SZ,
+ gq->rx_bufs[i] + RSWITCH_HEADROOM,
+ RSWITCH_MAP_BUF_SIZE,
DMA_FROM_DEVICE);
if (dma_mapping_error(ndev->dev.parent, dma_addr))
goto err;
- desc->desc.info_ds = cpu_to_le16(PKT_BUF_SZ);
+ desc->desc.info_ds = cpu_to_le16(RSWITCH_DESC_BUF_SIZE);
rswitch_desc_set_dptr(&desc->desc, dma_addr);
desc->desc.die_dt = DT_FEMPTY | DIE;
} else {
@@ -387,10 +402,10 @@ static int rswitch_gwca_queue_format(struct net_device *ndev,
err:
if (!gq->dir_tx) {
- for (i--, desc = gq->tx_ring; i >= 0; i--, desc++) {
+ for (desc = gq->tx_ring; i-- > 0; desc++) {
dma_addr = rswitch_desc_get_dptr(&desc->desc);
- dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_unmap_single(ndev->dev.parent, dma_addr,
+ RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE);
}
}
@@ -398,11 +413,12 @@ err:
}
static void rswitch_gwca_ts_queue_fill(struct rswitch_private *priv,
- int start_index, int num)
+ unsigned int start_index,
+ unsigned int num)
{
struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue;
struct rswitch_ts_desc *desc;
- int i, index;
+ unsigned int i, index;
for (i = 0; i < num; i++) {
index = (i + start_index) % gq->ring_size;
@@ -413,24 +429,26 @@ static void rswitch_gwca_ts_queue_fill(struct rswitch_private *priv,
static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev,
struct rswitch_gwca_queue *gq,
- int start_index, int num)
+ unsigned int start_index,
+ unsigned int num)
{
struct rswitch_device *rdev = netdev_priv(ndev);
struct rswitch_ext_ts_desc *desc;
+ unsigned int i, index;
dma_addr_t dma_addr;
- int i, index;
for (i = 0; i < num; i++) {
index = (i + start_index) % gq->ring_size;
desc = &gq->rx_ring[index];
if (!gq->dir_tx) {
dma_addr = dma_map_single(ndev->dev.parent,
- gq->skbs[index]->data, PKT_BUF_SZ,
+ gq->rx_bufs[index] + RSWITCH_HEADROOM,
+ RSWITCH_MAP_BUF_SIZE,
DMA_FROM_DEVICE);
if (dma_mapping_error(ndev->dev.parent, dma_addr))
goto err;
- desc->desc.info_ds = cpu_to_le16(PKT_BUF_SZ);
+ desc->desc.info_ds = cpu_to_le16(RSWITCH_DESC_BUF_SIZE);
rswitch_desc_set_dptr(&desc->desc, dma_addr);
dma_wmb();
desc->desc.die_dt = DT_FEMPTY | DIE;
@@ -444,12 +462,12 @@ static int rswitch_gwca_queue_ext_ts_fill(struct net_device *ndev,
err:
if (!gq->dir_tx) {
- for (i--; i >= 0; i--) {
+ for (; i-- > 0; ) {
index = (i + start_index) % gq->ring_size;
desc = &gq->rx_ring[index];
dma_addr = rswitch_desc_get_dptr(&desc->desc);
- dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_unmap_single(ndev->dev.parent, dma_addr,
+ RSWITCH_MAP_BUF_SIZE, DMA_FROM_DEVICE);
}
}
@@ -460,7 +478,7 @@ static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev,
struct rswitch_private *priv,
struct rswitch_gwca_queue *gq)
{
- int ring_size = sizeof(struct rswitch_ext_ts_desc) * gq->ring_size;
+ unsigned int ring_size = sizeof(struct rswitch_ext_ts_desc) * gq->ring_size;
struct rswitch_ext_ts_desc *desc;
struct rswitch_desc *linkfix;
int err;
@@ -487,7 +505,7 @@ static int rswitch_gwca_queue_ext_ts_format(struct net_device *ndev,
static int rswitch_gwca_linkfix_alloc(struct rswitch_private *priv)
{
- int i, num_queues = priv->gwca.num_queues;
+ unsigned int i, num_queues = priv->gwca.num_queues;
struct rswitch_gwca *gwca = &priv->gwca;
struct device *dev = &priv->pdev->dev;
@@ -537,7 +555,7 @@ static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv)
static struct rswitch_gwca_queue *rswitch_gwca_get(struct rswitch_private *priv)
{
struct rswitch_gwca_queue *gq;
- int index;
+ unsigned int index;
index = find_first_zero_bit(priv->gwca.used, priv->gwca.num_queues);
if (index >= priv->gwca.num_queues)
@@ -583,7 +601,7 @@ static void rswitch_txdmac_free(struct net_device *ndev)
rswitch_gwca_put(rdev->priv, rdev->tx_queue);
}
-static int rswitch_txdmac_init(struct rswitch_private *priv, int index)
+static int rswitch_txdmac_init(struct rswitch_private *priv, unsigned int index)
{
struct rswitch_device *rdev = priv->rdev[index];
@@ -617,7 +635,7 @@ static void rswitch_rxdmac_free(struct net_device *ndev)
rswitch_gwca_put(rdev->priv, rdev->rx_queue);
}
-static int rswitch_rxdmac_init(struct rswitch_private *priv, int index)
+static int rswitch_rxdmac_init(struct rswitch_private *priv, unsigned int index)
{
struct rswitch_device *rdev = priv->rdev[index];
struct net_device *ndev = rdev->ndev;
@@ -627,7 +645,8 @@ static int rswitch_rxdmac_init(struct rswitch_private *priv, int index)
static int rswitch_gwca_hw_init(struct rswitch_private *priv)
{
- int i, err;
+ unsigned int i;
+ int err;
err = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE);
if (err < 0)
@@ -649,6 +668,8 @@ static int rswitch_gwca_hw_init(struct rswitch_private *priv)
iowrite32(upper_32_bits(priv->gwca.linkfix_table_dma), priv->addr + GWDCBAC0);
iowrite32(lower_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC10);
iowrite32(upper_32_bits(priv->gwca.ts_queue.ring_dma), priv->addr + GWTDCAC00);
+ iowrite32(GWMDNC_TSDMN(1) | GWMDNC_TXDMN(0x1e) | GWMDNC_RXDMN(0x1f),
+ priv->addr + GWMDNC);
iowrite32(GWCA_TS_IRQ_BIT, priv->addr + GWTSDCC0);
iowrite32(GWTPC_PPPL(GWCA_IPV_NUM), priv->addr + GWTPC0);
@@ -693,15 +714,88 @@ static int rswitch_gwca_halt(struct rswitch_private *priv)
return err;
}
+static struct sk_buff *rswitch_rx_handle_desc(struct net_device *ndev,
+ struct rswitch_gwca_queue *gq,
+ struct rswitch_ext_ts_desc *desc)
+{
+ dma_addr_t dma_addr = rswitch_desc_get_dptr(&desc->desc);
+ u16 pkt_len = le16_to_cpu(desc->desc.info_ds) & RX_DS;
+ u8 die_dt = desc->desc.die_dt & DT_MASK;
+ struct sk_buff *skb = NULL;
+
+ dma_unmap_single(ndev->dev.parent, dma_addr, RSWITCH_MAP_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ /* The RX descriptor order will be one of the following:
+ * - FSINGLE
+ * - FSTART -> FEND
+ * - FSTART -> FMID -> FEND
+ */
+
+ /* Check whether the descriptor is unexpected order */
+ switch (die_dt) {
+ case DT_FSTART:
+ case DT_FSINGLE:
+ if (gq->skb_fstart) {
+ dev_kfree_skb_any(gq->skb_fstart);
+ gq->skb_fstart = NULL;
+ ndev->stats.rx_dropped++;
+ }
+ break;
+ case DT_FMID:
+ case DT_FEND:
+ if (!gq->skb_fstart) {
+ ndev->stats.rx_dropped++;
+ return NULL;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Handle the descriptor */
+ switch (die_dt) {
+ case DT_FSTART:
+ case DT_FSINGLE:
+ skb = build_skb(gq->rx_bufs[gq->cur], RSWITCH_BUF_SIZE);
+ if (skb) {
+ skb_reserve(skb, RSWITCH_HEADROOM);
+ skb_put(skb, pkt_len);
+ gq->pkt_len = pkt_len;
+ if (die_dt == DT_FSTART) {
+ gq->skb_fstart = skb;
+ skb = NULL;
+ }
+ }
+ break;
+ case DT_FMID:
+ case DT_FEND:
+ skb_add_rx_frag(gq->skb_fstart, skb_shinfo(gq->skb_fstart)->nr_frags,
+ virt_to_page(gq->rx_bufs[gq->cur]),
+ offset_in_page(gq->rx_bufs[gq->cur]) + RSWITCH_HEADROOM,
+ pkt_len, RSWITCH_BUF_SIZE);
+ if (die_dt == DT_FEND) {
+ skb = gq->skb_fstart;
+ gq->skb_fstart = NULL;
+ }
+ gq->pkt_len += pkt_len;
+ break;
+ default:
+ netdev_err(ndev, "%s: unexpected value (%x)\n", __func__, die_dt);
+ break;
+ }
+
+ return skb;
+}
+
static bool rswitch_rx(struct net_device *ndev, int *quota)
{
struct rswitch_device *rdev = netdev_priv(ndev);
struct rswitch_gwca_queue *gq = rdev->rx_queue;
struct rswitch_ext_ts_desc *desc;
- int limit, boguscnt, num, ret;
+ int limit, boguscnt, ret;
struct sk_buff *skb;
- dma_addr_t dma_addr;
- u16 pkt_len;
+ unsigned int num;
u32 get_ts;
if (*quota <= 0)
@@ -713,11 +807,10 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
desc = &gq->rx_ring[gq->cur];
while ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY) {
dma_rmb();
- pkt_len = le16_to_cpu(desc->desc.info_ds) & RX_DS;
- skb = gq->skbs[gq->cur];
- gq->skbs[gq->cur] = NULL;
- dma_addr = rswitch_desc_get_dptr(&desc->desc);
- dma_unmap_single(ndev->dev.parent, dma_addr, PKT_BUF_SZ, DMA_FROM_DEVICE);
+ skb = rswitch_rx_handle_desc(ndev, gq, desc);
+ if (!skb)
+ goto out;
+
get_ts = rdev->priv->ptp_priv->tstamp_rx_ctrl & RCAR_GEN4_RXTSTAMP_TYPE_V2_L2_EVENT;
if (get_ts) {
struct skb_shared_hwtstamps *shhwtstamps;
@@ -729,12 +822,13 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
ts.tv_nsec = __le32_to_cpu(desc->ts_nsec & cpu_to_le32(0x3fffffff));
shhwtstamps->hwtstamp = timespec64_to_ktime(ts);
}
- skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, ndev);
napi_gro_receive(&rdev->napi, skb);
rdev->ndev->stats.rx_packets++;
- rdev->ndev->stats.rx_bytes += pkt_len;
+ rdev->ndev->stats.rx_bytes += gq->pkt_len;
+out:
+ gq->rx_bufs[gq->cur] = NULL;
gq->cur = rswitch_next_queue_index(gq, true, 1);
desc = &gq->rx_ring[gq->cur];
@@ -743,7 +837,7 @@ static bool rswitch_rx(struct net_device *ndev, int *quota)
}
num = rswitch_get_num_cur_queues(gq);
- ret = rswitch_gwca_queue_alloc_skb(gq, gq->dirty, num);
+ ret = rswitch_gwca_queue_alloc_rx_buf(gq, gq->dirty, num);
if (ret < 0)
goto err;
ret = rswitch_gwca_queue_ext_ts_fill(ndev, gq, gq->dirty, num);
@@ -761,39 +855,32 @@ err:
return 0;
}
-static int rswitch_tx_free(struct net_device *ndev, bool free_txed_only)
+static void rswitch_tx_free(struct net_device *ndev)
{
struct rswitch_device *rdev = netdev_priv(ndev);
struct rswitch_gwca_queue *gq = rdev->tx_queue;
struct rswitch_ext_desc *desc;
- dma_addr_t dma_addr;
struct sk_buff *skb;
- int free_num = 0;
- int size;
for (; rswitch_get_num_cur_queues(gq) > 0;
gq->dirty = rswitch_next_queue_index(gq, false, 1)) {
desc = &gq->tx_ring[gq->dirty];
- if (free_txed_only && (desc->desc.die_dt & DT_MASK) != DT_FEMPTY)
+ if ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY)
break;
dma_rmb();
- size = le16_to_cpu(desc->desc.info_ds) & TX_DS;
skb = gq->skbs[gq->dirty];
if (skb) {
- dma_addr = rswitch_desc_get_dptr(&desc->desc);
- dma_unmap_single(ndev->dev.parent, dma_addr,
- size, DMA_TO_DEVICE);
+ dma_unmap_single(ndev->dev.parent,
+ gq->unmap_addrs[gq->dirty],
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(gq->skbs[gq->dirty]);
gq->skbs[gq->dirty] = NULL;
- free_num++;
+ rdev->ndev->stats.tx_packets++;
+ rdev->ndev->stats.tx_bytes += skb->len;
}
desc->desc.die_dt = DT_EEMPTY;
- rdev->ndev->stats.tx_packets++;
- rdev->ndev->stats.tx_bytes += size;
}
-
- return free_num;
}
static int rswitch_poll(struct napi_struct *napi, int budget)
@@ -808,7 +895,7 @@ static int rswitch_poll(struct napi_struct *napi, int budget)
priv = rdev->priv;
retry:
- rswitch_tx_free(ndev, true);
+ rswitch_tx_free(ndev);
if (rswitch_rx(ndev, &quota))
goto out;
@@ -851,7 +938,7 @@ static void rswitch_queue_interrupt(struct net_device *ndev)
static irqreturn_t rswitch_data_irq(struct rswitch_private *priv, u32 *dis)
{
struct rswitch_gwca_queue *gq;
- int i, index, bit;
+ unsigned int i, index, bit;
for (i = 0; i < priv->gwca.num_queues; i++) {
gq = &priv->gwca.queues[i];
@@ -918,8 +1005,8 @@ static void rswitch_ts(struct rswitch_private *priv)
struct skb_shared_hwtstamps shhwtstamps;
struct rswitch_ts_desc *desc;
struct timespec64 ts;
+ unsigned int num;
u32 tag, port;
- int num;
desc = &gq->ts_ring[gq->cur];
while ((desc->desc.die_dt & DT_MASK) != DT_FEMPTY_ND) {
@@ -1438,7 +1525,7 @@ err_init_one:
static void rswitch_ether_port_deinit_all(struct rswitch_private *priv)
{
- int i;
+ unsigned int i;
for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
phy_exit(priv->rdev[i]->serdes);
@@ -1500,31 +1587,10 @@ static int rswitch_stop(struct net_device *ndev)
return 0;
};
-static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+static bool rswitch_ext_desc_set_info1(struct rswitch_device *rdev,
+ struct sk_buff *skb,
+ struct rswitch_ext_desc *desc)
{
- struct rswitch_device *rdev = netdev_priv(ndev);
- struct rswitch_gwca_queue *gq = rdev->tx_queue;
- netdev_tx_t ret = NETDEV_TX_OK;
- struct rswitch_ext_desc *desc;
- dma_addr_t dma_addr;
-
- if (rswitch_get_num_cur_queues(gq) >= gq->ring_size - 1) {
- netif_stop_subqueue(ndev, 0);
- return NETDEV_TX_BUSY;
- }
-
- if (skb_put_padto(skb, ETH_ZLEN))
- return ret;
-
- dma_addr = dma_map_single(ndev->dev.parent, skb->data, skb->len, DMA_TO_DEVICE);
- if (dma_mapping_error(ndev->dev.parent, dma_addr))
- goto err_kfree;
-
- gq->skbs[gq->cur] = skb;
- desc = &gq->tx_ring[gq->cur];
- rswitch_desc_set_dptr(&desc->desc, dma_addr);
- desc->desc.info_ds = cpu_to_le16(skb->len);
-
desc->info1 = cpu_to_le64(INFO1_DV(BIT(rdev->etha->index)) |
INFO1_IPV(GWCA_IPV_NUM) | INFO1_FMT);
if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
@@ -1532,7 +1598,7 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd
ts_info = kzalloc(sizeof(*ts_info), GFP_ATOMIC);
if (!ts_info)
- goto err_unmap;
+ return false;
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
rdev->ts_tag++;
@@ -1546,18 +1612,97 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd
skb_tx_timestamp(skb);
}
+ return true;
+}
+
+static bool rswitch_ext_desc_set(struct rswitch_device *rdev,
+ struct sk_buff *skb,
+ struct rswitch_ext_desc *desc,
+ dma_addr_t dma_addr, u16 len, u8 die_dt)
+{
+ rswitch_desc_set_dptr(&desc->desc, dma_addr);
+ desc->desc.info_ds = cpu_to_le16(len);
+ if (!rswitch_ext_desc_set_info1(rdev, skb, desc))
+ return false;
+
dma_wmb();
- desc->desc.die_dt = DT_FSINGLE | DIE;
+ desc->desc.die_dt = die_dt;
+
+ return true;
+}
+
+static u8 rswitch_ext_desc_get_die_dt(unsigned int nr_desc, unsigned int index)
+{
+ if (nr_desc == 1)
+ return DT_FSINGLE | DIE;
+ if (index == 0)
+ return DT_FSTART;
+ if (nr_desc - 1 == index)
+ return DT_FEND | DIE;
+ return DT_FMID;
+}
+
+static u16 rswitch_ext_desc_get_len(u8 die_dt, unsigned int orig_len)
+{
+ switch (die_dt & DT_MASK) {
+ case DT_FSINGLE:
+ case DT_FEND:
+ return (orig_len % RSWITCH_DESC_BUF_SIZE) ?: RSWITCH_DESC_BUF_SIZE;
+ case DT_FSTART:
+ case DT_FMID:
+ return RSWITCH_DESC_BUF_SIZE;
+ default:
+ return 0;
+ }
+}
+
+static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct rswitch_device *rdev = netdev_priv(ndev);
+ struct rswitch_gwca_queue *gq = rdev->tx_queue;
+ dma_addr_t dma_addr, dma_addr_orig;
+ netdev_tx_t ret = NETDEV_TX_OK;
+ struct rswitch_ext_desc *desc;
+ unsigned int i, nr_desc;
+ u8 die_dt;
+ u16 len;
+
+ nr_desc = (skb->len - 1) / RSWITCH_DESC_BUF_SIZE + 1;
+ if (rswitch_get_num_cur_queues(gq) >= gq->ring_size - nr_desc) {
+ netif_stop_subqueue(ndev, 0);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (skb_put_padto(skb, ETH_ZLEN))
+ return ret;
+
+ dma_addr_orig = dma_map_single(ndev->dev.parent, skb->data, skb->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(ndev->dev.parent, dma_addr_orig))
+ goto err_kfree;
+
+ gq->skbs[gq->cur] = skb;
+ gq->unmap_addrs[gq->cur] = dma_addr_orig;
+
+ /* DT_FSTART should be set at last. So, this is reverse order. */
+ for (i = nr_desc; i-- > 0; ) {
+ desc = &gq->tx_ring[rswitch_next_queue_index(gq, true, i)];
+ die_dt = rswitch_ext_desc_get_die_dt(nr_desc, i);
+ dma_addr = dma_addr_orig + i * RSWITCH_DESC_BUF_SIZE;
+ len = rswitch_ext_desc_get_len(die_dt, skb->len);
+ if (!rswitch_ext_desc_set(rdev, skb, desc, dma_addr, len, die_dt))
+ goto err_unmap;
+ }
+
wmb(); /* gq->cur must be incremented after die_dt was set */
- gq->cur = rswitch_next_queue_index(gq, true, 1);
+ gq->cur = rswitch_next_queue_index(gq, true, nr_desc);
rswitch_modify(rdev->addr, GWTRC(gq->index), 0, BIT(gq->index % 32));
return ret;
err_unmap:
- dma_unmap_single(ndev->dev.parent, dma_addr, skb->len, DMA_TO_DEVICE);
+ dma_unmap_single(ndev->dev.parent, dma_addr_orig, skb->len, DMA_TO_DEVICE);
err_kfree:
dev_kfree_skb_any(skb);
@@ -1693,7 +1838,7 @@ static const struct of_device_id renesas_eth_sw_of_table[] = {
};
MODULE_DEVICE_TABLE(of, renesas_eth_sw_of_table);
-static void rswitch_etha_init(struct rswitch_private *priv, int index)
+static void rswitch_etha_init(struct rswitch_private *priv, unsigned int index)
{
struct rswitch_etha *etha = &priv->etha[index];
@@ -1709,7 +1854,7 @@ static void rswitch_etha_init(struct rswitch_private *priv, int index)
etha->psmcs = clk_get_rate(priv->clk) / 100000 / (25 * 2) - 1;
}
-static int rswitch_device_alloc(struct rswitch_private *priv, int index)
+static int rswitch_device_alloc(struct rswitch_private *priv, unsigned int index)
{
struct platform_device *pdev = priv->pdev;
struct rswitch_device *rdev;
@@ -1738,6 +1883,8 @@ static int rswitch_device_alloc(struct rswitch_private *priv, int index)
snprintf(ndev->name, IFNAMSIZ, "tsn%d", index);
ndev->netdev_ops = &rswitch_netdev_ops;
ndev->ethtool_ops = &rswitch_ethtool_ops;
+ ndev->max_mtu = RSWITCH_MAX_MTU;
+ ndev->min_mtu = ETH_MIN_MTU;
netif_napi_add(ndev, &rdev->napi, rswitch_poll);
@@ -1780,7 +1927,7 @@ out_get_params:
return err;
}
-static void rswitch_device_free(struct rswitch_private *priv, int index)
+static void rswitch_device_free(struct rswitch_private *priv, unsigned int index)
{
struct rswitch_device *rdev = priv->rdev[index];
struct net_device *ndev = rdev->ndev;
@@ -1832,8 +1979,8 @@ static int rswitch_init(struct rswitch_private *priv)
rswitch_fwd_init(priv);
- err = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT_S4,
- RCAR_GEN4_PTP_CLOCK_S4);
+ err = rcar_gen4_ptp_register(priv->ptp_priv, RCAR_GEN4_PTP_REG_LAYOUT,
+ clk_get_rate(priv->clk));
if (err < 0)
goto err_ptp_register;
diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h
index 27c9d3872c0e..72e3ff596d31 100644
--- a/drivers/net/ethernet/renesas/rswitch.h
+++ b/drivers/net/ethernet/renesas/rswitch.h
@@ -26,11 +26,17 @@
else
#define TX_RING_SIZE 1024
-#define RX_RING_SIZE 1024
+#define RX_RING_SIZE 4096
#define TS_RING_SIZE (TX_RING_SIZE * RSWITCH_NUM_PORTS)
-#define PKT_BUF_SZ 1584
+#define RSWITCH_MAX_MTU 9600
+#define RSWITCH_HEADROOM (NET_SKB_PAD + NET_IP_ALIGN)
+#define RSWITCH_DESC_BUF_SIZE 2048
+#define RSWITCH_TAILROOM SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
#define RSWITCH_ALIGN 128
+#define RSWITCH_BUF_SIZE (RSWITCH_HEADROOM + RSWITCH_DESC_BUF_SIZE + \
+ RSWITCH_TAILROOM + RSWITCH_ALIGN)
+#define RSWITCH_MAP_BUF_SIZE (RSWITCH_BUF_SIZE - RSWITCH_HEADROOM)
#define RSWITCH_MAX_CTAG_PCP 7
#define RSWITCH_TIMEOUT_US 100000
@@ -768,6 +774,10 @@ enum rswitch_gwca_mode {
#define GWARIRM_ARIOG BIT(0)
#define GWARIRM_ARR BIT(1)
+#define GWMDNC_TSDMN(num) (((num) << 16) & GENMASK(17, 16))
+#define GWMDNC_TXDMN(num) (((num) << 8) & GENMASK(12, 8))
+#define GWMDNC_RXDMN(num) ((num) & GENMASK(4, 0))
+
#define GWDCC_BALR BIT(24)
#define GWDCC_DCP_MASK GENMASK(18, 16)
#define GWDCC_DCP(prio) FIELD_PREP(GWDCC_DCP_MASK, (prio))
@@ -909,7 +919,7 @@ struct rswitch_ext_ts_desc {
} __packed;
struct rswitch_etha {
- int index;
+ unsigned int index;
void __iomem *addr;
void __iomem *coma_addr;
bool external_phy;
@@ -938,15 +948,28 @@ struct rswitch_gwca_queue {
/* Common */
dma_addr_t ring_dma;
- int ring_size;
- int cur;
- int dirty;
+ unsigned int ring_size;
+ unsigned int cur;
+ unsigned int dirty;
- /* For [rt]_ring */
- int index;
+ /* For [rt]x_ring */
+ unsigned int index;
bool dir_tx;
- struct sk_buff **skbs;
struct net_device *ndev; /* queue to ndev for irq */
+
+ union {
+ /* For TX */
+ struct {
+ struct sk_buff **skbs;
+ dma_addr_t *unmap_addrs;
+ };
+ /* For RX */
+ struct {
+ void **rx_bufs;
+ struct sk_buff *skb_fstart;
+ u16 pkt_len;
+ };
+ };
};
struct rswitch_gwca_ts_info {
@@ -959,7 +982,7 @@ struct rswitch_gwca_ts_info {
#define RSWITCH_NUM_IRQ_REGS (RSWITCH_MAX_NUM_QUEUES / BITS_PER_TYPE(u32))
struct rswitch_gwca {
- int index;
+ unsigned int index;
struct rswitch_desc *linkfix_table;
dma_addr_t linkfix_table_dma;
u32 linkfix_table_size;
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index 6dfa062feebc..8fa6c0e9195b 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -3706,13 +3706,13 @@ static int efx_ef10_ptp_set_ts_sync_events(struct efx_nic *efx, bool en,
}
static int efx_ef10_ptp_set_ts_config_vf(struct efx_nic *efx,
- struct hwtstamp_config *init)
+ struct kernel_hwtstamp_config *init)
{
return -EOPNOTSUPP;
}
static int efx_ef10_ptp_set_ts_config(struct efx_nic *efx,
- struct hwtstamp_config *init)
+ struct kernel_hwtstamp_config *init)
{
int rc;
diff --git a/drivers/net/ethernet/sfc/ef100_ethtool.c b/drivers/net/ethernet/sfc/ef100_ethtool.c
index 702abbe59b76..cf55202b3a7b 100644
--- a/drivers/net/ethernet/sfc/ef100_ethtool.c
+++ b/drivers/net/ethernet/sfc/ef100_ethtool.c
@@ -37,6 +37,7 @@ ef100_ethtool_get_ringparam(struct net_device *net_dev,
/* Ethtool options available
*/
const struct ethtool_ops ef100_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.get_drvinfo = efx_ethtool_get_drvinfo,
.get_msglevel = efx_ethtool_get_msglevel,
.set_msglevel = efx_ethtool_set_msglevel,
@@ -60,8 +61,6 @@ const struct ethtool_ops ef100_ethtool_ops = {
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh,
- .get_rxfh_context = efx_ethtool_get_rxfh_context,
- .set_rxfh_context = efx_ethtool_set_rxfh_context,
.get_module_info = efx_ethtool_get_module_info,
.get_module_eeprom = efx_ethtool_get_module_eeprom,
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 19f4b4d0b851..e9d9de8e648a 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -495,11 +495,6 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
struct efx_nic *efx = efx_netdev_priv(net_dev);
struct mii_ioctl_data *data = if_mii(ifr);
- if (cmd == SIOCSHWTSTAMP)
- return efx_ptp_set_ts_config(efx, ifr);
- if (cmd == SIOCGHWTSTAMP)
- return efx_ptp_get_ts_config(efx, ifr);
-
/* Convert phy_id from older PRTAD/DEVAD format */
if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
(data->phy_id & 0xfc00) == 0x0400)
@@ -581,6 +576,23 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi
return -EOPNOTSUPP;
}
+static int efx_hwtstamp_set(struct net_device *net_dev,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
+{
+ struct efx_nic *efx = efx_netdev_priv(net_dev);
+
+ return efx_ptp_set_ts_config(efx, config, extack);
+}
+
+static int efx_hwtstamp_get(struct net_device *net_dev,
+ struct kernel_hwtstamp_config *config)
+{
+ struct efx_nic *efx = efx_netdev_priv(net_dev);
+
+ return efx_ptp_get_ts_config(efx, config);
+}
+
static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
@@ -596,6 +608,8 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_features_check = efx_features_check,
.ndo_vlan_rx_add_vid = efx_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = efx_vlan_rx_kill_vid,
+ .ndo_hwtstamp_set = efx_hwtstamp_set,
+ .ndo_hwtstamp_get = efx_hwtstamp_get,
#ifdef CONFIG_SFC_SRIOV
.ndo_set_vf_mac = efx_sriov_set_vf_mac,
.ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c
index 364323599f7b..37c69c8d90b1 100644
--- a/drivers/net/ethernet/sfc/ethtool.c
+++ b/drivers/net/ethernet/sfc/ethtool.c
@@ -240,6 +240,7 @@ static int efx_ethtool_get_ts_info(struct net_device *net_dev,
}
const struct ethtool_ops efx_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USECS_IRQ |
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
@@ -269,8 +270,6 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh,
- .get_rxfh_context = efx_ethtool_get_rxfh_context,
- .set_rxfh_context = efx_ethtool_set_rxfh_context,
.get_ts_info = efx_ethtool_get_ts_info,
.get_module_info = efx_ethtool_get_module_info,
.get_module_eeprom = efx_ethtool_get_module_eeprom,
diff --git a/drivers/net/ethernet/sfc/ethtool_common.c b/drivers/net/ethernet/sfc/ethtool_common.c
index a8cbceeb301b..7d5e5db4eac5 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/ethtool_common.c
@@ -1163,48 +1163,8 @@ u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)
return efx->type->rx_hash_key_size;
}
-int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
- u8 *hfunc)
-{
- struct efx_nic *efx = efx_netdev_priv(net_dev);
- int rc;
-
- rc = efx->type->rx_pull_rss_config(efx);
- if (rc)
- return rc;
-
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (indir)
- memcpy(indir, efx->rss_context.rx_indir_table,
- sizeof(efx->rss_context.rx_indir_table));
- if (key)
- memcpy(key, efx->rss_context.rx_hash_key,
- efx->type->rx_hash_key_size);
- return 0;
-}
-
-int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
-{
- 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)
- return -EOPNOTSUPP;
- if (!indir && !key)
- return 0;
-
- if (!key)
- key = efx->rss_context.rx_hash_key;
- if (!indir)
- indir = efx->rss_context.rx_indir_table;
-
- return efx->type->rx_push_rss_config(efx, true, indir, key);
-}
-
-int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context)
+static int efx_ethtool_get_rxfh_context(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct efx_nic *efx = efx_netdev_priv(net_dev);
struct efx_rss_context *ctx;
@@ -1214,7 +1174,7 @@ int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
return -EOPNOTSUPP;
mutex_lock(&efx->rss_lock);
- ctx = efx_find_rss_context_entry(efx, rss_context);
+ ctx = efx_find_rss_context_entry(efx, rxfh->rss_context);
if (!ctx) {
rc = -ENOENT;
goto out_unlock;
@@ -1223,37 +1183,60 @@ int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
if (rc)
goto out_unlock;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (indir)
- memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table));
- if (key)
- memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size);
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->indir)
+ memcpy(rxfh->indir, ctx->rx_indir_table,
+ sizeof(ctx->rx_indir_table));
+ if (rxfh->key)
+ memcpy(rxfh->key, ctx->rx_hash_key,
+ efx->type->rx_hash_key_size);
out_unlock:
mutex_unlock(&efx->rss_lock);
return rc;
}
-int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
- const u32 *indir, const u8 *key,
- const u8 hfunc, u32 *rss_context,
- bool delete)
+int efx_ethtool_get_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh)
+{
+ struct efx_nic *efx = efx_netdev_priv(net_dev);
+ int rc;
+
+ if (rxfh->rss_context)
+ return efx_ethtool_get_rxfh_context(net_dev, rxfh);
+
+ rc = efx->type->rx_pull_rss_config(efx);
+ if (rc)
+ return rc;
+
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->indir)
+ memcpy(rxfh->indir, efx->rss_context.rx_indir_table,
+ sizeof(efx->rss_context.rx_indir_table));
+ if (rxfh->key)
+ memcpy(rxfh->key, efx->rss_context.rx_hash_key,
+ efx->type->rx_hash_key_size);
+ return 0;
+}
+
+static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct efx_nic *efx = efx_netdev_priv(net_dev);
+ u32 *rss_context = &rxfh->rss_context;
struct efx_rss_context *ctx;
+ u32 *indir = rxfh->indir;
bool allocated = false;
+ u8 *key = rxfh->key;
int rc;
if (!efx->type->rx_push_rss_context_config)
return -EOPNOTSUPP;
- /* Hash function is Toeplitz, cannot be changed */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
- return -EOPNOTSUPP;
mutex_lock(&efx->rss_lock);
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
- if (delete) {
+ if (rxfh->rss_delete) {
/* alloc + delete == Nothing to do */
rc = -EINVAL;
goto out_unlock;
@@ -1276,7 +1259,7 @@ int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
}
}
- if (delete) {
+ if (rxfh->rss_delete) {
/* delete this context */
rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL);
if (!rc)
@@ -1299,6 +1282,33 @@ out_unlock:
return rc;
}
+int efx_ethtool_set_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
+{
+ struct efx_nic *efx = efx_netdev_priv(net_dev);
+ u32 *indir = rxfh->indir;
+ u8 *key = rxfh->key;
+
+ /* Hash function is Toeplitz, cannot be changed */
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
+ if (rxfh->rss_context)
+ return efx_ethtool_set_rxfh_context(net_dev, rxfh, extack);
+
+ if (!indir && !key)
+ return 0;
+
+ if (!key)
+ key = efx->rss_context.rx_hash_key;
+ if (!indir)
+ indir = efx->rss_context.rx_indir_table;
+
+ return efx->type->rx_push_rss_config(efx, true, indir, key);
+}
+
int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
{
struct efx_nic *efx = efx_netdev_priv(net_dev);
diff --git a/drivers/net/ethernet/sfc/ethtool_common.h b/drivers/net/ethernet/sfc/ethtool_common.h
index 659491932101..a680e5980213 100644
--- a/drivers/net/ethernet/sfc/ethtool_common.h
+++ b/drivers/net/ethernet/sfc/ethtool_common.h
@@ -44,16 +44,11 @@ int efx_ethtool_set_rxnfc(struct net_device *net_dev,
struct ethtool_rxnfc *info);
u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev);
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);
+int efx_ethtool_get_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh);
int efx_ethtool_set_rxfh(struct net_device *net_dev,
- const u32 *indir, const u8 *key, const u8 hfunc);
-int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context);
-int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
- const u32 *indir, const u8 *key,
- const u8 hfunc, u32 *rss_context,
- bool delete);
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack);
int efx_ethtool_reset(struct net_device *net_dev, u32 *flags);
int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
struct ethtool_eeprom *ee,
diff --git a/drivers/net/ethernet/sfc/falcon/ethtool.c b/drivers/net/ethernet/sfc/falcon/ethtool.c
index 3976a333f7e3..f4db683b80f7 100644
--- a/drivers/net/ethernet/sfc/falcon/ethtool.c
+++ b/drivers/net/ethernet/sfc/falcon/ethtool.c
@@ -1257,31 +1257,33 @@ static u32 ef4_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
0 : ARRAY_SIZE(efx->rx_indir_table));
}
-static int ef4_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int ef4_ethtool_get_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct ef4_nic *efx = netdev_priv(net_dev);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (indir)
- memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->indir)
+ memcpy(rxfh->indir, efx->rx_indir_table,
+ sizeof(efx->rx_indir_table));
return 0;
}
-static int ef4_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int ef4_ethtool_set_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct ef4_nic *efx = netdev_priv(net_dev);
/* We do not allow change in unsupported parameters */
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!indir)
+ if (!rxfh->indir)
return 0;
- return efx->type->rx_push_rss_config(efx, true, indir);
+ return efx->type->rx_push_rss_config(efx, true, rxfh->indir);
}
static int ef4_ethtool_get_module_eeprom(struct net_device *net_dev,
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 27d86e90a3bb..f2dd7feb0e0c 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -1473,7 +1473,7 @@ struct efx_nic_type {
void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time);
int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp);
int (*ptp_set_ts_config)(struct efx_nic *efx,
- struct hwtstamp_config *init);
+ struct kernel_hwtstamp_config *init);
int (*sriov_configure)(struct efx_nic *efx, int num_vfs);
int (*vlan_rx_add_vid)(struct efx_nic *efx, __be16 proto, u16 vid);
int (*vlan_rx_kill_vid)(struct efx_nic *efx, __be16 proto, u16 vid);
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
index b04fdbb8aece..c3bffbf0ba2b 100644
--- a/drivers/net/ethernet/sfc/ptp.c
+++ b/drivers/net/ethernet/sfc/ptp.c
@@ -301,7 +301,7 @@ struct efx_ptp_data {
bool reset_required;
struct list_head rxfilters_mcast;
struct list_head rxfilters_ucast;
- struct hwtstamp_config config;
+ struct kernel_hwtstamp_config config;
bool enabled;
unsigned int mode;
void (*ns_to_nic_time)(s64 ns, u32 *nic_major, u32 *nic_minor);
@@ -1848,7 +1848,7 @@ int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
return 0;
}
-static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init)
+static int efx_ptp_ts_init(struct efx_nic *efx, struct kernel_hwtstamp_config *init)
{
int rc;
@@ -1895,33 +1895,25 @@ void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info)
ts_info->rx_filters = ptp->efx->type->hwtstamp_filters;
}
-int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr)
+int efx_ptp_set_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack __always_unused *extack)
{
- struct hwtstamp_config config;
- int rc;
-
/* Not a PTP enabled port */
if (!efx->ptp_data)
return -EOPNOTSUPP;
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
- return -EFAULT;
-
- rc = efx_ptp_ts_init(efx, &config);
- if (rc != 0)
- return rc;
-
- return copy_to_user(ifr->ifr_data, &config, sizeof(config))
- ? -EFAULT : 0;
+ return efx_ptp_ts_init(efx, config);
}
-int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr)
+int efx_ptp_get_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config)
{
+ /* Not a PTP enabled port */
if (!efx->ptp_data)
return -EOPNOTSUPP;
-
- return copy_to_user(ifr->ifr_data, &efx->ptp_data->config,
- sizeof(efx->ptp_data->config)) ? -EFAULT : 0;
+ *config = efx->ptp_data->config;
+ return 0;
}
static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len)
diff --git a/drivers/net/ethernet/sfc/ptp.h b/drivers/net/ethernet/sfc/ptp.h
index 7b1ef7002b3f..2f30dbb490d2 100644
--- a/drivers/net/ethernet/sfc/ptp.h
+++ b/drivers/net/ethernet/sfc/ptp.h
@@ -18,8 +18,11 @@ void efx_ptp_defer_probe_with_channel(struct efx_nic *efx);
struct efx_channel *efx_ptp_channel(struct efx_nic *efx);
void efx_ptp_update_channel(struct efx_nic *efx, struct efx_channel *channel);
void efx_ptp_remove(struct efx_nic *efx);
-int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
-int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
+int efx_ptp_set_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack);
+int efx_ptp_get_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config);
void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info);
bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
int efx_ptp_get_mode(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/siena/efx.c b/drivers/net/ethernet/sfc/siena/efx.c
index 8c557f6a183c..59d3a6043379 100644
--- a/drivers/net/ethernet/sfc/siena/efx.c
+++ b/drivers/net/ethernet/sfc/siena/efx.c
@@ -495,11 +495,6 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
struct efx_nic *efx = netdev_priv(net_dev);
struct mii_ioctl_data *data = if_mii(ifr);
- if (cmd == SIOCSHWTSTAMP)
- return efx_siena_ptp_set_ts_config(efx, ifr);
- if (cmd == SIOCGHWTSTAMP)
- return efx_siena_ptp_get_ts_config(efx, ifr);
-
/* Convert phy_id from older PRTAD/DEVAD format */
if ((cmd == SIOCGMIIREG || cmd == SIOCSMIIREG) &&
(data->phy_id & 0xfc00) == 0x0400)
@@ -579,6 +574,23 @@ static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vi
return -EOPNOTSUPP;
}
+static int efx_siena_hwtstamp_set(struct net_device *net_dev,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ return efx_siena_ptp_set_ts_config(efx, config, extack);
+}
+
+static int efx_siena_hwtstamp_get(struct net_device *net_dev,
+ struct kernel_hwtstamp_config *config)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ return efx_siena_ptp_get_ts_config(efx, config);
+}
+
static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
@@ -594,6 +606,8 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_features_check = efx_siena_features_check,
.ndo_vlan_rx_add_vid = efx_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = efx_vlan_rx_kill_vid,
+ .ndo_hwtstamp_set = efx_siena_hwtstamp_set,
+ .ndo_hwtstamp_get = efx_siena_hwtstamp_get,
#ifdef CONFIG_SFC_SIENA_SRIOV
.ndo_set_vf_mac = efx_sriov_set_vf_mac,
.ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
diff --git a/drivers/net/ethernet/sfc/siena/ethtool.c b/drivers/net/ethernet/sfc/siena/ethtool.c
index e4ec589216c1..14dd3893bdef 100644
--- a/drivers/net/ethernet/sfc/siena/ethtool.c
+++ b/drivers/net/ethernet/sfc/siena/ethtool.c
@@ -240,6 +240,7 @@ static int efx_ethtool_get_ts_info(struct net_device *net_dev,
}
const struct ethtool_ops efx_siena_ethtool_ops = {
+ .cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
ETHTOOL_COALESCE_USECS_IRQ |
ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
@@ -269,8 +270,6 @@ const struct ethtool_ops efx_siena_ethtool_ops = {
.get_rxfh_key_size = efx_siena_ethtool_get_rxfh_key_size,
.get_rxfh = efx_siena_ethtool_get_rxfh,
.set_rxfh = efx_siena_ethtool_set_rxfh,
- .get_rxfh_context = efx_siena_ethtool_get_rxfh_context,
- .set_rxfh_context = efx_siena_ethtool_set_rxfh_context,
.get_ts_info = efx_ethtool_get_ts_info,
.get_module_info = efx_siena_ethtool_get_module_info,
.get_module_eeprom = efx_siena_ethtool_get_module_eeprom,
diff --git a/drivers/net/ethernet/sfc/siena/ethtool_common.c b/drivers/net/ethernet/sfc/siena/ethtool_common.c
index f590e87e5a23..5f0a8127e967 100644
--- a/drivers/net/ethernet/sfc/siena/ethtool_common.c
+++ b/drivers/net/ethernet/sfc/siena/ethtool_common.c
@@ -1164,48 +1164,8 @@ u32 efx_siena_ethtool_get_rxfh_key_size(struct net_device *net_dev)
return efx->type->rx_hash_key_size;
}
-int efx_siena_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
- u8 *hfunc)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- int rc;
-
- rc = efx->type->rx_pull_rss_config(efx);
- if (rc)
- return rc;
-
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (indir)
- memcpy(indir, efx->rss_context.rx_indir_table,
- sizeof(efx->rss_context.rx_indir_table));
- if (key)
- memcpy(key, efx->rss_context.rx_hash_key,
- efx->type->rx_hash_key_size);
- return 0;
-}
-
-int efx_siena_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);
-
- /* Hash function is Toeplitz, cannot be changed */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
- return -EOPNOTSUPP;
- if (!indir && !key)
- return 0;
-
- if (!key)
- key = efx->rss_context.rx_hash_key;
- if (!indir)
- indir = efx->rss_context.rx_indir_table;
-
- return efx->type->rx_push_rss_config(efx, true, indir, key);
-}
-
-int efx_siena_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context)
+static int efx_siena_ethtool_get_rxfh_context(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_rss_context *ctx;
@@ -1215,7 +1175,7 @@ int efx_siena_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
return -EOPNOTSUPP;
mutex_lock(&efx->rss_lock);
- ctx = efx_siena_find_rss_context_entry(efx, rss_context);
+ ctx = efx_siena_find_rss_context_entry(efx, rxfh->rss_context);
if (!ctx) {
rc = -ENOENT;
goto out_unlock;
@@ -1224,37 +1184,60 @@ int efx_siena_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
if (rc)
goto out_unlock;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (indir)
- memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table));
- if (key)
- memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size);
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->indir)
+ memcpy(rxfh->indir, ctx->rx_indir_table,
+ sizeof(ctx->rx_indir_table));
+ if (rxfh->key)
+ memcpy(rxfh->key, ctx->rx_hash_key,
+ efx->type->rx_hash_key_size);
out_unlock:
mutex_unlock(&efx->rss_lock);
return rc;
}
-int efx_siena_ethtool_set_rxfh_context(struct net_device *net_dev,
- const u32 *indir, const u8 *key,
- const u8 hfunc, u32 *rss_context,
- bool delete)
+int efx_siena_ethtool_get_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ int rc;
+
+ if (rxfh->rss_context)
+ return efx_siena_ethtool_get_rxfh_context(net_dev, rxfh);
+
+ rc = efx->type->rx_pull_rss_config(efx);
+ if (rc)
+ return rc;
+
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->indir)
+ memcpy(rxfh->indir, efx->rss_context.rx_indir_table,
+ sizeof(efx->rss_context.rx_indir_table));
+ if (rxfh->key)
+ memcpy(rxfh->key, efx->rss_context.rx_hash_key,
+ efx->type->rx_hash_key_size);
+ return 0;
+}
+
+static int efx_siena_ethtool_set_rxfh_context(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ u32 *rss_context = &rxfh->rss_context;
struct efx_rss_context *ctx;
+ u32 *indir = rxfh->indir;
bool allocated = false;
+ u8 *key = rxfh->key;
int rc;
if (!efx->type->rx_push_rss_context_config)
return -EOPNOTSUPP;
- /* Hash function is Toeplitz, cannot be changed */
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
- return -EOPNOTSUPP;
mutex_lock(&efx->rss_lock);
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
- if (delete) {
+ if (rxfh->rss_delete) {
/* alloc + delete == Nothing to do */
rc = -EINVAL;
goto out_unlock;
@@ -1277,7 +1260,7 @@ int efx_siena_ethtool_set_rxfh_context(struct net_device *net_dev,
}
}
- if (delete) {
+ if (rxfh->rss_delete) {
/* delete this context */
rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL);
if (!rc)
@@ -1300,6 +1283,33 @@ out_unlock:
return rc;
}
+int efx_siena_ethtool_set_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+ u32 *indir = rxfh->indir;
+ u8 *key = rxfh->key;
+
+ /* Hash function is Toeplitz, cannot be changed */
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
+ return -EOPNOTSUPP;
+
+ if (rxfh->rss_context)
+ efx_siena_ethtool_set_rxfh_context(net_dev, rxfh, extack);
+
+ if (!indir && !key)
+ return 0;
+
+ if (!key)
+ key = efx->rss_context.rx_hash_key;
+ if (!indir)
+ indir = efx->rss_context.rx_indir_table;
+
+ return efx->type->rx_push_rss_config(efx, true, indir, key);
+}
+
int efx_siena_ethtool_reset(struct net_device *net_dev, u32 *flags)
{
struct efx_nic *efx = netdev_priv(net_dev);
diff --git a/drivers/net/ethernet/sfc/siena/ethtool_common.h b/drivers/net/ethernet/sfc/siena/ethtool_common.h
index 04b375dc6800..d674bab0f65b 100644
--- a/drivers/net/ethernet/sfc/siena/ethtool_common.h
+++ b/drivers/net/ethernet/sfc/siena/ethtool_common.h
@@ -41,16 +41,11 @@ int efx_siena_ethtool_set_rxnfc(struct net_device *net_dev,
struct ethtool_rxnfc *info);
u32 efx_siena_ethtool_get_rxfh_indir_size(struct net_device *net_dev);
u32 efx_siena_ethtool_get_rxfh_key_size(struct net_device *net_dev);
-int efx_siena_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
- u8 *hfunc);
+int efx_siena_ethtool_get_rxfh(struct net_device *net_dev,
+ struct ethtool_rxfh_param *rxfh);
int efx_siena_ethtool_set_rxfh(struct net_device *net_dev,
- const u32 *indir, const u8 *key, const u8 hfunc);
-int efx_siena_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
- u8 *key, u8 *hfunc, u32 rss_context);
-int efx_siena_ethtool_set_rxfh_context(struct net_device *net_dev,
- const u32 *indir, const u8 *key,
- const u8 hfunc, u32 *rss_context,
- bool delete);
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack);
int efx_siena_ethtool_reset(struct net_device *net_dev, u32 *flags);
int efx_siena_ethtool_get_module_eeprom(struct net_device *net_dev,
struct ethtool_eeprom *ee,
diff --git a/drivers/net/ethernet/sfc/siena/net_driver.h b/drivers/net/ethernet/sfc/siena/net_driver.h
index ff7bbc325952..94152f595acd 100644
--- a/drivers/net/ethernet/sfc/siena/net_driver.h
+++ b/drivers/net/ethernet/sfc/siena/net_driver.h
@@ -1424,7 +1424,7 @@ struct efx_nic_type {
void (*ptp_write_host_time)(struct efx_nic *efx, u32 host_time);
int (*ptp_set_ts_sync_events)(struct efx_nic *efx, bool en, bool temp);
int (*ptp_set_ts_config)(struct efx_nic *efx,
- struct hwtstamp_config *init);
+ struct kernel_hwtstamp_config *init);
int (*sriov_configure)(struct efx_nic *efx, int num_vfs);
int (*vlan_rx_add_vid)(struct efx_nic *efx, __be16 proto, u16 vid);
int (*vlan_rx_kill_vid)(struct efx_nic *efx, __be16 proto, u16 vid);
diff --git a/drivers/net/ethernet/sfc/siena/ptp.c b/drivers/net/ethernet/sfc/siena/ptp.c
index 38e666561bcd..4b5e2f0ba350 100644
--- a/drivers/net/ethernet/sfc/siena/ptp.c
+++ b/drivers/net/ethernet/sfc/siena/ptp.c
@@ -297,7 +297,7 @@ struct efx_ptp_data {
u32 rxfilter_event;
u32 rxfilter_general;
bool rxfilter_installed;
- struct hwtstamp_config config;
+ struct kernel_hwtstamp_config config;
bool enabled;
unsigned int mode;
void (*ns_to_nic_time)(s64 ns, u32 *nic_major, u32 *nic_minor);
@@ -1762,7 +1762,8 @@ int efx_siena_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
return 0;
}
-static int efx_ptp_ts_init(struct efx_nic *efx, struct hwtstamp_config *init)
+static int efx_ptp_ts_init(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *init)
{
int rc;
@@ -1799,33 +1800,26 @@ void efx_siena_ptp_get_ts_info(struct efx_nic *efx,
ts_info->rx_filters = ptp->efx->type->hwtstamp_filters;
}
-int efx_siena_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr)
+int efx_siena_ptp_set_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack __always_unused *extack)
{
- struct hwtstamp_config config;
- int rc;
-
/* Not a PTP enabled port */
if (!efx->ptp_data)
return -EOPNOTSUPP;
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
- return -EFAULT;
-
- rc = efx_ptp_ts_init(efx, &config);
- if (rc != 0)
- return rc;
-
- return copy_to_user(ifr->ifr_data, &config, sizeof(config))
- ? -EFAULT : 0;
+ return efx_ptp_ts_init(efx, config);
}
-int efx_siena_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr)
+int efx_siena_ptp_get_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config)
{
+ /* Not a PTP enabled port */
if (!efx->ptp_data)
return -EOPNOTSUPP;
- return copy_to_user(ifr->ifr_data, &efx->ptp_data->config,
- sizeof(efx->ptp_data->config)) ? -EFAULT : 0;
+ *config = efx->ptp_data->config;
+ return 0;
}
static void ptp_event_failure(struct efx_nic *efx, int expected_frag_len)
diff --git a/drivers/net/ethernet/sfc/siena/ptp.h b/drivers/net/ethernet/sfc/siena/ptp.h
index 4172f90e9f6f..6352f84424f6 100644
--- a/drivers/net/ethernet/sfc/siena/ptp.h
+++ b/drivers/net/ethernet/sfc/siena/ptp.h
@@ -15,8 +15,11 @@
struct ethtool_ts_info;
void efx_siena_ptp_defer_probe_with_channel(struct efx_nic *efx);
struct efx_channel *efx_siena_ptp_channel(struct efx_nic *efx);
-int efx_siena_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
-int efx_siena_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
+int efx_siena_ptp_set_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack);
+int efx_siena_ptp_get_ts_config(struct efx_nic *efx,
+ struct kernel_hwtstamp_config *config);
void efx_siena_ptp_get_ts_info(struct efx_nic *efx,
struct ethtool_ts_info *ts_info);
bool efx_siena_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
diff --git a/drivers/net/ethernet/sfc/siena/siena.c b/drivers/net/ethernet/sfc/siena/siena.c
index a44c8fa25748..ca33dc08e555 100644
--- a/drivers/net/ethernet/sfc/siena/siena.c
+++ b/drivers/net/ethernet/sfc/siena/siena.c
@@ -136,7 +136,7 @@ static void siena_ptp_write_host_time(struct efx_nic *efx, u32 host_time)
}
static int siena_ptp_set_ts_config(struct efx_nic *efx,
- struct hwtstamp_config *init)
+ struct kernel_hwtstamp_config *init)
{
int rc;
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index 0891e9e49ecb..5ab8b81b84e6 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -1302,6 +1302,8 @@ static int netsec_setup_rx_dring(struct netsec_priv *priv)
.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE,
.offset = NETSEC_RXBUF_HEADROOM,
.max_len = NETSEC_RX_BUF_SIZE,
+ .napi = &priv->napi,
+ .netdev = priv->ndev,
};
int i, err;
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 80e598bd4255..26cad4344701 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \
dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
- stmmac_xdp.o \
+ stmmac_xdp.o stmmac_est.o \
$(stmmac-y)
stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index e3f650e88f82..5ba606a596e7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -59,28 +59,51 @@
#undef FRAME_FILTER_DEBUG
/* #define FRAME_FILTER_DEBUG */
+struct stmmac_q_tx_stats {
+ u64_stats_t tx_bytes;
+ u64_stats_t tx_set_ic_bit;
+ u64_stats_t tx_tso_frames;
+ u64_stats_t tx_tso_nfrags;
+};
+
+struct stmmac_napi_tx_stats {
+ u64_stats_t tx_packets;
+ u64_stats_t tx_pkt_n;
+ u64_stats_t poll;
+ u64_stats_t tx_clean;
+ u64_stats_t tx_set_ic_bit;
+};
+
struct stmmac_txq_stats {
- u64 tx_bytes;
- u64 tx_packets;
- u64 tx_pkt_n;
- u64 tx_normal_irq_n;
- u64 napi_poll;
- u64 tx_clean;
- u64 tx_set_ic_bit;
- u64 tx_tso_frames;
- u64 tx_tso_nfrags;
- struct u64_stats_sync syncp;
+ /* Updates protected by tx queue lock. */
+ struct u64_stats_sync q_syncp;
+ struct stmmac_q_tx_stats q;
+
+ /* Updates protected by NAPI poll logic. */
+ struct u64_stats_sync napi_syncp;
+ struct stmmac_napi_tx_stats napi;
} ____cacheline_aligned_in_smp;
+struct stmmac_napi_rx_stats {
+ u64_stats_t rx_bytes;
+ u64_stats_t rx_packets;
+ u64_stats_t rx_pkt_n;
+ u64_stats_t poll;
+};
+
struct stmmac_rxq_stats {
- u64 rx_bytes;
- u64 rx_packets;
- u64 rx_pkt_n;
- u64 rx_normal_irq_n;
- u64 napi_poll;
- struct u64_stats_sync syncp;
+ /* Updates protected by NAPI poll logic. */
+ struct u64_stats_sync napi_syncp;
+ struct stmmac_napi_rx_stats napi;
} ____cacheline_aligned_in_smp;
+/* Updates on each CPU protected by not allowing nested irqs. */
+struct stmmac_pcpu_stats {
+ struct u64_stats_sync syncp;
+ u64_stats_t rx_normal_irq_n[MTL_MAX_TX_QUEUES];
+ u64_stats_t tx_normal_irq_n[MTL_MAX_RX_QUEUES];
+};
+
/* Extra statistic and debug information exposed by ethtool */
struct stmmac_extra_stats {
/* Transmit errors */
@@ -205,6 +228,7 @@ struct stmmac_extra_stats {
/* per queue statistics */
struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES];
struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES];
+ struct stmmac_pcpu_stats __percpu *pcpu_stats;
unsigned long rx_dropped;
unsigned long rx_errors;
unsigned long tx_dropped;
@@ -216,6 +240,7 @@ struct stmmac_safety_stats {
unsigned long mac_errors[32];
unsigned long mtl_errors[32];
unsigned long dma_errors[32];
+ unsigned long dma_dpp_errors[32];
};
/* Number of fields in Safety Stats */
@@ -563,6 +588,7 @@ struct mac_device_info {
const struct stmmac_hwtimestamp *ptp;
const struct stmmac_tc_ops *tc;
const struct stmmac_mmc_ops *mmc;
+ const struct stmmac_est_ops *est;
struct dw_xpcs *xpcs;
struct phylink_pcs *lynx_pcs; /* Lynx external PCS */
struct mii_regs mii; /* MII register Addresses */
@@ -580,6 +606,7 @@ struct mac_device_info {
u32 vlan_filter[32];
bool vlan_fail_q_en;
u8 vlan_fail_q;
+ bool hw_vlan_en;
};
struct stmmac_rx_routing {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
index 8f730ada71f9..6b65420e11b5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c
@@ -353,6 +353,10 @@ static int imx_dwmac_probe(struct platform_device *pdev)
if (data->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY)
plat_dat->flags |= STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY;
+ /* Default TX Q0 to use TSO and rest TXQ for TBS */
+ for (int i = 1; i < plat_dat->tx_queues_to_use; i++)
+ plat_dat->tx_queues_cfg[i].tbs_en = 1;
+
plat_dat->host_dma_width = dwmac->ops->addr_width;
plat_dat->init = imx_dwmac_init;
plat_dat->exit = imx_dwmac_exit;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
index 137741b94122..b21d99faa2d0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
@@ -441,8 +441,7 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
struct stmmac_extra_stats *x, u32 chan,
u32 dir)
{
- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
+ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
int ret = 0;
u32 v;
@@ -455,9 +454,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
if (v & EMAC_TX_INT) {
ret |= handle_tx;
- u64_stats_update_begin(&txq_stats->syncp);
- txq_stats->tx_normal_irq_n++;
- u64_stats_update_end(&txq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->tx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
}
if (v & EMAC_TX_DMA_STOP_INT)
@@ -479,9 +478,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv,
if (v & EMAC_RX_INT) {
ret |= handle_rx;
- u64_stats_update_begin(&rxq_stats->syncp);
- rxq_stats->rx_normal_irq_n++;
- u64_stats_update_end(&rxq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->rx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
}
if (v & EMAC_RX_BUF_UA_INT)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index c6ff1fa0e04d..6b6d0de09619 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -1134,6 +1134,35 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
return 0;
}
+static void dwmac4_rx_hw_vlan(struct mac_device_info *hw,
+ struct dma_desc *rx_desc, struct sk_buff *skb)
+{
+ if (hw->desc->get_rx_vlan_valid(rx_desc)) {
+ u16 vid = hw->desc->get_rx_vlan_tci(rx_desc);
+
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
+ }
+}
+
+static void dwmac4_set_hw_vlan_mode(struct mac_device_info *hw)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value = readl(ioaddr + GMAC_VLAN_TAG);
+
+ value &= ~GMAC_VLAN_TAG_CTRL_EVLS_MASK;
+
+ if (hw->hw_vlan_en)
+ /* Always strip VLAN on Receive */
+ value |= GMAC_VLAN_TAG_STRIP_ALL;
+ else
+ /* Do not strip VLAN on Receive */
+ value |= GMAC_VLAN_TAG_STRIP_NONE;
+
+ /* Enable outer VLAN Tag in Rx DMA descriptor */
+ value |= GMAC_VLAN_TAG_CTRL_EVLRXS;
+ writel(value, ioaddr + GMAC_VLAN_TAG);
+}
+
const struct stmmac_ops dwmac4_ops = {
.core_init = dwmac4_core_init,
.phylink_get_caps = dwmac4_phylink_get_caps,
@@ -1175,6 +1204,8 @@ const struct stmmac_ops dwmac4_ops = {
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
+ .rx_hw_vlan = dwmac4_rx_hw_vlan,
+ .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
};
const struct stmmac_ops dwmac410_ops = {
@@ -1216,14 +1247,14 @@ const struct stmmac_ops dwmac410_ops = {
.set_arp_offload = dwmac4_set_arp_offload,
.config_l3_filter = dwmac4_config_l3_filter,
.config_l4_filter = dwmac4_config_l4_filter,
- .est_configure = dwmac5_est_configure,
- .est_irq_status = dwmac5_est_irq_status,
.fpe_configure = dwmac5_fpe_configure,
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
.fpe_irq_status = dwmac5_fpe_irq_status,
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
+ .rx_hw_vlan = dwmac4_rx_hw_vlan,
+ .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
};
const struct stmmac_ops dwmac510_ops = {
@@ -1269,14 +1300,14 @@ const struct stmmac_ops dwmac510_ops = {
.set_arp_offload = dwmac4_set_arp_offload,
.config_l3_filter = dwmac4_config_l3_filter,
.config_l4_filter = dwmac4_config_l4_filter,
- .est_configure = dwmac5_est_configure,
- .est_irq_status = dwmac5_est_irq_status,
.fpe_configure = dwmac5_fpe_configure,
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
.fpe_irq_status = dwmac5_fpe_irq_status,
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
+ .rx_hw_vlan = dwmac4_rx_hw_vlan,
+ .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
};
static u32 dwmac4_get_num_vlan(void __iomem *ioaddr)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
index 89a14084c611..1c5802e0d7f4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c
@@ -198,6 +198,17 @@ static int dwmac4_get_tx_ls(struct dma_desc *p)
>> TDES3_LAST_DESCRIPTOR_SHIFT;
}
+static u16 dwmac4_wrback_get_rx_vlan_tci(struct dma_desc *p)
+{
+ return (le32_to_cpu(p->des0) & RDES0_VLAN_TAG_MASK);
+}
+
+static bool dwmac4_wrback_get_rx_vlan_valid(struct dma_desc *p)
+{
+ return ((le32_to_cpu(p->des3) & RDES3_LAST_DESCRIPTOR) &&
+ (le32_to_cpu(p->des3) & RDES3_RDES0_VALID));
+}
+
static int dwmac4_wrback_get_rx_frame_len(struct dma_desc *p, int rx_coe)
{
return (le32_to_cpu(p->des3) & RDES3_PACKET_SIZE_MASK);
@@ -551,6 +562,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
.set_tx_owner = dwmac4_set_tx_owner,
.set_rx_owner = dwmac4_set_rx_owner,
.get_tx_ls = dwmac4_get_tx_ls,
+ .get_rx_vlan_tci = dwmac4_wrback_get_rx_vlan_tci,
+ .get_rx_vlan_valid = dwmac4_wrback_get_rx_vlan_valid,
.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
index 9470d3fd2ded..0d185e54eb7e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c
@@ -171,8 +171,7 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs;
u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan));
u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan));
- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
+ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
int ret = 0;
if (dir == DMA_DIR_RX)
@@ -201,15 +200,15 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
}
/* TX/RX NORMAL interrupts */
if (likely(intr_status & DMA_CHAN_STATUS_RI)) {
- u64_stats_update_begin(&rxq_stats->syncp);
- rxq_stats->rx_normal_irq_n++;
- u64_stats_update_end(&rxq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->rx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
- u64_stats_update_begin(&txq_stats->syncp);
- txq_stats->tx_normal_irq_n++;
- u64_stats_update_end(&txq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->tx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
ret |= handle_tx;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
index 8fd167501fa0..e02cebc3f1b7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -573,143 +573,6 @@ int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
return 0;
}
-static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
-{
- u32 ctrl;
-
- writel(val, ioaddr + MTL_EST_GCL_DATA);
-
- ctrl = (reg << ADDR_SHIFT);
- ctrl |= gcl ? 0 : GCRR;
-
- writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
-
- ctrl |= SRWO;
- writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
-
- return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
- ctrl, !(ctrl & SRWO), 100, 5000);
-}
-
-int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
- unsigned int ptp_rate)
-{
- int i, ret = 0x0;
- u32 ctrl;
-
- ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
- ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
- ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
- ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
- ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
- ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
- if (ret)
- return ret;
-
- for (i = 0; i < cfg->gcl_size; i++) {
- ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
- if (ret)
- return ret;
- }
-
- ctrl = readl(ioaddr + MTL_EST_CONTROL);
- ctrl &= ~PTOV;
- ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
- if (cfg->enable)
- ctrl |= EEST | SSWL;
- else
- ctrl &= ~EEST;
-
- writel(ctrl, ioaddr + MTL_EST_CONTROL);
-
- /* Configure EST interrupt */
- if (cfg->enable)
- ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
- else
- ctrl = 0;
-
- writel(ctrl, ioaddr + MTL_EST_INT_EN);
-
- return 0;
-}
-
-void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
- struct stmmac_extra_stats *x, u32 txqcnt)
-{
- u32 status, value, feqn, hbfq, hbfs, btrl;
- u32 txqcnt_mask = (1 << txqcnt) - 1;
-
- status = readl(ioaddr + MTL_EST_STATUS);
-
- value = (CGCE | HLBS | HLBF | BTRE | SWLC);
-
- /* Return if there is no error */
- if (!(status & value))
- return;
-
- if (status & CGCE) {
- /* Clear Interrupt */
- writel(CGCE, ioaddr + MTL_EST_STATUS);
-
- x->mtl_est_cgce++;
- }
-
- if (status & HLBS) {
- value = readl(ioaddr + MTL_EST_SCH_ERR);
- value &= txqcnt_mask;
-
- x->mtl_est_hlbs++;
-
- /* Clear Interrupt */
- writel(value, ioaddr + MTL_EST_SCH_ERR);
-
- /* Collecting info to shows all the queues that has HLBS
- * issue. The only way to clear this is to clear the
- * statistic
- */
- if (net_ratelimit())
- netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
- }
-
- if (status & HLBF) {
- value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
- feqn = value & txqcnt_mask;
-
- value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
- hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
- hbfs = value & SZ_CAP_HBFS_MASK;
-
- x->mtl_est_hlbf++;
-
- /* Clear Interrupt */
- writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
-
- if (net_ratelimit())
- netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
- hbfq, hbfs);
- }
-
- if (status & BTRE) {
- if ((status & BTRL) == BTRL_MAX)
- x->mtl_est_btrlm++;
- else
- x->mtl_est_btre++;
-
- btrl = (status & BTRL) >> BTRL_SHIFT;
-
- if (net_ratelimit())
- netdev_info(dev, "EST: BTR Error Loop Count %u\n",
- btrl);
-
- writel(BTRE, ioaddr + MTL_EST_STATUS);
- }
-
- if (status & SWLC) {
- writel(SWLC, ioaddr + MTL_EST_STATUS);
- netdev_info(dev, "EST: SWOL has been switched\n");
- }
-}
-
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool enable)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
index 34e620790eb3..bf33a51d229e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -39,53 +39,6 @@
#define MAC_PPSx_INTERVAL(x) (0x00000b88 + ((x) * 0x10))
#define MAC_PPSx_WIDTH(x) (0x00000b8c + ((x) * 0x10))
-#define MTL_EST_CONTROL 0x00000c50
-#define PTOV GENMASK(31, 24)
-#define PTOV_SHIFT 24
-#define SSWL BIT(1)
-#define EEST BIT(0)
-
-#define MTL_EST_STATUS 0x00000c58
-#define BTRL GENMASK(11, 8)
-#define BTRL_SHIFT 8
-#define BTRL_MAX (0xF << BTRL_SHIFT)
-#define SWOL BIT(7)
-#define SWOL_SHIFT 7
-#define CGCE BIT(4)
-#define HLBS BIT(3)
-#define HLBF BIT(2)
-#define BTRE BIT(1)
-#define SWLC BIT(0)
-
-#define MTL_EST_SCH_ERR 0x00000c60
-#define MTL_EST_FRM_SZ_ERR 0x00000c64
-#define MTL_EST_FRM_SZ_CAP 0x00000c68
-#define SZ_CAP_HBFS_MASK GENMASK(14, 0)
-#define SZ_CAP_HBFQ_SHIFT 16
-#define SZ_CAP_HBFQ_MASK(_val) ({ typeof(_val) (val) = (_val); \
- ((val) > 4 ? GENMASK(18, 16) : \
- (val) > 2 ? GENMASK(17, 16) : \
- BIT(16)); })
-
-#define MTL_EST_INT_EN 0x00000c70
-#define IECGCE CGCE
-#define IEHS HLBS
-#define IEHF HLBF
-#define IEBE BTRE
-#define IECC SWLC
-
-#define MTL_EST_GCL_CONTROL 0x00000c80
-#define BTR_LOW 0x0
-#define BTR_HIGH 0x1
-#define CTR_LOW 0x2
-#define CTR_HIGH 0x3
-#define TER 0x4
-#define LLR 0x5
-#define ADDR_SHIFT 8
-#define GCRR BIT(2)
-#define SRWO BIT(0)
-#define MTL_EST_GCL_DATA 0x00000c84
-
#define MTL_RXP_CONTROL_STATUS 0x00000ca0
#define RXPI BIT(31)
#define NPE GENMASK(23, 16)
@@ -149,10 +102,6 @@ int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
struct stmmac_pps_cfg *cfg, bool enable,
u32 sub_second_inc, u32 systime_flags);
-int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
- unsigned int ptp_rate);
-void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
- struct stmmac_extra_stats *x, u32 txqcnt);
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool enable);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 7907d62d3437..85e18f9a22f9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -162,8 +162,7 @@ static void show_rx_process_state(unsigned int status)
int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
struct stmmac_extra_stats *x, u32 chan, u32 dir)
{
- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
+ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
int ret = 0;
/* read the status register (CSR5) */
u32 intr_status = readl(ioaddr + DMA_STATUS);
@@ -215,16 +214,16 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,
u32 value = readl(ioaddr + DMA_INTR_ENA);
/* to schedule NAPI on real RIE event. */
if (likely(value & DMA_INTR_ENA_RIE)) {
- u64_stats_update_begin(&rxq_stats->syncp);
- rxq_stats->rx_normal_irq_n++;
- u64_stats_update_end(&rxq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->rx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
}
if (likely(intr_status & DMA_STATUS_TI)) {
- u64_stats_update_begin(&txq_stats->syncp);
- txq_stats->tx_normal_irq_n++;
- u64_stats_update_end(&txq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->tx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
ret |= handle_tx;
}
if (unlikely(intr_status & DMA_STATUS_ERI))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index a4e8b498dea9..6a2c7d22df1e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -284,22 +284,6 @@
#define XGMAC_TC_PRTY_MAP1 0x00001044
#define XGMAC_PSTC(x) GENMASK((x) * 8 + 7, (x) * 8)
#define XGMAC_PSTC_SHIFT(x) ((x) * 8)
-#define XGMAC_MTL_EST_CONTROL 0x00001050
-#define XGMAC_PTOV GENMASK(31, 23)
-#define XGMAC_PTOV_SHIFT 23
-#define XGMAC_SSWL BIT(1)
-#define XGMAC_EEST BIT(0)
-#define XGMAC_MTL_EST_GCL_CONTROL 0x00001080
-#define XGMAC_BTR_LOW 0x0
-#define XGMAC_BTR_HIGH 0x1
-#define XGMAC_CTR_LOW 0x2
-#define XGMAC_CTR_HIGH 0x3
-#define XGMAC_TER 0x4
-#define XGMAC_LLR 0x5
-#define XGMAC_ADDR_SHIFT 8
-#define XGMAC_GCRR BIT(2)
-#define XGMAC_SRWO BIT(0)
-#define XGMAC_MTL_EST_GCL_DATA 0x00001084
#define XGMAC_MTL_RXP_CONTROL_STATUS 0x000010a0
#define XGMAC_RXPI BIT(31)
#define XGMAC_NPE GENMASK(23, 16)
@@ -319,6 +303,8 @@
#define XGMAC_RXCEIE BIT(4)
#define XGMAC_TXCEIE BIT(0)
#define XGMAC_MTL_ECC_INT_STATUS 0x000010cc
+#define XGMAC_MTL_DPP_CONTROL 0x000010e0
+#define XGMAC_DPP_DISABLE BIT(0)
#define XGMAC_MTL_TXQ_OPMODE(x) (0x00001100 + (0x80 * (x)))
#define XGMAC_TQS GENMASK(25, 16)
#define XGMAC_TQS_SHIFT 16
@@ -401,6 +387,7 @@
#define XGMAC_DCEIE BIT(1)
#define XGMAC_TCEIE BIT(0)
#define XGMAC_DMA_ECC_INT_STATUS 0x0000306c
+#define XGMAC_DMA_DPP_INT_STATUS 0x00003074
#define XGMAC_DMA_CH_CONTROL(x) (0x00003100 + (0x80 * (x)))
#define XGMAC_SPH BIT(24)
#define XGMAC_PBLx8 BIT(16)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index a74e71db79f9..1af2f89a0504 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -830,6 +830,44 @@ static const struct dwxgmac3_error_desc dwxgmac3_dma_errors[32]= {
{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
};
+#define DPP_RX_ERR "Read Rx Descriptor Parity checker Error"
+#define DPP_TX_ERR "Read Tx Descriptor Parity checker Error"
+
+static const struct dwxgmac3_error_desc dwxgmac3_dma_dpp_errors[32] = {
+ { true, "TDPES0", DPP_TX_ERR },
+ { true, "TDPES1", DPP_TX_ERR },
+ { true, "TDPES2", DPP_TX_ERR },
+ { true, "TDPES3", DPP_TX_ERR },
+ { true, "TDPES4", DPP_TX_ERR },
+ { true, "TDPES5", DPP_TX_ERR },
+ { true, "TDPES6", DPP_TX_ERR },
+ { true, "TDPES7", DPP_TX_ERR },
+ { true, "TDPES8", DPP_TX_ERR },
+ { true, "TDPES9", DPP_TX_ERR },
+ { true, "TDPES10", DPP_TX_ERR },
+ { true, "TDPES11", DPP_TX_ERR },
+ { true, "TDPES12", DPP_TX_ERR },
+ { true, "TDPES13", DPP_TX_ERR },
+ { true, "TDPES14", DPP_TX_ERR },
+ { true, "TDPES15", DPP_TX_ERR },
+ { true, "RDPES0", DPP_RX_ERR },
+ { true, "RDPES1", DPP_RX_ERR },
+ { true, "RDPES2", DPP_RX_ERR },
+ { true, "RDPES3", DPP_RX_ERR },
+ { true, "RDPES4", DPP_RX_ERR },
+ { true, "RDPES5", DPP_RX_ERR },
+ { true, "RDPES6", DPP_RX_ERR },
+ { true, "RDPES7", DPP_RX_ERR },
+ { true, "RDPES8", DPP_RX_ERR },
+ { true, "RDPES9", DPP_RX_ERR },
+ { true, "RDPES10", DPP_RX_ERR },
+ { true, "RDPES11", DPP_RX_ERR },
+ { true, "RDPES12", DPP_RX_ERR },
+ { true, "RDPES13", DPP_RX_ERR },
+ { true, "RDPES14", DPP_RX_ERR },
+ { true, "RDPES15", DPP_RX_ERR },
+};
+
static void dwxgmac3_handle_dma_err(struct net_device *ndev,
void __iomem *ioaddr, bool correctable,
struct stmmac_safety_stats *stats)
@@ -841,6 +879,13 @@ static void dwxgmac3_handle_dma_err(struct net_device *ndev,
dwxgmac3_log_error(ndev, value, correctable, "DMA",
dwxgmac3_dma_errors, STAT_OFF(dma_errors), stats);
+
+ value = readl(ioaddr + XGMAC_DMA_DPP_INT_STATUS);
+ writel(value, ioaddr + XGMAC_DMA_DPP_INT_STATUS);
+
+ dwxgmac3_log_error(ndev, value, false, "DMA_DPP",
+ dwxgmac3_dma_dpp_errors,
+ STAT_OFF(dma_dpp_errors), stats);
}
static int
@@ -881,6 +926,12 @@ dwxgmac3_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
value |= XGMAC_TMOUTEN; /* FSM Timeout Feature */
writel(value, ioaddr + XGMAC_MAC_FSM_CONTROL);
+ /* 5. Enable Data Path Parity Protection */
+ value = readl(ioaddr + XGMAC_MTL_DPP_CONTROL);
+ /* already enabled by default, explicit enable it again */
+ value &= ~XGMAC_DPP_DISABLE;
+ writel(value, ioaddr + XGMAC_MTL_DPP_CONTROL);
+
return 0;
}
@@ -914,7 +965,11 @@ static int dwxgmac3_safety_feat_irq_status(struct net_device *ndev,
ret |= !corr;
}
- err = dma & (XGMAC_DEUIS | XGMAC_DECIS);
+ /* DMA_DPP_Interrupt_Status is indicated by MCSIS bit in
+ * DMA_Safety_Interrupt_Status, so we handle DMA Data Path
+ * Parity Errors here
+ */
+ err = dma & (XGMAC_DEUIS | XGMAC_DECIS | XGMAC_MCSIS);
corr = dma & XGMAC_DECIS;
if (err) {
dwxgmac3_handle_dma_err(ndev, ioaddr, corr, stats);
@@ -930,6 +985,7 @@ static const struct dwxgmac3_error {
{ dwxgmac3_mac_errors },
{ dwxgmac3_mtl_errors },
{ dwxgmac3_dma_errors },
+ { dwxgmac3_dma_dpp_errors },
};
static int dwxgmac3_safety_feat_dump(struct stmmac_safety_stats *stats,
@@ -1433,57 +1489,6 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en,
writel(value, ioaddr + XGMAC_RX_CONFIG);
}
-static int dwxgmac3_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
-{
- u32 ctrl;
-
- writel(val, ioaddr + XGMAC_MTL_EST_GCL_DATA);
-
- ctrl = (reg << XGMAC_ADDR_SHIFT);
- ctrl |= gcl ? 0 : XGMAC_GCRR;
-
- writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
-
- ctrl |= XGMAC_SRWO;
- writel(ctrl, ioaddr + XGMAC_MTL_EST_GCL_CONTROL);
-
- return readl_poll_timeout_atomic(ioaddr + XGMAC_MTL_EST_GCL_CONTROL,
- ctrl, !(ctrl & XGMAC_SRWO), 100, 5000);
-}
-
-static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
- unsigned int ptp_rate)
-{
- int i, ret = 0x0;
- u32 ctrl;
-
- ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_LOW, cfg->btr[0], false);
- ret |= dwxgmac3_est_write(ioaddr, XGMAC_BTR_HIGH, cfg->btr[1], false);
- ret |= dwxgmac3_est_write(ioaddr, XGMAC_TER, cfg->ter, false);
- ret |= dwxgmac3_est_write(ioaddr, XGMAC_LLR, cfg->gcl_size, false);
- ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_LOW, cfg->ctr[0], false);
- ret |= dwxgmac3_est_write(ioaddr, XGMAC_CTR_HIGH, cfg->ctr[1], false);
- if (ret)
- return ret;
-
- for (i = 0; i < cfg->gcl_size; i++) {
- ret = dwxgmac3_est_write(ioaddr, i, cfg->gcl[i], true);
- if (ret)
- return ret;
- }
-
- ctrl = readl(ioaddr + XGMAC_MTL_EST_CONTROL);
- ctrl &= ~XGMAC_PTOV;
- ctrl |= ((1000000000 / ptp_rate) * 9) << XGMAC_PTOV_SHIFT;
- if (cfg->enable)
- ctrl |= XGMAC_EEST | XGMAC_SSWL;
- else
- ctrl &= ~XGMAC_EEST;
-
- writel(ctrl, ioaddr + XGMAC_MTL_EST_CONTROL);
- return 0;
-}
-
static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq,
u32 num_rxq, bool enable)
@@ -1553,7 +1558,6 @@ const struct stmmac_ops dwxgmac210_ops = {
.config_l3_filter = dwxgmac2_config_l3_filter,
.config_l4_filter = dwxgmac2_config_l4_filter,
.set_arp_offload = dwxgmac2_set_arp_offload,
- .est_configure = dwxgmac3_est_configure,
.fpe_configure = dwxgmac3_fpe_configure,
};
@@ -1615,7 +1619,6 @@ const struct stmmac_ops dwxlgmac2_ops = {
.config_l3_filter = dwxgmac2_config_l3_filter,
.config_l4_filter = dwxgmac2_config_l4_filter,
.set_arp_offload = dwxgmac2_set_arp_offload,
- .est_configure = dwxgmac3_est_configure,
.fpe_configure = dwxgmac3_fpe_configure,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index 3cde695fec91..dd2ab6185c40 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -337,8 +337,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
struct stmmac_extra_stats *x, u32 chan,
u32 dir)
{
- struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan];
- struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan];
+ struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
int ret = 0;
@@ -367,15 +366,15 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
/* TX/RX NORMAL interrupts */
if (likely(intr_status & XGMAC_NIS)) {
if (likely(intr_status & XGMAC_RI)) {
- u64_stats_update_begin(&rxq_stats->syncp);
- rxq_stats->rx_normal_irq_n++;
- u64_stats_update_end(&rxq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->rx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
ret |= handle_rx;
}
if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) {
- u64_stats_update_begin(&txq_stats->syncp);
- txq_stats->tx_normal_irq_n++;
- u64_stats_update_end(&txq_stats->syncp);
+ u64_stats_update_begin(&stats->syncp);
+ u64_stats_inc(&stats->tx_normal_irq_n[chan]);
+ u64_stats_update_end(&stats->syncp);
ret |= handle_tx;
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index b8ba8f2d8041..29367105df54 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -7,6 +7,7 @@
#include "common.h"
#include "stmmac.h"
#include "stmmac_ptp.h"
+#include "stmmac_est.h"
static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg)
{
@@ -114,6 +115,7 @@ static const struct stmmac_hwif_entry {
const void *mode;
const void *tc;
const void *mmc;
+ const void *est;
int (*setup)(struct stmmac_priv *priv);
int (*quirks)(struct stmmac_priv *priv);
} stmmac_hw[] = {
@@ -162,6 +164,7 @@ static const struct stmmac_hwif_entry {
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
+ .est_off = EST_GMAC4_OFFSET,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac4_dma_ops,
@@ -170,6 +173,7 @@ static const struct stmmac_hwif_entry {
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
+ .est = &dwmac510_est_ops,
.setup = dwmac4_setup,
.quirks = stmmac_dwmac4_quirks,
}, {
@@ -180,6 +184,7 @@ static const struct stmmac_hwif_entry {
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
+ .est_off = EST_GMAC4_OFFSET,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac4_dma_ops,
@@ -188,6 +193,7 @@ static const struct stmmac_hwif_entry {
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
+ .est = &dwmac510_est_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -198,6 +204,7 @@ static const struct stmmac_hwif_entry {
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
+ .est_off = EST_GMAC4_OFFSET,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac410_dma_ops,
@@ -206,6 +213,7 @@ static const struct stmmac_hwif_entry {
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
+ .est = &dwmac510_est_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -216,6 +224,7 @@ static const struct stmmac_hwif_entry {
.regs = {
.ptp_off = PTP_GMAC4_OFFSET,
.mmc_off = MMC_GMAC4_OFFSET,
+ .est_off = EST_GMAC4_OFFSET,
},
.desc = &dwmac4_desc_ops,
.dma = &dwmac410_dma_ops,
@@ -224,6 +233,7 @@ static const struct stmmac_hwif_entry {
.mode = &dwmac4_ring_mode_ops,
.tc = &dwmac510_tc_ops,
.mmc = &dwmac_mmc_ops,
+ .est = &dwmac510_est_ops,
.setup = dwmac4_setup,
.quirks = NULL,
}, {
@@ -235,6 +245,7 @@ static const struct stmmac_hwif_entry {
.regs = {
.ptp_off = PTP_XGMAC_OFFSET,
.mmc_off = MMC_XGMAC_OFFSET,
+ .est_off = EST_XGMAC_OFFSET,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
@@ -243,6 +254,7 @@ static const struct stmmac_hwif_entry {
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwxgmac_mmc_ops,
+ .est = &dwmac510_est_ops,
.setup = dwxgmac2_setup,
.quirks = NULL,
}, {
@@ -254,6 +266,7 @@ static const struct stmmac_hwif_entry {
.regs = {
.ptp_off = PTP_XGMAC_OFFSET,
.mmc_off = MMC_XGMAC_OFFSET,
+ .est_off = EST_XGMAC_OFFSET,
},
.desc = &dwxgmac210_desc_ops,
.dma = &dwxgmac210_dma_ops,
@@ -262,6 +275,7 @@ static const struct stmmac_hwif_entry {
.mode = NULL,
.tc = &dwmac510_tc_ops,
.mmc = &dwxgmac_mmc_ops,
+ .est = &dwmac510_est_ops,
.setup = dwxlgmac2_setup,
.quirks = stmmac_dwxlgmac_quirks,
},
@@ -296,6 +310,10 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
(needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET);
priv->mmcaddr = priv->ioaddr +
(needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET);
+ if (needs_gmac4)
+ priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET;
+ else if (needs_xgmac)
+ priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET;
/* Check for HW specific setup first */
if (priv->plat->setup) {
@@ -332,10 +350,13 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
mac->mode = mac->mode ? : entry->mode;
mac->tc = mac->tc ? : entry->tc;
mac->mmc = mac->mmc ? : entry->mmc;
+ mac->est = mac->est ? : entry->est;
priv->hw = mac;
priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
+ if (entry->est)
+ priv->estaddr = priv->ioaddr + entry->regs.est_off;
/* Entry found */
if (needs_setup) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 68aa2d5ca6e5..7be04b54738b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -56,6 +56,10 @@ struct stmmac_desc_ops {
void (*set_tx_ic)(struct dma_desc *p);
/* Last tx segment reports the transmit status */
int (*get_tx_ls)(struct dma_desc *p);
+ /* Get the tag of the descriptor */
+ u16 (*get_rx_vlan_tci)(struct dma_desc *p);
+ /* Get the valid status of descriptor */
+ bool (*get_rx_vlan_valid)(struct dma_desc *p);
/* Return the transmit status looking at the TDES1 */
int (*tx_status)(struct stmmac_extra_stats *x,
struct dma_desc *p, void __iomem *ioaddr);
@@ -117,6 +121,10 @@ struct stmmac_desc_ops {
stmmac_do_void_callback(__priv, desc, set_tx_ic, __args)
#define stmmac_get_tx_ls(__priv, __args...) \
stmmac_do_callback(__priv, desc, get_tx_ls, __args)
+#define stmmac_get_rx_vlan_tci(__priv, __args...) \
+ stmmac_do_callback(__priv, desc, get_rx_vlan_tci, __args)
+#define stmmac_get_rx_vlan_valid(__priv, __args...) \
+ stmmac_do_callback(__priv, desc, get_rx_vlan_valid, __args)
#define stmmac_tx_status(__priv, __args...) \
stmmac_do_callback(__priv, desc, tx_status, __args)
#define stmmac_get_tx_len(__priv, __args...) \
@@ -388,6 +396,9 @@ struct stmmac_ops {
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
__le16 perfect_match, bool is_double);
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
+ void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
+ struct sk_buff *skb);
+ void (*set_hw_vlan_mode)(struct mac_device_info *hw);
int (*add_hw_vlan_rx_fltr)(struct net_device *dev,
struct mac_device_info *hw,
__be16 proto, u16 vid);
@@ -408,10 +419,6 @@ struct stmmac_ops {
bool en, bool udp, bool sa, bool inv,
u32 match);
void (*set_arp_offload)(struct mac_device_info *hw, bool en, u32 addr);
- int (*est_configure)(void __iomem *ioaddr, struct stmmac_est *cfg,
- unsigned int ptp_rate);
- void (*est_irq_status)(void __iomem *ioaddr, struct net_device *dev,
- struct stmmac_extra_stats *x, u32 txqcnt);
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
u32 num_txq, u32 num_rxq,
bool enable);
@@ -499,6 +506,10 @@ struct stmmac_ops {
stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args)
#define stmmac_enable_vlan(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, enable_vlan, __args)
+#define stmmac_rx_hw_vlan(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mac, rx_hw_vlan, __args)
+#define stmmac_set_hw_vlan_mode(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mac, set_hw_vlan_mode, __args)
#define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \
stmmac_do_callback(__priv, mac, add_hw_vlan_rx_fltr, __args)
#define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \
@@ -515,10 +526,6 @@ struct stmmac_ops {
stmmac_do_callback(__priv, mac, config_l4_filter, __args)
#define stmmac_set_arp_offload(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, set_arp_offload, __args)
-#define stmmac_est_configure(__priv, __args...) \
- stmmac_do_callback(__priv, mac, est_configure, __args)
-#define stmmac_est_irq_status(__priv, __args...) \
- stmmac_do_void_callback(__priv, mac, est_irq_status, __args)
#define stmmac_fpe_configure(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
#define stmmac_fpe_send_mpacket(__priv, __args...) \
@@ -644,9 +651,22 @@ struct stmmac_mmc_ops {
#define stmmac_mmc_read(__priv, __args...) \
stmmac_do_void_callback(__priv, mmc, read, __args)
+struct stmmac_est_ops {
+ int (*configure)(struct stmmac_priv *priv, struct stmmac_est *cfg,
+ unsigned int ptp_rate);
+ void (*irq_status)(struct stmmac_priv *priv, struct net_device *dev,
+ struct stmmac_extra_stats *x, u32 txqcnt);
+};
+
+#define stmmac_est_configure(__priv, __args...) \
+ stmmac_do_callback(__priv, est, configure, __args)
+#define stmmac_est_irq_status(__priv, __args...) \
+ stmmac_do_void_callback(__priv, est, irq_status, __args)
+
struct stmmac_regs_off {
u32 ptp_off;
u32 mmc_off;
+ u32 est_off;
};
extern const struct stmmac_ops dwmac100_ops;
@@ -665,6 +685,7 @@ extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
extern const struct stmmac_mmc_ops dwmac_mmc_ops;
extern const struct stmmac_mmc_ops dwxgmac_mmc_ops;
+extern const struct stmmac_est_ops dwmac510_est_ops;
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
#define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc.h b/drivers/net/ethernet/stmicro/stmmac/mmc.h
index a0c05925883e..14c9d2637dfe 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc.h
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc.h
@@ -52,6 +52,8 @@ struct stmmac_counters {
unsigned int mmc_tx_excessdef;
unsigned int mmc_tx_pause_frame;
unsigned int mmc_tx_vlan_frame_g;
+ unsigned int mmc_tx_lpi_usec;
+ unsigned int mmc_tx_lpi_tran;
/* MMC RX counter registers */
unsigned int mmc_rx_framecount_gb;
@@ -78,9 +80,16 @@ struct stmmac_counters {
unsigned int mmc_rx_fifo_overflow;
unsigned int mmc_rx_vlan_frames_gb;
unsigned int mmc_rx_watchdog_error;
+ unsigned int mmc_rx_lpi_usec;
+ unsigned int mmc_rx_lpi_tran;
+ unsigned int mmc_rx_discard_frames_gb;
+ unsigned int mmc_rx_discard_octets_gb;
+ unsigned int mmc_rx_align_err_frames;
+
/* IPC */
unsigned int mmc_rx_ipc_intr_mask;
unsigned int mmc_rx_ipc_intr;
+
/* IPv4 */
unsigned int mmc_rx_ipv4_gd;
unsigned int mmc_rx_ipv4_hderr;
@@ -118,9 +127,14 @@ struct stmmac_counters {
unsigned int mmc_rx_icmp_gd_octets;
unsigned int mmc_rx_icmp_err_octets;
+ /* Stream-Gate Filter */
+ unsigned int mmc_sgf_pass_fragment_cntr;
+ unsigned int mmc_sgf_fail_fragment_cntr;
+
/* FPE */
unsigned int mmc_tx_fpe_fragment_cntr;
unsigned int mmc_tx_hold_req_cntr;
+ unsigned int mmc_tx_gate_overrun_cntr;
unsigned int mmc_rx_packet_assembly_err_cntr;
unsigned int mmc_rx_packet_smd_err_cntr;
unsigned int mmc_rx_packet_assembly_ok_cntr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
index 6a7c1d325c46..8597c6abae8d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
@@ -177,9 +177,12 @@
#define MMC_XGMAC_RX_DISCARD_OCT_GB 0x1b4
#define MMC_XGMAC_RX_ALIGN_ERR_PKT 0x1bc
+#define MMC_XGMAC_SGF_PASS_PKT 0x1f0
+#define MMC_XGMAC_SGF_FAIL_PKT 0x1f4
#define MMC_XGMAC_TX_FPE_INTR_MASK 0x204
#define MMC_XGMAC_TX_FPE_FRAG 0x208
#define MMC_XGMAC_TX_HOLD_REQ 0x20c
+#define MMC_XGMAC_TX_GATE_OVERRUN 0x210
#define MMC_XGMAC_RX_FPE_INTR_MASK 0x224
#define MMC_XGMAC_RX_PKT_ASSEMBLY_ERR 0x228
#define MMC_XGMAC_RX_PKT_SMD_ERR 0x22c
@@ -187,6 +190,40 @@
#define MMC_XGMAC_RX_FPE_FRAG 0x234
#define MMC_XGMAC_RX_IPC_INTR_MASK 0x25c
+#define MMC_XGMAC_RX_IPV4_GD 0x264
+#define MMC_XGMAC_RX_IPV4_HDERR 0x26c
+#define MMC_XGMAC_RX_IPV4_NOPAY 0x274
+#define MMC_XGMAC_RX_IPV4_FRAG 0x27c
+#define MMC_XGMAC_RX_IPV4_UDSBL 0x284
+
+#define MMC_XGMAC_RX_IPV6_GD 0x28c
+#define MMC_XGMAC_RX_IPV6_HDERR 0x294
+#define MMC_XGMAC_RX_IPV6_NOPAY 0x29c
+
+#define MMC_XGMAC_RX_UDP_GD 0x2a4
+#define MMC_XGMAC_RX_UDP_ERR 0x2ac
+#define MMC_XGMAC_RX_TCP_GD 0x2b4
+#define MMC_XGMAC_RX_TCP_ERR 0x2bc
+#define MMC_XGMAC_RX_ICMP_GD 0x2c4
+#define MMC_XGMAC_RX_ICMP_ERR 0x2cc
+
+#define MMC_XGMAC_RX_IPV4_GD_OCTETS 0x2d4
+#define MMC_XGMAC_RX_IPV4_HDERR_OCTETS 0x2dc
+#define MMC_XGMAC_RX_IPV4_NOPAY_OCTETS 0x2e4
+#define MMC_XGMAC_RX_IPV4_FRAG_OCTETS 0x2ec
+#define MMC_XGMAC_RX_IPV4_UDSBL_OCTETS 0x2f4
+
+#define MMC_XGMAC_RX_IPV6_GD_OCTETS 0x2fc
+#define MMC_XGMAC_RX_IPV6_HDERR_OCTETS 0x304
+#define MMC_XGMAC_RX_IPV6_NOPAY_OCTETS 0x30c
+
+#define MMC_XGMAC_RX_UDP_GD_OCTETS 0x314
+#define MMC_XGMAC_RX_UDP_ERR_OCTETS 0x31c
+#define MMC_XGMAC_RX_TCP_GD_OCTETS 0x324
+#define MMC_XGMAC_RX_TCP_ERR_OCTETS 0x32c
+#define MMC_XGMAC_RX_ICMP_GD_OCTETS 0x334
+#define MMC_XGMAC_RX_ICMP_ERR_OCTETS 0x33c
+
static void dwmac_mmc_ctrl(void __iomem *mmcaddr, unsigned int mode)
{
u32 value = readl(mmcaddr + MMC_CNTRL);
@@ -414,6 +451,8 @@ static void dwxgmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
&mmc->mmc_tx_pause_frame);
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_VLAN_PKT_G,
&mmc->mmc_tx_vlan_frame_g);
+ mmc->mmc_tx_lpi_usec += readl(mmcaddr + MMC_XGMAC_TX_LPI_USEC);
+ mmc->mmc_tx_lpi_tran += readl(mmcaddr + MMC_XGMAC_TX_LPI_TRAN);
/* MMC RX counter registers */
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_PKT_GB,
@@ -459,9 +498,23 @@ static void dwxgmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_VLAN_PKT_GB,
&mmc->mmc_rx_vlan_frames_gb);
mmc->mmc_rx_watchdog_error += readl(mmcaddr + MMC_XGMAC_RX_WATCHDOG_ERR);
-
+ mmc->mmc_rx_lpi_usec += readl(mmcaddr + MMC_XGMAC_RX_LPI_USEC);
+ mmc->mmc_rx_lpi_tran += readl(mmcaddr + MMC_XGMAC_RX_LPI_TRAN);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_DISCARD_PKT_GB,
+ &mmc->mmc_rx_discard_frames_gb);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_DISCARD_OCT_GB,
+ &mmc->mmc_rx_discard_octets_gb);
+ mmc->mmc_rx_align_err_frames +=
+ readl(mmcaddr + MMC_XGMAC_RX_ALIGN_ERR_PKT);
+
+ mmc->mmc_sgf_pass_fragment_cntr +=
+ readl(mmcaddr + MMC_XGMAC_SGF_PASS_PKT);
+ mmc->mmc_sgf_fail_fragment_cntr +=
+ readl(mmcaddr + MMC_XGMAC_SGF_FAIL_PKT);
mmc->mmc_tx_fpe_fragment_cntr += readl(mmcaddr + MMC_XGMAC_TX_FPE_FRAG);
mmc->mmc_tx_hold_req_cntr += readl(mmcaddr + MMC_XGMAC_TX_HOLD_REQ);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_TX_GATE_OVERRUN,
+ &mmc->mmc_tx_gate_overrun_cntr);
mmc->mmc_rx_packet_assembly_err_cntr +=
readl(mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_ERR);
mmc->mmc_rx_packet_smd_err_cntr +=
@@ -470,6 +523,68 @@ static void dwxgmac_mmc_read(void __iomem *mmcaddr, struct stmmac_counters *mmc)
readl(mmcaddr + MMC_XGMAC_RX_PKT_ASSEMBLY_OK);
mmc->mmc_rx_fpe_fragment_cntr +=
readl(mmcaddr + MMC_XGMAC_RX_FPE_FRAG);
+
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_GD,
+ &mmc->mmc_rx_ipv4_gd);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_HDERR,
+ &mmc->mmc_rx_ipv4_hderr);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_NOPAY,
+ &mmc->mmc_rx_ipv4_nopay);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_FRAG,
+ &mmc->mmc_rx_ipv4_frag);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_UDSBL,
+ &mmc->mmc_rx_ipv4_udsbl);
+
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_GD,
+ &mmc->mmc_rx_ipv6_gd);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_HDERR,
+ &mmc->mmc_rx_ipv6_hderr);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_NOPAY,
+ &mmc->mmc_rx_ipv6_nopay);
+
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_GD,
+ &mmc->mmc_rx_udp_gd);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_ERR,
+ &mmc->mmc_rx_udp_err);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_GD,
+ &mmc->mmc_rx_tcp_gd);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_ERR,
+ &mmc->mmc_rx_tcp_err);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_GD,
+ &mmc->mmc_rx_icmp_gd);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_ERR,
+ &mmc->mmc_rx_icmp_err);
+
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_GD_OCTETS,
+ &mmc->mmc_rx_ipv4_gd_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_HDERR_OCTETS,
+ &mmc->mmc_rx_ipv4_hderr_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_NOPAY_OCTETS,
+ &mmc->mmc_rx_ipv4_nopay_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_FRAG_OCTETS,
+ &mmc->mmc_rx_ipv4_frag_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV4_UDSBL_OCTETS,
+ &mmc->mmc_rx_ipv4_udsbl_octets);
+
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_GD_OCTETS,
+ &mmc->mmc_rx_ipv6_gd_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_HDERR_OCTETS,
+ &mmc->mmc_rx_ipv6_hderr_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_IPV6_NOPAY_OCTETS,
+ &mmc->mmc_rx_ipv6_nopay_octets);
+
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_GD_OCTETS,
+ &mmc->mmc_rx_udp_gd_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_UDP_ERR_OCTETS,
+ &mmc->mmc_rx_udp_err_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_GD_OCTETS,
+ &mmc->mmc_rx_tcp_gd_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_TCP_ERR_OCTETS,
+ &mmc->mmc_rx_tcp_err_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_GD_OCTETS,
+ &mmc->mmc_rx_icmp_gd_octets);
+ dwxgmac_read_mmc_reg(mmcaddr, MMC_XGMAC_RX_ICMP_ERR_OCTETS,
+ &mmc->mmc_rx_icmp_err_octets);
}
const struct stmmac_mmc_ops dwxgmac_mmc_ops = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index cd7a9768de5f..f155e4841c62 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -51,6 +51,7 @@ struct stmmac_tx_info {
bool last_segment;
bool is_jumbo;
enum stmmac_txbuf_type buf_type;
+ struct xsk_tx_metadata_compl xsk_meta;
};
#define STMMAC_TBS_AVAIL BIT(0)
@@ -100,6 +101,17 @@ struct stmmac_xdp_buff {
struct dma_desc *ndesc;
};
+struct stmmac_metadata_request {
+ struct stmmac_priv *priv;
+ struct dma_desc *tx_desc;
+ bool *set_ic;
+};
+
+struct stmmac_xsk_tx_complete {
+ struct stmmac_priv *priv;
+ struct dma_desc *desc;
+};
+
struct stmmac_rx_queue {
u32 rx_count_frames;
u32 queue_index;
@@ -255,6 +267,7 @@ struct stmmac_priv {
u32 msg_enable;
int wolopts;
int wol_irq;
+ bool wol_irq_disabled;
int clk_csr;
struct timer_list eee_ctrl_timer;
int lpi_irq;
@@ -283,6 +296,7 @@ struct stmmac_priv {
void __iomem *mmcaddr;
void __iomem *ptpaddr;
+ void __iomem *estaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
int sfty_ce_irq;
int sfty_ue_irq;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
new file mode 100644
index 000000000000..4da6ccc17c20
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, Intel Corporation
+ * stmmac EST(802.3 Qbv) handling
+ */
+#include <linux/iopoll.h>
+#include <linux/types.h>
+#include "stmmac.h"
+#include "stmmac_est.h"
+
+static int est_write(void __iomem *est_addr, u32 reg, u32 val, bool gcl)
+{
+ u32 ctrl;
+
+ writel(val, est_addr + EST_GCL_DATA);
+
+ ctrl = (reg << EST_ADDR_SHIFT);
+ ctrl |= gcl ? 0 : EST_GCRR;
+ writel(ctrl, est_addr + EST_GCL_CONTROL);
+
+ ctrl |= EST_SRWO;
+ writel(ctrl, est_addr + EST_GCL_CONTROL);
+
+ return readl_poll_timeout(est_addr + EST_GCL_CONTROL, ctrl,
+ !(ctrl & EST_SRWO), 100, 5000);
+}
+
+static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg,
+ unsigned int ptp_rate)
+{
+ void __iomem *est_addr = priv->estaddr;
+ int i, ret = 0;
+ u32 ctrl;
+
+ ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false);
+ ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false);
+ ret |= est_write(est_addr, EST_TER, cfg->ter, false);
+ ret |= est_write(est_addr, EST_LLR, cfg->gcl_size, false);
+ ret |= est_write(est_addr, EST_CTR_LOW, cfg->ctr[0], false);
+ ret |= est_write(est_addr, EST_CTR_HIGH, cfg->ctr[1], false);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < cfg->gcl_size; i++) {
+ ret = est_write(est_addr, i, cfg->gcl[i], true);
+ if (ret)
+ return ret;
+ }
+
+ ctrl = readl(est_addr + EST_CONTROL);
+ if (priv->plat->has_xgmac) {
+ ctrl &= ~EST_XGMAC_PTOV;
+ ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) <<
+ EST_XGMAC_PTOV_SHIFT;
+ } else {
+ ctrl &= ~EST_GMAC5_PTOV;
+ ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_GMAC5_PTOV_MUL) <<
+ EST_GMAC5_PTOV_SHIFT;
+ }
+ if (cfg->enable)
+ ctrl |= EST_EEST | EST_SSWL;
+ else
+ ctrl &= ~EST_EEST;
+
+ writel(ctrl, est_addr + EST_CONTROL);
+
+ /* Configure EST interrupt */
+ if (cfg->enable)
+ ctrl = EST_IECGCE | EST_IEHS | EST_IEHF | EST_IEBE | EST_IECC;
+ else
+ ctrl = 0;
+
+ writel(ctrl, est_addr + EST_INT_EN);
+
+ return 0;
+}
+
+static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev,
+ struct stmmac_extra_stats *x, u32 txqcnt)
+{
+ u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max;
+ void __iomem *est_addr = priv->estaddr;
+ u32 txqcnt_mask = BIT(txqcnt) - 1;
+
+ status = readl(est_addr + EST_STATUS);
+
+ value = EST_CGCE | EST_HLBS | EST_HLBF | EST_BTRE | EST_SWLC;
+
+ /* Return if there is no error */
+ if (!(status & value))
+ return;
+
+ if (status & EST_CGCE) {
+ /* Clear Interrupt */
+ writel(EST_CGCE, est_addr + EST_STATUS);
+
+ x->mtl_est_cgce++;
+ }
+
+ if (status & EST_HLBS) {
+ value = readl(est_addr + EST_SCH_ERR);
+ value &= txqcnt_mask;
+
+ x->mtl_est_hlbs++;
+
+ /* Clear Interrupt */
+ writel(value, est_addr + EST_SCH_ERR);
+
+ /* Collecting info to shows all the queues that has HLBS
+ * issue. The only way to clear this is to clear the
+ * statistic
+ */
+ if (net_ratelimit())
+ netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
+ }
+
+ if (status & EST_HLBF) {
+ value = readl(est_addr + EST_FRM_SZ_ERR);
+ feqn = value & txqcnt_mask;
+
+ value = readl(est_addr + EST_FRM_SZ_CAP);
+ hbfq = (value & EST_SZ_CAP_HBFQ_MASK(txqcnt)) >>
+ EST_SZ_CAP_HBFQ_SHIFT;
+ hbfs = value & EST_SZ_CAP_HBFS_MASK;
+
+ x->mtl_est_hlbf++;
+
+ /* Clear Interrupt */
+ writel(feqn, est_addr + EST_FRM_SZ_ERR);
+
+ if (net_ratelimit())
+ netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
+ hbfq, hbfs);
+ }
+
+ if (status & EST_BTRE) {
+ if (priv->plat->has_xgmac) {
+ btrl = FIELD_GET(EST_XGMAC_BTRL, status);
+ btrl_max = FIELD_MAX(EST_XGMAC_BTRL);
+ } else {
+ btrl = FIELD_GET(EST_GMAC5_BTRL, status);
+ btrl_max = FIELD_MAX(EST_GMAC5_BTRL);
+ }
+ if (btrl == btrl_max)
+ x->mtl_est_btrlm++;
+ else
+ x->mtl_est_btre++;
+
+ if (net_ratelimit())
+ netdev_info(dev, "EST: BTR Error Loop Count %u\n",
+ btrl);
+
+ writel(EST_BTRE, est_addr + EST_STATUS);
+ }
+
+ if (status & EST_SWLC) {
+ writel(EST_SWLC, est_addr + EST_STATUS);
+ netdev_info(dev, "EST: SWOL has been switched\n");
+ }
+}
+
+const struct stmmac_est_ops dwmac510_est_ops = {
+ .configure = est_configure,
+ .irq_status = est_irq_status,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h
new file mode 100644
index 000000000000..7a858c566e7e
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2023, Intel Corporation
+ * stmmac EST(802.3 Qbv) handling
+ */
+
+#define EST_GMAC4_OFFSET 0x00000c50
+#define EST_XGMAC_OFFSET 0x00001050
+
+#define EST_CONTROL 0x00000000
+#define EST_GMAC5_PTOV GENMASK(31, 24)
+#define EST_GMAC5_PTOV_SHIFT 24
+#define EST_GMAC5_PTOV_MUL 6
+#define EST_XGMAC_PTOV GENMASK(31, 23)
+#define EST_XGMAC_PTOV_SHIFT 23
+#define EST_XGMAC_PTOV_MUL 9
+#define EST_SSWL BIT(1)
+#define EST_EEST BIT(0)
+
+#define EST_STATUS 0x00000008
+#define EST_GMAC5_BTRL GENMASK(11, 8)
+#define EST_XGMAC_BTRL GENMASK(15, 8)
+#define EST_SWOL BIT(7)
+#define EST_SWOL_SHIFT 7
+#define EST_CGCE BIT(4)
+#define EST_HLBS BIT(3)
+#define EST_HLBF BIT(2)
+#define EST_BTRE BIT(1)
+#define EST_SWLC BIT(0)
+
+#define EST_SCH_ERR 0x00000010
+
+#define EST_FRM_SZ_ERR 0x00000014
+
+#define EST_FRM_SZ_CAP 0x00000018
+#define EST_SZ_CAP_HBFS_MASK GENMASK(14, 0)
+#define EST_SZ_CAP_HBFQ_SHIFT 16
+#define EST_SZ_CAP_HBFQ_MASK(val) \
+ ({ \
+ typeof(val) _val = (val); \
+ (_val > 4 ? GENMASK(18, 16) : \
+ _val > 2 ? GENMASK(17, 16) : \
+ BIT(16)); \
+ })
+
+#define EST_INT_EN 0x00000020
+#define EST_IECGCE EST_CGCE
+#define EST_IEHS EST_HLBS
+#define EST_IEHF EST_HLBF
+#define EST_IEBE EST_BTRE
+#define EST_IECC EST_SWLC
+
+#define EST_GCL_CONTROL 0x00000030
+#define EST_BTR_LOW 0x0
+#define EST_BTR_HIGH 0x1
+#define EST_CTR_LOW 0x2
+#define EST_CTR_HIGH 0x3
+#define EST_TER 0x4
+#define EST_LLR 0x5
+#define EST_ADDR_SHIFT 8
+#define EST_GCRR BIT(2)
+#define EST_SRWO BIT(0)
+
+#define EST_GCL_DATA 0x00000034
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index f628411ae4ae..ec44becf0e2d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -212,6 +212,8 @@ static const struct stmmac_stats stmmac_mmc[] = {
STMMAC_MMC_STAT(mmc_tx_excessdef),
STMMAC_MMC_STAT(mmc_tx_pause_frame),
STMMAC_MMC_STAT(mmc_tx_vlan_frame_g),
+ STMMAC_MMC_STAT(mmc_tx_lpi_usec),
+ STMMAC_MMC_STAT(mmc_tx_lpi_tran),
STMMAC_MMC_STAT(mmc_rx_framecount_gb),
STMMAC_MMC_STAT(mmc_rx_octetcount_gb),
STMMAC_MMC_STAT(mmc_rx_octetcount_g),
@@ -236,6 +238,11 @@ static const struct stmmac_stats stmmac_mmc[] = {
STMMAC_MMC_STAT(mmc_rx_fifo_overflow),
STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb),
STMMAC_MMC_STAT(mmc_rx_watchdog_error),
+ STMMAC_MMC_STAT(mmc_rx_lpi_usec),
+ STMMAC_MMC_STAT(mmc_rx_lpi_tran),
+ STMMAC_MMC_STAT(mmc_rx_discard_frames_gb),
+ STMMAC_MMC_STAT(mmc_rx_discard_octets_gb),
+ STMMAC_MMC_STAT(mmc_rx_align_err_frames),
STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask),
STMMAC_MMC_STAT(mmc_rx_ipc_intr),
STMMAC_MMC_STAT(mmc_rx_ipv4_gd),
@@ -266,8 +273,11 @@ static const struct stmmac_stats stmmac_mmc[] = {
STMMAC_MMC_STAT(mmc_rx_tcp_err_octets),
STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets),
STMMAC_MMC_STAT(mmc_rx_icmp_err_octets),
+ STMMAC_MMC_STAT(mmc_sgf_pass_fragment_cntr),
+ STMMAC_MMC_STAT(mmc_sgf_fail_fragment_cntr),
STMMAC_MMC_STAT(mmc_tx_fpe_fragment_cntr),
STMMAC_MMC_STAT(mmc_tx_hold_req_cntr),
+ STMMAC_MMC_STAT(mmc_tx_gate_overrun_cntr),
STMMAC_MMC_STAT(mmc_rx_packet_assembly_err_cntr),
STMMAC_MMC_STAT(mmc_rx_packet_smd_err_cntr),
STMMAC_MMC_STAT(mmc_rx_packet_assembly_ok_cntr),
@@ -311,8 +321,9 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev,
{
struct stmmac_priv *priv = netdev_priv(dev);
- if (priv->hw->pcs & STMMAC_PCS_RGMII ||
- priv->hw->pcs & STMMAC_PCS_SGMII) {
+ if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
+ (priv->hw->pcs & STMMAC_PCS_RGMII ||
+ priv->hw->pcs & STMMAC_PCS_SGMII)) {
struct rgmii_adv adv;
u32 supported, advertising, lp_advertising;
@@ -397,8 +408,9 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev,
{
struct stmmac_priv *priv = netdev_priv(dev);
- if (priv->hw->pcs & STMMAC_PCS_RGMII ||
- priv->hw->pcs & STMMAC_PCS_SGMII) {
+ if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) &&
+ (priv->hw->pcs & STMMAC_PCS_RGMII ||
+ priv->hw->pcs & STMMAC_PCS_SGMII)) {
/* Only support ANE */
if (cmd->base.autoneg != AUTONEG_ENABLE)
return -EINVAL;
@@ -537,49 +549,79 @@ stmmac_set_pauseparam(struct net_device *netdev,
}
}
+static u64 stmmac_get_rx_normal_irq_n(struct stmmac_priv *priv, int q)
+{
+ u64 total;
+ int cpu;
+
+ total = 0;
+ for_each_possible_cpu(cpu) {
+ struct stmmac_pcpu_stats *pcpu;
+ unsigned int start;
+ u64 irq_n;
+
+ pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu);
+ do {
+ start = u64_stats_fetch_begin(&pcpu->syncp);
+ irq_n = u64_stats_read(&pcpu->rx_normal_irq_n[q]);
+ } while (u64_stats_fetch_retry(&pcpu->syncp, start));
+ total += irq_n;
+ }
+ return total;
+}
+
+static u64 stmmac_get_tx_normal_irq_n(struct stmmac_priv *priv, int q)
+{
+ u64 total;
+ int cpu;
+
+ total = 0;
+ for_each_possible_cpu(cpu) {
+ struct stmmac_pcpu_stats *pcpu;
+ unsigned int start;
+ u64 irq_n;
+
+ pcpu = per_cpu_ptr(priv->xstats.pcpu_stats, cpu);
+ do {
+ start = u64_stats_fetch_begin(&pcpu->syncp);
+ irq_n = u64_stats_read(&pcpu->tx_normal_irq_n[q]);
+ } while (u64_stats_fetch_retry(&pcpu->syncp, start));
+ total += irq_n;
+ }
+ return total;
+}
+
static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data)
{
u32 tx_cnt = priv->plat->tx_queues_to_use;
u32 rx_cnt = priv->plat->rx_queues_to_use;
unsigned int start;
- int q, stat;
- u64 *pos;
- char *p;
+ int q;
- pos = data;
for (q = 0; q < tx_cnt; q++) {
struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q];
- struct stmmac_txq_stats snapshot;
+ u64 pkt_n;
- data = pos;
do {
- start = u64_stats_fetch_begin(&txq_stats->syncp);
- snapshot = *txq_stats;
- } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
+ start = u64_stats_fetch_begin(&txq_stats->napi_syncp);
+ pkt_n = u64_stats_read(&txq_stats->napi.tx_pkt_n);
+ } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start));
- p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n);
- for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) {
- *data++ += (*(u64 *)p);
- p += sizeof(u64);
- }
+ *data++ = pkt_n;
+ *data++ = stmmac_get_tx_normal_irq_n(priv, q);
}
- pos = data;
for (q = 0; q < rx_cnt; q++) {
struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q];
- struct stmmac_rxq_stats snapshot;
+ u64 pkt_n;
- data = pos;
do {
- start = u64_stats_fetch_begin(&rxq_stats->syncp);
- snapshot = *rxq_stats;
- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
+ start = u64_stats_fetch_begin(&rxq_stats->napi_syncp);
+ pkt_n = u64_stats_read(&rxq_stats->napi.rx_pkt_n);
+ } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start));
- p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n);
- for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) {
- *data++ += (*(u64 *)p);
- p += sizeof(u64);
- }
+ *data++ = pkt_n;
+ *data++ = stmmac_get_rx_normal_irq_n(priv, q);
}
}
@@ -638,39 +680,49 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
pos = j;
for (i = 0; i < rx_queues_count; i++) {
struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[i];
- struct stmmac_rxq_stats snapshot;
+ struct stmmac_napi_rx_stats snapshot;
+ u64 n_irq;
j = pos;
do {
- start = u64_stats_fetch_begin(&rxq_stats->syncp);
- snapshot = *rxq_stats;
- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
-
- data[j++] += snapshot.rx_pkt_n;
- data[j++] += snapshot.rx_normal_irq_n;
- normal_irq_n += snapshot.rx_normal_irq_n;
- napi_poll += snapshot.napi_poll;
+ start = u64_stats_fetch_begin(&rxq_stats->napi_syncp);
+ snapshot = rxq_stats->napi;
+ } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start));
+
+ data[j++] += u64_stats_read(&snapshot.rx_pkt_n);
+ n_irq = stmmac_get_rx_normal_irq_n(priv, i);
+ data[j++] += n_irq;
+ normal_irq_n += n_irq;
+ napi_poll += u64_stats_read(&snapshot.poll);
}
pos = j;
for (i = 0; i < tx_queues_count; i++) {
struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[i];
- struct stmmac_txq_stats snapshot;
+ struct stmmac_napi_tx_stats napi_snapshot;
+ struct stmmac_q_tx_stats q_snapshot;
+ u64 n_irq;
j = pos;
do {
- start = u64_stats_fetch_begin(&txq_stats->syncp);
- snapshot = *txq_stats;
- } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
-
- data[j++] += snapshot.tx_pkt_n;
- data[j++] += snapshot.tx_normal_irq_n;
- normal_irq_n += snapshot.tx_normal_irq_n;
- data[j++] += snapshot.tx_clean;
- data[j++] += snapshot.tx_set_ic_bit;
- data[j++] += snapshot.tx_tso_frames;
- data[j++] += snapshot.tx_tso_nfrags;
- napi_poll += snapshot.napi_poll;
+ start = u64_stats_fetch_begin(&txq_stats->q_syncp);
+ q_snapshot = txq_stats->q;
+ } while (u64_stats_fetch_retry(&txq_stats->q_syncp, start));
+ do {
+ start = u64_stats_fetch_begin(&txq_stats->napi_syncp);
+ napi_snapshot = txq_stats->napi;
+ } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start));
+
+ data[j++] += u64_stats_read(&napi_snapshot.tx_pkt_n);
+ n_irq = stmmac_get_tx_normal_irq_n(priv, i);
+ data[j++] += n_irq;
+ normal_irq_n += n_irq;
+ data[j++] += u64_stats_read(&napi_snapshot.tx_clean);
+ data[j++] += u64_stats_read(&q_snapshot.tx_set_ic_bit) +
+ u64_stats_read(&napi_snapshot.tx_set_ic_bit);
+ data[j++] += u64_stats_read(&q_snapshot.tx_tso_frames);
+ data[j++] += u64_stats_read(&q_snapshot.tx_tso_nfrags);
+ napi_poll += u64_stats_read(&napi_snapshot.poll);
}
normal_irq_n += priv->xstats.rx_early_irq;
data[j++] = normal_irq_n;
@@ -825,10 +877,16 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts) {
pr_info("stmmac: wakeup enable\n");
device_set_wakeup_enable(priv->device, 1);
- enable_irq_wake(priv->wol_irq);
+ /* Avoid unbalanced enable_irq_wake calls */
+ if (priv->wol_irq_disabled)
+ enable_irq_wake(priv->wol_irq);
+ priv->wol_irq_disabled = false;
} else {
device_set_wakeup_enable(priv->device, 0);
- disable_irq_wake(priv->wol_irq);
+ /* Avoid unbalanced disable_irq_wake calls */
+ if (!priv->wol_irq_disabled)
+ disable_irq_wake(priv->wol_irq);
+ priv->wol_irq_disabled = true;
}
mutex_lock(&priv->lock);
@@ -1077,41 +1135,42 @@ static u32 stmmac_get_rxfh_indir_size(struct net_device *dev)
return ARRAY_SIZE(priv->rss.table);
}
-static int stmmac_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int stmmac_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct stmmac_priv *priv = netdev_priv(dev);
int i;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++)
- indir[i] = priv->rss.table[i];
+ rxfh->indir[i] = priv->rss.table[i];
}
- if (key)
- memcpy(key, priv->rss.key, sizeof(priv->rss.key));
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ if (rxfh->key)
+ memcpy(rxfh->key, priv->rss.key, sizeof(priv->rss.key));
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int stmmac_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int stmmac_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct stmmac_priv *priv = netdev_priv(dev);
int i;
- if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && (hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < ARRAY_SIZE(priv->rss.table); i++)
- priv->rss.table[i] = indir[i];
+ priv->rss.table[i] = rxfh->indir[i];
}
- if (key)
- memcpy(priv->rss.key, key, sizeof(priv->rss.key));
+ if (rxfh->key)
+ memcpy(priv->rss.key, rxfh->key, sizeof(priv->rss.key));
return stmmac_rss_configure(priv, priv->hw, &priv->rss,
priv->plat->rx_queues_to_use);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 37e64283f910..7c6aef033a45 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2431,6 +2431,46 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
}
}
+static void stmmac_xsk_request_timestamp(void *_priv)
+{
+ struct stmmac_metadata_request *meta_req = _priv;
+
+ stmmac_enable_tx_timestamp(meta_req->priv, meta_req->tx_desc);
+ *meta_req->set_ic = true;
+}
+
+static u64 stmmac_xsk_fill_timestamp(void *_priv)
+{
+ struct stmmac_xsk_tx_complete *tx_compl = _priv;
+ struct stmmac_priv *priv = tx_compl->priv;
+ struct dma_desc *desc = tx_compl->desc;
+ bool found = false;
+ u64 ns = 0;
+
+ if (!priv->hwts_tx_en)
+ return 0;
+
+ /* check tx tstamp status */
+ if (stmmac_get_tx_timestamp_status(priv, desc)) {
+ stmmac_get_timestamp(priv, desc, priv->adv_ts, &ns);
+ found = true;
+ } else if (!stmmac_get_mac_tx_timestamp(priv, priv->hw, &ns)) {
+ found = true;
+ }
+
+ if (found) {
+ ns -= priv->plat->cdc_error_adj;
+ return ns_to_ktime(ns);
+ }
+
+ return 0;
+}
+
+static const struct xsk_tx_metadata_ops stmmac_xsk_tx_metadata_ops = {
+ .tmo_request_timestamp = stmmac_xsk_request_timestamp,
+ .tmo_fill_timestamp = stmmac_xsk_fill_timestamp,
+};
+
static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
{
struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue);
@@ -2442,7 +2482,6 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
struct xdp_desc xdp_desc;
bool work_done = true;
u32 tx_set_ic_bit = 0;
- unsigned long flags;
/* Avoids TX time-out as we are sharing with slow path */
txq_trans_cond_update(nq);
@@ -2450,6 +2489,8 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
budget = min(budget, stmmac_tx_avail(priv, queue));
while (budget-- > 0) {
+ struct stmmac_metadata_request meta_req;
+ struct xsk_tx_metadata *meta = NULL;
dma_addr_t dma_addr;
bool set_ic;
@@ -2473,6 +2514,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
tx_desc = tx_q->dma_tx + entry;
dma_addr = xsk_buff_raw_get_dma(pool, xdp_desc.addr);
+ meta = xsk_buff_get_metadata(pool, xdp_desc.addr);
xsk_buff_raw_dma_sync_for_device(pool, dma_addr, xdp_desc.len);
tx_q->tx_skbuff_dma[entry].buf_type = STMMAC_TXBUF_T_XSK_TX;
@@ -2500,6 +2542,11 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
else
set_ic = false;
+ meta_req.priv = priv;
+ meta_req.tx_desc = tx_desc;
+ meta_req.set_ic = &set_ic;
+ xsk_tx_metadata_request(meta, &stmmac_xsk_tx_metadata_ops,
+ &meta_req);
if (set_ic) {
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, tx_desc);
@@ -2512,12 +2559,15 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
stmmac_enable_dma_transmission(priv, priv->ioaddr);
+ xsk_tx_metadata_to_compl(meta,
+ &tx_q->tx_skbuff_dma[entry].xsk_meta);
+
tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size);
entry = tx_q->cur_tx;
}
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->tx_set_ic_bit += tx_set_ic_bit;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_update_begin(&txq_stats->napi_syncp);
+ u64_stats_add(&txq_stats->napi.tx_set_ic_bit, tx_set_ic_bit);
+ u64_stats_update_end(&txq_stats->napi_syncp);
if (tx_desc) {
stmmac_flush_tx_descriptors(priv, queue);
@@ -2565,7 +2615,6 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
unsigned int bytes_compl = 0, pkts_compl = 0;
unsigned int entry, xmits = 0, count = 0;
u32 tx_packets = 0, tx_errors = 0;
- unsigned long flags;
__netif_tx_lock_bh(netdev_get_tx_queue(priv->dev, queue));
@@ -2621,8 +2670,19 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
} else {
tx_packets++;
}
- if (skb)
+ if (skb) {
stmmac_get_tx_hwtstamp(priv, p, skb);
+ } else if (tx_q->xsk_pool &&
+ xp_tx_metadata_enabled(tx_q->xsk_pool)) {
+ struct stmmac_xsk_tx_complete tx_compl = {
+ .priv = priv,
+ .desc = p,
+ };
+
+ xsk_tx_metadata_complete(&tx_q->tx_skbuff_dma[entry].xsk_meta,
+ &stmmac_xsk_tx_metadata_ops,
+ &tx_compl);
+ }
}
if (likely(tx_q->tx_skbuff_dma[entry].buf &&
@@ -2721,11 +2781,11 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
if (tx_q->dirty_tx != tx_q->cur_tx)
*pending_packets = true;
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->tx_packets += tx_packets;
- txq_stats->tx_pkt_n += tx_packets;
- txq_stats->tx_clean++;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_update_begin(&txq_stats->napi_syncp);
+ u64_stats_add(&txq_stats->napi.tx_packets, tx_packets);
+ u64_stats_add(&txq_stats->napi.tx_pkt_n, tx_packets);
+ u64_stats_inc(&txq_stats->napi.tx_clean);
+ u64_stats_update_end(&txq_stats->napi_syncp);
priv->xstats.tx_errors += tx_errors;
@@ -3470,6 +3530,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
/* Start the ball rolling... */
stmmac_start_all_dma(priv);
+ stmmac_set_hw_vlan_mode(priv, priv->hw);
+
if (priv->dma_cap.fpesel) {
stmmac_fpe_start_wq(priv);
@@ -3565,6 +3627,7 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev)
/* Request the Wake IRQ in case of another line
* is used for WoL
*/
+ priv->wol_irq_disabled = true;
if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) {
int_name = priv->int_name_wol;
sprintf(int_name, "%s:%s", dev->name, "wol");
@@ -3868,6 +3931,9 @@ static int __stmmac_open(struct net_device *dev,
priv->rx_copybreak = STMMAC_RX_COPYBREAK;
buf_sz = dma_conf->dma_buf_sz;
+ for (int i = 0; i < MTL_MAX_TX_QUEUES; i++)
+ if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_EN)
+ dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
stmmac_reset_queues_param(priv);
@@ -3940,8 +4006,10 @@ static void stmmac_fpe_stop_wq(struct stmmac_priv *priv)
{
set_bit(__FPE_REMOVING, &priv->fpe_task_state);
- if (priv->fpe_wq)
+ if (priv->fpe_wq) {
destroy_workqueue(priv->fpe_wq);
+ priv->fpe_wq = NULL;
+ }
netdev_info(priv->dev, "FPE workqueue stop");
}
@@ -4146,7 +4214,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_tx_queue *tx_q;
bool has_vlan, set_ic;
u8 proto_hdr_len, hdr;
- unsigned long flags;
u32 pay_len, mss;
dma_addr_t des;
int i;
@@ -4311,13 +4378,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
}
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->tx_bytes += skb->len;
- txq_stats->tx_tso_frames++;
- txq_stats->tx_tso_nfrags += nfrags;
+ u64_stats_update_begin(&txq_stats->q_syncp);
+ u64_stats_add(&txq_stats->q.tx_bytes, skb->len);
+ u64_stats_inc(&txq_stats->q.tx_tso_frames);
+ u64_stats_add(&txq_stats->q.tx_tso_nfrags, nfrags);
if (set_ic)
- txq_stats->tx_set_ic_bit++;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_inc(&txq_stats->q.tx_set_ic_bit);
+ u64_stats_update_end(&txq_stats->q_syncp);
if (priv->sarc_type)
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
@@ -4372,6 +4439,28 @@ dma_map_err:
}
/**
+ * stmmac_has_ip_ethertype() - Check if packet has IP ethertype
+ * @skb: socket buffer to check
+ *
+ * Check if a packet has an ethertype that will trigger the IP header checks
+ * and IP/TCP checksum engine of the stmmac core.
+ *
+ * Return: true if the ethertype can trigger the checksum engine, false
+ * otherwise
+ */
+static bool stmmac_has_ip_ethertype(struct sk_buff *skb)
+{
+ int depth = 0;
+ __be16 proto;
+
+ proto = __vlan_get_protocol(skb, eth_header_parse_protocol(skb),
+ &depth);
+
+ return (depth <= ETH_HLEN) &&
+ (proto == htons(ETH_P_IP) || proto == htons(ETH_P_IPV6));
+}
+
+/**
* stmmac_xmit - Tx entry point of the driver
* @skb : the socket buffer
* @dev : device pointer
@@ -4394,7 +4483,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_tx_queue *tx_q;
bool has_vlan, set_ic;
int entry, first_tx;
- unsigned long flags;
dma_addr_t des;
tx_q = &priv->dma_conf.tx_queue[queue];
@@ -4435,9 +4523,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
/* DWMAC IPs can be synthesized to support tx coe only for a few tx
* queues. In that case, checksum offloading for those queues that don't
* support tx coe needs to fallback to software checksum calculation.
+ *
+ * Packets that won't trigger the COE e.g. most DSA-tagged packets will
+ * also have to be checksummed in software.
*/
if (csum_insertion &&
- priv->plat->tx_queues_cfg[queue].coe_unsupported) {
+ (priv->plat->tx_queues_cfg[queue].coe_unsupported ||
+ !stmmac_has_ip_ethertype(skb))) {
if (unlikely(skb_checksum_help(skb)))
goto dma_map_err;
csum_insertion = !csum_insertion;
@@ -4560,11 +4652,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue));
}
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->tx_bytes += skb->len;
+ u64_stats_update_begin(&txq_stats->q_syncp);
+ u64_stats_add(&txq_stats->q.tx_bytes, skb->len);
if (set_ic)
- txq_stats->tx_set_ic_bit++;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_inc(&txq_stats->q.tx_set_ic_bit);
+ u64_stats_update_end(&txq_stats->q_syncp);
if (priv->sarc_type)
stmmac_set_desc_sarc(priv, first, priv->sarc_type);
@@ -4828,12 +4920,11 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue,
set_ic = false;
if (set_ic) {
- unsigned long flags;
tx_q->tx_count_frames = 0;
stmmac_set_tx_ic(priv, tx_desc);
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->tx_set_ic_bit++;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_update_begin(&txq_stats->q_syncp);
+ u64_stats_inc(&txq_stats->q.tx_set_ic_bit);
+ u64_stats_update_end(&txq_stats->q_syncp);
}
stmmac_enable_dma_transmission(priv, priv->ioaddr);
@@ -4983,7 +5074,6 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
unsigned int len = xdp->data_end - xdp->data;
enum pkt_hash_types hash_type;
int coe = priv->hw->rx_csum;
- unsigned long flags;
struct sk_buff *skb;
u32 hash;
@@ -4994,10 +5084,15 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
}
stmmac_get_rx_hwtstamp(priv, p, np, skb);
- stmmac_rx_vlan(priv->dev, skb);
+ if (priv->hw->hw_vlan_en)
+ /* MAC level stripping. */
+ stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
+ else
+ /* Driver level stripping. */
+ stmmac_rx_vlan(priv->dev, skb);
skb->protocol = eth_type_trans(skb, priv->dev);
- if (unlikely(!coe))
+ if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
skb_checksum_none_assert(skb);
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -5008,10 +5103,10 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
skb_record_rx_queue(skb, queue);
napi_gro_receive(&ch->rxtx_napi, skb);
- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
- rxq_stats->rx_pkt_n++;
- rxq_stats->rx_bytes += len;
- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
+ u64_stats_update_begin(&rxq_stats->napi_syncp);
+ u64_stats_inc(&rxq_stats->napi.rx_pkt_n);
+ u64_stats_add(&rxq_stats->napi.rx_bytes, len);
+ u64_stats_update_end(&rxq_stats->napi_syncp);
}
static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
@@ -5093,7 +5188,6 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int desc_size;
struct bpf_prog *prog;
bool failure = false;
- unsigned long flags;
int xdp_status = 0;
int status = 0;
@@ -5248,9 +5342,9 @@ read_again:
stmmac_finalize_xdp_rx(priv, xdp_status);
- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
- rxq_stats->rx_pkt_n += count;
- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
+ u64_stats_update_begin(&rxq_stats->napi_syncp);
+ u64_stats_add(&rxq_stats->napi.rx_pkt_n, count);
+ u64_stats_update_end(&rxq_stats->napi_syncp);
priv->xstats.rx_dropped += rx_dropped;
priv->xstats.rx_errors += rx_errors;
@@ -5288,7 +5382,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
unsigned int desc_size;
struct sk_buff *skb = NULL;
struct stmmac_xdp_buff ctx;
- unsigned long flags;
int xdp_status = 0;
int buf_sz;
@@ -5510,10 +5603,17 @@ drain_data:
/* Got entire packet into SKB. Finish it. */
stmmac_get_rx_hwtstamp(priv, p, np, skb);
- stmmac_rx_vlan(priv->dev, skb);
+
+ if (priv->hw->hw_vlan_en)
+ /* MAC level stripping. */
+ stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
+ else
+ /* Driver level stripping. */
+ stmmac_rx_vlan(priv->dev, skb);
+
skb->protocol = eth_type_trans(skb, priv->dev);
- if (unlikely(!coe))
+ if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb))
skb_checksum_none_assert(skb);
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -5541,11 +5641,11 @@ drain_data:
stmmac_rx_refill(priv, queue);
- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
- rxq_stats->rx_packets += rx_packets;
- rxq_stats->rx_bytes += rx_bytes;
- rxq_stats->rx_pkt_n += count;
- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
+ u64_stats_update_begin(&rxq_stats->napi_syncp);
+ u64_stats_add(&rxq_stats->napi.rx_packets, rx_packets);
+ u64_stats_add(&rxq_stats->napi.rx_bytes, rx_bytes);
+ u64_stats_add(&rxq_stats->napi.rx_pkt_n, count);
+ u64_stats_update_end(&rxq_stats->napi_syncp);
priv->xstats.rx_dropped += rx_dropped;
priv->xstats.rx_errors += rx_errors;
@@ -5560,13 +5660,12 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget)
struct stmmac_priv *priv = ch->priv_data;
struct stmmac_rxq_stats *rxq_stats;
u32 chan = ch->index;
- unsigned long flags;
int work_done;
rxq_stats = &priv->xstats.rxq_stats[chan];
- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
- rxq_stats->napi_poll++;
- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
+ u64_stats_update_begin(&rxq_stats->napi_syncp);
+ u64_stats_inc(&rxq_stats->napi.poll);
+ u64_stats_update_end(&rxq_stats->napi_syncp);
work_done = stmmac_rx(priv, budget, chan);
if (work_done < budget && napi_complete_done(napi, work_done)) {
@@ -5588,13 +5687,12 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget)
struct stmmac_txq_stats *txq_stats;
bool pending_packets = false;
u32 chan = ch->index;
- unsigned long flags;
int work_done;
txq_stats = &priv->xstats.txq_stats[chan];
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->napi_poll++;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_update_begin(&txq_stats->napi_syncp);
+ u64_stats_inc(&txq_stats->napi.poll);
+ u64_stats_update_end(&txq_stats->napi_syncp);
work_done = stmmac_tx_clean(priv, budget, chan, &pending_packets);
work_done = min(work_done, budget);
@@ -5624,17 +5722,16 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget)
struct stmmac_rxq_stats *rxq_stats;
struct stmmac_txq_stats *txq_stats;
u32 chan = ch->index;
- unsigned long flags;
rxq_stats = &priv->xstats.rxq_stats[chan];
- flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp);
- rxq_stats->napi_poll++;
- u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags);
+ u64_stats_update_begin(&rxq_stats->napi_syncp);
+ u64_stats_inc(&rxq_stats->napi.poll);
+ u64_stats_update_end(&rxq_stats->napi_syncp);
txq_stats = &priv->xstats.txq_stats[chan];
- flags = u64_stats_update_begin_irqsave(&txq_stats->syncp);
- txq_stats->napi_poll++;
- u64_stats_update_end_irqrestore(&txq_stats->syncp, flags);
+ u64_stats_update_begin(&txq_stats->napi_syncp);
+ u64_stats_inc(&txq_stats->napi.poll);
+ u64_stats_update_end(&txq_stats->napi_syncp);
tx_done = stmmac_tx_clean(priv, budget, chan, &tx_pending_packets);
tx_done = min(tx_done, budget);
@@ -5819,6 +5916,13 @@ static int stmmac_set_features(struct net_device *netdev,
stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan);
}
+ if (features & NETIF_F_HW_VLAN_CTAG_RX)
+ priv->hw->hw_vlan_en = true;
+ else
+ priv->hw->hw_vlan_en = false;
+
+ stmmac_set_hw_vlan_mode(priv, priv->hw);
+
return 0;
}
@@ -5880,7 +5984,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv)
pm_wakeup_event(priv->device, 0);
if (priv->dma_cap.estsel)
- stmmac_est_irq_status(priv, priv->ioaddr, priv->dev,
+ stmmac_est_irq_status(priv, priv, priv->dev,
&priv->xstats, tx_cnt);
if (priv->dma_cap.fpesel) {
@@ -5958,11 +6062,6 @@ static irqreturn_t stmmac_mac_interrupt(int irq, void *dev_id)
struct net_device *dev = (struct net_device *)dev_id;
struct stmmac_priv *priv = netdev_priv(dev);
- if (unlikely(!dev)) {
- netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
- return IRQ_NONE;
- }
-
/* Check if adapter is up */
if (test_bit(STMMAC_DOWN, &priv->state))
return IRQ_HANDLED;
@@ -5978,11 +6077,6 @@ static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id)
struct net_device *dev = (struct net_device *)dev_id;
struct stmmac_priv *priv = netdev_priv(dev);
- if (unlikely(!dev)) {
- netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
- return IRQ_NONE;
- }
-
/* Check if adapter is up */
if (test_bit(STMMAC_DOWN, &priv->state))
return IRQ_HANDLED;
@@ -6004,11 +6098,6 @@ static irqreturn_t stmmac_msi_intr_tx(int irq, void *data)
dma_conf = container_of(tx_q, struct stmmac_dma_conf, tx_queue[chan]);
priv = container_of(dma_conf, struct stmmac_priv, dma_conf);
- if (unlikely(!data)) {
- netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
- return IRQ_NONE;
- }
-
/* Check if adapter is up */
if (test_bit(STMMAC_DOWN, &priv->state))
return IRQ_HANDLED;
@@ -6035,11 +6124,6 @@ static irqreturn_t stmmac_msi_intr_rx(int irq, void *data)
dma_conf = container_of(rx_q, struct stmmac_dma_conf, rx_queue[chan]);
priv = container_of(dma_conf, struct stmmac_priv, dma_conf);
- if (unlikely(!data)) {
- netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__);
- return IRQ_NONE;
- }
-
/* Check if adapter is up */
if (test_bit(STMMAC_DOWN, &priv->state))
return IRQ_HANDLED;
@@ -6182,30 +6266,23 @@ static struct dentry *stmmac_fs_dir;
static void sysfs_display_ring(void *head, int size, int extend_desc,
struct seq_file *seq, dma_addr_t dma_phy_addr)
{
- int i;
struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
struct dma_desc *p = (struct dma_desc *)head;
+ unsigned int desc_size;
dma_addr_t dma_addr;
+ int i;
+ desc_size = extend_desc ? sizeof(*ep) : sizeof(*p);
for (i = 0; i < size; i++) {
- if (extend_desc) {
- dma_addr = dma_phy_addr + i * sizeof(*ep);
- seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
- i, &dma_addr,
- le32_to_cpu(ep->basic.des0),
- le32_to_cpu(ep->basic.des1),
- le32_to_cpu(ep->basic.des2),
- le32_to_cpu(ep->basic.des3));
- ep++;
- } else {
- dma_addr = dma_phy_addr + i * sizeof(*p);
- seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
- i, &dma_addr,
- le32_to_cpu(p->des0), le32_to_cpu(p->des1),
- le32_to_cpu(p->des2), le32_to_cpu(p->des3));
+ dma_addr = dma_phy_addr + i * desc_size;
+ seq_printf(seq, "%d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
+ i, &dma_addr,
+ le32_to_cpu(p->des0), le32_to_cpu(p->des1),
+ le32_to_cpu(p->des2), le32_to_cpu(p->des3));
+ if (extend_desc)
+ p = &(++ep)->basic;
+ else
p++;
- }
- seq_printf(seq, "\n");
}
}
@@ -6960,10 +7037,13 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64
u64 tx_bytes;
do {
- start = u64_stats_fetch_begin(&txq_stats->syncp);
- tx_packets = txq_stats->tx_packets;
- tx_bytes = txq_stats->tx_bytes;
- } while (u64_stats_fetch_retry(&txq_stats->syncp, start));
+ start = u64_stats_fetch_begin(&txq_stats->q_syncp);
+ tx_bytes = u64_stats_read(&txq_stats->q.tx_bytes);
+ } while (u64_stats_fetch_retry(&txq_stats->q_syncp, start));
+ do {
+ start = u64_stats_fetch_begin(&txq_stats->napi_syncp);
+ tx_packets = u64_stats_read(&txq_stats->napi.tx_packets);
+ } while (u64_stats_fetch_retry(&txq_stats->napi_syncp, start));
stats->tx_packets += tx_packets;
stats->tx_bytes += tx_bytes;
@@ -6975,10 +7055,10 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64
u64 rx_bytes;
do {
- start = u64_stats_fetch_begin(&rxq_stats->syncp);
- rx_packets = rxq_stats->rx_packets;
- rx_bytes = rxq_stats->rx_bytes;
- } while (u64_stats_fetch_retry(&rxq_stats->syncp, start));
+ start = u64_stats_fetch_begin(&rxq_stats->napi_syncp);
+ rx_packets = u64_stats_read(&rxq_stats->napi.rx_packets);
+ rx_bytes = u64_stats_read(&rxq_stats->napi.rx_bytes);
+ } while (u64_stats_fetch_retry(&rxq_stats->napi_syncp, start));
stats->rx_packets += rx_packets;
stats->rx_bytes += rx_bytes;
@@ -7372,9 +7452,16 @@ int stmmac_dvr_probe(struct device *device,
priv->dev = ndev;
for (i = 0; i < MTL_MAX_RX_QUEUES; i++)
- u64_stats_init(&priv->xstats.rxq_stats[i].syncp);
- for (i = 0; i < MTL_MAX_TX_QUEUES; i++)
- u64_stats_init(&priv->xstats.txq_stats[i].syncp);
+ u64_stats_init(&priv->xstats.rxq_stats[i].napi_syncp);
+ for (i = 0; i < MTL_MAX_TX_QUEUES; i++) {
+ u64_stats_init(&priv->xstats.txq_stats[i].q_syncp);
+ u64_stats_init(&priv->xstats.txq_stats[i].napi_syncp);
+ }
+
+ priv->xstats.pcpu_stats =
+ devm_netdev_alloc_pcpu_stats(device, struct stmmac_pcpu_stats);
+ if (!priv->xstats.pcpu_stats)
+ return -ENOMEM;
stmmac_set_ethtool_ops(ndev);
priv->pause = pause;
@@ -7440,6 +7527,9 @@ int stmmac_dvr_probe(struct device *device,
dev_err(priv->device, "unable to bring out of ahb reset: %pe\n",
ERR_PTR(ret));
+ /* Wait a bit for the reset to take effect */
+ udelay(10);
+
/* Init MAC and get the capabilities */
ret = stmmac_hw_init(priv);
if (ret)
@@ -7455,6 +7545,7 @@ int stmmac_dvr_probe(struct device *device,
ndev->netdev_ops = &stmmac_netdev_ops;
ndev->xdp_metadata_ops = &stmmac_xdp_metadata_ops;
+ ndev->xsk_tx_metadata_ops = &stmmac_xsk_tx_metadata_ops;
ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXCSUM;
@@ -7521,6 +7612,9 @@ int stmmac_dvr_probe(struct device *device,
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
+ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
+ priv->hw->hw_vlan_en = true;
+
if (priv->dma_cap.vlhash) {
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 1ffde555da47..70eadc83ca68 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -296,62 +296,80 @@ out:
}
/**
- * stmmac_dt_phy - parse device-tree driver parameters to allocate PHY resources
- * @plat: driver data platform structure
- * @np: device tree node
- * @dev: device pointer
- * Description:
- * The mdio bus will be allocated in case of a phy transceiver is on board;
- * it will be NULL if the fixed-link is configured.
- * If there is the "snps,dwmac-mdio" sub-node the mdio will be allocated
- * in any case (for DSA, mdio must be registered even if fixed-link).
- * The table below sums the supported configurations:
- * -------------------------------
- * snps,phy-addr | Y
- * -------------------------------
- * phy-handle | Y
- * -------------------------------
- * fixed-link | N
- * -------------------------------
- * snps,dwmac-mdio |
- * even if | Y
- * fixed-link |
- * -------------------------------
+ * stmmac_of_get_mdio() - Gets the MDIO bus from the devicetree.
+ * @np: devicetree node
*
- * It returns 0 in case of success otherwise -ENODEV.
+ * The MDIO bus will be searched for in the following ways:
+ * 1. The compatible is "snps,dwc-qos-ethernet-4.10" && a "mdio" named
+ * child node exists
+ * 2. A child node with the "snps,dwmac-mdio" compatible is present
+ *
+ * Return: The MDIO node if present otherwise NULL
*/
-static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
- struct device_node *np, struct device *dev)
+static struct device_node *stmmac_of_get_mdio(struct device_node *np)
{
- bool mdio = !of_phy_is_fixed_link(np);
static const struct of_device_id need_mdio_ids[] = {
{ .compatible = "snps,dwc-qos-ethernet-4.10" },
{},
};
+ struct device_node *mdio_node = NULL;
if (of_match_node(need_mdio_ids, np)) {
- plat->mdio_node = of_get_child_by_name(np, "mdio");
+ mdio_node = of_get_child_by_name(np, "mdio");
} else {
/**
* If snps,dwmac-mdio is passed from DT, always register
* the MDIO
*/
- for_each_child_of_node(np, plat->mdio_node) {
- if (of_device_is_compatible(plat->mdio_node,
+ for_each_child_of_node(np, mdio_node) {
+ if (of_device_is_compatible(mdio_node,
"snps,dwmac-mdio"))
break;
}
}
- if (plat->mdio_node) {
+ return mdio_node;
+}
+
+/**
+ * stmmac_mdio_setup() - Populate platform related MDIO structures.
+ * @plat: driver data platform structure
+ * @np: devicetree node
+ * @dev: device pointer
+ *
+ * This searches for MDIO information from the devicetree.
+ * If an MDIO node is found, it's assigned to plat->mdio_node and
+ * plat->mdio_bus_data is allocated.
+ * If no connection can be determined, just plat->mdio_bus_data is allocated
+ * to indicate a bus should be created and scanned for a phy.
+ * If it's determined there's no MDIO bus needed, both are left NULL.
+ *
+ * This expects that plat->phy_node has already been searched for.
+ *
+ * Return: 0 on success, errno otherwise.
+ */
+static int stmmac_mdio_setup(struct plat_stmmacenet_data *plat,
+ struct device_node *np, struct device *dev)
+{
+ bool legacy_mdio;
+
+ plat->mdio_node = stmmac_of_get_mdio(np);
+ if (plat->mdio_node)
dev_dbg(dev, "Found MDIO subnode\n");
- mdio = true;
- }
- if (mdio) {
- plat->mdio_bus_data =
- devm_kzalloc(dev, sizeof(struct stmmac_mdio_bus_data),
- GFP_KERNEL);
+ /* Legacy devicetrees allowed for no MDIO bus description and expect
+ * the bus to be scanned for devices. If there's no phy or fixed-link
+ * described assume this is the case since there must be something
+ * connected to the MAC.
+ */
+ legacy_mdio = !of_phy_is_fixed_link(np) && !plat->phy_node;
+ if (legacy_mdio)
+ dev_info(dev, "Deprecated MDIO bus assumption used\n");
+
+ if (plat->mdio_node || legacy_mdio) {
+ plat->mdio_bus_data = devm_kzalloc(dev,
+ sizeof(*plat->mdio_bus_data),
+ GFP_KERNEL);
if (!plat->mdio_bus_data)
return -ENOMEM;
@@ -471,8 +489,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
- /* To Configure PHY by using all device-tree supported properties */
- rc = stmmac_dt_phy(plat, np, &pdev->dev);
+ rc = stmmac_mdio_setup(plat, np, &pdev->dev);
if (rc)
return ERR_PTR(rc);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index bffa5c017032..e04830a3a1fb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -72,7 +72,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
est_rst = true;
mutex_lock(&priv->plat->est->lock);
priv->plat->est->enable = false;
- stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ stmmac_est_configure(priv, priv, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->est->lock);
}
@@ -102,7 +102,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
priv->plat->est->btr[0] = (u32)time.tv_nsec;
priv->plat->est->btr[1] = (u32)time.tv_sec;
priv->plat->est->enable = true;
- ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ ret = stmmac_est_configure(priv, priv, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->est->lock);
if (ret)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 6ad3e0a11936..26fa33e5ec34 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
@@ -975,6 +975,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
return -EINVAL;
if (!qopt->cycle_time)
return -ERANGE;
+ if (qopt->cycle_time_extension >= BIT(wid + 7))
+ return -ERANGE;
if (!plat->est) {
plat->est = devm_kzalloc(priv->device, sizeof(*plat->est),
@@ -1041,6 +1043,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC);
priv->plat->est->ctr[1] = (u32)ctr;
+ priv->plat->est->ter = qopt->cycle_time_extension;
+
if (fpe && !priv->dma_cap.fpesel) {
mutex_unlock(&priv->plat->est->lock);
return -EOPNOTSUPP;
@@ -1051,7 +1055,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
*/
priv->plat->fpe_cfg->enable = fpe;
- ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ ret = stmmac_est_configure(priv, priv, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->est->lock);
if (ret) {
@@ -1072,7 +1076,7 @@ disable:
if (priv->plat->est) {
mutex_lock(&priv->plat->est->lock);
priv->plat->est->enable = false;
- stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
+ stmmac_est_configure(priv, priv, priv->plat->est,
priv->plat->clk_ptp_rate);
mutex_unlock(&priv->plat->est->lock);
}
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index e60b557d59b9..1530d13984d4 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -134,14 +134,16 @@ config TI_K3_AM65_CPTS
protocol, Ethernet Enhanced Scheduled Traffic Operations (CPTS_ESTFn)
and PCIe Subsystem Precision Time Measurement (PTM).
-config TI_AM65_CPSW_TAS
- bool "Enable TAS offload in AM65 CPSW"
+config TI_AM65_CPSW_QOS
+ bool "Enable QoS offload features in AM65 CPSW"
depends on TI_K3_AM65_CPSW_NUSS && NET_SCH_TAPRIO && TI_K3_AM65_CPTS
help
- Say y here to support Time Aware Shaper(TAS) offload in AM65 CPSW.
- AM65 CPSW hardware supports Enhanced Scheduled Traffic (EST)
- defined in IEEE 802.1Q 2018. The EST scheduler runs on CPTS and the
- TAS/EST schedule is updated in the Fetch RAM memory of the CPSW.
+ This option enables QoS offload features in AM65 CPSW like
+ Time Aware Shaper (TAS) / Enhanced Scheduled Traffic (EST),
+ MQPRIO qdisc offload and Frame-Preemption MAC Merge / Interspersing
+ Express Traffic (IET).
+ The EST scheduler runs on CPTS and the TAS/EST schedule is
+ updated in the Fetch RAM memory of the CPSW.
config TI_KEYSTONE_NETCP
tristate "TI Keystone NETCP Core Support"
@@ -187,6 +189,7 @@ config TI_ICSSG_PRUETH
select TI_K3_CPPI_DESC_POOL
depends on PRU_REMOTEPROC
depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER
+ depends on PTP_1588_CLOCK_OPTIONAL
help
Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.
This subsystem is available starting with the AM65 platform.
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 27de1d697134..d8590304f3df 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -26,7 +26,8 @@ keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o cpsw_ale.
obj-$(CONFIG_TI_K3_CPPI_DESC_POOL) += k3-cppi-desc-pool.o
obj-$(CONFIG_TI_K3_AM65_CPSW_NUSS) += ti-am65-cpsw-nuss.o
-ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o am65-cpsw-qos.o
+ti-am65-cpsw-nuss-y := am65-cpsw-nuss.o cpsw_sl.o am65-cpsw-ethtool.o cpsw_ale.o
+ti-am65-cpsw-nuss-$(CONFIG_TI_AM65_CPSW_QOS) += am65-cpsw-qos.o
ti-am65-cpsw-nuss-$(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV) += am65-cpsw-switchdev.o
obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o
diff --git a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
index c51e2af91f69..35fceba01ea4 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c
@@ -11,6 +11,7 @@
#include <linux/pm_runtime.h>
#include "am65-cpsw-nuss.h"
+#include "am65-cpsw-qos.h"
#include "cpsw_ale.h"
#include "am65-cpts.h"
@@ -662,6 +663,34 @@ static void am65_cpsw_get_ethtool_stats(struct net_device *ndev,
hw_stats[i].offset);
}
+static void am65_cpsw_get_eth_mac_stats(struct net_device *ndev,
+ struct ethtool_eth_mac_stats *s)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+ struct am65_cpsw_stats_regs __iomem *stats;
+
+ stats = port->stat_base;
+
+ if (s->src != ETHTOOL_MAC_STATS_SRC_AGGREGATE)
+ return;
+
+ s->FramesTransmittedOK = readl_relaxed(&stats->tx_good_frames);
+ s->SingleCollisionFrames = readl_relaxed(&stats->tx_single_coll_frames);
+ s->MultipleCollisionFrames = readl_relaxed(&stats->tx_mult_coll_frames);
+ s->FramesReceivedOK = readl_relaxed(&stats->rx_good_frames);
+ s->FrameCheckSequenceErrors = readl_relaxed(&stats->rx_crc_errors);
+ s->AlignmentErrors = readl_relaxed(&stats->rx_align_code_errors);
+ s->OctetsTransmittedOK = readl_relaxed(&stats->tx_octets);
+ s->FramesWithDeferredXmissions = readl_relaxed(&stats->tx_deferred_frames);
+ s->LateCollisions = readl_relaxed(&stats->tx_late_collisions);
+ s->CarrierSenseErrors = readl_relaxed(&stats->tx_carrier_sense_errors);
+ s->OctetsReceivedOK = readl_relaxed(&stats->rx_octets);
+ s->MulticastFramesXmittedOK = readl_relaxed(&stats->tx_multicast_frames);
+ s->BroadcastFramesXmittedOK = readl_relaxed(&stats->tx_broadcast_frames);
+ s->MulticastFramesReceivedOK = readl_relaxed(&stats->rx_multicast_frames);
+ s->BroadcastFramesReceivedOK = readl_relaxed(&stats->rx_broadcast_frames);
+};
+
static int am65_cpsw_get_ethtool_ts_info(struct net_device *ndev,
struct ethtool_ts_info *info)
{
@@ -715,6 +744,240 @@ static int am65_cpsw_set_ethtool_priv_flags(struct net_device *ndev, u32 flags)
return 0;
}
+static void am65_cpsw_port_iet_rx_enable(struct am65_cpsw_port *port, bool enable)
+{
+ u32 val;
+
+ val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
+ if (enable)
+ val |= AM65_CPSW_PN_CTL_IET_PORT_EN;
+ else
+ val &= ~AM65_CPSW_PN_CTL_IET_PORT_EN;
+
+ writel(val, port->port_base + AM65_CPSW_PN_REG_CTL);
+ am65_cpsw_iet_common_enable(port->common);
+}
+
+static void am65_cpsw_port_iet_tx_enable(struct am65_cpsw_port *port, bool enable)
+{
+ u32 val;
+
+ val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ if (enable)
+ val |= AM65_CPSW_PN_IET_MAC_PENABLE;
+ else
+ val &= ~AM65_CPSW_PN_IET_MAC_PENABLE;
+
+ writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+}
+
+static int am65_cpsw_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+ struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
+ u32 port_ctrl, iet_ctrl, iet_status;
+ u32 add_frag_size;
+
+ if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
+ return -EOPNOTSUPP;
+
+ mutex_lock(&priv->mm_lock);
+
+ iet_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ port_ctrl = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
+
+ state->tx_enabled = !!(iet_ctrl & AM65_CPSW_PN_IET_MAC_PENABLE);
+ state->pmac_enabled = !!(port_ctrl & AM65_CPSW_PN_CTL_IET_PORT_EN);
+
+ iet_status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
+
+ if (iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+ else if (iet_status & AM65_CPSW_PN_MAC_VERIFIED)
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
+ else if (iet_status & AM65_CPSW_PN_MAC_VERIFY_FAIL)
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
+ else
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;
+
+ add_frag_size = AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(iet_ctrl);
+ state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(add_frag_size);
+
+ /* Errata i2208: RX min fragment size cannot be less than 124 */
+ state->rx_min_frag_size = 124;
+
+ /* FPE active if common tx_enabled and verification success or disabled (forced) */
+ state->tx_active = state->tx_enabled &&
+ (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED ||
+ state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED);
+ state->verify_enabled = !(iet_ctrl & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY);
+
+ state->verify_time = port->qos.iet.verify_time_ms;
+
+ /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
+ * variable has a range between 1 and 128 ms inclusive. Limit to that.
+ */
+ state->max_verify_time = 128;
+
+ mutex_unlock(&priv->mm_lock);
+
+ return 0;
+}
+
+static int am65_cpsw_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+ struct am65_cpsw_ndev_priv *priv = netdev_priv(ndev);
+ struct am65_cpsw_iet *iet = &port->qos.iet;
+ u32 val, add_frag_size;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS))
+ return -EOPNOTSUPP;
+
+ err = ethtool_mm_frag_size_min_to_add(cfg->tx_min_frag_size, &add_frag_size, extack);
+ if (err)
+ return err;
+
+ mutex_lock(&priv->mm_lock);
+
+ if (cfg->pmac_enabled) {
+ /* change TX & RX FIFO MAX_BLKS as per TRM recommendation */
+ if (!iet->original_max_blks)
+ iet->original_max_blks = readl(port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
+
+ writel(AM65_CPSW_PN_TX_RX_MAX_BLKS_IET,
+ port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
+ } else if (iet->original_max_blks) {
+ /* restore RX & TX FIFO MAX_BLKS */
+ writel(iet->original_max_blks,
+ port->port_base + AM65_CPSW_PN_REG_MAX_BLKS);
+ }
+
+ am65_cpsw_port_iet_rx_enable(port, cfg->pmac_enabled);
+ am65_cpsw_port_iet_tx_enable(port, cfg->tx_enabled);
+
+ val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ if (cfg->verify_enabled) {
+ val &= ~AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
+ /* Reset Verify state machine. Verification won't start here.
+ * Verification will be done once link-up.
+ */
+ val |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
+ } else {
+ val |= AM65_CPSW_PN_IET_MAC_DISABLEVERIFY;
+ /* Clear LINKFAIL to allow verify/response packets */
+ val &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
+ }
+
+ val &= ~AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK;
+ val |= AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(add_frag_size);
+ writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+
+ /* verify_timeout_count can only be set at valid link */
+ port->qos.iet.verify_time_ms = cfg->verify_time;
+
+ /* enable/disable preemption based on link status */
+ am65_cpsw_iet_commit_preemptible_tcs(port);
+
+ mutex_unlock(&priv->mm_lock);
+
+ return 0;
+}
+
+static void am65_cpsw_get_mm_stats(struct net_device *ndev,
+ struct ethtool_mm_stats *s)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+ void __iomem *base = port->stat_base;
+
+ s->MACMergeFrameAssOkCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK);
+ s->MACMergeFrameAssErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR);
+ s->MACMergeFrameSmdErrorCount = readl(base + AM65_CPSW_STATN_IET_RX_SMD_ERROR);
+ /* CPSW Functional Spec states:
+ * "The IET stat aMACMergeFragCountRx is derived by adding the
+ * Receive Assembly Error count to this value. i.e. AM65_CPSW_STATN_IET_RX_FRAG"
+ */
+ s->MACMergeFragCountRx = readl(base + AM65_CPSW_STATN_IET_RX_FRAG) + s->MACMergeFrameAssErrorCount;
+ s->MACMergeFragCountTx = readl(base + AM65_CPSW_STATN_IET_TX_FRAG);
+ s->MACMergeHoldCount = readl(base + AM65_CPSW_STATN_IET_TX_HOLD);
+}
+
+static int am65_cpsw_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
+ struct am65_cpsw_tx_chn *tx_chn;
+
+ tx_chn = &common->tx_chns[0];
+
+ coal->rx_coalesce_usecs = common->rx_pace_timeout / 1000;
+ coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
+
+ return 0;
+}
+
+static int am65_cpsw_get_per_queue_coalesce(struct net_device *ndev, u32 queue,
+ struct ethtool_coalesce *coal)
+{
+ struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
+ struct am65_cpsw_tx_chn *tx_chn;
+
+ if (queue >= AM65_CPSW_MAX_TX_QUEUES)
+ return -EINVAL;
+
+ tx_chn = &common->tx_chns[queue];
+
+ coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout / 1000;
+
+ return 0;
+}
+
+static int am65_cpsw_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
+ struct am65_cpsw_tx_chn *tx_chn;
+
+ tx_chn = &common->tx_chns[0];
+
+ if (coal->rx_coalesce_usecs && coal->rx_coalesce_usecs < 20)
+ return -EINVAL;
+
+ if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20)
+ return -EINVAL;
+
+ common->rx_pace_timeout = coal->rx_coalesce_usecs * 1000;
+ tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
+
+ return 0;
+}
+
+static int am65_cpsw_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
+ struct ethtool_coalesce *coal)
+{
+ struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
+ struct am65_cpsw_tx_chn *tx_chn;
+
+ if (queue >= AM65_CPSW_MAX_TX_QUEUES)
+ return -EINVAL;
+
+ tx_chn = &common->tx_chns[queue];
+
+ if (coal->tx_coalesce_usecs && coal->tx_coalesce_usecs < 20) {
+ dev_info(common->dev, "defaulting to min value of 20us for tx-usecs for tx-%u\n",
+ queue);
+ coal->tx_coalesce_usecs = 20;
+ }
+
+ tx_chn->tx_pace_timeout = coal->tx_coalesce_usecs * 1000;
+
+ return 0;
+}
+
const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
.begin = am65_cpsw_ethtool_op_begin,
.complete = am65_cpsw_ethtool_op_complete,
@@ -729,9 +992,15 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
.get_sset_count = am65_cpsw_get_sset_count,
.get_strings = am65_cpsw_get_strings,
.get_ethtool_stats = am65_cpsw_get_ethtool_stats,
+ .get_eth_mac_stats = am65_cpsw_get_eth_mac_stats,
.get_ts_info = am65_cpsw_get_ethtool_ts_info,
.get_priv_flags = am65_cpsw_get_ethtool_priv_flags,
.set_priv_flags = am65_cpsw_set_ethtool_priv_flags,
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS,
+ .get_coalesce = am65_cpsw_get_coalesce,
+ .set_coalesce = am65_cpsw_set_coalesce,
+ .get_per_queue_coalesce = am65_cpsw_get_per_queue_coalesce,
+ .set_per_queue_coalesce = am65_cpsw_set_per_queue_coalesce,
.get_link = ethtool_op_get_link,
.get_link_ksettings = am65_cpsw_get_link_ksettings,
@@ -743,4 +1012,7 @@ const struct ethtool_ops am65_cpsw_ethtool_ops_slave = {
.get_eee = am65_cpsw_get_eee,
.set_eee = am65_cpsw_set_eee,
.nway_reset = am65_cpsw_nway_reset,
+ .get_mm = am65_cpsw_get_mm,
+ .set_mm = am65_cpsw_set_mm,
+ .get_mm_stats = am65_cpsw_get_mm_stats,
};
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index ece9f8df98ae..2939a21ca74f 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -56,7 +56,7 @@
#define AM65_CPSW_MAX_PORTS 8
#define AM65_CPSW_MIN_PACKET_SIZE VLAN_ETH_ZLEN
-#define AM65_CPSW_MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
+#define AM65_CPSW_MAX_PACKET_SIZE 2024
#define AM65_CPSW_REG_CTL 0x004
#define AM65_CPSW_REG_STAT_PORT_EN 0x014
@@ -136,6 +136,8 @@
NETIF_MSG_IFUP | NETIF_MSG_PROBE | NETIF_MSG_IFDOWN | \
NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+#define AM65_CPSW_DEFAULT_TX_CHNS 8
+
static void am65_cpsw_port_set_sl_mac(struct am65_cpsw_port *slave,
const u8 *dev_addr)
{
@@ -292,7 +294,7 @@ static void am65_cpsw_nuss_ndo_host_tx_timeout(struct net_device *ndev,
txqueue,
netif_tx_queue_stopped(netif_txq),
jiffies_to_msecs(jiffies - trans_start),
- dql_avail(&netif_txq->dql),
+ netdev_queue_dql_avail(netif_txq),
k3_cppi_desc_pool_avail(tx_chn->desc_pool));
if (netif_tx_queue_stopped(netif_txq)) {
@@ -367,10 +369,81 @@ static void am65_cpsw_init_host_port_emac(struct am65_cpsw_common *common);
static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port);
static void am65_cpsw_init_port_emac_ale(struct am65_cpsw_port *port);
+static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
+{
+ struct am65_cpsw_rx_chn *rx_chn = data;
+ struct cppi5_host_desc_t *desc_rx;
+ struct sk_buff *skb;
+ dma_addr_t buf_dma;
+ u32 buf_dma_len;
+ void **swdata;
+
+ desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
+ swdata = cppi5_hdesc_get_swdata(desc_rx);
+ skb = *swdata;
+ cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
+ k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
+
+ dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);
+ k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
+
+ dev_kfree_skb_any(skb);
+}
+
+static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn,
+ struct cppi5_host_desc_t *desc)
+{
+ struct cppi5_host_desc_t *first_desc, *next_desc;
+ dma_addr_t buf_dma, next_desc_dma;
+ u32 buf_dma_len;
+
+ first_desc = desc;
+ next_desc = first_desc;
+
+ cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
+
+ dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, DMA_TO_DEVICE);
+
+ next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
+ while (next_desc_dma) {
+ next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
+ next_desc_dma);
+ cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
+
+ dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len,
+ DMA_TO_DEVICE);
+
+ next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc);
+ k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
+
+ k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
+ }
+
+ k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
+}
+
+static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma)
+{
+ struct am65_cpsw_tx_chn *tx_chn = data;
+ struct cppi5_host_desc_t *desc_tx;
+ struct sk_buff *skb;
+ void **swdata;
+
+ desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma);
+ swdata = cppi5_hdesc_get_swdata(desc_tx);
+ skb = *(swdata);
+ am65_cpsw_nuss_xmit_free(tx_chn, desc_tx);
+
+ dev_kfree_skb_any(skb);
+}
+
static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
{
struct am65_cpsw_host *host_p = am65_common_get_host(common);
- int port_idx, i, ret;
+ int port_idx, i, ret, tx;
struct sk_buff *skb;
u32 val, port_mask;
@@ -437,8 +510,12 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
AM65_CPSW_MAX_PACKET_SIZE,
GFP_KERNEL);
if (!skb) {
+ ret = -ENOMEM;
dev_err(common->dev, "cannot allocate skb\n");
- return -ENOMEM;
+ if (i)
+ goto fail_rx;
+
+ return ret;
}
ret = am65_cpsw_nuss_rx_push(common, skb);
@@ -447,17 +524,28 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
"cannot submit skb to channel rx, error %d\n",
ret);
kfree_skb(skb);
+ if (i)
+ goto fail_rx;
+
return ret;
}
- kmemleak_not_leak(skb);
}
- k3_udma_glue_enable_rx_chn(common->rx_chns.rx_chn);
- for (i = 0; i < common->tx_ch_num; i++) {
- ret = k3_udma_glue_enable_tx_chn(common->tx_chns[i].tx_chn);
- if (ret)
- return ret;
- napi_enable(&common->tx_chns[i].napi_tx);
+ ret = k3_udma_glue_enable_rx_chn(common->rx_chns.rx_chn);
+ if (ret) {
+ dev_err(common->dev, "couldn't enable rx chn: %d\n", ret);
+ goto fail_rx;
+ }
+
+ for (tx = 0; tx < common->tx_ch_num; tx++) {
+ ret = k3_udma_glue_enable_tx_chn(common->tx_chns[tx].tx_chn);
+ if (ret) {
+ dev_err(common->dev, "couldn't enable tx chn %d: %d\n",
+ tx, ret);
+ tx--;
+ goto fail_tx;
+ }
+ napi_enable(&common->tx_chns[tx].napi_tx);
}
napi_enable(&common->napi_rx);
@@ -468,10 +556,22 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common)
dev_dbg(common->dev, "cpsw_nuss started\n");
return 0;
-}
-static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma);
-static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma);
+fail_tx:
+ while (tx >= 0) {
+ napi_disable(&common->tx_chns[tx].napi_tx);
+ k3_udma_glue_disable_tx_chn(common->tx_chns[tx].tx_chn);
+ tx--;
+ }
+
+ k3_udma_glue_disable_rx_chn(common->rx_chns.rx_chn);
+
+fail_rx:
+ k3_udma_glue_reset_rx_chn(common->rx_chns.rx_chn, 0,
+ &common->rx_chns,
+ am65_cpsw_nuss_rx_cleanup, 0);
+ return ret;
+}
static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
{
@@ -496,8 +596,10 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
msecs_to_jiffies(1000));
if (!i)
dev_err(common->dev, "tx timeout\n");
- for (i = 0; i < common->tx_ch_num; i++)
+ for (i = 0; i < common->tx_ch_num; i++) {
napi_disable(&common->tx_chns[i].napi_tx);
+ hrtimer_cancel(&common->tx_chns[i].tx_hrtimer);
+ }
for (i = 0; i < common->tx_ch_num; i++) {
k3_udma_glue_reset_tx_chn(common->tx_chns[i].tx_chn,
@@ -516,6 +618,7 @@ static int am65_cpsw_nuss_common_stop(struct am65_cpsw_common *common)
}
napi_disable(&common->napi_rx);
+ hrtimer_cancel(&common->rx_hrtimer);
for (i = 0; i < AM65_CPSW_MAX_RX_FLOWS; i++)
k3_udma_glue_reset_rx_chn(common->rx_chns.rx_chn, i,
@@ -646,27 +749,6 @@ runtime_put:
return ret;
}
-static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
-{
- struct am65_cpsw_rx_chn *rx_chn = data;
- struct cppi5_host_desc_t *desc_rx;
- struct sk_buff *skb;
- dma_addr_t buf_dma;
- u32 buf_dma_len;
- void **swdata;
-
- desc_rx = k3_cppi_desc_pool_dma2virt(rx_chn->desc_pool, desc_dma);
- swdata = cppi5_hdesc_get_swdata(desc_rx);
- skb = *swdata;
- cppi5_hdesc_get_obuf(desc_rx, &buf_dma, &buf_dma_len);
- k3_udma_glue_rx_cppi5_to_dma_addr(rx_chn->rx_chn, &buf_dma);
-
- dma_unmap_single(rx_chn->dma_dev, buf_dma, buf_dma_len, DMA_FROM_DEVICE);
- k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx);
-
- dev_kfree_skb_any(skb);
-}
-
static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata)
{
struct skb_shared_hwtstamps *ssh;
@@ -806,6 +888,15 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common,
return ret;
}
+static enum hrtimer_restart am65_cpsw_nuss_rx_timer_callback(struct hrtimer *timer)
+{
+ struct am65_cpsw_common *common =
+ container_of(timer, struct am65_cpsw_common, rx_hrtimer);
+
+ enable_irq(common->rx_chns.irq);
+ return HRTIMER_NORESTART;
+}
+
static int am65_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget)
{
struct am65_cpsw_common *common = am65_cpsw_napi_to_common(napi_rx);
@@ -833,63 +924,19 @@ static int am65_cpsw_nuss_rx_poll(struct napi_struct *napi_rx, int budget)
if (num_rx < budget && napi_complete_done(napi_rx, num_rx)) {
if (common->rx_irq_disabled) {
common->rx_irq_disabled = false;
- enable_irq(common->rx_chns.irq);
+ if (unlikely(common->rx_pace_timeout)) {
+ hrtimer_start(&common->rx_hrtimer,
+ ns_to_ktime(common->rx_pace_timeout),
+ HRTIMER_MODE_REL_PINNED);
+ } else {
+ enable_irq(common->rx_chns.irq);
+ }
}
}
return num_rx;
}
-static void am65_cpsw_nuss_xmit_free(struct am65_cpsw_tx_chn *tx_chn,
- struct cppi5_host_desc_t *desc)
-{
- struct cppi5_host_desc_t *first_desc, *next_desc;
- dma_addr_t buf_dma, next_desc_dma;
- u32 buf_dma_len;
-
- first_desc = desc;
- next_desc = first_desc;
-
- cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
- k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
-
- dma_unmap_single(tx_chn->dma_dev, buf_dma, buf_dma_len, DMA_TO_DEVICE);
-
- next_desc_dma = cppi5_hdesc_get_next_hbdesc(first_desc);
- k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
- while (next_desc_dma) {
- next_desc = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool,
- next_desc_dma);
- cppi5_hdesc_get_obuf(next_desc, &buf_dma, &buf_dma_len);
- k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
-
- dma_unmap_page(tx_chn->dma_dev, buf_dma, buf_dma_len,
- DMA_TO_DEVICE);
-
- next_desc_dma = cppi5_hdesc_get_next_hbdesc(next_desc);
- k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &next_desc_dma);
-
- k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
- }
-
- k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
-}
-
-static void am65_cpsw_nuss_tx_cleanup(void *data, dma_addr_t desc_dma)
-{
- struct am65_cpsw_tx_chn *tx_chn = data;
- struct cppi5_host_desc_t *desc_tx;
- struct sk_buff *skb;
- void **swdata;
-
- desc_tx = k3_cppi_desc_pool_dma2virt(tx_chn->desc_pool, desc_dma);
- swdata = cppi5_hdesc_get_swdata(desc_tx);
- skb = *(swdata);
- am65_cpsw_nuss_xmit_free(tx_chn, desc_tx);
-
- dev_kfree_skb_any(skb);
-}
-
static struct sk_buff *
am65_cpsw_nuss_tx_compl_packet(struct am65_cpsw_tx_chn *tx_chn,
dma_addr_t desc_dma)
@@ -939,7 +986,7 @@ static void am65_cpsw_nuss_tx_wake(struct am65_cpsw_tx_chn *tx_chn, struct net_d
}
static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
- int chn, unsigned int budget)
+ int chn, unsigned int budget, bool *tdown)
{
struct device *dev = common->dev;
struct am65_cpsw_tx_chn *tx_chn;
@@ -962,6 +1009,7 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
if (cppi5_desc_is_tdcm(desc_dma)) {
if (atomic_dec_and_test(&common->tdown_cnt))
complete(&common->tdown_complete);
+ *tdown = true;
break;
}
@@ -984,7 +1032,7 @@ static int am65_cpsw_nuss_tx_compl_packets(struct am65_cpsw_common *common,
}
static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
- int chn, unsigned int budget)
+ int chn, unsigned int budget, bool *tdown)
{
struct device *dev = common->dev;
struct am65_cpsw_tx_chn *tx_chn;
@@ -1005,6 +1053,7 @@ static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
if (cppi5_desc_is_tdcm(desc_dma)) {
if (atomic_dec_and_test(&common->tdown_cnt))
complete(&common->tdown_complete);
+ *tdown = true;
break;
}
@@ -1030,21 +1079,40 @@ static int am65_cpsw_nuss_tx_compl_packets_2g(struct am65_cpsw_common *common,
return num_tx;
}
+static enum hrtimer_restart am65_cpsw_nuss_tx_timer_callback(struct hrtimer *timer)
+{
+ struct am65_cpsw_tx_chn *tx_chns =
+ container_of(timer, struct am65_cpsw_tx_chn, tx_hrtimer);
+
+ enable_irq(tx_chns->irq);
+ return HRTIMER_NORESTART;
+}
+
static int am65_cpsw_nuss_tx_poll(struct napi_struct *napi_tx, int budget)
{
struct am65_cpsw_tx_chn *tx_chn = am65_cpsw_napi_to_tx_chn(napi_tx);
+ bool tdown = false;
int num_tx;
if (AM65_CPSW_IS_CPSW2G(tx_chn->common))
- num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id, budget);
+ num_tx = am65_cpsw_nuss_tx_compl_packets_2g(tx_chn->common, tx_chn->id,
+ budget, &tdown);
else
- num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common, tx_chn->id, budget);
+ num_tx = am65_cpsw_nuss_tx_compl_packets(tx_chn->common,
+ tx_chn->id, budget, &tdown);
if (num_tx >= budget)
return budget;
- if (napi_complete_done(napi_tx, num_tx))
- enable_irq(tx_chn->irq);
+ if (napi_complete_done(napi_tx, num_tx)) {
+ if (unlikely(tx_chn->tx_pace_timeout && !tdown)) {
+ hrtimer_start(&tx_chn->tx_hrtimer,
+ ns_to_ktime(tx_chn->tx_pace_timeout),
+ HRTIMER_MODE_REL_PINNED);
+ } else {
+ enable_irq(tx_chn->irq);
+ }
+ }
return 0;
}
@@ -1676,6 +1744,8 @@ static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
netif_napi_add_tx(common->dma_ndev, &tx_chn->napi_tx,
am65_cpsw_nuss_tx_poll);
+ hrtimer_init(&tx_chn->tx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+ tx_chn->tx_hrtimer.function = &am65_cpsw_nuss_tx_timer_callback;
ret = devm_request_irq(dev, tx_chn->irq,
am65_cpsw_nuss_tx_irq,
@@ -1901,6 +1971,8 @@ static int am65_cpsw_nuss_init_rx_chns(struct am65_cpsw_common *common)
netif_napi_add(common->dma_ndev, &common->napi_rx,
am65_cpsw_nuss_rx_poll);
+ hrtimer_init(&common->rx_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
+ common->rx_hrtimer.function = &am65_cpsw_nuss_rx_timer_callback;
ret = devm_request_irq(dev, rx_chn->irq,
am65_cpsw_nuss_rx_irq,
@@ -2098,6 +2170,9 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
dev_err(dev, "Use random MAC address\n");
}
}
+
+ /* Reset all Queue priorities to 0 */
+ writel(0, port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP);
}
of_node_put(node);
@@ -2162,12 +2237,15 @@ am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
ndev_priv = netdev_priv(port->ndev);
ndev_priv->port = port;
ndev_priv->msg_enable = AM65_CPSW_DEBUG;
+ mutex_init(&ndev_priv->mm_lock);
+ port->qos.link_speed = SPEED_UNKNOWN;
SET_NETDEV_DEV(port->ndev, dev);
eth_hw_addr_set(port->ndev, port->slave.mac_addr);
port->ndev->min_mtu = AM65_CPSW_MIN_PACKET_SIZE;
- port->ndev->max_mtu = AM65_CPSW_MAX_PACKET_SIZE;
+ port->ndev->max_mtu = AM65_CPSW_MAX_PACKET_SIZE -
+ (VLAN_ETH_HLEN + ETH_FCS_LEN);
port->ndev->hw_features = NETIF_F_SG |
NETIF_F_RXCSUM |
NETIF_F_HW_CSUM |
@@ -2897,7 +2975,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
common->rx_flow_id_base = -1;
init_completion(&common->tdown_complete);
- common->tx_ch_num = 1;
+ common->tx_ch_num = AM65_CPSW_DEFAULT_TX_CHNS;
common->pf_p0_rx_ptype_rrobin = false;
common->default_vlan = 1;
@@ -2999,7 +3077,7 @@ err_pm_clear:
return ret;
}
-static int am65_cpsw_nuss_remove(struct platform_device *pdev)
+static void am65_cpsw_nuss_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct am65_cpsw_common *common;
@@ -3008,8 +3086,14 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
common = dev_get_drvdata(dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ /* Note, if this error path is taken, we're leaking some
+ * resources.
+ */
+ dev_err(&pdev->dev, "Failed to resume device (%pe)\n",
+ ERR_PTR(ret));
+ return;
+ }
am65_cpsw_unregister_devlink(common);
am65_cpsw_unregister_notifiers(common);
@@ -3027,7 +3111,6 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return 0;
}
static int am65_cpsw_nuss_suspend(struct device *dev)
@@ -3127,7 +3210,7 @@ static struct platform_driver am65_cpsw_nuss_driver = {
.pm = &am65_cpsw_nuss_dev_pm_ops,
},
.probe = am65_cpsw_nuss_probe,
- .remove = am65_cpsw_nuss_remove,
+ .remove_new = am65_cpsw_nuss_remove,
};
module_platform_driver(am65_cpsw_nuss_driver);
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.h b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
index f3dad2ab9828..7da0492dc091 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.h
@@ -75,6 +75,8 @@ struct am65_cpsw_tx_chn {
struct k3_cppi_desc_pool *desc_pool;
struct k3_udma_glue_tx_channel *tx_chn;
spinlock_t lock; /* protect TX rings in multi-port mode */
+ struct hrtimer tx_hrtimer;
+ unsigned long tx_pace_timeout;
int irq;
u32 id;
u32 descs_num;
@@ -138,6 +140,8 @@ struct am65_cpsw_common {
struct napi_struct napi_rx;
bool rx_irq_disabled;
+ struct hrtimer rx_hrtimer;
+ unsigned long rx_pace_timeout;
u32 nuss_ver;
u32 cpsw_ver;
@@ -145,6 +149,7 @@ struct am65_cpsw_common {
bool pf_p0_rx_ptype_rrobin;
struct am65_cpts *cpts;
int est_enabled;
+ bool iet_enabled;
bool is_emac_mode;
u16 br_members;
@@ -170,6 +175,10 @@ struct am65_cpsw_ndev_priv {
struct am65_cpsw_port *port;
struct am65_cpsw_ndev_stats __percpu *stats;
bool offload_fwd_mark;
+ /* Serialize access to MAC Merge state between ethtool requests
+ * and link state updates
+ */
+ struct mutex mm_lock;
};
#define am65_ndev_to_priv(ndev) \
diff --git a/drivers/net/ethernet/ti/am65-cpsw-qos.c b/drivers/net/ethernet/ti/am65-cpsw-qos.c
index 9ac2ff05d501..816e73a3d6e4 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-qos.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-qos.c
@@ -4,10 +4,13 @@
*
* quality of service module includes:
* Enhanced Scheduler Traffic (EST - P802.1Qbv/D2.2)
+ * Interspersed Express Traffic (IET - P802.3br/D2.0)
*/
#include <linux/pm_runtime.h>
+#include <linux/math.h>
#include <linux/time.h>
+#include <linux/units.h>
#include <net/pkt_cls.h>
#include "am65-cpsw-nuss.h"
@@ -15,40 +18,7 @@
#include "am65-cpts.h"
#include "cpsw_ale.h"
-#define AM65_CPSW_REG_CTL 0x004
-#define AM65_CPSW_PN_REG_CTL 0x004
-#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050
-#define AM65_CPSW_PN_REG_EST_CTL 0x060
-#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri))
-
-/* AM65_CPSW_REG_CTL register fields */
-#define AM65_CPSW_CTL_EST_EN BIT(18)
-
-/* AM65_CPSW_PN_REG_CTL register fields */
-#define AM65_CPSW_PN_CTL_EST_PORT_EN BIT(17)
-
-/* AM65_CPSW_PN_REG_EST_CTL register fields */
-#define AM65_CPSW_PN_EST_ONEBUF BIT(0)
-#define AM65_CPSW_PN_EST_BUFSEL BIT(1)
-#define AM65_CPSW_PN_EST_TS_EN BIT(2)
-#define AM65_CPSW_PN_EST_TS_FIRST BIT(3)
-#define AM65_CPSW_PN_EST_ONEPRI BIT(4)
-#define AM65_CPSW_PN_EST_TS_PRI_MSK GENMASK(7, 5)
-
-/* AM65_CPSW_PN_REG_FIFO_STATUS register fields */
-#define AM65_CPSW_PN_FST_TX_PRI_ACTIVE_MSK GENMASK(7, 0)
-#define AM65_CPSW_PN_FST_TX_E_MAC_ALLOW_MSK GENMASK(15, 8)
-#define AM65_CPSW_PN_FST_EST_CNT_ERR BIT(16)
-#define AM65_CPSW_PN_FST_EST_ADD_ERR BIT(17)
-#define AM65_CPSW_PN_FST_EST_BUFACT BIT(18)
-
-/* EST FETCH COMMAND RAM */
-#define AM65_CPSW_FETCH_RAM_CMD_NUM 0x80
-#define AM65_CPSW_FETCH_CNT_MSK GENMASK(21, 8)
-#define AM65_CPSW_FETCH_CNT_MAX (AM65_CPSW_FETCH_CNT_MSK >> 8)
-#define AM65_CPSW_FETCH_CNT_OFFSET 8
-#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0)
-#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK
+#define TO_MBPS(x) DIV_ROUND_UP((x), BYTES_PER_MBIT)
enum timer_act {
TACT_PROG, /* need program timer */
@@ -56,6 +26,412 @@ enum timer_act {
TACT_SKIP_PROG, /* just buffer can be updated */
};
+static void am65_cpsw_iet_change_preemptible_tcs(struct am65_cpsw_port *port, u8 preemptible_tcs);
+
+static u32
+am65_cpsw_qos_tx_rate_calc(u32 rate_mbps, unsigned long bus_freq)
+{
+ u32 ir;
+
+ bus_freq /= 1000000;
+ ir = DIV_ROUND_UP(((u64)rate_mbps * 32768), bus_freq);
+ return ir;
+}
+
+static void am65_cpsw_tx_pn_shaper_reset(struct am65_cpsw_port *port)
+{
+ int prio;
+
+ for (prio = 0; prio < AM65_CPSW_PN_FIFO_PRIO_NUM; prio++) {
+ writel(0, port->port_base + AM65_CPSW_PN_REG_PRI_CIR(prio));
+ writel(0, port->port_base + AM65_CPSW_PN_REG_PRI_EIR(prio));
+ }
+}
+
+static void am65_cpsw_tx_pn_shaper_apply(struct am65_cpsw_port *port)
+{
+ struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
+ struct am65_cpsw_common *common = port->common;
+ struct tc_mqprio_qopt_offload *mqprio;
+ bool enable, shaper_susp = false;
+ u32 rate_mbps;
+ int tc, prio;
+
+ mqprio = &p_mqprio->mqprio_hw;
+ /* takes care of no link case as well */
+ if (p_mqprio->max_rate_total > port->qos.link_speed)
+ shaper_susp = true;
+
+ am65_cpsw_tx_pn_shaper_reset(port);
+
+ enable = p_mqprio->shaper_en && !shaper_susp;
+ if (!enable)
+ return;
+
+ /* Rate limit is specified per Traffic Class but
+ * for CPSW, rate limit can be applied per priority
+ * at port FIFO.
+ *
+ * We have assigned the same priority (TCn) to all queues
+ * of a Traffic Class so they share the same shaper
+ * bandwidth.
+ */
+ for (tc = 0; tc < mqprio->qopt.num_tc; tc++) {
+ prio = tc;
+
+ rate_mbps = TO_MBPS(mqprio->min_rate[tc]);
+ rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps,
+ common->bus_freq);
+ writel(rate_mbps,
+ port->port_base + AM65_CPSW_PN_REG_PRI_CIR(prio));
+
+ rate_mbps = 0;
+
+ if (mqprio->max_rate[tc]) {
+ rate_mbps = mqprio->max_rate[tc] - mqprio->min_rate[tc];
+ rate_mbps = TO_MBPS(rate_mbps);
+ rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps,
+ common->bus_freq);
+ }
+
+ writel(rate_mbps,
+ port->port_base + AM65_CPSW_PN_REG_PRI_EIR(prio));
+ }
+}
+
+static int am65_cpsw_mqprio_verify_shaper(struct am65_cpsw_port *port,
+ struct tc_mqprio_qopt_offload *mqprio)
+{
+ struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
+ struct netlink_ext_ack *extack = mqprio->extack;
+ u64 min_rate_total = 0, max_rate_total = 0;
+ u32 min_rate_msk = 0, max_rate_msk = 0;
+ bool has_min_rate, has_max_rate;
+ int num_tc, i;
+
+ if (!(mqprio->flags & TC_MQPRIO_F_SHAPER))
+ return 0;
+
+ if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE)
+ return 0;
+
+ has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
+ has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);
+
+ if (!has_min_rate && has_max_rate) {
+ NL_SET_ERR_MSG_MOD(extack, "min_rate is required with max_rate");
+ return -EOPNOTSUPP;
+ }
+
+ if (!has_min_rate)
+ return 0;
+
+ num_tc = mqprio->qopt.num_tc;
+
+ for (i = num_tc - 1; i >= 0; i--) {
+ u32 ch_msk;
+
+ if (mqprio->min_rate[i])
+ min_rate_msk |= BIT(i);
+ min_rate_total += mqprio->min_rate[i];
+
+ if (has_max_rate) {
+ if (mqprio->max_rate[i])
+ max_rate_msk |= BIT(i);
+ max_rate_total += mqprio->max_rate[i];
+
+ if (!mqprio->min_rate[i] && mqprio->max_rate[i]) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "TX tc%d rate max>0 but min=0",
+ i);
+ return -EINVAL;
+ }
+
+ if (mqprio->max_rate[i] &&
+ mqprio->max_rate[i] < mqprio->min_rate[i]) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "TX tc%d rate min(%llu)>max(%llu)",
+ i, mqprio->min_rate[i],
+ mqprio->max_rate[i]);
+ return -EINVAL;
+ }
+ }
+
+ ch_msk = GENMASK(num_tc - 1, i);
+ if ((min_rate_msk & BIT(i)) && (min_rate_msk ^ ch_msk)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Min rate must be set sequentially hi->lo tx_rate_msk%x",
+ min_rate_msk);
+ return -EINVAL;
+ }
+
+ if ((max_rate_msk & BIT(i)) && (max_rate_msk ^ ch_msk)) {
+ NL_SET_ERR_MSG_FMT_MOD(extack,
+ "Max rate must be set sequentially hi->lo tx_rate_msk%x",
+ max_rate_msk);
+ return -EINVAL;
+ }
+ }
+
+ min_rate_total = TO_MBPS(min_rate_total);
+ max_rate_total = TO_MBPS(max_rate_total);
+
+ p_mqprio->shaper_en = true;
+ p_mqprio->max_rate_total = max_t(u64, min_rate_total, max_rate_total);
+
+ return 0;
+}
+
+static void am65_cpsw_reset_tc_mqprio(struct net_device *ndev)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+ struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
+
+ p_mqprio->shaper_en = false;
+ p_mqprio->max_rate_total = 0;
+
+ am65_cpsw_tx_pn_shaper_reset(port);
+ netdev_reset_tc(ndev);
+
+ /* Reset all Queue priorities to 0 */
+ writel(0, port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP);
+
+ am65_cpsw_iet_change_preemptible_tcs(port, 0);
+}
+
+static int am65_cpsw_setup_mqprio(struct net_device *ndev, void *type_data)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+ struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
+ struct tc_mqprio_qopt_offload *mqprio = type_data;
+ struct am65_cpsw_common *common = port->common;
+ struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+ int i, tc, offset, count, prio, ret;
+ u8 num_tc = qopt->num_tc;
+ u32 tx_prio_map = 0;
+
+ memcpy(&p_mqprio->mqprio_hw, mqprio, sizeof(*mqprio));
+
+ ret = pm_runtime_get_sync(common->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(common->dev);
+ return ret;
+ }
+
+ if (!num_tc) {
+ am65_cpsw_reset_tc_mqprio(ndev);
+ ret = 0;
+ goto exit_put;
+ }
+
+ ret = am65_cpsw_mqprio_verify_shaper(port, mqprio);
+ if (ret)
+ goto exit_put;
+
+ netdev_set_num_tc(ndev, num_tc);
+
+ /* Multiple Linux priorities can map to a Traffic Class
+ * A Traffic Class can have multiple contiguous Queues,
+ * Queues get mapped to Channels (thread_id),
+ * if not VLAN tagged, thread_id is used as packet_priority
+ * if VLAN tagged. VLAN priority is used as packet_priority
+ * packet_priority gets mapped to header_priority in p0_rx_pri_map,
+ * header_priority gets mapped to switch_priority in pn_tx_pri_map.
+ * As p0_rx_pri_map is left at defaults (0x76543210), we can
+ * assume that Queue_n gets mapped to header_priority_n. We can then
+ * set the switch priority in pn_tx_pri_map.
+ */
+
+ for (tc = 0; tc < num_tc; tc++) {
+ prio = tc;
+
+ /* For simplicity we assign the same priority (TCn) to
+ * all queues of a Traffic Class.
+ */
+ for (i = qopt->offset[tc]; i < qopt->offset[tc] + qopt->count[tc]; i++)
+ tx_prio_map |= prio << (4 * i);
+
+ count = qopt->count[tc];
+ offset = qopt->offset[tc];
+ netdev_set_tc_queue(ndev, tc, count, offset);
+ }
+
+ writel(tx_prio_map, port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP);
+
+ am65_cpsw_tx_pn_shaper_apply(port);
+ am65_cpsw_iet_change_preemptible_tcs(port, mqprio->preemptible_tcs);
+
+exit_put:
+ pm_runtime_put(common->dev);
+
+ return ret;
+}
+
+static int am65_cpsw_iet_set_verify_timeout_count(struct am65_cpsw_port *port)
+{
+ int verify_time_ms = port->qos.iet.verify_time_ms;
+ u32 val;
+
+ /* The number of wireside clocks contained in the verify
+ * timeout counter. The default is 0x1312d0
+ * (10ms at 125Mhz in 1G mode).
+ */
+ val = 125 * HZ_PER_MHZ; /* assuming 125MHz wireside clock */
+
+ val /= MILLIHZ_PER_HZ; /* count per ms timeout */
+ val *= verify_time_ms; /* count for timeout ms */
+
+ if (val > AM65_CPSW_PN_MAC_VERIFY_CNT_MASK)
+ return -EINVAL;
+
+ writel(val, port->port_base + AM65_CPSW_PN_REG_IET_VERIFY);
+
+ return 0;
+}
+
+static int am65_cpsw_iet_verify_wait(struct am65_cpsw_port *port)
+{
+ u32 ctrl, status;
+ int try;
+
+ try = 20;
+ do {
+ /* Reset the verify state machine by writing 1
+ * to LINKFAIL
+ */
+ ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ ctrl |= AM65_CPSW_PN_IET_MAC_LINKFAIL;
+ writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+
+ /* Clear MAC_LINKFAIL bit to start Verify. */
+ ctrl = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ ctrl &= ~AM65_CPSW_PN_IET_MAC_LINKFAIL;
+ writel(ctrl, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+
+ msleep(port->qos.iet.verify_time_ms);
+
+ status = readl(port->port_base + AM65_CPSW_PN_REG_IET_STATUS);
+ if (status & AM65_CPSW_PN_MAC_VERIFIED)
+ return 0;
+
+ if (status & AM65_CPSW_PN_MAC_VERIFY_FAIL) {
+ netdev_dbg(port->ndev,
+ "MAC Merge verify failed, trying again\n");
+ continue;
+ }
+
+ if (status & AM65_CPSW_PN_MAC_RESPOND_ERR) {
+ netdev_dbg(port->ndev, "MAC Merge respond error\n");
+ return -ENODEV;
+ }
+
+ if (status & AM65_CPSW_PN_MAC_VERIFY_ERR) {
+ netdev_dbg(port->ndev, "MAC Merge verify error\n");
+ return -ENODEV;
+ }
+ } while (try-- > 0);
+
+ netdev_dbg(port->ndev, "MAC Merge verify timeout\n");
+ return -ETIMEDOUT;
+}
+
+static void am65_cpsw_iet_set_preempt_mask(struct am65_cpsw_port *port, u8 preemptible_tcs)
+{
+ u32 val;
+
+ val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ val &= ~AM65_CPSW_PN_IET_MAC_PREMPT_MASK;
+ val |= AM65_CPSW_PN_IET_MAC_SET_PREEMPT(preemptible_tcs);
+ writel(val, port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+}
+
+/* enable common IET_ENABLE only if at least 1 port has rx IET enabled.
+ * UAPI doesn't allow tx enable without rx enable.
+ */
+void am65_cpsw_iet_common_enable(struct am65_cpsw_common *common)
+{
+ struct am65_cpsw_port *port;
+ bool rx_enable = false;
+ u32 val;
+ int i;
+
+ for (i = 0; i < common->port_num; i++) {
+ port = &common->ports[i];
+ val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
+ rx_enable = !!(val & AM65_CPSW_PN_CTL_IET_PORT_EN);
+ if (rx_enable)
+ break;
+ }
+
+ val = readl(common->cpsw_base + AM65_CPSW_REG_CTL);
+
+ if (rx_enable)
+ val |= AM65_CPSW_CTL_IET_EN;
+ else
+ val &= ~AM65_CPSW_CTL_IET_EN;
+
+ writel(val, common->cpsw_base + AM65_CPSW_REG_CTL);
+ common->iet_enabled = rx_enable;
+}
+
+/* CPSW does not have an IRQ to notify changes to the MAC Merge TX status
+ * (active/inactive), but the preemptible traffic classes should only be
+ * committed to hardware once TX is active. Resort to polling.
+ */
+void am65_cpsw_iet_commit_preemptible_tcs(struct am65_cpsw_port *port)
+{
+ u8 preemptible_tcs;
+ int err;
+ u32 val;
+
+ if (port->qos.link_speed == SPEED_UNKNOWN)
+ return;
+
+ val = readl(port->port_base + AM65_CPSW_PN_REG_CTL);
+ if (!(val & AM65_CPSW_PN_CTL_IET_PORT_EN))
+ return;
+
+ /* update common IET enable */
+ am65_cpsw_iet_common_enable(port->common);
+
+ /* update verify count */
+ err = am65_cpsw_iet_set_verify_timeout_count(port);
+ if (err) {
+ netdev_err(port->ndev, "couldn't set verify count: %d\n", err);
+ return;
+ }
+
+ val = readl(port->port_base + AM65_CPSW_PN_REG_IET_CTRL);
+ if (!(val & AM65_CPSW_PN_IET_MAC_DISABLEVERIFY)) {
+ err = am65_cpsw_iet_verify_wait(port);
+ if (err)
+ return;
+ }
+
+ preemptible_tcs = port->qos.iet.preemptible_tcs;
+ am65_cpsw_iet_set_preempt_mask(port, preemptible_tcs);
+}
+
+static void am65_cpsw_iet_change_preemptible_tcs(struct am65_cpsw_port *port, u8 preemptible_tcs)
+{
+ struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(port->ndev);
+
+ port->qos.iet.preemptible_tcs = preemptible_tcs;
+ mutex_lock(&priv->mm_lock);
+ am65_cpsw_iet_commit_preemptible_tcs(port);
+ mutex_unlock(&priv->mm_lock);
+}
+
+static void am65_cpsw_iet_link_state_update(struct net_device *ndev)
+{
+ struct am65_cpsw_ndev_priv *priv = am65_ndev_to_priv(ndev);
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+
+ mutex_lock(&priv->mm_lock);
+ am65_cpsw_iet_commit_preemptible_tcs(port);
+ mutex_unlock(&priv->mm_lock);
+}
+
static int am65_cpsw_port_est_enabled(struct am65_cpsw_port *port)
{
return port->qos.est_oper || port->qos.est_admin;
@@ -428,7 +804,7 @@ static void am65_cpsw_stop_est(struct net_device *ndev)
am65_cpsw_timer_stop(ndev);
}
-static void am65_cpsw_purge_est(struct net_device *ndev)
+static void am65_cpsw_taprio_destroy(struct net_device *ndev)
{
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
@@ -439,31 +815,74 @@ static void am65_cpsw_purge_est(struct net_device *ndev)
port->qos.est_oper = NULL;
port->qos.est_admin = NULL;
+
+ am65_cpsw_reset_tc_mqprio(ndev);
}
-static int am65_cpsw_configure_taprio(struct net_device *ndev,
- struct am65_cpsw_est *est_new)
+static void am65_cpsw_cp_taprio(struct tc_taprio_qopt_offload *from,
+ struct tc_taprio_qopt_offload *to)
+{
+ int i;
+
+ *to = *from;
+ for (i = 0; i < from->num_entries; i++)
+ to->entries[i] = from->entries[i];
+}
+
+static int am65_cpsw_taprio_replace(struct net_device *ndev,
+ struct tc_taprio_qopt_offload *taprio)
{
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
+ struct netlink_ext_ack *extack = taprio->mqprio.extack;
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
struct am65_cpts *cpts = common->cpts;
- int ret = 0, tact = TACT_PROG;
+ struct am65_cpsw_est *est_new;
+ int ret, tact;
- am65_cpsw_est_update_state(ndev);
+ if (!netif_running(ndev)) {
+ NL_SET_ERR_MSG_MOD(extack, "interface is down, link speed unknown");
+ return -ENETDOWN;
+ }
- if (est_new->taprio.cmd == TAPRIO_CMD_DESTROY) {
- am65_cpsw_stop_est(ndev);
- return ret;
+ if (common->pf_p0_rx_ptype_rrobin) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "p0-rx-ptype-rrobin flag conflicts with taprio qdisc");
+ return -EINVAL;
}
+ if (port->qos.link_speed == SPEED_UNKNOWN)
+ return -ENOLINK;
+
+ if (taprio->cycle_time_extension) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "cycle time extension not supported");
+ return -EOPNOTSUPP;
+ }
+
+ est_new = devm_kzalloc(&ndev->dev,
+ struct_size(est_new, taprio.entries, taprio->num_entries),
+ GFP_KERNEL);
+ if (!est_new)
+ return -ENOMEM;
+
+ ret = am65_cpsw_setup_mqprio(ndev, &taprio->mqprio);
+ if (ret)
+ return ret;
+
+ am65_cpsw_cp_taprio(taprio, &est_new->taprio);
+
+ am65_cpsw_est_update_state(ndev);
+
ret = am65_cpsw_est_check_scheds(ndev, est_new);
if (ret < 0)
- return ret;
+ goto fail;
tact = am65_cpsw_timer_act(ndev, est_new);
if (tact == TACT_NEED_STOP) {
- dev_err(&ndev->dev,
- "Can't toggle estf timer, stop taprio first");
- return -EINVAL;
+ NL_SET_ERR_MSG_MOD(extack,
+ "Can't toggle estf timer, stop taprio first");
+ ret = -EINVAL;
+ goto fail;
}
if (tact == TACT_PROG)
@@ -476,62 +895,26 @@ static int am65_cpsw_configure_taprio(struct net_device *ndev,
am65_cpsw_est_set_sched_list(ndev, est_new);
am65_cpsw_port_est_assign_buf_num(ndev, est_new->buf);
- am65_cpsw_est_set(ndev, est_new->taprio.cmd == TAPRIO_CMD_REPLACE);
+ am65_cpsw_est_set(ndev, 1);
if (tact == TACT_PROG) {
ret = am65_cpsw_timer_set(ndev, est_new);
if (ret) {
- dev_err(&ndev->dev, "Failed to set cycle time");
- return ret;
+ NL_SET_ERR_MSG_MOD(extack,
+ "Failed to set cycle time");
+ goto fail;
}
}
- return ret;
-}
-
-static void am65_cpsw_cp_taprio(struct tc_taprio_qopt_offload *from,
- struct tc_taprio_qopt_offload *to)
-{
- int i;
-
- *to = *from;
- for (i = 0; i < from->num_entries; i++)
- to->entries[i] = from->entries[i];
-}
-
-static int am65_cpsw_set_taprio(struct net_device *ndev, void *type_data)
-{
- struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
- struct tc_taprio_qopt_offload *taprio = type_data;
- struct am65_cpsw_est *est_new;
- int ret = 0;
-
- if (taprio->cycle_time_extension) {
- dev_err(&ndev->dev, "Failed to set cycle time extension");
- return -EOPNOTSUPP;
- }
-
- est_new = devm_kzalloc(&ndev->dev,
- struct_size(est_new, taprio.entries, taprio->num_entries),
- GFP_KERNEL);
- if (!est_new)
- return -ENOMEM;
-
- am65_cpsw_cp_taprio(taprio, &est_new->taprio);
- ret = am65_cpsw_configure_taprio(ndev, est_new);
- if (!ret) {
- if (taprio->cmd == TAPRIO_CMD_REPLACE) {
- devm_kfree(&ndev->dev, port->qos.est_admin);
+ devm_kfree(&ndev->dev, port->qos.est_admin);
+ port->qos.est_admin = est_new;
+ am65_cpsw_iet_change_preemptible_tcs(port, taprio->mqprio.preemptible_tcs);
- port->qos.est_admin = est_new;
- } else {
- devm_kfree(&ndev->dev, est_new);
- am65_cpsw_purge_est(ndev);
- }
- } else {
- devm_kfree(&ndev->dev, est_new);
- }
+ return 0;
+fail:
+ am65_cpsw_reset_tc_mqprio(ndev);
+ devm_kfree(&ndev->dev, est_new);
return ret;
}
@@ -541,7 +924,6 @@ static void am65_cpsw_est_link_up(struct net_device *ndev, int link_speed)
ktime_t cur_time;
s64 delta;
- port->qos.link_speed = link_speed;
if (!am65_cpsw_port_est_enabled(port))
return;
@@ -558,37 +940,26 @@ static void am65_cpsw_est_link_up(struct net_device *ndev, int link_speed)
return;
purge_est:
- am65_cpsw_purge_est(ndev);
+ am65_cpsw_taprio_destroy(ndev);
}
static int am65_cpsw_setup_taprio(struct net_device *ndev, void *type_data)
{
- struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
struct tc_taprio_qopt_offload *taprio = type_data;
- struct am65_cpsw_common *common = port->common;
-
- if (taprio->cmd != TAPRIO_CMD_REPLACE &&
- taprio->cmd != TAPRIO_CMD_DESTROY)
- return -EOPNOTSUPP;
-
- if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS))
- return -ENODEV;
-
- if (!netif_running(ndev)) {
- dev_err(&ndev->dev, "interface is down, link speed unknown\n");
- return -ENETDOWN;
- }
-
- if (common->pf_p0_rx_ptype_rrobin) {
- dev_err(&ndev->dev,
- "p0-rx-ptype-rrobin flag conflicts with taprio qdisc\n");
- return -EINVAL;
+ int err = 0;
+
+ switch (taprio->cmd) {
+ case TAPRIO_CMD_REPLACE:
+ err = am65_cpsw_taprio_replace(ndev, taprio);
+ break;
+ case TAPRIO_CMD_DESTROY:
+ am65_cpsw_taprio_destroy(ndev);
+ break;
+ default:
+ err = -EOPNOTSUPP;
}
- if (port->qos.link_speed == SPEED_UNKNOWN)
- return -ENOLINK;
-
- return am65_cpsw_set_taprio(ndev, type_data);
+ return err;
}
static int am65_cpsw_tc_query_caps(struct net_device *ndev, void *type_data)
@@ -596,12 +967,17 @@ static int am65_cpsw_tc_query_caps(struct net_device *ndev, void *type_data)
struct tc_query_caps_base *base = type_data;
switch (base->type) {
+ case TC_SETUP_QDISC_MQPRIO: {
+ struct tc_mqprio_caps *caps = base->caps;
+
+ caps->validate_queue_counts = true;
+
+ return 0;
+ }
+
case TC_SETUP_QDISC_TAPRIO: {
struct tc_taprio_caps *caps = base->caps;
- if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS))
- return -EOPNOTSUPP;
-
caps->gate_mask_per_txq = true;
return 0;
@@ -787,55 +1163,6 @@ static int am65_cpsw_qos_setup_tc_block(struct net_device *ndev, struct flow_blo
port, port, true);
}
-int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
- void *type_data)
-{
- switch (type) {
- case TC_QUERY_CAPS:
- return am65_cpsw_tc_query_caps(ndev, type_data);
- case TC_SETUP_QDISC_TAPRIO:
- return am65_cpsw_setup_taprio(ndev, type_data);
- case TC_SETUP_BLOCK:
- return am65_cpsw_qos_setup_tc_block(ndev, type_data);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed)
-{
- struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
-
- if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS))
- return;
-
- am65_cpsw_est_link_up(ndev, link_speed);
- port->qos.link_down_time = 0;
-}
-
-void am65_cpsw_qos_link_down(struct net_device *ndev)
-{
- struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
-
- if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS))
- return;
-
- if (!port->qos.link_down_time)
- port->qos.link_down_time = ktime_get();
-
- port->qos.link_speed = SPEED_UNKNOWN;
-}
-
-static u32
-am65_cpsw_qos_tx_rate_calc(u32 rate_mbps, unsigned long bus_freq)
-{
- u32 ir;
-
- bus_freq /= 1000000;
- ir = DIV_ROUND_UP(((u64)rate_mbps * 32768), bus_freq);
- return ir;
-}
-
static void
am65_cpsw_qos_tx_p0_rate_apply(struct am65_cpsw_common *common,
int tx_ch, u32 rate_mbps)
@@ -937,3 +1264,44 @@ void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common)
host->port_base + AM65_CPSW_PN_REG_PRI_CIR(tx_ch));
}
}
+
+int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void *type_data)
+{
+ switch (type) {
+ case TC_QUERY_CAPS:
+ return am65_cpsw_tc_query_caps(ndev, type_data);
+ case TC_SETUP_QDISC_TAPRIO:
+ return am65_cpsw_setup_taprio(ndev, type_data);
+ case TC_SETUP_QDISC_MQPRIO:
+ return am65_cpsw_setup_mqprio(ndev, type_data);
+ case TC_SETUP_BLOCK:
+ return am65_cpsw_qos_setup_tc_block(ndev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+
+ port->qos.link_speed = link_speed;
+ am65_cpsw_tx_pn_shaper_apply(port);
+ am65_cpsw_iet_link_state_update(ndev);
+
+ am65_cpsw_est_link_up(ndev, link_speed);
+ port->qos.link_down_time = 0;
+}
+
+void am65_cpsw_qos_link_down(struct net_device *ndev)
+{
+ struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
+
+ port->qos.link_speed = SPEED_UNKNOWN;
+ am65_cpsw_tx_pn_shaper_apply(port);
+ am65_cpsw_iet_link_state_update(ndev);
+
+ if (!port->qos.link_down_time)
+ port->qos.link_down_time = ktime_get();
+}
diff --git a/drivers/net/ethernet/ti/am65-cpsw-qos.h b/drivers/net/ethernet/ti/am65-cpsw-qos.h
index 0cc2a3b3d7f9..b328e56c5b2b 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-qos.h
+++ b/drivers/net/ethernet/ti/am65-cpsw-qos.h
@@ -9,6 +9,7 @@
#include <net/pkt_sched.h>
struct am65_cpsw_common;
+struct am65_cpsw_port;
struct am65_cpsw_est {
int buf;
@@ -16,6 +17,18 @@ struct am65_cpsw_est {
struct tc_taprio_qopt_offload taprio;
};
+struct am65_cpsw_mqprio {
+ struct tc_mqprio_qopt_offload mqprio_hw;
+ u64 max_rate_total;
+ bool shaper_en;
+};
+
+struct am65_cpsw_iet {
+ u8 preemptible_tcs;
+ u32 original_max_blks;
+ int verify_time_ms;
+};
+
struct am65_cpsw_ale_ratelimit {
unsigned long cookie;
u64 rate_packet_ps;
@@ -26,16 +39,189 @@ struct am65_cpsw_qos {
struct am65_cpsw_est *est_oper;
ktime_t link_down_time;
int link_speed;
+ struct am65_cpsw_mqprio mqprio;
+ struct am65_cpsw_iet iet;
struct am65_cpsw_ale_ratelimit ale_bc_ratelimit;
struct am65_cpsw_ale_ratelimit ale_mc_ratelimit;
};
+#define AM65_CPSW_REG_CTL 0x004
+#define AM65_CPSW_PN_REG_CTL 0x004
+#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050
+#define AM65_CPSW_PN_REG_EST_CTL 0x060
+#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri))
+#define AM65_CPSW_P0_REG_PRI_EIR(pri) (0x160 + 4 * (pri))
+
+#define AM65_CPSW_PN_REG_CTL 0x004
+#define AM65_CPSW_PN_REG_TX_PRI_MAP 0x018
+#define AM65_CPSW_PN_REG_RX_PRI_MAP 0x020
+#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050
+#define AM65_CPSW_PN_REG_EST_CTL 0x060
+#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri))
+#define AM65_CPSW_PN_REG_PRI_EIR(pri) (0x160 + 4 * (pri))
+
+/* AM65_CPSW_REG_CTL register fields */
+#define AM65_CPSW_CTL_EST_EN BIT(18)
+
+/* AM65_CPSW_PN_REG_CTL register fields */
+#define AM65_CPSW_PN_CTL_EST_PORT_EN BIT(17)
+
+/* AM65_CPSW_PN_REG_EST_CTL register fields */
+#define AM65_CPSW_PN_EST_ONEBUF BIT(0)
+#define AM65_CPSW_PN_EST_BUFSEL BIT(1)
+#define AM65_CPSW_PN_EST_TS_EN BIT(2)
+#define AM65_CPSW_PN_EST_TS_FIRST BIT(3)
+#define AM65_CPSW_PN_EST_ONEPRI BIT(4)
+#define AM65_CPSW_PN_EST_TS_PRI_MSK GENMASK(7, 5)
+
+/* AM65_CPSW_PN_REG_FIFO_STATUS register fields */
+#define AM65_CPSW_PN_FST_TX_PRI_ACTIVE_MSK GENMASK(7, 0)
+#define AM65_CPSW_PN_FST_TX_E_MAC_ALLOW_MSK GENMASK(15, 8)
+#define AM65_CPSW_PN_FST_EST_CNT_ERR BIT(16)
+#define AM65_CPSW_PN_FST_EST_ADD_ERR BIT(17)
+#define AM65_CPSW_PN_FST_EST_BUFACT BIT(18)
+
+/* EST FETCH COMMAND RAM */
+#define AM65_CPSW_FETCH_RAM_CMD_NUM 0x80
+#define AM65_CPSW_FETCH_CNT_MSK GENMASK(21, 8)
+#define AM65_CPSW_FETCH_CNT_MAX (AM65_CPSW_FETCH_CNT_MSK >> 8)
+#define AM65_CPSW_FETCH_CNT_OFFSET 8
+#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0)
+#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK
+
+/* number of priority queues per port FIFO */
+#define AM65_CPSW_PN_FIFO_PRIO_NUM 8
+
+#if IS_ENABLED(CONFIG_TI_AM65_CPSW_QOS)
int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data);
void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed);
void am65_cpsw_qos_link_down(struct net_device *ndev);
int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev, int queue, u32 rate_mbps);
void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common);
+void am65_cpsw_iet_commit_preemptible_tcs(struct am65_cpsw_port *port);
+void am65_cpsw_iet_common_enable(struct am65_cpsw_common *common);
+#else
+static inline int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev,
+ enum tc_setup_type type,
+ void *type_data)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void am65_cpsw_qos_link_up(struct net_device *ndev,
+ int link_speed)
+{ }
+
+static inline void am65_cpsw_qos_link_down(struct net_device *ndev)
+{ }
+
+static inline int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev,
+ int queue,
+ u32 rate_mbps)
+{
+ return 0;
+}
+
+static inline void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common)
+{ }
+static inline void am65_cpsw_iet_commit_preemptible_tcs(struct am65_cpsw_port *port)
+{ }
+static inline void am65_cpsw_iet_common_enable(struct am65_cpsw_common *common)
+{ }
+#endif
+
+#define AM65_CPSW_REG_CTL 0x004
+#define AM65_CPSW_PN_REG_CTL 0x004
+#define AM65_CPSW_PN_REG_MAX_BLKS 0x008
+#define AM65_CPSW_PN_REG_TX_PRI_MAP 0x018
+#define AM65_CPSW_PN_REG_RX_PRI_MAP 0x020
+#define AM65_CPSW_PN_REG_IET_CTRL 0x040
+#define AM65_CPSW_PN_REG_IET_STATUS 0x044
+#define AM65_CPSW_PN_REG_IET_VERIFY 0x048
+#define AM65_CPSW_PN_REG_FIFO_STATUS 0x050
+#define AM65_CPSW_PN_REG_EST_CTL 0x060
+#define AM65_CPSW_PN_REG_PRI_CIR(pri) (0x140 + 4 * (pri))
+#define AM65_CPSW_PN_REG_PRI_EIR(pri) (0x160 + 4 * (pri))
+
+/* AM65_CPSW_REG_CTL register fields */
+#define AM65_CPSW_CTL_IET_EN BIT(17)
+#define AM65_CPSW_CTL_EST_EN BIT(18)
+
+/* AM65_CPSW_PN_REG_CTL register fields */
+#define AM65_CPSW_PN_CTL_IET_PORT_EN BIT(16)
+#define AM65_CPSW_PN_CTL_EST_PORT_EN BIT(17)
+
+/* AM65_CPSW_PN_REG_EST_CTL register fields */
+#define AM65_CPSW_PN_EST_ONEBUF BIT(0)
+#define AM65_CPSW_PN_EST_BUFSEL BIT(1)
+#define AM65_CPSW_PN_EST_TS_EN BIT(2)
+#define AM65_CPSW_PN_EST_TS_FIRST BIT(3)
+#define AM65_CPSW_PN_EST_ONEPRI BIT(4)
+#define AM65_CPSW_PN_EST_TS_PRI_MSK GENMASK(7, 5)
+
+/* AM65_CPSW_PN_REG_IET_CTRL register fields */
+#define AM65_CPSW_PN_IET_MAC_PENABLE BIT(0)
+#define AM65_CPSW_PN_IET_MAC_DISABLEVERIFY BIT(2)
+#define AM65_CPSW_PN_IET_MAC_LINKFAIL BIT(3)
+#define AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK GENMASK(10, 8)
+#define AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_OFFSET 8
+#define AM65_CPSW_PN_IET_MAC_PREMPT_MASK GENMASK(23, 16)
+#define AM65_CPSW_PN_IET_MAC_PREMPT_OFFSET 16
+
+#define AM65_CPSW_PN_IET_MAC_SET_ADDFRAGSIZE(n) (((n) << AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_OFFSET) & \
+ AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK)
+#define AM65_CPSW_PN_IET_MAC_GET_ADDFRAGSIZE(n) (((n) & AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_MASK) >> \
+ AM65_CPSW_PN_IET_MAC_MAC_ADDFRAGSIZE_OFFSET)
+#define AM65_CPSW_PN_IET_MAC_SET_PREEMPT(n) (((n) << AM65_CPSW_PN_IET_MAC_PREMPT_OFFSET) & \
+ AM65_CPSW_PN_IET_MAC_PREMPT_MASK)
+#define AM65_CPSW_PN_IET_MAC_GET_PREEMPT(n) (((n) & AM65_CPSW_PN_IET_MAC_PREMPT_MASK) >> \
+ AM65_CPSW_PN_IET_MAC_PREMPT_OFFSET)
+
+/* AM65_CPSW_PN_REG_IET_STATUS register fields */
+#define AM65_CPSW_PN_MAC_STATUS GENMASK(3, 0)
+#define AM65_CPSW_PN_MAC_VERIFIED BIT(0)
+#define AM65_CPSW_PN_MAC_VERIFY_FAIL BIT(1)
+#define AM65_CPSW_PN_MAC_RESPOND_ERR BIT(2)
+#define AM65_CPSW_PN_MAC_VERIFY_ERR BIT(3)
+
+/* AM65_CPSW_PN_REG_IET_VERIFY register fields */
+#define AM65_CPSW_PN_MAC_VERIFY_CNT_MASK GENMASK(23, 0)
+#define AM65_CPSW_PN_MAC_GET_VERIFY_CNT(n) ((n) & AM65_CPSW_PN_MAC_VERIFY_CNT_MASK)
+/* 10 msec converted to NSEC */
+#define AM65_CPSW_IET_VERIFY_CNT_MS (10)
+#define AM65_CPSW_IET_VERIFY_CNT_NS (AM65_CPSW_IET_VERIFY_CNT_MS * \
+ NSEC_PER_MSEC)
+
+/* AM65_CPSW_PN_REG_FIFO_STATUS register fields */
+#define AM65_CPSW_PN_FST_TX_PRI_ACTIVE_MSK GENMASK(7, 0)
+#define AM65_CPSW_PN_FST_TX_E_MAC_ALLOW_MSK GENMASK(15, 8)
+#define AM65_CPSW_PN_FST_EST_CNT_ERR BIT(16)
+#define AM65_CPSW_PN_FST_EST_ADD_ERR BIT(17)
+#define AM65_CPSW_PN_FST_EST_BUFACT BIT(18)
+
+/* EST FETCH COMMAND RAM */
+#define AM65_CPSW_FETCH_RAM_CMD_NUM 0x80
+#define AM65_CPSW_FETCH_CNT_MSK GENMASK(21, 8)
+#define AM65_CPSW_FETCH_CNT_MAX (AM65_CPSW_FETCH_CNT_MSK >> 8)
+#define AM65_CPSW_FETCH_CNT_OFFSET 8
+#define AM65_CPSW_FETCH_ALLOW_MSK GENMASK(7, 0)
+#define AM65_CPSW_FETCH_ALLOW_MAX AM65_CPSW_FETCH_ALLOW_MSK
+
+/* AM65_CPSW_PN_REG_MAX_BLKS fields for IET and No IET cases */
+/* 7 blocks for pn_rx_max_blks, 13 for pn_tx_max_blks*/
+#define AM65_CPSW_PN_TX_RX_MAX_BLKS_IET 0xD07
+
+/* Slave IET Stats. register offsets */
+#define AM65_CPSW_STATN_IET_RX_ASSEMBLY_ERROR 0x140
+#define AM65_CPSW_STATN_IET_RX_ASSEMBLY_OK 0x144
+#define AM65_CPSW_STATN_IET_RX_SMD_ERROR 0x148
+#define AM65_CPSW_STATN_IET_RX_FRAG 0x14c
+#define AM65_CPSW_STATN_IET_TX_HOLD 0x150
+#define AM65_CPSW_STATN_IET_TX_FRAG 0x154
+
+/* number of priority queues per port FIFO */
+#define AM65_CPSW_PN_FIFO_PRIO_NUM 8
#endif /* AM65_CPSW_QOS_H_ */
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index ca4d4548f85e..c0a5abd8d9a8 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -631,6 +631,8 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
}
}
+ phy->mac_managed_pm = true;
+
slave->phy = phy;
phy_attached_info(slave->phy);
@@ -1722,14 +1724,20 @@ clean_runtime_disable_ret:
return ret;
}
-static int cpsw_remove(struct platform_device *pdev)
+static void cpsw_remove(struct platform_device *pdev)
{
struct cpsw_common *cpsw = platform_get_drvdata(pdev);
int i, ret;
ret = pm_runtime_resume_and_get(&pdev->dev);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ /* Note, if this error path is taken, we're leaking some
+ * resources.
+ */
+ dev_err(&pdev->dev, "Failed to resume device (%pe)\n",
+ ERR_PTR(ret));
+ return;
+ }
for (i = 0; i < cpsw->data.slaves; i++)
if (cpsw->slaves[i].ndev)
@@ -1740,7 +1748,6 @@ static int cpsw_remove(struct platform_device *pdev)
cpsw_remove_dt(pdev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1795,7 +1802,7 @@ static struct platform_driver cpsw_driver = {
.of_match_table = cpsw_of_mtable,
},
.probe = cpsw_probe,
- .remove = cpsw_remove,
+ .remove_new = cpsw_remove,
};
module_platform_driver(cpsw_driver);
diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c
index 0e4f526b1753..087dcb67505a 100644
--- a/drivers/net/ethernet/ti/cpsw_new.c
+++ b/drivers/net/ethernet/ti/cpsw_new.c
@@ -773,6 +773,9 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
slave->slave_num);
return;
}
+
+ phy->mac_managed_pm = true;
+
slave->phy = phy;
phy_attached_info(slave->phy);
@@ -2037,14 +2040,20 @@ clean_dt_ret:
return ret;
}
-static int cpsw_remove(struct platform_device *pdev)
+static void cpsw_remove(struct platform_device *pdev)
{
struct cpsw_common *cpsw = platform_get_drvdata(pdev);
int ret;
ret = pm_runtime_resume_and_get(&pdev->dev);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ /* Note, if this error path is taken, we're leaking some
+ * resources.
+ */
+ dev_err(&pdev->dev, "Failed to resume device (%pe)\n",
+ ERR_PTR(ret));
+ return;
+ }
cpsw_unregister_notifiers(cpsw);
cpsw_unregister_devlink(cpsw);
@@ -2055,7 +2064,6 @@ static int cpsw_remove(struct platform_device *pdev)
cpsw_remove_dt(cpsw);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return 0;
}
static int __maybe_unused cpsw_suspend(struct device *dev)
@@ -2116,7 +2124,7 @@ static struct platform_driver cpsw_driver = {
.of_match_table = cpsw_of_mtable,
},
.probe = cpsw_probe,
- .remove = cpsw_remove,
+ .remove_new = cpsw_remove,
};
module_platform_driver(cpsw_driver);
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index bcccf43d368b..dbbea9146040 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -638,6 +638,16 @@ static void cpts_calc_mult_shift(struct cpts *cpts)
freq, cpts->cc.mult, cpts->cc.shift, (ns - NSEC_PER_SEC));
}
+static void cpts_clk_unregister(void *clk)
+{
+ clk_hw_unregister_mux(clk);
+}
+
+static void cpts_clk_del_provider(void *np)
+{
+ of_clk_del_provider(np);
+}
+
static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
{
struct device_node *refclk_np;
@@ -687,9 +697,7 @@ static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
goto mux_fail;
}
- ret = devm_add_action_or_reset(cpts->dev,
- (void(*)(void *))clk_hw_unregister_mux,
- clk_hw);
+ ret = devm_add_action_or_reset(cpts->dev, cpts_clk_unregister, clk_hw);
if (ret) {
dev_err(cpts->dev, "add clkmux unreg action %d", ret);
goto mux_fail;
@@ -699,8 +707,7 @@ static int cpts_of_mux_clk_setup(struct cpts *cpts, struct device_node *node)
if (ret)
goto mux_fail;
- ret = devm_add_action_or_reset(cpts->dev,
- (void(*)(void *))of_clk_del_provider,
+ ret = devm_add_action_or_reset(cpts->dev, cpts_clk_del_provider,
refclk_np);
if (ret) {
dev_err(cpts->dev, "add clkmux provider unreg action %d", ret);
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index 628c87dc1d28..8e07d4a1b6ba 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -511,16 +511,12 @@ static const struct k3_mdio_soc_data am65_mdio_soc_data = {
};
static const struct soc_device_attribute k3_mdio_socinfo[] = {
- { .family = "AM62X", .revision = "SR1.0", .data = &am65_mdio_soc_data },
- { .family = "AM64X", .revision = "SR1.0", .data = &am65_mdio_soc_data },
- { .family = "AM64X", .revision = "SR2.0", .data = &am65_mdio_soc_data },
- { .family = "AM65X", .revision = "SR1.0", .data = &am65_mdio_soc_data },
- { .family = "AM65X", .revision = "SR2.0", .data = &am65_mdio_soc_data },
- { .family = "J7200", .revision = "SR1.0", .data = &am65_mdio_soc_data },
- { .family = "J7200", .revision = "SR2.0", .data = &am65_mdio_soc_data },
- { .family = "J721E", .revision = "SR1.0", .data = &am65_mdio_soc_data },
- { .family = "J721E", .revision = "SR2.0", .data = &am65_mdio_soc_data },
- { .family = "J721S2", .revision = "SR1.0", .data = &am65_mdio_soc_data},
+ { .family = "AM62X", .data = &am65_mdio_soc_data },
+ { .family = "AM64X", .data = &am65_mdio_soc_data },
+ { .family = "AM65X", .data = &am65_mdio_soc_data },
+ { .family = "J7200", .data = &am65_mdio_soc_data },
+ { .family = "J721E", .data = &am65_mdio_soc_data },
+ { .family = "J721S2", .data = &am65_mdio_soc_data },
{ /* sentinel */ },
};
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.c b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
index 9d535ae59626..c1b0d35c8d05 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.c
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.c
@@ -93,12 +93,13 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card,
* gelic_descr_get_status -- returns the status of a descriptor
* @descr: descriptor to look at
*
- * returns the status as in the dmac_cmd_status field of the descriptor
+ * returns the status as in the hw_regs.dmac_cmd_status field of the descriptor
*/
static enum gelic_descr_dma_status
gelic_descr_get_status(struct gelic_descr *descr)
{
- return be32_to_cpu(descr->dmac_cmd_status) & GELIC_DESCR_DMA_STAT_MASK;
+ return be32_to_cpu(descr->hw_regs.dmac_cmd_status) &
+ GELIC_DESCR_DMA_STAT_MASK;
}
static int gelic_card_set_link_mode(struct gelic_card *card, int mode)
@@ -152,15 +153,15 @@ static void gelic_card_enable_rxdmac(struct gelic_card *card)
if (gelic_descr_get_status(card->rx_chain.head) !=
GELIC_DESCR_DMA_CARDOWNED) {
printk(KERN_ERR "%s: status=%x\n", __func__,
- be32_to_cpu(card->rx_chain.head->dmac_cmd_status));
+ be32_to_cpu(card->rx_chain.head->hw_regs.dmac_cmd_status));
printk(KERN_ERR "%s: nextphy=%x\n", __func__,
- be32_to_cpu(card->rx_chain.head->next_descr_addr));
+ be32_to_cpu(card->rx_chain.head->hw_regs.next_descr_addr));
printk(KERN_ERR "%s: head=%p\n", __func__,
card->rx_chain.head);
}
#endif
status = lv1_net_start_rx_dma(bus_id(card), dev_id(card),
- card->rx_chain.head->bus_addr, 0);
+ card->rx_chain.head->link.cpu_addr, 0);
if (status)
dev_info(ctodev(card),
"lv1_net_start_rx_dma failed, status=%d\n", status);
@@ -195,8 +196,8 @@ static void gelic_card_disable_rxdmac(struct gelic_card *card)
static void gelic_descr_set_status(struct gelic_descr *descr,
enum gelic_descr_dma_status status)
{
- descr->dmac_cmd_status = cpu_to_be32(status |
- (be32_to_cpu(descr->dmac_cmd_status) &
+ descr->hw_regs.dmac_cmd_status = cpu_to_be32(status |
+ (be32_to_cpu(descr->hw_regs.dmac_cmd_status) &
~GELIC_DESCR_DMA_STAT_MASK));
/*
* dma_cmd_status field is used to indicate whether the descriptor
@@ -224,13 +225,14 @@ static void gelic_card_reset_chain(struct gelic_card *card,
for (descr = start_descr; start_descr != descr->next; descr++) {
gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
- descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
+ descr->hw_regs.next_descr_addr
+ = cpu_to_be32(descr->next->link.cpu_addr);
}
chain->head = start_descr;
chain->tail = (descr - 1);
- (descr - 1)->next_descr_addr = 0;
+ (descr - 1)->hw_regs.next_descr_addr = 0;
}
void gelic_card_up(struct gelic_card *card)
@@ -286,10 +288,12 @@ static void gelic_card_free_chain(struct gelic_card *card,
{
struct gelic_descr *descr;
- for (descr = descr_in; descr && descr->bus_addr; descr = descr->next) {
- dma_unmap_single(ctodev(card), descr->bus_addr,
- GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL);
- descr->bus_addr = 0;
+ for (descr = descr_in; descr && descr->link.cpu_addr;
+ descr = descr->next) {
+ dma_unmap_single(ctodev(card), descr->link.cpu_addr,
+ descr->link.size, DMA_BIDIRECTIONAL);
+ descr->link.cpu_addr = 0;
+ descr->link.size = 0;
}
}
@@ -317,17 +321,21 @@ static int gelic_card_init_chain(struct gelic_card *card,
/* set up the hardware pointers in each descriptor */
for (i = 0; i < no; i++, descr++) {
- dma_addr_t cpu_addr;
-
gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
- cpu_addr = dma_map_single(ctodev(card), descr,
- GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL);
+ descr->link.size = sizeof(struct gelic_hw_regs);
+ descr->link.cpu_addr = dma_map_single(ctodev(card), descr,
+ descr->link.size, DMA_BIDIRECTIONAL);
- if (dma_mapping_error(ctodev(card), cpu_addr))
- goto iommu_error;
+ if (dma_mapping_error(ctodev(card), descr->link.cpu_addr)) {
+ for (i--, descr--; 0 <= i; i--, descr--) {
+ dma_unmap_single(ctodev(card),
+ descr->link.cpu_addr, descr->link.size,
+ DMA_BIDIRECTIONAL);
+ }
+ return -ENOMEM;
+ }
- descr->bus_addr = cpu_to_be32(cpu_addr);
descr->next = descr + 1;
descr->prev = descr - 1;
}
@@ -338,24 +346,17 @@ static int gelic_card_init_chain(struct gelic_card *card,
/* chain bus addr of hw descriptor */
descr = start_descr;
for (i = 0; i < no; i++, descr++) {
- descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
+ descr->hw_regs.next_descr_addr =
+ cpu_to_be32(descr->next->link.cpu_addr);
}
chain->head = start_descr;
chain->tail = start_descr;
/* do not chain last hw descriptor */
- (descr - 1)->next_descr_addr = 0;
+ (descr - 1)->hw_regs.next_descr_addr = 0;
return 0;
-
-iommu_error:
- for (i--, descr--; 0 <= i; i--, descr--)
- if (descr->bus_addr)
- dma_unmap_single(ctodev(card), descr->bus_addr,
- GELIC_DESCR_SIZE,
- DMA_BIDIRECTIONAL);
- return -ENOMEM;
}
/**
@@ -383,16 +384,18 @@ static int gelic_descr_prepare_rx(struct gelic_card *card,
if (gelic_descr_get_status(descr) != GELIC_DESCR_DMA_NOT_IN_USE)
dev_info(ctodev(card), "%s: ERROR status\n", __func__);
+ descr->hw_regs.dmac_cmd_status = 0;
+ descr->hw_regs.result_size = 0;
+ descr->hw_regs.valid_size = 0;
+ descr->hw_regs.data_error = 0;
+ descr->hw_regs.payload.dev_addr = 0;
+ descr->hw_regs.payload.size = 0;
+
descr->skb = netdev_alloc_skb(*card->netdev, rx_skb_size);
if (!descr->skb) {
- descr->buf_addr = 0; /* tell DMAC don't touch memory */
+ descr->hw_regs.payload.dev_addr = 0; /* tell DMAC don't touch memory */
return -ENOMEM;
}
- descr->buf_size = cpu_to_be32(rx_skb_size);
- descr->dmac_cmd_status = 0;
- descr->result_size = 0;
- descr->valid_size = 0;
- descr->data_error = 0;
offset = ((unsigned long)descr->skb->data) &
(GELIC_NET_RXBUF_ALIGN - 1);
@@ -401,7 +404,7 @@ static int gelic_descr_prepare_rx(struct gelic_card *card,
/* io-mmu-map the skb */
cpu_addr = dma_map_single(ctodev(card), descr->skb->data,
GELIC_NET_MAX_FRAME, DMA_FROM_DEVICE);
- descr->buf_addr = cpu_to_be32(cpu_addr);
+ descr->hw_regs.payload.dev_addr = cpu_to_be32(cpu_addr);
if (dma_mapping_error(ctodev(card), cpu_addr)) {
dev_kfree_skb_any(descr->skb);
descr->skb = NULL;
@@ -409,10 +412,14 @@ static int gelic_descr_prepare_rx(struct gelic_card *card,
"%s:Could not iommu-map rx buffer\n", __func__);
gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
return -ENOMEM;
- } else {
- gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
- return 0;
}
+
+ descr->hw_regs.payload.size = cpu_to_be32(GELIC_NET_MAX_FRAME);
+ descr->hw_regs.payload.dev_addr = cpu_to_be32(cpu_addr);
+
+ gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED);
+
+ return 0;
}
/**
@@ -427,14 +434,15 @@ static void gelic_card_release_rx_chain(struct gelic_card *card)
do {
if (descr->skb) {
dma_unmap_single(ctodev(card),
- be32_to_cpu(descr->buf_addr),
- descr->skb->len,
- DMA_FROM_DEVICE);
- descr->buf_addr = 0;
+ be32_to_cpu(descr->hw_regs.payload.dev_addr),
+ descr->skb->len,
+ DMA_FROM_DEVICE);
+ descr->hw_regs.payload.dev_addr = 0;
+ descr->hw_regs.payload.size = 0;
dev_kfree_skb_any(descr->skb);
descr->skb = NULL;
gelic_descr_set_status(descr,
- GELIC_DESCR_DMA_NOT_IN_USE);
+ GELIC_DESCR_DMA_NOT_IN_USE);
}
descr = descr->next;
} while (descr != card->rx_chain.head);
@@ -496,19 +504,20 @@ static void gelic_descr_release_tx(struct gelic_card *card,
{
struct sk_buff *skb = descr->skb;
- BUG_ON(!(be32_to_cpu(descr->data_status) & GELIC_DESCR_TX_TAIL));
+ BUG_ON(!(be32_to_cpu(descr->hw_regs.data_status) & GELIC_DESCR_TX_TAIL));
- dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr), skb->len,
- DMA_TO_DEVICE);
+ dma_unmap_single(ctodev(card),
+ be32_to_cpu(descr->hw_regs.payload.dev_addr), skb->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
- descr->buf_addr = 0;
- descr->buf_size = 0;
- descr->next_descr_addr = 0;
- descr->result_size = 0;
- descr->valid_size = 0;
- descr->data_status = 0;
- descr->data_error = 0;
+ descr->hw_regs.payload.dev_addr = 0;
+ descr->hw_regs.payload.size = 0;
+ descr->hw_regs.next_descr_addr = 0;
+ descr->hw_regs.result_size = 0;
+ descr->hw_regs.valid_size = 0;
+ descr->hw_regs.data_status = 0;
+ descr->hw_regs.data_error = 0;
descr->skb = NULL;
/* set descr status */
@@ -701,7 +710,7 @@ static void gelic_descr_set_tx_cmdstat(struct gelic_descr *descr,
struct sk_buff *skb)
{
if (skb->ip_summed != CHECKSUM_PARTIAL)
- descr->dmac_cmd_status =
+ descr->hw_regs.dmac_cmd_status =
cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM |
GELIC_DESCR_TX_DMA_FRAME_TAIL);
else {
@@ -709,19 +718,19 @@ static void gelic_descr_set_tx_cmdstat(struct gelic_descr *descr,
* if yes: tcp? udp? */
if (skb->protocol == htons(ETH_P_IP)) {
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
- descr->dmac_cmd_status =
+ descr->hw_regs.dmac_cmd_status =
cpu_to_be32(GELIC_DESCR_DMA_CMD_TCP_CHKSUM |
GELIC_DESCR_TX_DMA_FRAME_TAIL);
else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
- descr->dmac_cmd_status =
+ descr->hw_regs.dmac_cmd_status =
cpu_to_be32(GELIC_DESCR_DMA_CMD_UDP_CHKSUM |
GELIC_DESCR_TX_DMA_FRAME_TAIL);
else /*
* the stack should checksum non-tcp and non-udp
* packets on his own: NETIF_F_IP_CSUM
*/
- descr->dmac_cmd_status =
+ descr->hw_regs.dmac_cmd_status =
cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM |
GELIC_DESCR_TX_DMA_FRAME_TAIL);
}
@@ -789,11 +798,11 @@ static int gelic_descr_prepare_tx(struct gelic_card *card,
return -ENOMEM;
}
- descr->buf_addr = cpu_to_be32(buf);
- descr->buf_size = cpu_to_be32(skb->len);
+ descr->hw_regs.payload.dev_addr = cpu_to_be32(buf);
+ descr->hw_regs.payload.size = cpu_to_be32(skb->len);
descr->skb = skb;
- descr->data_status = 0;
- descr->next_descr_addr = 0; /* terminate hw descr */
+ descr->hw_regs.data_status = 0;
+ descr->hw_regs.next_descr_addr = 0; /* terminate hw descr */
gelic_descr_set_tx_cmdstat(descr, skb);
/* bump free descriptor pointer */
@@ -818,7 +827,7 @@ static int gelic_card_kick_txdma(struct gelic_card *card,
if (gelic_descr_get_status(descr) == GELIC_DESCR_DMA_CARDOWNED) {
card->tx_dma_progress = 1;
status = lv1_net_start_tx_dma(bus_id(card), dev_id(card),
- descr->bus_addr, 0);
+ descr->link.cpu_addr, 0);
if (status) {
card->tx_dma_progress = 0;
dev_info(ctodev(card), "lv1_net_start_txdma failed," \
@@ -871,7 +880,8 @@ netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
* link this prepared descriptor to previous one
* to achieve high performance
*/
- descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
+ descr->prev->hw_regs.next_descr_addr =
+ cpu_to_be32(descr->link.cpu_addr);
/*
* as hardware descriptor is modified in the above lines,
* ensure that the hardware sees it
@@ -884,12 +894,12 @@ netdev_tx_t gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
*/
netdev->stats.tx_dropped++;
/* don't trigger BUG_ON() in gelic_descr_release_tx */
- descr->data_status = cpu_to_be32(GELIC_DESCR_TX_TAIL);
+ descr->hw_regs.data_status = cpu_to_be32(GELIC_DESCR_TX_TAIL);
gelic_descr_release_tx(card, descr);
/* reset head */
card->tx_chain.head = descr;
/* reset hw termination */
- descr->prev->next_descr_addr = 0;
+ descr->prev->hw_regs.next_descr_addr = 0;
dev_info(ctodev(card), "%s: kick failure\n", __func__);
}
@@ -914,21 +924,21 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr,
struct sk_buff *skb = descr->skb;
u32 data_status, data_error;
- data_status = be32_to_cpu(descr->data_status);
- data_error = be32_to_cpu(descr->data_error);
+ data_status = be32_to_cpu(descr->hw_regs.data_status);
+ data_error = be32_to_cpu(descr->hw_regs.data_error);
/* unmap skb buffer */
- dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr),
- GELIC_NET_MAX_FRAME,
- DMA_FROM_DEVICE);
-
- skb_put(skb, be32_to_cpu(descr->valid_size)?
- be32_to_cpu(descr->valid_size) :
- be32_to_cpu(descr->result_size));
- if (!descr->valid_size)
+ dma_unmap_single(ctodev(card),
+ be32_to_cpu(descr->hw_regs.payload.dev_addr),
+ be32_to_cpu(descr->hw_regs.payload.size), DMA_FROM_DEVICE);
+
+ skb_put(skb, be32_to_cpu(descr->hw_regs.valid_size)?
+ be32_to_cpu(descr->hw_regs.valid_size) :
+ be32_to_cpu(descr->hw_regs.result_size));
+ if (!descr->hw_regs.valid_size)
dev_info(ctodev(card), "buffer full %x %x %x\n",
- be32_to_cpu(descr->result_size),
- be32_to_cpu(descr->buf_size),
- be32_to_cpu(descr->dmac_cmd_status));
+ be32_to_cpu(descr->hw_regs.result_size),
+ be32_to_cpu(descr->hw_regs.payload.size),
+ be32_to_cpu(descr->hw_regs.dmac_cmd_status));
descr->skb = NULL;
/*
@@ -1039,14 +1049,14 @@ refill:
/* is the current descriptor terminated with next_descr == NULL? */
dmac_chain_ended =
- be32_to_cpu(descr->dmac_cmd_status) &
+ be32_to_cpu(descr->hw_regs.dmac_cmd_status) &
GELIC_DESCR_RX_DMA_CHAIN_END;
/*
* So that always DMAC can see the end
* of the descriptor chain to avoid
* from unwanted DMAC overrun.
*/
- descr->next_descr_addr = 0;
+ descr->hw_regs.next_descr_addr = 0;
/* change the descriptor state: */
gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE);
@@ -1063,7 +1073,8 @@ refill:
/*
* Set this descriptor the end of the chain.
*/
- descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
+ descr->prev->hw_regs.next_descr_addr =
+ cpu_to_be32(descr->link.cpu_addr);
/*
* If dmac chain was met, DMAC stopped.
diff --git a/drivers/net/ethernet/toshiba/ps3_gelic_net.h b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
index 0d98defb011e..f7d7931e51b7 100644
--- a/drivers/net/ethernet/toshiba/ps3_gelic_net.h
+++ b/drivers/net/ethernet/toshiba/ps3_gelic_net.h
@@ -221,29 +221,35 @@ enum gelic_lv1_phy {
GELIC_LV1_PHY_ETHERNET_0 = 0x0000000000000002L,
};
-/* size of hardware part of gelic descriptor */
-#define GELIC_DESCR_SIZE (32)
-
enum gelic_port_type {
GELIC_PORT_ETHERNET_0 = 0,
GELIC_PORT_WIRELESS = 1,
GELIC_PORT_MAX
};
-struct gelic_descr {
- /* as defined by the hardware */
- __be32 buf_addr;
- __be32 buf_size;
+/* As defined by the gelic hardware device. */
+struct gelic_hw_regs {
+ struct {
+ __be32 dev_addr;
+ __be32 size;
+ } __packed payload;
__be32 next_descr_addr;
__be32 dmac_cmd_status;
__be32 result_size;
__be32 valid_size; /* all zeroes for tx */
__be32 data_status;
__be32 data_error; /* all zeroes for tx */
+} __packed;
+
+struct gelic_chain_link {
+ dma_addr_t cpu_addr;
+ unsigned int size;
+};
- /* used in the driver */
+struct gelic_descr {
+ struct gelic_hw_regs hw_regs;
+ struct gelic_chain_link link;
struct sk_buff *skb;
- dma_addr_t bus_addr;
struct gelic_descr *next;
struct gelic_descr *prev;
} __attribute__((aligned(32)));
@@ -346,12 +352,6 @@ static inline void *port_priv(struct gelic_port *port)
return port->priv;
}
-#ifdef CONFIG_PPC_EARLY_DEBUG_PS3GELIC
-void udbg_shutdown_ps3gelic(void);
-#else
-static inline void udbg_shutdown_ps3gelic(void) {}
-#endif
-
int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask);
/* shared netdev ops */
void gelic_card_up(struct gelic_card *card);
diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index 23cd610bd376..85cdbdd44fec 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -26,7 +26,7 @@ config NGBE
tristate "Wangxun(R) GbE PCI Express adapters support"
depends on PCI
select LIBWX
- select PHYLIB
+ select PHYLINK
help
This driver supports Wangxun(R) GbE PCI Express family of
adapters.
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index ddc5f6d20b9c..cc3bec42ed8e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -8,6 +8,7 @@
#include "wx_type.h"
#include "wx_ethtool.h"
#include "wx_hw.h"
+#include "wx_lib.h"
struct wx_stats {
char stat_string[ETH_GSTRING_LEN];
@@ -75,7 +76,7 @@ void wx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < WX_GLOBAL_STATS_LEN; i++)
- ethtool_sprintf(&p, wx_gstrings_stats[i].stat_string);
+ ethtool_puts(&p, wx_gstrings_stats[i].stat_string);
for (i = 0; i < netdev->num_tx_queues; i++) {
ethtool_sprintf(&p, "tx_queue_%u_packets", i);
ethtool_sprintf(&p, "tx_queue_%u_bytes", i);
@@ -185,3 +186,238 @@ void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
}
}
EXPORT_SYMBOL(wx_get_drvinfo);
+
+int wx_nway_reset(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ return phylink_ethtool_nway_reset(wx->phylink);
+}
+EXPORT_SYMBOL(wx_nway_reset);
+
+int wx_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ return phylink_ethtool_ksettings_get(wx->phylink, cmd);
+}
+EXPORT_SYMBOL(wx_get_link_ksettings);
+
+int wx_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ return phylink_ethtool_ksettings_set(wx->phylink, cmd);
+}
+EXPORT_SYMBOL(wx_set_link_ksettings);
+
+void wx_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ phylink_ethtool_get_pauseparam(wx->phylink, pause);
+}
+EXPORT_SYMBOL(wx_get_pauseparam);
+
+int wx_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ return phylink_ethtool_set_pauseparam(wx->phylink, pause);
+}
+EXPORT_SYMBOL(wx_set_pauseparam);
+
+void wx_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ ring->rx_max_pending = WX_MAX_RXD;
+ ring->tx_max_pending = WX_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = wx->rx_ring_count;
+ ring->tx_pending = wx->tx_ring_count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+EXPORT_SYMBOL(wx_get_ringparam);
+
+int wx_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ ec->tx_max_coalesced_frames_irq = wx->tx_work_limit;
+ /* only valid if in constant ITR mode */
+ if (wx->rx_itr_setting <= 1)
+ ec->rx_coalesce_usecs = wx->rx_itr_setting;
+ else
+ ec->rx_coalesce_usecs = wx->rx_itr_setting >> 2;
+
+ /* if in mixed tx/rx queues per vector mode, report only rx settings */
+ if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count)
+ return 0;
+
+ /* only valid if in constant ITR mode */
+ if (wx->tx_itr_setting <= 1)
+ ec->tx_coalesce_usecs = wx->tx_itr_setting;
+ else
+ ec->tx_coalesce_usecs = wx->tx_itr_setting >> 2;
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_get_coalesce);
+
+int wx_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+ u16 tx_itr_param, rx_itr_param;
+ struct wx_q_vector *q_vector;
+ u16 max_eitr;
+ int i;
+
+ if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count) {
+ /* reject Tx specific changes in case of mixed RxTx vectors */
+ if (ec->tx_coalesce_usecs)
+ return -EOPNOTSUPP;
+ }
+
+ if (ec->tx_max_coalesced_frames_irq)
+ wx->tx_work_limit = ec->tx_max_coalesced_frames_irq;
+
+ if (wx->mac.type == wx_mac_sp)
+ max_eitr = WX_SP_MAX_EITR;
+ else
+ max_eitr = WX_EM_MAX_EITR;
+
+ if ((ec->rx_coalesce_usecs > (max_eitr >> 2)) ||
+ (ec->tx_coalesce_usecs > (max_eitr >> 2)))
+ return -EINVAL;
+
+ if (ec->rx_coalesce_usecs > 1)
+ wx->rx_itr_setting = ec->rx_coalesce_usecs << 2;
+ else
+ wx->rx_itr_setting = ec->rx_coalesce_usecs;
+
+ if (wx->rx_itr_setting == 1)
+ rx_itr_param = WX_20K_ITR;
+ else
+ rx_itr_param = wx->rx_itr_setting;
+
+ if (ec->tx_coalesce_usecs > 1)
+ wx->tx_itr_setting = ec->tx_coalesce_usecs << 2;
+ else
+ wx->tx_itr_setting = ec->tx_coalesce_usecs;
+
+ if (wx->tx_itr_setting == 1) {
+ if (wx->mac.type == wx_mac_sp)
+ tx_itr_param = WX_12K_ITR;
+ else
+ tx_itr_param = WX_20K_ITR;
+ } else {
+ tx_itr_param = wx->tx_itr_setting;
+ }
+
+ /* mixed Rx/Tx */
+ if (wx->q_vector[0]->tx.count && wx->q_vector[0]->rx.count)
+ wx->tx_itr_setting = wx->rx_itr_setting;
+
+ for (i = 0; i < wx->num_q_vectors; i++) {
+ q_vector = wx->q_vector[i];
+ if (q_vector->tx.count && !q_vector->rx.count)
+ /* tx only */
+ q_vector->itr = tx_itr_param;
+ else
+ /* rx only or mixed */
+ q_vector->itr = rx_itr_param;
+ wx_write_eitr(q_vector);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_set_coalesce);
+
+static unsigned int wx_max_channels(struct wx *wx)
+{
+ unsigned int max_combined;
+
+ if (!wx->msix_q_entries) {
+ /* We only support one q_vector without MSI-X */
+ max_combined = 1;
+ } else {
+ /* support up to max allowed queues with RSS */
+ if (wx->mac.type == wx_mac_sp)
+ max_combined = 63;
+ else
+ max_combined = 8;
+ }
+
+ return max_combined;
+}
+
+void wx_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ struct wx *wx = netdev_priv(dev);
+
+ /* report maximum channels */
+ ch->max_combined = wx_max_channels(wx);
+
+ /* report info for other vector */
+ if (wx->msix_q_entries) {
+ ch->max_other = 1;
+ ch->other_count = 1;
+ }
+
+ /* record RSS queues */
+ ch->combined_count = wx->ring_feature[RING_F_RSS].indices;
+}
+EXPORT_SYMBOL(wx_get_channels);
+
+int wx_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ unsigned int count = ch->combined_count;
+ struct wx *wx = netdev_priv(dev);
+
+ /* verify other_count has not changed */
+ if (ch->other_count != 1)
+ return -EINVAL;
+
+ /* verify the number of channels does not exceed hardware limits */
+ if (count > wx_max_channels(wx))
+ return -EINVAL;
+
+ wx->ring_feature[RING_F_RSS].limit = count;
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_set_channels);
+
+u32 wx_get_msglevel(struct net_device *netdev)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ return wx->msg_enable;
+}
+EXPORT_SYMBOL(wx_get_msglevel);
+
+void wx_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ wx->msg_enable = data;
+}
+EXPORT_SYMBOL(wx_set_msglevel);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
index 16d1a09369a6..600c3b597d1a 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.h
@@ -13,4 +13,31 @@ void wx_get_mac_stats(struct net_device *netdev,
void wx_get_pause_stats(struct net_device *netdev,
struct ethtool_pause_stats *stats);
void wx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info);
+int wx_nway_reset(struct net_device *netdev);
+int wx_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd);
+int wx_set_link_ksettings(struct net_device *netdev,
+ const struct ethtool_link_ksettings *cmd);
+void wx_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause);
+int wx_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause);
+void wx_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack);
+int wx_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack);
+int wx_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack);
+void wx_get_channels(struct net_device *dev,
+ struct ethtool_channels *ch);
+int wx_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch);
+u32 wx_get_msglevel(struct net_device *netdev);
+void wx_set_msglevel(struct net_device *netdev, u32 data);
#endif /* _WX_ETHTOOL_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
index 533e912af089..1db754615cca 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c
@@ -149,9 +149,9 @@ void wx_irq_disable(struct wx *wx)
int vector;
for (vector = 0; vector < wx->num_q_vectors; vector++)
- synchronize_irq(wx->msix_entries[vector].vector);
+ synchronize_irq(wx->msix_q_entries[vector].vector);
- synchronize_irq(wx->msix_entries[vector].vector);
+ synchronize_irq(wx->msix_entry->vector);
} else {
synchronize_irq(pdev->irq);
}
@@ -1158,6 +1158,81 @@ static void wx_set_rxpba(struct wx *wx)
wr32(wx, WX_TDM_PB_THRE(0), txpbthresh);
}
+#define WX_ETH_FRAMING 20
+
+/**
+ * wx_hpbthresh - calculate high water mark for flow control
+ *
+ * @wx: board private structure to calculate for
+ **/
+static int wx_hpbthresh(struct wx *wx)
+{
+ struct net_device *dev = wx->netdev;
+ int link, tc, kb, marker;
+ u32 dv_id, rx_pba;
+
+ /* Calculate max LAN frame size */
+ link = dev->mtu + ETH_HLEN + ETH_FCS_LEN + WX_ETH_FRAMING;
+ tc = link;
+
+ /* Calculate delay value for device */
+ dv_id = WX_DV(link, tc);
+
+ /* Delay value is calculated in bit times convert to KB */
+ kb = WX_BT2KB(dv_id);
+ rx_pba = rd32(wx, WX_RDB_PB_SZ(0)) >> WX_RDB_PB_SZ_SHIFT;
+
+ marker = rx_pba - kb;
+
+ /* It is possible that the packet buffer is not large enough
+ * to provide required headroom. In this case throw an error
+ * to user and a do the best we can.
+ */
+ if (marker < 0) {
+ dev_warn(&wx->pdev->dev,
+ "Packet Buffer can not provide enough headroom to support flow control. Decrease MTU or number of traffic classes\n");
+ marker = tc + 1;
+ }
+
+ return marker;
+}
+
+/**
+ * wx_lpbthresh - calculate low water mark for flow control
+ *
+ * @wx: board private structure to calculate for
+ **/
+static int wx_lpbthresh(struct wx *wx)
+{
+ struct net_device *dev = wx->netdev;
+ u32 dv_id;
+ int tc;
+
+ /* Calculate max LAN frame size */
+ tc = dev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ /* Calculate delay value for device */
+ dv_id = WX_LOW_DV(tc);
+
+ /* Delay value is calculated in bit times convert to KB */
+ return WX_BT2KB(dv_id);
+}
+
+/**
+ * wx_pbthresh_setup - calculate and setup high low water marks
+ *
+ * @wx: board private structure to calculate for
+ **/
+static void wx_pbthresh_setup(struct wx *wx)
+{
+ wx->fc.high_water = wx_hpbthresh(wx);
+ wx->fc.low_water = wx_lpbthresh(wx);
+
+ /* Low water marks must not be larger than high water marks */
+ if (wx->fc.low_water > wx->fc.high_water)
+ wx->fc.low_water = 0;
+}
+
static void wx_configure_port(struct wx *wx)
{
u32 value, i;
@@ -1522,6 +1597,72 @@ static void wx_restore_vlan(struct wx *wx)
wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), vid);
}
+static void wx_store_reta(struct wx *wx)
+{
+ u8 *indir_tbl = wx->rss_indir_tbl;
+ u32 reta = 0;
+ u32 i;
+
+ /* Fill out the redirection table as follows:
+ * - 8 bit wide entries containing 4 bit RSS index
+ */
+ for (i = 0; i < WX_MAX_RETA_ENTRIES; i++) {
+ reta |= indir_tbl[i] << (i & 0x3) * 8;
+ if ((i & 3) == 3) {
+ wr32(wx, WX_RDB_RSSTBL(i >> 2), reta);
+ reta = 0;
+ }
+ }
+}
+
+static void wx_setup_reta(struct wx *wx)
+{
+ u16 rss_i = wx->ring_feature[RING_F_RSS].indices;
+ u32 random_key_size = WX_RSS_KEY_SIZE / 4;
+ u32 i, j;
+
+ /* Fill out hash function seeds */
+ for (i = 0; i < random_key_size; i++)
+ wr32(wx, WX_RDB_RSSRK(i), wx->rss_key[i]);
+
+ /* Fill out redirection table */
+ memset(wx->rss_indir_tbl, 0, sizeof(wx->rss_indir_tbl));
+
+ for (i = 0, j = 0; i < WX_MAX_RETA_ENTRIES; i++, j++) {
+ if (j == rss_i)
+ j = 0;
+
+ wx->rss_indir_tbl[i] = j;
+ }
+
+ wx_store_reta(wx);
+}
+
+static void wx_setup_mrqc(struct wx *wx)
+{
+ u32 rss_field = 0;
+
+ /* Disable indicating checksum in descriptor, enables RSS hash */
+ wr32m(wx, WX_PSR_CTL, WX_PSR_CTL_PCSD, WX_PSR_CTL_PCSD);
+
+ /* Perform hash on these packet types */
+ rss_field = WX_RDB_RA_CTL_RSS_IPV4 |
+ WX_RDB_RA_CTL_RSS_IPV4_TCP |
+ WX_RDB_RA_CTL_RSS_IPV4_UDP |
+ WX_RDB_RA_CTL_RSS_IPV6 |
+ WX_RDB_RA_CTL_RSS_IPV6_TCP |
+ WX_RDB_RA_CTL_RSS_IPV6_UDP;
+
+ netdev_rss_key_fill(wx->rss_key, sizeof(wx->rss_key));
+
+ wx_setup_reta(wx);
+
+ if (wx->rss_enabled)
+ rss_field |= WX_RDB_RA_CTL_RSS_EN;
+
+ wr32(wx, WX_RDB_RA_CTL, rss_field);
+}
+
/**
* wx_configure_rx - Configure Receive Unit after Reset
* @wx: pointer to private structure
@@ -1554,6 +1695,8 @@ void wx_configure_rx(struct wx *wx)
wr32(wx, WX_PSR_CTL, psrctl);
}
+ wx_setup_mrqc(wx);
+
/* set_rx_buffer_len must be called before ring initialization */
wx_set_rx_buffer_len(wx);
@@ -1584,6 +1727,7 @@ static void wx_configure_isb(struct wx *wx)
void wx_configure(struct wx *wx)
{
wx_set_rxpba(wx);
+ wx_pbthresh_setup(wx);
wx_configure_port(wx);
wx_set_rx_mode(wx->netdev);
@@ -1750,6 +1894,28 @@ int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count)
}
EXPORT_SYMBOL(wx_get_pcie_msix_counts);
+/**
+ * wx_init_rss_key - Initialize wx RSS key
+ * @wx: device handle
+ *
+ * Allocates and initializes the RSS key if it is not allocated.
+ **/
+static int wx_init_rss_key(struct wx *wx)
+{
+ u32 *rss_key;
+
+ if (!wx->rss_key) {
+ rss_key = kzalloc(WX_RSS_KEY_SIZE, GFP_KERNEL);
+ if (unlikely(!rss_key))
+ return -ENOMEM;
+
+ netdev_rss_key_fill(rss_key, WX_RSS_KEY_SIZE);
+ wx->rss_key = rss_key;
+ }
+
+ return 0;
+}
+
int wx_sw_init(struct wx *wx)
{
struct pci_dev *pdev = wx->pdev;
@@ -1777,14 +1943,23 @@ int wx_sw_init(struct wx *wx)
wx->subsystem_device_id = swab16((u16)ssid);
}
+ err = wx_init_rss_key(wx);
+ if (err < 0) {
+ wx_err(wx, "rss key allocation failed\n");
+ return err;
+ }
+
wx->mac_table = kcalloc(wx->mac.num_rar_entries,
sizeof(struct wx_mac_addr),
GFP_KERNEL);
if (!wx->mac_table) {
wx_err(wx, "mac_table allocation failed\n");
+ kfree(wx->rss_key);
return -ENOMEM;
}
+ wx->msix_in_use = false;
+
return 0;
}
EXPORT_SYMBOL(wx_sw_init);
@@ -2003,6 +2178,102 @@ int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
}
EXPORT_SYMBOL(wx_vlan_rx_kill_vid);
+static void wx_enable_rx_drop(struct wx *wx, struct wx_ring *ring)
+{
+ u16 reg_idx = ring->reg_idx;
+ u32 srrctl;
+
+ srrctl = rd32(wx, WX_PX_RR_CFG(reg_idx));
+ srrctl |= WX_PX_RR_CFG_DROP_EN;
+
+ wr32(wx, WX_PX_RR_CFG(reg_idx), srrctl);
+}
+
+static void wx_disable_rx_drop(struct wx *wx, struct wx_ring *ring)
+{
+ u16 reg_idx = ring->reg_idx;
+ u32 srrctl;
+
+ srrctl = rd32(wx, WX_PX_RR_CFG(reg_idx));
+ srrctl &= ~WX_PX_RR_CFG_DROP_EN;
+
+ wr32(wx, WX_PX_RR_CFG(reg_idx), srrctl);
+}
+
+int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause)
+{
+ u16 pause_time = WX_DEFAULT_FCPAUSE;
+ u32 mflcn_reg, fccfg_reg, reg;
+ u32 fcrtl, fcrth;
+ int i;
+
+ /* Low water mark of zero causes XOFF floods */
+ if (tx_pause && wx->fc.high_water) {
+ if (!wx->fc.low_water || wx->fc.low_water >= wx->fc.high_water) {
+ wx_err(wx, "Invalid water mark configuration\n");
+ return -EINVAL;
+ }
+ }
+
+ /* Disable any previous flow control settings */
+ mflcn_reg = rd32(wx, WX_MAC_RX_FLOW_CTRL);
+ mflcn_reg &= ~WX_MAC_RX_FLOW_CTRL_RFE;
+
+ fccfg_reg = rd32(wx, WX_RDB_RFCC);
+ fccfg_reg &= ~WX_RDB_RFCC_RFCE_802_3X;
+
+ if (rx_pause)
+ mflcn_reg |= WX_MAC_RX_FLOW_CTRL_RFE;
+ if (tx_pause)
+ fccfg_reg |= WX_RDB_RFCC_RFCE_802_3X;
+
+ /* Set 802.3x based flow control settings. */
+ wr32(wx, WX_MAC_RX_FLOW_CTRL, mflcn_reg);
+ wr32(wx, WX_RDB_RFCC, fccfg_reg);
+
+ /* Set up and enable Rx high/low water mark thresholds, enable XON. */
+ if (tx_pause && wx->fc.high_water) {
+ fcrtl = (wx->fc.low_water << 10) | WX_RDB_RFCL_XONE;
+ wr32(wx, WX_RDB_RFCL, fcrtl);
+ fcrth = (wx->fc.high_water << 10) | WX_RDB_RFCH_XOFFE;
+ } else {
+ wr32(wx, WX_RDB_RFCL, 0);
+ /* In order to prevent Tx hangs when the internal Tx
+ * switch is enabled we must set the high water mark
+ * to the Rx packet buffer size - 24KB. This allows
+ * the Tx switch to function even under heavy Rx
+ * workloads.
+ */
+ fcrth = rd32(wx, WX_RDB_PB_SZ(0)) - 24576;
+ }
+
+ wr32(wx, WX_RDB_RFCH, fcrth);
+
+ /* Configure pause time */
+ reg = pause_time * 0x00010001;
+ wr32(wx, WX_RDB_RFCV, reg);
+
+ /* Configure flow control refresh threshold value */
+ wr32(wx, WX_RDB_RFCRT, pause_time / 2);
+
+ /* We should set the drop enable bit if:
+ * Number of Rx queues > 1 and flow control is disabled
+ *
+ * This allows us to avoid head of line blocking for security
+ * and performance reasons.
+ */
+ if (wx->num_rx_queues > 1 && !tx_pause) {
+ for (i = 0; i < wx->num_rx_queues; i++)
+ wx_enable_rx_drop(wx, wx->rx_ring[i]);
+ } else {
+ for (i = 0; i < wx->num_rx_queues; i++)
+ wx_disable_rx_drop(wx, wx->rx_ring[i]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(wx_fc_enable);
+
/**
* wx_update_stats - Update the board statistics counters.
* @wx: board private structure
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.h b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
index 12c20a7c364d..9e219fa717a2 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_hw.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.h
@@ -41,6 +41,7 @@ int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count);
int wx_sw_init(struct wx *wx);
int wx_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid);
int wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid);
+int wx_fc_enable(struct wx *wx, bool tx_pause, bool rx_pause);
void wx_update_stats(struct wx *wx);
void wx_clear_hw_cntrs(struct wx *wx);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index 347d3cec02a3..8706223a6e5a 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -1568,8 +1568,14 @@ EXPORT_SYMBOL(wx_napi_disable_all);
**/
static void wx_set_rss_queues(struct wx *wx)
{
- wx->num_rx_queues = wx->mac.max_rx_queues;
- wx->num_tx_queues = wx->mac.max_tx_queues;
+ struct wx_ring_feature *f;
+
+ /* set mask for 16 queue limit of RSS */
+ f = &wx->ring_feature[RING_F_RSS];
+ f->indices = f->limit;
+
+ wx->num_rx_queues = f->limit;
+ wx->num_tx_queues = f->limit;
}
static void wx_set_num_queues(struct wx *wx)
@@ -1595,35 +1601,51 @@ static int wx_acquire_msix_vectors(struct wx *wx)
struct irq_affinity affd = {0, };
int nvecs, i;
- nvecs = min_t(int, num_online_cpus(), wx->mac.max_msix_vectors);
+ /* We start by asking for one vector per queue pair */
+ nvecs = max(wx->num_rx_queues, wx->num_tx_queues);
+ nvecs = min_t(int, nvecs, num_online_cpus());
+ nvecs = min_t(int, nvecs, wx->mac.max_msix_vectors);
- wx->msix_entries = kcalloc(nvecs,
- sizeof(struct msix_entry),
- GFP_KERNEL);
- if (!wx->msix_entries)
+ wx->msix_q_entries = kcalloc(nvecs, sizeof(struct msix_entry),
+ GFP_KERNEL);
+ if (!wx->msix_q_entries)
return -ENOMEM;
+ /* One for non-queue interrupts */
+ nvecs += 1;
+
+ if (!wx->msix_in_use) {
+ wx->msix_entry = kcalloc(1, sizeof(struct msix_entry),
+ GFP_KERNEL);
+ if (!wx->msix_entry) {
+ kfree(wx->msix_q_entries);
+ wx->msix_q_entries = NULL;
+ return -ENOMEM;
+ }
+ }
+
nvecs = pci_alloc_irq_vectors_affinity(wx->pdev, nvecs,
nvecs,
PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
&affd);
if (nvecs < 0) {
wx_err(wx, "Failed to allocate MSI-X interrupts. Err: %d\n", nvecs);
- kfree(wx->msix_entries);
- wx->msix_entries = NULL;
+ kfree(wx->msix_q_entries);
+ wx->msix_q_entries = NULL;
+ kfree(wx->msix_entry);
+ wx->msix_entry = NULL;
return nvecs;
}
+ wx->msix_entry->entry = 0;
+ wx->msix_entry->vector = pci_irq_vector(wx->pdev, 0);
+ nvecs -= 1;
for (i = 0; i < nvecs; i++) {
- wx->msix_entries[i].entry = i;
- wx->msix_entries[i].vector = pci_irq_vector(wx->pdev, i);
+ wx->msix_q_entries[i].entry = i;
+ wx->msix_q_entries[i].vector = pci_irq_vector(wx->pdev, i + 1);
}
- /* one for msix_other */
- nvecs -= 1;
wx->num_q_vectors = nvecs;
- wx->num_rx_queues = nvecs;
- wx->num_tx_queues = nvecs;
return 0;
}
@@ -1645,9 +1667,11 @@ static int wx_set_interrupt_capability(struct wx *wx)
if (ret == 0 || (ret == -ENOMEM))
return ret;
- wx->num_rx_queues = 1;
- wx->num_tx_queues = 1;
- wx->num_q_vectors = 1;
+ /* Disable RSS */
+ dev_warn(&wx->pdev->dev, "Disabling RSS support\n");
+ wx->ring_feature[RING_F_RSS].limit = 1;
+
+ wx_set_num_queues(wx);
/* minmum one for queue, one for misc*/
nvecs = 1;
@@ -1905,8 +1929,12 @@ void wx_reset_interrupt_capability(struct wx *wx)
return;
if (pdev->msix_enabled) {
- kfree(wx->msix_entries);
- wx->msix_entries = NULL;
+ kfree(wx->msix_q_entries);
+ wx->msix_q_entries = NULL;
+ if (!wx->msix_in_use) {
+ kfree(wx->msix_entry);
+ wx->msix_entry = NULL;
+ }
}
pci_free_irq_vectors(wx->pdev);
}
@@ -1978,7 +2006,7 @@ void wx_free_irq(struct wx *wx)
for (vector = 0; vector < wx->num_q_vectors; vector++) {
struct wx_q_vector *q_vector = wx->q_vector[vector];
- struct msix_entry *entry = &wx->msix_entries[vector];
+ struct msix_entry *entry = &wx->msix_q_entries[vector];
/* free only the irqs that were actually requested */
if (!q_vector->rx.ring && !q_vector->tx.ring)
@@ -1988,7 +2016,7 @@ void wx_free_irq(struct wx *wx)
}
if (wx->mac.type == wx_mac_em)
- free_irq(wx->msix_entries[vector].vector, wx);
+ free_irq(wx->msix_entry->vector, wx);
}
EXPORT_SYMBOL(wx_free_irq);
@@ -2065,6 +2093,7 @@ static void wx_set_ivar(struct wx *wx, s8 direction,
wr32(wx, WX_PX_MISC_IVAR, ivar);
} else {
/* tx or rx causes */
+ msix_vector += 1; /* offset for queue vectors */
msix_vector |= WX_PX_IVAR_ALLOC_VAL;
index = ((16 * (queue & 1)) + (8 * direction));
ivar = rd32(wx, WX_PX_IVAR(queue >> 1));
@@ -2082,7 +2111,7 @@ static void wx_set_ivar(struct wx *wx, s8 direction,
* when it needs to update EITR registers at runtime. Hardware
* specific quirks/differences are taken care of here.
*/
-static void wx_write_eitr(struct wx_q_vector *q_vector)
+void wx_write_eitr(struct wx_q_vector *q_vector)
{
struct wx *wx = q_vector->wx;
int v_idx = q_vector->v_idx;
@@ -2095,7 +2124,7 @@ static void wx_write_eitr(struct wx_q_vector *q_vector)
itr_reg |= WX_PX_ITR_CNT_WDIS;
- wr32(wx, WX_PX_ITR(v_idx), itr_reg);
+ wr32(wx, WX_PX_ITR(v_idx + 1), itr_reg);
}
/**
@@ -2141,9 +2170,9 @@ void wx_configure_vectors(struct wx *wx)
wx_write_eitr(q_vector);
}
- wx_set_ivar(wx, -1, 0, v_idx);
+ wx_set_ivar(wx, -1, 0, 0);
if (pdev->msix_enabled)
- wr32(wx, WX_PX_ITR(v_idx), 1950);
+ wr32(wx, WX_PX_ITR(0), 1950);
}
EXPORT_SYMBOL(wx_configure_vectors);
@@ -2656,11 +2685,14 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
netdev_features_t changed = netdev->features ^ features;
struct wx *wx = netdev_priv(netdev);
- if (changed & NETIF_F_RXHASH)
+ if (features & NETIF_F_RXHASH) {
wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN,
WX_RDB_RA_CTL_RSS_EN);
- else
+ wx->rss_enabled = true;
+ } else {
wr32m(wx, WX_RDB_RA_CTL, WX_RDB_RA_CTL_RSS_EN, 0);
+ wx->rss_enabled = false;
+ }
if (changed &
(NETIF_F_HW_VLAN_CTAG_RX |
@@ -2671,4 +2703,71 @@ int wx_set_features(struct net_device *netdev, netdev_features_t features)
}
EXPORT_SYMBOL(wx_set_features);
+void wx_set_ring(struct wx *wx, u32 new_tx_count,
+ u32 new_rx_count, struct wx_ring *temp_ring)
+{
+ int i, err = 0;
+
+ /* Setup new Tx resources and free the old Tx resources in that order.
+ * We can then assign the new resources to the rings via a memcpy.
+ * The advantage to this approach is that we are guaranteed to still
+ * have resources even in the case of an allocation failure.
+ */
+ if (new_tx_count != wx->tx_ring_count) {
+ for (i = 0; i < wx->num_tx_queues; i++) {
+ memcpy(&temp_ring[i], wx->tx_ring[i],
+ sizeof(struct wx_ring));
+
+ temp_ring[i].count = new_tx_count;
+ err = wx_setup_tx_resources(&temp_ring[i]);
+ if (err) {
+ wx_err(wx, "setup new tx resources failed, keep using the old config\n");
+ while (i) {
+ i--;
+ wx_free_tx_resources(&temp_ring[i]);
+ }
+ return;
+ }
+ }
+
+ for (i = 0; i < wx->num_tx_queues; i++) {
+ wx_free_tx_resources(wx->tx_ring[i]);
+
+ memcpy(wx->tx_ring[i], &temp_ring[i],
+ sizeof(struct wx_ring));
+ }
+
+ wx->tx_ring_count = new_tx_count;
+ }
+
+ /* Repeat the process for the Rx rings if needed */
+ if (new_rx_count != wx->rx_ring_count) {
+ for (i = 0; i < wx->num_rx_queues; i++) {
+ memcpy(&temp_ring[i], wx->rx_ring[i],
+ sizeof(struct wx_ring));
+
+ temp_ring[i].count = new_rx_count;
+ err = wx_setup_rx_resources(&temp_ring[i]);
+ if (err) {
+ wx_err(wx, "setup new rx resources failed, keep using the old config\n");
+ while (i) {
+ i--;
+ wx_free_rx_resources(&temp_ring[i]);
+ }
+ return;
+ }
+ }
+
+ for (i = 0; i < wx->num_rx_queues; i++) {
+ wx_free_rx_resources(wx->rx_ring[i]);
+ memcpy(wx->rx_ring[i], &temp_ring[i],
+ sizeof(struct wx_ring));
+ }
+
+ wx->rx_ring_count = new_rx_count;
+ }
+}
+EXPORT_SYMBOL(wx_set_ring);
+
+MODULE_DESCRIPTION("Common library for Wangxun(R) Ethernet drivers.");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.h b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
index df1f4a5951f0..ec909e876720 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.h
@@ -21,6 +21,7 @@ void wx_free_irq(struct wx *wx);
int wx_setup_isb_resources(struct wx *wx);
void wx_free_isb_resources(struct wx *wx);
u32 wx_misc_isb(struct wx *wx, enum wx_isb_idx idx);
+void wx_write_eitr(struct wx_q_vector *q_vector);
void wx_configure_vectors(struct wx *wx);
void wx_clean_all_rx_rings(struct wx *wx);
void wx_clean_all_tx_rings(struct wx *wx);
@@ -29,5 +30,7 @@ int wx_setup_resources(struct wx *wx);
void wx_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats);
int wx_set_features(struct net_device *netdev, netdev_features_t features);
+void wx_set_ring(struct wx *wx, u32 new_tx_count,
+ u32 new_rx_count, struct wx_ring *temp_ring);
#endif /* _NGBE_LIB_H_ */
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index 83f9bb7b3c22..b4dc4f341117 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
+#include <linux/phylink.h>
#include <net/ip.h>
#define WX_NCSI_SUP 0x8000
@@ -130,6 +131,15 @@
#define WX_RDB_PFCMACDAH 0x19214
#define WX_RDB_LXOFFTXC 0x19218
#define WX_RDB_LXONTXC 0x1921C
+/* Flow Control Registers */
+#define WX_RDB_RFCV 0x19200
+#define WX_RDB_RFCL 0x19220
+#define WX_RDB_RFCL_XONE BIT(31)
+#define WX_RDB_RFCH 0x19260
+#define WX_RDB_RFCH_XOFFE BIT(31)
+#define WX_RDB_RFCRT 0x192A0
+#define WX_RDB_RFCC 0x192A4
+#define WX_RDB_RFCC_RFCE_802_3X BIT(3)
/* ring assignment */
#define WX_RDB_PL_CFG(_i) (0x19300 + ((_i) * 4))
#define WX_RDB_PL_CFG_L4HDR BIT(1)
@@ -137,8 +147,16 @@
#define WX_RDB_PL_CFG_L2HDR BIT(3)
#define WX_RDB_PL_CFG_TUN_TUNHDR BIT(4)
#define WX_RDB_PL_CFG_TUN_OUTL2HDR BIT(5)
+#define WX_RDB_RSSTBL(_i) (0x19400 + ((_i) * 4))
+#define WX_RDB_RSSRK(_i) (0x19480 + ((_i) * 4))
#define WX_RDB_RA_CTL 0x194F4
#define WX_RDB_RA_CTL_RSS_EN BIT(2) /* RSS Enable */
+#define WX_RDB_RA_CTL_RSS_IPV4_TCP BIT(16)
+#define WX_RDB_RA_CTL_RSS_IPV4 BIT(17)
+#define WX_RDB_RA_CTL_RSS_IPV6 BIT(20)
+#define WX_RDB_RA_CTL_RSS_IPV6_TCP BIT(21)
+#define WX_RDB_RA_CTL_RSS_IPV4_UDP BIT(22)
+#define WX_RDB_RA_CTL_RSS_IPV6_UDP BIT(23)
/******************************* PSR Registers *******************************/
/* psr control */
@@ -305,6 +323,7 @@ enum WX_MSCA_CMD_value {
#define WX_PX_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */
#define WX_7K_ITR 595
#define WX_12K_ITR 336
+#define WX_20K_ITR 200
#define WX_SP_MAX_EITR 0x00000FF8U
#define WX_EM_MAX_EITR 0x00007FFCU
@@ -330,6 +349,7 @@ enum WX_MSCA_CMD_value {
#define WX_PX_MPRC(_i) (0x01020 + ((_i) * 0x40))
/* PX_RR_CFG bit definitions */
#define WX_PX_RR_CFG_VLAN BIT(31)
+#define WX_PX_RR_CFG_DROP_EN BIT(30)
#define WX_PX_RR_CFG_SPLIT_MODE BIT(26)
#define WX_PX_RR_CFG_RR_THER_SHIFT 16
#define WX_PX_RR_CFG_RR_HDR_SZ GENMASK(15, 12)
@@ -367,8 +387,46 @@ enum WX_MSCA_CMD_value {
#define WX_MAC_STATE_MODIFIED 0x2
#define WX_MAC_STATE_IN_USE 0x4
+/* BitTimes (BT) conversion */
+#define WX_BT2KB(BT) (((BT) + (8 * 1024 - 1)) / (8 * 1024))
+#define WX_B2BT(BT) ((BT) * 8)
+
+/* Calculate Delay to respond to PFC */
+#define WX_PFC_D 672
+/* Calculate Cable Delay */
+#define WX_CABLE_DC 5556 /* Delay Copper */
+/* Calculate Delay incurred from higher layer */
+#define WX_HD 6144
+
+/* Calculate Interface Delay */
+#define WX_PHY_D 12800
+#define WX_MAC_D 4096
+#define WX_XAUI_D (2 * 1024)
+#define WX_ID (WX_MAC_D + WX_XAUI_D + WX_PHY_D)
+/* Calculate PCI Bus delay for low thresholds */
+#define WX_PCI_DELAY 10000
+
+/* Calculate delay value in bit times */
+#define WX_DV(_max_frame_link, _max_frame_tc) \
+ ((36 * (WX_B2BT(_max_frame_link) + WX_PFC_D + \
+ (2 * WX_CABLE_DC) + (2 * WX_ID) + WX_HD) / 25 + 1) + \
+ 2 * WX_B2BT(_max_frame_tc))
+
+/* Calculate low threshold delay values */
+#define WX_LOW_DV(_max_frame_tc) \
+ (2 * (2 * WX_B2BT(_max_frame_tc) + (36 * WX_PCI_DELAY / 25) + 1))
+
+/* flow control */
+#define WX_DEFAULT_FCPAUSE 0xFFFF
+
#define WX_MAX_RXD 8192
#define WX_MAX_TXD 8192
+#define WX_MIN_RXD 128
+#define WX_MIN_TXD 128
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define WX_REQ_RX_DESCRIPTOR_MULTIPLE 8
+#define WX_REQ_TX_DESCRIPTOR_MULTIPLE 8
#define WX_MAX_JUMBO_FRAME_SIZE 9432 /* max payload 9414 */
#define VMDQ_P(p) p
@@ -871,6 +929,19 @@ struct wx_q_vector {
struct wx_ring ring[] ____cacheline_internodealigned_in_smp;
};
+struct wx_ring_feature {
+ u16 limit; /* upper limit on feature indices */
+ u16 indices; /* current value of indices */
+ u16 mask; /* Mask used for feature to ring mapping */
+ u16 offset; /* offset to start of feature */
+};
+
+enum wx_ring_f_enum {
+ RING_F_NONE = 0,
+ RING_F_RSS,
+ RING_F_ARRAY_SIZE /* must be last in enum set */
+};
+
enum wx_isb_idx {
WX_ISB_HEADER,
WX_ISB_MISC,
@@ -879,6 +950,11 @@ enum wx_isb_idx {
WX_ISB_MAX
};
+struct wx_fc_info {
+ u32 high_water; /* Flow Ctrl High-water */
+ u32 low_water; /* Flow Ctrl Low-water */
+};
+
/* Statistics counters collected by the MAC */
struct wx_hw_stats {
u64 gprc;
@@ -919,6 +995,7 @@ struct wx {
enum sp_media_type media_type;
struct wx_eeprom_info eeprom;
struct wx_addr_filter_info addr_ctrl;
+ struct wx_fc_info fc;
struct wx_mac_addr *mac_table;
u16 device_id;
u16 vendor_id;
@@ -939,6 +1016,8 @@ struct wx {
int speed;
int duplex;
struct phy_device *phydev;
+ struct phylink *phylink;
+ struct phylink_config phylink_config;
bool wol_hw_supported;
bool ncsi_enabled;
@@ -966,7 +1045,10 @@ struct wx {
struct wx_q_vector *q_vector[64];
unsigned int queues_per_pool;
- struct msix_entry *msix_entries;
+ struct msix_entry *msix_q_entries;
+ struct msix_entry *msix_entry;
+ bool msix_in_use;
+ struct wx_ring_feature ring_feature[RING_F_ARRAY_SIZE];
/* misc interrupt status block */
dma_addr_t isb_dma;
@@ -974,8 +1056,9 @@ struct wx {
u32 isb_tag[WX_ISB_MAX];
#define WX_MAX_RETA_ENTRIES 128
+#define WX_RSS_INDIR_TBL_MAX 64
u8 rss_indir_tbl[WX_MAX_RETA_ENTRIES];
-
+ bool rss_enabled;
#define WX_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
u32 *rss_key;
u32 wol;
@@ -992,7 +1075,7 @@ struct wx {
};
#define WX_INTR_ALL (~0ULL)
-#define WX_INTR_Q(i) BIT(i)
+#define WX_INTR_Q(i) BIT((i) + 1)
/* register operations */
#define wr32(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
@@ -1044,4 +1127,9 @@ rd64(struct wx *wx, u32 reg)
#define wx_dbg(wx, fmt, arg...) \
dev_dbg(&(wx)->pdev->dev, fmt, ##arg)
+static inline struct wx *phylink_to_wx(struct phylink_config *config)
+{
+ return container_of(config, struct wx, phylink_config);
+}
+
#endif /* _WX_TYPE_H_ */
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
index afbdf6919071..786a652ae64f 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_ethtool.c
@@ -7,7 +7,10 @@
#include "../libwx/wx_ethtool.h"
#include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
+#include "../libwx/wx_hw.h"
#include "ngbe_ethtool.h"
+#include "ngbe_type.h"
static void ngbe_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
@@ -41,12 +44,75 @@ static int ngbe_set_wol(struct net_device *netdev,
return 0;
}
+static int ngbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+ u32 new_rx_count, new_tx_count;
+ struct wx_ring *temp_ring;
+ int i;
+
+ new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ if (new_tx_count == wx->tx_ring_count &&
+ new_rx_count == wx->rx_ring_count)
+ return 0;
+
+ if (!netif_running(wx->netdev)) {
+ for (i = 0; i < wx->num_tx_queues; i++)
+ wx->tx_ring[i]->count = new_tx_count;
+ for (i = 0; i < wx->num_rx_queues; i++)
+ wx->rx_ring[i]->count = new_rx_count;
+ wx->tx_ring_count = new_tx_count;
+ wx->rx_ring_count = new_rx_count;
+
+ return 0;
+ }
+
+ /* allocate temporary buffer to store rings in */
+ i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
+ temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
+ if (!temp_ring)
+ return -ENOMEM;
+
+ ngbe_down(wx);
+
+ wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
+ kvfree(temp_ring);
+
+ wx_configure(wx);
+ ngbe_up(wx);
+
+ return 0;
+}
+
+static int ngbe_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
+{
+ int err;
+
+ err = wx_set_channels(dev, ch);
+ if (err < 0)
+ return err;
+
+ /* use setup TC to update any traffic class queue mapping */
+ return ngbe_setup_tc(dev, netdev_get_num_tc(dev));
+}
+
static const struct ethtool_ops ngbe_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
.get_drvinfo = wx_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
- .nway_reset = phy_ethtool_nway_reset,
+ .get_link_ksettings = wx_get_link_ksettings,
+ .set_link_ksettings = wx_set_link_ksettings,
+ .nway_reset = wx_nway_reset,
.get_wol = ngbe_get_wol,
.set_wol = ngbe_set_wol,
.get_sset_count = wx_get_sset_count,
@@ -54,6 +120,16 @@ static const struct ethtool_ops ngbe_ethtool_ops = {
.get_ethtool_stats = wx_get_ethtool_stats,
.get_eth_mac_stats = wx_get_mac_stats,
.get_pause_stats = wx_get_pause_stats,
+ .get_pauseparam = wx_get_pauseparam,
+ .set_pauseparam = wx_set_pauseparam,
+ .get_ringparam = wx_get_ringparam,
+ .set_ringparam = ngbe_set_ringparam,
+ .get_coalesce = wx_get_coalesce,
+ .set_coalesce = wx_set_coalesce,
+ .get_channels = wx_get_channels,
+ .set_channels = ngbe_set_channels,
+ .get_msglevel = wx_get_msglevel,
+ .set_msglevel = wx_set_msglevel,
};
void ngbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
index 8db804543e66..fdd6b4f70b7a 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_main.c
@@ -80,28 +80,6 @@ static void ngbe_init_type_code(struct wx *wx)
}
/**
- * ngbe_init_rss_key - Initialize wx RSS key
- * @wx: device handle
- *
- * Allocates and initializes the RSS key if it is not allocated.
- **/
-static inline int ngbe_init_rss_key(struct wx *wx)
-{
- u32 *rss_key;
-
- if (!wx->rss_key) {
- rss_key = kzalloc(WX_RSS_KEY_SIZE, GFP_KERNEL);
- if (unlikely(!rss_key))
- return -ENOMEM;
-
- netdev_rss_key_fill(rss_key, WX_RSS_KEY_SIZE);
- wx->rss_key = rss_key;
- }
-
- return 0;
-}
-
-/**
* ngbe_sw_init - Initialize general software structures
* @wx: board private structure to initialize
**/
@@ -134,8 +112,9 @@ static int ngbe_sw_init(struct wx *wx)
dev_err(&pdev->dev, "Do not support MSI-X\n");
wx->mac.max_msix_vectors = msix_count;
- if (ngbe_init_rss_key(wx))
- return -ENOMEM;
+ wx->ring_feature[RING_F_RSS].limit = min_t(int, NGBE_MAX_RSS_INDICES,
+ num_online_cpus());
+ wx->rss_enabled = true;
/* enable itr by default in dynamic mode */
wx->rx_itr_setting = 1;
@@ -175,7 +154,7 @@ static void ngbe_irq_enable(struct wx *wx, bool queues)
if (queues)
wx_intr_enable(wx, NGBE_INTR_ALL);
else
- wx_intr_enable(wx, NGBE_INTR_MISC(wx));
+ wx_intr_enable(wx, NGBE_INTR_MISC);
}
/**
@@ -241,7 +220,7 @@ static int ngbe_request_msix_irqs(struct wx *wx)
for (vector = 0; vector < wx->num_q_vectors; vector++) {
struct wx_q_vector *q_vector = wx->q_vector[vector];
- struct msix_entry *entry = &wx->msix_entries[vector];
+ struct msix_entry *entry = &wx->msix_q_entries[vector];
if (q_vector->tx.ring && q_vector->rx.ring)
snprintf(q_vector->name, sizeof(q_vector->name) - 1,
@@ -259,7 +238,7 @@ static int ngbe_request_msix_irqs(struct wx *wx)
}
}
- err = request_irq(wx->msix_entries[vector].vector,
+ err = request_irq(wx->msix_entry->vector,
ngbe_msix_other, 0, netdev->name, wx);
if (err) {
@@ -272,7 +251,7 @@ static int ngbe_request_msix_irqs(struct wx *wx)
free_queue_irqs:
while (vector) {
vector--;
- free_irq(wx->msix_entries[vector].vector,
+ free_irq(wx->msix_q_entries[vector].vector,
wx->q_vector[vector]);
}
wx_reset_interrupt_capability(wx);
@@ -334,15 +313,15 @@ static void ngbe_disable_device(struct wx *wx)
wx_update_stats(wx);
}
-static void ngbe_down(struct wx *wx)
+void ngbe_down(struct wx *wx)
{
- phy_stop(wx->phydev);
+ phylink_stop(wx->phylink);
ngbe_disable_device(wx);
wx_clean_all_tx_rings(wx);
wx_clean_all_rx_rings(wx);
}
-static void ngbe_up(struct wx *wx)
+void ngbe_up(struct wx *wx)
{
wx_configure_vectors(wx);
@@ -359,7 +338,7 @@ static void ngbe_up(struct wx *wx)
if (wx->gpio_ctrl)
ngbe_sfp_modules_txrx_powerctl(wx, true);
- phy_start(wx->phydev);
+ phylink_start(wx->phylink);
}
/**
@@ -388,7 +367,7 @@ static int ngbe_open(struct net_device *netdev)
if (err)
goto err_free_resources;
- err = ngbe_phy_connect(wx);
+ err = phylink_connect_phy(wx->phylink, wx->phydev);
if (err)
goto err_free_irq;
@@ -404,7 +383,7 @@ static int ngbe_open(struct net_device *netdev)
return 0;
err_dis_phy:
- phy_disconnect(wx->phydev);
+ phylink_disconnect_phy(wx->phylink);
err_free_irq:
wx_free_irq(wx);
err_free_resources:
@@ -430,7 +409,7 @@ static int ngbe_close(struct net_device *netdev)
ngbe_down(wx);
wx_free_irq(wx);
wx_free_resources(wx);
- phy_disconnect(wx->phydev);
+ phylink_disconnect_phy(wx->phylink);
wx_control_hw(wx, false);
return 0;
@@ -480,6 +459,39 @@ static void ngbe_shutdown(struct pci_dev *pdev)
}
}
+/**
+ * ngbe_setup_tc - routine to configure net_device for multiple traffic
+ * classes.
+ *
+ * @dev: net device to configure
+ * @tc: number of traffic classes to enable
+ */
+int ngbe_setup_tc(struct net_device *dev, u8 tc)
+{
+ struct wx *wx = netdev_priv(dev);
+
+ /* Hardware has to reinitialize queues and interrupts to
+ * match packet buffer alignment. Unfortunately, the
+ * hardware is not flexible enough to do this dynamically.
+ */
+ if (netif_running(dev))
+ ngbe_close(dev);
+
+ wx_clear_interrupt_scheme(wx);
+
+ if (tc)
+ netdev_set_num_tc(dev, tc);
+ else
+ netdev_reset_tc(dev);
+
+ wx_init_interrupt_scheme(wx);
+
+ if (netif_running(dev))
+ ngbe_open(dev);
+
+ return 0;
+}
+
static const struct net_device_ops ngbe_netdev_ops = {
.ndo_open = ngbe_open,
.ndo_stop = ngbe_close,
@@ -582,6 +594,7 @@ static int ngbe_probe(struct pci_dev *pdev,
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
+ netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE -
@@ -680,6 +693,7 @@ static int ngbe_probe(struct pci_dev *pdev,
return 0;
err_register:
+ phylink_destroy(wx->phylink);
wx_control_hw(wx, false);
err_clear_interrupt_scheme:
wx_clear_interrupt_scheme(wx);
@@ -709,9 +723,11 @@ static void ngbe_remove(struct pci_dev *pdev)
netdev = wx->netdev;
unregister_netdev(netdev);
+ phylink_destroy(wx->phylink);
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
+ kfree(wx->rss_key);
kfree(wx->mac_table);
wx_clear_interrupt_scheme(wx);
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
index 6302ecca71bb..ec54b18c5fe7 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.c
@@ -56,22 +56,28 @@ static int ngbe_phy_write_reg_c22(struct mii_bus *bus, int phy_addr,
return ret;
}
-static void ngbe_handle_link_change(struct net_device *dev)
+static void ngbe_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
{
- struct wx *wx = netdev_priv(dev);
- struct phy_device *phydev;
+}
+
+static void ngbe_mac_link_down(struct phylink_config *config,
+ unsigned int mode, phy_interface_t interface)
+{
+}
+
+static void ngbe_mac_link_up(struct phylink_config *config,
+ struct phy_device *phy,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct wx *wx = phylink_to_wx(config);
u32 lan_speed, reg;
- phydev = wx->phydev;
- if (!(wx->link != phydev->link ||
- wx->speed != phydev->speed ||
- wx->duplex != phydev->duplex))
- return;
+ wx_fc_enable(wx, tx_pause, rx_pause);
- wx->link = phydev->link;
- wx->speed = phydev->speed;
- wx->duplex = phydev->duplex;
- switch (phydev->speed) {
+ switch (speed) {
case SPEED_10:
lan_speed = 0;
break;
@@ -83,54 +89,51 @@ static void ngbe_handle_link_change(struct net_device *dev)
lan_speed = 2;
break;
}
+
wr32m(wx, NGBE_CFG_LAN_SPEED, 0x3, lan_speed);
- if (phydev->link) {
- reg = rd32(wx, WX_MAC_TX_CFG);
- reg &= ~WX_MAC_TX_CFG_SPEED_MASK;
- reg |= WX_MAC_TX_CFG_SPEED_1G | WX_MAC_TX_CFG_TE;
- wr32(wx, WX_MAC_TX_CFG, reg);
- /* Re configure MAC RX */
- reg = rd32(wx, WX_MAC_RX_CFG);
- wr32(wx, WX_MAC_RX_CFG, reg);
- wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
- reg = rd32(wx, WX_MAC_WDG_TIMEOUT);
- wr32(wx, WX_MAC_WDG_TIMEOUT, reg);
- }
- phy_print_status(phydev);
+ reg = rd32(wx, WX_MAC_TX_CFG);
+ reg &= ~WX_MAC_TX_CFG_SPEED_MASK;
+ reg |= WX_MAC_TX_CFG_SPEED_1G | WX_MAC_TX_CFG_TE;
+ wr32(wx, WX_MAC_TX_CFG, reg);
+
+ /* Re configure MAC Rx */
+ reg = rd32(wx, WX_MAC_RX_CFG);
+ wr32(wx, WX_MAC_RX_CFG, reg);
+ wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
+ reg = rd32(wx, WX_MAC_WDG_TIMEOUT);
+ wr32(wx, WX_MAC_WDG_TIMEOUT, reg);
}
-int ngbe_phy_connect(struct wx *wx)
+static const struct phylink_mac_ops ngbe_mac_ops = {
+ .mac_config = ngbe_mac_config,
+ .mac_link_down = ngbe_mac_link_down,
+ .mac_link_up = ngbe_mac_link_up,
+};
+
+static int ngbe_phylink_init(struct wx *wx)
{
- int ret;
+ struct phylink_config *config;
+ phy_interface_t phy_mode;
+ struct phylink *phylink;
- ret = phy_connect_direct(wx->netdev,
- wx->phydev,
- ngbe_handle_link_change,
- PHY_INTERFACE_MODE_RGMII_ID);
- if (ret) {
- wx_err(wx, "PHY connect failed.\n");
- return ret;
- }
+ config = &wx->phylink_config;
+ config->dev = &wx->netdev->dev;
+ config->type = PHYLINK_NETDEV;
+ config->mac_capabilities = MAC_1000FD | MAC_100FD | MAC_10FD |
+ MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+ config->mac_managed_pm = true;
- return 0;
-}
+ phy_mode = PHY_INTERFACE_MODE_RGMII_ID;
+ __set_bit(PHY_INTERFACE_MODE_RGMII_ID, config->supported_interfaces);
-static void ngbe_phy_fixup(struct wx *wx)
-{
- struct phy_device *phydev = wx->phydev;
- struct ethtool_eee eee;
-
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT);
- phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
-
- phydev->mac_managed_pm = true;
- if (wx->mac_type != em_mac_type_mdi)
- return;
- /* disable EEE, internal phy does not support eee */
- memset(&eee, 0, sizeof(eee));
- phy_ethtool_set_eee(phydev, &eee);
+ phylink = phylink_create(config, NULL, phy_mode, &ngbe_mac_ops);
+ if (IS_ERR(phylink))
+ return PTR_ERR(phylink);
+
+ wx->phylink = phylink;
+
+ return 0;
}
int ngbe_mdio_init(struct wx *wx)
@@ -165,11 +168,16 @@ int ngbe_mdio_init(struct wx *wx)
return -ENODEV;
phy_attached_info(wx->phydev);
- ngbe_phy_fixup(wx);
wx->link = 0;
wx->speed = 0;
wx->duplex = 0;
+ ret = ngbe_phylink_init(wx);
+ if (ret) {
+ wx_err(wx, "failed to init phylink: %d\n", ret);
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.h
index 0a6400dd89c4..f610b771888a 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_mdio.h
@@ -7,6 +7,5 @@
#ifndef _NGBE_MDIO_H_
#define _NGBE_MDIO_H_
-int ngbe_phy_connect(struct wx *wx);
int ngbe_mdio_init(struct wx *wx);
#endif /* _NGBE_MDIO_H_ */
diff --git a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
index ff754d69bdf6..f48ed7fc1805 100644
--- a/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
+++ b/drivers/net/ethernet/wangxun/ngbe/ngbe_type.h
@@ -80,7 +80,7 @@
NGBE_PX_MISC_IEN_GPIO)
#define NGBE_INTR_ALL 0x1FF
-#define NGBE_INTR_MISC(A) BIT((A)->num_q_vectors)
+#define NGBE_INTR_MISC BIT(0)
#define NGBE_PHY_CONFIG(reg_offset) (0x14000 + ((reg_offset) * 4))
#define NGBE_CFG_LAN_SPEED 0x14440
@@ -105,6 +105,7 @@
#define NGBE_FW_CMD_ST_FAIL 0x70657376
#define NGBE_MAX_FDIR_INDICES 7
+#define NGBE_MAX_RSS_INDICES 8
#define NGBE_MAX_RX_QUEUES (NGBE_MAX_FDIR_INDICES + 1)
#define NGBE_MAX_TX_QUEUES (NGBE_MAX_FDIR_INDICES + 1)
@@ -130,4 +131,8 @@
extern char ngbe_driver_name[];
+void ngbe_down(struct wx *wx);
+void ngbe_up(struct wx *wx);
+int ngbe_setup_tc(struct net_device *dev, u8 tc);
+
#endif /* _NGBE_TYPE_H_ */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
index 3f336a088e43..db675512ce4d 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
@@ -7,43 +7,93 @@
#include "../libwx/wx_ethtool.h"
#include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
#include "txgbe_type.h"
#include "txgbe_ethtool.h"
-static int txgbe_nway_reset(struct net_device *netdev)
+static int txgbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack)
{
- struct txgbe *txgbe = netdev_to_txgbe(netdev);
+ struct wx *wx = netdev_priv(netdev);
+ u32 new_rx_count, new_tx_count;
+ struct wx_ring *temp_ring;
+ int i;
- return phylink_ethtool_nway_reset(txgbe->phylink);
-}
+ new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
-static int txgbe_get_link_ksettings(struct net_device *netdev,
- struct ethtool_link_ksettings *cmd)
-{
- struct txgbe *txgbe = netdev_to_txgbe(netdev);
+ new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ if (new_tx_count == wx->tx_ring_count &&
+ new_rx_count == wx->rx_ring_count)
+ return 0;
+
+ if (!netif_running(wx->netdev)) {
+ for (i = 0; i < wx->num_tx_queues; i++)
+ wx->tx_ring[i]->count = new_tx_count;
+ for (i = 0; i < wx->num_rx_queues; i++)
+ wx->rx_ring[i]->count = new_rx_count;
+ wx->tx_ring_count = new_tx_count;
+ wx->rx_ring_count = new_rx_count;
+
+ return 0;
+ }
- return phylink_ethtool_ksettings_get(txgbe->phylink, cmd);
+ /* allocate temporary buffer to store rings in */
+ i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
+ temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
+ if (!temp_ring)
+ return -ENOMEM;
+
+ txgbe_down(wx);
+
+ wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
+ kvfree(temp_ring);
+
+ txgbe_up(wx);
+
+ return 0;
}
-static int txgbe_set_link_ksettings(struct net_device *netdev,
- const struct ethtool_link_ksettings *cmd)
+static int txgbe_set_channels(struct net_device *dev,
+ struct ethtool_channels *ch)
{
- struct txgbe *txgbe = netdev_to_txgbe(netdev);
+ int err;
+
+ err = wx_set_channels(dev, ch);
+ if (err < 0)
+ return err;
- return phylink_ethtool_ksettings_set(txgbe->phylink, cmd);
+ /* use setup TC to update any traffic class queue mapping */
+ return txgbe_setup_tc(dev, netdev_get_num_tc(dev));
}
static const struct ethtool_ops txgbe_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
+ ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
.get_drvinfo = wx_get_drvinfo,
- .nway_reset = txgbe_nway_reset,
+ .nway_reset = wx_nway_reset,
.get_link = ethtool_op_get_link,
- .get_link_ksettings = txgbe_get_link_ksettings,
- .set_link_ksettings = txgbe_set_link_ksettings,
+ .get_link_ksettings = wx_get_link_ksettings,
+ .set_link_ksettings = wx_set_link_ksettings,
.get_sset_count = wx_get_sset_count,
.get_strings = wx_get_strings,
.get_ethtool_stats = wx_get_ethtool_stats,
.get_eth_mac_stats = wx_get_mac_stats,
.get_pause_stats = wx_get_pause_stats,
+ .get_pauseparam = wx_get_pauseparam,
+ .set_pauseparam = wx_set_pauseparam,
+ .get_ringparam = wx_get_ringparam,
+ .set_ringparam = txgbe_set_ringparam,
+ .get_coalesce = wx_get_coalesce,
+ .set_coalesce = wx_set_coalesce,
+ .get_channels = wx_get_channels,
+ .set_channels = txgbe_set_channels,
+ .get_msglevel = wx_get_msglevel,
+ .set_msglevel = wx_set_msglevel,
};
void txgbe_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 526250102db2..3b151c410a5c 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -86,7 +86,7 @@ static void txgbe_irq_enable(struct wx *wx, bool queues)
wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK);
/* unmask interrupt */
- wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
+ wx_intr_enable(wx, TXGBE_INTR_MISC);
if (queues)
wx_intr_enable(wx, TXGBE_INTR_QALL(wx));
}
@@ -145,7 +145,7 @@ static int txgbe_request_msix_irqs(struct wx *wx)
for (vector = 0; vector < wx->num_q_vectors; vector++) {
struct wx_q_vector *q_vector = wx->q_vector[vector];
- struct msix_entry *entry = &wx->msix_entries[vector];
+ struct msix_entry *entry = &wx->msix_q_entries[vector];
if (q_vector->tx.ring && q_vector->rx.ring)
snprintf(q_vector->name, sizeof(q_vector->name) - 1,
@@ -168,7 +168,7 @@ static int txgbe_request_msix_irqs(struct wx *wx)
free_queue_irqs:
while (vector) {
vector--;
- free_irq(wx->msix_entries[vector].vector,
+ free_irq(wx->msix_q_entries[vector].vector,
wx->q_vector[vector]);
}
wx_reset_interrupt_capability(wx);
@@ -206,7 +206,6 @@ static int txgbe_request_irq(struct wx *wx)
static void txgbe_up_complete(struct wx *wx)
{
struct net_device *netdev = wx->netdev;
- struct txgbe *txgbe;
wx_control_hw(wx, true);
wx_configure_vectors(wx);
@@ -215,8 +214,7 @@ static void txgbe_up_complete(struct wx *wx)
smp_mb__before_atomic();
wx_napi_enable_all(wx);
- txgbe = netdev_to_txgbe(netdev);
- phylink_start(txgbe->phylink);
+ phylink_start(wx->phylink);
/* clear any pending interrupts, may auto mask */
rd32(wx, WX_PX_IC(0));
@@ -290,18 +288,22 @@ static void txgbe_disable_device(struct wx *wx)
wx_update_stats(wx);
}
-static void txgbe_down(struct wx *wx)
+void txgbe_down(struct wx *wx)
{
- struct txgbe *txgbe = netdev_to_txgbe(wx->netdev);
-
txgbe_disable_device(wx);
txgbe_reset(wx);
- phylink_stop(txgbe->phylink);
+ phylink_stop(wx->phylink);
wx_clean_all_tx_rings(wx);
wx_clean_all_rx_rings(wx);
}
+void txgbe_up(struct wx *wx)
+{
+ wx_configure(wx);
+ txgbe_up_complete(wx);
+}
+
/**
* txgbe_init_type_code - Initialize the shared code
* @wx: pointer to hardware structure
@@ -376,6 +378,10 @@ static int txgbe_sw_init(struct wx *wx)
wx_err(wx, "Do not support MSI-X\n");
wx->mac.max_msix_vectors = msix_count;
+ wx->ring_feature[RING_F_RSS].limit = min_t(int, TXGBE_MAX_RSS_INDICES,
+ num_online_cpus());
+ wx->rss_enabled = true;
+
/* enable itr by default in dynamic mode */
wx->rx_itr_setting = 1;
wx->tx_itr_setting = 1;
@@ -502,6 +508,41 @@ static void txgbe_shutdown(struct pci_dev *pdev)
}
}
+/**
+ * txgbe_setup_tc - routine to configure net_device for multiple traffic
+ * classes.
+ *
+ * @dev: net device to configure
+ * @tc: number of traffic classes to enable
+ */
+int txgbe_setup_tc(struct net_device *dev, u8 tc)
+{
+ struct wx *wx = netdev_priv(dev);
+
+ /* Hardware has to reinitialize queues and interrupts to
+ * match packet buffer alignment. Unfortunately, the
+ * hardware is not flexible enough to do this dynamically.
+ */
+ if (netif_running(dev))
+ txgbe_close(dev);
+ else
+ txgbe_reset(wx);
+
+ wx_clear_interrupt_scheme(wx);
+
+ if (tc)
+ netdev_set_num_tc(dev, tc);
+ else
+ netdev_reset_tc(dev);
+
+ wx_init_interrupt_scheme(wx);
+
+ if (netif_running(dev))
+ txgbe_open(dev);
+
+ return 0;
+}
+
static const struct net_device_ops txgbe_netdev_ops = {
.ndo_open = txgbe_open,
.ndo_stop = txgbe_close,
@@ -638,6 +679,7 @@ static int txgbe_probe(struct pci_dev *pdev,
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
+ netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
netdev->min_mtu = ETH_MIN_MTU;
netdev->max_mtu = WX_MAX_JUMBO_FRAME_SIZE -
@@ -775,6 +817,7 @@ static void txgbe_remove(struct pci_dev *pdev)
pci_release_selected_regions(pdev,
pci_select_bars(pdev, IORESOURCE_MEM));
+ kfree(wx->rss_key);
kfree(wx->mac_table);
wx_clear_interrupt_scheme(wx);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index b6c06adb8656..1b84d495d14e 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -159,7 +159,8 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe)
static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *config,
phy_interface_t interface)
{
- struct txgbe *txgbe = netdev_to_txgbe(to_net_dev(config->dev));
+ struct wx *wx = phylink_to_wx(config);
+ struct txgbe *txgbe = wx->priv;
if (interface == PHY_INTERFACE_MODE_10GBASER)
return &txgbe->xpcs->pcs;
@@ -175,7 +176,7 @@ static void txgbe_mac_config(struct phylink_config *config, unsigned int mode,
static void txgbe_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
- struct wx *wx = netdev_priv(to_net_dev(config->dev));
+ struct wx *wx = phylink_to_wx(config);
wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
}
@@ -186,9 +187,11 @@ static void txgbe_mac_link_up(struct phylink_config *config,
int speed, int duplex,
bool tx_pause, bool rx_pause)
{
- struct wx *wx = netdev_priv(to_net_dev(config->dev));
+ struct wx *wx = phylink_to_wx(config);
u32 txcfg, wdg;
+ wx_fc_enable(wx, tx_pause, rx_pause);
+
txcfg = rd32(wx, WX_MAC_TX_CFG);
txcfg &= ~WX_MAC_TX_CFG_SPEED_MASK;
@@ -217,7 +220,7 @@ static void txgbe_mac_link_up(struct phylink_config *config,
static int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
- struct wx *wx = netdev_priv(to_net_dev(config->dev));
+ struct wx *wx = phylink_to_wx(config);
wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
@@ -228,7 +231,7 @@ static int txgbe_mac_prepare(struct phylink_config *config, unsigned int mode,
static int txgbe_mac_finish(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
- struct wx *wx = netdev_priv(to_net_dev(config->dev));
+ struct wx *wx = phylink_to_wx(config);
txgbe_enable_sec_tx_path(wx);
wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
@@ -253,10 +256,7 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
phy_interface_t phy_mode;
struct phylink *phylink;
- config = devm_kzalloc(&wx->pdev->dev, sizeof(*config), GFP_KERNEL);
- if (!config)
- return -ENOMEM;
-
+ config = &wx->phylink_config;
config->dev = &wx->netdev->dev;
config->type = PHYLINK_NETDEV;
config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_100FD |
@@ -287,7 +287,7 @@ static int txgbe_phylink_init(struct txgbe *txgbe)
}
}
- txgbe->phylink = phylink;
+ wx->phylink = phylink;
return 0;
}
@@ -483,11 +483,11 @@ static void txgbe_irq_handler(struct irq_desc *desc)
TXGBE_PX_MISC_ETH_AN)) {
u32 reg = rd32(wx, TXGBE_CFG_PORT_ST);
- phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
+ phylink_mac_change(wx->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP));
}
/* unmask interrupt */
- wx_intr_enable(wx, TXGBE_INTR_MISC(wx));
+ wx_intr_enable(wx, TXGBE_INTR_MISC);
}
static int txgbe_gpio_init(struct txgbe *txgbe)
@@ -531,7 +531,12 @@ static int txgbe_gpio_init(struct txgbe *txgbe)
sizeof(*girq->parents), GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
- girq->parents[0] = wx->msix_entries[wx->num_q_vectors].vector;
+
+ /* now only suuported on MSI-X interrupt */
+ if (!wx->msix_entry)
+ return -EPERM;
+
+ girq->parents[0] = wx->msix_entry->vector;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
@@ -701,6 +706,7 @@ static int txgbe_ext_phy_init(struct txgbe *txgbe)
int txgbe_init_phy(struct txgbe *txgbe)
{
+ struct wx *wx = txgbe->wx;
int ret;
if (txgbe->wx->media_type == sp_media_copper)
@@ -708,46 +714,48 @@ int txgbe_init_phy(struct txgbe *txgbe)
ret = txgbe_swnodes_register(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to register software nodes\n");
+ wx_err(wx, "failed to register software nodes\n");
return ret;
}
ret = txgbe_mdio_pcs_init(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to init mdio pcs: %d\n", ret);
+ wx_err(wx, "failed to init mdio pcs: %d\n", ret);
goto err_unregister_swnode;
}
ret = txgbe_phylink_init(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to init phylink\n");
+ wx_err(wx, "failed to init phylink\n");
goto err_destroy_xpcs;
}
ret = txgbe_gpio_init(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to init gpio\n");
+ wx_err(wx, "failed to init gpio\n");
goto err_destroy_phylink;
}
ret = txgbe_clock_register(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to register clock: %d\n", ret);
+ wx_err(wx, "failed to register clock: %d\n", ret);
goto err_destroy_phylink;
}
ret = txgbe_i2c_register(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret);
+ wx_err(wx, "failed to init i2c interface: %d\n", ret);
goto err_unregister_clk;
}
ret = txgbe_sfp_register(txgbe);
if (ret) {
- wx_err(txgbe->wx, "failed to register sfp\n");
+ wx_err(wx, "failed to register sfp\n");
goto err_unregister_i2c;
}
+ wx->msix_in_use = true;
+
return 0;
err_unregister_i2c:
@@ -756,7 +764,7 @@ err_unregister_clk:
clkdev_drop(txgbe->clock);
clk_unregister(txgbe->clk);
err_destroy_phylink:
- phylink_destroy(txgbe->phylink);
+ phylink_destroy(wx->phylink);
err_destroy_xpcs:
xpcs_destroy(txgbe->xpcs);
err_unregister_swnode:
@@ -768,8 +776,8 @@ err_unregister_swnode:
void txgbe_remove_phy(struct txgbe *txgbe)
{
if (txgbe->wx->media_type == sp_media_copper) {
- phylink_disconnect_phy(txgbe->phylink);
- phylink_destroy(txgbe->phylink);
+ phylink_disconnect_phy(txgbe->wx->phylink);
+ phylink_destroy(txgbe->wx->phylink);
return;
}
@@ -777,7 +785,8 @@ void txgbe_remove_phy(struct txgbe *txgbe)
platform_device_unregister(txgbe->i2c_dev);
clkdev_drop(txgbe->clock);
clk_unregister(txgbe->clk);
- phylink_destroy(txgbe->phylink);
+ phylink_destroy(txgbe->wx->phylink);
xpcs_destroy(txgbe->xpcs);
software_node_unregister_node_group(txgbe->nodes.group);
+ txgbe->wx->msix_in_use = false;
}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index 3ba9ce43f394..270a6fd9ad0b 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -98,6 +98,7 @@
#define TXGBE_MAX_MSIX_VECTORS 64
#define TXGBE_MAX_FDIR_INDICES 63
+#define TXGBE_MAX_RSS_INDICES 63
#define TXGBE_MAX_RX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1)
#define TXGBE_MAX_TX_QUEUES (TXGBE_MAX_FDIR_INDICES + 1)
@@ -122,19 +123,16 @@
#define TXGBE_DEFAULT_RX_WORK 128
#endif
-#define TXGBE_INTR_MISC(A) BIT((A)->num_q_vectors)
-#define TXGBE_INTR_QALL(A) (TXGBE_INTR_MISC(A) - 1)
+#define TXGBE_INTR_MISC BIT(0)
+#define TXGBE_INTR_QALL(A) GENMASK((A)->num_q_vectors, 1)
#define TXGBE_MAX_EITR GENMASK(11, 3)
extern char txgbe_driver_name[];
-static inline struct txgbe *netdev_to_txgbe(struct net_device *netdev)
-{
- struct wx *wx = netdev_priv(netdev);
-
- return wx->priv;
-}
+void txgbe_down(struct wx *wx);
+void txgbe_up(struct wx *wx);
+int txgbe_setup_tc(struct net_device *dev, u8 tc);
#define NODE_PROP(_NAME, _PROP) \
(const struct software_node) { \
@@ -175,7 +173,6 @@ struct txgbe {
struct wx *wx;
struct txgbe_nodes nodes;
struct dw_xpcs *xpcs;
- struct phylink *phylink;
struct platform_device *sfp_dev;
struct platform_device *i2c_dev;
struct clk_lookup *clock;
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 0014729b8865..35d96c633a33 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -26,6 +26,7 @@ config XILINX_EMACLITE
config XILINX_AXI_EMAC
tristate "Xilinx 10/100/1000 AXI Ethernet support"
depends on HAS_IOMEM
+ depends on XILINX_DMA
select PHYLINK
help
This driver supports the 10/100/1000 Ethernet from Xilinx for the
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h
index 575ff9de8985..807ead678551 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet.h
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h
@@ -14,6 +14,7 @@
#include <linux/interrupt.h>
#include <linux/if_vlan.h>
#include <linux/phylink.h>
+#include <linux/skbuff.h>
/* Packet size info */
#define XAE_HDR_SIZE 14 /* Size of Ethernet header */
@@ -379,6 +380,22 @@ struct axidma_bd {
#define XAE_NUM_MISC_CLOCKS 3
/**
+ * struct skbuf_dma_descriptor - skb for each dma descriptor
+ * @sgl: Pointer for sglist.
+ * @desc: Pointer to dma descriptor.
+ * @dma_address: dma address of sglist.
+ * @skb: Pointer to SKB transferred using DMA
+ * @sg_len: number of entries in the sglist.
+ */
+struct skbuf_dma_descriptor {
+ struct scatterlist sgl[MAX_SKB_FRAGS + 1];
+ struct dma_async_tx_descriptor *desc;
+ dma_addr_t dma_address;
+ struct sk_buff *skb;
+ int sg_len;
+};
+
+/**
* struct axienet_local - axienet private per device data
* @ndev: Pointer for net_device to which it will be attached.
* @dev: Pointer to device structure
@@ -435,6 +452,15 @@ struct axidma_bd {
* @coalesce_usec_rx: IRQ coalesce delay for RX
* @coalesce_count_tx: Store the irq coalesce on TX side.
* @coalesce_usec_tx: IRQ coalesce delay for TX
+ * @use_dmaengine: flag to check dmaengine framework usage.
+ * @tx_chan: TX DMA channel.
+ * @rx_chan: RX DMA channel.
+ * @tx_skb_ring: Pointer to TX skb ring buffer array.
+ * @rx_skb_ring: Pointer to RX skb ring buffer array.
+ * @tx_ring_head: TX skb ring buffer head index.
+ * @tx_ring_tail: TX skb ring buffer tail index.
+ * @rx_ring_head: RX skb ring buffer head index.
+ * @rx_ring_tail: RX skb ring buffer tail index.
*/
struct axienet_local {
struct net_device *ndev;
@@ -499,6 +525,15 @@ struct axienet_local {
u32 coalesce_usec_rx;
u32 coalesce_count_tx;
u32 coalesce_usec_tx;
+ u8 use_dmaengine;
+ struct dma_chan *tx_chan;
+ struct dma_chan *rx_chan;
+ struct skbuf_dma_descriptor **tx_skb_ring;
+ struct skbuf_dma_descriptor **rx_skb_ring;
+ int tx_ring_head;
+ int tx_ring_tail;
+ int rx_ring_head;
+ int rx_ring_tail;
};
/**
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index bf6e33990490..aaf780fd4f5e 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -38,6 +38,11 @@
#include <linux/phy.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/xilinx_dma.h>
+#include <linux/circ_buf.h>
+#include <net/netdev_queues.h>
#include "xilinx_axienet.h"
@@ -47,6 +52,9 @@
#define TX_BD_NUM_MIN (MAX_SKB_FRAGS + 1)
#define TX_BD_NUM_MAX 4096
#define RX_BD_NUM_MAX 4096
+#define DMA_NUM_APP_WORDS 5
+#define LEN_APP 4
+#define RX_BUF_NUM_DEFAULT 128
/* Must be shorter than length of ethtool_drvinfo.driver field to fit */
#define DRIVER_NAME "xaxienet"
@@ -55,6 +63,8 @@
#define AXIENET_REGS_N 40
+static void axienet_rx_submit_desc(struct net_device *ndev);
+
/* Match table for of_platform binding */
static const struct of_device_id axienet_of_match[] = {
{ .compatible = "xlnx,axi-ethernet-1.00.a", },
@@ -120,6 +130,16 @@ static struct axienet_option axienet_options[] = {
{}
};
+static struct skbuf_dma_descriptor *axienet_get_rx_desc(struct axienet_local *lp, int i)
+{
+ return lp->rx_skb_ring[i & (RX_BUF_NUM_DEFAULT - 1)];
+}
+
+static struct skbuf_dma_descriptor *axienet_get_tx_desc(struct axienet_local *lp, int i)
+{
+ return lp->tx_skb_ring[i & (TX_BD_NUM_MAX - 1)];
+}
+
/**
* axienet_dma_in32 - Memory mapped Axi DMA register read
* @lp: Pointer to axienet local structure
@@ -589,10 +609,6 @@ static int axienet_device_reset(struct net_device *ndev)
struct axienet_local *lp = netdev_priv(ndev);
int ret;
- ret = __axienet_device_reset(lp);
- if (ret)
- return ret;
-
lp->max_frm_size = XAE_MAX_VLAN_FRAME_SIZE;
lp->options |= XAE_OPTION_VLAN;
lp->options &= (~XAE_OPTION_JUMBO);
@@ -606,11 +622,17 @@ static int axienet_device_reset(struct net_device *ndev)
lp->options |= XAE_OPTION_JUMBO;
}
- ret = axienet_dma_bd_init(ndev);
- if (ret) {
- netdev_err(ndev, "%s: descriptor allocation failed\n",
- __func__);
- return ret;
+ if (!lp->use_dmaengine) {
+ ret = __axienet_device_reset(lp);
+ if (ret)
+ return ret;
+
+ ret = axienet_dma_bd_init(ndev);
+ if (ret) {
+ netdev_err(ndev, "%s: descriptor allocation failed\n",
+ __func__);
+ return ret;
+ }
}
axienet_status = axienet_ior(lp, XAE_RCW1_OFFSET);
@@ -726,6 +748,128 @@ static inline int axienet_check_tx_bd_space(struct axienet_local *lp,
}
/**
+ * axienet_dma_tx_cb - DMA engine callback for TX channel.
+ * @data: Pointer to the axienet_local structure.
+ * @result: error reporting through dmaengine_result.
+ * This function is called by dmaengine driver for TX channel to notify
+ * that the transmit is done.
+ */
+static void axienet_dma_tx_cb(void *data, const struct dmaengine_result *result)
+{
+ struct skbuf_dma_descriptor *skbuf_dma;
+ struct axienet_local *lp = data;
+ struct netdev_queue *txq;
+ int len;
+
+ skbuf_dma = axienet_get_tx_desc(lp, lp->tx_ring_tail++);
+ len = skbuf_dma->skb->len;
+ txq = skb_get_tx_queue(lp->ndev, skbuf_dma->skb);
+ u64_stats_update_begin(&lp->tx_stat_sync);
+ u64_stats_add(&lp->tx_bytes, len);
+ u64_stats_add(&lp->tx_packets, 1);
+ u64_stats_update_end(&lp->tx_stat_sync);
+ dma_unmap_sg(lp->dev, skbuf_dma->sgl, skbuf_dma->sg_len, DMA_TO_DEVICE);
+ dev_consume_skb_any(skbuf_dma->skb);
+ netif_txq_completed_wake(txq, 1, len,
+ CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX),
+ 2 * MAX_SKB_FRAGS);
+}
+
+/**
+ * axienet_start_xmit_dmaengine - Starts the transmission.
+ * @skb: sk_buff pointer that contains data to be Txed.
+ * @ndev: Pointer to net_device structure.
+ *
+ * Return: NETDEV_TX_OK on success or any non space errors.
+ * NETDEV_TX_BUSY when free element in TX skb ring buffer
+ * is not available.
+ *
+ * This function is invoked to initiate transmission. The
+ * function sets the skbs, register dma callback API and submit
+ * the dma transaction.
+ * Additionally if checksum offloading is supported,
+ * it populates AXI Stream Control fields with appropriate values.
+ */
+static netdev_tx_t
+axienet_start_xmit_dmaengine(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct dma_async_tx_descriptor *dma_tx_desc = NULL;
+ struct axienet_local *lp = netdev_priv(ndev);
+ u32 app_metadata[DMA_NUM_APP_WORDS] = {0};
+ struct skbuf_dma_descriptor *skbuf_dma;
+ struct dma_device *dma_dev;
+ struct netdev_queue *txq;
+ u32 csum_start_off;
+ u32 csum_index_off;
+ int sg_len;
+ int ret;
+
+ dma_dev = lp->tx_chan->device;
+ sg_len = skb_shinfo(skb)->nr_frags + 1;
+ if (CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX) <= sg_len) {
+ netif_stop_queue(ndev);
+ if (net_ratelimit())
+ netdev_warn(ndev, "TX ring unexpectedly full\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ skbuf_dma = axienet_get_tx_desc(lp, lp->tx_ring_head);
+ if (!skbuf_dma)
+ goto xmit_error_drop_skb;
+
+ lp->tx_ring_head++;
+ sg_init_table(skbuf_dma->sgl, sg_len);
+ ret = skb_to_sgvec(skb, skbuf_dma->sgl, 0, skb->len);
+ if (ret < 0)
+ goto xmit_error_drop_skb;
+
+ ret = dma_map_sg(lp->dev, skbuf_dma->sgl, sg_len, DMA_TO_DEVICE);
+ if (!ret)
+ goto xmit_error_drop_skb;
+
+ /* Fill up app fields for checksum */
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (lp->features & XAE_FEATURE_FULL_TX_CSUM) {
+ /* Tx Full Checksum Offload Enabled */
+ app_metadata[0] |= 2;
+ } else if (lp->features & XAE_FEATURE_PARTIAL_TX_CSUM) {
+ csum_start_off = skb_transport_offset(skb);
+ csum_index_off = csum_start_off + skb->csum_offset;
+ /* Tx Partial Checksum Offload Enabled */
+ app_metadata[0] |= 1;
+ app_metadata[1] = (csum_start_off << 16) | csum_index_off;
+ }
+ } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ app_metadata[0] |= 2; /* Tx Full Checksum Offload Enabled */
+ }
+
+ dma_tx_desc = dma_dev->device_prep_slave_sg(lp->tx_chan, skbuf_dma->sgl,
+ sg_len, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT, (void *)app_metadata);
+ if (!dma_tx_desc)
+ goto xmit_error_unmap_sg;
+
+ skbuf_dma->skb = skb;
+ skbuf_dma->sg_len = sg_len;
+ dma_tx_desc->callback_param = lp;
+ dma_tx_desc->callback_result = axienet_dma_tx_cb;
+ dmaengine_submit(dma_tx_desc);
+ dma_async_issue_pending(lp->tx_chan);
+ txq = skb_get_tx_queue(lp->ndev, skb);
+ netdev_tx_sent_queue(txq, skb->len);
+ netif_txq_maybe_stop(txq, CIRC_SPACE(lp->tx_ring_head, lp->tx_ring_tail, TX_BD_NUM_MAX),
+ MAX_SKB_FRAGS + 1, 2 * MAX_SKB_FRAGS);
+
+ return NETDEV_TX_OK;
+
+xmit_error_unmap_sg:
+ dma_unmap_sg(lp->dev, skbuf_dma->sgl, sg_len, DMA_TO_DEVICE);
+xmit_error_drop_skb:
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+/**
* axienet_tx_poll - Invoked once a transmit is completed by the
* Axi DMA Tx channel.
* @napi: Pointer to NAPI structure.
@@ -892,6 +1036,42 @@ axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
/**
+ * axienet_dma_rx_cb - DMA engine callback for RX channel.
+ * @data: Pointer to the skbuf_dma_descriptor structure.
+ * @result: error reporting through dmaengine_result.
+ * This function is called by dmaengine driver for RX channel to notify
+ * that the packet is received.
+ */
+static void axienet_dma_rx_cb(void *data, const struct dmaengine_result *result)
+{
+ struct skbuf_dma_descriptor *skbuf_dma;
+ size_t meta_len, meta_max_len, rx_len;
+ struct axienet_local *lp = data;
+ struct sk_buff *skb;
+ u32 *app_metadata;
+
+ skbuf_dma = axienet_get_rx_desc(lp, lp->rx_ring_tail++);
+ skb = skbuf_dma->skb;
+ app_metadata = dmaengine_desc_get_metadata_ptr(skbuf_dma->desc, &meta_len,
+ &meta_max_len);
+ dma_unmap_single(lp->dev, skbuf_dma->dma_address, lp->max_frm_size,
+ DMA_FROM_DEVICE);
+ /* TODO: Derive app word index programmatically */
+ rx_len = (app_metadata[LEN_APP] & 0xFFFF);
+ skb_put(skb, rx_len);
+ skb->protocol = eth_type_trans(skb, lp->ndev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ __netif_rx(skb);
+ u64_stats_update_begin(&lp->rx_stat_sync);
+ u64_stats_add(&lp->rx_packets, 1);
+ u64_stats_add(&lp->rx_bytes, rx_len);
+ u64_stats_update_end(&lp->rx_stat_sync);
+ axienet_rx_submit_desc(lp->ndev);
+ dma_async_issue_pending(lp->rx_chan);
+}
+
+/**
* axienet_rx_poll - Triggered by RX ISR to complete the BD processing.
* @napi: Pointer to NAPI structure.
* @budget: Max number of RX packets to process.
@@ -1125,40 +1305,158 @@ static irqreturn_t axienet_eth_irq(int irq, void *_ndev)
static void axienet_dma_err_handler(struct work_struct *work);
/**
- * axienet_open - Driver open routine.
- * @ndev: Pointer to net_device structure
+ * axienet_rx_submit_desc - Submit the rx descriptors to dmaengine.
+ * allocate skbuff, map the scatterlist and obtain a descriptor
+ * and then add the callback information and submit descriptor.
+ *
+ * @ndev: net_device pointer
+ *
+ */
+static void axienet_rx_submit_desc(struct net_device *ndev)
+{
+ struct dma_async_tx_descriptor *dma_rx_desc = NULL;
+ struct axienet_local *lp = netdev_priv(ndev);
+ struct skbuf_dma_descriptor *skbuf_dma;
+ struct sk_buff *skb;
+ dma_addr_t addr;
+
+ skbuf_dma = axienet_get_rx_desc(lp, lp->rx_ring_head);
+ if (!skbuf_dma)
+ return;
+
+ lp->rx_ring_head++;
+ skb = netdev_alloc_skb(ndev, lp->max_frm_size);
+ if (!skb)
+ return;
+
+ sg_init_table(skbuf_dma->sgl, 1);
+ addr = dma_map_single(lp->dev, skb->data, lp->max_frm_size, DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(lp->dev, addr))) {
+ if (net_ratelimit())
+ netdev_err(ndev, "DMA mapping error\n");
+ goto rx_submit_err_free_skb;
+ }
+ sg_dma_address(skbuf_dma->sgl) = addr;
+ sg_dma_len(skbuf_dma->sgl) = lp->max_frm_size;
+ dma_rx_desc = dmaengine_prep_slave_sg(lp->rx_chan, skbuf_dma->sgl,
+ 1, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!dma_rx_desc)
+ goto rx_submit_err_unmap_skb;
+
+ skbuf_dma->skb = skb;
+ skbuf_dma->dma_address = sg_dma_address(skbuf_dma->sgl);
+ skbuf_dma->desc = dma_rx_desc;
+ dma_rx_desc->callback_param = lp;
+ dma_rx_desc->callback_result = axienet_dma_rx_cb;
+ dmaengine_submit(dma_rx_desc);
+
+ return;
+
+rx_submit_err_unmap_skb:
+ dma_unmap_single(lp->dev, addr, lp->max_frm_size, DMA_FROM_DEVICE);
+rx_submit_err_free_skb:
+ dev_kfree_skb(skb);
+}
+
+/**
+ * axienet_init_dmaengine - init the dmaengine code.
+ * @ndev: Pointer to net_device structure
*
* Return: 0, on success.
- * non-zero error value on failure
+ * non-zero error value on failure
*
- * This is the driver open routine. It calls phylink_start to start the
- * PHY device.
- * It also allocates interrupt service routines, enables the interrupt lines
- * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer
- * descriptors are initialized.
+ * This is the dmaengine initialization code.
*/
-static int axienet_open(struct net_device *ndev)
+static int axienet_init_dmaengine(struct net_device *ndev)
{
- int ret;
struct axienet_local *lp = netdev_priv(ndev);
+ struct skbuf_dma_descriptor *skbuf_dma;
+ int i, ret;
- dev_dbg(&ndev->dev, "axienet_open()\n");
+ lp->tx_chan = dma_request_chan(lp->dev, "tx_chan0");
+ if (IS_ERR(lp->tx_chan)) {
+ dev_err(lp->dev, "No Ethernet DMA (TX) channel found\n");
+ return PTR_ERR(lp->tx_chan);
+ }
- /* When we do an Axi Ethernet reset, it resets the complete core
- * including the MDIO. MDIO must be disabled before resetting.
- * Hold MDIO bus lock to avoid MDIO accesses during the reset.
- */
- axienet_lock_mii(lp);
- ret = axienet_device_reset(ndev);
- axienet_unlock_mii(lp);
+ lp->rx_chan = dma_request_chan(lp->dev, "rx_chan0");
+ if (IS_ERR(lp->rx_chan)) {
+ ret = PTR_ERR(lp->rx_chan);
+ dev_err(lp->dev, "No Ethernet DMA (RX) channel found\n");
+ goto err_dma_release_tx;
+ }
- ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0);
- if (ret) {
- dev_err(lp->dev, "phylink_of_phy_connect() failed: %d\n", ret);
- return ret;
+ lp->tx_ring_tail = 0;
+ lp->tx_ring_head = 0;
+ lp->rx_ring_tail = 0;
+ lp->rx_ring_head = 0;
+ lp->tx_skb_ring = kcalloc(TX_BD_NUM_MAX, sizeof(*lp->tx_skb_ring),
+ GFP_KERNEL);
+ if (!lp->tx_skb_ring) {
+ ret = -ENOMEM;
+ goto err_dma_release_rx;
+ }
+ for (i = 0; i < TX_BD_NUM_MAX; i++) {
+ skbuf_dma = kzalloc(sizeof(*skbuf_dma), GFP_KERNEL);
+ if (!skbuf_dma) {
+ ret = -ENOMEM;
+ goto err_free_tx_skb_ring;
+ }
+ lp->tx_skb_ring[i] = skbuf_dma;
}
- phylink_start(lp->phylink);
+ lp->rx_skb_ring = kcalloc(RX_BUF_NUM_DEFAULT, sizeof(*lp->rx_skb_ring),
+ GFP_KERNEL);
+ if (!lp->rx_skb_ring) {
+ ret = -ENOMEM;
+ goto err_free_tx_skb_ring;
+ }
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++) {
+ skbuf_dma = kzalloc(sizeof(*skbuf_dma), GFP_KERNEL);
+ if (!skbuf_dma) {
+ ret = -ENOMEM;
+ goto err_free_rx_skb_ring;
+ }
+ lp->rx_skb_ring[i] = skbuf_dma;
+ }
+ /* TODO: Instead of BD_NUM_DEFAULT use runtime support */
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++)
+ axienet_rx_submit_desc(ndev);
+ dma_async_issue_pending(lp->rx_chan);
+
+ return 0;
+
+err_free_rx_skb_ring:
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++)
+ kfree(lp->rx_skb_ring[i]);
+ kfree(lp->rx_skb_ring);
+err_free_tx_skb_ring:
+ for (i = 0; i < TX_BD_NUM_MAX; i++)
+ kfree(lp->tx_skb_ring[i]);
+ kfree(lp->tx_skb_ring);
+err_dma_release_rx:
+ dma_release_channel(lp->rx_chan);
+err_dma_release_tx:
+ dma_release_channel(lp->tx_chan);
+ return ret;
+}
+
+/**
+ * axienet_init_legacy_dma - init the dma legacy code.
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0, on success.
+ * non-zero error value on failure
+ *
+ * This is the dma initialization code. It also allocates interrupt
+ * service routines, enables the interrupt lines and ISR handling.
+ *
+ */
+static int axienet_init_legacy_dma(struct net_device *ndev)
+{
+ int ret;
+ struct axienet_local *lp = netdev_priv(ndev);
/* Enable worker thread for Axi DMA error handling */
INIT_WORK(&lp->dma_err_task, axienet_dma_err_handler);
@@ -1193,14 +1491,77 @@ err_rx_irq:
err_tx_irq:
napi_disable(&lp->napi_tx);
napi_disable(&lp->napi_rx);
- phylink_stop(lp->phylink);
- phylink_disconnect_phy(lp->phylink);
cancel_work_sync(&lp->dma_err_task);
dev_err(lp->dev, "request_irq() failed\n");
return ret;
}
/**
+ * axienet_open - Driver open routine.
+ * @ndev: Pointer to net_device structure
+ *
+ * Return: 0, on success.
+ * non-zero error value on failure
+ *
+ * This is the driver open routine. It calls phylink_start to start the
+ * PHY device.
+ * It also allocates interrupt service routines, enables the interrupt lines
+ * and ISR handling. Axi Ethernet core is reset through Axi DMA core. Buffer
+ * descriptors are initialized.
+ */
+static int axienet_open(struct net_device *ndev)
+{
+ int ret;
+ struct axienet_local *lp = netdev_priv(ndev);
+
+ dev_dbg(&ndev->dev, "%s\n", __func__);
+
+ /* When we do an Axi Ethernet reset, it resets the complete core
+ * including the MDIO. MDIO must be disabled before resetting.
+ * Hold MDIO bus lock to avoid MDIO accesses during the reset.
+ */
+ axienet_lock_mii(lp);
+ ret = axienet_device_reset(ndev);
+ axienet_unlock_mii(lp);
+
+ ret = phylink_of_phy_connect(lp->phylink, lp->dev->of_node, 0);
+ if (ret) {
+ dev_err(lp->dev, "phylink_of_phy_connect() failed: %d\n", ret);
+ return ret;
+ }
+
+ phylink_start(lp->phylink);
+
+ if (lp->use_dmaengine) {
+ /* Enable interrupts for Axi Ethernet core (if defined) */
+ if (lp->eth_irq > 0) {
+ ret = request_irq(lp->eth_irq, axienet_eth_irq, IRQF_SHARED,
+ ndev->name, ndev);
+ if (ret)
+ goto err_phy;
+ }
+
+ ret = axienet_init_dmaengine(ndev);
+ if (ret < 0)
+ goto err_free_eth_irq;
+ } else {
+ ret = axienet_init_legacy_dma(ndev);
+ if (ret)
+ goto err_phy;
+ }
+
+ return 0;
+
+err_free_eth_irq:
+ if (lp->eth_irq > 0)
+ free_irq(lp->eth_irq, ndev);
+err_phy:
+ phylink_stop(lp->phylink);
+ phylink_disconnect_phy(lp->phylink);
+ return ret;
+}
+
+/**
* axienet_stop - Driver stop routine.
* @ndev: Pointer to net_device structure
*
@@ -1213,11 +1574,14 @@ err_tx_irq:
static int axienet_stop(struct net_device *ndev)
{
struct axienet_local *lp = netdev_priv(ndev);
+ int i;
dev_dbg(&ndev->dev, "axienet_close()\n");
- napi_disable(&lp->napi_tx);
- napi_disable(&lp->napi_rx);
+ if (!lp->use_dmaengine) {
+ napi_disable(&lp->napi_tx);
+ napi_disable(&lp->napi_rx);
+ }
phylink_stop(lp->phylink);
phylink_disconnect_phy(lp->phylink);
@@ -1225,18 +1589,33 @@ static int axienet_stop(struct net_device *ndev)
axienet_setoptions(ndev, lp->options &
~(XAE_OPTION_TXEN | XAE_OPTION_RXEN));
- axienet_dma_stop(lp);
+ if (!lp->use_dmaengine) {
+ axienet_dma_stop(lp);
+ cancel_work_sync(&lp->dma_err_task);
+ free_irq(lp->tx_irq, ndev);
+ free_irq(lp->rx_irq, ndev);
+ axienet_dma_bd_release(ndev);
+ } else {
+ dmaengine_terminate_sync(lp->tx_chan);
+ dmaengine_synchronize(lp->tx_chan);
+ dmaengine_terminate_sync(lp->rx_chan);
+ dmaengine_synchronize(lp->rx_chan);
+
+ for (i = 0; i < TX_BD_NUM_MAX; i++)
+ kfree(lp->tx_skb_ring[i]);
+ kfree(lp->tx_skb_ring);
+ for (i = 0; i < RX_BUF_NUM_DEFAULT; i++)
+ kfree(lp->rx_skb_ring[i]);
+ kfree(lp->rx_skb_ring);
+
+ dma_release_channel(lp->rx_chan);
+ dma_release_channel(lp->tx_chan);
+ }
axienet_iow(lp, XAE_IE_OFFSET, 0);
- cancel_work_sync(&lp->dma_err_task);
-
if (lp->eth_irq > 0)
free_irq(lp->eth_irq, ndev);
- free_irq(lp->tx_irq, ndev);
- free_irq(lp->rx_irq, ndev);
-
- axienet_dma_bd_release(ndev);
return 0;
}
@@ -1333,6 +1712,18 @@ static const struct net_device_ops axienet_netdev_ops = {
#endif
};
+static const struct net_device_ops axienet_netdev_dmaengine_ops = {
+ .ndo_open = axienet_open,
+ .ndo_stop = axienet_stop,
+ .ndo_start_xmit = axienet_start_xmit_dmaengine,
+ .ndo_get_stats64 = axienet_get_stats64,
+ .ndo_change_mtu = axienet_change_mtu,
+ .ndo_set_mac_address = netdev_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_eth_ioctl = axienet_ioctl,
+ .ndo_set_rx_mode = axienet_set_multicast_list,
+};
+
/**
* axienet_ethtools_get_drvinfo - Get various Axi Ethernet driver information.
* @ndev: Pointer to net_device structure
@@ -1412,14 +1803,16 @@ static void axienet_ethtools_get_regs(struct net_device *ndev,
data[29] = axienet_ior(lp, XAE_FMI_OFFSET);
data[30] = axienet_ior(lp, XAE_AF0_OFFSET);
data[31] = axienet_ior(lp, XAE_AF1_OFFSET);
- data[32] = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
- data[33] = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
- data[34] = axienet_dma_in32(lp, XAXIDMA_TX_CDESC_OFFSET);
- data[35] = axienet_dma_in32(lp, XAXIDMA_TX_TDESC_OFFSET);
- data[36] = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
- data[37] = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
- data[38] = axienet_dma_in32(lp, XAXIDMA_RX_CDESC_OFFSET);
- data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET);
+ if (!lp->use_dmaengine) {
+ data[32] = axienet_dma_in32(lp, XAXIDMA_TX_CR_OFFSET);
+ data[33] = axienet_dma_in32(lp, XAXIDMA_TX_SR_OFFSET);
+ data[34] = axienet_dma_in32(lp, XAXIDMA_TX_CDESC_OFFSET);
+ data[35] = axienet_dma_in32(lp, XAXIDMA_TX_TDESC_OFFSET);
+ data[36] = axienet_dma_in32(lp, XAXIDMA_RX_CR_OFFSET);
+ data[37] = axienet_dma_in32(lp, XAXIDMA_RX_SR_OFFSET);
+ data[38] = axienet_dma_in32(lp, XAXIDMA_RX_CDESC_OFFSET);
+ data[39] = axienet_dma_in32(lp, XAXIDMA_RX_TDESC_OFFSET);
+ }
}
static void
@@ -1863,7 +2256,6 @@ static int axienet_probe(struct platform_device *pdev)
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
ndev->features = NETIF_F_SG;
- ndev->netdev_ops = &axienet_netdev_ops;
ndev->ethtool_ops = &axienet_ethtool_ops;
/* MTU range: 64 - 9000 */
@@ -1880,9 +2272,6 @@ static int axienet_probe(struct platform_device *pdev)
u64_stats_init(&lp->rx_stat_sync);
u64_stats_init(&lp->tx_stat_sync);
- netif_napi_add(ndev, &lp->napi_rx, axienet_rx_poll);
- netif_napi_add(ndev, &lp->napi_tx, axienet_tx_poll);
-
lp->axi_clk = devm_clk_get_optional(&pdev->dev, "s_axi_lite_clk");
if (!lp->axi_clk) {
/* For backward compatibility, if named AXI clock is not present,
@@ -2008,82 +2397,118 @@ static int axienet_probe(struct platform_device *pdev)
goto cleanup_clk;
}
- /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
- np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
- if (np) {
- struct resource dmares;
+ if (!of_find_property(pdev->dev.of_node, "dmas", NULL)) {
+ /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
+ np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);
- ret = of_address_to_resource(np, 0, &dmares);
- if (ret) {
- dev_err(&pdev->dev,
- "unable to get DMA resource\n");
+ if (np) {
+ struct resource dmares;
+
+ ret = of_address_to_resource(np, 0, &dmares);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "unable to get DMA resource\n");
+ of_node_put(np);
+ goto cleanup_clk;
+ }
+ lp->dma_regs = devm_ioremap_resource(&pdev->dev,
+ &dmares);
+ lp->rx_irq = irq_of_parse_and_map(np, 1);
+ lp->tx_irq = irq_of_parse_and_map(np, 0);
of_node_put(np);
+ lp->eth_irq = platform_get_irq_optional(pdev, 0);
+ } else {
+ /* Check for these resources directly on the Ethernet node. */
+ lp->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
+ lp->rx_irq = platform_get_irq(pdev, 1);
+ lp->tx_irq = platform_get_irq(pdev, 0);
+ lp->eth_irq = platform_get_irq_optional(pdev, 2);
+ }
+ if (IS_ERR(lp->dma_regs)) {
+ dev_err(&pdev->dev, "could not map DMA regs\n");
+ ret = PTR_ERR(lp->dma_regs);
+ goto cleanup_clk;
+ }
+ if (lp->rx_irq <= 0 || lp->tx_irq <= 0) {
+ dev_err(&pdev->dev, "could not determine irqs\n");
+ ret = -ENOMEM;
goto cleanup_clk;
}
- lp->dma_regs = devm_ioremap_resource(&pdev->dev,
- &dmares);
- lp->rx_irq = irq_of_parse_and_map(np, 1);
- lp->tx_irq = irq_of_parse_and_map(np, 0);
- of_node_put(np);
- lp->eth_irq = platform_get_irq_optional(pdev, 0);
- } else {
- /* Check for these resources directly on the Ethernet node. */
- lp->dma_regs = devm_platform_get_and_ioremap_resource(pdev, 1, NULL);
- lp->rx_irq = platform_get_irq(pdev, 1);
- lp->tx_irq = platform_get_irq(pdev, 0);
- lp->eth_irq = platform_get_irq_optional(pdev, 2);
- }
- if (IS_ERR(lp->dma_regs)) {
- dev_err(&pdev->dev, "could not map DMA regs\n");
- ret = PTR_ERR(lp->dma_regs);
- goto cleanup_clk;
- }
- if ((lp->rx_irq <= 0) || (lp->tx_irq <= 0)) {
- dev_err(&pdev->dev, "could not determine irqs\n");
- ret = -ENOMEM;
- goto cleanup_clk;
- }
- /* Reset core now that clocks are enabled, prior to accessing MDIO */
- ret = __axienet_device_reset(lp);
- if (ret)
- goto cleanup_clk;
+ /* Reset core now that clocks are enabled, prior to accessing MDIO */
+ ret = __axienet_device_reset(lp);
+ if (ret)
+ goto cleanup_clk;
+
+ /* Autodetect the need for 64-bit DMA pointers.
+ * When the IP is configured for a bus width bigger than 32 bits,
+ * writing the MSB registers is mandatory, even if they are all 0.
+ * We can detect this case by writing all 1's to one such register
+ * and see if that sticks: when the IP is configured for 32 bits
+ * only, those registers are RES0.
+ * Those MSB registers were introduced in IP v7.1, which we check first.
+ */
+ if ((axienet_ior(lp, XAE_ID_OFFSET) >> 24) >= 0x9) {
+ void __iomem *desc = lp->dma_regs + XAXIDMA_TX_CDESC_OFFSET + 4;
- /* Autodetect the need for 64-bit DMA pointers.
- * When the IP is configured for a bus width bigger than 32 bits,
- * writing the MSB registers is mandatory, even if they are all 0.
- * We can detect this case by writing all 1's to one such register
- * and see if that sticks: when the IP is configured for 32 bits
- * only, those registers are RES0.
- * Those MSB registers were introduced in IP v7.1, which we check first.
- */
- if ((axienet_ior(lp, XAE_ID_OFFSET) >> 24) >= 0x9) {
- void __iomem *desc = lp->dma_regs + XAXIDMA_TX_CDESC_OFFSET + 4;
-
- iowrite32(0x0, desc);
- if (ioread32(desc) == 0) { /* sanity check */
- iowrite32(0xffffffff, desc);
- if (ioread32(desc) > 0) {
- lp->features |= XAE_FEATURE_DMA_64BIT;
- addr_width = 64;
- dev_info(&pdev->dev,
- "autodetected 64-bit DMA range\n");
- }
iowrite32(0x0, desc);
+ if (ioread32(desc) == 0) { /* sanity check */
+ iowrite32(0xffffffff, desc);
+ if (ioread32(desc) > 0) {
+ lp->features |= XAE_FEATURE_DMA_64BIT;
+ addr_width = 64;
+ dev_info(&pdev->dev,
+ "autodetected 64-bit DMA range\n");
+ }
+ iowrite32(0x0, desc);
+ }
+ }
+ if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) {
+ dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n");
+ ret = -EINVAL;
+ goto cleanup_clk;
}
- }
- if (!IS_ENABLED(CONFIG_64BIT) && lp->features & XAE_FEATURE_DMA_64BIT) {
- dev_err(&pdev->dev, "64-bit addressable DMA is not compatible with 32-bit archecture\n");
- ret = -EINVAL;
- goto cleanup_clk;
- }
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width));
- if (ret) {
- dev_err(&pdev->dev, "No suitable DMA available\n");
- goto cleanup_clk;
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_width));
+ if (ret) {
+ dev_err(&pdev->dev, "No suitable DMA available\n");
+ goto cleanup_clk;
+ }
+ netif_napi_add(ndev, &lp->napi_rx, axienet_rx_poll);
+ netif_napi_add(ndev, &lp->napi_tx, axienet_tx_poll);
+ } else {
+ struct xilinx_vdma_config cfg;
+ struct dma_chan *tx_chan;
+
+ lp->eth_irq = platform_get_irq_optional(pdev, 0);
+ if (lp->eth_irq < 0 && lp->eth_irq != -ENXIO) {
+ ret = lp->eth_irq;
+ goto cleanup_clk;
+ }
+ tx_chan = dma_request_chan(lp->dev, "tx_chan0");
+ if (IS_ERR(tx_chan)) {
+ ret = PTR_ERR(tx_chan);
+ dev_err_probe(lp->dev, ret, "No Ethernet DMA (TX) channel found\n");
+ goto cleanup_clk;
+ }
+
+ cfg.reset = 1;
+ /* As name says VDMA but it has support for DMA channel reset */
+ ret = xilinx_vdma_channel_set_config(tx_chan, &cfg);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Reset channel failed\n");
+ dma_release_channel(tx_chan);
+ goto cleanup_clk;
+ }
+
+ dma_release_channel(tx_chan);
+ lp->use_dmaengine = 1;
}
+ if (lp->use_dmaengine)
+ ndev->netdev_ops = &axienet_netdev_dmaengine_ops;
+ else
+ ndev->netdev_ops = &axienet_netdev_ops;
/* Check for Ethernet core IRQ (optional) */
if (lp->eth_irq <= 0)
dev_info(&pdev->dev, "Ethernet core IRQ not defined\n");
@@ -2099,8 +2524,8 @@ static int axienet_probe(struct platform_device *pdev)
}
lp->coalesce_count_rx = XAXIDMA_DFT_RX_THRESHOLD;
- lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC;
lp->coalesce_count_tx = XAXIDMA_DFT_TX_THRESHOLD;
+ lp->coalesce_usec_rx = XAXIDMA_DFT_RX_USEC;
lp->coalesce_usec_tx = XAXIDMA_DFT_TX_USEC;
ret = axienet_mdio_setup(lp);
diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c
index 2b6a607ac0b7..a273362c9e70 100644
--- a/drivers/net/fddi/skfp/skfddi.c
+++ b/drivers/net/fddi/skfp/skfddi.c
@@ -153,6 +153,7 @@ static const struct pci_device_id skfddi_pci_tbl[] = {
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);
+MODULE_DESCRIPTION("SysKonnect FDDI PCI driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 704e949484d0..b9b5554ea862 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c
@@ -221,21 +221,25 @@ static int fjes_hw_setup(struct fjes_hw *hw)
mem_size = FJES_DEV_REQ_BUF_SIZE(hw->max_epid);
hw->hw_info.req_buf = kzalloc(mem_size, GFP_KERNEL);
- if (!(hw->hw_info.req_buf))
- return -ENOMEM;
+ if (!(hw->hw_info.req_buf)) {
+ result = -ENOMEM;
+ goto free_ep_info;
+ }
hw->hw_info.req_buf_size = mem_size;
mem_size = FJES_DEV_RES_BUF_SIZE(hw->max_epid);
hw->hw_info.res_buf = kzalloc(mem_size, GFP_KERNEL);
- if (!(hw->hw_info.res_buf))
- return -ENOMEM;
+ if (!(hw->hw_info.res_buf)) {
+ result = -ENOMEM;
+ goto free_req_buf;
+ }
hw->hw_info.res_buf_size = mem_size;
result = fjes_hw_alloc_shared_status_region(hw);
if (result)
- return result;
+ goto free_res_buf;
hw->hw_info.buffer_share_bit = 0;
hw->hw_info.buffer_unshare_reserve_bit = 0;
@@ -246,11 +250,11 @@ static int fjes_hw_setup(struct fjes_hw *hw)
result = fjes_hw_alloc_epbuf(&buf_pair->tx);
if (result)
- return result;
+ goto free_epbuf;
result = fjes_hw_alloc_epbuf(&buf_pair->rx);
if (result)
- return result;
+ goto free_epbuf;
spin_lock_irqsave(&hw->rx_status_lock, flags);
fjes_hw_setup_epbuf(&buf_pair->tx, mac,
@@ -273,6 +277,25 @@ static int fjes_hw_setup(struct fjes_hw *hw)
fjes_hw_init_command_registers(hw, &param);
return 0;
+
+free_epbuf:
+ for (epidx = 0; epidx < hw->max_epid ; epidx++) {
+ if (epidx == hw->my_epid)
+ continue;
+ fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx);
+ fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx);
+ }
+ fjes_hw_free_shared_status_region(hw);
+free_res_buf:
+ kfree(hw->hw_info.res_buf);
+ hw->hw_info.res_buf = NULL;
+free_req_buf:
+ kfree(hw->hw_info.req_buf);
+ hw->hw_info.req_buf = NULL;
+free_ep_info:
+ kfree(hw->ep_shm_info);
+ hw->ep_shm_info = NULL;
+ return result;
}
static void fjes_hw_cleanup(struct fjes_hw *hw)
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index cd8cf08477ec..5fbe33a09bb0 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c
@@ -1438,7 +1438,7 @@ err_out:
}
/* fjes_remove - Device Removal Routine */
-static int fjes_remove(struct platform_device *plat_dev)
+static void fjes_remove(struct platform_device *plat_dev)
{
struct net_device *netdev = dev_get_drvdata(&plat_dev->dev);
struct fjes_adapter *adapter = netdev_priv(netdev);
@@ -1462,8 +1462,6 @@ static int fjes_remove(struct platform_device *plat_dev)
netif_napi_del(&adapter->napi);
free_netdev(netdev);
-
- return 0;
}
static struct platform_driver fjes_driver = {
@@ -1471,7 +1469,7 @@ static struct platform_driver fjes_driver = {
.name = DRV_NAME,
},
.probe = fjes_probe,
- .remove = fjes_remove,
+ .remove_new = fjes_remove,
};
static acpi_status
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index acd9c615d1f4..c4ed36c71897 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -221,7 +221,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
struct genevehdr *gnvh = geneve_hdr(skb);
struct metadata_dst *tun_dst = NULL;
unsigned int len;
- int err = 0;
+ int nh, err = 0;
void *oiph;
if (ip_tunnel_collect_metadata() || gs->collect_md) {
@@ -234,7 +234,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
vni_to_tunnel_id(gnvh->vni),
gnvh->opt_len * 4);
if (!tun_dst) {
- geneve->dev->stats.rx_dropped++;
+ DEV_STATS_INC(geneve->dev, rx_dropped);
goto drop;
}
/* Update tunnel dst according to Geneve options. */
@@ -246,8 +246,8 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
* since we don't support any...
*/
if (gnvh->critical) {
- geneve->dev->stats.rx_frame_errors++;
- geneve->dev->stats.rx_errors++;
+ DEV_STATS_INC(geneve->dev, rx_frame_errors);
+ DEV_STATS_INC(geneve->dev, rx_errors);
goto drop;
}
}
@@ -263,7 +263,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
/* Ignore packet loops (and multicast echo) */
if (ether_addr_equal(eth_hdr(skb)->h_source,
geneve->dev->dev_addr)) {
- geneve->dev->stats.rx_errors++;
+ DEV_STATS_INC(geneve->dev, rx_errors);
goto drop;
}
} else {
@@ -272,9 +272,23 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
skb->pkt_type = PACKET_HOST;
}
- oiph = skb_network_header(skb);
+ /* Save offset of outer header relative to skb->head,
+ * because we are going to reset the network header to the inner header
+ * and might change skb->head.
+ */
+ nh = skb_network_header(skb) - skb->head;
+
skb_reset_network_header(skb);
+ if (!pskb_inet_may_pull(skb)) {
+ DEV_STATS_INC(geneve->dev, rx_length_errors);
+ DEV_STATS_INC(geneve->dev, rx_errors);
+ goto drop;
+ }
+
+ /* Get the outer header. */
+ oiph = skb->head + nh;
+
if (geneve_get_sk_family(gs) == AF_INET)
err = IP_ECN_decapsulate(oiph, skb);
#if IS_ENABLED(CONFIG_IPV6)
@@ -296,8 +310,8 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs,
#endif
}
if (err > 1) {
- ++geneve->dev->stats.rx_frame_errors;
- ++geneve->dev->stats.rx_errors;
+ DEV_STATS_INC(geneve->dev, rx_frame_errors);
+ DEV_STATS_INC(geneve->dev, rx_errors);
goto drop;
}
}
@@ -377,14 +391,14 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
if (unlikely((!geneve->cfg.inner_proto_inherit &&
inner_proto != htons(ETH_P_TEB)))) {
- geneve->dev->stats.rx_dropped++;
+ DEV_STATS_INC(geneve->dev, rx_dropped);
goto drop;
}
opts_len = geneveh->opt_len * 4;
if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, inner_proto,
!net_eq(geneve->net, dev_net(geneve->dev)))) {
- geneve->dev->stats.rx_dropped++;
+ DEV_STATS_INC(geneve->dev, rx_dropped);
goto drop;
}
@@ -1007,7 +1021,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
netdev_dbg(dev, "no tunnel metadata\n");
dev_kfree_skb(skb);
- dev->stats.tx_dropped++;
+ DEV_STATS_INC(dev, tx_dropped);
return NETDEV_TX_OK;
}
} else {
@@ -1030,11 +1044,11 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
if (err == -ELOOP)
- dev->stats.collisions++;
+ DEV_STATS_INC(dev, collisions);
else if (err == -ENETUNREACH)
- dev->stats.tx_carrier_errors++;
+ DEV_STATS_INC(dev, tx_carrier_errors);
- dev->stats.tx_errors++;
+ DEV_STATS_INC(dev, tx_errors);
return NETDEV_TX_OK;
}
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index b1919278e931..2b5357d94ff5 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -1903,26 +1903,26 @@ static int __init gtp_init(void)
get_random_bytes(&gtp_h_initval, sizeof(gtp_h_initval));
- err = rtnl_link_register(&gtp_link_ops);
+ err = register_pernet_subsys(&gtp_net_ops);
if (err < 0)
goto error_out;
- err = genl_register_family(&gtp_genl_family);
+ err = rtnl_link_register(&gtp_link_ops);
if (err < 0)
- goto unreg_rtnl_link;
+ goto unreg_pernet_subsys;
- err = register_pernet_subsys(&gtp_net_ops);
+ err = genl_register_family(&gtp_genl_family);
if (err < 0)
- goto unreg_genl_family;
+ goto unreg_rtnl_link;
pr_info("GTP module loaded (pdp ctx size %zd bytes)\n",
sizeof(struct pdp_ctx));
return 0;
-unreg_genl_family:
- genl_unregister_family(&gtp_genl_family);
unreg_rtnl_link:
rtnl_link_unregister(&gtp_link_ops);
+unreg_pernet_subsys:
+ unregister_pernet_subsys(&gtp_net_ops);
error_out:
pr_err("error loading GTP module loaded\n");
return err;
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 1dafa44155d0..a6fcbda64ecc 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -708,7 +708,10 @@ void netvsc_device_remove(struct hv_device *device)
/* Disable NAPI and disassociate its context from the device. */
for (i = 0; i < net_device->num_chn; i++) {
/* See also vmbus_reset_channel_cb(). */
- napi_disable(&net_device->chan_table[i].napi);
+ /* only disable enabled NAPI channel */
+ if (i < ndev->real_num_rx_queues)
+ napi_disable(&net_device->chan_table[i].napi);
+
netif_napi_del(&net_device->chan_table[i].napi);
}
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 706ea5263e87..11831a1c9762 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -42,9 +42,13 @@
#define LINKCHANGE_INT (2 * HZ)
#define VF_TAKEOVER_INT (HZ / 10)
+/* Macros to define the context of vf registration */
+#define VF_REG_IN_PROBE 1
+#define VF_REG_IN_NOTIFIER 2
+
static unsigned int ring_size __ro_after_init = 128;
module_param(ring_size, uint, 0444);
-MODULE_PARM_DESC(ring_size, "Ring buffer size (# of pages)");
+MODULE_PARM_DESC(ring_size, "Ring buffer size (# of 4K pages)");
unsigned int netvsc_ring_bytes __ro_after_init;
static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
@@ -1582,10 +1586,10 @@ static void netvsc_get_strings(struct net_device *dev, u32 stringset, u8 *data)
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(netvsc_stats); i++)
- ethtool_sprintf(&p, netvsc_stats[i].name);
+ ethtool_puts(&p, netvsc_stats[i].name);
for (i = 0; i < ARRAY_SIZE(vf_stats); i++)
- ethtool_sprintf(&p, vf_stats[i].name);
+ ethtool_puts(&p, vf_stats[i].name);
for (i = 0; i < nvdev->num_chn; i++) {
ethtool_sprintf(&p, "tx_queue_%u_packets", i);
@@ -1752,8 +1756,8 @@ static u32 netvsc_rss_indir_size(struct net_device *dev)
return ndc->rx_table_sz;
}
-static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
- u8 *hfunc)
+static int netvsc_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct net_device_context *ndc = netdev_priv(dev);
struct netvsc_device *ndev = rtnl_dereference(ndc->nvdev);
@@ -1763,47 +1767,49 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
if (!ndev)
return -ENODEV;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
+ rxfh->hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
rndis_dev = ndev->extension;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < ndc->rx_table_sz; i++)
- indir[i] = ndc->rx_table[i];
+ rxfh->indir[i] = ndc->rx_table[i];
}
- if (key)
- memcpy(key, rndis_dev->rss_key, NETVSC_HASH_KEYLEN);
+ if (rxfh->key)
+ memcpy(rxfh->key, rndis_dev->rss_key, NETVSC_HASH_KEYLEN);
return 0;
}
-static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir,
- const u8 *key, const u8 hfunc)
+static int netvsc_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct net_device_context *ndc = netdev_priv(dev);
struct netvsc_device *ndev = rtnl_dereference(ndc->nvdev);
struct rndis_device *rndis_dev;
+ u8 *key = rxfh->key;
int i;
if (!ndev)
return -ENODEV;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
rndis_dev = ndev->extension;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < ndc->rx_table_sz; i++)
- if (indir[i] >= ndev->num_chn)
+ if (rxfh->indir[i] >= ndev->num_chn)
return -EINVAL;
for (i = 0; i < ndc->rx_table_sz; i++)
- ndc->rx_table[i] = indir[i];
+ ndc->rx_table[i] = rxfh->indir[i];
}
if (!key) {
- if (!indir)
+ if (!rxfh->indir)
return 0;
key = rndis_dev->rss_key;
@@ -2183,7 +2189,7 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb)
}
static int netvsc_vf_join(struct net_device *vf_netdev,
- struct net_device *ndev)
+ struct net_device *ndev, int context)
{
struct net_device_context *ndev_ctx = netdev_priv(ndev);
int ret;
@@ -2206,7 +2212,11 @@ static int netvsc_vf_join(struct net_device *vf_netdev,
goto upper_link_failed;
}
- schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
+ /* If this registration is called from probe context vf_takeover
+ * is taken care of later in probe itself.
+ */
+ if (context == VF_REG_IN_NOTIFIER)
+ schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
@@ -2344,7 +2354,7 @@ static int netvsc_prepare_bonding(struct net_device *vf_netdev)
return NOTIFY_DONE;
}
-static int netvsc_register_vf(struct net_device *vf_netdev)
+static int netvsc_register_vf(struct net_device *vf_netdev, int context)
{
struct net_device_context *net_device_ctx;
struct netvsc_device *netvsc_dev;
@@ -2384,7 +2394,7 @@ static int netvsc_register_vf(struct net_device *vf_netdev)
netdev_info(ndev, "VF registering: %s\n", vf_netdev->name);
- if (netvsc_vf_join(vf_netdev, ndev) != 0)
+ if (netvsc_vf_join(vf_netdev, ndev, context) != 0)
return NOTIFY_DONE;
dev_hold(vf_netdev);
@@ -2482,10 +2492,31 @@ static int netvsc_unregister_vf(struct net_device *vf_netdev)
return NOTIFY_OK;
}
+static int check_dev_is_matching_vf(struct net_device *event_ndev)
+{
+ /* Skip NetVSC interfaces */
+ if (event_ndev->netdev_ops == &device_ops)
+ return -ENODEV;
+
+ /* Avoid non-Ethernet type devices */
+ if (event_ndev->type != ARPHRD_ETHER)
+ return -ENODEV;
+
+ /* Avoid Vlan dev with same MAC registering as VF */
+ if (is_vlan_dev(event_ndev))
+ return -ENODEV;
+
+ /* Avoid Bonding master dev with same MAC registering as VF */
+ if (netif_is_bond_master(event_ndev))
+ return -ENODEV;
+
+ return 0;
+}
+
static int netvsc_probe(struct hv_device *dev,
const struct hv_vmbus_device_id *dev_id)
{
- struct net_device *net = NULL;
+ struct net_device *net = NULL, *vf_netdev;
struct net_device_context *net_device_ctx;
struct netvsc_device_info *device_info = NULL;
struct netvsc_device *nvdev;
@@ -2597,6 +2628,30 @@ static int netvsc_probe(struct hv_device *dev,
}
list_add(&net_device_ctx->list, &netvsc_dev_list);
+
+ /* When the hv_netvsc driver is unloaded and reloaded, the
+ * NET_DEVICE_REGISTER for the vf device is replayed before probe
+ * is complete. This is because register_netdevice_notifier() gets
+ * registered before vmbus_driver_register() so that callback func
+ * is set before probe and we don't miss events like NETDEV_POST_INIT
+ * So, in this section we try to register the matching vf device that
+ * is present as a netdevice, knowing that its register call is not
+ * processed in the netvsc_netdev_notifier(as probing is progress and
+ * get_netvsc_byslot fails).
+ */
+ for_each_netdev(dev_net(net), vf_netdev) {
+ ret = check_dev_is_matching_vf(vf_netdev);
+ if (ret != 0)
+ continue;
+
+ if (net != get_netvsc_byslot(vf_netdev))
+ continue;
+
+ netvsc_prepare_bonding(vf_netdev);
+ netvsc_register_vf(vf_netdev, VF_REG_IN_PROBE);
+ __netvsc_vf_setup(net, vf_netdev);
+ break;
+ }
rtnl_unlock();
netvsc_devinfo_put(device_info);
@@ -2752,28 +2807,17 @@ static int netvsc_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
+ int ret = 0;
- /* Skip our own events */
- if (event_dev->netdev_ops == &device_ops)
- return NOTIFY_DONE;
-
- /* Avoid non-Ethernet type devices */
- if (event_dev->type != ARPHRD_ETHER)
- return NOTIFY_DONE;
-
- /* Avoid Vlan dev with same MAC registering as VF */
- if (is_vlan_dev(event_dev))
- return NOTIFY_DONE;
-
- /* Avoid Bonding master dev with same MAC registering as VF */
- if (netif_is_bond_master(event_dev))
+ ret = check_dev_is_matching_vf(event_dev);
+ if (ret != 0)
return NOTIFY_DONE;
switch (event) {
case NETDEV_POST_INIT:
return netvsc_prepare_bonding(event_dev);
case NETDEV_REGISTER:
- return netvsc_register_vf(event_dev);
+ return netvsc_register_vf(event_dev, VF_REG_IN_NOTIFIER);
case NETDEV_UNREGISTER:
return netvsc_unregister_vf(event_dev);
case NETDEV_UP:
@@ -2805,7 +2849,7 @@ static int __init netvsc_drv_init(void)
pr_info("Increased ring_size to %u (min allowed)\n",
ring_size);
}
- netvsc_ring_bytes = ring_size * PAGE_SIZE;
+ netvsc_ring_bytes = VMBUS_RING_SIZE(ring_size * 4096);
register_netdevice_notifier(&netvsc_netdev_notifier);
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index af95947a87c5..ecc2128ca9b7 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -21,7 +21,6 @@
#include <linux/rtnetlink.h>
#include <linux/ucs2_string.h>
#include <linux/string.h>
-#include <linux/slab.h>
#include "hyperv_net.h"
#include "netvsc_trace.h"
diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c
index 523d13ee02bf..2930141d7dd2 100644
--- a/drivers/net/ieee802154/fakelb.c
+++ b/drivers/net/ieee802154/fakelb.c
@@ -221,7 +221,7 @@ err_slave:
return err;
}
-static int fakelb_remove(struct platform_device *pdev)
+static void fakelb_remove(struct platform_device *pdev)
{
struct fakelb_phy *phy, *tmp;
@@ -229,14 +229,13 @@ static int fakelb_remove(struct platform_device *pdev)
list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
fakelb_del(phy);
mutex_unlock(&fakelb_phys_lock);
- return 0;
}
static struct platform_device *ieee802154fake_dev;
static struct platform_driver ieee802154fake_driver = {
.probe = fakelb_probe,
- .remove = fakelb_remove,
+ .remove_new = fakelb_remove,
.driver = {
.name = "ieee802154fakelb",
},
@@ -260,4 +259,5 @@ static __exit void fake_remove_module(void)
module_init(fakelb_init_module);
module_exit(fake_remove_module);
+MODULE_DESCRIPTION("IEEE 802.15.4 loopback driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index 31cba9aa7636..2c2483bbe780 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -1035,7 +1035,7 @@ err_slave:
return err;
}
-static int hwsim_remove(struct platform_device *pdev)
+static void hwsim_remove(struct platform_device *pdev)
{
struct hwsim_phy *phy, *tmp;
@@ -1043,13 +1043,11 @@ static int hwsim_remove(struct platform_device *pdev)
list_for_each_entry_safe(phy, tmp, &hwsim_phys, list)
hwsim_del(phy);
mutex_unlock(&hwsim_phys_lock);
-
- return 0;
}
static struct platform_driver mac802154hwsim_driver = {
.probe = hwsim_probe,
- .remove = hwsim_remove,
+ .remove_new = hwsim_remove,
.driver = {
.name = "mac802154_hwsim",
},
diff --git a/drivers/net/ipa/Makefile b/drivers/net/ipa/Makefile
index 7293d5cc2b2b..d3abb38633e0 100644
--- a/drivers/net/ipa/Makefile
+++ b/drivers/net/ipa/Makefile
@@ -2,12 +2,12 @@
#
# Makefile for the Qualcomm IPA driver.
-IPA_REG_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0
+IPA_REG_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.5
# Some IPA versions can reuse another set of GSI register definitions.
GSI_REG_VERSIONS := 3.1 3.5.1 4.0 4.5 4.9 4.11 5.0
-IPA_DATA_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0
+IPA_DATA_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 5.0 5.5
obj-$(CONFIG_QCOM_IPA) += ipa.o
diff --git a/drivers/net/ipa/data/ipa_data-v5.5.c b/drivers/net/ipa/data/ipa_data-v5.5.c
new file mode 100644
index 000000000000..2c6390f11354
--- /dev/null
+++ b/drivers/net/ipa/data/ipa_data-v5.5.c
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (C) 2023 Linaro Ltd. */
+
+#include <linux/kernel.h>
+#include <linux/log2.h>
+
+#include "../ipa_data.h"
+#include "../ipa_endpoint.h"
+#include "../ipa_mem.h"
+
+/** enum ipa_resource_type - IPA resource types for an SoC having IPA v5.5 */
+enum ipa_resource_type {
+ /* Source resource types; first must have value 0 */
+ IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS = 0,
+ IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS,
+ IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF,
+ IPA_RESOURCE_TYPE_SRC_HPS_DMARS,
+ IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES,
+
+ /* Destination resource types; first must have value 0 */
+ IPA_RESOURCE_TYPE_DST_DATA_SECTORS = 0,
+ IPA_RESOURCE_TYPE_DST_DPS_DMARS,
+ IPA_RESOURCE_TYPE_DST_ULSO_SEGMENTS,
+};
+
+/* Resource groups used for an SoC having IPA v5.5 */
+enum ipa_rsrc_group_id {
+ /* Source resource group identifiers */
+ IPA_RSRC_GROUP_SRC_UL = 0,
+ IPA_RSRC_GROUP_SRC_DL,
+ IPA_RSRC_GROUP_SRC_UNUSED_2,
+ IPA_RSRC_GROUP_SRC_UNUSED_3,
+ IPA_RSRC_GROUP_SRC_URLLC,
+ IPA_RSRC_GROUP_SRC_U_RX_QC,
+ IPA_RSRC_GROUP_SRC_COUNT, /* Last in set; not a source group */
+
+ /* Destination resource group identifiers */
+ IPA_RSRC_GROUP_DST_UL = 0,
+ IPA_RSRC_GROUP_DST_DL,
+ IPA_RSRC_GROUP_DST_UNUSED_2,
+ IPA_RSRC_GROUP_DST_UNUSED_3,
+ IPA_RSRC_GROUP_DST_UNUSED_4,
+ IPA_RSRC_GROUP_DST_UC,
+ IPA_RSRC_GROUP_DST_DRB_IP,
+ IPA_RSRC_GROUP_DST_COUNT, /* Last; not a destination group */
+};
+
+/* QSB configuration data for an SoC having IPA v5.5 */
+static const struct ipa_qsb_data ipa_qsb_data[] = {
+ [IPA_QSB_MASTER_DDR] = {
+ .max_writes = 0, /* Unlimited */
+ .max_reads = 12,
+ .max_reads_beats = 0,
+ },
+ [IPA_QSB_MASTER_PCIE] = {
+ .max_writes = 0, /* Unlimited */
+ .max_reads = 8,
+ .max_reads_beats = 0,
+ },
+};
+
+/* Endpoint configuration data for an SoC having IPA v5.5 */
+static const struct ipa_gsi_endpoint_data ipa_gsi_endpoint_data[] = {
+ [IPA_ENDPOINT_AP_COMMAND_TX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 12,
+ .endpoint_id = 14,
+ .toward_ipa = true,
+ .channel = {
+ .tre_count = 256,
+ .event_count = 256,
+ .tlv_count = 20,
+ },
+ .endpoint = {
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_SRC_UL,
+ .dma_mode = true,
+ .dma_endpoint = IPA_ENDPOINT_AP_LAN_RX,
+ .tx = {
+ .seq_type = IPA_SEQ_DMA,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_AP_LAN_RX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 13,
+ .endpoint_id = 16,
+ .toward_ipa = false,
+ .channel = {
+ .tre_count = 256,
+ .event_count = 256,
+ .tlv_count = 9,
+ },
+ .endpoint = {
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_DST_UL,
+ .aggregation = true,
+ .status_enable = true,
+ .rx = {
+ .buffer_size = 8192,
+ .pad_align = ilog2(sizeof(u32)),
+ .aggr_time_limit = 500,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_AP_MODEM_TX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 11,
+ .endpoint_id = 2,
+ .toward_ipa = true,
+ .channel = {
+ .tre_count = 512,
+ .event_count = 512,
+ .tlv_count = 25,
+ },
+ .endpoint = {
+ .filter_support = true,
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_SRC_UL,
+ .checksum = true,
+ .qmap = true,
+ .status_enable = true,
+ .tx = {
+ .seq_type = IPA_SEQ_2_PASS_SKIP_LAST_UC,
+ .status_endpoint =
+ IPA_ENDPOINT_MODEM_AP_RX,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_AP_MODEM_RX] = {
+ .ee_id = GSI_EE_AP,
+ .channel_id = 1,
+ .endpoint_id = 23,
+ .toward_ipa = false,
+ .channel = {
+ .tre_count = 256,
+ .event_count = 256,
+ .tlv_count = 9,
+ },
+ .endpoint = {
+ .config = {
+ .resource_group = IPA_RSRC_GROUP_DST_DL,
+ .checksum = true,
+ .qmap = true,
+ .aggregation = true,
+ .rx = {
+ .buffer_size = 8192,
+ .aggr_time_limit = 500,
+ .aggr_close_eof = true,
+ },
+ },
+ },
+ },
+ [IPA_ENDPOINT_MODEM_AP_TX] = {
+ .ee_id = GSI_EE_MODEM,
+ .channel_id = 0,
+ .endpoint_id = 12,
+ .toward_ipa = true,
+ .endpoint = {
+ .filter_support = true,
+ },
+ },
+ [IPA_ENDPOINT_MODEM_AP_RX] = {
+ .ee_id = GSI_EE_MODEM,
+ .channel_id = 7,
+ .endpoint_id = 21,
+ .toward_ipa = false,
+ },
+ [IPA_ENDPOINT_MODEM_DL_NLO_TX] = {
+ .ee_id = GSI_EE_MODEM,
+ .channel_id = 2,
+ .endpoint_id = 15,
+ .toward_ipa = true,
+ .endpoint = {
+ .filter_support = true,
+ },
+ },
+};
+
+/* Source resource configuration data for an SoC having IPA v5.5 */
+static const struct ipa_resource ipa_resource_src[] = {
+ [IPA_RESOURCE_TYPE_SRC_PKT_CONTEXTS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 3, .max = 9,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 4, .max = 10,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_URLLC] = {
+ .min = 1, .max = 63,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_U_RX_QC] = {
+ .min = 0, .max = 63,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_LISTS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 9, .max = 9,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 12, .max = 12,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_URLLC] = {
+ .min = 10, .max = 10,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_DESCRIPTOR_BUFF] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 9, .max = 9,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 24, .max = 24,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_URLLC] = {
+ .min = 20, .max = 20,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_HPS_DMARS] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 0, .max = 63,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 0, .max = 63,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_URLLC] = {
+ .min = 1, .max = 63,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_U_RX_QC] = {
+ .min = 0, .max = 63,
+ },
+ },
+ [IPA_RESOURCE_TYPE_SRC_ACK_ENTRIES] = {
+ .limits[IPA_RSRC_GROUP_SRC_UL] = {
+ .min = 22, .max = 22,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_DL] = {
+ .min = 16, .max = 16,
+ },
+ .limits[IPA_RSRC_GROUP_SRC_URLLC] = {
+ .min = 16, .max = 16,
+ },
+ },
+};
+
+/* Destination resource configuration data for an SoC having IPA v5.5 */
+static const struct ipa_resource ipa_resource_dst[] = {
+ [IPA_RESOURCE_TYPE_DST_DATA_SECTORS] = {
+ .limits[IPA_RSRC_GROUP_DST_UL] = {
+ .min = 6, .max = 6,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DL] = {
+ .min = 5, .max = 5,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DRB_IP] = {
+ .min = 39, .max = 39,
+ },
+ },
+ [IPA_RESOURCE_TYPE_DST_DPS_DMARS] = {
+ .limits[IPA_RSRC_GROUP_DST_UL] = {
+ .min = 0, .max = 3,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DL] = {
+ .min = 0, .max = 3,
+ },
+ },
+ [IPA_RESOURCE_TYPE_DST_ULSO_SEGMENTS] = {
+ .limits[IPA_RSRC_GROUP_DST_UL] = {
+ .min = 0, .max = 63,
+ },
+ .limits[IPA_RSRC_GROUP_DST_DL] = {
+ .min = 0, .max = 63,
+ },
+ },
+};
+
+/* Resource configuration data for an SoC having IPA v5.5 */
+static const struct ipa_resource_data ipa_resource_data = {
+ .rsrc_group_dst_count = IPA_RSRC_GROUP_DST_COUNT,
+ .rsrc_group_src_count = IPA_RSRC_GROUP_SRC_COUNT,
+ .resource_src_count = ARRAY_SIZE(ipa_resource_src),
+ .resource_src = ipa_resource_src,
+ .resource_dst_count = ARRAY_SIZE(ipa_resource_dst),
+ .resource_dst = ipa_resource_dst,
+};
+
+/* IPA-resident memory region data for an SoC having IPA v5.5 */
+static const struct ipa_mem ipa_mem_local_data[] = {
+ {
+ .id = IPA_MEM_UC_EVENT_RING,
+ .offset = 0x0000,
+ .size = 0x1000,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_UC_SHARED,
+ .offset = 0x1000,
+ .size = 0x0080,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_UC_INFO,
+ .offset = 0x1080,
+ .size = 0x0200,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_V4_FILTER_HASHED,
+ .offset = 0x1288,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V4_FILTER,
+ .offset = 0x1308,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_FILTER_HASHED,
+ .offset = 0x1388,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_FILTER,
+ .offset = 0x1408,
+ .size = 0x0078,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V4_ROUTE_HASHED,
+ .offset = 0x1488,
+ .size = 0x0098,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V4_ROUTE,
+ .offset = 0x1528,
+ .size = 0x0098,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_ROUTE_HASHED,
+ .offset = 0x15c8,
+ .size = 0x0098,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_V6_ROUTE,
+ .offset = 0x1668,
+ .size = 0x0098,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_MODEM_HEADER,
+ .offset = 0x1708,
+ .size = 0x0240,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_AP_HEADER,
+ .offset = 0x1948,
+ .size = 0x01e0,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_MODEM_PROC_CTX,
+ .offset = 0x1b40,
+ .size = 0x0b20,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_AP_PROC_CTX,
+ .offset = 0x2660,
+ .size = 0x0200,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_STATS_QUOTA_MODEM,
+ .offset = 0x2868,
+ .size = 0x0060,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_STATS_QUOTA_AP,
+ .offset = 0x28c8,
+ .size = 0x0048,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_STATS_TETHERING,
+ .offset = 0x2910,
+ .size = 0x03c0,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_AP_V4_FILTER,
+ .offset = 0x29b8,
+ .size = 0x0188,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_AP_V6_FILTER,
+ .offset = 0x2b40,
+ .size = 0x0228,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_STATS_FILTER_ROUTE,
+ .offset = 0x2cd0,
+ .size = 0x0ba0,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_STATS_DROP,
+ .offset = 0x3870,
+ .size = 0x0020,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_MODEM,
+ .offset = 0x3898,
+ .size = 0x0d48,
+ .canary_count = 2,
+ },
+ {
+ .id = IPA_MEM_NAT_TABLE,
+ .offset = 0x45e0,
+ .size = 0x0900,
+ .canary_count = 0,
+ },
+ {
+ .id = IPA_MEM_PDN_CONFIG,
+ .offset = 0x4ee8,
+ .size = 0x0100,
+ .canary_count = 2,
+ },
+};
+
+/* Memory configuration data for an SoC having IPA v5.5 */
+static const struct ipa_mem_data ipa_mem_data = {
+ .local_count = ARRAY_SIZE(ipa_mem_local_data),
+ .local = ipa_mem_local_data,
+ .imem_addr = 0x14688000,
+ .imem_size = 0x00002000,
+ .smem_id = 497,
+ .smem_size = 0x0000b000,
+};
+
+/* Interconnect rates are in 1000 byte/second units */
+static const struct ipa_interconnect_data ipa_interconnect_data[] = {
+ {
+ .name = "memory",
+ .peak_bandwidth = 1900000, /* 1.9 GBps */
+ .average_bandwidth = 600000, /* 600 MBps */
+ },
+ /* Average rate is unused for the next interconnect */
+ {
+ .name = "config",
+ .peak_bandwidth = 76800, /* 76.8 MBps */
+ .average_bandwidth = 0, /* unused */
+ },
+};
+
+/* Clock and interconnect configuration data for an SoC having IPA v5.5 */
+static const struct ipa_power_data ipa_power_data = {
+ .core_clock_rate = 120 * 1000 * 1000, /* Hz */
+ .interconnect_count = ARRAY_SIZE(ipa_interconnect_data),
+ .interconnect_data = ipa_interconnect_data,
+};
+
+/* Configuration data for an SoC having IPA v5.5. */
+const struct ipa_data ipa_data_v5_5 = {
+ .version = IPA_VERSION_5_5,
+ .qsb_count = ARRAY_SIZE(ipa_qsb_data),
+ .qsb_data = ipa_qsb_data,
+ .modem_route_count = 11,
+ .endpoint_count = ARRAY_SIZE(ipa_gsi_endpoint_data),
+ .endpoint_data = ipa_gsi_endpoint_data,
+ .resource_data = &ipa_resource_data,
+ .mem_data = &ipa_mem_data,
+ .power_data = &ipa_power_data,
+};
diff --git a/drivers/net/ipa/gsi_reg.c b/drivers/net/ipa/gsi_reg.c
index c5458e28b12f..106c43884aef 100644
--- a/drivers/net/ipa/gsi_reg.c
+++ b/drivers/net/ipa/gsi_reg.c
@@ -110,6 +110,7 @@ static const struct regs *gsi_regs(struct gsi *gsi)
return &gsi_regs_v4_11;
case IPA_VERSION_5_0:
+ case IPA_VERSION_5_5:
return &gsi_regs_v5_0;
default:
diff --git a/drivers/net/ipa/ipa_data.h b/drivers/net/ipa/ipa_data.h
index ce82b00fdc49..2a1605e67b65 100644
--- a/drivers/net/ipa/ipa_data.h
+++ b/drivers/net/ipa/ipa_data.h
@@ -250,5 +250,6 @@ extern const struct ipa_data ipa_data_v4_7;
extern const struct ipa_data ipa_data_v4_9;
extern const struct ipa_data ipa_data_v4_11;
extern const struct ipa_data ipa_data_v5_0;
+extern const struct ipa_data ipa_data_v5_5;
#endif /* _IPA_DATA_H_ */
diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c
index 4bc05948f772..a78c692f2d3c 100644
--- a/drivers/net/ipa/ipa_interrupt.c
+++ b/drivers/net/ipa/ipa_interrupt.c
@@ -212,7 +212,7 @@ void ipa_interrupt_suspend_clear_all(struct ipa_interrupt *interrupt)
u32 unit_count;
u32 unit;
- unit_count = roundup(ipa->endpoint_count, 32);
+ unit_count = DIV_ROUND_UP(ipa->endpoint_count, 32);
for (unit = 0; unit < unit_count; unit++) {
const struct reg *reg;
u32 val;
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index da853353a5c7..00475fd7a205 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -74,6 +74,7 @@
#define IPA_PAS_ID 15
/* Shift of 19.2 MHz timestamp to achieve lower resolution timestamps */
+/* IPA v5.5+ does not specify Qtime timestamp config for DPL */
#define DPL_TIMESTAMP_SHIFT 14 /* ~1.172 kHz, ~853 usec per tick */
#define TAG_TIMESTAMP_SHIFT 14
#define NAT_TIMESTAMP_SHIFT 24 /* ~1.144 Hz, ~874 msec per tick */
@@ -376,9 +377,11 @@ static void ipa_qtime_config(struct ipa *ipa)
iowrite32(0, ipa->reg_virt + reg_offset(reg));
reg = ipa_reg(ipa, QTIME_TIMESTAMP_CFG);
- /* Set DPL time stamp resolution to use Qtime (instead of 1 msec) */
- val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT);
- val |= reg_bit(reg, DPL_TIMESTAMP_SEL);
+ if (ipa->version < IPA_VERSION_5_5) {
+ /* Set DPL time stamp resolution to use Qtime (not 1 msec) */
+ val = reg_encode(reg, DPL_TIMESTAMP_LSB, DPL_TIMESTAMP_SHIFT);
+ val |= reg_bit(reg, DPL_TIMESTAMP_SEL);
+ }
/* Configure tag and NAT Qtime timestamp resolution as well */
val = reg_encode(reg, TAG_TIMESTAMP_LSB, TAG_TIMESTAMP_SHIFT);
val = reg_encode(reg, NAT_TIMESTAMP_LSB, NAT_TIMESTAMP_SHIFT);
@@ -688,6 +691,10 @@ static const struct of_device_id ipa_match[] = {
.compatible = "qcom,sdx65-ipa",
.data = &ipa_data_v5_0,
},
+ {
+ .compatible = "qcom,sm8550-ipa",
+ .data = &ipa_data_v5_5,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, ipa_match);
@@ -936,7 +943,7 @@ err_power_exit:
return ret;
}
-static int ipa_remove(struct platform_device *pdev)
+static void ipa_remove(struct platform_device *pdev)
{
struct ipa *ipa = dev_get_drvdata(&pdev->dev);
struct ipa_power *power = ipa->power;
@@ -959,8 +966,16 @@ static int ipa_remove(struct platform_device *pdev)
usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
ret = ipa_modem_stop(ipa);
}
- if (ret)
- return ret;
+ if (ret) {
+ /*
+ * Not cleaning up here properly might also yield a
+ * crash later on. As the device is still unregistered
+ * in this case, this might even yield a crash later on.
+ */
+ dev_err(dev, "Failed to stop modem (%pe), leaking resources\n",
+ ERR_PTR(ret));
+ return;
+ }
ipa_teardown(ipa);
}
@@ -978,17 +993,6 @@ out_power_put:
ipa_power_exit(power);
dev_info(dev, "IPA driver removed");
-
- return 0;
-}
-
-static void ipa_shutdown(struct platform_device *pdev)
-{
- int ret;
-
- ret = ipa_remove(pdev);
- if (ret)
- dev_err(&pdev->dev, "shutdown: remove returned %d\n", ret);
}
static const struct attribute_group *ipa_attribute_groups[] = {
@@ -1001,8 +1005,8 @@ static const struct attribute_group *ipa_attribute_groups[] = {
static struct platform_driver ipa_driver = {
.probe = ipa_probe,
- .remove = ipa_remove,
- .shutdown = ipa_shutdown,
+ .remove_new = ipa_remove,
+ .shutdown = ipa_remove,
.driver = {
.name = "ipa",
.pm = &ipa_pm_ops,
diff --git a/drivers/net/ipa/ipa_mem.c b/drivers/net/ipa/ipa_mem.c
index db6ada2343af..694960537ecd 100644
--- a/drivers/net/ipa/ipa_mem.c
+++ b/drivers/net/ipa/ipa_mem.c
@@ -165,7 +165,7 @@ static bool ipa_mem_id_valid(struct ipa *ipa, enum ipa_mem_id mem_id)
case IPA_MEM_AP_V4_FILTER:
case IPA_MEM_AP_V6_FILTER:
- if (version != IPA_VERSION_5_0)
+ if (version < IPA_VERSION_5_0)
return false;
break;
diff --git a/drivers/net/ipa/ipa_reg.c b/drivers/net/ipa/ipa_reg.c
index 818a84f7c42d..6a3203ae6f1e 100644
--- a/drivers/net/ipa/ipa_reg.c
+++ b/drivers/net/ipa/ipa_reg.c
@@ -44,12 +44,12 @@ static bool ipa_reg_id_valid(struct ipa *ipa, enum ipa_reg_id reg_id)
case DST_RSRC_GRP_45_RSRC_TYPE:
return version <= IPA_VERSION_3_1 ||
version == IPA_VERSION_4_5 ||
- version == IPA_VERSION_5_0;
+ version >= IPA_VERSION_5_0;
case SRC_RSRC_GRP_67_RSRC_TYPE:
case DST_RSRC_GRP_67_RSRC_TYPE:
return version <= IPA_VERSION_3_1 ||
- version == IPA_VERSION_5_0;
+ version >= IPA_VERSION_5_0;
case ENDP_FILTER_ROUTER_HSH_CFG:
return version < IPA_VERSION_5_0 &&
@@ -125,6 +125,8 @@ static const struct regs *ipa_regs(enum ipa_version version)
return &ipa_regs_v4_11;
case IPA_VERSION_5_0:
return &ipa_regs_v5_0;
+ case IPA_VERSION_5_5:
+ return &ipa_regs_v5_5;
default:
return NULL;
}
diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h
index 3ac48dea865b..2998f115f12c 100644
--- a/drivers/net/ipa/ipa_reg.h
+++ b/drivers/net/ipa/ipa_reg.h
@@ -240,25 +240,25 @@ enum ipa_reg_local_pkt_proc_cntxt_field_id {
/* COUNTER_CFG register */
enum ipa_reg_counter_cfg_field_id {
- EOT_COAL_GRANULARITY, /* Not v3.5+ */
+ EOT_COAL_GRANULARITY, /* Not IPA v3.5+ */
AGGR_GRANULARITY,
};
/* IPA_TX_CFG register */
enum ipa_reg_ipa_tx_cfg_field_id {
- TX0_PREFETCH_DISABLE, /* Not v4.0+ */
- TX1_PREFETCH_DISABLE, /* Not v4.0+ */
- PREFETCH_ALMOST_EMPTY_SIZE, /* Not v4.0+ */
- PREFETCH_ALMOST_EMPTY_SIZE_TX0, /* v4.0+ */
- DMAW_SCND_OUTSD_PRED_THRESHOLD, /* v4.0+ */
- DMAW_SCND_OUTSD_PRED_EN, /* v4.0+ */
- DMAW_MAX_BEATS_256_DIS, /* v4.0+ */
- PA_MASK_EN, /* v4.0+ */
- PREFETCH_ALMOST_EMPTY_SIZE_TX1, /* v4.0+ */
- DUAL_TX_ENABLE, /* v4.5+ */
- SSPND_PA_NO_START_STATE, /* v4,2+, not v4.5 */
- SSPND_PA_NO_BQ_STATE, /* v4.2 only */
- HOLB_STICKY_DROP_EN, /* v5.0+ */
+ TX0_PREFETCH_DISABLE, /* Not IPA v4.0+ */
+ TX1_PREFETCH_DISABLE, /* Not IPA v4.0+ */
+ PREFETCH_ALMOST_EMPTY_SIZE, /* Not IPA v4.0+ */
+ PREFETCH_ALMOST_EMPTY_SIZE_TX0, /* IPA v4.0+ */
+ DMAW_SCND_OUTSD_PRED_THRESHOLD, /* IPA v4.0+ */
+ DMAW_SCND_OUTSD_PRED_EN, /* IPA v4.0+ */
+ DMAW_MAX_BEATS_256_DIS, /* IPA v4.0+ */
+ PA_MASK_EN, /* IPA v4.0+ */
+ PREFETCH_ALMOST_EMPTY_SIZE_TX1, /* IPA v4.0+ */
+ DUAL_TX_ENABLE, /* IPA v4.5+ */
+ SSPND_PA_NO_START_STATE, /* IPA v4,2+, not IPA v4.5 */
+ SSPND_PA_NO_BQ_STATE, /* IPA v4.2 only */
+ HOLB_STICKY_DROP_EN, /* IPA v5.0+ */
};
/* FLAVOR_0 register */
@@ -277,8 +277,8 @@ enum ipa_reg_idle_indication_cfg_field_id {
/* QTIME_TIMESTAMP_CFG register */
enum ipa_reg_qtime_timestamp_cfg_field_id {
- DPL_TIMESTAMP_LSB,
- DPL_TIMESTAMP_SEL,
+ DPL_TIMESTAMP_LSB, /* Not IPA v5.5+ */
+ DPL_TIMESTAMP_SEL, /* Not IPA v5.5+ */
TAG_TIMESTAMP_LSB,
NAT_TIMESTAMP_LSB,
};
@@ -319,8 +319,8 @@ enum ipa_reg_rsrc_grp_rsrc_type_field_id {
/* ENDP_INIT_CTRL register */
enum ipa_reg_endp_init_ctrl_field_id {
- ENDP_SUSPEND, /* Not v4.0+ */
- ENDP_DELAY, /* Not v4.2+ */
+ ENDP_SUSPEND, /* Not IPA v4.0+ */
+ ENDP_DELAY, /* Not IPA v4.2+ */
};
/* ENDP_INIT_CFG register */
@@ -329,6 +329,7 @@ enum ipa_reg_endp_init_cfg_field_id {
CS_OFFLOAD_EN,
CS_METADATA_HDR_OFFSET,
CS_GEN_QMB_MASTER_SEL,
+ PIPE_REPLICATE_EN, /* IPA v5.5+ */
};
/** enum ipa_cs_offload_en - ENDP_INIT_CFG register CS_OFFLOAD_EN field value */
@@ -359,11 +360,11 @@ enum ipa_reg_endp_init_hdr_field_id {
HDR_ADDITIONAL_CONST_LEN,
HDR_OFST_PKT_SIZE_VALID,
HDR_OFST_PKT_SIZE,
- HDR_A5_MUX, /* Not v4.9+ */
+ HDR_A5_MUX, /* Not IPA v4.9+ */
HDR_LEN_INC_DEAGG_HDR,
- HDR_METADATA_REG_VALID, /* Not v4.5+ */
- HDR_LEN_MSB, /* v4.5+ */
- HDR_OFST_METADATA_MSB, /* v4.5+ */
+ HDR_METADATA_REG_VALID, /* Not IPA v4.5+ */
+ HDR_LEN_MSB, /* IPA v4.5+ */
+ HDR_OFST_METADATA_MSB, /* IPA v4.5+ */
};
/* ENDP_INIT_HDR_EXT register */
@@ -374,23 +375,23 @@ enum ipa_reg_endp_init_hdr_ext_field_id {
HDR_PAYLOAD_LEN_INC_PADDING,
HDR_TOTAL_LEN_OR_PAD_OFFSET,
HDR_PAD_TO_ALIGNMENT,
- HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB, /* v4.5+ */
- HDR_OFST_PKT_SIZE_MSB, /* v4.5+ */
- HDR_ADDITIONAL_CONST_LEN_MSB, /* v4.5+ */
- HDR_BYTES_TO_REMOVE_VALID, /* v5.0+ */
- HDR_BYTES_TO_REMOVE, /* v5.0+ */
+ HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB, /* IPA v4.5+ */
+ HDR_OFST_PKT_SIZE_MSB, /* IPA v4.5+ */
+ HDR_ADDITIONAL_CONST_LEN_MSB, /* IPA v4.5+ */
+ HDR_BYTES_TO_REMOVE_VALID, /* IPA v5.0+ */
+ HDR_BYTES_TO_REMOVE, /* IPA v5.0+ */
};
/* ENDP_INIT_MODE register */
enum ipa_reg_endp_init_mode_field_id {
ENDP_MODE,
- DCPH_ENABLE, /* v4.5+ */
+ DCPH_ENABLE, /* IPA v4.5+ */
DEST_PIPE_INDEX,
BYTE_THRESHOLD,
- PIPE_REPLICATION_EN,
+ PIPE_REPLICATION_EN, /* Not IPA v5.5+ */
PAD_EN,
- HDR_FTCH_DISABLE, /* v4.5+ */
- DRBIP_ACL_ENABLE, /* v4.9+ */
+ HDR_FTCH_DISABLE, /* IPA v4.5+ */
+ DRBIP_ACL_ENABLE, /* IPA v4.9+ */
};
/** enum ipa_mode - ENDP_INIT_MODE register MODE field value */
@@ -412,6 +413,7 @@ enum ipa_reg_endp_init_aggr_field_id {
FORCE_CLOSE,
HARD_BYTE_LIMIT_EN,
AGGR_GRAN_SEL,
+ AGGR_COAL_L2, /* IPA v5.5+ */
};
/** enum ipa_aggr_en - ENDP_INIT_AGGR register AGGR_EN field value */
@@ -439,10 +441,10 @@ enum ipa_reg_endp_init_hol_block_en_field_id {
/* ENDP_INIT_HOL_BLOCK_TIMER register */
enum ipa_reg_endp_init_hol_block_timer_field_id {
- TIMER_BASE_VALUE, /* Not v4.5+ */
- TIMER_SCALE, /* v4.2 only */
- TIMER_LIMIT, /* v4.5+ */
- TIMER_GRAN_SEL, /* v4.5+ */
+ TIMER_BASE_VALUE, /* Not IPA v4.5+ */
+ TIMER_SCALE, /* IPA v4.2 only */
+ TIMER_LIMIT, /* IPA v4.5+ */
+ TIMER_GRAN_SEL, /* IPA v4.5+ */
};
/* ENDP_INIT_DEAGGR register */
@@ -463,7 +465,7 @@ enum ipa_reg_endp_init_rsrc_grp_field_id {
/* ENDP_INIT_SEQ register */
enum ipa_reg_endp_init_seq_field_id {
SEQ_TYPE,
- SEQ_REP_TYPE, /* Not v4.5+ */
+ SEQ_REP_TYPE, /* Not IPA v4.5+ */
};
/**
@@ -512,8 +514,8 @@ enum ipa_seq_rep_type {
enum ipa_reg_endp_status_field_id {
STATUS_EN,
STATUS_ENDP,
- STATUS_LOCATION, /* Not v4.5+ */
- STATUS_PKT_SUPPRESS, /* v4.0+ */
+ STATUS_LOCATION, /* Not IPA v4.5+ */
+ STATUS_PKT_SUPPRESS, /* IPA v4.0+ */
};
/* ENDP_FILTER_ROUTER_HSH_CFG register */
@@ -585,11 +587,12 @@ enum ipa_reg_endp_cache_cfg_field_id {
* @IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN: (Not currently used)
* @IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN: (Not currently used)
* @IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN: (Not currently used)
+ * @IPA_IRQ_ERROR_NON_FATAL: (Not currently used)
+ * @IPA_IRQ_ERROR_FATAL: (Not currently used)
*/
enum ipa_irq_id {
- IPA_IRQ_BAD_SNOC_ACCESS = 0x0,
- /* The next bit is not present for IPA v3.5+ */
- IPA_IRQ_EOT_COAL = 0x1,
+ IPA_IRQ_BAD_SNOC_ACCESS = 0x0, /* Not IPA v5.5+ */
+ IPA_IRQ_EOT_COAL = 0x1, /* Not IPA v3.5+ */
IPA_IRQ_UC_0 = 0x2,
IPA_IRQ_UC_1 = 0x3,
IPA_IRQ_UC_2 = 0x4,
@@ -597,11 +600,11 @@ enum ipa_irq_id {
IPA_IRQ_UC_IN_Q_NOT_EMPTY = 0x6,
IPA_IRQ_UC_RX_CMD_Q_NOT_FULL = 0x7,
IPA_IRQ_PROC_UC_ACK_Q_NOT_EMPTY = 0x8,
- IPA_IRQ_RX_ERR = 0x9,
- IPA_IRQ_DEAGGR_ERR = 0xa,
- IPA_IRQ_TX_ERR = 0xb,
- IPA_IRQ_STEP_MODE = 0xc,
- IPA_IRQ_PROC_ERR = 0xd,
+ IPA_IRQ_RX_ERR = 0x9, /* Not IPA v5.5+ */
+ IPA_IRQ_DEAGGR_ERR = 0xa, /* Not IPA v5.5+ */
+ IPA_IRQ_TX_ERR = 0xb, /* Not IPA v5.5+ */
+ IPA_IRQ_STEP_MODE = 0xc, /* Not IPA v5.5+ */
+ IPA_IRQ_PROC_ERR = 0xd, /* Not IPA v5.5+ */
IPA_IRQ_TX_SUSPEND = 0xe,
IPA_IRQ_TX_HOLB_DROP = 0xf,
IPA_IRQ_BAM_GSI_IDLE = 0x10,
@@ -610,17 +613,16 @@ enum ipa_irq_id {
IPA_IRQ_PIPE_YELLOW_ABOVE = 0x13,
IPA_IRQ_PIPE_RED_ABOVE = 0x14,
IPA_IRQ_UCP = 0x15,
- /* The next bit is not present for IPA v4.5+ */
- IPA_IRQ_DCMP = 0x16,
+ IPA_IRQ_DCMP = 0x16, /* Not IPA v4.5+ */
IPA_IRQ_GSI_EE = 0x17,
IPA_IRQ_GSI_IPA_IF_TLV_RCVD = 0x18,
IPA_IRQ_GSI_UC = 0x19,
- /* The next bit is present for IPA v4.5+ */
- IPA_IRQ_TLV_LEN_MIN_DSM = 0x1a,
- /* The next three bits are present for IPA v4.9+ */
- IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN = 0x1b,
- IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN = 0x1c,
- IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN = 0x1d,
+ IPA_IRQ_TLV_LEN_MIN_DSM = 0x1a, /* IPA v4.5-v5.2 */
+ IPA_IRQ_DRBIP_PKT_EXCEED_MAX_SIZE_EN = 0x1b, /* IPA v4.9-v5.2 */
+ IPA_IRQ_DRBIP_DATA_SCTR_CFG_ERROR_EN = 0x1c, /* IPA v4.9-v5.2 */
+ IPA_IRQ_DRBIP_IMM_CMD_NO_FLSH_HZRD_EN = 0x1d, /* IPA v4.9-v5.2 */
+ IPA_IRQ_ERROR_NON_FATAL = 0x1e, /* IPA v5.5+ */
+ IPA_IRQ_ERROR_FATAL = 0x1f, /* IPA v5.5+ */
IPA_IRQ_COUNT, /* Last; not an id */
};
@@ -637,6 +639,7 @@ extern const struct regs ipa_regs_v4_7;
extern const struct regs ipa_regs_v4_9;
extern const struct regs ipa_regs_v4_11;
extern const struct regs ipa_regs_v5_0;
+extern const struct regs ipa_regs_v5_5;
const struct reg *ipa_reg(struct ipa *ipa, enum ipa_reg_id reg_id);
diff --git a/drivers/net/ipa/ipa_version.h b/drivers/net/ipa/ipa_version.h
index 06e75b8ece7e..38150345b607 100644
--- a/drivers/net/ipa/ipa_version.h
+++ b/drivers/net/ipa/ipa_version.h
@@ -56,6 +56,7 @@ static inline bool ipa_version_supported(enum ipa_version version)
case IPA_VERSION_4_9:
case IPA_VERSION_4_11:
case IPA_VERSION_5_0:
+ case IPA_VERSION_5_5:
return true;
default:
return false;
diff --git a/drivers/net/ipa/reg/ipa_reg-v5.5.c b/drivers/net/ipa/reg/ipa_reg-v5.5.c
new file mode 100644
index 000000000000..26ca9c9bac59
--- /dev/null
+++ b/drivers/net/ipa/reg/ipa_reg-v5.5.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (C) 2023 Linaro Ltd. */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bits.h>
+
+#include "../ipa_reg.h"
+#include "../ipa_version.h"
+
+static const u32 reg_flavor_0_fmask[] = {
+ [MAX_PIPES] = GENMASK(7, 0),
+ [MAX_CONS_PIPES] = GENMASK(15, 8),
+ [MAX_PROD_PIPES] = GENMASK(23, 16),
+ [PROD_LOWEST] = GENMASK(31, 24),
+};
+
+REG_FIELDS(FLAVOR_0, flavor_0, 0x00000000);
+
+static const u32 reg_comp_cfg_fmask[] = {
+ [RAM_ARB_PRI_CLIENT_SAMP_FIX_DIS] = BIT(0),
+ [GSI_SNOC_BYPASS_DIS] = BIT(1),
+ [GEN_QMB_0_SNOC_BYPASS_DIS] = BIT(2),
+ [GEN_QMB_1_SNOC_BYPASS_DIS] = BIT(3),
+ /* Bit 4 reserved */
+ [IPA_QMB_SELECT_CONS_EN] = BIT(5),
+ [IPA_QMB_SELECT_PROD_EN] = BIT(6),
+ [GSI_MULTI_INORDER_RD_DIS] = BIT(7),
+ [GSI_MULTI_INORDER_WR_DIS] = BIT(8),
+ [GEN_QMB_0_MULTI_INORDER_RD_DIS] = BIT(9),
+ [GEN_QMB_1_MULTI_INORDER_RD_DIS] = BIT(10),
+ [GEN_QMB_0_MULTI_INORDER_WR_DIS] = BIT(11),
+ [GEN_QMB_1_MULTI_INORDER_WR_DIS] = BIT(12),
+ [GEN_QMB_0_SNOC_CNOC_LOOP_PROT_DIS] = BIT(13),
+ [GSI_SNOC_CNOC_LOOP_PROT_DISABLE] = BIT(14),
+ [GSI_MULTI_AXI_MASTERS_DIS] = BIT(15),
+ [IPA_QMB_SELECT_GLOBAL_EN] = BIT(16),
+ /* Bits 17-18 reserved */
+ [QMB_RAM_RD_CACHE_DISABLE] = BIT(19),
+ [GENQMB_AOOOWR] = BIT(20),
+ [IF_OUT_OF_BUF_STOP_RESET_MASK_EN] = BIT(21),
+ [ATOMIC_FETCHER_ARB_LOCK_DIS] = GENMASK(27, 22),
+ /* Bits 28-29 reserved */
+ [GEN_QMB_1_DYNAMIC_ASIZE] = BIT(30),
+ [GEN_QMB_0_DYNAMIC_ASIZE] = BIT(31),
+};
+
+REG_FIELDS(COMP_CFG, comp_cfg, 0x00000048);
+
+static const u32 reg_clkon_cfg_fmask[] = {
+ [CLKON_RX] = BIT(0),
+ [CLKON_PROC] = BIT(1),
+ [TX_WRAPPER] = BIT(2),
+ [CLKON_MISC] = BIT(3),
+ [RAM_ARB] = BIT(4),
+ [FTCH_HPS] = BIT(5),
+ [FTCH_DPS] = BIT(6),
+ [CLKON_HPS] = BIT(7),
+ [CLKON_DPS] = BIT(8),
+ [RX_HPS_CMDQS] = BIT(9),
+ [HPS_DPS_CMDQS] = BIT(10),
+ [DPS_TX_CMDQS] = BIT(11),
+ [RSRC_MNGR] = BIT(12),
+ [CTX_HANDLER] = BIT(13),
+ [ACK_MNGR] = BIT(14),
+ [D_DCPH] = BIT(15),
+ [H_DCPH] = BIT(16),
+ /* Bit 17 reserved */
+ [NTF_TX_CMDQS] = BIT(18),
+ [CLKON_TX_0] = BIT(19),
+ [CLKON_TX_1] = BIT(20),
+ [CLKON_FNR] = BIT(21),
+ [QSB2AXI_CMDQ_L] = BIT(22),
+ [AGGR_WRAPPER] = BIT(23),
+ [RAM_SLAVEWAY] = BIT(24),
+ [CLKON_QMB] = BIT(25),
+ [WEIGHT_ARB] = BIT(26),
+ [GSI_IF] = BIT(27),
+ [CLKON_GLOBAL] = BIT(28),
+ [GLOBAL_2X_CLK] = BIT(29),
+ [DPL_FIFO] = BIT(30),
+ [DRBIP] = BIT(31),
+};
+
+REG_FIELDS(CLKON_CFG, clkon_cfg, 0x00000050);
+
+static const u32 reg_route_fmask[] = {
+ [ROUTE_DEF_PIPE] = GENMASK(7, 0),
+ [ROUTE_FRAG_DEF_PIPE] = GENMASK(15, 8),
+ [ROUTE_DEF_HDR_OFST] = GENMASK(25, 16),
+ [ROUTE_DEF_HDR_TABLE] = BIT(26),
+ [ROUTE_DEF_RETAIN_HDR] = BIT(27),
+ [ROUTE_DIS] = BIT(28),
+ /* Bits 29-31 reserved */
+};
+
+REG_FIELDS(ROUTE, route, 0x00000054);
+
+static const u32 reg_shared_mem_size_fmask[] = {
+ [MEM_SIZE] = GENMASK(15, 0),
+ [MEM_BADDR] = GENMASK(31, 16),
+};
+
+REG_FIELDS(SHARED_MEM_SIZE, shared_mem_size, 0x0000005c);
+
+static const u32 reg_qsb_max_writes_fmask[] = {
+ [GEN_QMB_0_MAX_WRITES] = GENMASK(3, 0),
+ [GEN_QMB_1_MAX_WRITES] = GENMASK(7, 4),
+ /* Bits 8-31 reserved */
+};
+
+REG_FIELDS(QSB_MAX_WRITES, qsb_max_writes, 0x00000070);
+
+static const u32 reg_qsb_max_reads_fmask[] = {
+ [GEN_QMB_0_MAX_READS] = GENMASK(3, 0),
+ [GEN_QMB_1_MAX_READS] = GENMASK(7, 4),
+ /* Bits 8-15 reserved */
+ [GEN_QMB_0_MAX_READS_BEATS] = GENMASK(23, 16),
+ [GEN_QMB_1_MAX_READS_BEATS] = GENMASK(31, 24),
+};
+
+REG_FIELDS(QSB_MAX_READS, qsb_max_reads, 0x00000074);
+
+/* Valid bits defined by ipa->available */
+
+REG_STRIDE(STATE_AGGR_ACTIVE, state_aggr_active, 0x00000120, 0x0004);
+
+static const u32 reg_filt_rout_cache_flush_fmask[] = {
+ [ROUTER_CACHE] = BIT(0),
+ /* Bits 1-3 reserved */
+ [FILTER_CACHE] = BIT(4),
+ /* Bits 5-31 reserved */
+};
+
+REG_FIELDS(FILT_ROUT_CACHE_FLUSH, filt_rout_cache_flush, 0x0000404);
+
+static const u32 reg_local_pkt_proc_cntxt_fmask[] = {
+ [IPA_BASE_ADDR] = GENMASK(17, 0),
+ /* Bits 18-31 reserved */
+};
+
+/* Offset must be a multiple of 8 */
+REG_FIELDS(LOCAL_PKT_PROC_CNTXT, local_pkt_proc_cntxt, 0x00000478);
+
+static const u32 reg_ipa_tx_cfg_fmask[] = {
+ /* Bits 0-1 reserved */
+ [PREFETCH_ALMOST_EMPTY_SIZE_TX0] = GENMASK(5, 2),
+ [DMAW_SCND_OUTSD_PRED_THRESHOLD] = GENMASK(9, 6),
+ [DMAW_SCND_OUTSD_PRED_EN] = BIT(10),
+ [DMAW_MAX_BEATS_256_DIS] = BIT(11),
+ [PA_MASK_EN] = BIT(12),
+ [PREFETCH_ALMOST_EMPTY_SIZE_TX1] = GENMASK(16, 13),
+ [DUAL_TX_ENABLE] = BIT(17),
+ [SSPND_PA_NO_START_STATE] = BIT(18),
+ /* Bit 19 reserved */
+ [HOLB_STICKY_DROP_EN] = BIT(20),
+ /* Bits 21-31 reserved */
+};
+
+REG_FIELDS(IPA_TX_CFG, ipa_tx_cfg, 0x00000488);
+
+static const u32 reg_idle_indication_cfg_fmask[] = {
+ [ENTER_IDLE_DEBOUNCE_THRESH] = GENMASK(15, 0),
+ [CONST_NON_IDLE_ENABLE] = BIT(16),
+ /* Bits 17-31 reserved */
+};
+
+REG_FIELDS(IDLE_INDICATION_CFG, idle_indication_cfg, 0x000004a8);
+
+static const u32 reg_qtime_timestamp_cfg_fmask[] = {
+ /* Bits 0-7 reserved */
+ [TAG_TIMESTAMP_LSB] = GENMASK(12, 8),
+ /* Bits 13-15 reserved */
+ [NAT_TIMESTAMP_LSB] = GENMASK(20, 16),
+ /* Bits 21-31 reserved */
+};
+
+REG_FIELDS(QTIME_TIMESTAMP_CFG, qtime_timestamp_cfg, 0x000004ac);
+
+static const u32 reg_timers_xo_clk_div_cfg_fmask[] = {
+ [DIV_VALUE] = GENMASK(8, 0),
+ /* Bits 9-30 reserved */
+ [DIV_ENABLE] = BIT(31),
+};
+
+REG_FIELDS(TIMERS_XO_CLK_DIV_CFG, timers_xo_clk_div_cfg, 0x000004b0);
+
+static const u32 reg_timers_pulse_gran_cfg_fmask[] = {
+ [PULSE_GRAN_0] = GENMASK(2, 0),
+ [PULSE_GRAN_1] = GENMASK(5, 3),
+ [PULSE_GRAN_2] = GENMASK(8, 6),
+ [PULSE_GRAN_3] = GENMASK(11, 9),
+ /* Bits 12-31 reserved */
+};
+
+REG_FIELDS(TIMERS_PULSE_GRAN_CFG, timers_pulse_gran_cfg, 0x000004b4);
+
+static const u32 reg_src_rsrc_grp_01_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(SRC_RSRC_GRP_01_RSRC_TYPE, src_rsrc_grp_01_rsrc_type,
+ 0x00000500, 0x0020);
+
+static const u32 reg_src_rsrc_grp_23_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(SRC_RSRC_GRP_23_RSRC_TYPE, src_rsrc_grp_23_rsrc_type,
+ 0x00000504, 0x0020);
+
+static const u32 reg_src_rsrc_grp_45_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(SRC_RSRC_GRP_45_RSRC_TYPE, src_rsrc_grp_45_rsrc_type,
+ 0x00000508, 0x0020);
+
+static const u32 reg_src_rsrc_grp_67_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(SRC_RSRC_GRP_67_RSRC_TYPE, src_rsrc_grp_67_rsrc_type,
+ 0x0000050c, 0x0020);
+
+static const u32 reg_dst_rsrc_grp_01_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(DST_RSRC_GRP_01_RSRC_TYPE, dst_rsrc_grp_01_rsrc_type,
+ 0x00000600, 0x0020);
+
+static const u32 reg_dst_rsrc_grp_23_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(DST_RSRC_GRP_23_RSRC_TYPE, dst_rsrc_grp_23_rsrc_type,
+ 0x00000604, 0x0020);
+
+static const u32 reg_dst_rsrc_grp_45_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(DST_RSRC_GRP_45_RSRC_TYPE, dst_rsrc_grp_45_rsrc_type,
+ 0x00000608, 0x0020);
+
+static const u32 reg_dst_rsrc_grp_67_rsrc_type_fmask[] = {
+ [X_MIN_LIM] = GENMASK(5, 0),
+ /* Bits 6-7 reserved */
+ [X_MAX_LIM] = GENMASK(13, 8),
+ /* Bits 14-15 reserved */
+ [Y_MIN_LIM] = GENMASK(21, 16),
+ /* Bits 22-23 reserved */
+ [Y_MAX_LIM] = GENMASK(29, 24),
+ /* Bits 30-31 reserved */
+};
+
+REG_STRIDE_FIELDS(DST_RSRC_GRP_67_RSRC_TYPE, dst_rsrc_grp_67_rsrc_type,
+ 0x0000060c, 0x0020);
+
+/* Valid bits defined by ipa->available */
+
+REG_STRIDE(AGGR_FORCE_CLOSE, aggr_force_close, 0x000006b0, 0x0004);
+
+static const u32 reg_endp_init_cfg_fmask[] = {
+ [FRAG_OFFLOAD_EN] = BIT(0),
+ [CS_OFFLOAD_EN] = GENMASK(2, 1),
+ [CS_METADATA_HDR_OFFSET] = GENMASK(6, 3),
+ /* Bit 7 reserved */
+ [CS_GEN_QMB_MASTER_SEL] = BIT(8),
+ [PIPE_REPLICATE_EN] = BIT(9),
+ /* Bits 10-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_CFG, endp_init_cfg, 0x00001008, 0x0080);
+
+static const u32 reg_endp_init_nat_fmask[] = {
+ [NAT_EN] = GENMASK(1, 0),
+ /* Bits 2-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_NAT, endp_init_nat, 0x0000100c, 0x0080);
+
+static const u32 reg_endp_init_hdr_fmask[] = {
+ [HDR_LEN] = GENMASK(5, 0),
+ [HDR_OFST_METADATA_VALID] = BIT(6),
+ [HDR_OFST_METADATA] = GENMASK(12, 7),
+ [HDR_ADDITIONAL_CONST_LEN] = GENMASK(18, 13),
+ [HDR_OFST_PKT_SIZE_VALID] = BIT(19),
+ [HDR_OFST_PKT_SIZE] = GENMASK(25, 20),
+ /* Bit 26 reserved */
+ [HDR_LEN_INC_DEAGG_HDR] = BIT(27),
+ [HDR_LEN_MSB] = GENMASK(29, 28),
+ [HDR_OFST_METADATA_MSB] = GENMASK(31, 30),
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_HDR, endp_init_hdr, 0x00001010, 0x0080);
+
+static const u32 reg_endp_init_hdr_ext_fmask[] = {
+ [HDR_ENDIANNESS] = BIT(0),
+ [HDR_TOTAL_LEN_OR_PAD_VALID] = BIT(1),
+ [HDR_TOTAL_LEN_OR_PAD] = BIT(2),
+ [HDR_PAYLOAD_LEN_INC_PADDING] = BIT(3),
+ [HDR_TOTAL_LEN_OR_PAD_OFFSET] = GENMASK(9, 4),
+ [HDR_PAD_TO_ALIGNMENT] = GENMASK(13, 10),
+ /* Bits 14-15 reserved */
+ [HDR_TOTAL_LEN_OR_PAD_OFFSET_MSB] = GENMASK(17, 16),
+ [HDR_OFST_PKT_SIZE_MSB] = GENMASK(19, 18),
+ [HDR_ADDITIONAL_CONST_LEN_MSB] = GENMASK(21, 20),
+ [HDR_BYTES_TO_REMOVE_VALID] = BIT(22),
+ /* Bit 23 reserved */
+ [HDR_BYTES_TO_REMOVE] = GENMASK(31, 24),
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_HDR_EXT, endp_init_hdr_ext, 0x00001014, 0x0080);
+
+REG_STRIDE(ENDP_INIT_HDR_METADATA_MASK, endp_init_hdr_metadata_mask,
+ 0x00001018, 0x0080);
+
+static const u32 reg_endp_init_mode_fmask[] = {
+ [ENDP_MODE] = GENMASK(2, 0),
+ [DCPH_ENABLE] = BIT(3),
+ [DEST_PIPE_INDEX] = GENMASK(11, 4),
+ [BYTE_THRESHOLD] = GENMASK(27, 12),
+ /* Bit 28 reserved */
+ [PAD_EN] = BIT(29),
+ [DRBIP_ACL_ENABLE] = BIT(30),
+ /* Bit 31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_MODE, endp_init_mode, 0x00001020, 0x0080);
+
+static const u32 reg_endp_init_aggr_fmask[] = {
+ [AGGR_EN] = GENMASK(1, 0),
+ [AGGR_TYPE] = GENMASK(4, 2),
+ [BYTE_LIMIT] = GENMASK(10, 5),
+ /* Bit 11 reserved */
+ [TIME_LIMIT] = GENMASK(16, 12),
+ [PKT_LIMIT] = GENMASK(22, 17),
+ [SW_EOF_ACTIVE] = BIT(23),
+ [FORCE_CLOSE] = BIT(24),
+ /* Bit 25 reserved */
+ [HARD_BYTE_LIMIT_EN] = BIT(26),
+ [AGGR_GRAN_SEL] = BIT(27),
+ [AGGR_COAL_L2] = BIT(28),
+ /* Bits 27-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_AGGR, endp_init_aggr, 0x00001024, 0x0080);
+
+static const u32 reg_endp_init_hol_block_en_fmask[] = {
+ [HOL_BLOCK_EN] = BIT(0),
+ /* Bits 1-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_HOL_BLOCK_EN, endp_init_hol_block_en,
+ 0x0000102c, 0x0080);
+
+static const u32 reg_endp_init_hol_block_timer_fmask[] = {
+ [TIMER_LIMIT] = GENMASK(4, 0),
+ /* Bits 5-7 reserved */
+ [TIMER_GRAN_SEL] = GENMASK(9, 8),
+ /* Bits 10-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_HOL_BLOCK_TIMER, endp_init_hol_block_timer,
+ 0x00001030, 0x0080);
+
+static const u32 reg_endp_init_deaggr_fmask[] = {
+ [DEAGGR_HDR_LEN] = GENMASK(5, 0),
+ [SYSPIPE_ERR_DETECTION] = BIT(6),
+ [PACKET_OFFSET_VALID] = BIT(7),
+ [PACKET_OFFSET_LOCATION] = GENMASK(13, 8),
+ [IGNORE_MIN_PKT_ERR] = BIT(14),
+ /* Bit 15 reserved */
+ [MAX_PACKET_LEN] = GENMASK(31, 16),
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_DEAGGR, endp_init_deaggr, 0x00001034, 0x0080);
+
+static const u32 reg_endp_init_rsrc_grp_fmask[] = {
+ [ENDP_RSRC_GRP] = GENMASK(2, 0),
+ /* Bits 3-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_RSRC_GRP, endp_init_rsrc_grp, 0x00001038, 0x0080);
+
+static const u32 reg_endp_init_seq_fmask[] = {
+ [SEQ_TYPE] = GENMASK(7, 0),
+ /* Bits 8-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_INIT_SEQ, endp_init_seq, 0x0000103c, 0x0080);
+
+static const u32 reg_endp_status_fmask[] = {
+ [STATUS_EN] = BIT(0),
+ [STATUS_ENDP] = GENMASK(8, 1),
+ [STATUS_PKT_SUPPRESS] = BIT(9),
+ /* Bits 10-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_STATUS, endp_status, 0x00001040, 0x0080);
+
+static const u32 reg_endp_filter_cache_cfg_fmask[] = {
+ [CACHE_MSK_SRC_ID] = BIT(0),
+ [CACHE_MSK_SRC_IP] = BIT(1),
+ [CACHE_MSK_DST_IP] = BIT(2),
+ [CACHE_MSK_SRC_PORT] = BIT(3),
+ [CACHE_MSK_DST_PORT] = BIT(4),
+ [CACHE_MSK_PROTOCOL] = BIT(5),
+ [CACHE_MSK_METADATA] = BIT(6),
+ /* Bits 7-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_FILTER_CACHE_CFG, endp_filter_cache_cfg,
+ 0x0000105c, 0x0080);
+
+static const u32 reg_endp_router_cache_cfg_fmask[] = {
+ [CACHE_MSK_SRC_ID] = BIT(0),
+ [CACHE_MSK_SRC_IP] = BIT(1),
+ [CACHE_MSK_DST_IP] = BIT(2),
+ [CACHE_MSK_SRC_PORT] = BIT(3),
+ [CACHE_MSK_DST_PORT] = BIT(4),
+ [CACHE_MSK_PROTOCOL] = BIT(5),
+ [CACHE_MSK_METADATA] = BIT(6),
+ /* Bits 7-31 reserved */
+};
+
+REG_STRIDE_FIELDS(ENDP_ROUTER_CACHE_CFG, endp_router_cache_cfg,
+ 0x00001060, 0x0080);
+
+/* Valid bits defined by enum ipa_irq_id; only used for GSI_EE_AP */
+REG(IPA_IRQ_STTS, ipa_irq_stts, 0x0000c008 + 0x1000 * GSI_EE_AP);
+
+/* Valid bits defined by enum ipa_irq_id; only used for GSI_EE_AP */
+REG(IPA_IRQ_EN, ipa_irq_en, 0x0000c00c + 0x1000 * GSI_EE_AP);
+
+/* Valid bits defined by enum ipa_irq_id; only used for GSI_EE_AP */
+REG(IPA_IRQ_CLR, ipa_irq_clr, 0x0000c010 + 0x1000 * GSI_EE_AP);
+
+static const u32 reg_ipa_irq_uc_fmask[] = {
+ [UC_INTR] = BIT(0),
+ /* Bits 1-31 reserved */
+};
+
+REG_FIELDS(IPA_IRQ_UC, ipa_irq_uc, 0x0000c01c + 0x1000 * GSI_EE_AP);
+
+/* Valid bits defined by ipa->available */
+
+REG_STRIDE(IRQ_SUSPEND_INFO, irq_suspend_info,
+ 0x0000c030 + 0x1000 * GSI_EE_AP, 0x0004);
+
+/* Valid bits defined by ipa->available */
+
+REG_STRIDE(IRQ_SUSPEND_EN, irq_suspend_en,
+ 0x0000c050 + 0x1000 * GSI_EE_AP, 0x0004);
+
+/* Valid bits defined by ipa->available */
+
+REG_STRIDE(IRQ_SUSPEND_CLR, irq_suspend_clr,
+ 0x0000c070 + 0x1000 * GSI_EE_AP, 0x0004);
+
+static const struct reg *reg_array[] = {
+ [COMP_CFG] = &reg_comp_cfg,
+ [CLKON_CFG] = &reg_clkon_cfg,
+ [ROUTE] = &reg_route,
+ [SHARED_MEM_SIZE] = &reg_shared_mem_size,
+ [QSB_MAX_WRITES] = &reg_qsb_max_writes,
+ [QSB_MAX_READS] = &reg_qsb_max_reads,
+ [FILT_ROUT_CACHE_FLUSH] = &reg_filt_rout_cache_flush,
+ [STATE_AGGR_ACTIVE] = &reg_state_aggr_active,
+ [LOCAL_PKT_PROC_CNTXT] = &reg_local_pkt_proc_cntxt,
+ [AGGR_FORCE_CLOSE] = &reg_aggr_force_close,
+ [IPA_TX_CFG] = &reg_ipa_tx_cfg,
+ [FLAVOR_0] = &reg_flavor_0,
+ [IDLE_INDICATION_CFG] = &reg_idle_indication_cfg,
+ [QTIME_TIMESTAMP_CFG] = &reg_qtime_timestamp_cfg,
+ [TIMERS_XO_CLK_DIV_CFG] = &reg_timers_xo_clk_div_cfg,
+ [TIMERS_PULSE_GRAN_CFG] = &reg_timers_pulse_gran_cfg,
+ [SRC_RSRC_GRP_01_RSRC_TYPE] = &reg_src_rsrc_grp_01_rsrc_type,
+ [SRC_RSRC_GRP_23_RSRC_TYPE] = &reg_src_rsrc_grp_23_rsrc_type,
+ [SRC_RSRC_GRP_45_RSRC_TYPE] = &reg_src_rsrc_grp_45_rsrc_type,
+ [SRC_RSRC_GRP_67_RSRC_TYPE] = &reg_src_rsrc_grp_67_rsrc_type,
+ [DST_RSRC_GRP_01_RSRC_TYPE] = &reg_dst_rsrc_grp_01_rsrc_type,
+ [DST_RSRC_GRP_23_RSRC_TYPE] = &reg_dst_rsrc_grp_23_rsrc_type,
+ [DST_RSRC_GRP_45_RSRC_TYPE] = &reg_dst_rsrc_grp_45_rsrc_type,
+ [DST_RSRC_GRP_67_RSRC_TYPE] = &reg_dst_rsrc_grp_67_rsrc_type,
+ [ENDP_INIT_CFG] = &reg_endp_init_cfg,
+ [ENDP_INIT_NAT] = &reg_endp_init_nat,
+ [ENDP_INIT_HDR] = &reg_endp_init_hdr,
+ [ENDP_INIT_HDR_EXT] = &reg_endp_init_hdr_ext,
+ [ENDP_INIT_HDR_METADATA_MASK] = &reg_endp_init_hdr_metadata_mask,
+ [ENDP_INIT_MODE] = &reg_endp_init_mode,
+ [ENDP_INIT_AGGR] = &reg_endp_init_aggr,
+ [ENDP_INIT_HOL_BLOCK_EN] = &reg_endp_init_hol_block_en,
+ [ENDP_INIT_HOL_BLOCK_TIMER] = &reg_endp_init_hol_block_timer,
+ [ENDP_INIT_DEAGGR] = &reg_endp_init_deaggr,
+ [ENDP_INIT_RSRC_GRP] = &reg_endp_init_rsrc_grp,
+ [ENDP_INIT_SEQ] = &reg_endp_init_seq,
+ [ENDP_STATUS] = &reg_endp_status,
+ [ENDP_FILTER_CACHE_CFG] = &reg_endp_filter_cache_cfg,
+ [ENDP_ROUTER_CACHE_CFG] = &reg_endp_router_cache_cfg,
+ [IPA_IRQ_STTS] = &reg_ipa_irq_stts,
+ [IPA_IRQ_EN] = &reg_ipa_irq_en,
+ [IPA_IRQ_CLR] = &reg_ipa_irq_clr,
+ [IPA_IRQ_UC] = &reg_ipa_irq_uc,
+ [IRQ_SUSPEND_INFO] = &reg_irq_suspend_info,
+ [IRQ_SUSPEND_EN] = &reg_irq_suspend_en,
+ [IRQ_SUSPEND_CLR] = &reg_irq_suspend_clr,
+};
+
+const struct regs ipa_regs_v5_5 = {
+ .reg_count = ARRAY_SIZE(reg_array),
+ .reg = reg_array,
+};
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 57c79f5f2991..df7c43a109e1 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -387,6 +387,7 @@ static const struct header_ops ipvlan_header_ops = {
.parse = eth_header_parse,
.cache = eth_header_cache,
.cache_update = eth_header_cache_update,
+ .parse_protocol = eth_header_parse_protocol,
};
static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
@@ -600,15 +601,15 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,
port->dev_id_start = 0x1;
/* Since L2 address is shared among all IPvlan slaves including
- * master, use unique 16 bit dev-ids to diffentiate among them.
+ * master, use unique 16 bit dev-ids to differentiate among them.
* Assign IDs between 0x1 and 0xFFFE (used by the master) to each
* slave link [see addrconf_ifid_eui48()].
*/
- err = ida_simple_get(&port->ida, port->dev_id_start, 0xFFFE,
- GFP_KERNEL);
+ err = ida_alloc_range(&port->ida, port->dev_id_start, 0xFFFD,
+ GFP_KERNEL);
if (err < 0)
- err = ida_simple_get(&port->ida, 0x1, port->dev_id_start,
- GFP_KERNEL);
+ err = ida_alloc_range(&port->ida, 0x1, port->dev_id_start - 1,
+ GFP_KERNEL);
if (err < 0)
goto unregister_netdev;
dev->dev_id = err;
@@ -640,7 +641,7 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,
unlink_netdev:
netdev_upper_dev_unlink(phy_dev, dev);
remove_ida:
- ida_simple_remove(&port->ida, dev->dev_id);
+ ida_free(&port->ida, dev->dev_id);
unregister_netdev:
unregister_netdevice(dev);
return err;
@@ -660,7 +661,7 @@ void ipvlan_link_delete(struct net_device *dev, struct list_head *head)
}
spin_unlock_bh(&ipvlan->addrs_lock);
- ida_simple_remove(&ipvlan->port->ida, dev->dev_id);
+ ida_free(&ipvlan->port->ida, dev->dev_id);
list_del_rcu(&ipvlan->pnode);
unregister_netdevice_queue(dev, head);
netdev_upper_dev_unlink(ipvlan->phy_dev, dev);
diff --git a/drivers/net/ipvlan/ipvtap.c b/drivers/net/ipvlan/ipvtap.c
index 60944a4beada..1afc4c47be73 100644
--- a/drivers/net/ipvlan/ipvtap.c
+++ b/drivers/net/ipvlan/ipvtap.c
@@ -237,4 +237,5 @@ static void __exit ipvtap_exit(void)
module_exit(ipvtap_exit);
MODULE_ALIAS_RTNL_LINK("ipvtap");
MODULE_AUTHOR("Sainath Grandhi <sainath.grandhi@intel.com>");
+MODULE_DESCRIPTION("IP-VLAN based tap driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 9663050a852d..7f5426285c61 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -93,6 +93,8 @@ struct pcpu_secy_stats {
* @secys: linked list of SecY's on the underlying device
* @gro_cells: pointer to the Generic Receive Offload cell
* @offload: status of offloading on the MACsec device
+ * @insert_tx_tag: when offloading, device requires to insert an
+ * additional tag
*/
struct macsec_dev {
struct macsec_secy secy;
@@ -102,6 +104,7 @@ struct macsec_dev {
struct list_head secys;
struct gro_cells gro_cells;
enum macsec_offload offload;
+ bool insert_tx_tag;
};
/**
@@ -2583,6 +2586,33 @@ static bool macsec_is_configured(struct macsec_dev *macsec)
return false;
}
+static bool macsec_needs_tx_tag(struct macsec_dev *macsec,
+ const struct macsec_ops *ops)
+{
+ return macsec->offload == MACSEC_OFFLOAD_PHY &&
+ ops->mdo_insert_tx_tag;
+}
+
+static void macsec_set_head_tail_room(struct net_device *dev)
+{
+ struct macsec_dev *macsec = macsec_priv(dev);
+ struct net_device *real_dev = macsec->real_dev;
+ int needed_headroom, needed_tailroom;
+ const struct macsec_ops *ops;
+
+ ops = macsec_get_ops(macsec, NULL);
+ if (ops) {
+ needed_headroom = ops->needed_headroom;
+ needed_tailroom = ops->needed_tailroom;
+ } else {
+ needed_headroom = MACSEC_NEEDED_HEADROOM;
+ needed_tailroom = MACSEC_NEEDED_TAILROOM;
+ }
+
+ dev->needed_headroom = real_dev->needed_headroom + needed_headroom;
+ dev->needed_tailroom = real_dev->needed_tailroom + needed_tailroom;
+}
+
static int macsec_update_offload(struct net_device *dev, enum macsec_offload offload)
{
enum macsec_offload prev_offload;
@@ -2620,8 +2650,13 @@ static int macsec_update_offload(struct net_device *dev, enum macsec_offload off
ctx.secy = &macsec->secy;
ret = offload == MACSEC_OFFLOAD_OFF ? macsec_offload(ops->mdo_del_secy, &ctx)
: macsec_offload(ops->mdo_add_secy, &ctx);
- if (ret)
+ if (ret) {
macsec->offload = prev_offload;
+ return ret;
+ }
+
+ macsec_set_head_tail_room(dev);
+ macsec->insert_tx_tag = macsec_needs_tx_tag(macsec, ops);
return ret;
}
@@ -3379,6 +3414,40 @@ static struct genl_family macsec_fam __ro_after_init = {
.resv_start_op = MACSEC_CMD_UPD_OFFLOAD + 1,
};
+static struct sk_buff *macsec_insert_tx_tag(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct macsec_dev *macsec = macsec_priv(dev);
+ const struct macsec_ops *ops;
+ struct phy_device *phydev;
+ struct macsec_context ctx;
+ int skb_final_len;
+ int err;
+
+ ops = macsec_get_ops(macsec, &ctx);
+ skb_final_len = skb->len - ETH_HLEN + ops->needed_headroom +
+ ops->needed_tailroom;
+ if (unlikely(skb_final_len > macsec->real_dev->mtu)) {
+ err = -EINVAL;
+ goto cleanup;
+ }
+
+ phydev = macsec->real_dev->phydev;
+
+ err = skb_ensure_writable_head_tail(skb, dev);
+ if (unlikely(err < 0))
+ goto cleanup;
+
+ err = ops->mdo_insert_tx_tag(phydev, skb);
+ if (unlikely(err))
+ goto cleanup;
+
+ return skb;
+cleanup:
+ kfree_skb(skb);
+ return ERR_PTR(err);
+}
+
static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -3393,6 +3462,15 @@ static netdev_tx_t macsec_start_xmit(struct sk_buff *skb,
skb_dst_drop(skb);
dst_hold(&md_dst->dst);
skb_dst_set(skb, &md_dst->dst);
+
+ if (macsec->insert_tx_tag) {
+ skb = macsec_insert_tx_tag(skb, dev);
+ if (IS_ERR(skb)) {
+ DEV_STATS_INC(dev, tx_dropped);
+ return NETDEV_TX_OK;
+ }
+ }
+
skb->dev = macsec->real_dev;
return dev_queue_xmit(skb);
}
@@ -3454,10 +3532,7 @@ static int macsec_dev_init(struct net_device *dev)
dev->features = real_dev->features & MACSEC_FEATURES;
dev->features |= NETIF_F_LLTX | NETIF_F_GSO_SOFTWARE;
- dev->needed_headroom = real_dev->needed_headroom +
- MACSEC_NEEDED_HEADROOM;
- dev->needed_tailroom = real_dev->needed_tailroom +
- MACSEC_NEEDED_TAILROOM;
+ macsec_set_head_tail_room(dev);
if (is_zero_ether_addr(dev->dev_addr))
eth_hw_addr_inherit(dev, real_dev);
@@ -3604,21 +3679,19 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
struct macsec_dev *macsec = macsec_priv(dev);
struct net_device *real_dev = macsec->real_dev;
struct sockaddr *addr = p;
+ u8 old_addr[ETH_ALEN];
int err;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- if (!(dev->flags & IFF_UP))
- goto out;
-
- err = dev_uc_add(real_dev, addr->sa_data);
- if (err < 0)
- return err;
-
- dev_uc_del(real_dev, dev->dev_addr);
+ if (dev->flags & IFF_UP) {
+ err = dev_uc_add(real_dev, addr->sa_data);
+ if (err < 0)
+ return err;
+ }
-out:
+ ether_addr_copy(old_addr, dev->dev_addr);
eth_hw_addr_set(dev, addr->sa_data);
/* If h/w offloading is available, propagate to the device */
@@ -3627,13 +3700,29 @@ out:
struct macsec_context ctx;
ops = macsec_get_ops(macsec, &ctx);
- if (ops) {
- ctx.secy = &macsec->secy;
- macsec_offload(ops->mdo_upd_secy, &ctx);
+ if (!ops) {
+ err = -EOPNOTSUPP;
+ goto restore_old_addr;
}
+
+ ctx.secy = &macsec->secy;
+ err = macsec_offload(ops->mdo_upd_secy, &ctx);
+ if (err)
+ goto restore_old_addr;
}
+ if (dev->flags & IFF_UP)
+ dev_uc_del(real_dev, old_addr);
+
return 0;
+
+restore_old_addr:
+ if (dev->flags & IFF_UP)
+ dev_uc_del(real_dev, addr->sa_data);
+
+ eth_hw_addr_set(dev, old_addr);
+
+ return err;
}
static int macsec_change_mtu(struct net_device *dev, int new_mtu)
@@ -4126,6 +4215,9 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
err = macsec_offload(ops->mdo_add_secy, &ctx);
if (err)
goto del_dev;
+
+ macsec->insert_tx_tag =
+ macsec_needs_tx_tag(macsec, ops);
}
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index c8da94af4161..a3cc665757e8 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -609,6 +609,7 @@ static const struct header_ops macvlan_hard_header_ops = {
.parse = eth_header_parse,
.cache = eth_header_cache,
.cache_update = eth_header_cache_update,
+ .parse_protocol = eth_header_parse_protocol,
};
static int macvlan_open(struct net_device *dev)
@@ -1086,20 +1087,8 @@ static int macvlan_ethtool_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
struct net_device *real_dev = macvlan_dev_real_dev(dev);
- const struct ethtool_ops *ops = real_dev->ethtool_ops;
- struct phy_device *phydev = real_dev->phydev;
- if (phy_has_tsinfo(phydev)) {
- return phy_ts_info(phydev, info);
- } else if (ops->get_ts_info) {
- return ops->get_ts_info(real_dev, info);
- } else {
- info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE;
- info->phc_index = -1;
- }
-
- return 0;
+ return ethtool_get_ts_info_by_layer(real_dev, info);
}
static netdev_features_t macvlan_fix_features(struct net_device *dev,
diff --git a/drivers/net/mdio/mdio-bcm-unimac.c b/drivers/net/mdio/mdio-bcm-unimac.c
index e8cd8eef319b..68f8ee0ec8ba 100644
--- a/drivers/net/mdio/mdio-bcm-unimac.c
+++ b/drivers/net/mdio/mdio-bcm-unimac.c
@@ -73,24 +73,19 @@ static inline void unimac_mdio_start(struct unimac_mdio_priv *priv)
unimac_mdio_writel(priv, reg, MDIO_CMD);
}
-static inline unsigned int unimac_mdio_busy(struct unimac_mdio_priv *priv)
-{
- return unimac_mdio_readl(priv, MDIO_CMD) & MDIO_START_BUSY;
-}
-
static int unimac_mdio_poll(void *wait_func_data)
{
struct unimac_mdio_priv *priv = wait_func_data;
- unsigned int timeout = 1000;
+ u32 val;
- do {
- if (!unimac_mdio_busy(priv))
- return 0;
-
- usleep_range(1000, 2000);
- } while (--timeout);
+ /*
+ * C22 transactions should take ~25 usec, will need to adjust
+ * if C45 support is added.
+ */
+ udelay(30);
- return -ETIMEDOUT;
+ return read_poll_timeout(unimac_mdio_readl, val, !(val & MDIO_START_BUSY),
+ 2000, 100000, false, priv, MDIO_CMD);
}
static int unimac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
diff --git a/drivers/net/mdio/mdio-gpio.c b/drivers/net/mdio/mdio-gpio.c
index 897b88c50bbb..778db310a28d 100644
--- a/drivers/net/mdio/mdio-gpio.c
+++ b/drivers/net/mdio/mdio-gpio.c
@@ -123,9 +123,9 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
new_bus->parent = dev;
if (bus_id != -1)
- snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id);
+ snprintf(new_bus->id, sizeof(new_bus->id), "gpio-%x", bus_id);
else
- strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE);
+ strscpy(new_bus->id, "gpio", sizeof(new_bus->id));
if (pdata) {
new_bus->phy_mask = pdata->phy_mask;
diff --git a/drivers/net/mdio/mdio-mux-bcm-iproc.c b/drivers/net/mdio/mdio-mux-bcm-iproc.c
index a750bd4c77a0..1ce7d67ba72e 100644
--- a/drivers/net/mdio/mdio-mux-bcm-iproc.c
+++ b/drivers/net/mdio/mdio-mux-bcm-iproc.c
@@ -2,6 +2,7 @@
/*
* Copyright 2016 Broadcom
*/
+#include <linux/align.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -11,6 +12,7 @@
#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/sizes.h>
#define MDIO_RATE_ADJ_EXT_OFFSET 0x000
#define MDIO_RATE_ADJ_INT_OFFSET 0x004
@@ -220,12 +222,12 @@ static int mdio_mux_iproc_probe(struct platform_device *pdev)
md->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(md->base))
return PTR_ERR(md->base);
- if (res->start & 0xfff) {
+ if (!IS_ALIGNED(res->start, SZ_4K)) {
/* For backward compatibility in case the
* base address is specified with an offset.
*/
dev_info(&pdev->dev, "fix base address in dt-blob\n");
- res->start &= ~0xfff;
+ res->start = ALIGN_DOWN(res->start, SZ_4K);
res->end = res->start + MDIO_REG_ADDR_SPACE_SIZE - 1;
}
diff --git a/drivers/net/mdio/mdio-mux.c b/drivers/net/mdio/mdio-mux.c
index bef4cce71287..fe0e46bd7964 100644
--- a/drivers/net/mdio/mdio-mux.c
+++ b/drivers/net/mdio/mdio-mux.c
@@ -190,8 +190,8 @@ int mdio_mux_init(struct device *dev,
r = of_property_read_u32(child_bus_node, "reg", &v);
if (r) {
dev_err(dev,
- "Error: Failed to find reg for child %pOF\n",
- child_bus_node);
+ "Error: Failed to find reg for child %pOF: %pe\n",
+ child_bus_node, ERR_PTR(r));
continue;
}
@@ -214,8 +214,10 @@ int mdio_mux_init(struct device *dev,
snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x.%x",
cb->mii_bus->name, pb->parent_id, v);
cb->mii_bus->parent = dev;
- cb->mii_bus->read = mdio_mux_read;
- cb->mii_bus->write = mdio_mux_write;
+ if (parent_bus->read)
+ cb->mii_bus->read = mdio_mux_read;
+ if (parent_bus->write)
+ cb->mii_bus->write = mdio_mux_write;
if (parent_bus->read_c45)
cb->mii_bus->read_c45 = mdio_mux_read_c45;
if (parent_bus->write_c45)
@@ -229,8 +231,8 @@ int mdio_mux_init(struct device *dev,
}
devm_kfree(dev, cb);
dev_err(dev,
- "Error: Failed to register MDIO bus for child %pOF\n",
- child_bus_node);
+ "Error: Failed to register MDIO bus for child %pOF: %pe\n",
+ child_bus_node, ERR_PTR(r));
} else {
cb->next = pb->children;
pb->children = cb;
diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
index b4d3b9cde8bd..92a7a36b93ac 100644
--- a/drivers/net/netdevsim/dev.c
+++ b/drivers/net/netdevsim/dev.c
@@ -835,14 +835,14 @@ static void nsim_dev_trap_report_work(struct work_struct *work)
trap_report_dw.work);
nsim_dev = nsim_trap_data->nsim_dev;
- /* For each running port and enabled packet trap, generate a UDP
- * packet with a random 5-tuple and report it.
- */
if (!devl_trylock(priv_to_devlink(nsim_dev))) {
- schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 0);
+ schedule_delayed_work(&nsim_dev->trap_data->trap_report_dw, 1);
return;
}
+ /* For each running port and enabled packet trap, generate a UDP
+ * packet with a random 5-tuple and report it.
+ */
list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) {
if (!netif_running(nsim_dev_port->ns->netdev))
continue;
diff --git a/drivers/net/netdevsim/macsec.c b/drivers/net/netdevsim/macsec.c
index 0d5f50430dd3..aa007b1e4b78 100644
--- a/drivers/net/netdevsim/macsec.c
+++ b/drivers/net/netdevsim/macsec.c
@@ -3,11 +3,6 @@
#include <net/macsec.h>
#include "netdevsim.h"
-static inline u64 sci_to_cpu(sci_t sci)
-{
- return be64_to_cpu((__force __be64)sci);
-}
-
static int nsim_macsec_find_secy(struct netdevsim *ns, sci_t sci)
{
int i;
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index aecaf5f44374..77e8250282a5 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -369,6 +369,12 @@ static int nsim_init_netdevsim_vf(struct netdevsim *ns)
return err;
}
+static void nsim_exit_netdevsim(struct netdevsim *ns)
+{
+ nsim_udp_tunnels_info_destroy(ns->netdev);
+ mock_phc_destroy(ns->phc);
+}
+
struct netdevsim *
nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
{
@@ -417,8 +423,7 @@ void nsim_destroy(struct netdevsim *ns)
}
rtnl_unlock();
if (nsim_dev_port_is_pf(ns->nsim_dev_port))
- nsim_udp_tunnels_info_destroy(dev);
- mock_phc_destroy(ns->phc);
+ nsim_exit_netdevsim(ns);
free_netdev(dev);
}
diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c
index 97139c07130f..d93f84fbb1fd 100644
--- a/drivers/net/pcs/pcs-rzn1-miic.c
+++ b/drivers/net/pcs/pcs-rzn1-miic.c
@@ -505,11 +505,9 @@ disable_runtime_pm:
return ret;
}
-static int miic_remove(struct platform_device *pdev)
+static void miic_remove(struct platform_device *pdev)
{
pm_runtime_put(&pdev->dev);
-
- return 0;
}
static const struct of_device_id miic_of_mtable[] = {
@@ -525,7 +523,7 @@ static struct platform_driver miic_driver = {
.of_match_table = miic_of_mtable,
},
.probe = miic_probe,
- .remove = miic_remove,
+ .remove_new = miic_remove,
};
module_platform_driver(miic_driver);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 421d2b62918f..9e2672800f0b 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -60,6 +60,14 @@ config FIXED_PHY
Currently tested with mpc866ads and mpc8349e-mitx.
+config RUST_PHYLIB_ABSTRACTIONS
+ bool "Rust PHYLIB abstractions support"
+ depends on RUST
+ depends on PHYLIB=y
+ help
+ Adds support needed for PHY drivers written in Rust. It provides
+ a wrapper around the C phylib core.
+
config SFP
tristate "SFP cage support"
depends on I2C && PHYLINK
@@ -96,10 +104,7 @@ config ADIN1100_PHY
Currently supports the:
- ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY
-config AQUANTIA_PHY
- tristate "Aquantia PHYs"
- help
- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
+source "drivers/net/phy/aquantia/Kconfig"
config AX88796B_PHY
tristate "Asix PHYs"
@@ -107,6 +112,14 @@ config AX88796B_PHY
Currently supports the Asix Electronics PHY found in the X-Surf 100
AX88796B package.
+config AX88796B_RUST_PHY
+ bool "Rust reference driver for Asix PHYs"
+ depends on RUST_PHYLIB_ABSTRACTIONS && AX88796B_PHY
+ help
+ Uses the Rust reference driver for Asix PHYs (ax88796b_rust.ko).
+ The features are equivalent. It supports the Asix Electronics PHY
+ found in the X-Surf 100 AX88796B package.
+
config BROADCOM_PHY
tristate "Broadcom 54XX PHYs"
select BCM_NET_PHYLIB
@@ -304,9 +317,10 @@ config NXP_CBTX_PHY
config NXP_C45_TJA11XX_PHY
tristate "NXP C45 TJA11XX PHYs"
depends on PTP_1588_CLOCK_OPTIONAL
+ depends on MACSEC || !MACSEC
help
Enable support for NXP C45 TJA11XX PHYs.
- Currently supports the TJA1103 and TJA1120 PHYs.
+ Currently supports the TJA1103, TJA1104 and TJA1120 PHYs.
config NXP_TJA11XX_PHY
tristate "NXP TJA11xx PHYs support"
@@ -397,6 +411,19 @@ config DP83TD510_PHY
Support for the DP83TD510 Ethernet 10Base-T1L PHY. This PHY supports
a 10M single pair Ethernet connection for up to 1000 meter cable.
+config DP83TG720_PHY
+ tristate "Texas Instruments DP83TG720 Ethernet 1000Base-T1 PHY"
+ help
+ The DP83TG720S-Q1 is an automotive Ethernet physical layer
+ transceiver compliant with IEEE 802.3bp and Open Alliance
+ standards. It supports key functions necessary for
+ transmitting and receiving data over both unshielded and
+ shielded single twisted-pair cables. This device offers
+ flexible xMII interface options, including support for both
+ RGMII and SGMII MAC interfaces. It's suitable for applications
+ requiring high-speed data transmission in automotive
+ networking environments.
+
config VITESSE_PHY
tristate "Vitesse PHYs"
help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index c945ed9bd14b..6097afd44392 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -35,13 +35,13 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m)
obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
obj-$(CONFIG_AMD_PHY) += amd.o
-aquantia-objs += aquantia_main.o
-ifdef CONFIG_HWMON
-aquantia-objs += aquantia_hwmon.o
-endif
-obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
+obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
obj-$(CONFIG_AT803X_PHY) += at803x.o
-obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
+ifdef CONFIG_AX88796B_RUST_PHY
+ obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o
+else
+ obj-$(CONFIG_AX88796B_PHY) += ax88796b.o
+endif
obj-$(CONFIG_BCM54140_PHY) += bcm54140.o
obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
@@ -61,6 +61,7 @@ obj-$(CONFIG_DP83867_PHY) += dp83867.o
obj-$(CONFIG_DP83869_PHY) += dp83869.o
obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o
obj-$(CONFIG_DP83TD510_PHY) += dp83td510.o
+obj-$(CONFIG_DP83TG720_PHY) += dp83tg720.o
obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o
@@ -83,7 +84,11 @@ obj-$(CONFIG_MICROSEMI_PHY) += mscc/
obj-$(CONFIG_MOTORCOMM_PHY) += motorcomm.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_NCN26000_PHY) += ncn26000.o
-obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja11xx.o
+nxp-c45-tja-objs += nxp-c45-tja11xx.o
+ifdef CONFIG_MACSEC
+nxp-c45-tja-objs += nxp-c45-tja11xx-macsec.o
+endif
+obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja.o
obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
index 134637584a83..2e1a46e121d9 100644
--- a/drivers/net/phy/adin.c
+++ b/drivers/net/phy/adin.c
@@ -68,6 +68,24 @@
#define ADIN1300_EEE_CAP_REG 0x8000
#define ADIN1300_EEE_ADV_REG 0x8001
#define ADIN1300_EEE_LPABLE_REG 0x8002
+
+#define ADIN1300_FLD_EN_REG 0x8E27
+#define ADIN1300_FLD_PCS_ERR_100_EN BIT(7)
+#define ADIN1300_FLD_PCS_ERR_1000_EN BIT(6)
+#define ADIN1300_FLD_SLCR_OUT_STUCK_100_EN BIT(5)
+#define ADIN1300_FLD_SLCR_OUT_STUCK_1000_EN BIT(4)
+#define ADIN1300_FLD_SLCR_IN_ZDET_100_EN BIT(3)
+#define ADIN1300_FLD_SLCR_IN_ZDET_1000_EN BIT(2)
+#define ADIN1300_FLD_SLCR_IN_INVLD_100_EN BIT(1)
+#define ADIN1300_FLD_SLCR_IN_INVLD_1000_EN BIT(0)
+/* These bits are the ones which are enabled by default. */
+#define ADIN1300_FLD_EN_ON \
+ (ADIN1300_FLD_SLCR_OUT_STUCK_100_EN | \
+ ADIN1300_FLD_SLCR_OUT_STUCK_1000_EN | \
+ ADIN1300_FLD_SLCR_IN_ZDET_100_EN | \
+ ADIN1300_FLD_SLCR_IN_ZDET_1000_EN | \
+ ADIN1300_FLD_SLCR_IN_INVLD_1000_EN)
+
#define ADIN1300_CLOCK_STOP_REG 0x9400
#define ADIN1300_LPI_WAKE_ERR_CNT_REG 0xa000
@@ -416,6 +434,37 @@ static int adin_set_edpd(struct phy_device *phydev, u16 tx_interval)
val);
}
+static int adin_get_fast_down(struct phy_device *phydev, u8 *msecs)
+{
+ int reg;
+
+ reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_FLD_EN_REG);
+ if (reg < 0)
+ return reg;
+
+ if (reg & ADIN1300_FLD_EN_ON)
+ *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON;
+ else
+ *msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
+
+ return 0;
+}
+
+static int adin_set_fast_down(struct phy_device *phydev, const u8 *msecs)
+{
+ if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_ON)
+ return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ ADIN1300_FLD_EN_REG,
+ ADIN1300_FLD_EN_ON);
+
+ if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ ADIN1300_FLD_EN_REG,
+ ADIN1300_FLD_EN_ON);
+
+ return -EINVAL;
+}
+
static int adin_get_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, void *data)
{
@@ -424,6 +473,8 @@ static int adin_get_tunable(struct phy_device *phydev,
return adin_get_downshift(phydev, data);
case ETHTOOL_PHY_EDPD:
return adin_get_edpd(phydev, data);
+ case ETHTOOL_PHY_FAST_LINK_DOWN:
+ return adin_get_fast_down(phydev, data);
default:
return -EOPNOTSUPP;
}
@@ -437,6 +488,8 @@ static int adin_set_tunable(struct phy_device *phydev,
return adin_set_downshift(phydev, *(const u8 *)data);
case ETHTOOL_PHY_EDPD:
return adin_set_edpd(phydev, *(const u16 *)data);
+ case ETHTOOL_PHY_FAST_LINK_DOWN:
+ return adin_set_fast_down(phydev, data);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
deleted file mode 100644
index c684b65c642c..000000000000
--- a/drivers/net/phy/aquantia.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* HWMON driver for Aquantia PHY
- *
- * Author: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
- * Author: Andrew Lunn <andrew@lunn.ch>
- * Author: Heiner Kallweit <hkallweit1@gmail.com>
- */
-
-#include <linux/device.h>
-#include <linux/phy.h>
-
-#if IS_REACHABLE(CONFIG_HWMON)
-int aqr_hwmon_probe(struct phy_device *phydev);
-#else
-static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
-#endif
diff --git a/drivers/net/phy/aquantia/Kconfig b/drivers/net/phy/aquantia/Kconfig
new file mode 100644
index 000000000000..1a65678583cf
--- /dev/null
+++ b/drivers/net/phy/aquantia/Kconfig
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config AQUANTIA_PHY
+ tristate "Aquantia PHYs"
+ select CRC_ITU_T
+ help
+ Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405
diff --git a/drivers/net/phy/aquantia/Makefile b/drivers/net/phy/aquantia/Makefile
new file mode 100644
index 000000000000..aa77fb63c8ec
--- /dev/null
+++ b/drivers/net/phy/aquantia/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+aquantia-objs += aquantia_main.o aquantia_firmware.o
+ifdef CONFIG_HWMON
+aquantia-objs += aquantia_hwmon.o
+endif
+obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
diff --git a/drivers/net/phy/aquantia/aquantia.h b/drivers/net/phy/aquantia/aquantia.h
new file mode 100644
index 000000000000..1c19ae74ad2b
--- /dev/null
+++ b/drivers/net/phy/aquantia/aquantia.h
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* HWMON driver for Aquantia PHY
+ *
+ * Author: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
+ * Author: Andrew Lunn <andrew@lunn.ch>
+ * Author: Heiner Kallweit <hkallweit1@gmail.com>
+ */
+
+#include <linux/device.h>
+#include <linux/phy.h>
+
+/* Vendor specific 1, MDIO_MMD_VEND1 */
+#define VEND1_GLOBAL_SC 0x0
+#define VEND1_GLOBAL_SC_SOFT_RESET BIT(15)
+#define VEND1_GLOBAL_SC_LOW_POWER BIT(11)
+
+#define VEND1_GLOBAL_FW_ID 0x0020
+#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
+#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
+
+#define VEND1_GLOBAL_MAILBOX_INTERFACE1 0x0200
+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE BIT(15)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE BIT(14)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET BIT(12)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE1_BUSY BIT(8)
+
+#define VEND1_GLOBAL_MAILBOX_INTERFACE2 0x0201
+#define VEND1_GLOBAL_MAILBOX_INTERFACE3 0x0202
+#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK GENMASK(15, 0)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR_MASK, (u16)((x) >> 16))
+#define VEND1_GLOBAL_MAILBOX_INTERFACE4 0x0203
+#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK GENMASK(15, 2)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR_MASK, (u16)(x))
+
+#define VEND1_GLOBAL_MAILBOX_INTERFACE5 0x0204
+#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK GENMASK(15, 0)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA_MASK, (u16)((x) >> 16))
+#define VEND1_GLOBAL_MAILBOX_INTERFACE6 0x0205
+#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK GENMASK(15, 0)
+#define VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(x) FIELD_PREP(VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA_MASK, (u16)(x))
+
+/* The following registers all have similar layouts; first the registers... */
+#define VEND1_GLOBAL_CFG_10M 0x0310
+#define VEND1_GLOBAL_CFG_100M 0x031b
+#define VEND1_GLOBAL_CFG_1G 0x031c
+#define VEND1_GLOBAL_CFG_2_5G 0x031d
+#define VEND1_GLOBAL_CFG_5G 0x031e
+#define VEND1_GLOBAL_CFG_10G 0x031f
+/* ...and now the fields */
+#define VEND1_GLOBAL_CFG_SERDES_MODE GENMASK(2, 0)
+#define VEND1_GLOBAL_CFG_SERDES_MODE_XFI 0
+#define VEND1_GLOBAL_CFG_SERDES_MODE_SGMII 3
+#define VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII 4
+#define VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G 6
+#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
+#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
+#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
+#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
+
+/* Vendor specific 1, MDIO_MMD_VEND2 */
+#define VEND1_GLOBAL_CONTROL2 0xc001
+#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST BIT(15)
+#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD BIT(6)
+#define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL BIT(0)
+
+#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
+#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
+#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
+#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
+#define VEND1_THERMAL_STAT1 0xc820
+#define VEND1_THERMAL_STAT2 0xc821
+#define VEND1_THERMAL_STAT2_VALID BIT(0)
+#define VEND1_GENERAL_STAT1 0xc830
+#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14)
+#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13)
+#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12)
+#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11)
+
+#define VEND1_GLOBAL_GEN_STAT2 0xc831
+#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
+
+#define VEND1_GLOBAL_RSVD_STAT1 0xc885
+#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
+#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
+
+#define VEND1_GLOBAL_RSVD_STAT9 0xc88d
+#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
+#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
+
+#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
+#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
+
+#define VEND1_GLOBAL_INT_STD_MASK 0xff00
+#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15)
+#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14)
+#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13)
+#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12)
+#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11)
+#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10)
+#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9)
+#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8)
+#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7)
+#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6)
+#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0)
+
+#define VEND1_GLOBAL_INT_VEND_MASK 0xff01
+#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15)
+#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14)
+#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13)
+#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12)
+#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11)
+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2)
+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
+#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
+
+#if IS_REACHABLE(CONFIG_HWMON)
+int aqr_hwmon_probe(struct phy_device *phydev);
+#else
+static inline int aqr_hwmon_probe(struct phy_device *phydev) { return 0; }
+#endif
+
+int aqr_firmware_load(struct phy_device *phydev);
diff --git a/drivers/net/phy/aquantia/aquantia_firmware.c b/drivers/net/phy/aquantia/aquantia_firmware.c
new file mode 100644
index 000000000000..0c9640ef153b
--- /dev/null
+++ b/drivers/net/phy/aquantia/aquantia_firmware.c
@@ -0,0 +1,374 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bitfield.h>
+#include <linux/of.h>
+#include <linux/firmware.h>
+#include <linux/crc-itu-t.h>
+#include <linux/nvmem-consumer.h>
+
+#include <asm/unaligned.h>
+
+#include "aquantia.h"
+
+#define UP_RESET_SLEEP 100
+
+/* addresses of memory segments in the phy */
+#define DRAM_BASE_ADDR 0x3FFE0000
+#define IRAM_BASE_ADDR 0x40000000
+
+/* firmware image format constants */
+#define VERSION_STRING_SIZE 0x40
+#define VERSION_STRING_OFFSET 0x0200
+/* primary offset is written at an offset from the start of the fw blob */
+#define PRIMARY_OFFSET_OFFSET 0x8
+/* primary offset needs to be then added to a base offset */
+#define PRIMARY_OFFSET_SHIFT 12
+#define PRIMARY_OFFSET(x) ((x) << PRIMARY_OFFSET_SHIFT)
+#define HEADER_OFFSET 0x300
+
+struct aqr_fw_header {
+ u32 padding;
+ u8 iram_offset[3];
+ u8 iram_size[3];
+ u8 dram_offset[3];
+ u8 dram_size[3];
+} __packed;
+
+enum aqr_fw_src {
+ AQR_FW_SRC_NVMEM = 0,
+ AQR_FW_SRC_FS,
+};
+
+static const char * const aqr_fw_src_string[] = {
+ [AQR_FW_SRC_NVMEM] = "NVMEM",
+ [AQR_FW_SRC_FS] = "FS",
+};
+
+/* AQR firmware doesn't have fixed offsets for iram and dram section
+ * but instead provide an header with the offset to use on reading
+ * and parsing the firmware.
+ *
+ * AQR firmware can't be trusted and each offset is validated to be
+ * not negative and be in the size of the firmware itself.
+ */
+static bool aqr_fw_validate_get(size_t size, size_t offset, size_t get_size)
+{
+ return offset + get_size <= size;
+}
+
+static int aqr_fw_get_be16(const u8 *data, size_t offset, size_t size, u16 *value)
+{
+ if (!aqr_fw_validate_get(size, offset, sizeof(u16)))
+ return -EINVAL;
+
+ *value = get_unaligned_be16(data + offset);
+
+ return 0;
+}
+
+static int aqr_fw_get_le16(const u8 *data, size_t offset, size_t size, u16 *value)
+{
+ if (!aqr_fw_validate_get(size, offset, sizeof(u16)))
+ return -EINVAL;
+
+ *value = get_unaligned_le16(data + offset);
+
+ return 0;
+}
+
+static int aqr_fw_get_le24(const u8 *data, size_t offset, size_t size, u32 *value)
+{
+ if (!aqr_fw_validate_get(size, offset, sizeof(u8) * 3))
+ return -EINVAL;
+
+ *value = get_unaligned_le24(data + offset);
+
+ return 0;
+}
+
+/* load data into the phy's memory */
+static int aqr_fw_load_memory(struct phy_device *phydev, u32 addr,
+ const u8 *data, size_t len)
+{
+ u16 crc = 0, up_crc;
+ size_t pos;
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_GLOBAL_MAILBOX_INTERFACE1,
+ VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET);
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_GLOBAL_MAILBOX_INTERFACE3,
+ VEND1_GLOBAL_MAILBOX_INTERFACE3_MSW_ADDR(addr));
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_GLOBAL_MAILBOX_INTERFACE4,
+ VEND1_GLOBAL_MAILBOX_INTERFACE4_LSW_ADDR(addr));
+
+ /* We assume and enforce the size to be word aligned.
+ * If a firmware that is not word aligned is found, please report upstream.
+ */
+ for (pos = 0; pos < len; pos += sizeof(u32)) {
+ u8 crc_data[4];
+ u32 word;
+
+ /* FW data is always stored in little-endian */
+ word = get_unaligned_le32((const u32 *)(data + pos));
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5,
+ VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word));
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE6,
+ VEND1_GLOBAL_MAILBOX_INTERFACE6_LSW_DATA(word));
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE1,
+ VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE |
+ VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE);
+
+ /* Word is swapped internally and MAILBOX CRC is calculated
+ * using big-endian order. Mimic what the PHY does to have a
+ * matching CRC...
+ */
+ crc_data[0] = word >> 24;
+ crc_data[1] = word >> 16;
+ crc_data[2] = word >> 8;
+ crc_data[3] = word;
+
+ /* ...calculate CRC as we load data... */
+ crc = crc_itu_t(crc, crc_data, sizeof(crc_data));
+ }
+ /* ...gets CRC from MAILBOX after we have loaded the entire section... */
+ up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2);
+ /* ...and make sure it does match our calculated CRC */
+ if (crc != up_crc) {
+ phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n",
+ crc, up_crc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aqr_fw_boot(struct phy_device *phydev, const u8 *data, size_t size,
+ enum aqr_fw_src fw_src)
+{
+ u16 calculated_crc, read_crc, read_primary_offset;
+ u32 iram_offset = 0, iram_size = 0;
+ u32 dram_offset = 0, dram_size = 0;
+ char version[VERSION_STRING_SIZE];
+ u32 primary_offset = 0;
+ int ret;
+
+ /* extract saved CRC at the end of the fw
+ * CRC is saved in big-endian as PHY is BE
+ */
+ ret = aqr_fw_get_be16(data, size - sizeof(u16), size, &read_crc);
+ if (ret) {
+ phydev_err(phydev, "bad firmware CRC in firmware\n");
+ return ret;
+ }
+ calculated_crc = crc_itu_t(0, data, size - sizeof(u16));
+ if (read_crc != calculated_crc) {
+ phydev_err(phydev, "bad firmware CRC: file 0x%04x calculated 0x%04x\n",
+ read_crc, calculated_crc);
+ return -EINVAL;
+ }
+
+ /* Get the primary offset to extract DRAM and IRAM sections. */
+ ret = aqr_fw_get_le16(data, PRIMARY_OFFSET_OFFSET, size, &read_primary_offset);
+ if (ret) {
+ phydev_err(phydev, "bad primary offset in firmware\n");
+ return ret;
+ }
+ primary_offset = PRIMARY_OFFSET(read_primary_offset);
+
+ /* Find the DRAM and IRAM sections within the firmware file.
+ * Make sure the fw_header is correctly in the firmware.
+ */
+ if (!aqr_fw_validate_get(size, primary_offset + HEADER_OFFSET,
+ sizeof(struct aqr_fw_header))) {
+ phydev_err(phydev, "bad fw_header in firmware\n");
+ return -EINVAL;
+ }
+
+ /* offset are in LE and values needs to be converted to cpu endian */
+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
+ offsetof(struct aqr_fw_header, iram_offset),
+ size, &iram_offset);
+ if (ret) {
+ phydev_err(phydev, "bad iram offset in firmware\n");
+ return ret;
+ }
+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
+ offsetof(struct aqr_fw_header, iram_size),
+ size, &iram_size);
+ if (ret) {
+ phydev_err(phydev, "invalid iram size in firmware\n");
+ return ret;
+ }
+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
+ offsetof(struct aqr_fw_header, dram_offset),
+ size, &dram_offset);
+ if (ret) {
+ phydev_err(phydev, "bad dram offset in firmware\n");
+ return ret;
+ }
+ ret = aqr_fw_get_le24(data, primary_offset + HEADER_OFFSET +
+ offsetof(struct aqr_fw_header, dram_size),
+ size, &dram_size);
+ if (ret) {
+ phydev_err(phydev, "invalid dram size in firmware\n");
+ return ret;
+ }
+
+ /* Increment the offset with the primary offset.
+ * Validate iram/dram offset and size.
+ */
+ iram_offset += primary_offset;
+ if (iram_size % sizeof(u32)) {
+ phydev_err(phydev, "iram size if not aligned to word size. Please report this upstream!\n");
+ return -EINVAL;
+ }
+ if (!aqr_fw_validate_get(size, iram_offset, iram_size)) {
+ phydev_err(phydev, "invalid iram offset for iram size\n");
+ return -EINVAL;
+ }
+
+ dram_offset += primary_offset;
+ if (dram_size % sizeof(u32)) {
+ phydev_err(phydev, "dram size if not aligned to word size. Please report this upstream!\n");
+ return -EINVAL;
+ }
+ if (!aqr_fw_validate_get(size, dram_offset, dram_size)) {
+ phydev_err(phydev, "invalid iram offset for iram size\n");
+ return -EINVAL;
+ }
+
+ phydev_dbg(phydev, "primary %d IRAM offset=%d size=%d DRAM offset=%d size=%d\n",
+ primary_offset, iram_offset, iram_size, dram_offset, dram_size);
+
+ if (!aqr_fw_validate_get(size, dram_offset + VERSION_STRING_OFFSET,
+ VERSION_STRING_SIZE)) {
+ phydev_err(phydev, "invalid version in firmware\n");
+ return -EINVAL;
+ }
+ strscpy(version, (char *)data + dram_offset + VERSION_STRING_OFFSET,
+ VERSION_STRING_SIZE);
+ if (version[0] == '\0') {
+ phydev_err(phydev, "invalid version in firmware\n");
+ return -EINVAL;
+ }
+ phydev_info(phydev, "loading firmware version '%s' from '%s'\n", version,
+ aqr_fw_src_string[fw_src]);
+
+ /* stall the microcprocessor */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL | VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD);
+
+ phydev_dbg(phydev, "loading DRAM 0x%08x from offset=%d size=%d\n",
+ DRAM_BASE_ADDR, dram_offset, dram_size);
+ ret = aqr_fw_load_memory(phydev, DRAM_BASE_ADDR, data + dram_offset,
+ dram_size);
+ if (ret)
+ return ret;
+
+ phydev_dbg(phydev, "loading IRAM 0x%08x from offset=%d size=%d\n",
+ IRAM_BASE_ADDR, iram_offset, iram_size);
+ ret = aqr_fw_load_memory(phydev, IRAM_BASE_ADDR, data + iram_offset,
+ iram_size);
+ if (ret)
+ return ret;
+
+ /* make sure soft reset and low power mode are clear */
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_SC,
+ VEND1_GLOBAL_SC_SOFT_RESET | VEND1_GLOBAL_SC_LOW_POWER);
+
+ /* Release the microprocessor. UP_RESET must be held for 100 usec. */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL |
+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD |
+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_RST);
+ usleep_range(UP_RESET_SLEEP, UP_RESET_SLEEP * 2);
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_CONTROL2,
+ VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD);
+
+ return 0;
+}
+
+static int aqr_firmware_load_nvmem(struct phy_device *phydev)
+{
+ struct nvmem_cell *cell;
+ size_t size;
+ u8 *buf;
+ int ret;
+
+ cell = nvmem_cell_get(&phydev->mdio.dev, "firmware");
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = nvmem_cell_read(cell, &size);
+ if (IS_ERR(buf)) {
+ ret = PTR_ERR(buf);
+ goto exit;
+ }
+
+ ret = aqr_fw_boot(phydev, buf, size, AQR_FW_SRC_NVMEM);
+ if (ret)
+ phydev_err(phydev, "firmware loading failed: %d\n", ret);
+
+ kfree(buf);
+exit:
+ nvmem_cell_put(cell);
+
+ return ret;
+}
+
+static int aqr_firmware_load_fs(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ const struct firmware *fw;
+ const char *fw_name;
+ int ret;
+
+ ret = of_property_read_string(dev->of_node, "firmware-name",
+ &fw_name);
+ if (ret)
+ return ret;
+
+ ret = request_firmware(&fw, fw_name, dev);
+ if (ret) {
+ phydev_err(phydev, "failed to find FW file %s (%d)\n",
+ fw_name, ret);
+ return ret;
+ }
+
+ ret = aqr_fw_boot(phydev, fw->data, fw->size, AQR_FW_SRC_FS);
+ if (ret)
+ phydev_err(phydev, "firmware loading failed: %d\n", ret);
+
+ release_firmware(fw);
+
+ return ret;
+}
+
+int aqr_firmware_load(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Check if the firmware is not already loaded by pooling
+ * the current version returned by the PHY. If 0 is returned,
+ * no firmware is loaded.
+ */
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_FW_ID);
+ if (ret > 0)
+ goto exit;
+
+ ret = aqr_firmware_load_nvmem(phydev);
+ if (!ret)
+ goto exit;
+
+ ret = aqr_firmware_load_fs(phydev);
+ if (ret)
+ return ret;
+
+exit:
+ return 0;
+}
diff --git a/drivers/net/phy/aquantia_hwmon.c b/drivers/net/phy/aquantia/aquantia_hwmon.c
index 0da451e46f69..7b3c49c3bf49 100644
--- a/drivers/net/phy/aquantia_hwmon.c
+++ b/drivers/net/phy/aquantia/aquantia_hwmon.c
@@ -13,20 +13,6 @@
#include "aquantia.h"
-/* Vendor specific 1, MDIO_MMD_VEND2 */
-#define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
-#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
-#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
-#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
-#define VEND1_THERMAL_STAT1 0xc820
-#define VEND1_THERMAL_STAT2 0xc821
-#define VEND1_THERMAL_STAT2_VALID BIT(0)
-#define VEND1_GENERAL_STAT1 0xc830
-#define VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL BIT(14)
-#define VEND1_GENERAL_STAT1_LOW_TEMP_FAIL BIT(13)
-#define VEND1_GENERAL_STAT1_HIGH_TEMP_WARN BIT(12)
-#define VEND1_GENERAL_STAT1_LOW_TEMP_WARN BIT(11)
-
#if IS_REACHABLE(CONFIG_HWMON)
static umode_t aqr_hwmon_is_visible(const void *data,
diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c
index 334a6904ca5a..97a2fafa15ca 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
@@ -91,61 +91,6 @@
#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
-/* Vendor specific 1, MDIO_MMD_VEND1 */
-#define VEND1_GLOBAL_FW_ID 0x0020
-#define VEND1_GLOBAL_FW_ID_MAJOR GENMASK(15, 8)
-#define VEND1_GLOBAL_FW_ID_MINOR GENMASK(7, 0)
-
-#define VEND1_GLOBAL_GEN_STAT2 0xc831
-#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
-
-/* The following registers all have similar layouts; first the registers... */
-#define VEND1_GLOBAL_CFG_10M 0x0310
-#define VEND1_GLOBAL_CFG_100M 0x031b
-#define VEND1_GLOBAL_CFG_1G 0x031c
-#define VEND1_GLOBAL_CFG_2_5G 0x031d
-#define VEND1_GLOBAL_CFG_5G 0x031e
-#define VEND1_GLOBAL_CFG_10G 0x031f
-/* ...and now the fields */
-#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
-#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
-#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
-#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
-
-#define VEND1_GLOBAL_RSVD_STAT1 0xc885
-#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
-#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
-
-#define VEND1_GLOBAL_RSVD_STAT9 0xc88d
-#define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
-#define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
-
-#define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
-#define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
-
-#define VEND1_GLOBAL_INT_STD_MASK 0xff00
-#define VEND1_GLOBAL_INT_STD_MASK_PMA1 BIT(15)
-#define VEND1_GLOBAL_INT_STD_MASK_PMA2 BIT(14)
-#define VEND1_GLOBAL_INT_STD_MASK_PCS1 BIT(13)
-#define VEND1_GLOBAL_INT_STD_MASK_PCS2 BIT(12)
-#define VEND1_GLOBAL_INT_STD_MASK_PCS3 BIT(11)
-#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS1 BIT(10)
-#define VEND1_GLOBAL_INT_STD_MASK_PHY_XS2 BIT(9)
-#define VEND1_GLOBAL_INT_STD_MASK_AN1 BIT(8)
-#define VEND1_GLOBAL_INT_STD_MASK_AN2 BIT(7)
-#define VEND1_GLOBAL_INT_STD_MASK_GBE BIT(6)
-#define VEND1_GLOBAL_INT_STD_MASK_ALL BIT(0)
-
-#define VEND1_GLOBAL_INT_VEND_MASK 0xff01
-#define VEND1_GLOBAL_INT_VEND_MASK_PMA BIT(15)
-#define VEND1_GLOBAL_INT_VEND_MASK_PCS BIT(14)
-#define VEND1_GLOBAL_INT_VEND_MASK_PHY_XS BIT(13)
-#define VEND1_GLOBAL_INT_VEND_MASK_AN BIT(12)
-#define VEND1_GLOBAL_INT_VEND_MASK_GBE BIT(11)
-#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL1 BIT(2)
-#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
-#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
-
/* Sleep and timeout for checking if the Processor-Intensive
* MDIO operation is finished
*/
@@ -711,13 +656,93 @@ static int aqr107_resume(struct phy_device *phydev)
return aqr107_wait_processor_intensive_op(phydev);
}
+static const u16 aqr_global_cfg_regs[] = {
+ VEND1_GLOBAL_CFG_10M,
+ VEND1_GLOBAL_CFG_100M,
+ VEND1_GLOBAL_CFG_1G,
+ VEND1_GLOBAL_CFG_2_5G,
+ VEND1_GLOBAL_CFG_5G,
+ VEND1_GLOBAL_CFG_10G
+};
+
+static int aqr107_fill_interface_modes(struct phy_device *phydev)
+{
+ unsigned long *possible = phydev->possible_interfaces;
+ unsigned int serdes_mode, rate_adapt;
+ phy_interface_t interface;
+ int i, val;
+
+ /* Walk the media-speed configuration registers to determine which
+ * host-side serdes modes may be used by the PHY depending on the
+ * negotiated media speed.
+ */
+ for (i = 0; i < ARRAY_SIZE(aqr_global_cfg_regs); i++) {
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ aqr_global_cfg_regs[i]);
+ if (val < 0)
+ return val;
+
+ serdes_mode = FIELD_GET(VEND1_GLOBAL_CFG_SERDES_MODE, val);
+ rate_adapt = FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val);
+
+ switch (serdes_mode) {
+ case VEND1_GLOBAL_CFG_SERDES_MODE_XFI:
+ if (rate_adapt == VEND1_GLOBAL_CFG_RATE_ADAPT_USX)
+ interface = PHY_INTERFACE_MODE_USXGMII;
+ else
+ interface = PHY_INTERFACE_MODE_10GBASER;
+ break;
+
+ case VEND1_GLOBAL_CFG_SERDES_MODE_XFI5G:
+ interface = PHY_INTERFACE_MODE_5GBASER;
+ break;
+
+ case VEND1_GLOBAL_CFG_SERDES_MODE_OCSGMII:
+ interface = PHY_INTERFACE_MODE_2500BASEX;
+ break;
+
+ case VEND1_GLOBAL_CFG_SERDES_MODE_SGMII:
+ interface = PHY_INTERFACE_MODE_SGMII;
+ break;
+
+ default:
+ phydev_warn(phydev, "unrecognised serdes mode %u\n",
+ serdes_mode);
+ interface = PHY_INTERFACE_MODE_NA;
+ break;
+ }
+
+ if (interface != PHY_INTERFACE_MODE_NA)
+ __set_bit(interface, possible);
+ }
+
+ return 0;
+}
+
+static int aqr113c_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = aqr107_config_init(phydev);
+ if (ret < 0)
+ return ret;
+
+ return aqr107_fill_interface_modes(phydev);
+}
+
static int aqr107_probe(struct phy_device *phydev)
{
+ int ret;
+
phydev->priv = devm_kzalloc(&phydev->mdio.dev,
sizeof(struct aqr107_priv), GFP_KERNEL);
if (!phydev->priv)
return -ENOMEM;
+ ret = aqr_firmware_load(phydev);
+ if (ret)
+ return ret;
+
return aqr_hwmon_probe(phydev);
}
@@ -843,7 +868,7 @@ static struct phy_driver aqr_driver[] = {
.name = "Aquantia AQR113C",
.probe = aqr107_probe,
.get_rate_matching = aqr107_get_rate_matching,
- .config_init = aqr107_config_init,
+ .config_init = aqr113c_config_init,
.config_aneg = aqr_config_aneg,
.config_intr = aqr_config_intr,
.handle_interrupt = aqr_handle_interrupt,
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 37fb033e1c29..a62442a55774 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -254,6 +254,7 @@
#define QCA808X_CDT_ENABLE_TEST BIT(15)
#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
+#define QCA808X_CDT_STATUS BIT(11)
#define QCA808X_CDT_LENGTH_UNIT BIT(10)
#define QCA808X_MMD3_CDT_STATUS 0x8064
@@ -261,16 +262,44 @@
#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
-#define QCA808X_CDT_DIAG_LENGTH GENMASK(7, 0)
+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
-#define QCA808X_CDT_STATUS_STAT_FAIL 0
-#define QCA808X_CDT_STATUS_STAT_NORMAL 1
-#define QCA808X_CDT_STATUS_STAT_OPEN 2
-#define QCA808X_CDT_STATUS_STAT_SHORT 3
+
+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
+
+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
+
+/* NORMAL are MDI with type set to 0 */
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI1)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI1)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI2)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI2)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI3)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI3)
+
+/* Added for reference of existence but should be handled by wait_for_completion already */
+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
/* QCA808X 1G chip type */
#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d
@@ -295,12 +324,17 @@ struct at803x_hw_stat {
enum stat_access_type access_type;
};
-static struct at803x_hw_stat at803x_hw_stats[] = {
+static struct at803x_hw_stat qca83xx_hw_stats[] = {
{ "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
{ "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
{ "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
};
+struct at803x_ss_mask {
+ u16 speed_mask;
+ u8 speed_shift;
+};
+
struct at803x_priv {
int flags;
u16 clk_25m_reg;
@@ -311,7 +345,7 @@ struct at803x_priv {
bool is_1000basex;
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
- u64 stats[ARRAY_SIZE(at803x_hw_stats)];
+ u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
};
struct at803x_context {
@@ -457,7 +491,7 @@ static int at803x_set_wol(struct phy_device *phydev,
if (!ndev)
return -ENODEV;
- mac = (const u8 *) ndev->dev_addr;
+ mac = (const u8 *)ndev->dev_addr;
if (!is_valid_ether_addr(mac))
return -EINVAL;
@@ -466,27 +500,11 @@ static int at803x_set_wol(struct phy_device *phydev,
phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i],
mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
- /* Enable WOL function for 1588 */
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
- AT803X_PHY_MMD3_WOL_CTRL,
- 0, AT803X_WOL_EN);
- if (ret)
- return ret;
- }
/* Enable WOL interrupt */
ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL);
if (ret)
return ret;
} else {
- /* Disable WoL function for 1588 */
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
- AT803X_PHY_MMD3_WOL_CTRL,
- AT803X_WOL_EN, 0);
- if (ret)
- return ret;
- }
/* Disable WOL interrupt */
ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0);
if (ret)
@@ -529,24 +547,24 @@ static void at803x_get_wol(struct phy_device *phydev,
wol->wolopts |= WAKE_MAGIC;
}
-static int at803x_get_sset_count(struct phy_device *phydev)
+static int qca83xx_get_sset_count(struct phy_device *phydev)
{
- return ARRAY_SIZE(at803x_hw_stats);
+ return ARRAY_SIZE(qca83xx_hw_stats);
}
-static void at803x_get_strings(struct phy_device *phydev, u8 *data)
+static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++) {
+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
strscpy(data + i * ETH_GSTRING_LEN,
- at803x_hw_stats[i].string, ETH_GSTRING_LEN);
+ qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
}
}
-static u64 at803x_get_stat(struct phy_device *phydev, int i)
+static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
{
- struct at803x_hw_stat stat = at803x_hw_stats[i];
+ struct at803x_hw_stat stat = qca83xx_hw_stats[i];
struct at803x_priv *priv = phydev->priv;
int val;
u64 ret;
@@ -567,13 +585,13 @@ static u64 at803x_get_stat(struct phy_device *phydev, int i)
return ret;
}
-static void at803x_get_stats(struct phy_device *phydev,
- struct ethtool_stats *stats, u64 *data)
+static void qca83xx_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data)
{
int i;
- for (i = 0; i < ARRAY_SIZE(at803x_hw_stats); i++)
- data[i] = at803x_get_stat(phydev, i);
+ for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
+ data[i] = qca83xx_get_stat(phydev, i);
}
static int at803x_suspend(struct phy_device *phydev)
@@ -599,139 +617,6 @@ static int at803x_resume(struct phy_device *phydev)
return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
}
-static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int selector)
-{
- struct phy_device *phydev = rdev_get_drvdata(rdev);
-
- if (selector)
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
- 0, AT803X_DEBUG_RGMII_1V8);
- else
- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
- AT803X_DEBUG_RGMII_1V8, 0);
-}
-
-static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
-{
- struct phy_device *phydev = rdev_get_drvdata(rdev);
- int val;
-
- val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
- if (val < 0)
- return val;
-
- return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
-}
-
-static const struct regulator_ops vddio_regulator_ops = {
- .list_voltage = regulator_list_voltage_table,
- .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel,
- .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel,
-};
-
-static const unsigned int vddio_voltage_table[] = {
- 1500000,
- 1800000,
-};
-
-static const struct regulator_desc vddio_desc = {
- .name = "vddio",
- .of_match = of_match_ptr("vddio-regulator"),
- .n_voltages = ARRAY_SIZE(vddio_voltage_table),
- .volt_table = vddio_voltage_table,
- .ops = &vddio_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
-};
-
-static const struct regulator_ops vddh_regulator_ops = {
-};
-
-static const struct regulator_desc vddh_desc = {
- .name = "vddh",
- .of_match = of_match_ptr("vddh-regulator"),
- .n_voltages = 1,
- .fixed_uV = 2500000,
- .ops = &vddh_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
-};
-
-static int at8031_register_regulators(struct phy_device *phydev)
-{
- struct at803x_priv *priv = phydev->priv;
- struct device *dev = &phydev->mdio.dev;
- struct regulator_config config = { };
-
- config.dev = dev;
- config.driver_data = phydev;
-
- priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
- if (IS_ERR(priv->vddio_rdev)) {
- phydev_err(phydev, "failed to register VDDIO regulator\n");
- return PTR_ERR(priv->vddio_rdev);
- }
-
- priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
- if (IS_ERR(priv->vddh_rdev)) {
- phydev_err(phydev, "failed to register VDDH regulator\n");
- return PTR_ERR(priv->vddh_rdev);
- }
-
- return 0;
-}
-
-static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
-{
- struct phy_device *phydev = upstream;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
- __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
- DECLARE_PHY_INTERFACE_MASK(interfaces);
- phy_interface_t iface;
-
- linkmode_zero(phy_support);
- phylink_set(phy_support, 1000baseX_Full);
- phylink_set(phy_support, 1000baseT_Full);
- phylink_set(phy_support, Autoneg);
- phylink_set(phy_support, Pause);
- phylink_set(phy_support, Asym_Pause);
-
- linkmode_zero(sfp_support);
- sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
- /* Some modules support 10G modes as well as others we support.
- * Mask out non-supported modes so the correct interface is picked.
- */
- linkmode_and(sfp_support, phy_support, sfp_support);
-
- if (linkmode_empty(sfp_support)) {
- dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
- return -EINVAL;
- }
-
- iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
-
- /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
- * interface for use with SFP modules.
- * However, some copper modules detected as having a preferred SGMII
- * interface do default to and function in 1000Base-X mode, so just
- * print a warning and allow such modules, as they may have some chance
- * of working.
- */
- if (iface == PHY_INTERFACE_MODE_SGMII)
- dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
- else if (iface != PHY_INTERFACE_MODE_1000BASEX)
- return -EINVAL;
-
- return 0;
-}
-
-static const struct sfp_upstream_ops at803x_sfp_ops = {
- .attach = phy_sfp_attach,
- .detach = phy_sfp_detach,
- .module_insert = at803x_sfp_insert,
-};
-
static int at803x_parse_dt(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
@@ -787,23 +672,6 @@ static int at803x_parse_dt(struct phy_device *phydev)
priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel);
priv->clk_25m_mask |= AT803X_CLK_OUT_MASK;
-
- /* Fixup for the AR8030/AR8035. This chip has another mask and
- * doesn't support the DSP reference. Eg. the lowest bit of the
- * mask. The upper two bits select the same frequencies. Mask
- * the lowest bit here.
- *
- * Warning:
- * There was no datasheet for the AR8030 available so this is
- * just a guess. But the AR8035 is listed as pin compatible
- * to the AR8030 so there might be a good chance it works on
- * the AR8030 too.
- */
- if (phydev->drv->phy_id == ATH8030_PHY_ID ||
- phydev->drv->phy_id == ATH8035_PHY_ID) {
- priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
- priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
- }
}
ret = of_property_read_u32(node, "qca,clk-out-strength", &strength);
@@ -825,30 +693,6 @@ static int at803x_parse_dt(struct phy_device *phydev)
}
}
- /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
- * options.
- */
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- if (of_property_read_bool(node, "qca,keep-pll-enabled"))
- priv->flags |= AT803X_KEEP_PLL_ENABLED;
-
- ret = at8031_register_regulators(phydev);
- if (ret < 0)
- return ret;
-
- ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
- "vddio");
- if (ret) {
- phydev_err(phydev, "failed to get VDDIO regulator\n");
- return ret;
- }
-
- /* Only AR8031/8033 support 1000Base-X for SFP modules */
- ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
@@ -868,35 +712,6 @@ static int at803x_probe(struct phy_device *phydev)
if (ret)
return ret;
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
- int mode_cfg;
-
- if (ccr < 0)
- return ccr;
- mode_cfg = ccr & AT803X_MODE_CFG_MASK;
-
- switch (mode_cfg) {
- case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
- case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
- priv->is_1000basex = true;
- fallthrough;
- case AT803X_MODE_CFG_FX100_RGMII_50OHM:
- case AT803X_MODE_CFG_FX100_RGMII_75OHM:
- priv->is_fiber = true;
- break;
- }
-
- /* Disable WoL in 1588 register which is enabled
- * by default
- */
- ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
- AT803X_PHY_MMD3_WOL_CTRL,
- AT803X_WOL_EN, 0);
- if (ret)
- return ret;
- }
-
return 0;
}
@@ -1004,27 +819,8 @@ static int at803x_hibernation_mode_config(struct phy_device *phydev)
static int at803x_config_init(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
int ret;
- if (phydev->drv->phy_id == ATH8031_PHY_ID) {
- /* Some bootloaders leave the fiber page selected.
- * Switch to the appropriate page (fiber or copper), as otherwise we
- * read the PHY capabilities from the wrong page.
- */
- phy_lock_mdio_bus(phydev);
- ret = at803x_write_page(phydev,
- priv->is_fiber ? AT803X_PAGE_FIBER :
- AT803X_PAGE_COPPER);
- phy_unlock_mdio_bus(phydev);
- if (ret)
- return ret;
-
- ret = at8031_pll_config(phydev);
- if (ret < 0)
- return ret;
- }
-
/* The RX and TX delay default is:
* after HW reset: RX delay enabled and TX delay disabled
* after SW reset: RX delay enabled, while TX delay retains the
@@ -1078,7 +874,6 @@ static int at803x_ack_interrupt(struct phy_device *phydev)
static int at803x_config_intr(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
int err;
int value;
@@ -1095,10 +890,6 @@ static int at803x_config_intr(struct phy_device *phydev)
value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
value |= AT803X_INTR_ENABLE_LINK_FAIL;
value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
- if (priv->is_fiber) {
- value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
- value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
- }
err = phy_write(phydev, AT803X_INTR_ENABLE, value);
} else {
@@ -1154,9 +945,9 @@ static void at803x_link_change_notify(struct phy_device *phydev)
at803x_context_save(phydev, &context);
phy_device_reset(phydev, 1);
- msleep(1);
+ usleep_range(1000, 2000);
phy_device_reset(phydev, 0);
- msleep(1);
+ usleep_range(1000, 2000);
at803x_context_restore(phydev, &context);
@@ -1164,7 +955,8 @@ static void at803x_link_change_notify(struct phy_device *phydev)
}
}
-static int at803x_read_specific_status(struct phy_device *phydev)
+static int at803x_read_specific_status(struct phy_device *phydev,
+ struct at803x_ss_mask ss_mask)
{
int ss;
@@ -1183,11 +975,8 @@ static int at803x_read_specific_status(struct phy_device *phydev)
if (sfc < 0)
return sfc;
- /* qca8081 takes the different bits for speed value from at803x */
- if (phydev->drv->phy_id == QCA8081_PHY_ID)
- speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
- else
- speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);
+ speed = ss & ss_mask.speed_mask;
+ speed >>= ss_mask.speed_shift;
switch (speed) {
case AT803X_SS_SPEED_10:
@@ -1231,12 +1020,9 @@ static int at803x_read_specific_status(struct phy_device *phydev)
static int at803x_read_status(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
+ struct at803x_ss_mask ss_mask = { 0 };
int err, old_link = phydev->link;
- if (priv->is_1000basex)
- return genphy_c37_read_status(phydev);
-
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
if (err)
@@ -1255,7 +1041,9 @@ static int at803x_read_status(struct phy_device *phydev)
if (err < 0)
return err;
- err = at803x_read_specific_status(phydev);
+ ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
+ ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
+ err = at803x_read_specific_status(phydev, ss_mask);
if (err < 0)
return err;
@@ -1288,9 +1076,8 @@ static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
}
-static int at803x_config_aneg(struct phy_device *phydev)
+static int at803x_prepare_config_aneg(struct phy_device *phydev)
{
- struct at803x_priv *priv = phydev->priv;
int ret;
ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
@@ -1307,33 +1094,22 @@ static int at803x_config_aneg(struct phy_device *phydev)
return ret;
}
- if (priv->is_1000basex)
- return genphy_c37_config_aneg(phydev);
-
- /* Do not restart auto-negotiation by setting ret to 0 defautly,
- * when calling __genphy_config_aneg later.
- */
- ret = 0;
-
- if (phydev->drv->phy_id == QCA8081_PHY_ID) {
- int phy_ctrl = 0;
+ return 0;
+}
- /* The reg MII_BMCR also needs to be configured for force mode, the
- * genphy_config_aneg is also needed.
- */
- if (phydev->autoneg == AUTONEG_DISABLE)
- genphy_c45_pma_setup_forced(phydev);
+static int at803x_config_aneg(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int ret;
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
- phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
+ ret = at803x_prepare_config_aneg(phydev);
+ if (ret)
+ return ret;
- ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
- MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
- if (ret < 0)
- return ret;
- }
+ if (priv->is_1000basex)
+ return genphy_c37_config_aneg(phydev);
- return __genphy_config_aneg(phydev, ret);
+ return genphy_config_aneg(phydev);
}
static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
@@ -1441,10 +1217,8 @@ static bool at803x_cdt_fault_length_valid(u16 status)
return false;
}
-static int at803x_cdt_fault_length(u16 status)
+static int at803x_cdt_fault_length(int dt)
{
- int dt;
-
/* According to the datasheet the distance to the fault is
* DELTA_TIME * 0.824 meters.
*
@@ -1460,36 +1234,19 @@ static int at803x_cdt_fault_length(u16 status)
* With a VF of 0.69 we get the factor 0.824 mentioned in the
* datasheet.
*/
- dt = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, status);
-
return (dt * 824) / 10;
}
-static int at803x_cdt_start(struct phy_device *phydev, int pair)
+static int at803x_cdt_start(struct phy_device *phydev,
+ u32 cdt_start)
{
- u16 cdt;
-
- /* qca8081 takes the different bit 15 to enable CDT test */
- if (phydev->drv->phy_id == QCA8081_PHY_ID)
- cdt = QCA808X_CDT_ENABLE_TEST |
- QCA808X_CDT_LENGTH_UNIT |
- QCA808X_CDT_INTER_CHECK_DIS;
- else
- cdt = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
- AT803X_CDT_ENABLE_TEST;
-
- return phy_write(phydev, AT803X_CDT, cdt);
+ return phy_write(phydev, AT803X_CDT, cdt_start);
}
-static int at803x_cdt_wait_for_completion(struct phy_device *phydev)
+static int at803x_cdt_wait_for_completion(struct phy_device *phydev,
+ u32 cdt_en)
{
int val, ret;
- u16 cdt_en;
-
- if (phydev->drv->phy_id == QCA8081_PHY_ID)
- cdt_en = QCA808X_CDT_ENABLE_TEST;
- else
- cdt_en = AT803X_CDT_ENABLE_TEST;
/* One test run takes about 25ms */
ret = phy_read_poll_timeout(phydev, AT803X_CDT, val,
@@ -1509,11 +1266,13 @@ static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
};
int ret, val;
- ret = at803x_cdt_start(phydev, pair);
+ val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) |
+ AT803X_CDT_ENABLE_TEST;
+ ret = at803x_cdt_start(phydev, val);
if (ret)
return ret;
- ret = at803x_cdt_wait_for_completion(phydev);
+ ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST);
if (ret)
return ret;
@@ -1527,27 +1286,21 @@ static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair)
ethnl_cable_test_result(phydev, ethtool_pair[pair],
at803x_cable_test_result_trans(val));
- if (at803x_cdt_fault_length_valid(val))
+ if (at803x_cdt_fault_length_valid(val)) {
+ val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val);
ethnl_cable_test_fault_length(phydev, ethtool_pair[pair],
at803x_cdt_fault_length(val));
+ }
return 1;
}
static int at803x_cable_test_get_status(struct phy_device *phydev,
- bool *finished)
+ bool *finished, unsigned long pair_mask)
{
- unsigned long pair_mask;
int retries = 20;
int pair, ret;
- if (phydev->phy_id == ATH9331_PHY_ID ||
- phydev->phy_id == ATH8032_PHY_ID ||
- phydev->phy_id == QCA9561_PHY_ID)
- pair_mask = 0x3;
- else
- pair_mask = 0xf;
-
*finished = false;
/* According to the datasheet the CDT can be performed when
@@ -1574,7 +1327,7 @@ static int at803x_cable_test_get_status(struct phy_device *phydev,
return 0;
}
-static int at803x_cable_test_start(struct phy_device *phydev)
+static void at803x_cable_test_autoneg(struct phy_device *phydev)
{
/* Enable auto-negotiation, but advertise no capabilities, no link
* will be established. A restart of the auto-negotiation is not
@@ -1582,15 +1335,358 @@ static int at803x_cable_test_start(struct phy_device *phydev)
*/
phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA);
- if (phydev->phy_id != ATH9331_PHY_ID &&
- phydev->phy_id != ATH8032_PHY_ID &&
- phydev->phy_id != QCA9561_PHY_ID)
- phy_write(phydev, MII_CTRL1000, 0);
+}
+
+static int at803x_cable_test_start(struct phy_device *phydev)
+{
+ at803x_cable_test_autoneg(phydev);
+ /* we do all the (time consuming) work later */
+ return 0;
+}
+
+static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct phy_device *phydev = rdev_get_drvdata(rdev);
+
+ if (selector)
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
+ 0, AT803X_DEBUG_RGMII_1V8);
+ else
+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F,
+ AT803X_DEBUG_RGMII_1V8, 0);
+}
+
+static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct phy_device *phydev = rdev_get_drvdata(rdev);
+ int val;
+
+ val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F);
+ if (val < 0)
+ return val;
+
+ return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0;
+}
+
+static const struct regulator_ops vddio_regulator_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel,
+ .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel,
+};
+
+static const unsigned int vddio_voltage_table[] = {
+ 1500000,
+ 1800000,
+};
+
+static const struct regulator_desc vddio_desc = {
+ .name = "vddio",
+ .of_match = of_match_ptr("vddio-regulator"),
+ .n_voltages = ARRAY_SIZE(vddio_voltage_table),
+ .volt_table = vddio_voltage_table,
+ .ops = &vddio_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static const struct regulator_ops vddh_regulator_ops = {
+};
+
+static const struct regulator_desc vddh_desc = {
+ .name = "vddh",
+ .of_match = of_match_ptr("vddh-regulator"),
+ .n_voltages = 1,
+ .fixed_uV = 2500000,
+ .ops = &vddh_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static int at8031_register_regulators(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+ struct regulator_config config = { };
+
+ config.dev = dev;
+ config.driver_data = phydev;
+
+ priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config);
+ if (IS_ERR(priv->vddio_rdev)) {
+ phydev_err(phydev, "failed to register VDDIO regulator\n");
+ return PTR_ERR(priv->vddio_rdev);
+ }
+
+ priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config);
+ if (IS_ERR(priv->vddh_rdev)) {
+ phydev_err(phydev, "failed to register VDDH regulator\n");
+ return PTR_ERR(priv->vddh_rdev);
+ }
+
+ return 0;
+}
+
+static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+ struct phy_device *phydev = upstream;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support);
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
+ phy_interface_t iface;
+
+ linkmode_zero(phy_support);
+ phylink_set(phy_support, 1000baseX_Full);
+ phylink_set(phy_support, 1000baseT_Full);
+ phylink_set(phy_support, Autoneg);
+ phylink_set(phy_support, Pause);
+ phylink_set(phy_support, Asym_Pause);
+
+ linkmode_zero(sfp_support);
+ sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces);
+ /* Some modules support 10G modes as well as others we support.
+ * Mask out non-supported modes so the correct interface is picked.
+ */
+ linkmode_and(sfp_support, phy_support, sfp_support);
+
+ if (linkmode_empty(sfp_support)) {
+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
+ return -EINVAL;
+ }
+
+ iface = sfp_select_interface(phydev->sfp_bus, sfp_support);
+
+ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes
+ * interface for use with SFP modules.
+ * However, some copper modules detected as having a preferred SGMII
+ * interface do default to and function in 1000Base-X mode, so just
+ * print a warning and allow such modules, as they may have some chance
+ * of working.
+ */
+ if (iface == PHY_INTERFACE_MODE_SGMII)
+ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n");
+ else if (iface != PHY_INTERFACE_MODE_1000BASEX)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct sfp_upstream_ops at8031_sfp_ops = {
+ .attach = phy_sfp_attach,
+ .detach = phy_sfp_detach,
+ .module_insert = at8031_sfp_insert,
+};
+
+static int at8031_parse_dt(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct at803x_priv *priv = phydev->priv;
+ int ret;
+
+ if (of_property_read_bool(node, "qca,keep-pll-enabled"))
+ priv->flags |= AT803X_KEEP_PLL_ENABLED;
+
+ ret = at8031_register_regulators(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_regulator_get_enable_optional(&phydev->mdio.dev,
+ "vddio");
+ if (ret) {
+ phydev_err(phydev, "failed to get VDDIO regulator\n");
+ return ret;
+ }
+
+ /* Only AR8031/8033 support 1000Base-X for SFP modules */
+ return phy_sfp_probe(phydev, &at8031_sfp_ops);
+}
+
+static int at8031_probe(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int mode_cfg;
+ int ccr;
+ int ret;
+
+ ret = at803x_probe(phydev);
+ if (ret)
+ return ret;
+
+ /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping
+ * options.
+ */
+ ret = at8031_parse_dt(phydev);
+ if (ret)
+ return ret;
+
+ ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
+ if (ccr < 0)
+ return ccr;
+ mode_cfg = ccr & AT803X_MODE_CFG_MASK;
+
+ switch (mode_cfg) {
+ case AT803X_MODE_CFG_BX1000_RGMII_50OHM:
+ case AT803X_MODE_CFG_BX1000_RGMII_75OHM:
+ priv->is_1000basex = true;
+ fallthrough;
+ case AT803X_MODE_CFG_FX100_RGMII_50OHM:
+ case AT803X_MODE_CFG_FX100_RGMII_75OHM:
+ priv->is_fiber = true;
+ break;
+ }
+
+ /* Disable WoL in 1588 register which is enabled
+ * by default
+ */
+ return phy_modify_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_PHY_MMD3_WOL_CTRL,
+ AT803X_WOL_EN, 0);
+}
+
+static int at8031_config_init(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int ret;
+
+ /* Some bootloaders leave the fiber page selected.
+ * Switch to the appropriate page (fiber or copper), as otherwise we
+ * read the PHY capabilities from the wrong page.
+ */
+ phy_lock_mdio_bus(phydev);
+ ret = at803x_write_page(phydev,
+ priv->is_fiber ? AT803X_PAGE_FIBER :
+ AT803X_PAGE_COPPER);
+ phy_unlock_mdio_bus(phydev);
+ if (ret)
+ return ret;
+
+ ret = at8031_pll_config(phydev);
+ if (ret < 0)
+ return ret;
+
+ return at803x_config_init(phydev);
+}
+
+static int at8031_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ int ret;
+
+ /* First setup MAC address and enable WOL interrupt */
+ ret = at803x_set_wol(phydev, wol);
+ if (ret)
+ return ret;
+
+ if (wol->wolopts & WAKE_MAGIC)
+ /* Enable WOL function for 1588 */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_PHY_MMD3_WOL_CTRL,
+ 0, AT803X_WOL_EN);
+ else
+ /* Disable WoL function for 1588 */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_PHY_MMD3_WOL_CTRL,
+ AT803X_WOL_EN, 0);
+
+ return ret;
+}
+
+static int at8031_config_intr(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+ int err, value = 0;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED &&
+ priv->is_fiber) {
+ /* Clear any pending interrupts */
+ err = at803x_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX;
+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX;
+
+ err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value);
+ if (err)
+ return err;
+ }
+
+ return at803x_config_intr(phydev);
+}
+
+/* AR8031 and AR8033 share the same read status logic */
+static int at8031_read_status(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+
+ if (priv->is_1000basex)
+ return genphy_c37_read_status(phydev);
+ return at803x_read_status(phydev);
+}
+
+/* AR8031 and AR8035 share the same cable test get status reg */
+static int at8031_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ return at803x_cable_test_get_status(phydev, finished, 0xf);
+}
+
+/* AR8031 and AR8035 share the same cable test start logic */
+static int at8031_cable_test_start(struct phy_device *phydev)
+{
+ at803x_cable_test_autoneg(phydev);
+ phy_write(phydev, MII_CTRL1000, 0);
/* we do all the (time consuming) work later */
return 0;
}
+/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */
+static int at8032_cable_test_get_status(struct phy_device *phydev,
+ bool *finished)
+{
+ return at803x_cable_test_get_status(phydev, finished, 0x3);
+}
+
+static int at8035_parse_dt(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+
+ /* Mask is set by the generic at803x_parse_dt
+ * if property is set. Assume property is set
+ * with the mask not zero.
+ */
+ if (priv->clk_25m_mask) {
+ /* Fixup for the AR8030/AR8035. This chip has another mask and
+ * doesn't support the DSP reference. Eg. the lowest bit of the
+ * mask. The upper two bits select the same frequencies. Mask
+ * the lowest bit here.
+ *
+ * Warning:
+ * There was no datasheet for the AR8030 available so this is
+ * just a guess. But the AR8035 is listed as pin compatible
+ * to the AR8030 so there might be a good chance it works on
+ * the AR8030 too.
+ */
+ priv->clk_25m_reg &= AT8035_CLK_OUT_MASK;
+ priv->clk_25m_mask &= AT8035_CLK_OUT_MASK;
+ }
+
+ return 0;
+}
+
+/* AR8030 and AR8035 shared the same special mask for clk_25m */
+static int at8035_probe(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = at803x_probe(phydev);
+ if (ret)
+ return ret;
+
+ return at8035_parse_dt(phydev);
+}
+
static int qca83xx_config_init(struct phy_device *phydev)
{
u8 switch_revision;
@@ -1616,27 +1712,26 @@ static int qca83xx_config_init(struct phy_device *phydev)
break;
}
+ /* Following original QCA sourcecode set port to prefer master */
+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
+
+ return 0;
+}
+
+static int qca8327_config_init(struct phy_device *phydev)
+{
/* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
* Disable on init and enable only with 100m speed following
* qca original source code.
*/
- if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
- phydev->drv->phy_id == QCA8327_B_PHY_ID)
- at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- QCA8327_DEBUG_MANU_CTRL_EN, 0);
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
+ QCA8327_DEBUG_MANU_CTRL_EN, 0);
- /* Following original QCA sourcecode set port to prefer master */
- phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
-
- return 0;
+ return qca83xx_config_init(phydev);
}
static void qca83xx_link_change_notify(struct phy_device *phydev)
{
- /* QCA8337 doesn't require DAC Amplitude adjustement */
- if (phydev->drv->phy_id == QCA8337_PHY_ID)
- return;
-
/* Set DAC Amplitude adjustment to +6% for 100m on link running */
if (phydev->state == PHY_RUNNING) {
if (phydev->speed == SPEED_100)
@@ -1672,26 +1767,13 @@ static int qca83xx_resume(struct phy_device *phydev)
if (ret)
return ret;
- msleep(1);
+ usleep_range(1000, 2000);
return 0;
}
static int qca83xx_suspend(struct phy_device *phydev)
{
- u16 mask = 0;
-
- /* Only QCA8337 support actual suspend.
- * QCA8327 cause port unreliability when phy suspend
- * is set.
- */
- if (phydev->drv->phy_id == QCA8337_PHY_ID) {
- genphy_suspend(phydev);
- } else {
- mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
- phy_modify(phydev, MII_BMCR, mask, 0);
- }
-
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
AT803X_DEBUG_GATE_CLK_IN1000, 0);
@@ -1702,6 +1784,27 @@ static int qca83xx_suspend(struct phy_device *phydev)
return 0;
}
+static int qca8337_suspend(struct phy_device *phydev)
+{
+ /* Only QCA8337 support actual suspend. */
+ genphy_suspend(phydev);
+
+ return qca83xx_suspend(phydev);
+}
+
+static int qca8327_suspend(struct phy_device *phydev)
+{
+ u16 mask = 0;
+
+ /* QCA8327 cause port unreliability when phy suspend
+ * is set.
+ */
+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
+ phy_modify(phydev, MII_BMCR, mask, 0);
+
+ return qca83xx_suspend(phydev);
+}
+
static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
{
int ret;
@@ -1712,27 +1815,27 @@ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
return ret;
phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1,
- QCA808X_TOP_OPTION1_DATA);
+ QCA808X_TOP_OPTION1_DATA);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB,
- QCA808X_MSE_THRESHOLD_20DB_VALUE);
+ QCA808X_MSE_THRESHOLD_20DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB,
- QCA808X_MSE_THRESHOLD_17DB_VALUE);
+ QCA808X_MSE_THRESHOLD_17DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB,
- QCA808X_MSE_THRESHOLD_27DB_VALUE);
+ QCA808X_MSE_THRESHOLD_27DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB,
- QCA808X_MSE_THRESHOLD_28DB_VALUE);
+ QCA808X_MSE_THRESHOLD_28DB_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1,
- QCA808X_MMD3_DEBUG_1_VALUE);
+ QCA808X_MMD3_DEBUG_1_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4,
- QCA808X_MMD3_DEBUG_4_VALUE);
+ QCA808X_MMD3_DEBUG_4_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5,
- QCA808X_MMD3_DEBUG_5_VALUE);
+ QCA808X_MMD3_DEBUG_5_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3,
- QCA808X_MMD3_DEBUG_3_VALUE);
+ QCA808X_MMD3_DEBUG_3_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6,
- QCA808X_MMD3_DEBUG_6_VALUE);
+ QCA808X_MMD3_DEBUG_6_VALUE);
phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2,
- QCA808X_MMD3_DEBUG_2_VALUE);
+ QCA808X_MMD3_DEBUG_2_VALUE);
return 0;
}
@@ -1769,13 +1872,14 @@ static int qca808x_config_init(struct phy_device *phydev)
/* Active adc&vga on 802.3az for the link 1000M and 100M */
ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7,
- QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
+ QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN);
if (ret)
return ret;
/* Adjust the threshold on 802.3az for the link 1000M */
ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
- QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, QCA808X_MMD3_AZ_TRAINING_VAL);
+ QCA808X_PHY_MMD3_AZ_TRAINING_CTRL,
+ QCA808X_MMD3_AZ_TRAINING_VAL);
if (ret)
return ret;
@@ -1801,11 +1905,13 @@ static int qca808x_config_init(struct phy_device *phydev)
/* Configure adc threshold as 100mv for the link 10M */
return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD,
- QCA808X_ADC_THRESHOLD_MASK, QCA808X_ADC_THRESHOLD_100MV);
+ QCA808X_ADC_THRESHOLD_MASK,
+ QCA808X_ADC_THRESHOLD_100MV);
}
static int qca808x_read_status(struct phy_device *phydev)
{
+ struct at803x_ss_mask ss_mask = { 0 };
int ret;
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
@@ -1813,13 +1919,16 @@ static int qca808x_read_status(struct phy_device *phydev)
return ret;
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
- ret & MDIO_AN_10GBT_STAT_LP2_5G);
+ ret & MDIO_AN_10GBT_STAT_LP2_5G);
ret = genphy_read_status(phydev);
if (ret)
return ret;
- ret = at803x_read_specific_status(phydev);
+ /* qca8081 takes the different bits for speed value from at803x */
+ ss_mask.speed_mask = QCA808X_SS_SPEED_MASK;
+ ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK);
+ ret = at803x_read_specific_status(phydev, ss_mask);
if (ret < 0)
return ret;
@@ -1840,7 +1949,7 @@ static int qca808x_read_status(struct phy_device *phydev)
*/
if (qca808x_has_fast_retrain_or_slave_seed(phydev)) {
if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR ||
- qca808x_is_prefer_master(phydev)) {
+ qca808x_is_prefer_master(phydev)) {
qca808x_phy_ms_seed_enable(phydev, false);
} else {
qca808x_phy_ms_seed_enable(phydev, true);
@@ -1868,8 +1977,17 @@ static int qca808x_soft_reset(struct phy_device *phydev)
static bool qca808x_cdt_fault_length_valid(int cdt_code)
{
switch (cdt_code) {
- case QCA808X_CDT_STATUS_STAT_SHORT:
- case QCA808X_CDT_STATUS_STAT_OPEN:
+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
return true;
default:
return false;
@@ -1881,17 +1999,28 @@ static int qca808x_cable_test_result_trans(int cdt_code)
switch (cdt_code) {
case QCA808X_CDT_STATUS_STAT_NORMAL:
return ETHTOOL_A_CABLE_RESULT_CODE_OK;
- case QCA808X_CDT_STATUS_STAT_SHORT:
+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
- case QCA808X_CDT_STATUS_STAT_OPEN:
+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
case QCA808X_CDT_STATUS_STAT_FAIL:
default:
return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
}
}
-static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair)
+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
+ int result)
{
int val;
u32 cdt_length_reg = 0;
@@ -1917,7 +2046,12 @@ static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair)
if (val < 0)
return val;
- return (FIELD_GET(QCA808X_CDT_DIAG_LENGTH, val) * 824) / 10;
+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
+ else
+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
+
+ return at803x_cdt_fault_length(val);
}
static int qca808x_cable_test_start(struct phy_device *phydev)
@@ -1961,18 +2095,53 @@ static int qca808x_cable_test_start(struct phy_device *phydev)
return 0;
}
+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
+ u16 status)
+{
+ int length, result;
+ u16 pair_code;
+
+ switch (pair) {
+ case ETHTOOL_A_CABLE_PAIR_A:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_B:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_C:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_D:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ result = qca808x_cable_test_result_trans(pair_code);
+ ethnl_cable_test_result(phydev, pair, result);
+
+ if (qca808x_cdt_fault_length_valid(pair_code)) {
+ length = qca808x_cdt_fault_length(phydev, pair, result);
+ ethnl_cable_test_fault_length(phydev, pair, length);
+ }
+
+ return 0;
+}
+
static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
{
int ret, val;
- int pair_a, pair_b, pair_c, pair_d;
*finished = false;
- ret = at803x_cdt_start(phydev, 0);
+ val = QCA808X_CDT_ENABLE_TEST |
+ QCA808X_CDT_LENGTH_UNIT;
+ ret = at803x_cdt_start(phydev, val);
if (ret)
return ret;
- ret = at803x_cdt_wait_for_completion(phydev);
+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
if (ret)
return ret;
@@ -1980,32 +2149,21 @@ static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finish
if (val < 0)
return val;
- pair_a = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, val);
- pair_b = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, val);
- pair_c = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, val);
- pair_d = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, val);
-
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
- qca808x_cable_test_result_trans(pair_a));
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
- qca808x_cable_test_result_trans(pair_b));
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
- qca808x_cable_test_result_trans(pair_c));
- ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
- qca808x_cable_test_result_trans(pair_d));
-
- if (qca808x_cdt_fault_length_valid(pair_a))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_A));
- if (qca808x_cdt_fault_length_valid(pair_b))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_B));
- if (qca808x_cdt_fault_length_valid(pair_c))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_C));
- if (qca808x_cdt_fault_length_valid(pair_d))
- ethnl_cable_test_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D,
- qca808x_cdt_fault_length(phydev, ETHTOOL_A_CABLE_PAIR_D));
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
+ if (ret)
+ return ret;
*finished = true;
@@ -2040,14 +2198,41 @@ static int qca808x_get_features(struct phy_device *phydev)
return 0;
}
+static int qca808x_config_aneg(struct phy_device *phydev)
+{
+ int phy_ctrl = 0;
+ int ret;
+
+ ret = at803x_prepare_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ /* The reg MII_BMCR also needs to be configured for force mode, the
+ * genphy_config_aneg is also needed.
+ */
+ if (phydev->autoneg == AUTONEG_DISABLE)
+ genphy_c45_pma_setup_forced(phydev);
+
+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising))
+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
+
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+ MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl);
+ if (ret < 0)
+ return ret;
+
+ return __genphy_config_aneg(phydev, ret);
+}
+
static void qca808x_link_change_notify(struct phy_device *phydev)
{
/* Assert interface sgmii fifo on link down, deassert it on link up,
* the interface device address is always phy address added by 1.
*/
mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1,
- MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
- QCA8081_PHY_FIFO_RSTN, phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
+ MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL,
+ QCA8081_PHY_FIFO_RSTN,
+ phydev->link ? QCA8081_PHY_FIFO_RSTN : 0);
}
static struct phy_driver at803x_driver[] = {
@@ -2056,7 +2241,7 @@ static struct phy_driver at803x_driver[] = {
PHY_ID_MATCH_EXACT(ATH8035_PHY_ID),
.name = "Qualcomm Atheros AR8035",
.flags = PHY_POLL_CABLE_TEST,
- .probe = at803x_probe,
+ .probe = at8035_probe,
.config_aneg = at803x_config_aneg,
.config_init = at803x_config_init,
.soft_reset = genphy_soft_reset,
@@ -2070,14 +2255,14 @@ static struct phy_driver at803x_driver[] = {
.handle_interrupt = at803x_handle_interrupt,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
- .cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_start = at8031_cable_test_start,
+ .cable_test_get_status = at8031_cable_test_get_status,
}, {
/* Qualcomm Atheros AR8030 */
.phy_id = ATH8030_PHY_ID,
.name = "Qualcomm Atheros AR8030",
.phy_id_mask = AT8030_PHY_ID_MASK,
- .probe = at803x_probe,
+ .probe = at8035_probe,
.config_init = at803x_config_init,
.link_change_notify = at803x_link_change_notify,
.set_wol = at803x_set_wol,
@@ -2092,24 +2277,24 @@ static struct phy_driver at803x_driver[] = {
PHY_ID_MATCH_EXACT(ATH8031_PHY_ID),
.name = "Qualcomm Atheros AR8031/AR8033",
.flags = PHY_POLL_CABLE_TEST,
- .probe = at803x_probe,
- .config_init = at803x_config_init,
+ .probe = at8031_probe,
+ .config_init = at8031_config_init,
.config_aneg = at803x_config_aneg,
.soft_reset = genphy_soft_reset,
- .set_wol = at803x_set_wol,
+ .set_wol = at8031_set_wol,
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
.resume = at803x_resume,
.read_page = at803x_read_page,
.write_page = at803x_write_page,
.get_features = at803x_get_features,
- .read_status = at803x_read_status,
- .config_intr = &at803x_config_intr,
+ .read_status = at8031_read_status,
+ .config_intr = at8031_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
- .cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_start = at8031_cable_test_start,
+ .cable_test_get_status = at8031_cable_test_get_status,
}, {
/* Qualcomm Atheros AR8032 */
PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
@@ -2124,7 +2309,7 @@ static struct phy_driver at803x_driver[] = {
.config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_get_status = at8032_cable_test_get_status,
}, {
/* ATHEROS AR9331 */
PHY_ID_MATCH_EXACT(ATH9331_PHY_ID),
@@ -2134,10 +2319,10 @@ static struct phy_driver at803x_driver[] = {
.resume = at803x_resume,
.flags = PHY_POLL_CABLE_TEST,
/* PHY_BASIC_FEATURES */
- .config_intr = &at803x_config_intr,
+ .config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_get_status = at8032_cable_test_get_status,
.read_status = at803x_read_status,
.soft_reset = genphy_soft_reset,
.config_aneg = at803x_config_aneg,
@@ -2150,10 +2335,10 @@ static struct phy_driver at803x_driver[] = {
.resume = at803x_resume,
.flags = PHY_POLL_CABLE_TEST,
/* PHY_BASIC_FEATURES */
- .config_intr = &at803x_config_intr,
+ .config_intr = at803x_config_intr,
.handle_interrupt = at803x_handle_interrupt,
.cable_test_start = at803x_cable_test_start,
- .cable_test_get_status = at803x_cable_test_get_status,
+ .cable_test_get_status = at8032_cable_test_get_status,
.read_status = at803x_read_status,
.soft_reset = genphy_soft_reset,
.config_aneg = at803x_config_aneg,
@@ -2163,15 +2348,14 @@ static struct phy_driver at803x_driver[] = {
.phy_id_mask = QCA8K_PHY_ID_MASK,
.name = "Qualcomm Atheros 8337 internal PHY",
/* PHY_GBIT_FEATURES */
- .link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
.soft_reset = genphy_soft_reset,
- .get_sset_count = at803x_get_sset_count,
- .get_strings = at803x_get_strings,
- .get_stats = at803x_get_stats,
- .suspend = qca83xx_suspend,
+ .get_sset_count = qca83xx_get_sset_count,
+ .get_strings = qca83xx_get_strings,
+ .get_stats = qca83xx_get_stats,
+ .suspend = qca8337_suspend,
.resume = qca83xx_resume,
}, {
/* QCA8327-A from switch QCA8327-AL1A */
@@ -2182,12 +2366,12 @@ static struct phy_driver at803x_driver[] = {
.link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
+ .config_init = qca8327_config_init,
.soft_reset = genphy_soft_reset,
- .get_sset_count = at803x_get_sset_count,
- .get_strings = at803x_get_strings,
- .get_stats = at803x_get_stats,
- .suspend = qca83xx_suspend,
+ .get_sset_count = qca83xx_get_sset_count,
+ .get_strings = qca83xx_get_strings,
+ .get_stats = qca83xx_get_stats,
+ .suspend = qca8327_suspend,
.resume = qca83xx_resume,
}, {
/* QCA8327-B from switch QCA8327-BL1A */
@@ -2198,12 +2382,12 @@ static struct phy_driver at803x_driver[] = {
.link_change_notify = qca83xx_link_change_notify,
.probe = at803x_probe,
.flags = PHY_IS_INTERNAL,
- .config_init = qca83xx_config_init,
+ .config_init = qca8327_config_init,
.soft_reset = genphy_soft_reset,
- .get_sset_count = at803x_get_sset_count,
- .get_strings = at803x_get_strings,
- .get_stats = at803x_get_stats,
- .suspend = qca83xx_suspend,
+ .get_sset_count = qca83xx_get_sset_count,
+ .get_strings = qca83xx_get_strings,
+ .get_stats = qca83xx_get_stats,
+ .suspend = qca8327_suspend,
.resume = qca83xx_resume,
}, {
/* Qualcomm QCA8081 */
@@ -2218,7 +2402,7 @@ static struct phy_driver at803x_driver[] = {
.set_wol = at803x_set_wol,
.get_wol = at803x_get_wol,
.get_features = qca808x_get_features,
- .config_aneg = at803x_config_aneg,
+ .config_aneg = qca808x_config_aneg,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_status = qca808x_read_status,
diff --git a/drivers/net/phy/ax88796b_rust.rs b/drivers/net/phy/ax88796b_rust.rs
new file mode 100644
index 000000000000..5c92572962dc
--- /dev/null
+++ b/drivers/net/phy/ax88796b_rust.rs
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com>
+
+//! Rust Asix PHYs driver
+//!
+//! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c)
+use kernel::{
+ c_str,
+ net::phy::{self, DeviceId, Driver},
+ prelude::*,
+ uapi,
+};
+
+kernel::module_phy_driver! {
+ drivers: [PhyAX88772A, PhyAX88772C, PhyAX88796B],
+ device_table: [
+ DeviceId::new_with_driver::<PhyAX88772A>(),
+ DeviceId::new_with_driver::<PhyAX88772C>(),
+ DeviceId::new_with_driver::<PhyAX88796B>()
+ ],
+ name: "rust_asix_phy",
+ author: "FUJITA Tomonori <fujita.tomonori@gmail.com>",
+ description: "Rust Asix PHYs driver",
+ license: "GPL",
+}
+
+const MII_BMCR: u16 = uapi::MII_BMCR as u16;
+const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16;
+const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16;
+
+// Performs a software PHY reset using the standard
+// BMCR_RESET bit and poll for the reset bit to be cleared.
+// Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation
+// such as used on the Individual Computers' X-Surf 100 Zorro card.
+fn asix_soft_reset(dev: &mut phy::Device) -> Result {
+ dev.write(uapi::MII_BMCR as u16, 0)?;
+ dev.genphy_soft_reset()
+}
+
+struct PhyAX88772A;
+
+#[vtable]
+impl Driver for PhyAX88772A {
+ const FLAGS: u32 = phy::flags::IS_INTERNAL;
+ const NAME: &'static CStr = c_str!("Asix Electronics AX88772A");
+ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861);
+
+ // AX88772A is not working properly with some old switches (NETGEAR EN 108TP):
+ // after autoneg is done and the link status is reported as active, the MII_LPA
+ // register is 0. This issue is not reproducible on AX88772C.
+ fn read_status(dev: &mut phy::Device) -> Result<u16> {
+ dev.genphy_update_link()?;
+ if !dev.is_link_up() {
+ return Ok(0);
+ }
+ // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve
+ // linkmode so use MII_BMCR as default values.
+ let ret = dev.read(MII_BMCR)?;
+
+ if ret & BMCR_SPEED100 != 0 {
+ dev.set_speed(uapi::SPEED_100);
+ } else {
+ dev.set_speed(uapi::SPEED_10);
+ }
+
+ let duplex = if ret & BMCR_FULLDPLX != 0 {
+ phy::DuplexMode::Full
+ } else {
+ phy::DuplexMode::Half
+ };
+ dev.set_duplex(duplex);
+
+ dev.genphy_read_lpa()?;
+
+ if dev.is_autoneg_enabled() && dev.is_autoneg_completed() {
+ dev.resolve_aneg_linkmode();
+ }
+
+ Ok(0)
+ }
+
+ fn suspend(dev: &mut phy::Device) -> Result {
+ dev.genphy_suspend()
+ }
+
+ fn resume(dev: &mut phy::Device) -> Result {
+ dev.genphy_resume()
+ }
+
+ fn soft_reset(dev: &mut phy::Device) -> Result {
+ asix_soft_reset(dev)
+ }
+
+ fn link_change_notify(dev: &mut phy::Device) {
+ // Reset PHY, otherwise MII_LPA will provide outdated information.
+ // This issue is reproducible only with some link partner PHYs.
+ if dev.state() == phy::DeviceState::NoLink {
+ let _ = dev.init_hw();
+ let _ = dev.start_aneg();
+ }
+ }
+}
+
+struct PhyAX88772C;
+
+#[vtable]
+impl Driver for PhyAX88772C {
+ const FLAGS: u32 = phy::flags::IS_INTERNAL;
+ const NAME: &'static CStr = c_str!("Asix Electronics AX88772C");
+ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881);
+
+ fn suspend(dev: &mut phy::Device) -> Result {
+ dev.genphy_suspend()
+ }
+
+ fn resume(dev: &mut phy::Device) -> Result {
+ dev.genphy_resume()
+ }
+
+ fn soft_reset(dev: &mut phy::Device) -> Result {
+ asix_soft_reset(dev)
+ }
+}
+
+struct PhyAX88796B;
+
+#[vtable]
+impl Driver for PhyAX88796B {
+ const NAME: &'static CStr = c_str!("Asix Electronics AX88796B");
+ const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841);
+
+ fn soft_reset(dev: &mut phy::Device) -> Result {
+ asix_soft_reset(dev)
+ }
+}
diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c
index cb4b91af5e17..617d384d4551 100644
--- a/drivers/net/phy/bcm-phy-ptp.c
+++ b/drivers/net/phy/bcm-phy-ptp.c
@@ -782,16 +782,13 @@ out:
}
static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts,
- struct ifreq *ifr)
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
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) {
+ switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
priv->hwts_rx = false;
break;
@@ -804,14 +801,14 @@ static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts,
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;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
priv->hwts_rx = true;
break;
default:
return -ERANGE;
}
- priv->tx_type = cfg.tx_type;
+ 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;
@@ -840,7 +837,7 @@ static int bcm_ptp_hwtstamp(struct mii_timestamper *mii_ts,
/* purge existing data */
skb_queue_purge(&priv->tx_queue);
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ return 0;
}
static int bcm_ptp_ts_info(struct mii_timestamper *mii_ts,
diff --git a/drivers/net/phy/bcm54140.c b/drivers/net/phy/bcm54140.c
index d43076592f81..2eea3d09b1e6 100644
--- a/drivers/net/phy/bcm54140.c
+++ b/drivers/net/phy/bcm54140.c
@@ -128,6 +128,10 @@
#define BCM54140_DEFAULT_DOWNSHIFT 5
#define BCM54140_MAX_DOWNSHIFT 9
+enum bcm54140_global_phy {
+ BCM54140_BASE_ADDR = 0,
+};
+
struct bcm54140_priv {
int port;
int base_addr;
@@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct phy_device *phydev, u16 rdb)
int ret;
phy_lock_mdio_bus(phydev);
- ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
+ ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
+ MII_BCM54XX_RDB_ADDR, rdb);
if (ret < 0)
goto out;
- ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
+ ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
+ MII_BCM54XX_RDB_DATA);
out:
phy_unlock_mdio_bus(phydev);
@@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struct phy_device *phydev,
int ret;
phy_lock_mdio_bus(phydev);
- ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
+ ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
+ MII_BCM54XX_RDB_ADDR, rdb);
if (ret < 0)
goto out;
- ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
+ ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
+ MII_BCM54XX_RDB_DATA, val);
out:
phy_unlock_mdio_bus(phydev);
diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c
index 9717a1626f3f..f1d47c264058 100644
--- a/drivers/net/phy/bcm84881.c
+++ b/drivers/net/phy/bcm84881.c
@@ -29,8 +29,19 @@ static int bcm84881_wait_init(struct phy_device *phydev)
100000, 2000000, false);
}
+static void bcm84881_fill_possible_interfaces(struct phy_device *phydev)
+{
+ unsigned long *possible = phydev->possible_interfaces;
+
+ __set_bit(PHY_INTERFACE_MODE_SGMII, possible);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, possible);
+}
+
static int bcm84881_config_init(struct phy_device *phydev)
{
+ bcm84881_fill_possible_interfaces(phydev);
+
switch (phydev->interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_2500BASEX:
@@ -39,6 +50,7 @@ static int bcm84881_config_init(struct phy_device *phydev)
default:
return -ENODEV;
}
+
return 0;
}
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 3a627105675a..312a8bb35d78 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -1135,6 +1135,8 @@ static struct phy_driver broadcom_drivers[] = {
.handle_interrupt = bcm_phy_handle_interrupt,
.link_change_notify = bcm54xx_link_change_notify,
.led_brightness_set = bcm_phy_led_brightness_set,
+ .suspend = bcm54xx_suspend,
+ .resume = bcm54xx_resume,
}, {
.phy_id = PHY_ID_BCM54616S,
.phy_id_mask = 0xfffffff0,
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
index 2657be7cc049..5c42c47dc564 100644
--- a/drivers/net/phy/dp83640.c
+++ b/drivers/net/phy/dp83640.c
@@ -1207,22 +1207,20 @@ static irqreturn_t dp83640_handle_interrupt(struct phy_device *phydev)
return IRQ_HANDLED;
}
-static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
+static int dp83640_hwtstamp(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct dp83640_private *dp83640 =
container_of(mii_ts, struct dp83640_private, mii_ts);
- struct hwtstamp_config cfg;
u16 txcfg0, rxcfg0;
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ONESTEP_SYNC)
+ if (cfg->tx_type < 0 || cfg->tx_type > HWTSTAMP_TX_ONESTEP_SYNC)
return -ERANGE;
- dp83640->hwts_tx_en = cfg.tx_type;
+ dp83640->hwts_tx_en = cfg->tx_type;
- switch (cfg.rx_filter) {
+ switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
dp83640->hwts_rx_en = 0;
dp83640->layer = 0;
@@ -1234,7 +1232,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
dp83640->hwts_rx_en = 1;
dp83640->layer = PTP_CLASS_L4;
dp83640->version = PTP_CLASS_V1;
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
@@ -1242,7 +1240,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
dp83640->hwts_rx_en = 1;
dp83640->layer = PTP_CLASS_L4;
dp83640->version = PTP_CLASS_V2;
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
@@ -1250,7 +1248,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
dp83640->hwts_rx_en = 1;
dp83640->layer = PTP_CLASS_L2;
dp83640->version = PTP_CLASS_V2;
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
@@ -1258,7 +1256,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
dp83640->hwts_rx_en = 1;
dp83640->layer = PTP_CLASS_L4 | PTP_CLASS_L2;
dp83640->version = PTP_CLASS_V2;
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
return -ERANGE;
@@ -1292,7 +1290,7 @@ static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
mutex_unlock(&dp83640->clock->extreg_lock);
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ return 0;
}
static void rx_timestamp_work(struct work_struct *work)
diff --git a/drivers/net/phy/dp83tg720.c b/drivers/net/phy/dp83tg720.c
new file mode 100644
index 000000000000..326c9770a6dc
--- /dev/null
+++ b/drivers/net/phy/dp83tg720.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Driver for the Texas Instruments DP83TG720 PHY
+ * Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
+ */
+#include <linux/bitfield.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define DP83TG720S_PHY_ID 0x2000a284
+
+/* MDIO_MMD_VEND2 registers */
+#define DP83TG720S_MII_REG_10 0x10
+#define DP83TG720S_STS_MII_INT BIT(7)
+#define DP83TG720S_LINK_STATUS BIT(0)
+
+#define DP83TG720S_PHY_RESET 0x1f
+#define DP83TG720S_HW_RESET BIT(15)
+
+#define DP83TG720S_RGMII_DELAY_CTRL 0x602
+/* In RGMII mode, Enable or disable the internal delay for RXD */
+#define DP83TG720S_RGMII_RX_CLK_SEL BIT(1)
+/* In RGMII mode, Enable or disable the internal delay for TXD */
+#define DP83TG720S_RGMII_TX_CLK_SEL BIT(0)
+
+#define DP83TG720S_SQI_REG_1 0x871
+#define DP83TG720S_SQI_OUT_WORST GENMASK(7, 5)
+#define DP83TG720S_SQI_OUT GENMASK(3, 1)
+
+#define DP83TG720_SQI_MAX 7
+
+static int dp83tg720_config_aneg(struct phy_device *phydev)
+{
+ /* Autoneg is not supported and this PHY supports only one speed.
+ * We need to care only about master/slave configuration if it was
+ * changed by user.
+ */
+ return genphy_c45_pma_baset1_setup_master_slave(phydev);
+}
+
+static int dp83tg720_read_status(struct phy_device *phydev)
+{
+ u16 phy_sts;
+ int ret;
+
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+
+ /* Most of Clause 45 registers are not present, so we can't use
+ * genphy_c45_read_status() here.
+ */
+ phy_sts = phy_read(phydev, DP83TG720S_MII_REG_10);
+ phydev->link = !!(phy_sts & DP83TG720S_LINK_STATUS);
+ if (!phydev->link) {
+ /* According to the "DP83TC81x, DP83TG72x Software
+ * Implementation Guide", the PHY needs to be reset after a
+ * link loss or if no link is created after at least 100ms.
+ *
+ * Currently we are polling with the PHY_STATE_TIME (1000ms)
+ * interval, which is still enough for not automotive use cases.
+ */
+ ret = phy_init_hw(phydev);
+ if (ret)
+ return ret;
+
+ /* After HW reset we need to restore master/slave configuration.
+ */
+ ret = dp83tg720_config_aneg(phydev);
+ if (ret)
+ return ret;
+
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ } else {
+ /* PMA/PMD control 1 register (Register 1.0) is present, but it
+ * doesn't contain the link speed information.
+ * So genphy_c45_read_pma() can't be used here.
+ */
+ ret = genphy_c45_pma_baset1_read_master_slave(phydev);
+ if (ret)
+ return ret;
+
+ phydev->duplex = DUPLEX_FULL;
+ phydev->speed = SPEED_1000;
+ }
+
+ return 0;
+}
+
+static int dp83tg720_get_sqi(struct phy_device *phydev)
+{
+ int ret;
+
+ if (!phydev->link)
+ return 0;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_SQI_REG_1);
+ if (ret < 0)
+ return ret;
+
+ return FIELD_GET(DP83TG720S_SQI_OUT, ret);
+}
+
+static int dp83tg720_get_sqi_max(struct phy_device *phydev)
+{
+ return DP83TG720_SQI_MAX;
+}
+
+static int dp83tg720_config_rgmii_delay(struct phy_device *phydev)
+{
+ u16 rgmii_delay_mask;
+ u16 rgmii_delay = 0;
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ rgmii_delay = 0;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL |
+ DP83TG720S_RGMII_TX_CLK_SEL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ rgmii_delay = DP83TG720S_RGMII_TX_CLK_SEL;
+ break;
+ default:
+ return 0;
+ }
+
+ rgmii_delay_mask = DP83TG720S_RGMII_RX_CLK_SEL |
+ DP83TG720S_RGMII_TX_CLK_SEL;
+
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
+ DP83TG720S_RGMII_DELAY_CTRL, rgmii_delay_mask,
+ rgmii_delay);
+}
+
+static int dp83tg720_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Software Restart is not enough to recover from a link failure.
+ * Using Hardware Reset instead.
+ */
+ ret = phy_write(phydev, DP83TG720S_PHY_RESET, DP83TG720S_HW_RESET);
+ if (ret)
+ return ret;
+
+ /* Wait until MDC can be used again.
+ * The wait value of one 1ms is documented in "DP83TG720S-Q1 1000BASE-T1
+ * Automotive Ethernet PHY with SGMII and RGMII" datasheet.
+ */
+ usleep_range(1000, 2000);
+
+ if (phy_interface_is_rgmii(phydev))
+ return dp83tg720_config_rgmii_delay(phydev);
+
+ return 0;
+}
+
+static struct phy_driver dp83tg720_driver[] = {
+{
+ PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID),
+ .name = "TI DP83TG720S",
+
+ .config_aneg = dp83tg720_config_aneg,
+ .read_status = dp83tg720_read_status,
+ .get_features = genphy_c45_pma_read_ext_abilities,
+ .config_init = dp83tg720_config_init,
+ .get_sqi = dp83tg720_get_sqi,
+ .get_sqi_max = dp83tg720_get_sqi_max,
+
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+} };
+module_phy_driver(dp83tg720_driver);
+
+static struct mdio_device_id __maybe_unused dp83tg720_tbl[] = {
+ { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(mdio, dp83tg720_tbl);
+
+MODULE_DESCRIPTION("Texas Instruments DP83TG720S PHY driver");
+MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index d4bb90d76881..ad43e280930c 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -141,13 +141,21 @@ enum {
MV_V2_TEMP_UNKNOWN = 0x9600, /* unknown function */
};
+struct mv3310_mactype {
+ bool valid;
+ bool fixed_interface;
+ phy_interface_t interface_10g;
+};
+
struct mv3310_chip {
bool (*has_downshift)(struct phy_device *phydev);
void (*init_supported_interfaces)(unsigned long *mask);
int (*get_mactype)(struct phy_device *phydev);
int (*set_mactype)(struct phy_device *phydev, int mactype);
int (*select_mactype)(unsigned long *interfaces);
- int (*init_interface)(struct phy_device *phydev, int mactype);
+
+ const struct mv3310_mactype *mactypes;
+ size_t n_mactypes;
#ifdef CONFIG_HWMON
int (*hwmon_read_temp_reg)(struct phy_device *phydev);
@@ -156,11 +164,10 @@ struct mv3310_chip {
struct mv3310_priv {
DECLARE_BITMAP(supported_interfaces, PHY_INTERFACE_MODE_MAX);
+ const struct mv3310_mactype *mactype;
u32 firmware_ver;
bool has_downshift;
- bool rate_match;
- phy_interface_t const_interface;
struct device *hwmon_dev;
char *hwmon_name;
@@ -702,70 +709,114 @@ static int mv3310_select_mactype(unsigned long *interfaces)
return -1;
}
-static int mv2110_init_interface(struct phy_device *phydev, int mactype)
-{
- struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
-
- priv->rate_match = false;
-
- if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH)
- priv->rate_match = true;
-
- if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII)
- priv->const_interface = PHY_INTERFACE_MODE_USXGMII;
- else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH)
- priv->const_interface = PHY_INTERFACE_MODE_10GBASER;
- else if (mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER ||
- mactype == MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN)
- priv->const_interface = PHY_INTERFACE_MODE_NA;
- else
- return -EINVAL;
-
- return 0;
-}
-
-static int mv3310_init_interface(struct phy_device *phydev, int mactype)
-{
- struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+static const struct mv3310_mactype mv2110_mactypes[] = {
+ [MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_USXGMII,
+ },
+ [MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_NA,
+ },
+ [MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER_NO_SGMII_AN] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_NA,
+ },
+ [MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+};
- priv->rate_match = false;
-
- if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH ||
- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH ||
- mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH)
- priv->rate_match = true;
-
- if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII)
- priv->const_interface = PHY_INTERFACE_MODE_USXGMII;
- else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH ||
- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN ||
- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER)
- priv->const_interface = PHY_INTERFACE_MODE_10GBASER;
- else if (mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH ||
- mactype == MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI)
- priv->const_interface = PHY_INTERFACE_MODE_RXAUI;
- else if (mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH ||
- mactype == MV_V2_3310_PORT_CTRL_MACTYPE_XAUI)
- priv->const_interface = PHY_INTERFACE_MODE_XAUI;
- else
- return -EINVAL;
+static const struct mv3310_mactype mv3310_mactypes[] = {
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_RXAUI,
+ },
+ [MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_XAUI,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_RXAUI,
+ },
+ [MV_V2_3310_PORT_CTRL_MACTYPE_XAUI] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_XAUI,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_USXGMII,
+ },
+};
- return 0;
-}
+static const struct mv3310_mactype mv3340_mactypes[] = {
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_RXAUI,
+ },
+ [MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_RXAUI,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_RXAUI,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN] = {
+ .valid = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_10GBASER,
+ },
+ [MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII] = {
+ .valid = true,
+ .fixed_interface = true,
+ .interface_10g = PHY_INTERFACE_MODE_USXGMII,
+ },
+};
-static int mv3340_init_interface(struct phy_device *phydev, int mactype)
+static void mv3310_fill_possible_interfaces(struct phy_device *phydev)
{
struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
- int err = 0;
-
- priv->rate_match = false;
+ unsigned long *possible = phydev->possible_interfaces;
+ const struct mv3310_mactype *mactype = priv->mactype;
- if (mactype == MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN)
- priv->const_interface = PHY_INTERFACE_MODE_RXAUI;
- else
- err = mv3310_init_interface(phydev, mactype);
+ if (mactype->interface_10g != PHY_INTERFACE_MODE_NA)
+ __set_bit(priv->mactype->interface_10g, possible);
- return err;
+ if (!mactype->fixed_interface) {
+ __set_bit(PHY_INTERFACE_MODE_5GBASER, possible);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
+ __set_bit(PHY_INTERFACE_MODE_SGMII, possible);
+ }
}
static int mv3310_config_init(struct phy_device *phydev)
@@ -803,12 +854,15 @@ static int mv3310_config_init(struct phy_device *phydev)
if (mactype < 0)
return mactype;
- err = chip->init_interface(phydev, mactype);
- if (err) {
+ if (mactype >= chip->n_mactypes || !chip->mactypes[mactype].valid) {
phydev_err(phydev, "MACTYPE configuration invalid\n");
- return err;
+ return -EINVAL;
}
+ priv->mactype = &chip->mactypes[mactype];
+
+ mv3310_fill_possible_interfaces(phydev);
+
/* Enable EDPD mode - saving 600mW */
err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
if (err)
@@ -935,9 +989,8 @@ static void mv3310_update_interface(struct phy_device *phydev)
*
* In USXGMII mode the PHY interface mode is also fixed.
*/
- if (priv->rate_match ||
- priv->const_interface == PHY_INTERFACE_MODE_USXGMII) {
- phydev->interface = priv->const_interface;
+ if (priv->mactype->fixed_interface) {
+ phydev->interface = priv->mactype->interface_10g;
return;
}
@@ -949,7 +1002,7 @@ static void mv3310_update_interface(struct phy_device *phydev)
*/
switch (phydev->speed) {
case SPEED_10000:
- phydev->interface = priv->const_interface;
+ phydev->interface = priv->mactype->interface_10g;
break;
case SPEED_5000:
phydev->interface = PHY_INTERFACE_MODE_5GBASER;
@@ -1163,7 +1216,9 @@ static const struct mv3310_chip mv3310_type = {
.get_mactype = mv3310_get_mactype,
.set_mactype = mv3310_set_mactype,
.select_mactype = mv3310_select_mactype,
- .init_interface = mv3310_init_interface,
+
+ .mactypes = mv3310_mactypes,
+ .n_mactypes = ARRAY_SIZE(mv3310_mactypes),
#ifdef CONFIG_HWMON
.hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg,
@@ -1176,7 +1231,9 @@ static const struct mv3310_chip mv3340_type = {
.get_mactype = mv3310_get_mactype,
.set_mactype = mv3310_set_mactype,
.select_mactype = mv3310_select_mactype,
- .init_interface = mv3340_init_interface,
+
+ .mactypes = mv3340_mactypes,
+ .n_mactypes = ARRAY_SIZE(mv3340_mactypes),
#ifdef CONFIG_HWMON
.hwmon_read_temp_reg = mv3310_hwmon_read_temp_reg,
@@ -1188,7 +1245,9 @@ static const struct mv3310_chip mv2110_type = {
.get_mactype = mv2110_get_mactype,
.set_mactype = mv2110_set_mactype,
.select_mactype = mv2110_select_mactype,
- .init_interface = mv2110_init_interface,
+
+ .mactypes = mv2110_mactypes,
+ .n_mactypes = ARRAY_SIZE(mv2110_mactypes),
#ifdef CONFIG_HWMON
.hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg,
@@ -1200,7 +1259,9 @@ static const struct mv3310_chip mv2111_type = {
.get_mactype = mv2110_get_mactype,
.set_mactype = mv2110_set_mactype,
.select_mactype = mv2110_select_mactype,
- .init_interface = mv2110_init_interface,
+
+ .mactypes = mv2110_mactypes,
+ .n_mactypes = ARRAY_SIZE(mv2110_mactypes),
#ifdef CONFIG_HWMON
.hwmon_read_temp_reg = mv2110_hwmon_read_temp_reg,
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 25dcaa49ab8b..afbad1ad8683 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -193,6 +193,10 @@ static void mdiobus_release(struct device *d)
bus->state != MDIOBUS_ALLOCATED,
"%s: not in RELEASED or ALLOCATED state\n",
bus->id);
+
+ if (bus->state == MDIOBUS_RELEASED)
+ fwnode_handle_put(dev_fwnode(d));
+
kfree(bus);
}
@@ -506,7 +510,7 @@ static int mdiobus_create_device(struct mii_bus *bus,
if (IS_ERR(mdiodev))
return -ENODEV;
- strncpy(mdiodev->modalias, bi->modalias,
+ strscpy(mdiodev->modalias, bi->modalias,
sizeof(mdiodev->modalias));
mdiodev->bus_match = mdio_device_bus_match;
mdiodev->dev.platform_data = (void *)bi->platform_data;
@@ -684,6 +688,15 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner)
bus->dev.groups = NULL;
dev_set_name(&bus->dev, "%s", bus->id);
+ /* If the bus state is allocated, we're registering a fresh bus
+ * that may have a fwnode associated with it. Grab a reference
+ * to the fwnode. This will be dropped when the bus is released.
+ * If the bus was set to unregistered, it means that the bus was
+ * previously registered, and we've already grabbed a reference.
+ */
+ if (bus->state == MDIOBUS_ALLOCATED)
+ fwnode_handle_get(dev_fwnode(&bus->dev));
+
/* We need to set state to MDIOBUS_UNREGISTERED to correctly release
* the device in mdiobus_free()
*
diff --git a/drivers/net/phy/mdio_device.c b/drivers/net/phy/mdio_device.c
index 044828d081d2..73f6539b9e50 100644
--- a/drivers/net/phy/mdio_device.c
+++ b/drivers/net/phy/mdio_device.c
@@ -62,6 +62,7 @@ struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)
mdiodev->device_remove = mdio_device_remove;
mdiodev->bus = bus;
mdiodev->addr = addr;
+ mdiodev->reset_state = -1;
dev_set_name(&mdiodev->dev, PHY_ID_FMT, bus->id, addr);
@@ -122,6 +123,9 @@ void mdio_device_reset(struct mdio_device *mdiodev, int value)
if (!mdiodev->reset_gpio && !mdiodev->reset_ctrl)
return;
+ if (mdiodev->reset_state == value)
+ return;
+
if (mdiodev->reset_gpio)
gpiod_set_value_cansleep(mdiodev->reset_gpio, value);
@@ -135,6 +139,8 @@ void mdio_device_reset(struct mdio_device *mdiodev, int value)
d = value ? mdiodev->reset_assert_delay : mdiodev->reset_deassert_delay;
if (d)
fsleep(d);
+
+ mdiodev->reset_state = value;
}
EXPORT_SYMBOL(mdio_device_reset);
diff --git a/drivers/net/phy/mdio_devres.c b/drivers/net/phy/mdio_devres.c
index 69b829e6ab35..7fd3377dbd79 100644
--- a/drivers/net/phy/mdio_devres.c
+++ b/drivers/net/phy/mdio_devres.c
@@ -131,4 +131,5 @@ int __devm_of_mdiobus_register(struct device *dev, struct mii_bus *mdio,
EXPORT_SYMBOL(__devm_of_mdiobus_register);
#endif /* CONFIG_OF_MDIO */
+MODULE_DESCRIPTION("Network MDIO bus devres helpers");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/mediatek-ge-soc.c b/drivers/net/phy/mediatek-ge-soc.c
index 8a20d9889f10..0f3a1538a8b8 100644
--- a/drivers/net/phy/mediatek-ge-soc.c
+++ b/drivers/net/phy/mediatek-ge-soc.c
@@ -489,7 +489,7 @@ static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val,
u16 reg, val;
if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988)
- bias = -2;
+ bias = -1;
val = clamp_val(bias + tx_r50_cal_val, 0, 63);
@@ -705,6 +705,11 @@ restore:
static void mt798x_phy_common_finetune(struct phy_device *phydev)
{
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
+ __phy_write(phydev, 0x11, 0xc71);
+ __phy_write(phydev, 0x12, 0xc);
+ __phy_write(phydev, 0x10, 0x8fae);
+
/* EnabRandUpdTrig = 1 */
__phy_write(phydev, 0x11, 0x2f00);
__phy_write(phydev, 0x12, 0xe);
@@ -715,15 +720,56 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x83aa);
- /* TrFreeze = 0 */
+ /* FfeUpdGainForce = 1(Enable), FfeUpdGainForceVal = 4 */
+ __phy_write(phydev, 0x11, 0x240);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x9680);
+
+ /* TrFreeze = 0 (mt7988 default) */
__phy_write(phydev, 0x11, 0x0);
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x9686);
+ /* SSTrKp100 = 5 */
+ /* SSTrKf100 = 6 */
+ /* SSTrKp1000Mas = 5 */
+ /* SSTrKf1000Mas = 6 */
/* SSTrKp1000Slv = 5 */
+ /* SSTrKf1000Slv = 6 */
__phy_write(phydev, 0x11, 0xbaef);
__phy_write(phydev, 0x12, 0x2e);
__phy_write(phydev, 0x10, 0x968c);
+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+}
+
+static void mt7981_phy_finetune(struct phy_device *phydev)
+{
+ u16 val[8] = { 0x01ce, 0x01c1,
+ 0x020f, 0x0202,
+ 0x03d0, 0x03c0,
+ 0x0013, 0x0005 };
+ int i, k;
+
+ /* 100M eye finetune:
+ * Keep middle level of TX MLT3 shapper as default.
+ * Only change TX MLT3 overshoot level here.
+ */
+ for (k = 0, i = 1; i < 12; i++) {
+ if (i % 3 == 0)
+ continue;
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
+ }
+
+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
+ /* ResetSyncOffset = 6 */
+ __phy_write(phydev, 0x11, 0x600);
+ __phy_write(phydev, 0x12, 0x0);
+ __phy_write(phydev, 0x10, 0x8fc0);
+
+ /* VgaDecRate = 1 */
+ __phy_write(phydev, 0x11, 0x4c2a);
+ __phy_write(phydev, 0x12, 0x3e);
+ __phy_write(phydev, 0x10, 0x8fa4);
/* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2,
* MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2
@@ -738,7 +784,7 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
__phy_write(phydev, 0x10, 0x8ec0);
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
- /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9));
@@ -771,48 +817,6 @@ static void mt798x_phy_common_finetune(struct phy_device *phydev)
phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222);
}
-static void mt7981_phy_finetune(struct phy_device *phydev)
-{
- u16 val[8] = { 0x01ce, 0x01c1,
- 0x020f, 0x0202,
- 0x03d0, 0x03c0,
- 0x0013, 0x0005 };
- int i, k;
-
- /* 100M eye finetune:
- * Keep middle level of TX MLT3 shapper as default.
- * Only change TX MLT3 overshoot level here.
- */
- for (k = 0, i = 1; i < 12; i++) {
- if (i % 3 == 0)
- continue;
- phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]);
- }
-
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */
- __phy_write(phydev, 0x11, 0xc71);
- __phy_write(phydev, 0x12, 0xc);
- __phy_write(phydev, 0x10, 0x8fae);
-
- /* ResetSyncOffset = 6 */
- __phy_write(phydev, 0x11, 0x600);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x8fc0);
-
- /* VgaDecRate = 1 */
- __phy_write(phydev, 0x11, 0x4c2a);
- __phy_write(phydev, 0x12, 0x3e);
- __phy_write(phydev, 0x10, 0x8fa4);
-
- /* FfeUpdGainForce = 4 */
- __phy_write(phydev, 0x11, 0x240);
- __phy_write(phydev, 0x12, 0x0);
- __phy_write(phydev, 0x10, 0x9680);
-
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
-}
-
static void mt7988_phy_finetune(struct phy_device *phydev)
{
u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182,
@@ -827,17 +831,7 @@ static void mt7988_phy_finetune(struct phy_device *phydev)
/* TCT finetune */
phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5);
- /* Disable TX power saving */
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
- MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
-
phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5);
-
- /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */
- __phy_write(phydev, 0x11, 0x671);
- __phy_write(phydev, 0x12, 0xc);
- __phy_write(phydev, 0x10, 0x8fae);
-
/* ResetSyncOffset = 5 */
__phy_write(phydev, 0x11, 0x500);
__phy_write(phydev, 0x12, 0x0);
@@ -845,13 +839,27 @@ static void mt7988_phy_finetune(struct phy_device *phydev)
/* VgaDecRate is 1 at default on mt7988 */
- phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+ /* MrvlTrFix100Kp = 6, MrvlTrFix100Kf = 7,
+ * MrvlTrFix1000Kp = 6, MrvlTrFix1000Kf = 7
+ */
+ __phy_write(phydev, 0x11, 0xb90a);
+ __phy_write(phydev, 0x12, 0x6f);
+ __phy_write(phydev, 0x10, 0x8f82);
+
+ /* RemAckCntLimitCtrl = 1 */
+ __phy_write(phydev, 0x11, 0xfbba);
+ __phy_write(phydev, 0x12, 0xc3);
+ __phy_write(phydev, 0x10, 0x87f8);
- phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30);
- /* TxClkOffset = 2 */
- __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK,
- FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2));
phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0);
+
+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 10 */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234,
+ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK,
+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0xa));
+
+ /* rg_tr_lpf_cnt_val = 1023 */
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x3ff);
}
static void mt798x_phy_eee(struct phy_device *phydev)
@@ -884,11 +892,11 @@ static void mt798x_phy_eee(struct phy_device *phydev)
MTK_PHY_LPI_SLV_SEND_TX_EN,
FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120));
- phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
- MTK_PHY_LPI_SEND_LOC_TIMER_MASK |
- MTK_PHY_LPI_TXPCS_LOC_RCV,
- FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117));
+ /* Keep MTK_PHY_LPI_SEND_LOC_TIMER as 375 */
+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239,
+ MTK_PHY_LPI_TXPCS_LOC_RCV);
+ /* This also fixes some IoT issues, such as CH340 */
phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK,
FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
@@ -922,7 +930,7 @@ static void mt798x_phy_eee(struct phy_device *phydev)
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x9690);
- /* REG_EEE_st2TrKf1000 = 3 */
+ /* REG_EEE_st2TrKf1000 = 2 */
__phy_write(phydev, 0x11, 0x114f);
__phy_write(phydev, 0x12, 0x2);
__phy_write(phydev, 0x10, 0x969a);
@@ -947,7 +955,7 @@ static void mt798x_phy_eee(struct phy_device *phydev)
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x96b8);
- /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */
+ /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 0 */
__phy_write(phydev, 0x11, 0x1463);
__phy_write(phydev, 0x12, 0x0);
__phy_write(phydev, 0x10, 0x96ca);
@@ -1459,6 +1467,13 @@ static int mt7988_phy_probe(struct phy_device *phydev)
if (err)
return err;
+ /* Disable TX power saving at probing to:
+ * 1. Meet common mode compliance test criteria
+ * 2. Make sure that TX-VCM calibration works fine
+ */
+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7,
+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8);
+
return mt798x_phy_calibration(phydev);
}
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 08e3915001c3..dad720138baa 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -120,6 +120,11 @@
*/
#define LAN8814_1PPM_FORMAT 17179
+#define PTP_RX_VERSION 0x0248
+#define PTP_TX_VERSION 0x0288
+#define PTP_MAX_VERSION(x) (((x) & GENMASK(7, 0)) << 8)
+#define PTP_MIN_VERSION(x) ((x) & GENMASK(7, 0))
+
#define PTP_RX_MOD 0x024F
#define PTP_RX_MOD_BAD_UDPV4_CHKSUM_FORCE_FCS_DIS_ BIT(3)
#define PTP_RX_TIMESTAMP_EN 0x024D
@@ -2001,7 +2006,7 @@ static int kszphy_probe(struct phy_device *phydev)
kszphy_parse_led_mode(phydev);
- clk = devm_clk_get(&phydev->mdio.dev, "rmii-ref");
+ clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, "rmii-ref");
/* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */
if (!IS_ERR_OR_NULL(clk)) {
unsigned long rate = clk_get_rate(clk);
@@ -2021,6 +2026,11 @@ static int kszphy_probe(struct phy_device *phydev)
rate);
return -EINVAL;
}
+ } else if (!clk) {
+ /* unnamed clock from the generic ethernet-phy binding */
+ clk = devm_clk_get_optional_enabled(&phydev->mdio.dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
}
if (ksz8041_fiber_mode(phydev))
@@ -2395,24 +2405,22 @@ static void lan8814_flush_fifo(struct phy_device *phydev, bool egress)
lanphy_read_page_reg(phydev, 5, PTP_TSU_INT_STS);
}
-static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
+static int lan8814_hwtstamp(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
{
struct kszphy_ptp_priv *ptp_priv =
container_of(mii_ts, struct kszphy_ptp_priv, mii_ts);
struct phy_device *phydev = ptp_priv->phydev;
struct lan8814_shared_priv *shared = phydev->shared->priv;
struct lan8814_ptp_rx_ts *rx_ts, *tmp;
- struct hwtstamp_config config;
int txcfg = 0, rxcfg = 0;
int pkt_ts_enable;
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
- return -EFAULT;
-
- ptp_priv->hwts_tx_type = config.tx_type;
- ptp_priv->rx_filter = config.rx_filter;
+ ptp_priv->hwts_tx_type = config->tx_type;
+ ptp_priv->rx_filter = config->rx_filter;
- switch (config.rx_filter) {
+ switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
ptp_priv->layer = 0;
ptp_priv->version = 0;
@@ -2458,13 +2466,13 @@ static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
lanphy_write_page_reg(ptp_priv->phydev, 5, PTP_TX_MOD,
PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_);
- if (config.rx_filter != HWTSTAMP_FILTER_NONE)
+ if (config->rx_filter != HWTSTAMP_FILTER_NONE)
lan8814_config_ts_intr(ptp_priv->phydev, true);
else
lan8814_config_ts_intr(ptp_priv->phydev, false);
mutex_lock(&shared->shared_lock);
- if (config.rx_filter != HWTSTAMP_FILTER_NONE)
+ if (config->rx_filter != HWTSTAMP_FILTER_NONE)
shared->ref++;
else
shared->ref--;
@@ -2488,7 +2496,7 @@ static int lan8814_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
lan8814_flush_fifo(ptp_priv->phydev, false);
lan8814_flush_fifo(ptp_priv->phydev, true);
- return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
+ return 0;
}
static void lan8814_txtstamp(struct mii_timestamper *mii_ts,
@@ -3147,6 +3155,12 @@ static void lan8814_ptp_init(struct phy_device *phydev)
lanphy_write_page_reg(phydev, 5, PTP_TX_PARSE_IP_ADDR_EN, 0);
lanphy_write_page_reg(phydev, 5, PTP_RX_PARSE_IP_ADDR_EN, 0);
+ /* Disable checking for minorVersionPTP field */
+ lanphy_write_page_reg(phydev, 5, PTP_RX_VERSION,
+ PTP_MAX_VERSION(0xff) | PTP_MIN_VERSION(0x0));
+ lanphy_write_page_reg(phydev, 5, PTP_TX_VERSION,
+ PTP_MAX_VERSION(0xff) | PTP_MIN_VERSION(0x0));
+
skb_queue_head_init(&ptp_priv->tx_queue);
skb_queue_head_init(&ptp_priv->rx_queue);
INIT_LIST_HEAD(&ptp_priv->rx_ts_list);
@@ -3335,8 +3349,10 @@ static int lan8814_probe(struct phy_device *phydev)
#define LAN8841_ADC_CHANNEL_MASK 198
#define LAN8841_PTP_RX_PARSE_L2_ADDR_EN 370
#define LAN8841_PTP_RX_PARSE_IP_ADDR_EN 371
+#define LAN8841_PTP_RX_VERSION 374
#define LAN8841_PTP_TX_PARSE_L2_ADDR_EN 434
#define LAN8841_PTP_TX_PARSE_IP_ADDR_EN 435
+#define LAN8841_PTP_TX_VERSION 438
#define LAN8841_PTP_CMD_CTL 256
#define LAN8841_PTP_CMD_CTL_PTP_ENABLE BIT(2)
#define LAN8841_PTP_CMD_CTL_PTP_DISABLE BIT(1)
@@ -3380,6 +3396,12 @@ static int lan8841_config_init(struct phy_device *phydev)
phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
LAN8841_PTP_RX_PARSE_IP_ADDR_EN, 0);
+ /* Disable checking for minorVersionPTP field */
+ phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_RX_VERSION, 0xff00);
+ phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_TX_VERSION, 0xff00);
+
/* 100BT Clause 40 improvenent errata */
phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
LAN8841_ANALOG_CONTROL_1,
@@ -3631,12 +3653,8 @@ static int lan8841_ts_info(struct mii_timestamper *mii_ts,
info->phc_index = ptp_priv->ptp_clock ?
ptp_clock_index(ptp_priv->ptp_clock) : -1;
- if (info->phc_index == -1) {
- info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE |
- SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE;
+ if (info->phc_index == -1)
return 0;
- }
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
@@ -3703,21 +3721,19 @@ static void lan8841_ptp_enable_processing(struct kszphy_ptp_priv *ptp_priv,
#define LAN8841_PTP_TX_TIMESTAMP_EN 443
#define LAN8841_PTP_TX_MOD 445
-static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
+static int lan8841_hwtstamp(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *config,
+ struct netlink_ext_ack *extack)
{
struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts);
struct phy_device *phydev = ptp_priv->phydev;
- struct hwtstamp_config config;
int txcfg = 0, rxcfg = 0;
int pkt_ts_enable;
- if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
- return -EFAULT;
-
- ptp_priv->hwts_tx_type = config.tx_type;
- ptp_priv->rx_filter = config.rx_filter;
+ ptp_priv->hwts_tx_type = config->tx_type;
+ ptp_priv->rx_filter = config->rx_filter;
- switch (config.rx_filter) {
+ switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
ptp_priv->layer = 0;
ptp_priv->version = 0;
@@ -3771,13 +3787,13 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
/* Now enable/disable the timestamping */
lan8841_ptp_enable_processing(ptp_priv,
- config.rx_filter != HWTSTAMP_FILTER_NONE);
+ config->rx_filter != HWTSTAMP_FILTER_NONE);
skb_queue_purge(&ptp_priv->tx_queue);
lan8841_ptp_flush_fifo(ptp_priv);
- return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
+ return 0;
}
static bool lan8841_rxtstamp(struct mii_timestamper *mii_ts,
@@ -4842,6 +4858,7 @@ static struct phy_driver ksphy_driver[] = {
.flags = PHY_POLL_CABLE_TEST,
.driver_data = &ksz9131_type,
.probe = kszphy_probe,
+ .soft_reset = genphy_soft_reset,
.config_init = ksz9131_config_init,
.config_intr = kszphy_config_intr,
.config_aneg = ksz9131_config_aneg,
diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h
index 7a962050a4d4..6a3d8a754eb8 100644
--- a/drivers/net/phy/mscc/mscc.h
+++ b/drivers/net/phy/mscc/mscc.h
@@ -416,6 +416,11 @@ struct vsc8531_private {
* gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
* is shared.
*/
+
+enum vsc85xx_global_phy {
+ VSC88XX_BASE_ADDR = 0,
+};
+
struct vsc85xx_shared_private {
struct mutex gpio_lock;
};
diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c
index 4171f01d34e5..6f74ce0ab1aa 100644
--- a/drivers/net/phy/mscc/mscc_main.c
+++ b/drivers/net/phy/mscc/mscc_main.c
@@ -711,7 +711,7 @@ int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
dump_stack();
}
- return __phy_package_write(phydev, regnum, val);
+ return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
}
/* phydev->bus->mdio_lock should be locked when using this function */
@@ -722,7 +722,7 @@ int phy_base_read(struct phy_device *phydev, u32 regnum)
dump_stack();
}
- return __phy_package_read(phydev, regnum);
+ return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
}
u32 vsc85xx_csr_read(struct phy_device *phydev,
diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c
index cf728bfd83e2..eb0b032cb613 100644
--- a/drivers/net/phy/mscc/mscc_ptp.c
+++ b/drivers/net/phy/mscc/mscc_ptp.c
@@ -1045,19 +1045,17 @@ static void vsc85xx_ts_reset_fifo(struct phy_device *phydev)
val);
}
-static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
+static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts,
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct vsc8531_private *vsc8531 =
container_of(mii_ts, struct vsc8531_private, mii_ts);
struct phy_device *phydev = vsc8531->ptp->phydev;
- struct hwtstamp_config cfg;
bool one_step = false;
u32 val;
- if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
- return -EFAULT;
-
- switch (cfg.tx_type) {
+ switch (cfg->tx_type) {
case HWTSTAMP_TX_ONESTEP_SYNC:
one_step = true;
break;
@@ -1069,9 +1067,9 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
return -ERANGE;
}
- vsc8531->ptp->tx_type = cfg.tx_type;
+ vsc8531->ptp->tx_type = cfg->tx_type;
- switch (cfg.rx_filter) {
+ switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
@@ -1084,7 +1082,7 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
return -ERANGE;
}
- vsc8531->ptp->rx_filter = cfg.rx_filter;
+ vsc8531->ptp->rx_filter = cfg->rx_filter;
mutex_lock(&vsc8531->ts_lock);
@@ -1132,7 +1130,7 @@ static int vsc85xx_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
vsc8531->ptp->configured = 1;
mutex_unlock(&vsc8531->ts_lock);
- return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ return 0;
}
static int vsc85xx_ts_info(struct mii_timestamper *mii_ts,
diff --git a/drivers/net/phy/nxp-c45-tja11xx-macsec.c b/drivers/net/phy/nxp-c45-tja11xx-macsec.c
new file mode 100644
index 000000000000..550ef08970f4
--- /dev/null
+++ b/drivers/net/phy/nxp-c45-tja11xx-macsec.c
@@ -0,0 +1,1729 @@
+// SPDX-License-Identifier: GPL-2.0
+/* NXP C45 PTP PHY driver interface
+ * Copyright 2023 NXP
+ * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/ethtool_netlink.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/processor.h>
+#include <net/dst_metadata.h>
+#include <net/macsec.h>
+
+#include "nxp-c45-tja11xx.h"
+
+#define MACSEC_REG_SIZE 32
+#define TX_SC_MAX 4
+
+#define TX_SC_BIT(secy_id) BIT(MACSEC_REG_SIZE - (secy_id) - 1)
+
+#define VEND1_MACSEC_BASE 0x9000
+
+#define MACSEC_CFG 0x0000
+#define MACSEC_CFG_BYPASS BIT(1)
+#define MACSEC_CFG_S0I BIT(0)
+
+#define MACSEC_TPNET 0x0044
+#define PN_WRAP_THRESHOLD 0xffffffff
+
+#define MACSEC_RXSCA 0x0080
+#define MACSEC_RXSCKA 0x0084
+
+#define MACSEC_TXSCA 0x00C0
+#define MACSEC_TXSCKA 0x00C4
+
+#define MACSEC_RXSC_SCI_1H 0x0100
+
+#define MACSEC_RXSC_CFG 0x0128
+#define MACSEC_RXSC_CFG_XPN BIT(25)
+#define MACSEC_RXSC_CFG_AES_256 BIT(24)
+#define MACSEC_RXSC_CFG_SCI_EN BIT(11)
+#define MACSEC_RXSC_CFG_RP BIT(10)
+#define MACSEC_RXSC_CFG_VF_MASK GENMASK(9, 8)
+#define MACSEC_RXSC_CFG_VF_OFF 8
+
+#define MACSEC_RPW 0x012C
+
+#define MACSEC_RXSA_A_CS 0x0180
+#define MACSEC_RXSA_A_NPN 0x0184
+#define MACSEC_RXSA_A_XNPN 0x0188
+#define MACSEC_RXSA_A_LNPN 0x018C
+#define MACSEC_RXSA_A_LXNPN 0x0190
+
+#define MACSEC_RXSA_B_CS 0x01C0
+#define MACSEC_RXSA_B_NPN 0x01C4
+#define MACSEC_RXSA_B_XNPN 0x01C8
+#define MACSEC_RXSA_B_LNPN 0x01CC
+#define MACSEC_RXSA_B_LXNPN 0x01D0
+
+#define MACSEC_RXSA_CS_AN_OFF 1
+#define MACSEC_RXSA_CS_EN BIT(0)
+
+#define MACSEC_TXSC_SCI_1H 0x0200
+#define MACSEC_TXSC_CFG 0x0228
+#define MACSEC_TXSC_CFG_XPN BIT(25)
+#define MACSEC_TXSC_CFG_AES_256 BIT(24)
+#define MACSEC_TXSC_CFG_AN_MASK GENMASK(19, 18)
+#define MACSEC_TXSC_CFG_AN_OFF 18
+#define MACSEC_TXSC_CFG_ASA BIT(17)
+#define MACSEC_TXSC_CFG_SCE BIT(16)
+#define MACSEC_TXSC_CFG_ENCRYPT BIT(4)
+#define MACSEC_TXSC_CFG_PROTECT BIT(3)
+#define MACSEC_TXSC_CFG_SEND_SCI BIT(2)
+#define MACSEC_TXSC_CFG_END_STATION BIT(1)
+#define MACSEC_TXSC_CFG_SCB BIT(0)
+
+#define MACSEC_TXSA_A_CS 0x0280
+#define MACSEC_TXSA_A_NPN 0x0284
+#define MACSEC_TXSA_A_XNPN 0x0288
+
+#define MACSEC_TXSA_B_CS 0x02C0
+#define MACSEC_TXSA_B_NPN 0x02C4
+#define MACSEC_TXSA_B_XNPN 0x02C8
+
+#define MACSEC_SA_CS_A BIT(31)
+
+#define MACSEC_EVR 0x0400
+#define MACSEC_EVER 0x0404
+
+#define MACSEC_RXSA_A_KA 0x0700
+#define MACSEC_RXSA_A_SSCI 0x0720
+#define MACSEC_RXSA_A_SALT 0x0724
+
+#define MACSEC_RXSA_B_KA 0x0740
+#define MACSEC_RXSA_B_SSCI 0x0760
+#define MACSEC_RXSA_B_SALT 0x0764
+
+#define MACSEC_TXSA_A_KA 0x0780
+#define MACSEC_TXSA_A_SSCI 0x07A0
+#define MACSEC_TXSA_A_SALT 0x07A4
+
+#define MACSEC_TXSA_B_KA 0x07C0
+#define MACSEC_TXSA_B_SSCI 0x07E0
+#define MACSEC_TXSA_B_SALT 0x07E4
+
+#define MACSEC_UPFR0D2 0x0A08
+#define MACSEC_UPFR0M1 0x0A10
+#define MACSEC_OVP BIT(12)
+
+#define MACSEC_UPFR0M2 0x0A14
+#define ETYPE_MASK 0xffff
+
+#define MACSEC_UPFR0R 0x0A18
+#define MACSEC_UPFR_EN BIT(0)
+
+#define ADPTR_CNTRL 0x0F00
+#define ADPTR_CNTRL_CONFIG_EN BIT(14)
+#define ADPTR_CNTRL_ADPTR_EN BIT(12)
+#define ADPTR_TX_TAG_CNTRL 0x0F0C
+#define ADPTR_TX_TAG_CNTRL_ENA BIT(31)
+
+#define TX_SC_FLT_BASE 0x800
+#define TX_SC_FLT_SIZE 0x10
+#define TX_FLT_BASE(flt_id) (TX_SC_FLT_BASE + \
+ TX_SC_FLT_SIZE * (flt_id))
+
+#define TX_SC_FLT_OFF_MAC_DA_SA 0x04
+#define TX_SC_FLT_OFF_MAC_SA 0x08
+#define TX_SC_FLT_OFF_MAC_CFG 0x0C
+#define TX_SC_FLT_BY_SA BIT(14)
+#define TX_SC_FLT_EN BIT(8)
+
+#define TX_SC_FLT_MAC_DA_SA(base) ((base) + TX_SC_FLT_OFF_MAC_DA_SA)
+#define TX_SC_FLT_MAC_SA(base) ((base) + TX_SC_FLT_OFF_MAC_SA)
+#define TX_SC_FLT_MAC_CFG(base) ((base) + TX_SC_FLT_OFF_MAC_CFG)
+
+#define ADAPTER_EN BIT(6)
+#define MACSEC_EN BIT(5)
+
+#define MACSEC_INOV1HS 0x0140
+#define MACSEC_INOV2HS 0x0144
+#define MACSEC_INOD1HS 0x0148
+#define MACSEC_INOD2HS 0x014C
+#define MACSEC_RXSCIPUS 0x0150
+#define MACSEC_RXSCIPDS 0x0154
+#define MACSEC_RXSCIPLS 0x0158
+#define MACSEC_RXAN0INUSS 0x0160
+#define MACSEC_RXAN0IPUSS 0x0170
+#define MACSEC_RXSA_A_IPOS 0x0194
+#define MACSEC_RXSA_A_IPIS 0x01B0
+#define MACSEC_RXSA_A_IPNVS 0x01B4
+#define MACSEC_RXSA_B_IPOS 0x01D4
+#define MACSEC_RXSA_B_IPIS 0x01F0
+#define MACSEC_RXSA_B_IPNVS 0x01F4
+#define MACSEC_OPUS 0x021C
+#define MACSEC_OPTLS 0x022C
+#define MACSEC_OOP1HS 0x0240
+#define MACSEC_OOP2HS 0x0244
+#define MACSEC_OOE1HS 0x0248
+#define MACSEC_OOE2HS 0x024C
+#define MACSEC_TXSA_A_OPPS 0x028C
+#define MACSEC_TXSA_A_OPES 0x0290
+#define MACSEC_TXSA_B_OPPS 0x02CC
+#define MACSEC_TXSA_B_OPES 0x02D0
+#define MACSEC_INPWTS 0x0630
+#define MACSEC_INPBTS 0x0638
+#define MACSEC_IPSNFS 0x063C
+
+#define TJA11XX_TLV_TX_NEEDED_HEADROOM (32)
+#define TJA11XX_TLV_NEEDED_TAILROOM (0)
+
+#define ETH_P_TJA11XX_TLV (0x4e58)
+
+enum nxp_c45_sa_type {
+ TX_SA,
+ RX_SA,
+};
+
+struct nxp_c45_sa {
+ void *sa;
+ const struct nxp_c45_sa_regs *regs;
+ enum nxp_c45_sa_type type;
+ bool is_key_a;
+ u8 an;
+ struct list_head list;
+};
+
+struct nxp_c45_secy {
+ struct macsec_secy *secy;
+ struct macsec_rx_sc *rx_sc;
+ struct list_head sa_list;
+ int secy_id;
+ bool rx_sc0_impl;
+ struct list_head list;
+};
+
+struct nxp_c45_macsec {
+ struct list_head secy_list;
+ DECLARE_BITMAP(secy_bitmap, TX_SC_MAX);
+ DECLARE_BITMAP(tx_sc_bitmap, TX_SC_MAX);
+};
+
+struct nxp_c45_sa_regs {
+ u16 cs;
+ u16 npn;
+ u16 xnpn;
+ u16 lnpn;
+ u16 lxnpn;
+ u16 ka;
+ u16 ssci;
+ u16 salt;
+ u16 ipis;
+ u16 ipnvs;
+ u16 ipos;
+ u16 opps;
+ u16 opes;
+};
+
+static const struct nxp_c45_sa_regs rx_sa_a_regs = {
+ .cs = MACSEC_RXSA_A_CS,
+ .npn = MACSEC_RXSA_A_NPN,
+ .xnpn = MACSEC_RXSA_A_XNPN,
+ .lnpn = MACSEC_RXSA_A_LNPN,
+ .lxnpn = MACSEC_RXSA_A_LXNPN,
+ .ka = MACSEC_RXSA_A_KA,
+ .ssci = MACSEC_RXSA_A_SSCI,
+ .salt = MACSEC_RXSA_A_SALT,
+ .ipis = MACSEC_RXSA_A_IPIS,
+ .ipnvs = MACSEC_RXSA_A_IPNVS,
+ .ipos = MACSEC_RXSA_A_IPOS,
+};
+
+static const struct nxp_c45_sa_regs rx_sa_b_regs = {
+ .cs = MACSEC_RXSA_B_CS,
+ .npn = MACSEC_RXSA_B_NPN,
+ .xnpn = MACSEC_RXSA_B_XNPN,
+ .lnpn = MACSEC_RXSA_B_LNPN,
+ .lxnpn = MACSEC_RXSA_B_LXNPN,
+ .ka = MACSEC_RXSA_B_KA,
+ .ssci = MACSEC_RXSA_B_SSCI,
+ .salt = MACSEC_RXSA_B_SALT,
+ .ipis = MACSEC_RXSA_B_IPIS,
+ .ipnvs = MACSEC_RXSA_B_IPNVS,
+ .ipos = MACSEC_RXSA_B_IPOS,
+};
+
+static const struct nxp_c45_sa_regs tx_sa_a_regs = {
+ .cs = MACSEC_TXSA_A_CS,
+ .npn = MACSEC_TXSA_A_NPN,
+ .xnpn = MACSEC_TXSA_A_XNPN,
+ .ka = MACSEC_TXSA_A_KA,
+ .ssci = MACSEC_TXSA_A_SSCI,
+ .salt = MACSEC_TXSA_A_SALT,
+ .opps = MACSEC_TXSA_A_OPPS,
+ .opes = MACSEC_TXSA_A_OPES,
+};
+
+static const struct nxp_c45_sa_regs tx_sa_b_regs = {
+ .cs = MACSEC_TXSA_B_CS,
+ .npn = MACSEC_TXSA_B_NPN,
+ .xnpn = MACSEC_TXSA_B_XNPN,
+ .ka = MACSEC_TXSA_B_KA,
+ .ssci = MACSEC_TXSA_B_SSCI,
+ .salt = MACSEC_TXSA_B_SALT,
+ .opps = MACSEC_TXSA_B_OPPS,
+ .opes = MACSEC_TXSA_B_OPES,
+};
+
+static const
+struct nxp_c45_sa_regs *nxp_c45_sa_regs_get(enum nxp_c45_sa_type sa_type,
+ bool key_a)
+{
+ if (sa_type == RX_SA)
+ if (key_a)
+ return &rx_sa_a_regs;
+ else
+ return &rx_sa_b_regs;
+ else if (sa_type == TX_SA)
+ if (key_a)
+ return &tx_sa_a_regs;
+ else
+ return &tx_sa_b_regs;
+ else
+ return NULL;
+}
+
+static int nxp_c45_macsec_write(struct phy_device *phydev, u16 addr, u32 value)
+{
+ u32 lvalue = value;
+ u16 laddr;
+ int ret;
+
+ WARN_ON_ONCE(addr % 4);
+
+ phydev_dbg(phydev, "write addr 0x%x value 0x%x\n", addr, value);
+
+ laddr = VEND1_MACSEC_BASE + addr / 2;
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, laddr, lvalue);
+ if (ret)
+ return ret;
+
+ laddr += 1;
+ lvalue >>= 16;
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, laddr, lvalue);
+
+ return ret;
+}
+
+static int nxp_c45_macsec_read(struct phy_device *phydev, u16 addr, u32 *value)
+{
+ u32 lvalue;
+ u16 laddr;
+ int ret;
+
+ WARN_ON_ONCE(addr % 4);
+
+ laddr = VEND1_MACSEC_BASE + addr / 2;
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, laddr);
+ if (ret < 0)
+ return ret;
+
+ laddr += 1;
+ lvalue = (u32)ret & 0xffff;
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, laddr);
+ if (ret < 0)
+ return ret;
+
+ lvalue |= (u32)ret << 16;
+ *value = lvalue;
+
+ phydev_dbg(phydev, "read addr 0x%x value 0x%x\n", addr, *value);
+
+ return 0;
+}
+
+static void nxp_c45_macsec_read32_64(struct phy_device *phydev, u16 addr,
+ u64 *value)
+{
+ u32 lvalue;
+
+ nxp_c45_macsec_read(phydev, addr, &lvalue);
+ *value = lvalue;
+}
+
+static void nxp_c45_macsec_read64(struct phy_device *phydev, u16 addr,
+ u64 *value)
+{
+ u32 lvalue;
+
+ nxp_c45_macsec_read(phydev, addr, &lvalue);
+ *value = (u64)lvalue << 32;
+ nxp_c45_macsec_read(phydev, addr + 4, &lvalue);
+ *value |= lvalue;
+}
+
+static void nxp_c45_secy_irq_en(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy, bool en)
+{
+ u32 reg;
+
+ nxp_c45_macsec_read(phydev, MACSEC_EVER, &reg);
+ if (en)
+ reg |= TX_SC_BIT(phy_secy->secy_id);
+ else
+ reg &= ~TX_SC_BIT(phy_secy->secy_id);
+ nxp_c45_macsec_write(phydev, MACSEC_EVER, reg);
+}
+
+static struct nxp_c45_secy *nxp_c45_find_secy(struct list_head *secy_list,
+ sci_t sci)
+{
+ struct nxp_c45_secy *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, secy_list, list)
+ if (pos->secy->sci == sci)
+ return pos;
+
+ return ERR_PTR(-EINVAL);
+}
+
+static struct
+nxp_c45_secy *nxp_c45_find_secy_by_id(struct list_head *secy_list,
+ int id)
+{
+ struct nxp_c45_secy *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, secy_list, list)
+ if (pos->secy_id == id)
+ return pos;
+
+ return ERR_PTR(-EINVAL);
+}
+
+static void nxp_c45_secy_free(struct nxp_c45_secy *phy_secy)
+{
+ list_del(&phy_secy->list);
+ kfree(phy_secy);
+}
+
+static struct nxp_c45_sa *nxp_c45_find_sa(struct list_head *sa_list,
+ enum nxp_c45_sa_type sa_type, u8 an)
+{
+ struct nxp_c45_sa *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, sa_list, list)
+ if (pos->an == an && pos->type == sa_type)
+ return pos;
+
+ return ERR_PTR(-EINVAL);
+}
+
+static struct nxp_c45_sa *nxp_c45_sa_alloc(struct list_head *sa_list, void *sa,
+ enum nxp_c45_sa_type sa_type, u8 an)
+{
+ struct nxp_c45_sa *first = NULL, *pos, *tmp;
+ int occurrences = 0;
+
+ list_for_each_entry_safe(pos, tmp, sa_list, list) {
+ if (pos->type != sa_type)
+ continue;
+
+ if (pos->an == an)
+ return ERR_PTR(-EINVAL);
+
+ first = pos;
+ occurrences++;
+ if (occurrences >= 2)
+ return ERR_PTR(-ENOSPC);
+ }
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return ERR_PTR(-ENOMEM);
+
+ if (first)
+ tmp->is_key_a = !first->is_key_a;
+ else
+ tmp->is_key_a = true;
+
+ tmp->sa = sa;
+ tmp->type = sa_type;
+ tmp->an = an;
+ tmp->regs = nxp_c45_sa_regs_get(tmp->type, tmp->is_key_a);
+ list_add_tail(&tmp->list, sa_list);
+
+ return tmp;
+}
+
+static void nxp_c45_sa_free(struct nxp_c45_sa *sa)
+{
+ list_del(&sa->list);
+ kfree(sa);
+}
+
+static void nxp_c45_sa_list_free(struct list_head *sa_list)
+{
+ struct nxp_c45_sa *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, sa_list, list)
+ nxp_c45_sa_free(pos);
+}
+
+static void nxp_c45_sa_set_pn(struct phy_device *phydev,
+ struct nxp_c45_sa *sa, u64 pn,
+ u32 replay_window)
+{
+ const struct nxp_c45_sa_regs *sa_regs = sa->regs;
+ pn_t npn = {.full64 = pn};
+ pn_t lnpn;
+
+ nxp_c45_macsec_write(phydev, sa_regs->npn, npn.lower);
+ nxp_c45_macsec_write(phydev, sa_regs->xnpn, npn.upper);
+ if (sa->type != RX_SA)
+ return;
+
+ if (pn > replay_window)
+ lnpn.full64 = pn - replay_window;
+ else
+ lnpn.full64 = 1;
+
+ nxp_c45_macsec_write(phydev, sa_regs->lnpn, lnpn.lower);
+ nxp_c45_macsec_write(phydev, sa_regs->lxnpn, lnpn.upper);
+}
+
+static void nxp_c45_sa_set_key(struct macsec_context *ctx,
+ const struct nxp_c45_sa_regs *sa_regs,
+ u8 *salt, ssci_t ssci)
+{
+ struct phy_device *phydev = ctx->phydev;
+ u32 key_size = ctx->secy->key_len / 4;
+ u32 salt_size = MACSEC_SALT_LEN / 4;
+ u32 *key_u32 = (u32 *)ctx->sa.key;
+ u32 *salt_u32 = (u32 *)salt;
+ u32 reg, value;
+ int i;
+
+ for (i = 0; i < key_size; i++) {
+ reg = sa_regs->ka + i * 4;
+ value = (__force u32)cpu_to_be32(key_u32[i]);
+ nxp_c45_macsec_write(phydev, reg, value);
+ }
+
+ if (ctx->secy->xpn) {
+ for (i = 0; i < salt_size; i++) {
+ reg = sa_regs->salt + (2 - i) * 4;
+ value = (__force u32)cpu_to_be32(salt_u32[i]);
+ nxp_c45_macsec_write(phydev, reg, value);
+ }
+
+ value = (__force u32)cpu_to_be32((__force u32)ssci);
+ nxp_c45_macsec_write(phydev, sa_regs->ssci, value);
+ }
+
+ nxp_c45_macsec_write(phydev, sa_regs->cs, MACSEC_SA_CS_A);
+}
+
+static void nxp_c45_rx_sa_clear_stats(struct phy_device *phydev,
+ struct nxp_c45_sa *sa)
+{
+ nxp_c45_macsec_write(phydev, sa->regs->ipis, 0);
+ nxp_c45_macsec_write(phydev, sa->regs->ipnvs, 0);
+ nxp_c45_macsec_write(phydev, sa->regs->ipos, 0);
+
+ nxp_c45_macsec_write(phydev, MACSEC_RXAN0INUSS + sa->an * 4, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_RXAN0IPUSS + sa->an * 4, 0);
+}
+
+static void nxp_c45_rx_sa_read_stats(struct phy_device *phydev,
+ struct nxp_c45_sa *sa,
+ struct macsec_rx_sa_stats *stats)
+{
+ nxp_c45_macsec_read(phydev, sa->regs->ipis, &stats->InPktsInvalid);
+ nxp_c45_macsec_read(phydev, sa->regs->ipnvs, &stats->InPktsNotValid);
+ nxp_c45_macsec_read(phydev, sa->regs->ipos, &stats->InPktsOK);
+}
+
+static void nxp_c45_tx_sa_clear_stats(struct phy_device *phydev,
+ struct nxp_c45_sa *sa)
+{
+ nxp_c45_macsec_write(phydev, sa->regs->opps, 0);
+ nxp_c45_macsec_write(phydev, sa->regs->opes, 0);
+}
+
+static void nxp_c45_tx_sa_read_stats(struct phy_device *phydev,
+ struct nxp_c45_sa *sa,
+ struct macsec_tx_sa_stats *stats)
+{
+ nxp_c45_macsec_read(phydev, sa->regs->opps, &stats->OutPktsProtected);
+ nxp_c45_macsec_read(phydev, sa->regs->opes, &stats->OutPktsEncrypted);
+}
+
+static void nxp_c45_rx_sa_update(struct phy_device *phydev,
+ struct nxp_c45_sa *sa, bool en)
+{
+ const struct nxp_c45_sa_regs *sa_regs = sa->regs;
+ u32 cfg;
+
+ cfg = sa->an << MACSEC_RXSA_CS_AN_OFF;
+ cfg |= en ? MACSEC_RXSA_CS_EN : 0;
+ nxp_c45_macsec_write(phydev, sa_regs->cs, cfg);
+}
+
+static void nxp_c45_tx_sa_update(struct phy_device *phydev,
+ struct nxp_c45_sa *sa, bool en)
+{
+ u32 cfg = 0;
+
+ nxp_c45_macsec_read(phydev, MACSEC_TXSC_CFG, &cfg);
+
+ cfg &= ~MACSEC_TXSC_CFG_AN_MASK;
+ cfg |= sa->an << MACSEC_TXSC_CFG_AN_OFF;
+
+ if (sa->is_key_a)
+ cfg &= ~MACSEC_TXSC_CFG_ASA;
+ else
+ cfg |= MACSEC_TXSC_CFG_ASA;
+
+ if (en)
+ cfg |= MACSEC_TXSC_CFG_SCE;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_SCE;
+
+ nxp_c45_macsec_write(phydev, MACSEC_TXSC_CFG, cfg);
+}
+
+static void nxp_c45_set_sci(struct phy_device *phydev, u16 sci_base_addr,
+ sci_t sci)
+{
+ u64 lsci = sci_to_cpu(sci);
+
+ nxp_c45_macsec_write(phydev, sci_base_addr, lsci >> 32);
+ nxp_c45_macsec_write(phydev, sci_base_addr + 4, lsci);
+}
+
+static bool nxp_c45_port_is_1(sci_t sci)
+{
+ u16 port = sci_to_cpu(sci);
+
+ return port == 1;
+}
+
+static void nxp_c45_select_secy(struct phy_device *phydev, u8 id)
+{
+ nxp_c45_macsec_write(phydev, MACSEC_RXSCA, id);
+ nxp_c45_macsec_write(phydev, MACSEC_RXSCKA, id);
+ nxp_c45_macsec_write(phydev, MACSEC_TXSCA, id);
+ nxp_c45_macsec_write(phydev, MACSEC_TXSCKA, id);
+}
+
+static bool nxp_c45_secy_valid(struct nxp_c45_secy *phy_secy,
+ bool can_rx_sc0_impl)
+{
+ bool end_station = phy_secy->secy->tx_sc.end_station;
+ bool scb = phy_secy->secy->tx_sc.scb;
+
+ phy_secy->rx_sc0_impl = false;
+
+ if (end_station) {
+ if (!nxp_c45_port_is_1(phy_secy->secy->sci))
+ return false;
+ if (!phy_secy->rx_sc)
+ return true;
+ return nxp_c45_port_is_1(phy_secy->rx_sc->sci);
+ }
+
+ if (scb)
+ return false;
+
+ if (!can_rx_sc0_impl)
+ return false;
+
+ if (phy_secy->secy_id != 0)
+ return false;
+
+ phy_secy->rx_sc0_impl = true;
+
+ return true;
+}
+
+static bool nxp_c45_rx_sc0_impl(struct nxp_c45_secy *phy_secy)
+{
+ bool end_station = phy_secy->secy->tx_sc.end_station;
+ bool send_sci = phy_secy->secy->tx_sc.send_sci;
+ bool scb = phy_secy->secy->tx_sc.scb;
+
+ return !end_station && !send_sci && !scb;
+}
+
+static bool nxp_c45_mac_addr_free(struct macsec_context *ctx)
+{
+ struct nxp_c45_phy *priv = ctx->phydev->priv;
+ struct nxp_c45_secy *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, &priv->macsec->secy_list, list) {
+ if (pos->secy == ctx->secy)
+ continue;
+
+ if (memcmp(pos->secy->netdev->dev_addr,
+ ctx->secy->netdev->dev_addr, ETH_ALEN) == 0)
+ return false;
+ }
+
+ return true;
+}
+
+static void nxp_c45_tx_sc_en_flt(struct phy_device *phydev, int secy_id,
+ bool en)
+{
+ u32 tx_flt_base = TX_FLT_BASE(secy_id);
+ u32 reg = 0;
+
+ nxp_c45_macsec_read(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), &reg);
+ if (en)
+ reg |= TX_SC_FLT_EN;
+ else
+ reg &= ~TX_SC_FLT_EN;
+ nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), reg);
+}
+
+static void nxp_c45_tx_sc_set_flt(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy)
+{
+ const u8 *dev_addr = phy_secy->secy->netdev->dev_addr;
+ u32 tx_flt_base = TX_FLT_BASE(phy_secy->secy_id);
+ u32 reg;
+
+ reg = dev_addr[0] << 8 | dev_addr[1];
+ nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_DA_SA(tx_flt_base), reg);
+ reg = dev_addr[5] | dev_addr[4] << 8 | dev_addr[3] << 16 |
+ dev_addr[2] << 24;
+
+ nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_SA(tx_flt_base), reg);
+ nxp_c45_macsec_read(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), &reg);
+ reg &= TX_SC_FLT_EN;
+ reg |= TX_SC_FLT_BY_SA | phy_secy->secy_id;
+ nxp_c45_macsec_write(phydev, TX_SC_FLT_MAC_CFG(tx_flt_base), reg);
+}
+
+static void nxp_c45_tx_sc_update(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy)
+{
+ u32 cfg = 0;
+
+ nxp_c45_macsec_read(phydev, MACSEC_TXSC_CFG, &cfg);
+
+ phydev_dbg(phydev, "XPN %s\n", phy_secy->secy->xpn ? "on" : "off");
+ if (phy_secy->secy->xpn)
+ cfg |= MACSEC_TXSC_CFG_XPN;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_XPN;
+
+ phydev_dbg(phydev, "key len %u\n", phy_secy->secy->key_len);
+ if (phy_secy->secy->key_len == 32)
+ cfg |= MACSEC_TXSC_CFG_AES_256;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_AES_256;
+
+ phydev_dbg(phydev, "encryption %s\n",
+ phy_secy->secy->tx_sc.encrypt ? "on" : "off");
+ if (phy_secy->secy->tx_sc.encrypt)
+ cfg |= MACSEC_TXSC_CFG_ENCRYPT;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_ENCRYPT;
+
+ phydev_dbg(phydev, "protect frames %s\n",
+ phy_secy->secy->protect_frames ? "on" : "off");
+ if (phy_secy->secy->protect_frames)
+ cfg |= MACSEC_TXSC_CFG_PROTECT;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_PROTECT;
+
+ phydev_dbg(phydev, "send sci %s\n",
+ phy_secy->secy->tx_sc.send_sci ? "on" : "off");
+ if (phy_secy->secy->tx_sc.send_sci)
+ cfg |= MACSEC_TXSC_CFG_SEND_SCI;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_SEND_SCI;
+
+ phydev_dbg(phydev, "end station %s\n",
+ phy_secy->secy->tx_sc.end_station ? "on" : "off");
+ if (phy_secy->secy->tx_sc.end_station)
+ cfg |= MACSEC_TXSC_CFG_END_STATION;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_END_STATION;
+
+ phydev_dbg(phydev, "scb %s\n",
+ phy_secy->secy->tx_sc.scb ? "on" : "off");
+ if (phy_secy->secy->tx_sc.scb)
+ cfg |= MACSEC_TXSC_CFG_SCB;
+ else
+ cfg &= ~MACSEC_TXSC_CFG_SCB;
+
+ nxp_c45_macsec_write(phydev, MACSEC_TXSC_CFG, cfg);
+}
+
+static void nxp_c45_tx_sc_clear_stats(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy)
+{
+ struct nxp_c45_sa *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list)
+ if (pos->type == TX_SA)
+ nxp_c45_tx_sa_clear_stats(phydev, pos);
+
+ nxp_c45_macsec_write(phydev, MACSEC_OPUS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_OPTLS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_OOP1HS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_OOP2HS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_OOE1HS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_OOE2HS, 0);
+}
+
+static void nxp_c45_set_rx_sc0_impl(struct phy_device *phydev,
+ bool enable)
+{
+ u32 reg = 0;
+
+ nxp_c45_macsec_read(phydev, MACSEC_CFG, &reg);
+ if (enable)
+ reg |= MACSEC_CFG_S0I;
+ else
+ reg &= ~MACSEC_CFG_S0I;
+ nxp_c45_macsec_write(phydev, MACSEC_CFG, reg);
+}
+
+static bool nxp_c45_is_rx_sc0_impl(struct list_head *secy_list)
+{
+ struct nxp_c45_secy *pos, *tmp;
+
+ list_for_each_entry_safe(pos, tmp, secy_list, list)
+ if (pos->rx_sc0_impl)
+ return pos->rx_sc0_impl;
+
+ return false;
+}
+
+static void nxp_c45_rx_sc_en(struct phy_device *phydev,
+ struct macsec_rx_sc *rx_sc, bool en)
+{
+ u32 reg = 0;
+
+ nxp_c45_macsec_read(phydev, MACSEC_RXSC_CFG, &reg);
+ if (rx_sc->active && en)
+ reg |= MACSEC_RXSC_CFG_SCI_EN;
+ else
+ reg &= ~MACSEC_RXSC_CFG_SCI_EN;
+ nxp_c45_macsec_write(phydev, MACSEC_RXSC_CFG, reg);
+}
+
+static void nxp_c45_rx_sc_update(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy)
+{
+ struct macsec_rx_sc *rx_sc = phy_secy->rx_sc;
+ struct nxp_c45_phy *priv = phydev->priv;
+ u32 cfg = 0;
+
+ nxp_c45_macsec_read(phydev, MACSEC_RXSC_CFG, &cfg);
+ cfg &= ~MACSEC_RXSC_CFG_VF_MASK;
+ cfg = phy_secy->secy->validate_frames << MACSEC_RXSC_CFG_VF_OFF;
+
+ phydev_dbg(phydev, "validate frames %u\n",
+ phy_secy->secy->validate_frames);
+ phydev_dbg(phydev, "replay_protect %s window %u\n",
+ phy_secy->secy->replay_protect ? "on" : "off",
+ phy_secy->secy->replay_window);
+ if (phy_secy->secy->replay_protect) {
+ cfg |= MACSEC_RXSC_CFG_RP;
+ nxp_c45_macsec_write(phydev, MACSEC_RPW,
+ phy_secy->secy->replay_window);
+ } else {
+ cfg &= ~MACSEC_RXSC_CFG_RP;
+ }
+
+ phydev_dbg(phydev, "rx_sc->active %s\n",
+ rx_sc->active ? "on" : "off");
+ if (rx_sc->active &&
+ test_bit(phy_secy->secy_id, priv->macsec->secy_bitmap))
+ cfg |= MACSEC_RXSC_CFG_SCI_EN;
+ else
+ cfg &= ~MACSEC_RXSC_CFG_SCI_EN;
+
+ phydev_dbg(phydev, "key len %u\n", phy_secy->secy->key_len);
+ if (phy_secy->secy->key_len == 32)
+ cfg |= MACSEC_RXSC_CFG_AES_256;
+ else
+ cfg &= ~MACSEC_RXSC_CFG_AES_256;
+
+ phydev_dbg(phydev, "XPN %s\n", phy_secy->secy->xpn ? "on" : "off");
+ if (phy_secy->secy->xpn)
+ cfg |= MACSEC_RXSC_CFG_XPN;
+ else
+ cfg &= ~MACSEC_RXSC_CFG_XPN;
+
+ nxp_c45_macsec_write(phydev, MACSEC_RXSC_CFG, cfg);
+}
+
+static void nxp_c45_rx_sc_clear_stats(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy)
+{
+ struct nxp_c45_sa *pos, *tmp;
+ int i;
+
+ list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list)
+ if (pos->type == RX_SA)
+ nxp_c45_rx_sa_clear_stats(phydev, pos);
+
+ nxp_c45_macsec_write(phydev, MACSEC_INOD1HS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_INOD2HS, 0);
+
+ nxp_c45_macsec_write(phydev, MACSEC_INOV1HS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_INOV2HS, 0);
+
+ nxp_c45_macsec_write(phydev, MACSEC_RXSCIPDS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_RXSCIPLS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_RXSCIPUS, 0);
+
+ for (i = 0; i < MACSEC_NUM_AN; i++) {
+ nxp_c45_macsec_write(phydev, MACSEC_RXAN0INUSS + i * 4, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_RXAN0IPUSS + i * 4, 0);
+ }
+}
+
+static void nxp_c45_rx_sc_del(struct phy_device *phydev,
+ struct nxp_c45_secy *phy_secy)
+{
+ struct nxp_c45_sa *pos, *tmp;
+
+ nxp_c45_macsec_write(phydev, MACSEC_RXSC_CFG, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_RPW, 0);
+ nxp_c45_set_sci(phydev, MACSEC_RXSC_SCI_1H, 0);
+
+ nxp_c45_rx_sc_clear_stats(phydev, phy_secy);
+
+ list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list) {
+ if (pos->type == RX_SA) {
+ nxp_c45_rx_sa_update(phydev, pos, false);
+ nxp_c45_sa_free(pos);
+ }
+ }
+}
+
+static void nxp_c45_clear_global_stats(struct phy_device *phydev)
+{
+ nxp_c45_macsec_write(phydev, MACSEC_INPBTS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_INPWTS, 0);
+ nxp_c45_macsec_write(phydev, MACSEC_IPSNFS, 0);
+}
+
+static void nxp_c45_macsec_en(struct phy_device *phydev, bool en)
+{
+ u32 reg;
+
+ nxp_c45_macsec_read(phydev, MACSEC_CFG, &reg);
+ if (en)
+ reg |= MACSEC_CFG_BYPASS;
+ else
+ reg &= ~MACSEC_CFG_BYPASS;
+ nxp_c45_macsec_write(phydev, MACSEC_CFG, reg);
+}
+
+static int nxp_c45_mdo_dev_open(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ int any_bit_set;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ nxp_c45_tx_sc_en_flt(phydev, phy_secy->secy_id, true);
+ nxp_c45_set_rx_sc0_impl(phydev, phy_secy->rx_sc0_impl);
+ if (phy_secy->rx_sc)
+ nxp_c45_rx_sc_en(phydev, phy_secy->rx_sc, true);
+
+ any_bit_set = find_first_bit(priv->macsec->secy_bitmap, TX_SC_MAX);
+ if (any_bit_set == TX_SC_MAX)
+ nxp_c45_macsec_en(phydev, true);
+
+ set_bit(phy_secy->secy_id, priv->macsec->secy_bitmap);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_dev_stop(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ int any_bit_set;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ nxp_c45_tx_sc_en_flt(phydev, phy_secy->secy_id, false);
+ if (phy_secy->rx_sc)
+ nxp_c45_rx_sc_en(phydev, phy_secy->rx_sc, false);
+ nxp_c45_set_rx_sc0_impl(phydev, false);
+
+ clear_bit(phy_secy->secy_id, priv->macsec->secy_bitmap);
+ any_bit_set = find_first_bit(priv->macsec->secy_bitmap, TX_SC_MAX);
+ if (any_bit_set == TX_SC_MAX)
+ nxp_c45_macsec_en(phydev, false);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_add_secy(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ bool can_rx_sc0_impl;
+ int idx;
+
+ phydev_dbg(phydev, "add SecY SCI %016llx\n",
+ sci_to_cpu(ctx->secy->sci));
+
+ if (!nxp_c45_mac_addr_free(ctx))
+ return -EBUSY;
+
+ if (nxp_c45_is_rx_sc0_impl(&priv->macsec->secy_list))
+ return -EBUSY;
+
+ idx = find_first_zero_bit(priv->macsec->tx_sc_bitmap, TX_SC_MAX);
+ if (idx == TX_SC_MAX)
+ return -ENOSPC;
+
+ phy_secy = kzalloc(sizeof(*phy_secy), GFP_KERNEL);
+ if (!phy_secy)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&phy_secy->sa_list);
+ phy_secy->secy = ctx->secy;
+ phy_secy->secy_id = idx;
+
+ /* If the point to point mode should be enabled, we should have no
+ * SecY added yet.
+ */
+ can_rx_sc0_impl = list_count_nodes(&priv->macsec->secy_list) == 0;
+ if (!nxp_c45_secy_valid(phy_secy, can_rx_sc0_impl)) {
+ kfree(phy_secy);
+ return -EINVAL;
+ }
+
+ phy_secy->rx_sc0_impl = nxp_c45_rx_sc0_impl(phy_secy);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_set_sci(phydev, MACSEC_TXSC_SCI_1H, ctx->secy->sci);
+ nxp_c45_tx_sc_set_flt(phydev, phy_secy);
+ nxp_c45_tx_sc_update(phydev, phy_secy);
+ if (phy_interrupt_is_valid(phydev))
+ nxp_c45_secy_irq_en(phydev, phy_secy, true);
+
+ set_bit(idx, priv->macsec->tx_sc_bitmap);
+ list_add_tail(&phy_secy->list, &priv->macsec->secy_list);
+
+ return 0;
+}
+
+static void nxp_c45_tx_sa_next(struct nxp_c45_secy *phy_secy,
+ struct nxp_c45_sa *next_sa, u8 encoding_sa)
+{
+ struct nxp_c45_sa *sa;
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, encoding_sa);
+ if (!IS_ERR(sa)) {
+ memcpy(next_sa, sa, sizeof(*sa));
+ } else {
+ next_sa->is_key_a = true;
+ next_sa->an = encoding_sa;
+ }
+}
+
+static int nxp_c45_mdo_upd_secy(struct macsec_context *ctx)
+{
+ u8 encoding_sa = ctx->secy->tx_sc.encoding_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ struct nxp_c45_sa next_sa;
+ bool can_rx_sc0_impl;
+
+ phydev_dbg(phydev, "update SecY SCI %016llx\n",
+ sci_to_cpu(ctx->secy->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ if (!nxp_c45_mac_addr_free(ctx))
+ return -EBUSY;
+
+ /* If the point to point mode should be enabled, we should have only
+ * one SecY added, respectively the updated one.
+ */
+ can_rx_sc0_impl = list_count_nodes(&priv->macsec->secy_list) == 1;
+ if (!nxp_c45_secy_valid(phy_secy, can_rx_sc0_impl))
+ return -EINVAL;
+ phy_secy->rx_sc0_impl = nxp_c45_rx_sc0_impl(phy_secy);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_tx_sc_set_flt(phydev, phy_secy);
+ nxp_c45_tx_sc_update(phydev, phy_secy);
+ nxp_c45_tx_sa_next(phy_secy, &next_sa, encoding_sa);
+ nxp_c45_tx_sa_update(phydev, &next_sa, ctx->secy->operational);
+
+ nxp_c45_set_rx_sc0_impl(phydev, phy_secy->rx_sc0_impl);
+ if (phy_secy->rx_sc)
+ nxp_c45_rx_sc_update(phydev, phy_secy);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_del_secy(struct macsec_context *ctx)
+{
+ u8 encoding_sa = ctx->secy->tx_sc.encoding_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ struct nxp_c45_sa next_sa;
+
+ phydev_dbg(phydev, "delete SecY SCI %016llx\n",
+ sci_to_cpu(ctx->secy->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ nxp_c45_mdo_dev_stop(ctx);
+ nxp_c45_tx_sa_next(phy_secy, &next_sa, encoding_sa);
+ nxp_c45_tx_sa_update(phydev, &next_sa, false);
+ nxp_c45_tx_sc_clear_stats(phydev, phy_secy);
+ if (phy_secy->rx_sc)
+ nxp_c45_rx_sc_del(phydev, phy_secy);
+
+ nxp_c45_sa_list_free(&phy_secy->sa_list);
+ if (phy_interrupt_is_valid(phydev))
+ nxp_c45_secy_irq_en(phydev, phy_secy, false);
+
+ clear_bit(phy_secy->secy_id, priv->macsec->tx_sc_bitmap);
+ nxp_c45_secy_free(phy_secy);
+
+ if (list_empty(&priv->macsec->secy_list))
+ nxp_c45_clear_global_stats(phydev);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_add_rxsc(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+
+ phydev_dbg(phydev, "add RX SC SCI %016llx %s\n",
+ sci_to_cpu(ctx->rx_sc->sci),
+ ctx->rx_sc->active ? "enabled" : "disabled");
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ if (phy_secy->rx_sc)
+ return -ENOSPC;
+
+ if (phy_secy->secy->tx_sc.end_station &&
+ !nxp_c45_port_is_1(ctx->rx_sc->sci))
+ return -EINVAL;
+
+ phy_secy->rx_sc = ctx->rx_sc;
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_set_sci(phydev, MACSEC_RXSC_SCI_1H, ctx->rx_sc->sci);
+ nxp_c45_rx_sc_update(phydev, phy_secy);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_upd_rxsc(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+
+ phydev_dbg(phydev, "update RX SC SCI %016llx %s\n",
+ sci_to_cpu(ctx->rx_sc->sci),
+ ctx->rx_sc->active ? "enabled" : "disabled");
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_rx_sc_update(phydev, phy_secy);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_del_rxsc(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+
+ phydev_dbg(phydev, "delete RX SC SCI %016llx %s\n",
+ sci_to_cpu(ctx->rx_sc->sci),
+ ctx->rx_sc->active ? "enabled" : "disabled");
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_rx_sc_del(phydev, phy_secy);
+ phy_secy->rx_sc = NULL;
+
+ return 0;
+}
+
+static int nxp_c45_mdo_add_rxsa(struct macsec_context *ctx)
+{
+ struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phydev_dbg(phydev, "add RX SA %u %s to RX SC SCI %016llx\n",
+ an, rx_sa->active ? "enabled" : "disabled",
+ sci_to_cpu(rx_sa->sc->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_sa_alloc(&phy_secy->sa_list, rx_sa, RX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_sa_set_pn(phydev, sa, rx_sa->next_pn,
+ ctx->secy->replay_window);
+ nxp_c45_sa_set_key(ctx, sa->regs, rx_sa->key.salt.bytes, rx_sa->ssci);
+ nxp_c45_rx_sa_update(phydev, sa, rx_sa->active);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_upd_rxsa(struct macsec_context *ctx)
+{
+ struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phydev_dbg(phydev, "update RX SA %u %s to RX SC SCI %016llx\n",
+ an, rx_sa->active ? "enabled" : "disabled",
+ sci_to_cpu(rx_sa->sc->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, RX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ if (ctx->sa.update_pn)
+ nxp_c45_sa_set_pn(phydev, sa, rx_sa->next_pn,
+ ctx->secy->replay_window);
+ nxp_c45_rx_sa_update(phydev, sa, rx_sa->active);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_del_rxsa(struct macsec_context *ctx)
+{
+ struct macsec_rx_sa *rx_sa = ctx->sa.rx_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phydev_dbg(phydev, "delete RX SA %u %s to RX SC SCI %016llx\n",
+ an, rx_sa->active ? "enabled" : "disabled",
+ sci_to_cpu(rx_sa->sc->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, RX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_rx_sa_update(phydev, sa, false);
+ nxp_c45_rx_sa_clear_stats(phydev, sa);
+
+ nxp_c45_sa_free(sa);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_add_txsa(struct macsec_context *ctx)
+{
+ struct macsec_tx_sa *tx_sa = ctx->sa.tx_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phydev_dbg(phydev, "add TX SA %u %s to TX SC %016llx\n",
+ an, ctx->sa.tx_sa->active ? "enabled" : "disabled",
+ sci_to_cpu(ctx->secy->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_sa_alloc(&phy_secy->sa_list, tx_sa, TX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_sa_set_pn(phydev, sa, tx_sa->next_pn, 0);
+ nxp_c45_sa_set_key(ctx, sa->regs, tx_sa->key.salt.bytes, tx_sa->ssci);
+ if (ctx->secy->tx_sc.encoding_sa == sa->an)
+ nxp_c45_tx_sa_update(phydev, sa, tx_sa->active);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_upd_txsa(struct macsec_context *ctx)
+{
+ struct macsec_tx_sa *tx_sa = ctx->sa.tx_sa;
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phydev_dbg(phydev, "update TX SA %u %s to TX SC %016llx\n",
+ an, ctx->sa.tx_sa->active ? "enabled" : "disabled",
+ sci_to_cpu(ctx->secy->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ if (ctx->sa.update_pn)
+ nxp_c45_sa_set_pn(phydev, sa, tx_sa->next_pn, 0);
+ if (ctx->secy->tx_sc.encoding_sa == sa->an)
+ nxp_c45_tx_sa_update(phydev, sa, tx_sa->active);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_del_txsa(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phydev_dbg(phydev, "delete TX SA %u %s to TX SC %016llx\n",
+ an, ctx->sa.tx_sa->active ? "enabled" : "disabled",
+ sci_to_cpu(ctx->secy->sci));
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ if (ctx->secy->tx_sc.encoding_sa == sa->an)
+ nxp_c45_tx_sa_update(phydev, sa, false);
+ nxp_c45_tx_sa_clear_stats(phydev, sa);
+
+ nxp_c45_sa_free(sa);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_get_dev_stats(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct macsec_dev_stats *dev_stats;
+ struct nxp_c45_secy *phy_secy;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ dev_stats = ctx->stats.dev_stats;
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ nxp_c45_macsec_read32_64(phydev, MACSEC_OPUS,
+ &dev_stats->OutPktsUntagged);
+ nxp_c45_macsec_read32_64(phydev, MACSEC_OPTLS,
+ &dev_stats->OutPktsTooLong);
+ nxp_c45_macsec_read32_64(phydev, MACSEC_INPBTS,
+ &dev_stats->InPktsBadTag);
+
+ if (phy_secy->secy->validate_frames == MACSEC_VALIDATE_STRICT)
+ nxp_c45_macsec_read32_64(phydev, MACSEC_INPWTS,
+ &dev_stats->InPktsNoTag);
+ else
+ nxp_c45_macsec_read32_64(phydev, MACSEC_INPWTS,
+ &dev_stats->InPktsUntagged);
+
+ if (phy_secy->secy->validate_frames == MACSEC_VALIDATE_STRICT)
+ nxp_c45_macsec_read32_64(phydev, MACSEC_IPSNFS,
+ &dev_stats->InPktsNoSCI);
+ else
+ nxp_c45_macsec_read32_64(phydev, MACSEC_IPSNFS,
+ &dev_stats->InPktsUnknownSCI);
+
+ /* Always 0. */
+ dev_stats->InPktsOverrun = 0;
+
+ return 0;
+}
+
+static int nxp_c45_mdo_get_tx_sc_stats(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct macsec_tx_sa_stats tx_sa_stats;
+ struct macsec_tx_sc_stats *stats;
+ struct nxp_c45_secy *phy_secy;
+ struct nxp_c45_sa *pos, *tmp;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ stats = ctx->stats.tx_sc_stats;
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ nxp_c45_macsec_read64(phydev, MACSEC_OOE1HS,
+ &stats->OutOctetsEncrypted);
+ nxp_c45_macsec_read64(phydev, MACSEC_OOP1HS,
+ &stats->OutOctetsProtected);
+ list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list) {
+ if (pos->type != TX_SA)
+ continue;
+
+ memset(&tx_sa_stats, 0, sizeof(tx_sa_stats));
+ nxp_c45_tx_sa_read_stats(phydev, pos, &tx_sa_stats);
+
+ stats->OutPktsEncrypted += tx_sa_stats.OutPktsEncrypted;
+ stats->OutPktsProtected += tx_sa_stats.OutPktsProtected;
+ }
+
+ return 0;
+}
+
+static int nxp_c45_mdo_get_tx_sa_stats(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct macsec_tx_sa_stats *stats;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, TX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ stats = ctx->stats.tx_sa_stats;
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+ nxp_c45_tx_sa_read_stats(phydev, sa, stats);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_get_rx_sc_stats(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct macsec_rx_sa_stats rx_sa_stats;
+ struct macsec_rx_sc_stats *stats;
+ struct nxp_c45_secy *phy_secy;
+ struct nxp_c45_sa *pos, *tmp;
+ u32 reg = 0;
+ int i;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ if (phy_secy->rx_sc != ctx->rx_sc)
+ return -EINVAL;
+
+ stats = ctx->stats.rx_sc_stats;
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ list_for_each_entry_safe(pos, tmp, &phy_secy->sa_list, list) {
+ if (pos->type != RX_SA)
+ continue;
+
+ memset(&rx_sa_stats, 0, sizeof(rx_sa_stats));
+ nxp_c45_rx_sa_read_stats(phydev, pos, &rx_sa_stats);
+
+ stats->InPktsInvalid += rx_sa_stats.InPktsInvalid;
+ stats->InPktsNotValid += rx_sa_stats.InPktsNotValid;
+ stats->InPktsOK += rx_sa_stats.InPktsOK;
+ }
+
+ for (i = 0; i < MACSEC_NUM_AN; i++) {
+ nxp_c45_macsec_read(phydev, MACSEC_RXAN0INUSS + i * 4, &reg);
+ stats->InPktsNotUsingSA += reg;
+ nxp_c45_macsec_read(phydev, MACSEC_RXAN0IPUSS + i * 4, &reg);
+ stats->InPktsUnusedSA += reg;
+ }
+
+ nxp_c45_macsec_read64(phydev, MACSEC_INOD1HS,
+ &stats->InOctetsDecrypted);
+ nxp_c45_macsec_read64(phydev, MACSEC_INOV1HS,
+ &stats->InOctetsValidated);
+
+ nxp_c45_macsec_read32_64(phydev, MACSEC_RXSCIPDS,
+ &stats->InPktsDelayed);
+ nxp_c45_macsec_read32_64(phydev, MACSEC_RXSCIPLS,
+ &stats->InPktsLate);
+ nxp_c45_macsec_read32_64(phydev, MACSEC_RXSCIPUS,
+ &stats->InPktsUnchecked);
+
+ return 0;
+}
+
+static int nxp_c45_mdo_get_rx_sa_stats(struct macsec_context *ctx)
+{
+ struct phy_device *phydev = ctx->phydev;
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct macsec_rx_sa_stats *stats;
+ struct nxp_c45_secy *phy_secy;
+ u8 an = ctx->sa.assoc_num;
+ struct nxp_c45_sa *sa;
+
+ phy_secy = nxp_c45_find_secy(&priv->macsec->secy_list, ctx->secy->sci);
+ if (IS_ERR(phy_secy))
+ return PTR_ERR(phy_secy);
+
+ sa = nxp_c45_find_sa(&phy_secy->sa_list, RX_SA, an);
+ if (IS_ERR(sa))
+ return PTR_ERR(sa);
+
+ stats = ctx->stats.rx_sa_stats;
+ nxp_c45_select_secy(phydev, phy_secy->secy_id);
+
+ nxp_c45_rx_sa_read_stats(phydev, sa, stats);
+ nxp_c45_macsec_read(phydev, MACSEC_RXAN0INUSS + an * 4,
+ &stats->InPktsNotUsingSA);
+ nxp_c45_macsec_read(phydev, MACSEC_RXAN0IPUSS + an * 4,
+ &stats->InPktsUnusedSA);
+
+ return 0;
+}
+
+struct tja11xx_tlv_header {
+ struct ethhdr eth;
+ u8 subtype;
+ u8 len;
+ u8 payload[28];
+};
+
+static int nxp_c45_mdo_insert_tx_tag(struct phy_device *phydev,
+ struct sk_buff *skb)
+{
+ struct tja11xx_tlv_header *tlv;
+ struct ethhdr *eth;
+
+ eth = eth_hdr(skb);
+ tlv = skb_push(skb, TJA11XX_TLV_TX_NEEDED_HEADROOM);
+ memmove(tlv, eth, sizeof(*eth));
+ skb_reset_mac_header(skb);
+ tlv->eth.h_proto = htons(ETH_P_TJA11XX_TLV);
+ tlv->subtype = 1;
+ tlv->len = sizeof(tlv->payload);
+ memset(tlv->payload, 0, sizeof(tlv->payload));
+
+ return 0;
+}
+
+static const struct macsec_ops nxp_c45_macsec_ops = {
+ .mdo_dev_open = nxp_c45_mdo_dev_open,
+ .mdo_dev_stop = nxp_c45_mdo_dev_stop,
+ .mdo_add_secy = nxp_c45_mdo_add_secy,
+ .mdo_upd_secy = nxp_c45_mdo_upd_secy,
+ .mdo_del_secy = nxp_c45_mdo_del_secy,
+ .mdo_add_rxsc = nxp_c45_mdo_add_rxsc,
+ .mdo_upd_rxsc = nxp_c45_mdo_upd_rxsc,
+ .mdo_del_rxsc = nxp_c45_mdo_del_rxsc,
+ .mdo_add_rxsa = nxp_c45_mdo_add_rxsa,
+ .mdo_upd_rxsa = nxp_c45_mdo_upd_rxsa,
+ .mdo_del_rxsa = nxp_c45_mdo_del_rxsa,
+ .mdo_add_txsa = nxp_c45_mdo_add_txsa,
+ .mdo_upd_txsa = nxp_c45_mdo_upd_txsa,
+ .mdo_del_txsa = nxp_c45_mdo_del_txsa,
+ .mdo_get_dev_stats = nxp_c45_mdo_get_dev_stats,
+ .mdo_get_tx_sc_stats = nxp_c45_mdo_get_tx_sc_stats,
+ .mdo_get_tx_sa_stats = nxp_c45_mdo_get_tx_sa_stats,
+ .mdo_get_rx_sc_stats = nxp_c45_mdo_get_rx_sc_stats,
+ .mdo_get_rx_sa_stats = nxp_c45_mdo_get_rx_sa_stats,
+ .mdo_insert_tx_tag = nxp_c45_mdo_insert_tx_tag,
+ .needed_headroom = TJA11XX_TLV_TX_NEEDED_HEADROOM,
+ .needed_tailroom = TJA11XX_TLV_NEEDED_TAILROOM,
+};
+
+int nxp_c45_macsec_config_init(struct phy_device *phydev)
+{
+ struct nxp_c45_phy *priv = phydev->priv;
+ int ret;
+
+ if (!priv->macsec)
+ return 0;
+
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES,
+ MACSEC_EN | ADAPTER_EN);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, ADPTR_CNTRL, ADPTR_CNTRL_CONFIG_EN |
+ ADPTR_CNTRL_ADPTR_EN);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, ADPTR_TX_TAG_CNTRL,
+ ADPTR_TX_TAG_CNTRL_ENA);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, ADPTR_CNTRL, ADPTR_CNTRL_ADPTR_EN);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, MACSEC_TPNET, PN_WRAP_THRESHOLD);
+ if (ret)
+ return ret;
+
+ /* Set MKA filter. */
+ ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0D2, ETH_P_PAE);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0M1, MACSEC_OVP);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0M2, ETYPE_MASK);
+ if (ret)
+ return ret;
+
+ ret = nxp_c45_macsec_write(phydev, MACSEC_UPFR0R, MACSEC_UPFR_EN);
+
+ return ret;
+}
+
+int nxp_c45_macsec_probe(struct phy_device *phydev)
+{
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct device *dev = &phydev->mdio.dev;
+
+ priv->macsec = devm_kzalloc(dev, sizeof(*priv->macsec), GFP_KERNEL);
+ if (!priv->macsec)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&priv->macsec->secy_list);
+ phydev->macsec_ops = &nxp_c45_macsec_ops;
+
+ return 0;
+}
+
+void nxp_c45_macsec_remove(struct phy_device *phydev)
+{
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *secy_p, *secy_t;
+ struct nxp_c45_sa *sa_p, *sa_t;
+ struct list_head *secy_list;
+
+ if (!priv->macsec)
+ return;
+
+ secy_list = &priv->macsec->secy_list;
+ nxp_c45_macsec_en(phydev, false);
+
+ list_for_each_entry_safe(secy_p, secy_t, secy_list, list) {
+ list_for_each_entry_safe(sa_p, sa_t, &secy_p->sa_list, list)
+ nxp_c45_sa_free(sa_p);
+ nxp_c45_secy_free(secy_p);
+ }
+}
+
+void nxp_c45_handle_macsec_interrupt(struct phy_device *phydev,
+ irqreturn_t *ret)
+{
+ struct nxp_c45_phy *priv = phydev->priv;
+ struct nxp_c45_secy *secy;
+ struct nxp_c45_sa *sa;
+ u8 encoding_sa;
+ int secy_id;
+ u32 reg = 0;
+
+ if (!priv->macsec)
+ return;
+
+ do {
+ nxp_c45_macsec_read(phydev, MACSEC_EVR, &reg);
+ if (!reg)
+ return;
+
+ secy_id = MACSEC_REG_SIZE - ffs(reg);
+ secy = nxp_c45_find_secy_by_id(&priv->macsec->secy_list,
+ secy_id);
+ if (IS_ERR(secy)) {
+ WARN_ON(1);
+ goto macsec_ack_irq;
+ }
+
+ encoding_sa = secy->secy->tx_sc.encoding_sa;
+ phydev_dbg(phydev, "pn_wrapped: TX SC %d, encoding_sa %u\n",
+ secy->secy_id, encoding_sa);
+
+ sa = nxp_c45_find_sa(&secy->sa_list, TX_SA, encoding_sa);
+ if (!IS_ERR(sa))
+ macsec_pn_wrapped(secy->secy, sa->sa);
+ else
+ WARN_ON(1);
+
+macsec_ack_irq:
+ nxp_c45_macsec_write(phydev, MACSEC_EVR,
+ TX_SC_BIT(secy_id));
+ *ret = IRQ_HANDLED;
+ } while (reg);
+}
diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c
index 7ab080ff02df..3cf614b4cd52 100644
--- a/drivers/net/phy/nxp-c45-tja11xx.c
+++ b/drivers/net/phy/nxp-c45-tja11xx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/* NXP C45 PHY driver
- * Copyright (C) 2021 NXP
+ * Copyright 2021-2023 NXP
* Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
*/
@@ -14,9 +14,10 @@
#include <linux/processor.h>
#include <linux/property.h>
#include <linux/ptp_classify.h>
-#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
+#include "nxp-c45-tja11xx.h"
+
#define PHY_ID_TJA_1103 0x001BB010
#define PHY_ID_TJA_1120 0x001BB031
@@ -75,9 +76,11 @@
#define PORT_CONTROL_EN BIT(14)
#define VEND1_PORT_ABILITIES 0x8046
+#define MACSEC_ABILITY BIT(5)
#define PTP_ABILITY BIT(3)
#define VEND1_PORT_FUNC_IRQ_EN 0x807A
+#define MACSEC_IRQS BIT(5)
#define PTP_IRQS BIT(3)
#define VEND1_PTP_IRQ_ACK 0x9008
@@ -148,7 +151,6 @@
#define TS_SEC_MASK GENMASK(1, 0)
-#define VEND1_PORT_FUNC_ENABLES 0x8048
#define PTP_ENABLE BIT(3)
#define PHY_TEST_ENABLE BIT(0)
@@ -281,25 +283,6 @@ struct nxp_c45_phy_data {
irqreturn_t *irq_status);
};
-struct nxp_c45_phy {
- const struct nxp_c45_phy_data *phy_data;
- struct phy_device *phydev;
- struct mii_timestamper mii_ts;
- struct ptp_clock *ptp_clock;
- struct ptp_clock_info caps;
- struct sk_buff_head tx_queue;
- struct sk_buff_head rx_queue;
- /* used to access the PTP registers atomic */
- struct mutex ptp_lock;
- int hwts_tx;
- int hwts_rx;
- u32 tx_delay;
- u32 rx_delay;
- struct timespec64 extts_ts;
- int extts_index;
- bool extts;
-};
-
static const
struct nxp_c45_phy_data *nxp_c45_get_data(struct phy_device *phydev)
{
@@ -1022,24 +1005,21 @@ static bool nxp_c45_rxtstamp(struct mii_timestamper *mii_ts,
}
static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
- struct ifreq *ifreq)
+ struct kernel_hwtstamp_config *cfg,
+ struct netlink_ext_ack *extack)
{
struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy,
mii_ts);
struct phy_device *phydev = priv->phydev;
const struct nxp_c45_phy_data *data;
- struct hwtstamp_config cfg;
-
- if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg)))
- return -EFAULT;
- if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON)
+ if (cfg->tx_type < 0 || cfg->tx_type > HWTSTAMP_TX_ON)
return -ERANGE;
data = nxp_c45_get_data(phydev);
- priv->hwts_tx = cfg.tx_type;
+ priv->hwts_tx = cfg->tx_type;
- switch (cfg.rx_filter) {
+ switch (cfg->rx_filter) {
case HWTSTAMP_FILTER_NONE:
priv->hwts_rx = 0;
break;
@@ -1047,7 +1027,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
priv->hwts_rx = 1;
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ cfg->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
break;
default:
return -ERANGE;
@@ -1074,7 +1054,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts,
nxp_c45_clear_reg_field(phydev, &data->regmap->irq_egr_ts_en);
nxp_c45_no_ptp_irq:
- return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+ return 0;
}
static int nxp_c45_ts_info(struct mii_timestamper *mii_ts,
@@ -1218,12 +1198,25 @@ static int nxp_c45_start_op(struct phy_device *phydev)
static int nxp_c45_config_intr(struct phy_device *phydev)
{
- if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ int ret;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_FUNC_IRQ_EN, MACSEC_IRQS);
+ if (ret)
+ return ret;
+
return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT);
- else
- return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT);
+ }
+
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_FUNC_IRQ_EN, MACSEC_IRQS);
+ if (ret)
+ return ret;
+
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PHY_IRQ_EN, PHY_IRQ_LINK_EVENT);
}
static int tja1103_config_intr(struct phy_device *phydev)
@@ -1289,6 +1282,7 @@ static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev)
}
data->nmi_handler(phydev, &ret);
+ nxp_c45_handle_macsec_interrupt(phydev, &ret);
return ret;
}
@@ -1614,6 +1608,9 @@ static int nxp_c45_config_init(struct phy_device *phydev)
nxp_c45_counters_enable(phydev);
nxp_c45_ptp_init(phydev);
+ ret = nxp_c45_macsec_config_init(phydev);
+ if (ret)
+ return ret;
return nxp_c45_start_op(phydev);
}
@@ -1629,7 +1626,9 @@ static int nxp_c45_get_features(struct phy_device *phydev)
static int nxp_c45_probe(struct phy_device *phydev)
{
struct nxp_c45_phy *priv;
- int ptp_ability;
+ bool macsec_ability;
+ int phy_abilities;
+ bool ptp_ability;
int ret = 0;
priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
@@ -1645,9 +1644,9 @@ static int nxp_c45_probe(struct phy_device *phydev)
mutex_init(&priv->ptp_lock);
- ptp_ability = phy_read_mmd(phydev, MDIO_MMD_VEND1,
- VEND1_PORT_ABILITIES);
- ptp_ability = !!(ptp_ability & PTP_ABILITY);
+ phy_abilities = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+ VEND1_PORT_ABILITIES);
+ ptp_ability = !!(phy_abilities & PTP_ABILITY);
if (!ptp_ability) {
phydev_dbg(phydev, "the phy does not support PTP");
goto no_ptp_support;
@@ -1666,6 +1665,20 @@ static int nxp_c45_probe(struct phy_device *phydev)
}
no_ptp_support:
+ macsec_ability = !!(phy_abilities & MACSEC_ABILITY);
+ if (!macsec_ability) {
+ phydev_info(phydev, "the phy does not support MACsec\n");
+ goto no_macsec_support;
+ }
+
+ if (IS_ENABLED(CONFIG_MACSEC)) {
+ ret = nxp_c45_macsec_probe(phydev);
+ phydev_dbg(phydev, "MACsec support enabled.");
+ } else {
+ phydev_dbg(phydev, "MACsec support not enabled even if the phy supports it");
+ }
+
+no_macsec_support:
return ret;
}
@@ -1679,6 +1692,7 @@ static void nxp_c45_remove(struct phy_device *phydev)
skb_queue_purge(&priv->tx_queue);
skb_queue_purge(&priv->rx_queue);
+ nxp_c45_macsec_remove(phydev);
}
static void tja1103_counters_enable(struct phy_device *phydev)
diff --git a/drivers/net/phy/nxp-c45-tja11xx.h b/drivers/net/phy/nxp-c45-tja11xx.h
new file mode 100644
index 000000000000..f364fca68f0b
--- /dev/null
+++ b/drivers/net/phy/nxp-c45-tja11xx.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* NXP C45 PHY driver header file
+ * Copyright 2023 NXP
+ * Author: Radu Pirea <radu-nicolae.pirea@oss.nxp.com>
+ */
+
+#include <linux/ptp_clock_kernel.h>
+
+#define VEND1_PORT_FUNC_ENABLES 0x8048
+
+struct nxp_c45_macsec;
+
+struct nxp_c45_phy {
+ const struct nxp_c45_phy_data *phy_data;
+ struct phy_device *phydev;
+ struct mii_timestamper mii_ts;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info caps;
+ struct sk_buff_head tx_queue;
+ struct sk_buff_head rx_queue;
+ /* used to access the PTP registers atomic */
+ struct mutex ptp_lock;
+ int hwts_tx;
+ int hwts_rx;
+ u32 tx_delay;
+ u32 rx_delay;
+ struct timespec64 extts_ts;
+ int extts_index;
+ bool extts;
+ struct nxp_c45_macsec *macsec;
+};
+
+#if IS_ENABLED(CONFIG_MACSEC)
+int nxp_c45_macsec_config_init(struct phy_device *phydev);
+int nxp_c45_macsec_probe(struct phy_device *phydev);
+void nxp_c45_macsec_remove(struct phy_device *phydev);
+void nxp_c45_handle_macsec_interrupt(struct phy_device *phydev,
+ irqreturn_t *ret);
+#else
+static inline
+int nxp_c45_macsec_config_init(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static inline
+int nxp_c45_macsec_probe(struct phy_device *phydev)
+{
+ return 0;
+}
+
+static inline
+void nxp_c45_macsec_remove(struct phy_device *phydev)
+{
+}
+
+static inline
+void nxp_c45_handle_macsec_interrupt(struct phy_device *phydev,
+ irqreturn_t *ret)
+{
+}
+#endif
diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c
index a71399965142..2c263ae44b4f 100644
--- a/drivers/net/phy/nxp-tja11xx.c
+++ b/drivers/net/phy/nxp-tja11xx.c
@@ -415,7 +415,7 @@ static void tja11xx_get_strings(struct phy_device *phydev, u8 *data)
int i;
for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++)
- ethtool_sprintf(&data, "%s", tja11xx_hw_stats[i].string);
+ ethtool_puts(&data, tja11xx_hw_stats[i].string);
}
static void tja11xx_get_stats(struct phy_device *phydev,
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 8e6fd4962c48..747d14bf152c 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -920,6 +920,79 @@ int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev)
EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities);
/**
+ * genphy_c45_pma_read_ext_abilities - read supported link modes from PMA
+ * @phydev: target phy_device struct
+ *
+ * Read the supported link modes from the PMA/PMD extended ability register
+ * (Register 1.11).
+ */
+int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev)
+{
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_10GBLRM);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_10GBT);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_10GBKX4);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_10GBKR);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_1000BT);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_1000BKX);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_100BTX);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_100BTX);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_10BT);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+ phydev->supported,
+ val & MDIO_PMA_EXTABLE_10BT);
+
+ if (val & MDIO_PMA_EXTABLE_NBT) {
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
+ MDIO_PMA_NG_EXTABLE);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_NG_EXTABLE_2_5GBT);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_NG_EXTABLE_5GBT);
+ }
+
+ if (val & MDIO_PMA_EXTABLE_BT1) {
+ val = genphy_c45_pma_baset1_read_abilities(phydev);
+ if (val < 0)
+ return val;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_pma_read_ext_abilities);
+
+/**
* genphy_c45_pma_read_abilities - read supported link modes from PMA
* @phydev: target phy_device struct
*
@@ -962,63 +1035,9 @@ int genphy_c45_pma_read_abilities(struct phy_device *phydev)
val & MDIO_PMA_STAT2_10GBER);
if (val & MDIO_PMA_STAT2_EXTABLE) {
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
+ val = genphy_c45_pma_read_ext_abilities(phydev);
if (val < 0)
return val;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBLRM);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBKX4);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10GBKR);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_1000BT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_1000BKX);
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_100BTX);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_100BTX);
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10BT);
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
- phydev->supported,
- val & MDIO_PMA_EXTABLE_10BT);
-
- if (val & MDIO_PMA_EXTABLE_NBT) {
- val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
- MDIO_PMA_NG_EXTABLE);
- if (val < 0)
- return val;
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_NG_EXTABLE_2_5GBT);
-
- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
- phydev->supported,
- val & MDIO_PMA_NG_EXTABLE_5GBT);
- }
-
- if (val & MDIO_PMA_EXTABLE_BT1) {
- val = genphy_c45_pma_baset1_read_abilities(phydev);
- if (val < 0)
- return val;
- }
}
/* This is optional functionality. If not supported, we may get an error
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 966c93cbe616..15f349e5995a 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -540,6 +540,28 @@ static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
devad | MII_MMD_CTRL_NOINCR);
}
+static int mmd_phy_read(struct mii_bus *bus, int phy_addr, bool is_c45,
+ int devad, u32 regnum)
+{
+ if (is_c45)
+ return __mdiobus_c45_read(bus, phy_addr, devad, regnum);
+
+ mmd_phy_indirect(bus, phy_addr, devad, regnum);
+ /* Read the content of the MMD's selected register */
+ return __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
+}
+
+static int mmd_phy_write(struct mii_bus *bus, int phy_addr, bool is_c45,
+ int devad, u32 regnum, u16 val)
+{
+ if (is_c45)
+ return __mdiobus_c45_write(bus, phy_addr, devad, regnum, val);
+
+ mmd_phy_indirect(bus, phy_addr, devad, regnum);
+ /* Write the data into MMD's selected register */
+ return __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
+}
+
/**
* __phy_read_mmd - Convenience function for reading a register
* from an MMD on a given PHY.
@@ -551,26 +573,14 @@ static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
*/
int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
{
- int val;
-
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
- if (phydev->drv && phydev->drv->read_mmd) {
- val = phydev->drv->read_mmd(phydev, devad, regnum);
- } else if (phydev->is_c45) {
- val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
- devad, regnum);
- } else {
- struct mii_bus *bus = phydev->mdio.bus;
- int phy_addr = phydev->mdio.addr;
-
- mmd_phy_indirect(bus, phy_addr, devad, regnum);
+ if (phydev->drv && phydev->drv->read_mmd)
+ return phydev->drv->read_mmd(phydev, devad, regnum);
- /* Read the content of the MMD's selected register */
- val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
- }
- return val;
+ return mmd_phy_read(phydev->mdio.bus, phydev->mdio.addr,
+ phydev->is_c45, devad, regnum);
}
EXPORT_SYMBOL(__phy_read_mmd);
@@ -607,28 +617,14 @@ EXPORT_SYMBOL(phy_read_mmd);
*/
int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
{
- int ret;
-
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
- if (phydev->drv && phydev->drv->write_mmd) {
- ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
- } else if (phydev->is_c45) {
- ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
- devad, regnum, val);
- } else {
- struct mii_bus *bus = phydev->mdio.bus;
- int phy_addr = phydev->mdio.addr;
-
- mmd_phy_indirect(bus, phy_addr, devad, regnum);
+ if (phydev->drv && phydev->drv->write_mmd)
+ return phydev->drv->write_mmd(phydev, devad, regnum, val);
- /* Write the data into MMD's selected register */
- __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
-
- ret = 0;
- }
- return ret;
+ return mmd_phy_write(phydev->mdio.bus, phydev->mdio.addr,
+ phydev->is_c45, devad, regnum, val);
}
EXPORT_SYMBOL(__phy_write_mmd);
@@ -655,6 +651,146 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
EXPORT_SYMBOL(phy_write_mmd);
/**
+ * __phy_package_read_mmd - read MMD reg relative to PHY package base addr
+ * @phydev: The phy_device struct
+ * @addr_offset: The offset to be added to PHY package base_addr
+ * @devad: The MMD to read from
+ * @regnum: The register on the MMD to read
+ *
+ * Convenience helper for reading a register of an MMD on a given PHY
+ * using the PHY package base address. The base address is added to
+ * the addr_offset value.
+ *
+ * Same calling rules as for __phy_read();
+ *
+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
+ */
+int __phy_package_read_mmd(struct phy_device *phydev,
+ unsigned int addr_offset, int devad,
+ u32 regnum)
+{
+ int addr = phy_package_address(phydev, addr_offset);
+
+ if (addr < 0)
+ return addr;
+
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+ return mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
+ regnum);
+}
+EXPORT_SYMBOL(__phy_package_read_mmd);
+
+/**
+ * phy_package_read_mmd - read MMD reg relative to PHY package base addr
+ * @phydev: The phy_device struct
+ * @addr_offset: The offset to be added to PHY package base_addr
+ * @devad: The MMD to read from
+ * @regnum: The register on the MMD to read
+ *
+ * Convenience helper for reading a register of an MMD on a given PHY
+ * using the PHY package base address. The base address is added to
+ * the addr_offset value.
+ *
+ * Same calling rules as for phy_read();
+ *
+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
+ */
+int phy_package_read_mmd(struct phy_device *phydev,
+ unsigned int addr_offset, int devad,
+ u32 regnum)
+{
+ int addr = phy_package_address(phydev, addr_offset);
+ int val;
+
+ if (addr < 0)
+ return addr;
+
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+ phy_lock_mdio_bus(phydev);
+ val = mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
+ regnum);
+ phy_unlock_mdio_bus(phydev);
+
+ return val;
+}
+EXPORT_SYMBOL(phy_package_read_mmd);
+
+/**
+ * __phy_package_write_mmd - write MMD reg relative to PHY package base addr
+ * @phydev: The phy_device struct
+ * @addr_offset: The offset to be added to PHY package base_addr
+ * @devad: The MMD to write to
+ * @regnum: The register on the MMD to write
+ * @val: value to write to @regnum
+ *
+ * Convenience helper for writing a register of an MMD on a given PHY
+ * using the PHY package base address. The base address is added to
+ * the addr_offset value.
+ *
+ * Same calling rules as for __phy_write();
+ *
+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
+ */
+int __phy_package_write_mmd(struct phy_device *phydev,
+ unsigned int addr_offset, int devad,
+ u32 regnum, u16 val)
+{
+ int addr = phy_package_address(phydev, addr_offset);
+
+ if (addr < 0)
+ return addr;
+
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+ return mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
+ regnum, val);
+}
+EXPORT_SYMBOL(__phy_package_write_mmd);
+
+/**
+ * phy_package_write_mmd - write MMD reg relative to PHY package base addr
+ * @phydev: The phy_device struct
+ * @addr_offset: The offset to be added to PHY package base_addr
+ * @devad: The MMD to write to
+ * @regnum: The register on the MMD to write
+ * @val: value to write to @regnum
+ *
+ * Convenience helper for writing a register of an MMD on a given PHY
+ * using the PHY package base address. The base address is added to
+ * the addr_offset value.
+ *
+ * Same calling rules as for phy_write();
+ *
+ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
+ */
+int phy_package_write_mmd(struct phy_device *phydev,
+ unsigned int addr_offset, int devad,
+ u32 regnum, u16 val)
+{
+ int addr = phy_package_address(phydev, addr_offset);
+ int ret;
+
+ if (addr < 0)
+ return addr;
+
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+ phy_lock_mdio_bus(phydev);
+ ret = mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
+ regnum, val);
+ phy_unlock_mdio_bus(phydev);
+
+ return ret;
+}
+EXPORT_SYMBOL(phy_package_write_mmd);
+
+/**
* phy_modify_changed - Function for modifying a PHY register
* @phydev: the phy_device struct
* @regnum: register number to modify
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index a5fa077650e8..3376e58e2b88 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -325,9 +325,13 @@ EXPORT_SYMBOL(phy_ethtool_ksettings_get);
int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *mii_data = if_mii(ifr);
+ struct kernel_hwtstamp_config kernel_cfg;
+ struct netlink_ext_ack extack = {};
u16 val = mii_data->val_in;
bool change_autoneg = false;
+ struct hwtstamp_config cfg;
int prtad, devad;
+ int ret;
switch (cmd) {
case SIOCGMIIPHY:
@@ -411,8 +415,21 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
return 0;
case SIOCSHWTSTAMP:
- if (phydev->mii_ts && phydev->mii_ts->hwtstamp)
- return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr);
+ if (phydev->mii_ts && phydev->mii_ts->hwtstamp) {
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ hwtstamp_config_to_kernel(&kernel_cfg, &cfg);
+ ret = phydev->mii_ts->hwtstamp(phydev->mii_ts, &kernel_cfg, &extack);
+ if (ret)
+ return ret;
+
+ hwtstamp_config_from_kernel(&cfg, &kernel_cfg);
+ if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)))
+ return -EFAULT;
+
+ return 0;
+ }
fallthrough;
default:
@@ -469,7 +486,7 @@ int __phy_hwtstamp_get(struct phy_device *phydev,
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, config->ifr, SIOCGHWTSTAMP);
+ return -EOPNOTSUPP;
}
/**
@@ -486,7 +503,10 @@ int __phy_hwtstamp_set(struct phy_device *phydev,
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, config->ifr, SIOCSHWTSTAMP);
+ if (phydev->mii_ts && phydev->mii_ts->hwtstamp)
+ return phydev->mii_ts->hwtstamp(phydev->mii_ts, config, extack);
+
+ return -EOPNOTSUPP;
}
/**
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index a42df2c1bd04..3611ea64875e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -654,6 +654,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
mdiodev->flags = MDIO_DEVICE_FLAG_PHY;
mdiodev->device_free = phy_mdio_device_free;
mdiodev->device_remove = phy_mdio_device_remove;
+ mdiodev->reset_state = -1;
dev->speed = SPEED_UNKNOWN;
dev->duplex = DUPLEX_UNKNOWN;
@@ -1235,18 +1236,19 @@ int phy_init_hw(struct phy_device *phydev)
if (phydev->drv->soft_reset) {
ret = phydev->drv->soft_reset(phydev);
+ if (ret < 0)
+ return ret;
+
/* see comment in genphy_soft_reset for an explanation */
- if (!ret)
- phydev->suspended = 0;
+ phydev->suspended = 0;
}
- if (ret < 0)
- return ret;
-
ret = phy_scan_fixups(phydev);
if (ret < 0)
return ret;
+ phy_interface_zero(phydev->possible_interfaces);
+
if (phydev->drv->config_init) {
ret = phydev->drv->config_init(phydev);
if (ret < 0)
@@ -1650,20 +1652,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
/**
* phy_package_join - join a common PHY group
* @phydev: target phy_device struct
- * @addr: cookie and PHY address for global register access
+ * @base_addr: cookie and base PHY address of PHY package for offset
+ * calculation of global register access
* @priv_size: if non-zero allocate this amount of bytes for private data
*
* This joins a PHY group and provides a shared storage for all phydevs in
* this group. This is intended to be used for packages which contain
* more than one PHY, for example a quad PHY transceiver.
*
- * The addr parameter serves as a cookie which has to have the same value
- * for all members of one group and as a PHY address to access generic
- * registers of a PHY package. Usually, one of the PHY addresses of the
- * different PHYs in the package provides access to these global registers.
+ * The base_addr parameter serves as cookie which has to have the same values
+ * for all members of one group and as the base PHY address of the PHY package
+ * for offset calculation to access generic registers of a PHY package.
+ * Usually, one of the PHY addresses of the different PHYs in the package
+ * provides access to these global registers.
* The address which is given here, will be used in the phy_package_read()
- * and phy_package_write() convenience functions. If your PHY doesn't have
- * global registers you can just pick any of the PHY addresses.
+ * and phy_package_write() convenience functions as base and added to the
+ * passed offset in those functions.
*
* This will set the shared pointer of the phydev to the shared storage.
* If this is the first call for a this cookie the shared storage will be
@@ -1673,17 +1677,17 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
* Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
* with the same cookie but a different priv_size is an error.
*/
-int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
{
struct mii_bus *bus = phydev->mdio.bus;
struct phy_package_shared *shared;
int ret;
- if (addr < 0 || addr >= PHY_MAX_ADDR)
+ if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
return -EINVAL;
mutex_lock(&bus->shared_lock);
- shared = bus->shared[addr];
+ shared = bus->shared[base_addr];
if (!shared) {
ret = -ENOMEM;
shared = kzalloc(sizeof(*shared), GFP_KERNEL);
@@ -1695,9 +1699,9 @@ int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
goto err_free;
shared->priv_size = priv_size;
}
- shared->addr = addr;
+ shared->base_addr = base_addr;
refcount_set(&shared->refcnt, 1);
- bus->shared[addr] = shared;
+ bus->shared[base_addr] = shared;
} else {
ret = -EINVAL;
if (priv_size && priv_size != shared->priv_size)
@@ -1735,7 +1739,7 @@ void phy_package_leave(struct phy_device *phydev)
return;
if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
- bus->shared[shared->addr] = NULL;
+ bus->shared[shared->base_addr] = NULL;
mutex_unlock(&bus->shared_lock);
kfree(shared->priv);
kfree(shared);
@@ -1754,7 +1758,8 @@ static void devm_phy_package_leave(struct device *dev, void *res)
* devm_phy_package_join - resource managed phy_package_join()
* @dev: device that is registering this PHY package
* @phydev: target phy_device struct
- * @addr: cookie and PHY address for global register access
+ * @base_addr: cookie and base PHY address of PHY package for offset
+ * calculation of global register access
* @priv_size: if non-zero allocate this amount of bytes for private data
*
* Managed phy_package_join(). Shared storage fetched by this function,
@@ -1762,7 +1767,7 @@ static void devm_phy_package_leave(struct device *dev, void *res)
* phy_package_join() for more information.
*/
int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
- int addr, size_t priv_size)
+ int base_addr, size_t priv_size)
{
struct phy_device **ptr;
int ret;
@@ -1772,7 +1777,7 @@ int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
if (!ptr)
return -ENOMEM;
- ret = phy_package_join(phydev, addr, priv_size);
+ ret = phy_package_join(phydev, base_addr, priv_size);
if (!ret) {
*ptr = phydev;
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 25c19496a336..ed0b4ccaa6a6 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -121,6 +121,19 @@ do { \
})
#endif
+static const phy_interface_t phylink_sfp_interface_preference[] = {
+ PHY_INTERFACE_MODE_25GBASER,
+ PHY_INTERFACE_MODE_USXGMII,
+ PHY_INTERFACE_MODE_10GBASER,
+ PHY_INTERFACE_MODE_5GBASER,
+ PHY_INTERFACE_MODE_2500BASEX,
+ PHY_INTERFACE_MODE_SGMII,
+ PHY_INTERFACE_MODE_1000BASEX,
+ PHY_INTERFACE_MODE_100BASEX,
+};
+
+static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
+
/**
* phylink_set_port_modes() - set the port type modes in the ethtool mask
* @mask: ethtool link mode mask
@@ -689,28 +702,48 @@ static int phylink_validate_mac_and_pcs(struct phylink *pl,
return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
}
-static int phylink_validate_mask(struct phylink *pl, unsigned long *supported,
+static void phylink_validate_one(struct phylink *pl, struct phy_device *phy,
+ const unsigned long *supported,
+ const struct phylink_link_state *state,
+ phy_interface_t interface,
+ unsigned long *accum_supported,
+ unsigned long *accum_advertising)
+{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp_supported);
+ struct phylink_link_state tmp_state;
+
+ linkmode_copy(tmp_supported, supported);
+
+ tmp_state = *state;
+ tmp_state.interface = interface;
+
+ if (phy)
+ tmp_state.rate_matching = phy_get_rate_matching(phy, interface);
+
+ if (!phylink_validate_mac_and_pcs(pl, tmp_supported, &tmp_state)) {
+ phylink_dbg(pl, " interface %u (%s) rate match %s supports %*pbl\n",
+ interface, phy_modes(interface),
+ phy_rate_matching_to_str(tmp_state.rate_matching),
+ __ETHTOOL_LINK_MODE_MASK_NBITS, tmp_supported);
+
+ linkmode_or(accum_supported, accum_supported, tmp_supported);
+ linkmode_or(accum_advertising, accum_advertising,
+ tmp_state.advertising);
+ }
+}
+
+static int phylink_validate_mask(struct phylink *pl, struct phy_device *phy,
+ unsigned long *supported,
struct phylink_link_state *state,
const unsigned long *interfaces)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, };
__ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, };
- __ETHTOOL_DECLARE_LINK_MODE_MASK(s);
- struct phylink_link_state t;
- int intf;
-
- for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
- if (test_bit(intf, interfaces)) {
- linkmode_copy(s, supported);
-
- t = *state;
- t.interface = intf;
- if (!phylink_validate_mac_and_pcs(pl, s, &t)) {
- linkmode_or(all_s, all_s, s);
- linkmode_or(all_adv, all_adv, t.advertising);
- }
- }
- }
+ int interface;
+
+ for_each_set_bit(interface, interfaces, PHY_INTERFACE_MODE_MAX)
+ phylink_validate_one(pl, phy, supported, state, interface,
+ all_s, all_adv);
linkmode_copy(supported, all_s);
linkmode_copy(state->advertising, all_adv);
@@ -724,7 +757,8 @@ static int phylink_validate(struct phylink *pl, unsigned long *supported,
const unsigned long *interfaces = pl->config->supported_interfaces;
if (state->interface == PHY_INTERFACE_MODE_NA)
- return phylink_validate_mask(pl, supported, state, interfaces);
+ return phylink_validate_mask(pl, NULL, supported, state,
+ interfaces);
if (!test_bit(state->interface, interfaces))
return -EINVAL;
@@ -805,7 +839,7 @@ static int phylink_parse_fixedlink(struct phylink *pl,
phylink_warn(pl, "fixed link specifies half duplex for %dMbps link?\n",
pl->link_config.speed);
- bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ linkmode_fill(pl->supported);
linkmode_copy(pl->link_config.advertising, pl->supported);
phylink_validate(pl, pl->supported, &pl->link_config);
@@ -849,6 +883,7 @@ static int phylink_parse_mode(struct phylink *pl,
{
struct fwnode_handle *dn;
const char *managed;
+ unsigned long caps;
dn = fwnode_get_named_child_node(fwnode, "fixed-link");
if (dn || fwnode_property_present(fwnode, "fixed-link"))
@@ -881,80 +916,18 @@ static int phylink_parse_mode(struct phylink *pl,
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
case PHY_INTERFACE_MODE_RTBI:
- phylink_set(pl->supported, 10baseT_Half);
- phylink_set(pl->supported, 10baseT_Full);
- phylink_set(pl->supported, 100baseT_Half);
- phylink_set(pl->supported, 100baseT_Full);
- phylink_set(pl->supported, 1000baseT_Half);
- phylink_set(pl->supported, 1000baseT_Full);
- break;
-
case PHY_INTERFACE_MODE_1000BASEX:
- phylink_set(pl->supported, 1000baseX_Full);
- break;
-
case PHY_INTERFACE_MODE_2500BASEX:
- phylink_set(pl->supported, 2500baseX_Full);
- break;
-
case PHY_INTERFACE_MODE_5GBASER:
- phylink_set(pl->supported, 5000baseT_Full);
- break;
-
case PHY_INTERFACE_MODE_25GBASER:
- phylink_set(pl->supported, 25000baseCR_Full);
- phylink_set(pl->supported, 25000baseKR_Full);
- phylink_set(pl->supported, 25000baseSR_Full);
- fallthrough;
case PHY_INTERFACE_MODE_USXGMII:
case PHY_INTERFACE_MODE_10GKR:
case PHY_INTERFACE_MODE_10GBASER:
- phylink_set(pl->supported, 10baseT_Half);
- phylink_set(pl->supported, 10baseT_Full);
- phylink_set(pl->supported, 100baseT_Half);
- phylink_set(pl->supported, 100baseT_Full);
- phylink_set(pl->supported, 1000baseT_Half);
- phylink_set(pl->supported, 1000baseT_Full);
- phylink_set(pl->supported, 1000baseX_Full);
- phylink_set(pl->supported, 1000baseKX_Full);
- phylink_set(pl->supported, 2500baseT_Full);
- phylink_set(pl->supported, 2500baseX_Full);
- phylink_set(pl->supported, 5000baseT_Full);
- phylink_set(pl->supported, 10000baseT_Full);
- phylink_set(pl->supported, 10000baseKR_Full);
- phylink_set(pl->supported, 10000baseKX4_Full);
- phylink_set(pl->supported, 10000baseCR_Full);
- phylink_set(pl->supported, 10000baseSR_Full);
- phylink_set(pl->supported, 10000baseLR_Full);
- phylink_set(pl->supported, 10000baseLRM_Full);
- phylink_set(pl->supported, 10000baseER_Full);
- break;
-
case PHY_INTERFACE_MODE_XLGMII:
- phylink_set(pl->supported, 25000baseCR_Full);
- phylink_set(pl->supported, 25000baseKR_Full);
- phylink_set(pl->supported, 25000baseSR_Full);
- phylink_set(pl->supported, 40000baseKR4_Full);
- phylink_set(pl->supported, 40000baseCR4_Full);
- phylink_set(pl->supported, 40000baseSR4_Full);
- phylink_set(pl->supported, 40000baseLR4_Full);
- phylink_set(pl->supported, 50000baseCR2_Full);
- phylink_set(pl->supported, 50000baseKR2_Full);
- phylink_set(pl->supported, 50000baseSR2_Full);
- phylink_set(pl->supported, 50000baseKR_Full);
- phylink_set(pl->supported, 50000baseSR_Full);
- phylink_set(pl->supported, 50000baseCR_Full);
- phylink_set(pl->supported, 50000baseLR_ER_FR_Full);
- phylink_set(pl->supported, 50000baseDR_Full);
- phylink_set(pl->supported, 100000baseKR4_Full);
- phylink_set(pl->supported, 100000baseSR4_Full);
- phylink_set(pl->supported, 100000baseCR4_Full);
- phylink_set(pl->supported, 100000baseLR4_ER4_Full);
- phylink_set(pl->supported, 100000baseKR2_Full);
- phylink_set(pl->supported, 100000baseSR2_Full);
- phylink_set(pl->supported, 100000baseCR2_Full);
- phylink_set(pl->supported, 100000baseLR2_ER2_FR2_Full);
- phylink_set(pl->supported, 100000baseDR2_Full);
+ caps = ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
+ caps = phylink_get_capabilities(pl->link_config.interface, caps,
+ RATE_MATCH_NONE);
+ phylink_caps_to_linkmodes(pl->supported, caps);
break;
default:
@@ -1101,6 +1074,72 @@ static void phylink_pcs_an_restart(struct phylink *pl)
pl->pcs->ops->pcs_an_restart(pl->pcs);
}
+/**
+ * phylink_pcs_neg_mode() - helper to determine PCS inband mode
+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
+ * @interface: interface mode to be used
+ * @advertising: adertisement ethtool link mode mask
+ *
+ * Determines the negotiation mode to be used by the PCS, and returns
+ * one of:
+ *
+ * - %PHYLINK_PCS_NEG_NONE: interface mode does not support inband
+ * - %PHYLINK_PCS_NEG_OUTBAND: an out of band mode (e.g. reading the PHY)
+ * will be used.
+ * - %PHYLINK_PCS_NEG_INBAND_DISABLED: inband mode selected but autoneg
+ * disabled
+ * - %PHYLINK_PCS_NEG_INBAND_ENABLED: inband mode selected and autoneg enabled
+ *
+ * Note: this is for cases where the PCS itself is involved in negotiation
+ * (e.g. Clause 37, SGMII and similar) not Clause 73.
+ */
+static unsigned int phylink_pcs_neg_mode(unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising)
+{
+ unsigned int neg_mode;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_QSGMII:
+ case PHY_INTERFACE_MODE_QUSGMII:
+ case PHY_INTERFACE_MODE_USXGMII:
+ /* These protocols are designed for use with a PHY which
+ * communicates its negotiation result back to the MAC via
+ * inband communication. Note: there exist PHYs that run
+ * with SGMII but do not send the inband data.
+ */
+ if (!phylink_autoneg_inband(mode))
+ neg_mode = PHYLINK_PCS_NEG_OUTBAND;
+ else
+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+ break;
+
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ /* 1000base-X is designed for use media-side for Fibre
+ * connections, and thus the Autoneg bit needs to be
+ * taken into account. We also do this for 2500base-X
+ * as well, but drivers may not support this, so may
+ * need to override this.
+ */
+ if (!phylink_autoneg_inband(mode))
+ neg_mode = PHYLINK_PCS_NEG_OUTBAND;
+ else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ advertising))
+ neg_mode = PHYLINK_PCS_NEG_INBAND_ENABLED;
+ else
+ neg_mode = PHYLINK_PCS_NEG_INBAND_DISABLED;
+ break;
+
+ default:
+ neg_mode = PHYLINK_PCS_NEG_NONE;
+ break;
+ }
+
+ return neg_mode;
+}
+
static void phylink_major_config(struct phylink *pl, bool restart,
const struct phylink_link_state *state)
{
@@ -1640,7 +1679,7 @@ struct phylink *phylink_create(struct phylink_config *config,
__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
- bitmap_fill(pl->supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+ linkmode_fill(pl->supported);
linkmode_copy(pl->link_config.advertising, pl->supported);
phylink_validate(pl, pl->supported, &pl->link_config);
@@ -1739,31 +1778,55 @@ static void phylink_phy_change(struct phy_device *phydev, bool up)
phylink_pause_to_str(pl->phy_state.pause));
}
-static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
- phy_interface_t interface)
+static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy,
+ unsigned long *supported,
+ struct phylink_link_state *state)
{
- struct phylink_link_state config;
- __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
- char *irq_str;
- int ret;
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
- /*
- * This is the new way of dealing with flow control for PHYs,
- * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
- * phy drivers should not set SUPPORTED_[Asym_]Pause") except
- * using our validate call to the MAC, we rely upon the MAC
- * clearing the bits from both supported and advertising fields.
+ /* If the PHY provides a bitmap of the interfaces it will be using
+ * depending on the negotiated media speeds, use this to validate
+ * which ethtool link modes can be used.
*/
- phy_support_asym_pause(phy);
+ if (!phy_interface_empty(phy->possible_interfaces)) {
+ /* We only care about the union of the PHY's interfaces and
+ * those which the host supports.
+ */
+ phy_interface_and(interfaces, phy->possible_interfaces,
+ pl->config->supported_interfaces);
- memset(&config, 0, sizeof(config));
- linkmode_copy(supported, phy->supported);
- linkmode_copy(config.advertising, phy->advertising);
+ if (phy_interface_empty(interfaces)) {
+ phylink_err(pl, "PHY has no common interfaces\n");
+ return -EINVAL;
+ }
+
+ if (phy_on_sfp(phy)) {
+ /* If the PHY is on a SFP, limit the interfaces to
+ * those that can be used with a SFP module.
+ */
+ phy_interface_and(interfaces, interfaces,
+ phylink_sfp_interfaces);
+
+ if (phy_interface_empty(interfaces)) {
+ phylink_err(pl, "SFP PHY's possible interfaces becomes empty\n");
+ return -EINVAL;
+ }
+ }
+
+ phylink_dbg(pl, "PHY %s uses interfaces %*pbl, validating %*pbl\n",
+ phydev_name(phy),
+ (int)PHY_INTERFACE_MODE_MAX,
+ phy->possible_interfaces,
+ (int)PHY_INTERFACE_MODE_MAX, interfaces);
+
+ return phylink_validate_mask(pl, phy, supported, state,
+ interfaces);
+ }
/* Check whether we would use rate matching for the proposed interface
* mode.
*/
- config.rate_matching = phy_get_rate_matching(phy, interface);
+ state->rate_matching = phy_get_rate_matching(phy, state->interface);
/* Clause 45 PHYs may switch their Serdes lane between, e.g. 10GBASE-R,
* 5GBASE-R, 2500BASE-X and SGMII if they are not using rate matching.
@@ -1776,15 +1839,38 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
* against all interface modes, which may lead to more ethtool link
* modes being advertised than are actually supported.
*/
- if (phy->is_c45 && config.rate_matching == RATE_MATCH_NONE &&
- interface != PHY_INTERFACE_MODE_RXAUI &&
- interface != PHY_INTERFACE_MODE_XAUI &&
- interface != PHY_INTERFACE_MODE_USXGMII)
- config.interface = PHY_INTERFACE_MODE_NA;
- else
- config.interface = interface;
+ if (phy->is_c45 && state->rate_matching == RATE_MATCH_NONE &&
+ state->interface != PHY_INTERFACE_MODE_RXAUI &&
+ state->interface != PHY_INTERFACE_MODE_XAUI &&
+ state->interface != PHY_INTERFACE_MODE_USXGMII)
+ state->interface = PHY_INTERFACE_MODE_NA;
- ret = phylink_validate(pl, supported, &config);
+ return phylink_validate(pl, supported, state);
+}
+
+static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
+ phy_interface_t interface)
+{
+ struct phylink_link_state config;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+ char *irq_str;
+ int ret;
+
+ /*
+ * This is the new way of dealing with flow control for PHYs,
+ * as described by Timur Tabi in commit 529ed1275263 ("net: phy:
+ * phy drivers should not set SUPPORTED_[Asym_]Pause") except
+ * using our validate call to the MAC, we rely upon the MAC
+ * clearing the bits from both supported and advertising fields.
+ */
+ phy_support_asym_pause(phy);
+
+ memset(&config, 0, sizeof(config));
+ linkmode_copy(supported, phy->supported);
+ linkmode_copy(config.advertising, phy->advertising);
+ config.interface = interface;
+
+ ret = phylink_validate_phy(pl, phy, supported, &config);
if (ret) {
phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %pe\n",
phy_modes(config.interface),
@@ -3005,19 +3091,6 @@ static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
pl->netdev->sfp_bus = NULL;
}
-static const phy_interface_t phylink_sfp_interface_preference[] = {
- PHY_INTERFACE_MODE_25GBASER,
- PHY_INTERFACE_MODE_USXGMII,
- PHY_INTERFACE_MODE_10GBASER,
- PHY_INTERFACE_MODE_5GBASER,
- PHY_INTERFACE_MODE_2500BASEX,
- PHY_INTERFACE_MODE_SGMII,
- PHY_INTERFACE_MODE_1000BASEX,
- PHY_INTERFACE_MODE_100BASEX,
-};
-
-static DECLARE_PHY_INTERFACE_MASK(phylink_sfp_interfaces);
-
static phy_interface_t phylink_choose_sfp_interface(struct phylink *pl,
const unsigned long *intf)
{
@@ -3160,7 +3233,8 @@ static int phylink_sfp_config_optical(struct phylink *pl)
/* For all the interfaces that are supported, reduce the sfp_support
* mask to only those link modes that can be supported.
*/
- ret = phylink_validate_mask(pl, pl->sfp_support, &config, interfaces);
+ ret = phylink_validate_mask(pl, NULL, pl->sfp_support, &config,
+ interfaces);
if (ret) {
phylink_err(pl, "unsupported SFP module: validation with support %*pb failed\n",
__ETHTOOL_LINK_MODE_MASK_NBITS, support);
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 894172a3e15f..337899c69738 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -421,9 +421,11 @@ static int rtl8211f_config_init(struct phy_device *phydev)
ERR_PTR(ret));
return ret;
}
+
+ return genphy_soft_reset(phydev);
}
- return genphy_soft_reset(phydev);
+ return 0;
}
static int rtl821x_suspend(struct phy_device *phydev)
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index 208a9393c2df..db39dec7f247 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -151,10 +151,6 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
unsigned int br_min, br_nom, br_max;
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
- phylink_set(modes, Autoneg);
- phylink_set(modes, Pause);
- phylink_set(modes, Asym_Pause);
-
/* Decode the bitrate information to MBd */
br_min = br_nom = br_max = 0;
if (id->base.br_nominal) {
@@ -328,7 +324,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
* modules use 2500Mbaud rather than 3100 or 3200Mbaud for
* 2500BASE-X, so we allow some slack here.
*/
- if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) {
+ if (linkmode_empty(modes) && br_nom) {
if (br_min <= 1300 && br_max >= 1200) {
phylink_set(modes, 1000baseX_Full);
__set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
@@ -339,6 +335,10 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
}
}
+ phylink_set(modes, Autoneg);
+ phylink_set(modes, Pause);
+ phylink_set(modes, Asym_Pause);
+
if (bus->sfp_quirk && bus->sfp_quirk->modes)
bus->sfp_quirk->modes(id, modes, interfaces);
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 5468bd209fab..f75c9eb3958e 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -191,7 +191,7 @@ static const enum gpiod_flags gpio_flags[] = {
* R_PHY_RETRY is the number of attempts.
*/
#define T_PHY_RETRY msecs_to_jiffies(50)
-#define R_PHY_RETRY 12
+#define R_PHY_RETRY 25
/* SFP module presence detection is poor: the three MOD DEF signals are
* the same length on the PCB, which means it's possible for MOD DEF 0 to
@@ -275,6 +275,7 @@ struct sfp {
unsigned int module_power_mW;
unsigned int module_t_start_up;
unsigned int module_t_wait;
+ unsigned int phy_t_retry;
unsigned int rate_kbd;
unsigned int rs_threshold_kbd;
@@ -372,18 +373,28 @@ static void sfp_fixup_10gbaset_30m(struct sfp *sfp)
sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR;
}
-static void sfp_fixup_rollball_proto(struct sfp *sfp, unsigned int secs)
+static void sfp_fixup_rollball(struct sfp *sfp)
{
sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
- sfp->module_t_wait = msecs_to_jiffies(secs * 1000);
+
+ /* RollBall modules may disallow access to PHY registers for up to 25
+ * seconds, and the reads return 0xffff before that. Increase the time
+ * between PHY probe retries from 50ms to 1s so that we will wait for
+ * the PHY for a sufficient amount of time.
+ */
+ sfp->phy_t_retry = msecs_to_jiffies(1000);
}
static void sfp_fixup_fs_10gt(struct sfp *sfp)
{
sfp_fixup_10gbaset_30m(sfp);
+ sfp_fixup_rollball(sfp);
- // These SFPs need 4 seconds before the PHY can be accessed
- sfp_fixup_rollball_proto(sfp, 4);
+ /* The RollBall fixup is not enough for FS modules, the AQR chip inside
+ * them does not return 0xffff for PHY ID registers in all MMDs for the
+ * while initializing. They need a 4 second wait before accessing PHY.
+ */
+ sfp->module_t_wait = msecs_to_jiffies(4000);
}
static void sfp_fixup_halny_gsfp(struct sfp *sfp)
@@ -395,12 +406,6 @@ static void sfp_fixup_halny_gsfp(struct sfp *sfp)
sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS);
}
-static void sfp_fixup_rollball(struct sfp *sfp)
-{
- // Rollball SFPs need 25 seconds before the PHY can be accessed
- sfp_fixup_rollball_proto(sfp, 25);
-}
-
static void sfp_fixup_rollball_cc(struct sfp *sfp)
{
sfp_fixup_rollball(sfp);
@@ -2332,6 +2337,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
sfp->module_t_start_up = T_START_UP;
sfp->module_t_wait = T_WAIT;
+ sfp->phy_t_retry = T_PHY_RETRY;
sfp->state_ignore_mask = 0;
@@ -2629,7 +2635,11 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
ret = sfp_sm_probe_for_phy(sfp);
if (ret == -ENODEV) {
if (--sfp->sm_phy_retries) {
- sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY);
+ sfp_sm_next(sfp, SFP_S_INIT_PHY,
+ sfp->phy_t_retry);
+ dev_dbg(sfp->dev,
+ "no PHY detected, %u tries left\n",
+ sfp->sm_phy_retries);
break;
} else {
dev_info(sfp->dev, "no PHY detected\n");
@@ -3096,7 +3106,7 @@ static int sfp_probe(struct platform_device *pdev)
return 0;
}
-static int sfp_remove(struct platform_device *pdev)
+static void sfp_remove(struct platform_device *pdev)
{
struct sfp *sfp = platform_get_drvdata(pdev);
@@ -3106,8 +3116,6 @@ static int sfp_remove(struct platform_device *pdev)
rtnl_lock();
sfp_sm_event(sfp, SFP_E_REMOVE);
rtnl_unlock();
-
- return 0;
}
static void sfp_shutdown(struct platform_device *pdev)
@@ -3128,7 +3136,7 @@ static void sfp_shutdown(struct platform_device *pdev)
static struct platform_driver sfp_driver = {
.probe = sfp_probe,
- .remove = sfp_remove,
+ .remove_new = sfp_remove,
.shutdown = sfp_shutdown,
.driver = {
.name = "sfp",
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 1c7306a1af13..150aea7c9c36 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -508,7 +508,7 @@ static void smsc_get_strings(struct phy_device *phydev, u8 *data)
int i;
for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)
- ethtool_sprintf(&data, "%s", smsc_hw_stats[i].string);
+ ethtool_puts(&data, smsc_hw_stats[i].string);
}
static u64 smsc_get_stat(struct phy_device *phydev, int i)
diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index 40ce8abe6999..cc7d1113ece0 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -1437,4 +1437,5 @@ static int __init plip_init (void)
module_init(plip_init);
module_exit(plip_cleanup_module);
+MODULE_DESCRIPTION("PLIP (parallel port) network module");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ppp/bsd_comp.c b/drivers/net/ppp/bsd_comp.c
index db0dc36d12e3..55954594e157 100644
--- a/drivers/net/ppp/bsd_comp.c
+++ b/drivers/net/ppp/bsd_comp.c
@@ -1166,5 +1166,6 @@ static void __exit bsdcomp_cleanup(void)
module_init(bsdcomp_init);
module_exit(bsdcomp_cleanup);
+MODULE_DESCRIPTION("PPP BSD-Compress compression module");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_BSD_COMPRESS));
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index fbaaa8c102a1..c33c3db3cc08 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -87,6 +87,7 @@ struct asyncppp {
static int flag_time = HZ;
module_param(flag_time, int, 0);
MODULE_PARM_DESC(flag_time, "ppp_async: interval between flagged packets (in clock ticks)");
+MODULE_DESCRIPTION("PPP async serial channel module");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_PPP);
@@ -460,6 +461,10 @@ ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd, unsigned long arg)
case PPPIOCSMRU:
if (get_user(val, p))
break;
+ if (val > U16_MAX) {
+ err = -EINVAL;
+ break;
+ }
if (val < PPP_MRU)
val = PPP_MRU;
ap->mru = val;
@@ -533,7 +538,7 @@ ppp_async_encode(struct asyncppp *ap)
proto = get_unaligned_be16(data);
/*
- * LCP packets with code values between 1 (configure-reqest)
+ * LCP packets with code values between 1 (configure-request)
* and 7 (code-reject) must be sent as though no options
* had been negotiated.
*/
diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
index e6d48e5c65a3..4d2ff63f2ee2 100644
--- a/drivers/net/ppp/ppp_deflate.c
+++ b/drivers/net/ppp/ppp_deflate.c
@@ -630,6 +630,7 @@ static void __exit deflate_cleanup(void)
module_init(deflate_init);
module_exit(deflate_cleanup);
+MODULE_DESCRIPTION("PPP Deflate compression module");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 0193af2d31c9..3dd52bf28f15 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -3604,6 +3604,7 @@ EXPORT_SYMBOL(ppp_input_error);
EXPORT_SYMBOL(ppp_output_wakeup);
EXPORT_SYMBOL(ppp_register_compressor);
EXPORT_SYMBOL(ppp_unregister_compressor);
+MODULE_DESCRIPTION("Generic PPP layer driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV(PPP_MAJOR, 0);
MODULE_ALIAS_RTNL_LINK("ppp");
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 52d05ce4a281..45bf59ac8f57 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -724,5 +724,6 @@ ppp_sync_cleanup(void)
module_init(ppp_sync_init);
module_exit(ppp_sync_cleanup);
+MODULE_DESCRIPTION("PPP synchronous TTY channel module");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_SYNC_PPP);
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 8e7238e97d0a..2ea4f4890d23 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -1007,26 +1007,21 @@ static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
struct sk_buff *skb;
int error = 0;
- if (sk->sk_state & PPPOX_BOUND) {
- error = -EIO;
- goto end;
- }
+ if (sk->sk_state & PPPOX_BOUND)
+ return -EIO;
skb = skb_recv_datagram(sk, flags, &error);
- if (error < 0)
- goto end;
+ if (!skb)
+ return error;
- if (skb) {
- total_len = min_t(size_t, total_len, skb->len);
- error = skb_copy_datagram_msg(skb, 0, m, total_len);
- if (error == 0) {
- consume_skb(skb);
- return total_len;
- }
+ total_len = min_t(size_t, total_len, skb->len);
+ error = skb_copy_datagram_msg(skb, 0, m, total_len);
+ if (error == 0) {
+ consume_skb(skb);
+ return total_len;
}
kfree_skb(skb);
-end:
return error;
}
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index ba93bab948e0..18df7ca66198 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -752,4 +752,5 @@ EXPORT_SYMBOL(slhc_compress);
EXPORT_SYMBOL(slhc_uncompress);
EXPORT_SYMBOL(slhc_toss);
+MODULE_DESCRIPTION("Compression helpers for SLIP (serial line)");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index e4280e37fec9..0aba3569ccc0 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -1437,5 +1437,6 @@ out:
}
#endif
+MODULE_DESCRIPTION("SLIP (serial line) protocol module");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_SLIP);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index afa5497f7c35..8f95a562b8d0 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -653,6 +653,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
tun->tfiles[tun->numqueues - 1]);
ntfile = rtnl_dereference(tun->tfiles[index]);
ntfile->queue_index = index;
+ ntfile->xdp_rxq.queue_index = index;
rcu_assign_pointer(tun->tfiles[tun->numqueues - 1],
NULL);
@@ -1630,13 +1631,19 @@ static int tun_xdp_act(struct tun_struct *tun, struct bpf_prog *xdp_prog,
switch (act) {
case XDP_REDIRECT:
err = xdp_do_redirect(tun->dev, xdp, xdp_prog);
- if (err)
+ if (err) {
+ dev_core_stats_rx_dropped_inc(tun->dev);
return err;
+ }
+ dev_sw_netstats_rx_add(tun->dev, xdp->data_end - xdp->data);
break;
case XDP_TX:
err = tun_xdp_tx(tun->dev, xdp);
- if (err < 0)
+ if (err < 0) {
+ dev_core_stats_rx_dropped_inc(tun->dev);
return err;
+ }
+ dev_sw_netstats_rx_add(tun->dev, xdp->data_end - xdp->data);
break;
case XDP_PASS:
break;
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
index 5a1bf42ce156..d837c1887416 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1315,8 +1315,6 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
netif_set_tso_max_size(dev->net, 16384);
- ax88179_reset(dev);
-
return 0;
}
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 99ec1d4a972d..8b6d6a1b3c2e 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -232,7 +232,7 @@ static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)
err = dm_read_shared_word(dev, 1, loc, &res);
if (err < 0) {
netdev_err(dev->net, "MDIO read error: %d\n", err);
- return err;
+ return 0;
}
netdev_dbg(dev->net,
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 83b8452220ec..f088ea2ba6f3 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -363,7 +363,6 @@ static int disable_net;
/* driver info */
static const char driver_name[] = "hso";
static const char tty_filename[] = "ttyHS";
-static const char *version = __FILE__ ": " MOD_AUTHOR;
/* the usb driver itself (registered in hso_init) */
static struct usb_driver hso_driver;
/* serial structures */
@@ -3228,16 +3227,8 @@ static struct usb_driver hso_driver = {
static int __init hso_init(void)
{
- int i;
int result;
- /* put it in the log */
- pr_info("%s\n", version);
-
- /* Initialise the serial table semaphore and table */
- for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++)
- serial_table[i] = NULL;
-
/* allocate our driver using the proper amount of supported minors */
tty_drv = tty_alloc_driver(HSO_SERIAL_TTY_MINORS, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
@@ -3285,8 +3276,6 @@ err_free_tty:
static void __exit hso_exit(void)
{
- pr_info("unloaded\n");
-
tty_unregister_driver(tty_drv);
/* deregister the usb driver */
usb_deregister(&hso_driver);
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index 5add4145d9fc..d2aa2c5b1989 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -1501,7 +1501,9 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
lan78xx_rx_urb_submit_all(dev);
+ local_bh_disable();
napi_schedule(&dev->napi);
+ local_bh_enable();
}
return 0;
@@ -1691,8 +1693,6 @@ static int lan78xx_get_eee(struct net_device *net, struct ethtool_eee *edata)
ret = lan78xx_read_reg(dev, MAC_CR, &buf);
if (buf & MAC_CR_EEE_EN_) {
edata->eee_enabled = true;
- edata->eee_active = !!(edata->advertised &
- edata->lp_advertised);
edata->tx_lpi_enabled = true;
/* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
ret = lan78xx_read_reg(dev, EEE_TX_LPI_REQ_DLY, &buf);
@@ -3035,7 +3035,8 @@ static int lan78xx_reset(struct lan78xx_net *dev)
if (dev->chipid == ID_REV_CHIP_ID_7801_)
buf &= ~MAC_CR_GMII_EN_;
- if (dev->chipid == ID_REV_CHIP_ID_7800_) {
+ if (dev->chipid == ID_REV_CHIP_ID_7800_ ||
+ dev->chipid == ID_REV_CHIP_ID_7850_) {
ret = lan78xx_read_raw_eeprom(dev, 0, 1, &sig);
if (!ret && sig != EEPROM_INDICATOR) {
/* Implies there is no external eeprom. Set mac speed */
@@ -3134,7 +3135,8 @@ static int lan78xx_open(struct net_device *net)
done:
mutex_unlock(&dev->dev_mutex);
- usb_autopm_put_interface(dev->intf);
+ if (ret < 0)
+ usb_autopm_put_interface(dev->intf);
return ret;
}
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 9bf2140fd0a1..0d0672d2a654 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -10069,7 +10069,7 @@ static struct usb_driver rtl8152_driver = {
.disable_hub_initiated_lpm = 1,
};
-static int rtl8152_cfgselector_probe(struct usb_device *udev)
+static int rtl8152_cfgselector_choose_configuration(struct usb_device *udev)
{
struct usb_host_config *c;
int i, num_configs;
@@ -10096,19 +10096,13 @@ static int rtl8152_cfgselector_probe(struct usb_device *udev)
if (i == num_configs)
return -ENODEV;
- if (usb_set_configuration(udev, c->desc.bConfigurationValue)) {
- dev_err(&udev->dev, "Failed to set configuration %d\n",
- c->desc.bConfigurationValue);
- return -ENODEV;
- }
-
- return 0;
+ return c->desc.bConfigurationValue;
}
static struct usb_device_driver rtl8152_cfgselector_driver = {
- .name = MODULENAME "-cfgselector",
- .probe = rtl8152_cfgselector_probe,
- .id_table = rtl8152_table,
+ .name = MODULENAME "-cfgselector",
+ .choose_configuration = rtl8152_cfgselector_choose_configuration,
+ .id_table = rtl8152_table,
.generic_subclass = 1,
.supports_autosuspend = 1,
};
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index a530f20ee257..2fa46baa589e 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -2105,6 +2105,11 @@ static const struct usb_device_id products[] = {
.driver_info = (unsigned long) &smsc95xx_info,
},
{
+ /* SYSTEC USB-SPEmodule1 10BASE-T1L Ethernet Device */
+ USB_DEVICE(0x0878, 0x1400),
+ .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,
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 977861c46b1f..cd4a6fe458f9 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -1208,14 +1208,6 @@ static int veth_enable_xdp(struct net_device *dev)
veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues, true);
return err;
}
-
- if (!veth_gro_requested(dev)) {
- /* user-space did not require GRO, but adding XDP
- * is supposed to get GRO working
- */
- dev->features |= NETIF_F_GRO;
- netdev_features_change(dev);
- }
}
}
@@ -1235,18 +1227,9 @@ static void veth_disable_xdp(struct net_device *dev)
for (i = 0; i < dev->real_num_rx_queues; i++)
rcu_assign_pointer(priv->rq[i].xdp_prog, NULL);
- if (!netif_running(dev) || !veth_gro_requested(dev)) {
+ if (!netif_running(dev) || !veth_gro_requested(dev))
veth_napi_del(dev);
- /* if user-space did not require GRO, since adding XDP
- * enabled it, clear it now
- */
- if (!veth_gro_requested(dev) && netif_running(dev)) {
- dev->features &= ~NETIF_F_GRO;
- netdev_features_change(dev);
- }
- }
-
veth_disable_xdp_range(dev, 0, dev->real_num_rx_queues, false);
}
@@ -1478,7 +1461,8 @@ static int veth_alloc_queues(struct net_device *dev)
struct veth_priv *priv = netdev_priv(dev);
int i;
- priv->rq = kcalloc(dev->num_rx_queues, sizeof(*priv->rq), GFP_KERNEL_ACCOUNT);
+ priv->rq = kvcalloc(dev->num_rx_queues, sizeof(*priv->rq),
+ GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
if (!priv->rq)
return -ENOMEM;
@@ -1494,7 +1478,7 @@ static void veth_free_queues(struct net_device *dev)
{
struct veth_priv *priv = netdev_priv(dev);
- kfree(priv->rq);
+ kvfree(priv->rq);
}
static int veth_dev_init(struct net_device *dev)
@@ -1654,6 +1638,14 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
}
if (!old_prog) {
+ if (!veth_gro_requested(dev)) {
+ /* user-space did not require GRO, but adding
+ * XDP is supposed to get GRO working
+ */
+ dev->features |= NETIF_F_GRO;
+ netdev_features_change(dev);
+ }
+
peer->hw_features &= ~NETIF_F_GSO_SOFTWARE;
peer->max_mtu = max_mtu;
}
@@ -1669,6 +1661,14 @@ static int veth_xdp_set(struct net_device *dev, struct bpf_prog *prog,
if (dev->flags & IFF_UP)
veth_disable_xdp(dev);
+ /* if user-space did not require GRO, since adding XDP
+ * enabled it, clear it now
+ */
+ if (!veth_gro_requested(dev)) {
+ dev->features &= ~NETIF_F_GRO;
+ netdev_features_change(dev);
+ }
+
if (peer) {
peer->hw_features |= NETIF_F_GSO_SOFTWARE;
peer->max_mtu = ETH_MAX_MTU;
@@ -1723,6 +1723,24 @@ static int veth_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash,
return 0;
}
+static int veth_xdp_rx_vlan_tag(const struct xdp_md *ctx, __be16 *vlan_proto,
+ u16 *vlan_tci)
+{
+ const struct veth_xdp_buff *_ctx = (void *)ctx;
+ const struct sk_buff *skb = _ctx->skb;
+ int err;
+
+ if (!skb)
+ return -ENODATA;
+
+ err = __vlan_hwaccel_get_tag(skb, vlan_tci);
+ if (err)
+ return err;
+
+ *vlan_proto = skb->vlan_proto;
+ return err;
+}
+
static const struct net_device_ops veth_netdev_ops = {
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
@@ -1747,6 +1765,7 @@ static const struct net_device_ops veth_netdev_ops = {
static const struct xdp_metadata_ops veth_xdp_metadata_ops = {
.xmo_rx_timestamp = veth_xdp_rx_timestamp,
.xmo_rx_hash = veth_xdp_rx_hash,
+ .xmo_rx_vlan_tag = veth_xdp_rx_vlan_tag,
};
#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 51b1868d2f22..d7ce4a1011ea 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -19,6 +19,7 @@
#include <linux/average.h>
#include <linux/filter.h>
#include <linux/kernel.h>
+#include <linux/dim.h>
#include <net/route.h>
#include <net/xdp.h>
#include <net/net_failover.h>
@@ -172,6 +173,17 @@ struct receive_queue {
struct virtnet_rq_stats stats;
+ /* The number of rx notifications */
+ u16 calls;
+
+ /* Is dynamic interrupt moderation enabled? */
+ bool dim_enabled;
+
+ /* Dynamic Interrupt Moderation */
+ struct dim dim;
+
+ u32 packets_in_napi;
+
struct virtnet_interrupt_coalesce intr_coal;
/* Chain pages by the private ptr. */
@@ -305,6 +317,9 @@ struct virtnet_info {
u8 duplex;
u32 speed;
+ /* Is rx dynamic interrupt moderation enabled? */
+ bool rx_dim_enabled;
+
/* Interrupt coalescing settings */
struct virtnet_interrupt_coalesce intr_coal_tx;
struct virtnet_interrupt_coalesce intr_coal_rx;
@@ -441,7 +456,7 @@ static void virtqueue_napi_schedule(struct napi_struct *napi,
}
}
-static void virtqueue_napi_complete(struct napi_struct *napi,
+static bool virtqueue_napi_complete(struct napi_struct *napi,
struct virtqueue *vq, int processed)
{
int opaque;
@@ -450,9 +465,13 @@ static void virtqueue_napi_complete(struct napi_struct *napi,
if (napi_complete_done(napi, processed)) {
if (unlikely(virtqueue_poll(vq, opaque)))
virtqueue_napi_schedule(napi, vq);
+ else
+ return true;
} else {
virtqueue_disable_cb(vq);
}
+
+ return false;
}
static void skb_xmit_done(struct virtqueue *vq)
@@ -2010,6 +2029,7 @@ static void skb_recv_done(struct virtqueue *rvq)
struct virtnet_info *vi = rvq->vdev->priv;
struct receive_queue *rq = &vi->rq[vq2rxq(rvq)];
+ rq->calls++;
virtqueue_napi_schedule(&rq->napi, rvq);
}
@@ -2150,6 +2170,24 @@ static void virtnet_poll_cleantx(struct receive_queue *rq)
}
}
+static void virtnet_rx_dim_update(struct virtnet_info *vi, struct receive_queue *rq)
+{
+ struct dim_sample cur_sample = {};
+
+ if (!rq->packets_in_napi)
+ return;
+
+ u64_stats_update_begin(&rq->stats.syncp);
+ dim_update_sample(rq->calls,
+ u64_stats_read(&rq->stats.packets),
+ u64_stats_read(&rq->stats.bytes),
+ &cur_sample);
+ u64_stats_update_end(&rq->stats.syncp);
+
+ net_dim(&rq->dim, cur_sample);
+ rq->packets_in_napi = 0;
+}
+
static int virtnet_poll(struct napi_struct *napi, int budget)
{
struct receive_queue *rq =
@@ -2158,17 +2196,22 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
struct send_queue *sq;
unsigned int received;
unsigned int xdp_xmit = 0;
+ bool napi_complete;
virtnet_poll_cleantx(rq);
received = virtnet_receive(rq, budget, &xdp_xmit);
+ rq->packets_in_napi += received;
if (xdp_xmit & VIRTIO_XDP_REDIR)
xdp_do_flush();
/* Out of packets? */
- if (received < budget)
- virtqueue_napi_complete(napi, rq->vq, received);
+ if (received < budget) {
+ napi_complete = virtqueue_napi_complete(napi, rq->vq, received);
+ if (napi_complete && rq->dim_enabled)
+ virtnet_rx_dim_update(vi, rq);
+ }
if (xdp_xmit & VIRTIO_XDP_TX) {
sq = virtnet_xdp_get_sq(vi);
@@ -2239,8 +2282,11 @@ err_enable_qp:
disable_delayed_refill(vi);
cancel_delayed_work_sync(&vi->refill);
- for (i--; i >= 0; i--)
+ for (i--; i >= 0; i--) {
virtnet_disable_queue_pair(vi, i);
+ cancel_work_sync(&vi->rq[i].dim.work);
+ }
+
return err;
}
@@ -2402,8 +2448,10 @@ static int virtnet_rx_resize(struct virtnet_info *vi,
qindex = rq - vi->rq;
- if (running)
+ if (running) {
napi_disable(&rq->napi);
+ cancel_work_sync(&rq->dim.work);
+ }
err = virtqueue_resize(rq->vq, ring_num, virtnet_rq_unmap_free_buf);
if (err)
@@ -2650,8 +2698,10 @@ static int virtnet_close(struct net_device *dev)
/* Make sure refill_work doesn't re-enable napi! */
cancel_delayed_work_sync(&vi->refill);
- for (i = 0; i < vi->max_queue_pairs; i++)
+ for (i = 0; i < vi->max_queue_pairs; i++) {
virtnet_disable_queue_pair(vi, i);
+ cancel_work_sync(&vi->rq[i].dim.work);
+ }
return 0;
}
@@ -2858,6 +2908,58 @@ static void virtnet_cpu_notif_remove(struct virtnet_info *vi)
&vi->node_dead);
}
+static int virtnet_send_ctrl_coal_vq_cmd(struct virtnet_info *vi,
+ u16 vqn, u32 max_usecs, u32 max_packets)
+{
+ struct scatterlist sgs;
+
+ vi->ctrl->coal_vq.vqn = cpu_to_le16(vqn);
+ vi->ctrl->coal_vq.coal.max_usecs = cpu_to_le32(max_usecs);
+ vi->ctrl->coal_vq.coal.max_packets = cpu_to_le32(max_packets);
+ sg_init_one(&sgs, &vi->ctrl->coal_vq, sizeof(vi->ctrl->coal_vq));
+
+ if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
+ VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET,
+ &sgs))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int virtnet_send_rx_ctrl_coal_vq_cmd(struct virtnet_info *vi,
+ u16 queue, u32 max_usecs,
+ u32 max_packets)
+{
+ int err;
+
+ err = virtnet_send_ctrl_coal_vq_cmd(vi, rxq2vq(queue),
+ max_usecs, max_packets);
+ if (err)
+ return err;
+
+ vi->rq[queue].intr_coal.max_usecs = max_usecs;
+ vi->rq[queue].intr_coal.max_packets = max_packets;
+
+ return 0;
+}
+
+static int virtnet_send_tx_ctrl_coal_vq_cmd(struct virtnet_info *vi,
+ u16 queue, u32 max_usecs,
+ u32 max_packets)
+{
+ int err;
+
+ err = virtnet_send_ctrl_coal_vq_cmd(vi, txq2vq(queue),
+ max_usecs, max_packets);
+ if (err)
+ return err;
+
+ vi->sq[queue].intr_coal.max_usecs = max_usecs;
+ vi->sq[queue].intr_coal.max_packets = max_packets;
+
+ return 0;
+}
+
static void virtnet_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -2871,9 +2973,6 @@ static void virtnet_get_ringparam(struct net_device *dev,
ring->tx_pending = virtqueue_get_vring_size(vi->sq[0].vq);
}
-static int virtnet_send_ctrl_coal_vq_cmd(struct virtnet_info *vi,
- u16 vqn, u32 max_usecs, u32 max_packets);
-
static int virtnet_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ring,
struct kernel_ethtool_ringparam *kernel_ring,
@@ -2915,14 +3014,11 @@ static int virtnet_set_ringparam(struct net_device *dev,
* through the VIRTIO_NET_CTRL_NOTF_COAL_TX_SET command, or, if the driver
* did not set any TX coalescing parameters, to 0.
*/
- err = virtnet_send_ctrl_coal_vq_cmd(vi, txq2vq(i),
- vi->intr_coal_tx.max_usecs,
- vi->intr_coal_tx.max_packets);
+ err = virtnet_send_tx_ctrl_coal_vq_cmd(vi, i,
+ vi->intr_coal_tx.max_usecs,
+ vi->intr_coal_tx.max_packets);
if (err)
return err;
-
- vi->sq[i].intr_coal.max_usecs = vi->intr_coal_tx.max_usecs;
- vi->sq[i].intr_coal.max_packets = vi->intr_coal_tx.max_packets;
}
if (ring->rx_pending != rx_pending) {
@@ -2931,14 +3027,11 @@ static int virtnet_set_ringparam(struct net_device *dev,
return err;
/* The reason is same as the transmit virtqueue reset */
- err = virtnet_send_ctrl_coal_vq_cmd(vi, rxq2vq(i),
- vi->intr_coal_rx.max_usecs,
- vi->intr_coal_rx.max_packets);
+ err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, i,
+ vi->intr_coal_rx.max_usecs,
+ vi->intr_coal_rx.max_packets);
if (err)
return err;
-
- vi->rq[i].intr_coal.max_usecs = vi->intr_coal_rx.max_usecs;
- vi->rq[i].intr_coal.max_packets = vi->intr_coal_rx.max_packets;
}
}
@@ -3275,10 +3368,10 @@ static int virtnet_get_link_ksettings(struct net_device *dev,
return 0;
}
-static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
- struct ethtool_coalesce *ec)
+static int virtnet_send_tx_notf_coal_cmds(struct virtnet_info *vi,
+ struct ethtool_coalesce *ec)
{
- struct scatterlist sgs_tx, sgs_rx;
+ struct scatterlist sgs_tx;
int i;
vi->ctrl->coal_tx.tx_usecs = cpu_to_le32(ec->tx_coalesce_usecs);
@@ -3290,7 +3383,6 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
&sgs_tx))
return -EINVAL;
- /* Save parameters */
vi->intr_coal_tx.max_usecs = ec->tx_coalesce_usecs;
vi->intr_coal_tx.max_packets = ec->tx_max_coalesced_frames;
for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -3298,6 +3390,40 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
vi->sq[i].intr_coal.max_packets = ec->tx_max_coalesced_frames;
}
+ return 0;
+}
+
+static int virtnet_send_rx_notf_coal_cmds(struct virtnet_info *vi,
+ struct ethtool_coalesce *ec)
+{
+ bool rx_ctrl_dim_on = !!ec->use_adaptive_rx_coalesce;
+ struct scatterlist sgs_rx;
+ int i;
+
+ if (rx_ctrl_dim_on && !virtio_has_feature(vi->vdev, VIRTIO_NET_F_VQ_NOTF_COAL))
+ return -EOPNOTSUPP;
+
+ if (rx_ctrl_dim_on && (ec->rx_coalesce_usecs != vi->intr_coal_rx.max_usecs ||
+ ec->rx_max_coalesced_frames != vi->intr_coal_rx.max_packets))
+ return -EINVAL;
+
+ if (rx_ctrl_dim_on && !vi->rx_dim_enabled) {
+ vi->rx_dim_enabled = true;
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ vi->rq[i].dim_enabled = true;
+ return 0;
+ }
+
+ if (!rx_ctrl_dim_on && vi->rx_dim_enabled) {
+ vi->rx_dim_enabled = false;
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ vi->rq[i].dim_enabled = false;
+ }
+
+ /* Since the per-queue coalescing params can be set,
+ * we need apply the global new params even if they
+ * are not updated.
+ */
vi->ctrl->coal_rx.rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
vi->ctrl->coal_rx.rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
sg_init_one(&sgs_rx, &vi->ctrl->coal_rx, sizeof(vi->ctrl->coal_rx));
@@ -3307,7 +3433,6 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
&sgs_rx))
return -EINVAL;
- /* Save parameters */
vi->intr_coal_rx.max_usecs = ec->rx_coalesce_usecs;
vi->intr_coal_rx.max_packets = ec->rx_max_coalesced_frames;
for (i = 0; i < vi->max_queue_pairs; i++) {
@@ -3318,21 +3443,55 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
return 0;
}
-static int virtnet_send_ctrl_coal_vq_cmd(struct virtnet_info *vi,
- u16 vqn, u32 max_usecs, u32 max_packets)
+static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
+ struct ethtool_coalesce *ec)
{
- struct scatterlist sgs;
+ int err;
- vi->ctrl->coal_vq.vqn = cpu_to_le16(vqn);
- vi->ctrl->coal_vq.coal.max_usecs = cpu_to_le32(max_usecs);
- vi->ctrl->coal_vq.coal.max_packets = cpu_to_le32(max_packets);
- sg_init_one(&sgs, &vi->ctrl->coal_vq, sizeof(vi->ctrl->coal_vq));
+ err = virtnet_send_tx_notf_coal_cmds(vi, ec);
+ if (err)
+ return err;
- if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
- VIRTIO_NET_CTRL_NOTF_COAL_VQ_SET,
- &sgs))
+ err = virtnet_send_rx_notf_coal_cmds(vi, ec);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int virtnet_send_rx_notf_coal_vq_cmds(struct virtnet_info *vi,
+ struct ethtool_coalesce *ec,
+ u16 queue)
+{
+ bool rx_ctrl_dim_on = !!ec->use_adaptive_rx_coalesce;
+ bool cur_rx_dim = vi->rq[queue].dim_enabled;
+ u32 max_usecs, max_packets;
+ int err;
+
+ max_usecs = vi->rq[queue].intr_coal.max_usecs;
+ max_packets = vi->rq[queue].intr_coal.max_packets;
+
+ if (rx_ctrl_dim_on && (ec->rx_coalesce_usecs != max_usecs ||
+ ec->rx_max_coalesced_frames != max_packets))
return -EINVAL;
+ if (rx_ctrl_dim_on && !cur_rx_dim) {
+ vi->rq[queue].dim_enabled = true;
+ return 0;
+ }
+
+ if (!rx_ctrl_dim_on && cur_rx_dim)
+ vi->rq[queue].dim_enabled = false;
+
+ /* If no params are updated, userspace ethtool will
+ * reject the modification.
+ */
+ err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, queue,
+ ec->rx_coalesce_usecs,
+ ec->rx_max_coalesced_frames);
+ if (err)
+ return err;
+
return 0;
}
@@ -3342,27 +3501,62 @@ static int virtnet_send_notf_coal_vq_cmds(struct virtnet_info *vi,
{
int err;
- err = virtnet_send_ctrl_coal_vq_cmd(vi, rxq2vq(queue),
- ec->rx_coalesce_usecs,
- ec->rx_max_coalesced_frames);
+ err = virtnet_send_rx_notf_coal_vq_cmds(vi, ec, queue);
if (err)
return err;
- vi->rq[queue].intr_coal.max_usecs = ec->rx_coalesce_usecs;
- vi->rq[queue].intr_coal.max_packets = ec->rx_max_coalesced_frames;
-
- err = virtnet_send_ctrl_coal_vq_cmd(vi, txq2vq(queue),
- ec->tx_coalesce_usecs,
- ec->tx_max_coalesced_frames);
+ err = virtnet_send_tx_ctrl_coal_vq_cmd(vi, queue,
+ ec->tx_coalesce_usecs,
+ ec->tx_max_coalesced_frames);
if (err)
return err;
- vi->sq[queue].intr_coal.max_usecs = ec->tx_coalesce_usecs;
- vi->sq[queue].intr_coal.max_packets = ec->tx_max_coalesced_frames;
-
return 0;
}
+static void virtnet_rx_dim_work(struct work_struct *work)
+{
+ struct dim *dim = container_of(work, struct dim, work);
+ struct receive_queue *rq = container_of(dim,
+ struct receive_queue, dim);
+ struct virtnet_info *vi = rq->vq->vdev->priv;
+ struct net_device *dev = vi->dev;
+ struct dim_cq_moder update_moder;
+ int i, qnum, err;
+
+ if (!rtnl_trylock())
+ return;
+
+ /* Each rxq's work is queued by "net_dim()->schedule_work()"
+ * in response to NAPI traffic changes. Note that dim->profile_ix
+ * for each rxq is updated prior to the queuing action.
+ * So we only need to traverse and update profiles for all rxqs
+ * in the work which is holding rtnl_lock.
+ */
+ for (i = 0; i < vi->curr_queue_pairs; i++) {
+ rq = &vi->rq[i];
+ dim = &rq->dim;
+ qnum = rq - vi->rq;
+
+ if (!rq->dim_enabled)
+ continue;
+
+ update_moder = net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
+ if (update_moder.usec != rq->intr_coal.max_usecs ||
+ update_moder.pkts != rq->intr_coal.max_packets) {
+ err = virtnet_send_rx_ctrl_coal_vq_cmd(vi, qnum,
+ update_moder.usec,
+ update_moder.pkts);
+ if (err)
+ pr_debug("%s: Failed to send dim parameters on rxq%d\n",
+ dev->name, qnum);
+ dim->state = DIM_START_MEASURE;
+ }
+ }
+
+ rtnl_unlock();
+}
+
static int virtnet_coal_params_supported(struct ethtool_coalesce *ec)
{
/* usecs coalescing is supported only if VIRTIO_NET_F_NOTF_COAL
@@ -3444,6 +3638,7 @@ static int virtnet_get_coalesce(struct net_device *dev,
ec->tx_coalesce_usecs = vi->intr_coal_tx.max_usecs;
ec->tx_max_coalesced_frames = vi->intr_coal_tx.max_packets;
ec->rx_max_coalesced_frames = vi->intr_coal_rx.max_packets;
+ ec->use_adaptive_rx_coalesce = vi->rx_dim_enabled;
} else {
ec->rx_max_coalesced_frames = 1;
@@ -3501,6 +3696,7 @@ static int virtnet_get_per_queue_coalesce(struct net_device *dev,
ec->tx_coalesce_usecs = vi->sq[queue].intr_coal.max_usecs;
ec->tx_max_coalesced_frames = vi->sq[queue].intr_coal.max_packets;
ec->rx_max_coalesced_frames = vi->rq[queue].intr_coal.max_packets;
+ ec->use_adaptive_rx_coalesce = vi->rq[queue].dim_enabled;
} else {
ec->rx_max_coalesced_frames = 1;
@@ -3548,39 +3744,42 @@ static u32 virtnet_get_rxfh_indir_size(struct net_device *dev)
return ((struct virtnet_info *)netdev_priv(dev))->rss_indir_table_size;
}
-static int virtnet_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, u8 *hfunc)
+static int virtnet_get_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh)
{
struct virtnet_info *vi = netdev_priv(dev);
int i;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < vi->rss_indir_table_size; ++i)
- indir[i] = vi->ctrl->rss.indirection_table[i];
+ rxfh->indir[i] = vi->ctrl->rss.indirection_table[i];
}
- if (key)
- memcpy(key, vi->ctrl->rss.key, vi->rss_key_size);
+ if (rxfh->key)
+ memcpy(rxfh->key, vi->ctrl->rss.key, vi->rss_key_size);
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
return 0;
}
-static int virtnet_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key, const u8 hfunc)
+static int virtnet_set_rxfh(struct net_device *dev,
+ struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
struct virtnet_info *vi = netdev_priv(dev);
int i;
- if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (indir) {
+ if (rxfh->indir) {
for (i = 0; i < vi->rss_indir_table_size; ++i)
- vi->ctrl->rss.indirection_table[i] = indir[i];
+ vi->ctrl->rss.indirection_table[i] = rxfh->indir[i];
}
- if (key)
- memcpy(vi->ctrl->rss.key, key, vi->rss_key_size);
+ if (rxfh->key)
+ memcpy(vi->ctrl->rss.key, rxfh->key, vi->rss_key_size);
virtnet_commit_rss_command(vi);
@@ -3626,7 +3825,7 @@ static int virtnet_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info)
static const struct ethtool_ops virtnet_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES |
- ETHTOOL_COALESCE_USECS,
+ ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_USE_ADAPTIVE_RX,
.get_drvinfo = virtnet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = virtnet_get_ringparam,
@@ -4096,10 +4295,11 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
{
vq_callback_t **callbacks;
struct virtqueue **vqs;
- int ret = -ENOMEM;
- int i, total_vqs;
const char **names;
+ int ret = -ENOMEM;
+ int total_vqs;
bool *ctx;
+ u16 i;
/* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by
* possible N-1 RX/TX queue pairs used in multiqueue mode, followed by
@@ -4136,8 +4336,8 @@ static int virtnet_find_vqs(struct virtnet_info *vi)
for (i = 0; i < vi->max_queue_pairs; i++) {
callbacks[rxq2vq(i)] = skb_recv_done;
callbacks[txq2vq(i)] = skb_xmit_done;
- sprintf(vi->rq[i].name, "input.%d", i);
- sprintf(vi->sq[i].name, "output.%d", i);
+ sprintf(vi->rq[i].name, "input.%u", i);
+ sprintf(vi->sq[i].name, "output.%u", i);
names[rxq2vq(i)] = vi->rq[i].name;
names[txq2vq(i)] = vi->sq[i].name;
if (ctx)
@@ -4203,6 +4403,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
virtnet_poll_tx,
napi_tx ? napi_weight : 0);
+ INIT_WORK(&vi->rq[i].dim.work, virtnet_rx_dim_work);
+ vi->rq[i].dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+
sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg));
ewma_pkt_len_init(&vi->rq[i].mrg_avg_pkt_len);
sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg));
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 98c22d7d87a2..7e8008d5378a 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -245,20 +245,20 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
for (j = 0; j < adapter->num_tx_queues; j++) {
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
- ethtool_sprintf(&buf, vmxnet3_tq_dev_stats[i].desc);
+ ethtool_puts(&buf, vmxnet3_tq_dev_stats[i].desc);
for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
- ethtool_sprintf(&buf, vmxnet3_tq_driver_stats[i].desc);
+ ethtool_puts(&buf, vmxnet3_tq_driver_stats[i].desc);
}
for (j = 0; j < adapter->num_rx_queues; j++) {
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
- ethtool_sprintf(&buf, vmxnet3_rq_dev_stats[i].desc);
+ ethtool_puts(&buf, vmxnet3_rq_dev_stats[i].desc);
for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
- ethtool_sprintf(&buf, vmxnet3_rq_driver_stats[i].desc);
+ ethtool_puts(&buf, vmxnet3_rq_driver_stats[i].desc);
}
for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++)
- ethtool_sprintf(&buf, vmxnet3_global_stats[i].desc);
+ ethtool_puts(&buf, vmxnet3_global_stats[i].desc);
}
netdev_features_t vmxnet3_fix_features(struct net_device *netdev,
@@ -1136,27 +1136,26 @@ vmxnet3_get_rss_indir_size(struct net_device *netdev)
}
static int
-vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key, u8 *hfunc)
+vmxnet3_get_rss(struct net_device *netdev, struct ethtool_rxfh_param *rxfh)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
unsigned int n = rssConf->indTableSize;
- if (hfunc)
- *hfunc = ETH_RSS_HASH_TOP;
- if (!p)
+ rxfh->hfunc = ETH_RSS_HASH_TOP;
+ if (!rxfh->indir)
return 0;
if (n > UPT1_RSS_MAX_IND_TABLE_SIZE)
return 0;
while (n--)
- p[n] = rssConf->indTable[n];
+ rxfh->indir[n] = rssConf->indTable[n];
return 0;
}
static int
-vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key,
- const u8 hfunc)
+vmxnet3_set_rss(struct net_device *netdev, struct ethtool_rxfh_param *rxfh,
+ struct netlink_ext_ack *extack)
{
unsigned int i;
unsigned long flags;
@@ -1164,13 +1163,14 @@ vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key,
struct UPT1_RSSConf *rssConf = adapter->rss_conf;
/* We do not allow change in unsupported parameters */
- if (key ||
- (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->key ||
+ (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP;
- if (!p)
+ if (!rxfh->indir)
return 0;
for (i = 0; i < rssConf->indTableSize; i++)
- rssConf->indTable[i] = p[i];
+ rssConf->indTable[i] = rxfh->indir[i];
spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 412c3c0b6990..16106e088c63 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2379,7 +2379,17 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
else
udp_sum = !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
#if IS_ENABLED(CONFIG_IPV6)
- key.label = vxlan->cfg.label;
+ switch (vxlan->cfg.label_policy) {
+ case VXLAN_LABEL_FIXED:
+ key.label = vxlan->cfg.label;
+ break;
+ case VXLAN_LABEL_INHERIT:
+ key.label = ip_tunnel_get_flowlabel(old_iph, skb);
+ break;
+ default:
+ DEBUG_NET_WARN_ON_ONCE(1);
+ goto drop;
+ }
#endif
} else {
if (!info) {
@@ -3225,6 +3235,7 @@ static const struct net_device_ops vxlan_netdev_ether_ops = {
.ndo_fdb_get = vxlan_fdb_get,
.ndo_mdb_add = vxlan_mdb_add,
.ndo_mdb_del = vxlan_mdb_del,
+ .ndo_mdb_del_bulk = vxlan_mdb_del_bulk,
.ndo_mdb_dump = vxlan_mdb_dump,
.ndo_mdb_get = vxlan_mdb_get,
.ndo_fill_metadata_dst = vxlan_fill_metadata_dst,
@@ -3366,6 +3377,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_DF] = { .type = NLA_U8 },
[IFLA_VXLAN_VNIFILTER] = { .type = NLA_U8 },
[IFLA_VXLAN_LOCALBYPASS] = NLA_POLICY_MAX(NLA_U8, 1),
+ [IFLA_VXLAN_LABEL_POLICY] = NLA_POLICY_MAX(NLA_U32, VXLAN_LABEL_MAX),
};
static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[],
@@ -3740,6 +3752,12 @@ static int vxlan_config_validate(struct net *src_net, struct vxlan_config *conf,
return -EINVAL;
}
+ if (conf->label_policy && !use_ipv6) {
+ NL_SET_ERR_MSG(extack,
+ "Label policy only applies to IPv6 VXLAN devices");
+ return -EINVAL;
+ }
+
if (conf->remote_ifindex) {
struct net_device *lowerdev;
@@ -4082,6 +4100,8 @@ static int vxlan_nl2conf(struct nlattr *tb[], struct nlattr *data[],
if (data[IFLA_VXLAN_LABEL])
conf->label = nla_get_be32(data[IFLA_VXLAN_LABEL]) &
IPV6_FLOWLABEL_MASK;
+ if (data[IFLA_VXLAN_LABEL_POLICY])
+ conf->label_policy = nla_get_u32(data[IFLA_VXLAN_LABEL_POLICY]);
if (data[IFLA_VXLAN_LEARNING]) {
err = vxlan_nl2flag(conf, data, IFLA_VXLAN_LEARNING,
@@ -4398,6 +4418,7 @@ static size_t vxlan_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_TOS */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_DF */
nla_total_size(sizeof(__be32)) + /* IFLA_VXLAN_LABEL */
+ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LABEL_POLICY */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LEARNING */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_PROXY */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_RSC */
@@ -4471,6 +4492,7 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) ||
nla_put_u8(skb, IFLA_VXLAN_DF, vxlan->cfg.df) ||
nla_put_be32(skb, IFLA_VXLAN_LABEL, vxlan->cfg.label) ||
+ nla_put_u32(skb, IFLA_VXLAN_LABEL_POLICY, vxlan->cfg.label_policy) ||
nla_put_u8(skb, IFLA_VXLAN_LEARNING,
!!(vxlan->cfg.flags & VXLAN_F_LEARN)) ||
nla_put_u8(skb, IFLA_VXLAN_PROXY,
diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
index eb4c580b5cee..60eb95a06d55 100644
--- a/drivers/net/vxlan/vxlan_mdb.c
+++ b/drivers/net/vxlan/vxlan_mdb.c
@@ -74,6 +74,14 @@ struct vxlan_mdb_config {
u8 rt_protocol;
};
+struct vxlan_mdb_flush_desc {
+ union vxlan_addr remote_ip;
+ __be32 src_vni;
+ __be32 remote_vni;
+ __be16 remote_port;
+ u8 rt_protocol;
+};
+
static const struct rhashtable_params vxlan_mdb_rht_params = {
.head_offset = offsetof(struct vxlan_mdb_entry, rhnode),
.key_offset = offsetof(struct vxlan_mdb_entry, key),
@@ -1306,6 +1314,145 @@ int vxlan_mdb_del(struct net_device *dev, struct nlattr *tb[],
return err;
}
+static const struct nla_policy
+vxlan_mdbe_attrs_del_bulk_pol[MDBE_ATTR_MAX + 1] = {
+ [MDBE_ATTR_RTPROT] = NLA_POLICY_MIN(NLA_U8, RTPROT_STATIC),
+ [MDBE_ATTR_DST] = NLA_POLICY_RANGE(NLA_BINARY,
+ sizeof(struct in_addr),
+ sizeof(struct in6_addr)),
+ [MDBE_ATTR_DST_PORT] = { .type = NLA_U16 },
+ [MDBE_ATTR_VNI] = NLA_POLICY_FULL_RANGE(NLA_U32, &vni_range),
+ [MDBE_ATTR_SRC_VNI] = NLA_POLICY_FULL_RANGE(NLA_U32, &vni_range),
+ [MDBE_ATTR_STATE_MASK] = NLA_POLICY_MASK(NLA_U8, MDB_PERMANENT),
+};
+
+static int vxlan_mdb_flush_desc_init(struct vxlan_dev *vxlan,
+ struct vxlan_mdb_flush_desc *desc,
+ struct nlattr *tb[],
+ struct netlink_ext_ack *extack)
+{
+ struct br_mdb_entry *entry = nla_data(tb[MDBA_SET_ENTRY]);
+ struct nlattr *mdbe_attrs[MDBE_ATTR_MAX + 1];
+ int err;
+
+ if (entry->ifindex && entry->ifindex != vxlan->dev->ifindex) {
+ NL_SET_ERR_MSG_MOD(extack, "Invalid port net device");
+ return -EINVAL;
+ }
+
+ if (entry->vid) {
+ NL_SET_ERR_MSG_MOD(extack, "VID must not be specified");
+ return -EINVAL;
+ }
+
+ if (!tb[MDBA_SET_ENTRY_ATTRS])
+ return 0;
+
+ err = nla_parse_nested(mdbe_attrs, MDBE_ATTR_MAX,
+ tb[MDBA_SET_ENTRY_ATTRS],
+ vxlan_mdbe_attrs_del_bulk_pol, extack);
+ if (err)
+ return err;
+
+ if (mdbe_attrs[MDBE_ATTR_STATE_MASK]) {
+ u8 state_mask = nla_get_u8(mdbe_attrs[MDBE_ATTR_STATE_MASK]);
+
+ if ((state_mask & MDB_PERMANENT) && !(entry->state & MDB_PERMANENT)) {
+ NL_SET_ERR_MSG_MOD(extack, "Only permanent MDB entries are supported");
+ return -EINVAL;
+ }
+ }
+
+ if (mdbe_attrs[MDBE_ATTR_RTPROT])
+ desc->rt_protocol = nla_get_u8(mdbe_attrs[MDBE_ATTR_RTPROT]);
+
+ if (mdbe_attrs[MDBE_ATTR_DST])
+ vxlan_nla_get_addr(&desc->remote_ip, mdbe_attrs[MDBE_ATTR_DST]);
+
+ if (mdbe_attrs[MDBE_ATTR_DST_PORT])
+ desc->remote_port =
+ cpu_to_be16(nla_get_u16(mdbe_attrs[MDBE_ATTR_DST_PORT]));
+
+ if (mdbe_attrs[MDBE_ATTR_VNI])
+ desc->remote_vni =
+ cpu_to_be32(nla_get_u32(mdbe_attrs[MDBE_ATTR_VNI]));
+
+ if (mdbe_attrs[MDBE_ATTR_SRC_VNI])
+ desc->src_vni =
+ cpu_to_be32(nla_get_u32(mdbe_attrs[MDBE_ATTR_SRC_VNI]));
+
+ return 0;
+}
+
+static void vxlan_mdb_remotes_flush(struct vxlan_dev *vxlan,
+ struct vxlan_mdb_entry *mdb_entry,
+ const struct vxlan_mdb_flush_desc *desc)
+{
+ struct vxlan_mdb_remote *remote, *tmp;
+
+ list_for_each_entry_safe(remote, tmp, &mdb_entry->remotes, list) {
+ struct vxlan_rdst *rd = rtnl_dereference(remote->rd);
+ __be32 remote_vni;
+
+ if (desc->remote_ip.sa.sa_family &&
+ !vxlan_addr_equal(&desc->remote_ip, &rd->remote_ip))
+ continue;
+
+ /* Encapsulation is performed with source VNI if remote VNI
+ * is not set.
+ */
+ remote_vni = rd->remote_vni ? : mdb_entry->key.vni;
+ if (desc->remote_vni && desc->remote_vni != remote_vni)
+ continue;
+
+ if (desc->remote_port && desc->remote_port != rd->remote_port)
+ continue;
+
+ if (desc->rt_protocol &&
+ desc->rt_protocol != remote->rt_protocol)
+ continue;
+
+ vxlan_mdb_remote_del(vxlan, mdb_entry, remote);
+ }
+}
+
+static void vxlan_mdb_flush(struct vxlan_dev *vxlan,
+ const struct vxlan_mdb_flush_desc *desc)
+{
+ struct vxlan_mdb_entry *mdb_entry;
+ struct hlist_node *tmp;
+
+ /* The removal of an entry cannot trigger the removal of another entry
+ * since entries are always added to the head of the list.
+ */
+ hlist_for_each_entry_safe(mdb_entry, tmp, &vxlan->mdb_list, mdb_node) {
+ if (desc->src_vni && desc->src_vni != mdb_entry->key.vni)
+ continue;
+
+ vxlan_mdb_remotes_flush(vxlan, mdb_entry, desc);
+ /* Entry will only be removed if its remotes list is empty. */
+ vxlan_mdb_entry_put(vxlan, mdb_entry);
+ }
+}
+
+int vxlan_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[],
+ struct netlink_ext_ack *extack)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_mdb_flush_desc desc = {};
+ int err;
+
+ ASSERT_RTNL();
+
+ err = vxlan_mdb_flush_desc_init(vxlan, &desc, tb, extack);
+ if (err)
+ return err;
+
+ vxlan_mdb_flush(vxlan, &desc);
+
+ return 0;
+}
+
static const struct nla_policy vxlan_mdbe_attrs_get_pol[MDBE_ATTR_MAX + 1] = {
[MDBE_ATTR_SOURCE] = NLA_POLICY_RANGE(NLA_BINARY,
sizeof(struct in_addr),
@@ -1575,29 +1722,6 @@ static void vxlan_mdb_check_empty(void *ptr, void *arg)
WARN_ON_ONCE(1);
}
-static void vxlan_mdb_remotes_flush(struct vxlan_dev *vxlan,
- struct vxlan_mdb_entry *mdb_entry)
-{
- struct vxlan_mdb_remote *remote, *tmp;
-
- list_for_each_entry_safe(remote, tmp, &mdb_entry->remotes, list)
- vxlan_mdb_remote_del(vxlan, mdb_entry, remote);
-}
-
-static void vxlan_mdb_entries_flush(struct vxlan_dev *vxlan)
-{
- struct vxlan_mdb_entry *mdb_entry;
- struct hlist_node *tmp;
-
- /* The removal of an entry cannot trigger the removal of another entry
- * since entries are always added to the head of the list.
- */
- hlist_for_each_entry_safe(mdb_entry, tmp, &vxlan->mdb_list, mdb_node) {
- vxlan_mdb_remotes_flush(vxlan, mdb_entry);
- vxlan_mdb_entry_put(vxlan, mdb_entry);
- }
-}
-
int vxlan_mdb_init(struct vxlan_dev *vxlan)
{
int err;
@@ -1613,7 +1737,9 @@ int vxlan_mdb_init(struct vxlan_dev *vxlan)
void vxlan_mdb_fini(struct vxlan_dev *vxlan)
{
- vxlan_mdb_entries_flush(vxlan);
+ struct vxlan_mdb_flush_desc desc = {};
+
+ vxlan_mdb_flush(vxlan, &desc);
WARN_ON_ONCE(vxlan->cfg.flags & VXLAN_F_MDB);
rhashtable_free_and_destroy(&vxlan->mdb_tbl, vxlan_mdb_check_empty,
NULL);
diff --git a/drivers/net/vxlan/vxlan_private.h b/drivers/net/vxlan/vxlan_private.h
index db679c380955..b35d96b78843 100644
--- a/drivers/net/vxlan/vxlan_private.h
+++ b/drivers/net/vxlan/vxlan_private.h
@@ -235,6 +235,8 @@ int vxlan_mdb_add(struct net_device *dev, struct nlattr *tb[], u16 nlmsg_flags,
struct netlink_ext_ack *extack);
int vxlan_mdb_del(struct net_device *dev, struct nlattr *tb[],
struct netlink_ext_ack *extack);
+int vxlan_mdb_del_bulk(struct net_device *dev, struct nlattr *tb[],
+ struct netlink_ext_ack *extack);
int vxlan_mdb_get(struct net_device *dev, struct nlattr *tb[], u32 portid,
u32 seq, struct netlink_ext_ack *extack);
struct vxlan_mdb_entry *vxlan_mdb_entry_skb_get(struct vxlan_dev *vxlan,
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index dcb069dde66b..7dda87756d3f 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -95,6 +95,8 @@ config HDLC_X25
comment "X.25/LAPB support is disabled"
depends on HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y
+source "drivers/net/wan/framer/Kconfig"
+
config PCI200SYN
tristate "Goramo PCI200SYN support"
depends on HDLC && PCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 5bec8fae47f8..8119b49d1da9 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
+obj-y += framer/
+
obj-$(CONFIG_FARSYNC) += farsync.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
diff --git a/drivers/net/wan/framer/Kconfig b/drivers/net/wan/framer/Kconfig
new file mode 100644
index 000000000000..dc83caef9485
--- /dev/null
+++ b/drivers/net/wan/framer/Kconfig
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# FRAMER
+#
+
+menuconfig FRAMER
+ tristate "Framer Subsystem"
+ help
+ A framer is a component in charge of an E1/T1 line interface.
+ Connected usually to a TDM bus, it converts TDM frames to/from E1/T1
+ frames. It also provides information related to the E1/T1 line.
+ Used with HDLC, the network can be reached through the E1/T1 line.
+
+ This framework is designed to provide a generic interface for framer
+ devices present in the kernel. This layer will have the generic
+ API by which framer drivers can create framer using the framer
+ framework and framer users can obtain reference to the framer.
+ All the users of this framework should select this config.
+
+if FRAMER
+
+config GENERIC_FRAMER
+ bool
+
+config FRAMER_PEF2256
+ tristate "Lantiq PEF2256"
+ depends on OF
+ depends on HAS_IOMEM
+ select GENERIC_FRAMER
+ select MFD_CORE
+ select REGMAP_MMIO
+ help
+ Enable support for the Lantiq PEF2256 (FALC56) framer.
+ The PEF2256 is a framer and line interface between analog E1/T1/J1
+ line and a digital PCM bus.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called framer-pef2256.
+
+endif # FRAMER
diff --git a/drivers/net/wan/framer/Makefile b/drivers/net/wan/framer/Makefile
new file mode 100644
index 000000000000..3403f2b14534
--- /dev/null
+++ b/drivers/net/wan/framer/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the framer drivers.
+#
+
+obj-$(CONFIG_GENERIC_FRAMER) += framer-core.o
+obj-$(CONFIG_FRAMER_PEF2256) += pef2256/
diff --git a/drivers/net/wan/framer/framer-core.c b/drivers/net/wan/framer/framer-core.c
new file mode 100644
index 000000000000..c04dc88bda6c
--- /dev/null
+++ b/drivers/net/wan/framer/framer-core.c
@@ -0,0 +1,882 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Generic Framer framework.
+ *
+ * Copyright 2023 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/framer/framer.h>
+#include <linux/framer/framer-provider.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+static struct class *framer_class;
+static DEFINE_MUTEX(framer_provider_mutex);
+static LIST_HEAD(framer_provider_list);
+static DEFINE_IDA(framer_ida);
+
+#define dev_to_framer(a) (container_of((a), struct framer, dev))
+
+int framer_pm_runtime_get(struct framer *framer)
+{
+ int ret;
+
+ if (!pm_runtime_enabled(&framer->dev))
+ return -EOPNOTSUPP;
+
+ ret = pm_runtime_get(&framer->dev);
+ if (ret < 0 && ret != -EINPROGRESS)
+ pm_runtime_put_noidle(&framer->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_pm_runtime_get);
+
+int framer_pm_runtime_get_sync(struct framer *framer)
+{
+ int ret;
+
+ if (!pm_runtime_enabled(&framer->dev))
+ return -EOPNOTSUPP;
+
+ ret = pm_runtime_get_sync(&framer->dev);
+ if (ret < 0)
+ pm_runtime_put_sync(&framer->dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_pm_runtime_get_sync);
+
+int framer_pm_runtime_put(struct framer *framer)
+{
+ if (!pm_runtime_enabled(&framer->dev))
+ return -EOPNOTSUPP;
+
+ return pm_runtime_put(&framer->dev);
+}
+EXPORT_SYMBOL_GPL(framer_pm_runtime_put);
+
+int framer_pm_runtime_put_sync(struct framer *framer)
+{
+ if (!pm_runtime_enabled(&framer->dev))
+ return -EOPNOTSUPP;
+
+ return pm_runtime_put_sync(&framer->dev);
+}
+EXPORT_SYMBOL_GPL(framer_pm_runtime_put_sync);
+
+/**
+ * framer_init - framer internal initialization before framer operation
+ * @framer: the framer returned by framer_get()
+ *
+ * Used to allow framer's driver to perform framer internal initialization,
+ * such as PLL block powering, clock initialization or anything that's
+ * is required by the framer to perform the start of operation.
+ * Must be called before framer_power_on().
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_init(struct framer *framer)
+{
+ bool start_polling = false;
+ int ret;
+
+ ret = framer_pm_runtime_get_sync(framer);
+ if (ret < 0 && ret != -EOPNOTSUPP)
+ return ret;
+ ret = 0; /* Override possible ret == -EOPNOTSUPP */
+
+ mutex_lock(&framer->mutex);
+ if (framer->power_count > framer->init_count)
+ dev_warn(&framer->dev, "framer_power_on was called before framer init\n");
+
+ if (framer->init_count == 0) {
+ if (framer->ops->init) {
+ ret = framer->ops->init(framer);
+ if (ret < 0) {
+ dev_err(&framer->dev, "framer init failed --> %d\n", ret);
+ goto out;
+ }
+ }
+ if (framer->ops->flags & FRAMER_FLAG_POLL_STATUS)
+ start_polling = true;
+ }
+ ++framer->init_count;
+
+out:
+ mutex_unlock(&framer->mutex);
+
+ if (!ret && start_polling) {
+ ret = framer_get_status(framer, &framer->prev_status);
+ if (ret < 0) {
+ dev_warn(&framer->dev, "framer get status failed --> %d\n", ret);
+ /* Will be retried on polling_work */
+ ret = 0;
+ }
+ queue_delayed_work(system_power_efficient_wq, &framer->polling_work, 1 * HZ);
+ }
+
+ framer_pm_runtime_put(framer);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_init);
+
+/**
+ * framer_exit - Framer internal un-initialization
+ * @framer: the framer returned by framer_get()
+ *
+ * Must be called after framer_power_off().
+ */
+int framer_exit(struct framer *framer)
+{
+ int ret;
+
+ ret = framer_pm_runtime_get_sync(framer);
+ if (ret < 0 && ret != -EOPNOTSUPP)
+ return ret;
+ ret = 0; /* Override possible ret == -EOPNOTSUPP */
+
+ mutex_lock(&framer->mutex);
+ --framer->init_count;
+ if (framer->init_count == 0) {
+ if (framer->ops->flags & FRAMER_FLAG_POLL_STATUS) {
+ mutex_unlock(&framer->mutex);
+ cancel_delayed_work_sync(&framer->polling_work);
+ mutex_lock(&framer->mutex);
+ }
+
+ if (framer->ops->exit)
+ framer->ops->exit(framer);
+ }
+
+ mutex_unlock(&framer->mutex);
+ framer_pm_runtime_put(framer);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_exit);
+
+/**
+ * framer_power_on - Enable the framer and enter proper operation
+ * @framer: the framer returned by framer_get()
+ *
+ * Must be called after framer_init().
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_power_on(struct framer *framer)
+{
+ int ret;
+
+ if (framer->pwr) {
+ ret = regulator_enable(framer->pwr);
+ if (ret)
+ return ret;
+ }
+
+ ret = framer_pm_runtime_get_sync(framer);
+ if (ret < 0 && ret != -EOPNOTSUPP)
+ goto err_pm_sync;
+
+ mutex_lock(&framer->mutex);
+ if (framer->power_count == 0 && framer->ops->power_on) {
+ ret = framer->ops->power_on(framer);
+ if (ret < 0) {
+ dev_err(&framer->dev, "framer poweron failed --> %d\n", ret);
+ goto err_pwr_on;
+ }
+ }
+ ++framer->power_count;
+ mutex_unlock(&framer->mutex);
+ return 0;
+
+err_pwr_on:
+ mutex_unlock(&framer->mutex);
+ framer_pm_runtime_put_sync(framer);
+err_pm_sync:
+ if (framer->pwr)
+ regulator_disable(framer->pwr);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_power_on);
+
+/**
+ * framer_power_off - Disable the framer.
+ * @framer: the framer returned by framer_get()
+ *
+ * Must be called before framer_exit().
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_power_off(struct framer *framer)
+{
+ int ret;
+
+ mutex_lock(&framer->mutex);
+ if (framer->power_count == 1 && framer->ops->power_off) {
+ ret = framer->ops->power_off(framer);
+ if (ret < 0) {
+ dev_err(&framer->dev, "framer poweroff failed --> %d\n", ret);
+ mutex_unlock(&framer->mutex);
+ return ret;
+ }
+ }
+ --framer->power_count;
+ mutex_unlock(&framer->mutex);
+ framer_pm_runtime_put(framer);
+
+ if (framer->pwr)
+ regulator_disable(framer->pwr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(framer_power_off);
+
+/**
+ * framer_get_status() - Gets the framer status
+ * @framer: the framer returned by framer_get()
+ * @status: the status to retrieve
+ *
+ * Used to get the framer status. framer_init() must have been called
+ * on the framer.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_get_status(struct framer *framer, struct framer_status *status)
+{
+ int ret;
+
+ if (!framer->ops->get_status)
+ return -EOPNOTSUPP;
+
+ /* Be sure to have known values (struct padding and future extensions) */
+ memset(status, 0, sizeof(*status));
+
+ mutex_lock(&framer->mutex);
+ ret = framer->ops->get_status(framer, status);
+ mutex_unlock(&framer->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_get_status);
+
+/**
+ * framer_set_config() - Sets the framer configuration
+ * @framer: the framer returned by framer_get()
+ * @config: the configuration to set
+ *
+ * Used to set the framer configuration. framer_init() must have been called
+ * on the framer.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_set_config(struct framer *framer, const struct framer_config *config)
+{
+ int ret;
+
+ if (!framer->ops->set_config)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&framer->mutex);
+ ret = framer->ops->set_config(framer, config);
+ mutex_unlock(&framer->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_set_config);
+
+/**
+ * framer_get_config() - Gets the framer configuration
+ * @framer: the framer returned by framer_get()
+ * @config: the configuration to retrieve
+ *
+ * Used to get the framer configuration. framer_init() must have been called
+ * on the framer.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_get_config(struct framer *framer, struct framer_config *config)
+{
+ int ret;
+
+ if (!framer->ops->get_config)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&framer->mutex);
+ ret = framer->ops->get_config(framer, config);
+ mutex_unlock(&framer->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(framer_get_config);
+
+static void framer_polling_work(struct work_struct *work)
+{
+ struct framer *framer = container_of(work, struct framer, polling_work.work);
+ struct framer_status status;
+ int ret;
+
+ ret = framer_get_status(framer, &status);
+ if (ret) {
+ dev_err(&framer->dev, "polling, get status failed (%d)\n", ret);
+ goto end;
+ }
+ if (memcmp(&framer->prev_status, &status, sizeof(status))) {
+ blocking_notifier_call_chain(&framer->notifier_list,
+ FRAMER_EVENT_STATUS, NULL);
+ memcpy(&framer->prev_status, &status, sizeof(status));
+ }
+
+end:
+ /* Re-schedule task in 1 sec */
+ queue_delayed_work(system_power_efficient_wq, &framer->polling_work, 1 * HZ);
+}
+
+/**
+ * framer_notifier_register() - Registers a notifier
+ * @framer: the framer returned by framer_get()
+ * @nb: the notifier block to register
+ *
+ * Used to register a notifier block on framer events. framer_init() must have
+ * been called on the framer.
+ * The available framer events are present in enum framer_events.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_notifier_register(struct framer *framer, struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&framer->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(framer_notifier_register);
+
+/**
+ * framer_notifier_unregister() - Unregisters a notifier
+ * @framer: the framer returned by framer_get()
+ * @nb: the notifier block to unregister
+ *
+ * Used to unregister a notifier block. framer_init() must have
+ * been called on the framer.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int framer_notifier_unregister(struct framer *framer, struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&framer->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(framer_notifier_unregister);
+
+static struct framer_provider *framer_provider_of_lookup(const struct device_node *node)
+{
+ struct framer_provider *framer_provider;
+
+ list_for_each_entry(framer_provider, &framer_provider_list, list) {
+ if (device_match_of_node(framer_provider->dev, node))
+ return framer_provider;
+ }
+
+ return ERR_PTR(-EPROBE_DEFER);
+}
+
+static struct framer *framer_of_get_from_provider(struct of_phandle_args *args)
+{
+ struct framer_provider *framer_provider;
+ struct framer *framer;
+
+ mutex_lock(&framer_provider_mutex);
+ framer_provider = framer_provider_of_lookup(args->np);
+ if (IS_ERR(framer_provider) || !try_module_get(framer_provider->owner)) {
+ framer = ERR_PTR(-EPROBE_DEFER);
+ goto end;
+ }
+
+ framer = framer_provider->of_xlate(framer_provider->dev, args);
+
+ module_put(framer_provider->owner);
+
+end:
+ mutex_unlock(&framer_provider_mutex);
+
+ return framer;
+}
+
+static struct framer *framer_of_get_byphandle(struct device_node *np, const char *propname,
+ int index)
+{
+ struct of_phandle_args args;
+ struct framer *framer;
+ int ret;
+
+ ret = of_parse_phandle_with_optional_args(np, propname, "#framer-cells", index, &args);
+ if (ret)
+ return ERR_PTR(-ENODEV);
+
+ if (!of_device_is_available(args.np)) {
+ framer = ERR_PTR(-ENODEV);
+ goto out_node_put;
+ }
+
+ framer = framer_of_get_from_provider(&args);
+
+out_node_put:
+ of_node_put(args.np);
+
+ return framer;
+}
+
+static struct framer *framer_of_get_byparent(struct device_node *np, int index)
+{
+ struct of_phandle_args args;
+ struct framer *framer;
+
+ args.np = of_get_parent(np);
+ args.args_count = 1;
+ args.args[0] = index;
+
+ while (args.np) {
+ framer = framer_of_get_from_provider(&args);
+ if (IS_ERR(framer) && PTR_ERR(framer) != -EPROBE_DEFER) {
+ args.np = of_get_next_parent(args.np);
+ continue;
+ }
+ of_node_put(args.np);
+ return framer;
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
+/**
+ * framer_get() - lookup and obtain a reference to a framer.
+ * @dev: device that requests the framer
+ * @con_id: name of the framer from device's point of view
+ *
+ * Returns the framer driver, after getting a refcount to it; or
+ * -ENODEV if there is no such framer. The caller is responsible for
+ * calling framer_put() to release that count.
+ */
+struct framer *framer_get(struct device *dev, const char *con_id)
+{
+ struct framer *framer = ERR_PTR(-ENODEV);
+ struct device_link *link;
+ int ret;
+
+ if (dev->of_node) {
+ if (con_id)
+ framer = framer_of_get_byphandle(dev->of_node, con_id, 0);
+ else
+ framer = framer_of_get_byparent(dev->of_node, 0);
+ }
+
+ if (IS_ERR(framer))
+ return framer;
+
+ get_device(&framer->dev);
+
+ if (!try_module_get(framer->ops->owner)) {
+ ret = -EPROBE_DEFER;
+ goto err_put_device;
+ }
+
+ link = device_link_add(dev, &framer->dev, DL_FLAG_STATELESS);
+ if (!link) {
+ dev_err(dev, "failed to create device_link to %s\n", dev_name(&framer->dev));
+ ret = -EPROBE_DEFER;
+ goto err_module_put;
+ }
+
+ return framer;
+
+err_module_put:
+ module_put(framer->ops->owner);
+err_put_device:
+ put_device(&framer->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(framer_get);
+
+/**
+ * framer_put() - release the framer
+ * @dev: device that wants to release this framer
+ * @framer: the framer returned by framer_get()
+ *
+ * Releases a refcount the caller received from framer_get().
+ */
+void framer_put(struct device *dev, struct framer *framer)
+{
+ device_link_remove(dev, &framer->dev);
+
+ module_put(framer->ops->owner);
+ put_device(&framer->dev);
+}
+EXPORT_SYMBOL_GPL(framer_put);
+
+static void devm_framer_put(struct device *dev, void *res)
+{
+ struct framer *framer = *(struct framer **)res;
+
+ framer_put(dev, framer);
+}
+
+/**
+ * devm_framer_get() - lookup and obtain a reference to a framer.
+ * @dev: device that requests this framer
+ * @con_id: name of the framer from device's point of view
+ *
+ * Gets the framer using framer_get(), and associates a device with it using
+ * devres. On driver detach, framer_put() function is invoked on the devres
+ * data, then, devres data is freed.
+ */
+struct framer *devm_framer_get(struct device *dev, const char *con_id)
+{
+ struct framer **ptr, *framer;
+
+ ptr = devres_alloc(devm_framer_put, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ framer = framer_get(dev, con_id);
+ if (!IS_ERR(framer)) {
+ *ptr = framer;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ return framer;
+ }
+
+ return framer;
+}
+EXPORT_SYMBOL_GPL(devm_framer_get);
+
+/**
+ * devm_framer_optional_get() - lookup and obtain a reference to an optional
+ * framer.
+ * @dev: device that requests this framer
+ * @con_id: name of the framer from device's point of view
+ *
+ * Same as devm_framer_get() except that if the framer does not exist, it is not
+ * considered an error and -ENODEV will not be returned. Instead the NULL framer
+ * is returned.
+ */
+struct framer *devm_framer_optional_get(struct device *dev, const char *con_id)
+{
+ struct framer *framer = devm_framer_get(dev, con_id);
+
+ if (PTR_ERR(framer) == -ENODEV)
+ framer = NULL;
+
+ return framer;
+}
+EXPORT_SYMBOL_GPL(devm_framer_optional_get);
+
+static void framer_notify_status_work(struct work_struct *work)
+{
+ struct framer *framer = container_of(work, struct framer, notify_status_work);
+
+ blocking_notifier_call_chain(&framer->notifier_list, FRAMER_EVENT_STATUS, NULL);
+}
+
+void framer_notify_status_change(struct framer *framer)
+{
+ /* Can be called from atomic context -> just schedule a task to call
+ * blocking notifiers
+ */
+ queue_work(system_power_efficient_wq, &framer->notify_status_work);
+}
+EXPORT_SYMBOL_GPL(framer_notify_status_change);
+
+/**
+ * framer_create() - create a new framer
+ * @dev: device that is creating the new framer
+ * @node: device node of the framer. default to dev->of_node.
+ * @ops: function pointers for performing framer operations
+ *
+ * Called to create a framer using framer framework.
+ */
+struct framer *framer_create(struct device *dev, struct device_node *node,
+ const struct framer_ops *ops)
+{
+ struct framer *framer;
+ int ret;
+ int id;
+
+ /* get_status() is mandatory if the provider ask for polling status */
+ if (WARN_ON((ops->flags & FRAMER_FLAG_POLL_STATUS) && !ops->get_status))
+ return ERR_PTR(-EINVAL);
+
+ framer = kzalloc(sizeof(*framer), GFP_KERNEL);
+ if (!framer)
+ return ERR_PTR(-ENOMEM);
+
+ id = ida_alloc(&framer_ida, GFP_KERNEL);
+ if (id < 0) {
+ dev_err(dev, "unable to get id\n");
+ ret = id;
+ goto free_framer;
+ }
+
+ device_initialize(&framer->dev);
+ mutex_init(&framer->mutex);
+ INIT_WORK(&framer->notify_status_work, framer_notify_status_work);
+ INIT_DELAYED_WORK(&framer->polling_work, framer_polling_work);
+ BLOCKING_INIT_NOTIFIER_HEAD(&framer->notifier_list);
+
+ framer->dev.class = framer_class;
+ framer->dev.parent = dev;
+ framer->dev.of_node = node ? node : dev->of_node;
+ framer->id = id;
+ framer->ops = ops;
+
+ ret = dev_set_name(&framer->dev, "framer-%s.%d", dev_name(dev), id);
+ if (ret)
+ goto put_dev;
+
+ /* framer-supply */
+ framer->pwr = regulator_get_optional(&framer->dev, "framer");
+ if (IS_ERR(framer->pwr)) {
+ ret = PTR_ERR(framer->pwr);
+ if (ret == -EPROBE_DEFER)
+ goto put_dev;
+
+ framer->pwr = NULL;
+ }
+
+ ret = device_add(&framer->dev);
+ if (ret)
+ goto put_dev;
+
+ if (pm_runtime_enabled(dev)) {
+ pm_runtime_enable(&framer->dev);
+ pm_runtime_no_callbacks(&framer->dev);
+ }
+
+ return framer;
+
+put_dev:
+ put_device(&framer->dev); /* calls framer_release() which frees resources */
+ return ERR_PTR(ret);
+
+free_framer:
+ kfree(framer);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(framer_create);
+
+/**
+ * framer_destroy() - destroy the framer
+ * @framer: the framer to be destroyed
+ *
+ * Called to destroy the framer.
+ */
+void framer_destroy(struct framer *framer)
+{
+ /* polling_work should already be stopped but if framer_exit() was not
+ * called (bug), here it's the last time to do that ...
+ */
+ cancel_delayed_work_sync(&framer->polling_work);
+ cancel_work_sync(&framer->notify_status_work);
+ pm_runtime_disable(&framer->dev);
+ device_unregister(&framer->dev); /* calls framer_release() which frees resources */
+}
+EXPORT_SYMBOL_GPL(framer_destroy);
+
+static void devm_framer_destroy(struct device *dev, void *res)
+{
+ struct framer *framer = *(struct framer **)res;
+
+ framer_destroy(framer);
+}
+
+/**
+ * devm_framer_create() - create a new framer
+ * @dev: device that is creating the new framer
+ * @node: device node of the framer
+ * @ops: function pointers for performing framer operations
+ *
+ * Creates a new framer device adding it to the framer class.
+ * While at that, it also associates the device with the framer using devres.
+ * On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct framer *devm_framer_create(struct device *dev, struct device_node *node,
+ const struct framer_ops *ops)
+{
+ struct framer **ptr, *framer;
+
+ ptr = devres_alloc(devm_framer_destroy, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ framer = framer_create(dev, node, ops);
+ if (!IS_ERR(framer)) {
+ *ptr = framer;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return framer;
+}
+EXPORT_SYMBOL_GPL(devm_framer_create);
+
+/**
+ * framer_provider_simple_of_xlate() - returns the framer instance from framer provider
+ * @dev: the framer provider device
+ * @args: of_phandle_args (not used here)
+ *
+ * Intended to be used by framer provider for the common case where #framer-cells is
+ * 0. For other cases where #framer-cells is greater than '0', the framer provider
+ * should provide a custom of_xlate function that reads the *args* and returns
+ * the appropriate framer.
+ */
+struct framer *framer_provider_simple_of_xlate(struct device *dev, struct of_phandle_args *args)
+{
+ struct class_dev_iter iter;
+ struct framer *framer;
+
+ class_dev_iter_init(&iter, framer_class, NULL, NULL);
+ while ((dev = class_dev_iter_next(&iter))) {
+ framer = dev_to_framer(dev);
+ if (args->np != framer->dev.of_node)
+ continue;
+
+ class_dev_iter_exit(&iter);
+ return framer;
+ }
+
+ class_dev_iter_exit(&iter);
+ return ERR_PTR(-ENODEV);
+}
+EXPORT_SYMBOL_GPL(framer_provider_simple_of_xlate);
+
+/**
+ * __framer_provider_of_register() - create/register framer provider with the framework
+ * @dev: struct device of the framer provider
+ * @owner: the module owner containing of_xlate
+ * @of_xlate: function pointer to obtain framer instance from framer provider
+ *
+ * Creates struct framer_provider from dev and of_xlate function pointer.
+ * This is used in the case of dt boot for finding the framer instance from
+ * framer provider.
+ */
+struct framer_provider *
+__framer_provider_of_register(struct device *dev, struct module *owner,
+ struct framer *(*of_xlate)(struct device *dev,
+ struct of_phandle_args *args))
+{
+ struct framer_provider *framer_provider;
+
+ framer_provider = kzalloc(sizeof(*framer_provider), GFP_KERNEL);
+ if (!framer_provider)
+ return ERR_PTR(-ENOMEM);
+
+ framer_provider->dev = dev;
+ framer_provider->owner = owner;
+ framer_provider->of_xlate = of_xlate;
+
+ of_node_get(framer_provider->dev->of_node);
+
+ mutex_lock(&framer_provider_mutex);
+ list_add_tail(&framer_provider->list, &framer_provider_list);
+ mutex_unlock(&framer_provider_mutex);
+
+ return framer_provider;
+}
+EXPORT_SYMBOL_GPL(__framer_provider_of_register);
+
+/**
+ * framer_provider_of_unregister() - unregister framer provider from the framework
+ * @framer_provider: framer provider returned by framer_provider_of_register()
+ *
+ * Removes the framer_provider created using framer_provider_of_register().
+ */
+void framer_provider_of_unregister(struct framer_provider *framer_provider)
+{
+ mutex_lock(&framer_provider_mutex);
+ list_del(&framer_provider->list);
+ mutex_unlock(&framer_provider_mutex);
+
+ of_node_put(framer_provider->dev->of_node);
+ kfree(framer_provider);
+}
+EXPORT_SYMBOL_GPL(framer_provider_of_unregister);
+
+static void devm_framer_provider_of_unregister(struct device *dev, void *res)
+{
+ struct framer_provider *framer_provider = *(struct framer_provider **)res;
+
+ framer_provider_of_unregister(framer_provider);
+}
+
+/**
+ * __devm_framer_provider_of_register() - create/register framer provider with
+ * the framework
+ * @dev: struct device of the framer provider
+ * @owner: the module owner containing of_xlate
+ * @of_xlate: function pointer to obtain framer instance from framer provider
+ *
+ * Creates struct framer_provider from dev and of_xlate function pointer.
+ * This is used in the case of dt boot for finding the framer instance from
+ * framer provider. While at that, it also associates the device with the
+ * framer provider using devres. On driver detach, release function is invoked
+ * on the devres data, then, devres data is freed.
+ */
+struct framer_provider *
+__devm_framer_provider_of_register(struct device *dev, struct module *owner,
+ struct framer *(*of_xlate)(struct device *dev,
+ struct of_phandle_args *args))
+{
+ struct framer_provider **ptr, *framer_provider;
+
+ ptr = devres_alloc(devm_framer_provider_of_unregister, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ framer_provider = __framer_provider_of_register(dev, owner, of_xlate);
+ if (!IS_ERR(framer_provider)) {
+ *ptr = framer_provider;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return framer_provider;
+}
+EXPORT_SYMBOL_GPL(__devm_framer_provider_of_register);
+
+/**
+ * framer_release() - release the framer
+ * @dev: the dev member within framer
+ *
+ * When the last reference to the device is removed, it is called
+ * from the embedded kobject as release method.
+ */
+static void framer_release(struct device *dev)
+{
+ struct framer *framer;
+
+ framer = dev_to_framer(dev);
+ regulator_put(framer->pwr);
+ ida_free(&framer_ida, framer->id);
+ kfree(framer);
+}
+
+static int __init framer_core_init(void)
+{
+ framer_class = class_create("framer");
+ if (IS_ERR(framer_class)) {
+ pr_err("failed to create framer class (%pe)\n", framer_class);
+ return PTR_ERR(framer_class);
+ }
+
+ framer_class->dev_release = framer_release;
+
+ return 0;
+}
+device_initcall(framer_core_init);
diff --git a/drivers/net/wan/framer/pef2256/Makefile b/drivers/net/wan/framer/pef2256/Makefile
new file mode 100644
index 000000000000..f4d1208dd8a4
--- /dev/null
+++ b/drivers/net/wan/framer/pef2256/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the pef2256 driver.
+#
+
+obj-$(CONFIG_FRAMER_PEF2256) += framer-pef2256.o
+
+framer-pef2256-objs := pef2256.o
diff --git a/drivers/net/wan/framer/pef2256/pef2256-regs.h b/drivers/net/wan/framer/pef2256/pef2256-regs.h
new file mode 100644
index 000000000000..5d3183c91714
--- /dev/null
+++ b/drivers/net/wan/framer/pef2256/pef2256-regs.h
@@ -0,0 +1,250 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PEF2256 registers definition
+ *
+ * Copyright 2023 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+#ifndef __PEF2256_REGS_H__
+#define __PEF2256_REGS_H__
+
+#include "linux/bitfield.h"
+
+/* Command Register */
+#define PEF2256_CMDR 0x02
+#define PEF2256_CMDR_RRES BIT(6)
+#define PEF2256_CMDR_XRES BIT(4)
+#define PEF2256_CMDR_SRES BIT(0)
+
+/* Interrupt Mask Register 0..5 */
+#define PEF2256_IMR0 0x14
+#define PEF2256_IMR1 0x15
+#define PEF2256_IMR2 0x16
+#define PEF2256_IMR3 0x17
+#define PEF2256_IMR4 0x18
+#define PEF2256_IMR5 0x19
+
+/* Framer Mode Register 0 */
+#define PEF2256_FMR0 0x1C
+#define PEF2256_FMR0_XC_MASK GENMASK(7, 6)
+#define PEF2256_FMR0_XC_NRZ FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x0)
+#define PEF2256_FMR0_XC_CMI FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x1)
+#define PEF2256_FMR0_XC_AMI FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x2)
+#define PEF2256_FMR0_XC_HDB3 FIELD_PREP_CONST(PEF2256_FMR0_XC_MASK, 0x3)
+#define PEF2256_FMR0_RC_MASK GENMASK(5, 4)
+#define PEF2256_FMR0_RC_NRZ FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x0)
+#define PEF2256_FMR0_RC_CMI FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x1)
+#define PEF2256_FMR0_RC_AMI FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x2)
+#define PEF2256_FMR0_RC_HDB3 FIELD_PREP_CONST(PEF2256_FMR0_RC_MASK, 0x3)
+
+/* Framer Mode Register 1 */
+#define PEF2256_FMR1 0x1D
+#define PEF2256_FMR1_XFS BIT(3)
+#define PEF2256_FMR1_ECM BIT(2)
+/* SSD is defined on 2 bits. The other bit is on SIC1 register */
+#define PEF2256_FMR1_SSD_MASK GENMASK(1, 1)
+#define PEF2256_FMR1_SSD_2048 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x0)
+#define PEF2256_FMR1_SSD_4096 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x1)
+#define PEF2256_FMR1_SSD_8192 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x0)
+#define PEF2256_FMR1_SSD_16384 FIELD_PREP_CONST(PEF2256_FMR1_SSD_MASK, 0x1)
+
+/* Framer Mode Register 2 */
+#define PEF2256_FMR2 0x1E
+#define PEF2256_FMR2_RFS_MASK GENMASK(7, 6)
+#define PEF2256_FMR2_RFS_DOUBLEFRAME FIELD_PREP_CONST(PEF2256_FMR2_RFS_MASK, 0x0)
+#define PEF2256_FMR2_RFS_CRC4_MULTIFRAME FIELD_PREP_CONST(PEF2256_FMR2_RFS_MASK, 0x2)
+#define PEF2256_FMR2_RFS_AUTO_MULTIFRAME FIELD_PREP_CONST(PEF2256_FMR2_RFS_MASK, 0x3)
+#define PEF2256_FMR2_AXRA BIT(1)
+
+/* Transmit Service Word */
+#define PEF2256_XSW 0x20
+#define PEF2256_XSW_XSIS BIT(7)
+#define PEF2256_XSW_XTM BIT(6)
+#define PEF2256_XSW_XY_MASK GENMASK(5, 0)
+#define PEF2256_XSW_XY(_v) FIELD_PREP(PEF2256_XSW_XY_MASK, _v)
+
+/* Transmit Spare Bits */
+#define PEF2256_XSP 0x21
+#define PEF2256_XSP_XSIF BIT(2)
+
+/* Transmit Control 0..1 */
+#define PEF2256_XC0 0x22
+#define PEF2256_XC1 0x23
+
+/* Receive Control 0 */
+#define PEF2256_RC0 0x24
+#define PEF2256_RC0_SWD BIT(7)
+#define PEF2256_RC0_ASY4 BIT(6)
+
+/* Receive Control 1 */
+#define PEF2256_RC1 0x25
+
+/* Transmit Pulse Mask 0..1 */
+#define PEF2256_XPM0 0x26
+#define PEF2256_XPM1 0x27
+
+/* Transmit Pulse Mask 2 */
+#define PEF2256_XPM2 0x28
+#define PEF2256_XPM2_XLT BIT(6)
+
+/* Transparent Service Word Mask */
+#define PEF2256_TSWM 0x29
+
+/* Line Interface Mode 0 */
+#define PEF2256_LIM0 0x36
+#define PEF2256_2X_LIM0_BIT3 BIT(3) /* v2.x, described as a forced '1' bit */
+#define PEF2256_LIM0_MAS BIT(0)
+
+/* Line Interface Mode 1 */
+#define PEF2256_LIM1 0x37
+#define PEF2256_12_LIM1_RIL_MASK GENMASK(6, 4)
+#define PEF2256_12_LIM1_RIL_910 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x0)
+#define PEF2256_12_LIM1_RIL_740 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x1)
+#define PEF2256_12_LIM1_RIL_590 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x2)
+#define PEF2256_12_LIM1_RIL_420 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x3)
+#define PEF2256_12_LIM1_RIL_320 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x4)
+#define PEF2256_12_LIM1_RIL_210 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x5)
+#define PEF2256_12_LIM1_RIL_160 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x6)
+#define PEF2256_12_LIM1_RIL_100 FIELD_PREP_CONST(PEF2256_12_LIM1_RIL_MASK, 0x7)
+#define PEF2256_2X_LIM1_RIL_MASK GENMASK(6, 4)
+#define PEF2256_2X_LIM1_RIL_2250 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x0)
+#define PEF2256_2X_LIM1_RIL_1100 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x1)
+#define PEF2256_2X_LIM1_RIL_600 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x2)
+#define PEF2256_2X_LIM1_RIL_350 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x3)
+#define PEF2256_2X_LIM1_RIL_210 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x4)
+#define PEF2256_2X_LIM1_RIL_140 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x5)
+#define PEF2256_2X_LIM1_RIL_100 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x6)
+#define PEF2256_2X_LIM1_RIL_50 FIELD_PREP_CONST(PEF2256_2X_LIM1_RIL_MASK, 0x7)
+
+/* Pulse Count Detection */
+#define PEF2256_PCD 0x38
+
+ /* Pulse Count Recovery */
+#define PEF2256_PCR 0x39
+
+ /* Line Interface Mode 2 */
+#define PEF2256_LIM2 0x3A
+#define PEF2256_LIM2_SLT_MASK GENMASK(5, 4)
+#define PEF2256_LIM2_SLT_THR55 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x0)
+#define PEF2256_LIM2_SLT_THR67 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x1)
+#define PEF2256_LIM2_SLT_THR50 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x2)
+#define PEF2256_LIM2_SLT_THR45 FIELD_PREP_CONST(PEF2256_LIM2_SLT_MASK, 0x3)
+#define PEF2256_LIM2_ELT BIT(2)
+
+/* System Interface Control 1 */
+#define PEF2256_SIC1 0x3E
+#define PEF2256_SIC1_SSC_MASK (BIT(7) | BIT(3))
+#define PEF2256_SIC1_SSC_2048 (0)
+#define PEF2256_SIC1_SSC_4096 BIT(3)
+#define PEF2256_SIC1_SSC_8192 BIT(7)
+#define PEF2256_SIC1_SSC_16384 (BIT(7) | BIT(3))
+/* SSD is defined on 2 bits. The other bit is on FMR1 register */
+#define PEF2256_SIC1_SSD_MASK GENMASK(6, 6)
+#define PEF2256_SIC1_SSD_2048 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x0)
+#define PEF2256_SIC1_SSD_4096 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x0)
+#define PEF2256_SIC1_SSD_8192 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x1)
+#define PEF2256_SIC1_SSD_16384 FIELD_PREP_CONST(PEF2256_SIC1_SSD_MASK, 0x1)
+#define PEF2256_SIC1_RBS_MASK GENMASK(5, 4)
+#define PEF2256_SIC1_RBS_2FRAMES FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x0)
+#define PEF2256_SIC1_RBS_1FRAME FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x1)
+#define PEF2256_SIC1_RBS_96BITS FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x2)
+#define PEF2256_SIC1_RBS_BYPASS FIELD_PREP_CONST(PEF2256_SIC1_RBS_MASK, 0x3)
+#define PEF2256_SIC1_XBS_MASK GENMASK(1, 0)
+#define PEF2256_SIC1_XBS_BYPASS FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x0)
+#define PEF2256_SIC1_XBS_1FRAME FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x1)
+#define PEF2256_SIC1_XBS_2FRAMES FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x2)
+#define PEF2256_SIC1_XBS_96BITS FIELD_PREP_CONST(PEF2256_SIC1_XBS_MASK, 0x3)
+
+/* System Interface Control 2 */
+#define PEF2256_SIC2 0x3F
+#define PEF2256_SIC2_SICS_MASK GENMASK(3, 1)
+#define PEF2256_SIC2_SICS(_v) FIELD_PREP(PEF2256_SIC2_SICS_MASK, _v)
+
+/* System Interface Control 3 */
+#define PEF2256_SIC3 0x40
+#define PEF2256_SIC3_RTRI BIT(5)
+#define PEF2256_SIC3_RESX BIT(3)
+#define PEF2256_SIC3_RESR BIT(2)
+
+/* Clock Mode Register 1 */
+#define PEF2256_CMR1 0x44
+#define PEF2256_CMR1_RS_MASK GENMASK(5, 4)
+#define PEF2256_CMR1_RS_DPLL FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x0)
+#define PEF2256_CMR1_RS_DPLL_LOS_HIGH FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x1)
+#define PEF2256_CMR1_RS_DCOR_2048 FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x2)
+#define PEF2256_CMR1_RS_DCOR_8192 FIELD_PREP_CONST(PEF2256_CMR1_RS_MASK, 0x3)
+#define PEF2256_CMR1_DCS BIT(3)
+
+/* Clock Mode Register 2 */
+#define PEF2256_CMR2 0x45
+#define PEF2256_CMR2_DCOXC BIT(5)
+
+/* Global Configuration Register */
+#define PEF2256_GCR 0x46
+#define PEF2256_GCR_SCI BIT(6)
+#define PEF2256_GCR_ECMC BIT(4)
+
+/* Port Configuration 5 */
+#define PEF2256_PC5 0x84
+#define PEF2256_PC5_CRP BIT(0)
+
+/* Global Port Configuration 1 */
+#define PEF2256_GPC1 0x85
+#define PEF2256_GPC1_CSFP_MASK GENMASK(7, 5)
+#define PEF2256_GPC1_CSFP_SEC_IN_HIGH FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x0)
+#define PEF2256_GPC1_CSFP_SEC_OUT_HIGH FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x1)
+#define PEF2256_GPC1_CSFP_FSC_OUT_HIGH FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x2)
+#define PEF2256_GPC1_CSFP_FSC_OUT_LOW FIELD_PREP_CONST(PEF2256_GPC1_CSFP_MASK, 0x3)
+
+/* Port Configuration 6 */
+#define PEF2256_PC6 0x86
+
+/* Global Counter Mode n=1..8 */
+#define PEF2256_GCM(_n) (0x92 + (_n) - 1)
+#define PEF2256_GCM1 0x92
+#define PEF2256_GCM2 0x93
+#define PEF2256_GCM3 0x94
+#define PEF2256_GCM4 0x95
+#define PEF2256_GCM5 0x96
+#define PEF2256_GCM6 0x97
+#define PEF2256_GCM7 0x98
+#define PEF2256_GCM8 0x99
+
+/* Version Status Register */
+#define PEF2256_VSTR 0x4A
+#define PEF2256_VSTR_VERSION_12 0x00
+#define PEF2256_VSTR_VERSION_21 0x10
+#define PEF2256_VSTR_VERSION_2x 0x05
+
+/* Framer Receive Status 0 */
+#define PEF2256_FRS0 0x4C
+#define PEF2256_FRS0_LOS BIT(7)
+#define PEF2256_FRS0_AIS BIT(6)
+
+/* Interrupt Status Register 0..5 */
+#define PEF2256_ISR(_n) (0x68 + (_n))
+#define PEF2256_ISR0 0x68
+#define PEF2256_ISR1 0x69
+#define PEF2256_ISR2 0x6A
+#define PEF2256_ISR3 0x6B
+#define PEF2256_ISR4 0x6C
+#define PEF2256_ISR5 0x6D
+
+/* Global Interrupt Status */
+#define PEF2256_GIS 0x6E
+#define PEF2256_GIS_ISR(_n) BIT(_n)
+
+/* Wafer Identification Register */
+#define PEF2256_WID 0xEC
+#define PEF2256_12_WID_MASK GENMASK(1, 0)
+#define PEF2256_12_WID_VERSION_12 FIELD_PREP_CONST(PEF2256_12_WID_MASK, 0x3)
+#define PEF2256_2X_WID_MASK GENMASK(7, 6)
+#define PEF2256_2X_WID_VERSION_21 FIELD_PREP_CONST(PEF2256_2X_WID_MASK, 0x0)
+#define PEF2256_2X_WID_VERSION_22 FIELD_PREP_CONST(PEF2256_2X_WID_MASK, 0x1)
+
+/* IMR2/ISR2 Interrupts common bits */
+#define PEF2256_INT2_AIS BIT(3)
+#define PEF2256_INT2_LOS BIT(2)
+
+#endif /* __PEF2256_REGS_H__ */
diff --git a/drivers/net/wan/framer/pef2256/pef2256.c b/drivers/net/wan/framer/pef2256/pef2256.c
new file mode 100644
index 000000000000..4f81053ee4f0
--- /dev/null
+++ b/drivers/net/wan/framer/pef2256/pef2256.c
@@ -0,0 +1,880 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PEF2256 also known as FALC56 driver
+ *
+ * Copyright 2023 CS GROUP France
+ *
+ * Author: Herve Codina <herve.codina@bootlin.com>
+ */
+
+#include <linux/framer/pef2256.h>
+#include <linux/clk.h>
+#include <linux/framer/framer-provider.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include "pef2256-regs.h"
+
+enum pef2256_frame_type {
+ PEF2256_FRAME_E1_DOUBLEFRAME,
+ PEF2256_FRAME_E1_CRC4_MULTIFRAME,
+ PEF2256_FRAME_E1_AUTO_MULTIFRAME,
+ PEF2256_FRAME_T1J1_4FRAME,
+ PEF2256_FRAME_T1J1_12FRAME,
+ PEF2256_FRAME_T1J1_24FRAME,
+ PEF2256_FRAME_T1J1_72FRAME,
+};
+
+struct pef2256 {
+ struct device *dev;
+ struct regmap *regmap;
+ enum pef2256_version version;
+ struct clk *mclk;
+ struct clk *sclkr;
+ struct clk *sclkx;
+ struct gpio_desc *reset_gpio;
+ unsigned long sysclk_rate;
+ u32 data_rate;
+ bool is_tx_falling_edge;
+ bool is_subordinate;
+ enum pef2256_frame_type frame_type;
+ u8 channel_phase;
+ atomic_t carrier;
+ struct framer *framer;
+};
+
+static u8 pef2256_read8(struct pef2256 *pef2256, int offset)
+{
+ int val;
+
+ regmap_read(pef2256->regmap, offset, &val);
+ return val;
+}
+
+static void pef2256_write8(struct pef2256 *pef2256, int offset, u8 val)
+{
+ regmap_write(pef2256->regmap, offset, val);
+}
+
+static void pef2256_clrbits8(struct pef2256 *pef2256, int offset, u8 clr)
+{
+ regmap_clear_bits(pef2256->regmap, offset, clr);
+}
+
+static void pef2256_setbits8(struct pef2256 *pef2256, int offset, u8 set)
+{
+ regmap_set_bits(pef2256->regmap, offset, set);
+}
+
+static void pef2256_clrsetbits8(struct pef2256 *pef2256, int offset, u8 clr, u8 set)
+{
+ regmap_update_bits(pef2256->regmap, offset, clr | set, set);
+}
+
+enum pef2256_version pef2256_get_version(struct pef2256 *pef2256)
+{
+ enum pef2256_version version = PEF2256_VERSION_UNKNOWN;
+ u8 vstr, wid;
+
+ vstr = pef2256_read8(pef2256, PEF2256_VSTR);
+ wid = pef2256_read8(pef2256, PEF2256_WID);
+
+ switch (vstr) {
+ case PEF2256_VSTR_VERSION_12:
+ if ((wid & PEF2256_12_WID_MASK) == PEF2256_12_WID_VERSION_12)
+ version = PEF2256_VERSION_1_2;
+ break;
+ case PEF2256_VSTR_VERSION_2x:
+ switch (wid & PEF2256_2X_WID_MASK) {
+ case PEF2256_2X_WID_VERSION_21:
+ version = PEF2256_VERSION_2_1;
+ break;
+ case PEF2256_2X_WID_VERSION_22:
+ version = PEF2256_VERSION_2_2;
+ break;
+ }
+ break;
+ case PEF2256_VSTR_VERSION_21:
+ version = PEF2256_VERSION_2_1;
+ break;
+ }
+
+ if (version == PEF2256_VERSION_UNKNOWN)
+ dev_err(pef2256->dev, "Unknown version (0x%02x, 0x%02x)\n", vstr, wid);
+
+ return version;
+}
+EXPORT_SYMBOL_GPL(pef2256_get_version);
+
+enum pef2256_gcm_config_item {
+ PEF2256_GCM_CONFIG_1544000 = 0,
+ PEF2256_GCM_CONFIG_2048000,
+ PEF2256_GCM_CONFIG_8192000,
+ PEF2256_GCM_CONFIG_10000000,
+ PEF2256_GCM_CONFIG_12352000,
+ PEF2256_GCM_CONFIG_16384000,
+};
+
+struct pef2256_gcm_config {
+ u8 gcm_12[6];
+ u8 gcm_2x[8];
+};
+
+static const struct pef2256_gcm_config pef2256_gcm_configs[] = {
+ [PEF2256_GCM_CONFIG_1544000] = {
+ .gcm_12 = {0xF0, 0x51, 0x00, 0x80, 0x00, 0x15},
+ .gcm_2x = {0x00, 0x15, 0x00, 0x08, 0x00, 0x3F, 0x9C, 0xDF},
+ },
+ [PEF2256_GCM_CONFIG_2048000] = {
+ .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x00, 0x10},
+ .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x00, 0x2F, 0xDB, 0xDF},
+ },
+ [PEF2256_GCM_CONFIG_8192000] = {
+ .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x03, 0x10},
+ .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x00, 0x0B, 0xDB, 0xDF},
+ },
+ [PEF2256_GCM_CONFIG_10000000] = {
+ .gcm_12 = {0x90, 0x51, 0x81, 0x8F, 0x04, 0x10},
+ .gcm_2x = {0x40, 0x1B, 0x3D, 0x0A, 0x00, 0x07, 0xC9, 0xDC},
+ },
+ [PEF2256_GCM_CONFIG_12352000] = {
+ .gcm_12 = {0xF0, 0x51, 0x00, 0x80, 0x07, 0x15},
+ .gcm_2x = {0x00, 0x19, 0x00, 0x08, 0x01, 0x0A, 0x98, 0xDA},
+ },
+ [PEF2256_GCM_CONFIG_16384000] = {
+ .gcm_12 = {0x00, 0x58, 0xD2, 0xC2, 0x07, 0x10},
+ .gcm_2x = {0x00, 0x18, 0xFB, 0x0B, 0x01, 0x0B, 0xDB, 0xDF},
+ },
+};
+
+static int pef2256_setup_gcm(struct pef2256 *pef2256)
+{
+ enum pef2256_gcm_config_item item;
+ unsigned long mclk_rate;
+ const u8 *gcm;
+ int i, count;
+
+ mclk_rate = clk_get_rate(pef2256->mclk);
+ switch (mclk_rate) {
+ case 1544000:
+ item = PEF2256_GCM_CONFIG_1544000;
+ break;
+ case 2048000:
+ item = PEF2256_GCM_CONFIG_2048000;
+ break;
+ case 8192000:
+ item = PEF2256_GCM_CONFIG_8192000;
+ break;
+ case 10000000:
+ item = PEF2256_GCM_CONFIG_10000000;
+ break;
+ case 12352000:
+ item = PEF2256_GCM_CONFIG_12352000;
+ break;
+ case 16384000:
+ item = PEF2256_GCM_CONFIG_16384000;
+ break;
+ default:
+ dev_err(pef2256->dev, "Unsupported v2.x MCLK rate %lu\n", mclk_rate);
+ return -EINVAL;
+ }
+
+ BUILD_BUG_ON(item >= ARRAY_SIZE(pef2256_gcm_configs));
+
+ if (pef2256->version == PEF2256_VERSION_1_2) {
+ gcm = pef2256_gcm_configs[item].gcm_12;
+ count = ARRAY_SIZE(pef2256_gcm_configs[item].gcm_12);
+ } else {
+ gcm = pef2256_gcm_configs[item].gcm_2x;
+ count = ARRAY_SIZE(pef2256_gcm_configs[item].gcm_2x);
+ }
+
+ for (i = 0; i < count; i++)
+ pef2256_write8(pef2256, PEF2256_GCM(i + 1), *(gcm + i));
+
+ return 0;
+}
+
+static int pef2256_setup_e1_line(struct pef2256 *pef2256)
+{
+ u8 fmr1, fmr2;
+
+ /* RCLK output : DPLL clock, DCO-X enabled, DCO-X internal ref clock */
+ pef2256_write8(pef2256, PEF2256_CMR1, 0x00);
+
+ /* SCLKR selected, SCLKX selected,
+ * receive synchro pulse sourced by SYPR,
+ * transmit synchro pulse sourced by SYPX,
+ * DCO-X center frequency enabled
+ */
+ pef2256_write8(pef2256, PEF2256_CMR2, PEF2256_CMR2_DCOXC);
+
+ if (pef2256->is_subordinate) {
+ /* select RCLK source = 2M, disable switching from RCLK to SYNC */
+ pef2256_clrsetbits8(pef2256, PEF2256_CMR1, PEF2256_CMR1_RS_MASK,
+ PEF2256_CMR1_RS_DCOR_2048 | PEF2256_CMR1_DCS);
+ }
+
+ /* slave mode, local loop off, mode short-haul
+ * In v2.x, bit3 is a forced 1 bit in the datasheet -> Need to be set.
+ */
+ if (pef2256->version == PEF2256_VERSION_1_2)
+ pef2256_write8(pef2256, PEF2256_LIM0, 0x00);
+ else
+ pef2256_write8(pef2256, PEF2256_LIM0, PEF2256_2X_LIM0_BIT3);
+
+ /* "master" mode */
+ if (!pef2256->is_subordinate)
+ pef2256_setbits8(pef2256, PEF2256_LIM0, PEF2256_LIM0_MAS);
+
+ /* analog interface selected, remote loop off */
+ pef2256_write8(pef2256, PEF2256_LIM1, 0x00);
+
+ /* receive input threshold = 0,21V */
+ if (pef2256->version == PEF2256_VERSION_1_2)
+ pef2256_clrsetbits8(pef2256, PEF2256_LIM1, PEF2256_12_LIM1_RIL_MASK,
+ PEF2256_12_LIM1_RIL_210);
+ else
+ pef2256_clrsetbits8(pef2256, PEF2256_LIM1, PEF2256_2X_LIM1_RIL_MASK,
+ PEF2256_2X_LIM1_RIL_210);
+
+ /* transmit pulse mask, default value from datasheet
+ * transmit line in normal operation
+ */
+ if (pef2256->version == PEF2256_VERSION_1_2)
+ pef2256_write8(pef2256, PEF2256_XPM0, 0x7B);
+ else
+ pef2256_write8(pef2256, PEF2256_XPM0, 0x9C);
+ pef2256_write8(pef2256, PEF2256_XPM1, 0x03);
+ pef2256_write8(pef2256, PEF2256_XPM2, 0x00);
+
+ /* HDB3 coding, no alarm simulation */
+ pef2256_write8(pef2256, PEF2256_FMR0, PEF2256_FMR0_XC_HDB3 | PEF2256_FMR0_RC_HDB3);
+
+ /* E1, frame format, 2 Mbit/s system data rate, no AIS
+ * transmission to remote end or system interface, payload loop
+ * off, transmit remote alarm on
+ */
+ fmr1 = 0x00;
+ fmr2 = PEF2256_FMR2_AXRA;
+ switch (pef2256->frame_type) {
+ case PEF2256_FRAME_E1_DOUBLEFRAME:
+ fmr2 |= PEF2256_FMR2_RFS_DOUBLEFRAME;
+ break;
+ case PEF2256_FRAME_E1_CRC4_MULTIFRAME:
+ fmr1 |= PEF2256_FMR1_XFS;
+ fmr2 |= PEF2256_FMR2_RFS_CRC4_MULTIFRAME;
+ break;
+ case PEF2256_FRAME_E1_AUTO_MULTIFRAME:
+ fmr1 |= PEF2256_FMR1_XFS;
+ fmr2 |= PEF2256_FMR2_RFS_AUTO_MULTIFRAME;
+ break;
+ default:
+ dev_err(pef2256->dev, "Unsupported frame type %d\n", pef2256->frame_type);
+ return -EINVAL;
+ }
+ pef2256_clrsetbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_XFS, fmr1);
+ pef2256_write8(pef2256, PEF2256_FMR2, fmr2);
+
+ if (!pef2256->is_subordinate) {
+ /* SEC input, active high */
+ pef2256_write8(pef2256, PEF2256_GPC1, PEF2256_GPC1_CSFP_SEC_IN_HIGH);
+ } else {
+ /* FSC output, active high */
+ pef2256_write8(pef2256, PEF2256_GPC1, PEF2256_GPC1_CSFP_FSC_OUT_HIGH);
+ }
+
+ /* SCLKR, SCLKX, RCLK configured to inputs,
+ * XFMS active low, CLK1 and CLK2 pin configuration
+ */
+ pef2256_write8(pef2256, PEF2256_PC5, 0x00);
+ pef2256_write8(pef2256, PEF2256_PC6, 0x00);
+
+ /* port RCLK is output */
+ pef2256_setbits8(pef2256, PEF2256_PC5, PEF2256_PC5_CRP);
+
+ return 0;
+}
+
+static void pef2256_setup_e1_los(struct pef2256 *pef2256)
+{
+ /* detection of LOS alarm = 176 pulses (ie (10 + 1) * 16) */
+ pef2256_write8(pef2256, PEF2256_PCD, 10);
+ /* recovery of LOS alarm = 22 pulses (ie 21 + 1) */
+ pef2256_write8(pef2256, PEF2256_PCR, 21);
+ /* E1 default for the receive slicer threshold */
+ pef2256_write8(pef2256, PEF2256_LIM2, PEF2256_LIM2_SLT_THR50);
+ if (pef2256->is_subordinate) {
+ /* Loop-timed */
+ pef2256_setbits8(pef2256, PEF2256_LIM2, PEF2256_LIM2_ELT);
+ }
+}
+
+static int pef2256_setup_e1_system(struct pef2256 *pef2256)
+{
+ u8 sic1, fmr1;
+
+ /* 2.048 MHz system clocking rate, receive buffer 2 frames, transmit
+ * buffer bypass, data sampled and transmitted on the falling edge of
+ * SCLKR/X, automatic freeze signaling, data is active in the first
+ * channel phase
+ */
+ pef2256_write8(pef2256, PEF2256_SIC1, 0x00);
+ pef2256_write8(pef2256, PEF2256_SIC2, 0x00);
+ pef2256_write8(pef2256, PEF2256_SIC3, 0x00);
+
+ if (pef2256->is_subordinate) {
+ /* transmit buffer size = 2 frames, transparent mode */
+ pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_XBS_MASK,
+ PEF2256_SIC1_XBS_2FRAMES);
+ }
+
+ if (pef2256->version != PEF2256_VERSION_1_2) {
+ /* during inactive channel phase switch RDO/RSIG into tri-state */
+ pef2256_setbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RTRI);
+ }
+
+ if (pef2256->is_tx_falling_edge) {
+ /* falling edge sync pulse transmit, rising edge sync pulse receive */
+ pef2256_clrsetbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RESX, PEF2256_SIC3_RESR);
+ } else {
+ /* rising edge sync pulse transmit, falling edge sync pulse receive */
+ pef2256_clrsetbits8(pef2256, PEF2256_SIC3, PEF2256_SIC3_RESR, PEF2256_SIC3_RESX);
+ }
+
+ /* transmit offset counter (XCO10..0) = 4 */
+ pef2256_write8(pef2256, PEF2256_XC0, 0);
+ pef2256_write8(pef2256, PEF2256_XC1, 4);
+ /* receive offset counter (RCO10..0) = 4 */
+ pef2256_write8(pef2256, PEF2256_RC0, 0);
+ pef2256_write8(pef2256, PEF2256_RC1, 4);
+
+ /* system clock rate */
+ switch (pef2256->sysclk_rate) {
+ case 2048000:
+ sic1 = PEF2256_SIC1_SSC_2048;
+ break;
+ case 4096000:
+ sic1 = PEF2256_SIC1_SSC_4096;
+ break;
+ case 8192000:
+ sic1 = PEF2256_SIC1_SSC_8192;
+ break;
+ case 16384000:
+ sic1 = PEF2256_SIC1_SSC_16384;
+ break;
+ default:
+ dev_err(pef2256->dev, "Unsupported sysclk rate %lu\n", pef2256->sysclk_rate);
+ return -EINVAL;
+ }
+ pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_SSC_MASK, sic1);
+
+ /* data clock rate */
+ switch (pef2256->data_rate) {
+ case 2048000:
+ fmr1 = PEF2256_FMR1_SSD_2048;
+ sic1 = PEF2256_SIC1_SSD_2048;
+ break;
+ case 4096000:
+ fmr1 = PEF2256_FMR1_SSD_4096;
+ sic1 = PEF2256_SIC1_SSD_4096;
+ break;
+ case 8192000:
+ fmr1 = PEF2256_FMR1_SSD_8192;
+ sic1 = PEF2256_SIC1_SSD_8192;
+ break;
+ case 16384000:
+ fmr1 = PEF2256_FMR1_SSD_16384;
+ sic1 = PEF2256_SIC1_SSD_16384;
+ break;
+ default:
+ dev_err(pef2256->dev, "Unsupported data rate %u\n", pef2256->data_rate);
+ return -EINVAL;
+ }
+ pef2256_clrsetbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_SSD_MASK, fmr1);
+ pef2256_clrsetbits8(pef2256, PEF2256_SIC1, PEF2256_SIC1_SSD_MASK, sic1);
+
+ /* channel phase */
+ pef2256_clrsetbits8(pef2256, PEF2256_SIC2, PEF2256_SIC2_SICS_MASK,
+ PEF2256_SIC2_SICS(pef2256->channel_phase));
+
+ return 0;
+}
+
+static void pef2256_setup_e1_signaling(struct pef2256 *pef2256)
+{
+ /* All bits of the transmitted service word are cleared */
+ pef2256_write8(pef2256, PEF2256_XSW, PEF2256_XSW_XY(0x1F));
+
+ /* CAS disabled and clear spare bit values */
+ pef2256_write8(pef2256, PEF2256_XSP, 0x00);
+
+ if (pef2256->is_subordinate) {
+ /* transparent mode */
+ pef2256_setbits8(pef2256, PEF2256_XSW, PEF2256_XSW_XTM);
+ }
+
+ /* Si-Bit, Spare bit For International, FAS word */
+ pef2256_setbits8(pef2256, PEF2256_XSW, PEF2256_XSW_XSIS);
+ pef2256_setbits8(pef2256, PEF2256_XSP, PEF2256_XSP_XSIF);
+
+ /* no transparent mode active */
+ pef2256_write8(pef2256, PEF2256_TSWM, 0x00);
+}
+
+static void pef2256_setup_e1_errors(struct pef2256 *pef2256)
+{
+ /* error counter latched every 1s */
+ pef2256_setbits8(pef2256, PEF2256_FMR1, PEF2256_FMR1_ECM);
+
+ /* error counter mode COFA */
+ pef2256_setbits8(pef2256, PEF2256_GCR, PEF2256_GCR_ECMC);
+
+ /* errors in service words have no influence */
+ pef2256_setbits8(pef2256, PEF2256_RC0, PEF2256_RC0_SWD);
+
+ /* 4 consecutive incorrect FAS causes loss of sync */
+ pef2256_setbits8(pef2256, PEF2256_RC0, PEF2256_RC0_ASY4);
+}
+
+static int pef2256_setup_e1(struct pef2256 *pef2256)
+{
+ int ret;
+
+ /* Setup, Master clocking mode (GCM8..1) */
+ ret = pef2256_setup_gcm(pef2256);
+ if (ret)
+ return ret;
+
+ /* Select E1 mode */
+ pef2256_write8(pef2256, PEF2256_FMR1, 0x00);
+
+ /* internal second timer, power on */
+ pef2256_write8(pef2256, PEF2256_GCR, 0x00);
+
+ /* Setup line interface */
+ ret = pef2256_setup_e1_line(pef2256);
+ if (ret)
+ return ret;
+
+ /* Setup Loss-of-signal detection and recovery */
+ pef2256_setup_e1_los(pef2256);
+
+ /* Setup system interface */
+ ret = pef2256_setup_e1_system(pef2256);
+ if (ret)
+ return ret;
+
+ /* Setup signaling */
+ pef2256_setup_e1_signaling(pef2256);
+
+ /* Setup errors counters and condition */
+ pef2256_setup_e1_errors(pef2256);
+
+ /* status changed interrupt at both up and down */
+ pef2256_setbits8(pef2256, PEF2256_GCR, PEF2256_GCR_SCI);
+
+ /* Clear any ISR2 pending interrupts and unmask needed interrupts */
+ pef2256_read8(pef2256, PEF2256_ISR2);
+ pef2256_clrbits8(pef2256, PEF2256_IMR2, PEF2256_INT2_LOS | PEF2256_INT2_AIS);
+
+ /* reset lines */
+ pef2256_write8(pef2256, PEF2256_CMDR, PEF2256_CMDR_RRES | PEF2256_CMDR_XRES);
+ return 0;
+}
+
+static void pef2256_isr_default_handler(struct pef2256 *pef2256, u8 nbr, u8 isr)
+{
+ dev_warn_ratelimited(pef2256->dev, "ISR%u: 0x%02x not handled\n", nbr, isr);
+}
+
+static bool pef2256_is_carrier_on(struct pef2256 *pef2256)
+{
+ u8 frs0;
+
+ frs0 = pef2256_read8(pef2256, PEF2256_FRS0);
+ return !(frs0 & (PEF2256_FRS0_LOS | PEF2256_FRS0_AIS));
+}
+
+static void pef2256_isr2_handler(struct pef2256 *pef2256, u8 nbr, u8 isr)
+{
+ bool carrier;
+
+ if (isr & (PEF2256_INT2_LOS | PEF2256_INT2_AIS)) {
+ carrier = pef2256_is_carrier_on(pef2256);
+ if (atomic_xchg(&pef2256->carrier, carrier) != carrier)
+ framer_notify_status_change(pef2256->framer);
+ }
+}
+
+static irqreturn_t pef2256_irq_handler(int irq, void *priv)
+{
+ static void (*pef2256_isr_handler[])(struct pef2256 *, u8, u8) = {
+ [0] = pef2256_isr_default_handler,
+ [1] = pef2256_isr_default_handler,
+ [2] = pef2256_isr2_handler,
+ [3] = pef2256_isr_default_handler,
+ [4] = pef2256_isr_default_handler,
+ [5] = pef2256_isr_default_handler
+ };
+ struct pef2256 *pef2256 = (struct pef2256 *)priv;
+ u8 gis;
+ u8 isr;
+ u8 n;
+
+ gis = pef2256_read8(pef2256, PEF2256_GIS);
+
+ for (n = 0; n < ARRAY_SIZE(pef2256_isr_handler); n++) {
+ if (gis & PEF2256_GIS_ISR(n)) {
+ isr = pef2256_read8(pef2256, PEF2256_ISR(n));
+ pef2256_isr_handler[n](pef2256, n, isr);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pef2256_check_rates(struct pef2256 *pef2256, unsigned long sysclk_rate,
+ unsigned long data_rate)
+{
+ unsigned long rate;
+
+ switch (sysclk_rate) {
+ case 2048000:
+ case 4096000:
+ case 8192000:
+ case 16384000:
+ break;
+ default:
+ dev_err(pef2256->dev, "Unsupported system clock rate %lu\n", sysclk_rate);
+ return -EINVAL;
+ }
+
+ for (rate = data_rate; rate <= data_rate * 4; rate *= 2) {
+ if (rate == sysclk_rate)
+ return 0;
+ }
+ dev_err(pef2256->dev, "Unsupported data rate %lu with system clock rate %lu\n",
+ data_rate, sysclk_rate);
+ return -EINVAL;
+}
+
+static int pef2556_of_parse(struct pef2256 *pef2256, struct device_node *np)
+{
+ int ret;
+
+ pef2256->data_rate = 2048000;
+ ret = of_property_read_u32(np, "lantiq,data-rate-bps", &pef2256->data_rate);
+ if (ret && ret != -EINVAL) {
+ dev_err(pef2256->dev, "%pOF: failed to read lantiq,data-rate-bps\n", np);
+ return ret;
+ }
+
+ ret = pef2256_check_rates(pef2256, pef2256->sysclk_rate, pef2256->data_rate);
+ if (ret)
+ return ret;
+
+ pef2256->is_tx_falling_edge = of_property_read_bool(np, "lantiq,clock-falling-edge");
+
+ pef2256->channel_phase = 0;
+ ret = of_property_read_u8(np, "lantiq,channel-phase", &pef2256->channel_phase);
+ if (ret && ret != -EINVAL) {
+ dev_err(pef2256->dev, "%pOF: failed to read lantiq,channel-phase\n",
+ np);
+ return ret;
+ }
+ if (pef2256->channel_phase >= pef2256->sysclk_rate / pef2256->data_rate) {
+ dev_err(pef2256->dev, "%pOF: Invalid lantiq,channel-phase %u\n",
+ np, pef2256->channel_phase);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config pef2256_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .max_register = 0xff,
+};
+
+static const struct mfd_cell pef2256_devs[] = {
+ { .name = "lantiq-pef2256-pinctrl", },
+};
+
+static int pef2256_add_audio_devices(struct pef2256 *pef2256)
+{
+ const char *compatible = "lantiq,pef2256-codec";
+ struct mfd_cell *audio_devs;
+ struct device_node *np;
+ unsigned int count = 0;
+ unsigned int i;
+ int ret;
+
+ for_each_available_child_of_node(pef2256->dev->of_node, np) {
+ if (of_device_is_compatible(np, compatible))
+ count++;
+ }
+
+ if (!count)
+ return 0;
+
+ audio_devs = kcalloc(count, sizeof(*audio_devs), GFP_KERNEL);
+ if (!audio_devs)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ audio_devs[i].name = "framer-codec";
+ audio_devs[i].of_compatible = compatible;
+ audio_devs[i].id = i;
+ }
+
+ ret = mfd_add_devices(pef2256->dev, 0, audio_devs, count, NULL, 0, NULL);
+ kfree(audio_devs);
+ return ret;
+}
+
+static int pef2256_framer_get_status(struct framer *framer, struct framer_status *status)
+{
+ struct pef2256 *pef2256 = framer_get_drvdata(framer);
+
+ status->link_is_on = !!atomic_read(&pef2256->carrier);
+ return 0;
+}
+
+static int pef2256_framer_set_config(struct framer *framer, const struct framer_config *config)
+{
+ struct pef2256 *pef2256 = framer_get_drvdata(framer);
+
+ if (config->iface != FRAMER_IFACE_E1) {
+ dev_err(pef2256->dev, "Only E1 line is currently supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ switch (config->clock_type) {
+ case FRAMER_CLOCK_EXT:
+ pef2256->is_subordinate = true;
+ break;
+ case FRAMER_CLOCK_INT:
+ pef2256->is_subordinate = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Apply the new settings */
+ return pef2256_setup_e1(pef2256);
+}
+
+static int pef2256_framer_get_config(struct framer *framer, struct framer_config *config)
+{
+ struct pef2256 *pef2256 = framer_get_drvdata(framer);
+
+ config->iface = FRAMER_IFACE_E1;
+ config->clock_type = pef2256->is_subordinate ? FRAMER_CLOCK_EXT : FRAMER_CLOCK_INT;
+ config->line_clock_rate = 2048000;
+ return 0;
+}
+
+static const struct framer_ops pef2256_framer_ops = {
+ .owner = THIS_MODULE,
+ .get_status = pef2256_framer_get_status,
+ .get_config = pef2256_framer_get_config,
+ .set_config = pef2256_framer_set_config,
+};
+
+static int pef2256_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ unsigned long sclkr_rate, sclkx_rate;
+ struct framer_provider *framer_provider;
+ struct pef2256 *pef2256;
+ const char *version_txt;
+ void __iomem *iomem;
+ int ret;
+ int irq;
+
+ pef2256 = devm_kzalloc(&pdev->dev, sizeof(*pef2256), GFP_KERNEL);
+ if (!pef2256)
+ return -ENOMEM;
+
+ pef2256->dev = &pdev->dev;
+ atomic_set(&pef2256->carrier, 0);
+
+ pef2256->is_subordinate = true;
+ pef2256->frame_type = PEF2256_FRAME_E1_DOUBLEFRAME;
+
+ iomem = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(iomem))
+ return PTR_ERR(iomem);
+
+ pef2256->regmap = devm_regmap_init_mmio(&pdev->dev, iomem,
+ &pef2256_regmap_config);
+ if (IS_ERR(pef2256->regmap)) {
+ dev_err(&pdev->dev, "Failed to initialise Regmap (%ld)\n",
+ PTR_ERR(pef2256->regmap));
+ return PTR_ERR(pef2256->regmap);
+ }
+
+ pef2256->mclk = devm_clk_get_enabled(&pdev->dev, "mclk");
+ if (IS_ERR(pef2256->mclk))
+ return PTR_ERR(pef2256->mclk);
+
+ pef2256->sclkr = devm_clk_get_enabled(&pdev->dev, "sclkr");
+ if (IS_ERR(pef2256->sclkr))
+ return PTR_ERR(pef2256->sclkr);
+
+ pef2256->sclkx = devm_clk_get_enabled(&pdev->dev, "sclkx");
+ if (IS_ERR(pef2256->sclkx))
+ return PTR_ERR(pef2256->sclkx);
+
+ /* Both SCLKR (receive) and SCLKX (transmit) must have the same rate,
+ * stored as sysclk_rate.
+ * The exact value will be checked at pef2256_check_rates()
+ */
+ sclkr_rate = clk_get_rate(pef2256->sclkr);
+ sclkx_rate = clk_get_rate(pef2256->sclkx);
+ if (sclkr_rate != sclkx_rate) {
+ dev_err(pef2256->dev, "clk rate mismatch. sclkr %lu Hz, sclkx %lu Hz\n",
+ sclkr_rate, sclkx_rate);
+ return -EINVAL;
+ }
+ pef2256->sysclk_rate = sclkr_rate;
+
+ /* Reset the component. The MCLK clock must be active during reset */
+ pef2256->reset_gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(pef2256->reset_gpio))
+ return PTR_ERR(pef2256->reset_gpio);
+ if (pef2256->reset_gpio) {
+ gpiod_set_value_cansleep(pef2256->reset_gpio, 1);
+ usleep_range(10, 20);
+ gpiod_set_value_cansleep(pef2256->reset_gpio, 0);
+ usleep_range(10, 20);
+ }
+
+ pef2256->version = pef2256_get_version(pef2256);
+ switch (pef2256->version) {
+ case PEF2256_VERSION_1_2:
+ version_txt = "1.2";
+ break;
+ case PEF2256_VERSION_2_1:
+ version_txt = "2.1";
+ break;
+ case PEF2256_VERSION_2_2:
+ version_txt = "2.2";
+ break;
+ default:
+ return -ENODEV;
+ }
+ dev_info(pef2256->dev, "Version %s detected\n", version_txt);
+
+ ret = pef2556_of_parse(pef2256, np);
+ if (ret)
+ return ret;
+
+ /* Create the framer. It can be used on interrupts */
+ pef2256->framer = devm_framer_create(pef2256->dev, NULL, &pef2256_framer_ops);
+ if (IS_ERR(pef2256->framer))
+ return PTR_ERR(pef2256->framer);
+
+ framer_set_drvdata(pef2256->framer, pef2256);
+
+ /* Disable interrupts */
+ pef2256_write8(pef2256, PEF2256_IMR0, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR1, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR2, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR3, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR4, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR5, 0xff);
+
+ /* Clear any pending interrupts */
+ pef2256_read8(pef2256, PEF2256_ISR0);
+ pef2256_read8(pef2256, PEF2256_ISR1);
+ pef2256_read8(pef2256, PEF2256_ISR2);
+ pef2256_read8(pef2256, PEF2256_ISR3);
+ pef2256_read8(pef2256, PEF2256_ISR4);
+ pef2256_read8(pef2256, PEF2256_ISR5);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+ ret = devm_request_irq(pef2256->dev, irq, pef2256_irq_handler, 0, "pef2256", pef2256);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, pef2256);
+
+ ret = mfd_add_devices(pef2256->dev, 0, pef2256_devs,
+ ARRAY_SIZE(pef2256_devs), NULL, 0, NULL);
+ if (ret) {
+ dev_err(pef2256->dev, "add devices failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = pef2256_setup_e1(pef2256);
+ if (ret)
+ return ret;
+
+ framer_provider = devm_framer_provider_of_register(pef2256->dev,
+ framer_provider_simple_of_xlate);
+ if (IS_ERR(framer_provider))
+ return PTR_ERR(framer_provider);
+
+ /* Add audio devices */
+ ret = pef2256_add_audio_devices(pef2256);
+ if (ret < 0) {
+ dev_err(pef2256->dev, "add audio devices failed (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pef2256_remove(struct platform_device *pdev)
+{
+ struct pef2256 *pef2256 = platform_get_drvdata(pdev);
+
+ /* Disable interrupts */
+ pef2256_write8(pef2256, PEF2256_IMR0, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR1, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR2, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR3, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR4, 0xff);
+ pef2256_write8(pef2256, PEF2256_IMR5, 0xff);
+
+ return 0;
+}
+
+static const struct of_device_id pef2256_id_table[] = {
+ { .compatible = "lantiq,pef2256" },
+ {} /* sentinel */
+};
+MODULE_DEVICE_TABLE(of, pef2256_id_table);
+
+static struct platform_driver pef2256_driver = {
+ .driver = {
+ .name = "lantiq-pef2256",
+ .of_match_table = pef2256_id_table,
+ },
+ .probe = pef2256_probe,
+ .remove = pef2256_remove,
+};
+module_platform_driver(pef2256_driver);
+
+struct regmap *pef2256_get_regmap(struct pef2256 *pef2256)
+{
+ return pef2256->regmap;
+}
+EXPORT_SYMBOL_GPL(pef2256_get_regmap);
+
+MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>");
+MODULE_DESCRIPTION("PEF2256 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
index fd50bb313b92..605e70f7baac 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -1259,7 +1259,7 @@ free_uhdlc_priv:
return ret;
}
-static int ucc_hdlc_remove(struct platform_device *pdev)
+static void ucc_hdlc_remove(struct platform_device *pdev)
{
struct ucc_hdlc_private *priv = dev_get_drvdata(&pdev->dev);
@@ -1277,8 +1277,6 @@ static int ucc_hdlc_remove(struct platform_device *pdev)
kfree(priv);
dev_info(&pdev->dev, "UCC based hdlc module removed\n");
-
- return 0;
}
static const struct of_device_id fsl_ucc_hdlc_of_match[] = {
@@ -1292,7 +1290,7 @@ MODULE_DEVICE_TABLE(of, fsl_ucc_hdlc_of_match);
static struct platform_driver ucc_hdlc_driver = {
.probe = ucc_hdlc_probe,
- .remove = ucc_hdlc_remove,
+ .remove_new = ucc_hdlc_remove,
.driver = {
.name = DRV_NAME,
.pm = HDLC_PM_OPS,
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index b09f4c235142..931c5ca79ea5 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -1522,20 +1522,19 @@ err_plat:
return err;
}
-static int ixp4xx_hss_remove(struct platform_device *pdev)
+static void ixp4xx_hss_remove(struct platform_device *pdev)
{
struct port *port = platform_get_drvdata(pdev);
unregister_hdlc_device(port->netdev);
free_netdev(port->netdev);
npe_release(port->npe);
- return 0;
}
static struct platform_driver ixp4xx_hss_driver = {
.driver.name = DRV_NAME,
.probe = ixp4xx_hss_probe,
- .remove = ixp4xx_hss_remove,
+ .remove_new = ixp4xx_hss_remove,
};
module_platform_driver(ixp4xx_hss_driver);
diff --git a/drivers/net/wan/slic_ds26522.c b/drivers/net/wan/slic_ds26522.c
index 8a51cfcff99e..cbb99fc5ea9f 100644
--- a/drivers/net/wan/slic_ds26522.c
+++ b/drivers/net/wan/slic_ds26522.c
@@ -28,6 +28,7 @@
static struct spi_device *g_spi;
+MODULE_DESCRIPTION("Slic Maxim DS26522 driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Zhao Qiang<B45475@freescale.com>");
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7555af5195ec..c6599594dc99 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -22,7 +22,6 @@ source "drivers/net/wireless/admtek/Kconfig"
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/atmel/Kconfig"
source "drivers/net/wireless/broadcom/Kconfig"
-source "drivers/net/wireless/cisco/Kconfig"
source "drivers/net/wireless/intel/Kconfig"
source "drivers/net/wireless/intersil/Kconfig"
source "drivers/net/wireless/marvell/Kconfig"
@@ -38,8 +37,6 @@ source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
source "drivers/net/wireless/quantenna/Kconfig"
-source "drivers/net/wireless/legacy/Kconfig"
-
source "drivers/net/wireless/virtual/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 4d7374d567d1..e1c4141c6004 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/
obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/
obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/
obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/
-obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/
obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/
obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/
obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/
@@ -23,5 +22,4 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/
obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
-obj-$(CONFIG_WLAN) += legacy/
obj-$(CONFIG_WLAN) += virtual/
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c
index 43e0db78d42b..a742cec44e3d 100644
--- a/drivers/net/wireless/ath/ar5523/ar5523.c
+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
@@ -1803,5 +1803,6 @@ static struct usb_driver ar5523_driver = {
module_usb_driver(ar5523_driver);
+MODULE_DESCRIPTION("Atheros AR5523 wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_FIRMWARE(AR5523_FIRMWARE_FILE);
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c
index af6546572df2..9a4f8e815412 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.c
+++ b/drivers/net/wireless/ath/ath10k/bmi.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "bmi.h"
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index c27b8204718a..afae4a8027f8 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "hif.h"
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 6cdb225b7eac..0032f8aa892f 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -100,6 +101,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA988X_HW_2_0_VERSION,
@@ -140,6 +142,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA9887_HW_1_0_VERSION,
@@ -181,6 +184,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA6174_HW_3_2_VERSION,
@@ -217,6 +221,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
@@ -257,6 +262,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA6174_HW_2_1_VERSION,
@@ -297,6 +303,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA6174_HW_3_0_VERSION,
@@ -337,6 +344,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA6174_HW_3_2_VERSION,
@@ -381,6 +389,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = true,
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -427,6 +436,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA9984_HW_1_0_DEV_VERSION,
@@ -480,6 +490,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA9888_HW_2_0_DEV_VERSION,
@@ -530,6 +541,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
@@ -570,6 +582,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
@@ -612,6 +625,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA9377_HW_1_1_DEV_VERSION,
@@ -645,6 +659,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = QCA4019_HW_1_0_DEV_VERSION,
@@ -692,6 +707,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = false,
.use_fw_tx_credits = true,
.delay_unmap_buffer = false,
+ .mcast_frame_registration = false,
},
{
.id = WCN3990_HW_1_0_DEV_VERSION,
@@ -725,6 +741,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.hw_restart_disconnect = true,
.use_fw_tx_credits = false,
.delay_unmap_buffer = true,
+ .mcast_frame_registration = false,
},
};
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4b5239de4018..c110d15528bd 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _CORE_H_
@@ -607,7 +608,7 @@ struct ath10k_vif {
u8 tim_bitmap[64];
u8 tim_len;
u32 ssid_len;
- u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN] __nonstring;
bool hidden_ssid;
/* P2P_IE with NoA attribute for P2P_GO case */
u32 noa_len;
diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c
index 2d1634a890dd..bb3a276b7ed5 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.c
+++ b/drivers/net/wireless/ath/ath10k/coredump.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "coredump.h"
diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h
index 437b9759f05d..e5ef0352e319 100644
--- a/drivers/net/wireless/ath/ath10k/coredump.h
+++ b/drivers/net/wireless/ath/ath10k/coredump.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: ISC */
/*
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _COREDUMP_H_
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index ad9cf953a2fc..b93a64bf8190 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
index 87a3365330ff..394bf3c32abf 100644
--- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 5bfeecb95fca..a6e21ce90bad 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath10k/htc.h b/drivers/net/wireless/ath/ath10k/htc.h
index 0d180faf3b77..7ff665020015 100644
--- a/drivers/net/wireless/ath/ath10k/htc.h
+++ b/drivers/net/wireless/ath/ath10k/htc.h
@@ -246,26 +246,12 @@ struct ath10k_htc_lookahead_bundle {
struct ath10k_htc_record {
struct ath10k_ath10k_htc_record_hdr hdr;
union {
- struct ath10k_htc_credit_report credit_report[0];
- struct ath10k_htc_lookahead_report lookahead_report[0];
- struct ath10k_htc_lookahead_bundle lookahead_bundle[0];
- u8 pauload[0];
+ DECLARE_FLEX_ARRAY(struct ath10k_htc_credit_report, credit_report);
+ DECLARE_FLEX_ARRAY(struct ath10k_htc_lookahead_report, lookahead_report);
+ DECLARE_FLEX_ARRAY(struct ath10k_htc_lookahead_bundle, lookahead_bundle);
};
} __packed __aligned(4);
-/*
- * note: the trailer offset is dynamic depending
- * on payload length. this is only a struct layout draft
- */
-struct ath10k_htc_frame {
- struct ath10k_htc_hdr hdr;
- union {
- struct ath10k_htc_msg msg;
- u8 payload[0];
- };
- struct ath10k_htc_record trailer[0];
-} __packed __aligned(4);
-
/*******************/
/* Host-side stuff */
/*******************/
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index c80470e8886a..4a9270e2a4c8 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _HTT_H_
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index b261d6371c0f..7d28ae5453cf 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
@@ -1294,7 +1295,7 @@ static void ath10k_htt_rx_h_ppdu(struct ath10k *ar,
status->encoding = RX_ENC_LEGACY;
status->bw = RATE_INFO_BW_20;
- status->flag &= ~RX_FLAG_MACTIME_END;
+ status->flag &= ~RX_FLAG_MACTIME;
status->flag |= RX_FLAG_NO_SIGNAL_VAL;
status->flag &= ~(RX_FLAG_AMPDU_IS_LAST);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index be4d4536aaa8..9725feecefd6 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/etherdevice.h>
@@ -40,7 +41,6 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ath10k_sta *arsta;
struct ath10k_vif *arvif = (void *)txq->vif->drv_priv;
- unsigned long frame_cnt;
unsigned long byte_cnt;
int idx;
u32 bit;
@@ -67,7 +67,7 @@ static void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
bit = BIT(peer_id % 32);
idx = peer_id / 32;
- ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt);
+ ieee80211_txq_get_depth(txq, NULL, &byte_cnt);
count = ath10k_htt_tx_txq_calc_size(byte_cnt);
if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) ||
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
index 6d32b43a4da6..8fafe096adff 100644
--- a/drivers/net/wireless/ath/ath10k/hw.c
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/types.h>
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 9643031a4427..93c073091996 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _HW_H_
@@ -639,6 +640,9 @@ struct ath10k_hw_params {
bool use_fw_tx_credits;
bool delay_unmap_buffer;
+
+ /* The hardware support multicast frame registrations */
+ bool mcast_frame_registration;
};
struct htt_resp;
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 2cf693f3fea9..090bcf148d0c 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "mac.h"
@@ -1242,7 +1243,7 @@ static bool ath10k_mac_monitor_vdev_is_needed(struct ath10k *ar)
return ar->monitor ||
(!test_bit(ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST,
ar->running_fw->fw_file.fw_features) &&
- (ar->filter_flags & FIF_OTHER_BSS)) ||
+ (ar->filter_flags & (FIF_OTHER_BSS | FIF_MCAST_ACTION))) ||
test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
}
@@ -6025,10 +6026,15 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
{
struct ath10k *ar = hw->priv;
int ret;
+ unsigned int supported = SUPPORTED_FILTERS;
mutex_lock(&ar->conf_mutex);
- *total_flags &= SUPPORTED_FILTERS;
+ if (ar->hw_params.mcast_frame_registration)
+ supported |= FIF_MCAST_ACTION;
+
+ *total_flags &= supported;
+
ar->filter_flags = *total_flags;
ret = ath10k_monitor_recalc(ar);
@@ -6121,9 +6127,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (ieee80211_vif_is_mesh(vif)) {
/* mesh doesn't use SSID but firmware needs it */
- strncpy(arvif->u.ap.ssid, "mesh",
- sizeof(arvif->u.ap.ssid));
arvif->u.ap.ssid_len = 4;
+ memcpy(arvif->u.ap.ssid, "mesh", arvif->u.ap.ssid_len);
}
}
@@ -10118,6 +10123,10 @@ int ath10k_mac_register(struct ath10k *ar)
NL80211_EXT_FEATURE_SET_SCAN_DWELL);
wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL);
+ if (ar->hw_params.mcast_frame_registration)
+ wiphy_ext_feature_set(ar->hw->wiphy,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
+
if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) ||
test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map))
wiphy_ext_feature_set(ar->hw->wiphy,
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 2f8c785277af..3de2de6d44bc 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/pci.h>
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index 480cd97ab739..27bb4cf2dfea 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _PCI_H_
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 52c1a3de8da6..38e939f572a9 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/completion.h>
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
index 1c81e454f943..0e85c75d2278 100644
--- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/soc/qcom/qmi.h>
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
index f0db991408dc..9f311f3bc9e7 100644
--- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: ISC */
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef WCN3990_QMI_SVC_V01_H
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index 777e53aa69dc..564293df1e9a 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _RX_DESC_H_
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 56fbcfb80bf8..0ab5433f6cf6 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -3,6 +3,7 @@
* Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012,2017 Qualcomm Atheros, Inc.
* Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com>
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
index cefd97323dfe..31c8d7fbb095 100644
--- a/drivers/net/wireless/ath/ath10k/thermal.c
+++ b/drivers/net/wireless/ath/ath10k/thermal.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
diff --git a/drivers/net/wireless/ath/ath10k/usb.h b/drivers/net/wireless/ath/ath10k/usb.h
index 48e066ba8162..7e4cfbb673c9 100644
--- a/drivers/net/wireless/ath/ath10k/usb.h
+++ b/drivers/net/wireless/ath/ath10k/usb.h
@@ -3,6 +3,7 @@
* Copyright (c) 2004-2011 Atheros Communications Inc.
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
* Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com>
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _USB_H_
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
index dbb48d70f2e9..83a8f07a687f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _WMI_TLV_H
#define _WMI_TLV_H
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 05fa7d4c0e1a..88befe92f95d 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/skbuff.h>
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index b112e8826093..9146df98fcee 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3,6 +3,7 @@
* Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _WMI_H_
diff --git a/drivers/net/wireless/ath/ath10k/wow.c b/drivers/net/wireless/ath/ath10k/wow.c
index 20b9aa8ddf7d..aa7b2e703f3d 100644
--- a/drivers/net/wireless/ath/ath10k/wow.c
+++ b/drivers/net/wireless/ath/ath10k/wow.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "mac.h"
diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig
index ad5cc6cac05b..27f0523bf967 100644
--- a/drivers/net/wireless/ath/ath11k/Kconfig
+++ b/drivers/net/wireless/ath/ath11k/Kconfig
@@ -2,7 +2,7 @@
config ATH11K
tristate "Qualcomm Technologies 802.11ax chipset support"
depends on MAC80211 && HAS_DMA
- depends on CRYPTO_MICHAEL_MIC
+ select CRYPTO_MICHAEL_MIC
select ATH_COMMON
select QCOM_QMI_HELPERS
help
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 235336ef2a7a..7c0a23517949 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -803,8 +803,8 @@ static int ath11k_core_get_rproc(struct ath11k_base *ab)
prproc = rproc_get_by_phandle(rproc_phandle);
if (!prproc) {
- ath11k_err(ab, "failed to get rproc\n");
- return -EINVAL;
+ ath11k_dbg(ab, ATH11K_DBG_AHB, "failed to get rproc, deferring\n");
+ return -EPROBE_DEFER;
}
ab_ahb->tgt_rproc = prproc;
@@ -1251,7 +1251,7 @@ static void ath11k_ahb_free_resources(struct ath11k_base *ab)
platform_set_drvdata(pdev, NULL);
}
-static int ath11k_ahb_remove(struct platform_device *pdev)
+static void ath11k_ahb_remove(struct platform_device *pdev)
{
struct ath11k_base *ab = platform_get_drvdata(pdev);
@@ -1267,8 +1267,6 @@ static int ath11k_ahb_remove(struct platform_device *pdev)
qmi_fail:
ath11k_ahb_free_resources(ab);
-
- return 0;
}
static void ath11k_ahb_shutdown(struct platform_device *pdev)
@@ -1296,7 +1294,7 @@ static struct platform_driver ath11k_ahb_driver = {
.of_match_table = ath11k_ahb_of_match,
},
.probe = ath11k_ahb_probe,
- .remove = ath11k_ahb_remove,
+ .remove_new = ath11k_ahb_remove,
.shutdown = ath11k_ahb_shutdown,
};
diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c
index 289d47ae92af..e66e86bdec20 100644
--- a/drivers/net/wireless/ath/ath11k/ce.c
+++ b/drivers/net/wireless/ath/ath11k/ce.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "dp_rx.h"
diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h
index c0f6a0ba86df..69946fc70077 100644
--- a/drivers/net/wireless/ath/ath11k/ce.h
+++ b/drivers/net/wireless/ath/ath11k/ce.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_CE_H
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index f12b606e2d2e..02e160d831be 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -368,10 +368,6 @@ struct ath11k_vif {
struct ieee80211_chanctx_conf chanctx;
struct ath11k_arp_ns_offload arp_ns_offload;
struct ath11k_rekey_data rekey_data;
-
-#ifdef CONFIG_ATH11K_DEBUGFS
- struct dentry *debugfs_twt;
-#endif /* CONFIG_ATH11K_DEBUGFS */
};
struct ath11k_vif_iter {
@@ -599,7 +595,6 @@ struct ath11k {
struct ath11k_base *ab;
struct ath11k_pdev *pdev;
struct ieee80211_hw *hw;
- struct ieee80211_ops *ops;
struct ath11k_pdev_wmi *wmi;
struct ath11k_pdev_dp dp;
u8 mac_addr[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c
index 5536e8642331..fbb6e8d8a476 100644
--- a/drivers/net/wireless/ath/ath11k/dbring.c
+++ b/drivers/net/wireless/ath/ath11k/dbring.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath11k/dbring.h b/drivers/net/wireless/ath/ath11k/dbring.h
index ef906c687b8c..2f93b78a50df 100644
--- a/drivers/net/wireless/ath/ath11k/dbring.h
+++ b/drivers/net/wireless/ath/ath11k/dbring.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_DBRING_H
diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c
index f5c8a34c8802..2b8544355fc1 100644
--- a/drivers/net/wireless/ath/ath11k/debug.c
+++ b/drivers/net/wireless/ath/ath11k/debug.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h
index 9c52804ef8ac..cc8934d15697 100644
--- a/drivers/net/wireless/ath/ath11k/debug.h
+++ b/drivers/net/wireless/ath/ath11k/debug.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_DEBUG_H_
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c
index be76e7d1c436..a48e737ef35d 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/vmalloc.h>
@@ -1893,35 +1894,30 @@ static const struct file_operations ath11k_fops_twt_resume_dialog = {
.open = simple_open
};
-void ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
+void ath11k_debugfs_op_vif_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
struct ath11k_base *ab = arvif->ar->ab;
+ struct dentry *debugfs_twt;
if (arvif->vif->type != NL80211_IFTYPE_AP &&
!(arvif->vif->type == NL80211_IFTYPE_STATION &&
test_bit(WMI_TLV_SERVICE_STA_TWT, ab->wmi_ab.svc_map)))
return;
- arvif->debugfs_twt = debugfs_create_dir("twt",
- arvif->vif->debugfs_dir);
- debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt,
+ debugfs_twt = debugfs_create_dir("twt",
+ arvif->vif->debugfs_dir);
+ debugfs_create_file("add_dialog", 0200, debugfs_twt,
arvif, &ath11k_fops_twt_add_dialog);
- debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt,
+ debugfs_create_file("del_dialog", 0200, debugfs_twt,
arvif, &ath11k_fops_twt_del_dialog);
- debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt,
+ debugfs_create_file("pause_dialog", 0200, debugfs_twt,
arvif, &ath11k_fops_twt_pause_dialog);
- debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt,
+ debugfs_create_file("resume_dialog", 0200, debugfs_twt,
arvif, &ath11k_fops_twt_resume_dialog);
}
-void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif)
-{
- if (!arvif->debugfs_twt)
- return;
-
- debugfs_remove_recursive(arvif->debugfs_twt);
- arvif->debugfs_twt = NULL;
-}
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h
index 3af0169f6cf2..a39e458637b0 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_DEBUGFS_H_
@@ -306,8 +307,8 @@ static inline int ath11k_debugfs_rx_filter(struct ath11k *ar)
return ar->debug.rx_filter;
}
-void ath11k_debugfs_add_interface(struct ath11k_vif *arvif);
-void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif);
+void ath11k_debugfs_op_vif_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
enum wmi_direct_buffer_module id,
enum ath11k_dbg_dbr_event event,
@@ -386,14 +387,6 @@ static inline int ath11k_debugfs_get_fw_stats(struct ath11k *ar,
return 0;
}
-static inline void ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
-{
-}
-
-static inline void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif)
-{
-}
-
static inline void
ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
enum wmi_direct_buffer_module id,
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
index 0207fc4910f3..870e86a31bf8 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
index 96219301f05b..476689bbd4da 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef DEBUG_HTT_STATS_H
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
index 8c177fba6f14..f56a24b6c8da 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.h b/drivers/net/wireless/ath/ath11k/debugfs_sta.h
index e6c11b3a40aa..ace877e19275 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_DEBUGFS_STA_H_
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index a7252b52555c..8975dc57ad77 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <crypto/hash.h>
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
index 15815af453b2..2f6dd69d3be2 100644
--- a/drivers/net/wireless/ath/ath11k/dp.h
+++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_DP_H
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 7eac93ce7a1d..afd481f5858f 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/ieee80211.h>
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index a5fa08bc623b..c1072e66e3e8 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.h b/drivers/net/wireless/ath/ath11k/dp_tx.h
index 68a21ea9b934..61be2265e09f 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.h
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_DP_TX_H
diff --git a/drivers/net/wireless/ath/ath11k/fw.c b/drivers/net/wireless/ath/ath11k/fw.c
index 8f84fba29886..4e36292a79db 100644
--- a/drivers/net/wireless/ath/ath11k/fw.c
+++ b/drivers/net/wireless/ath/ath11k/fw.c
@@ -133,7 +133,7 @@ static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab,
len -= ie_len;
data += ie_len;
- };
+ }
return 0;
diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c
index 23f3af8e372d..c060c4b5c0cc 100644
--- a/drivers/net/wireless/ath/ath11k/hal.c
+++ b/drivers/net/wireless/ath/ath11k/hal.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/dma-mapping.h>
#include "hal_tx.h"
diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h
index 1942d41d6de5..80447f488954 100644
--- a/drivers/net/wireless/ath/ath11k/hal.h
+++ b/drivers/net/wireless/ath/ath11k/hal.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HAL_H
diff --git a/drivers/net/wireless/ath/ath11k/hal_desc.h b/drivers/net/wireless/ath/ath11k/hal_desc.h
index d895ea878d9f..b2fd180bd28e 100644
--- a/drivers/net/wireless/ath/ath11k/hal_desc.h
+++ b/drivers/net/wireless/ath/ath11k/hal_desc.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.c b/drivers/net/wireless/ath/ath11k/hal_rx.c
index 41946795d620..e758ee8e17c9 100644
--- a/drivers/net/wireless/ath/ath11k/hal_rx.c
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "debug.h"
diff --git a/drivers/net/wireless/ath/ath11k/hal_rx.h b/drivers/net/wireless/ath/ath11k/hal_rx.h
index 472a52cf5889..0fa9aef9d533 100644
--- a/drivers/net/wireless/ath/ath11k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath11k/hal_rx.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HAL_RX_H
diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h
index d68ed4214dec..877a4073fed6 100644
--- a/drivers/net/wireless/ath/ath11k/hif.h
+++ b/drivers/net/wireless/ath/ath11k/hif.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _HIF_H_
diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c
index 2c2e425c8665..23054ab29a5e 100644
--- a/drivers/net/wireless/ath/ath11k/htc.c
+++ b/drivers/net/wireless/ath/ath11k/htc.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/skbuff.h>
#include <linux/ctype.h>
diff --git a/drivers/net/wireless/ath/ath11k/htc.h b/drivers/net/wireless/ath/ath11k/htc.h
index d31e501c807c..86f77eacaea7 100644
--- a/drivers/net/wireless/ath/ath11k/htc.h
+++ b/drivers/net/wireless/ath/ath11k/htc.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HTC_H
@@ -150,10 +151,7 @@ struct ath11k_htc_credit_report {
struct ath11k_htc_record {
struct ath11k_htc_record_hdr hdr;
- union {
- struct ath11k_htc_credit_report credit_report[0];
- u8 pauload[0];
- };
+ struct ath11k_htc_credit_report credit_report[];
} __packed __aligned(4);
enum ath11k_htc_svc_gid {
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index d7b5ec6e6904..77d8f9237680 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/types.h>
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index d51a99669dd6..1b070747a5db 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HW_H
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 7f7b39817773..b13525bbbb80 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4654,6 +4654,14 @@ static int ath11k_station_disassoc(struct ath11k *ar,
return 0;
}
+static u32 ath11k_mac_max_nss(const u8 *ht_mcs_mask, const u16 *vht_mcs_mask,
+ const u16 *he_mcs_mask)
+{
+ return max3(ath11k_mac_max_ht_nss(ht_mcs_mask),
+ ath11k_mac_max_vht_nss(vht_mcs_mask),
+ ath11k_mac_max_he_nss(he_mcs_mask));
+}
+
static void ath11k_sta_rc_update_wk(struct work_struct *wk)
{
struct ath11k *ar;
@@ -4699,9 +4707,7 @@ static void ath11k_sta_rc_update_wk(struct work_struct *wk)
mutex_lock(&ar->conf_mutex);
nss = max_t(u32, 1, nss);
- nss = min(nss, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask),
- ath11k_mac_max_vht_nss(vht_mcs_mask)),
- ath11k_mac_max_he_nss(he_mcs_mask)));
+ nss = min(nss, ath11k_mac_max_nss(ht_mcs_mask, vht_mcs_mask, he_mcs_mask));
if (changed & IEEE80211_RC_BW_CHANGED) {
/* Get the peer phymode */
@@ -6750,13 +6756,6 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
goto err;
}
- /* In the case of hardware recovery, debugfs files are
- * not deleted since ieee80211_ops.remove_interface() is
- * not invoked. In such cases, try to delete the files.
- * These will be re-created later.
- */
- ath11k_debugfs_remove_interface(arvif);
-
memset(arvif, 0, sizeof(*arvif));
arvif->ar = ar;
@@ -6933,8 +6932,6 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
ath11k_dp_vdev_tx_attach(ar, arvif);
- ath11k_debugfs_add_interface(arvif);
-
if (vif->type != NL80211_IFTYPE_MONITOR &&
test_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags)) {
ret = ath11k_mac_monitor_vdev_create(ar);
@@ -7050,8 +7047,6 @@ err_vdev_del:
/* Recalc txpower for remaining vdev */
ath11k_mac_txpower_recalc(ar);
- ath11k_debugfs_remove_interface(arvif);
-
/* TODO: recal traffic pause state based on the available vdevs */
mutex_unlock(&ar->conf_mutex);
@@ -8391,9 +8386,7 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
ath11k_warn(ar->ab,
"could not update fixed rate settings to all peers due to mcs/nss incompatibility\n");
nss = min_t(u32, ar->num_tx_chains,
- max(max(ath11k_mac_max_ht_nss(ht_mcs_mask),
- ath11k_mac_max_vht_nss(vht_mcs_mask)),
- ath11k_mac_max_he_nss(he_mcs_mask)));
+ ath11k_mac_max_nss(ht_mcs_mask, vht_mcs_mask, he_mcs_mask));
/* If multiple rates across different preambles are given
* we can reconfigure this info with all peers using PEER_ASSOC
@@ -9149,6 +9142,7 @@ static const struct ieee80211_ops ath11k_ops = {
#endif
#ifdef CONFIG_ATH11K_DEBUGFS
+ .vif_add_debugfs = ath11k_debugfs_op_vif_add,
.sta_add_debugfs = ath11k_debugfs_sta_op_add,
#endif
diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h
index 0231783ad754..0dfdeed5177b 100644
--- a/drivers/net/wireless/ath/ath11k/mac.h
+++ b/drivers/net/wireless/ath/ath11k/mac.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_MAC_H
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index afeabd6ecc67..6835c14b82cc 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/msi.h>
diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h
index 8d9f852da695..f81fba2644a4 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.h
+++ b/drivers/net/wireless/ath/ath11k/mhi.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_MHI_H
#define _ATH11K_MHI_H
diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c
index 16d1e332193f..15e2ceb22a44 100644
--- a/drivers/net/wireless/ath/ath11k/pcic.c
+++ b/drivers/net/wireless/ath/ath11k/pcic.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
@@ -460,8 +460,6 @@ void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab)
{
int i;
- set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
-
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
@@ -471,6 +469,8 @@ void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab)
}
ath11k_pcic_ext_grp_enable(irq_grp);
}
+
+ set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
}
EXPORT_SYMBOL(ath11k_pcic_ext_irq_enable);
diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c
index 1c79a932d17f..6d0126c39301 100644
--- a/drivers/net/wireless/ath/ath11k/peer.c
+++ b/drivers/net/wireless/ath/ath11k/peer.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h
index 9bd385d0a38c..3ad2f3355b14 100644
--- a/drivers/net/wireless/ath/ath11k/peer.h
+++ b/drivers/net/wireless/ath/ath11k/peer.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_PEER_H
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index c270dc46d506..2c7cab62b9bb 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/elf.h>
diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h
index d477e2be814b..7e06d100af57 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_QMI_H
diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c
index 3c7debae800a..b4fd4d2107c7 100644
--- a/drivers/net/wireless/ath/ath11k/reg.c
+++ b/drivers/net/wireless/ath/ath11k/reg.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/rtnetlink.h>
diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h
index 84daa6543b6a..f28902f85e41 100644
--- a/drivers/net/wireless/ath/ath11k/reg.h
+++ b/drivers/net/wireless/ath/ath11k/reg.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_REG_H
diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h
index 786d5f36f5e5..2da6da727278 100644
--- a/drivers/net/wireless/ath/ath11k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath11k/rx_desc.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_RX_DESC_H
#define ATH11K_RX_DESC_H
diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c
index 0b7b7122cc05..79e091134515 100644
--- a/drivers/net/wireless/ath/ath11k/spectral.c
+++ b/drivers/net/wireless/ath/ath11k/spectral.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/relay.h>
diff --git a/drivers/net/wireless/ath/ath11k/spectral.h b/drivers/net/wireless/ath/ath11k/spectral.h
index 96bfa16e18e9..789cff7c64a7 100644
--- a/drivers/net/wireless/ath/ath11k/spectral.h
+++ b/drivers/net/wireless/ath/ath11k/spectral.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_SPECTRAL_H
diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c
index c9b012f97ba5..c29b11ab5bfa 100644
--- a/drivers/net/wireless/ath/ath11k/thermal.c
+++ b/drivers/net/wireless/ath/ath11k/thermal.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
diff --git a/drivers/net/wireless/ath/ath11k/thermal.h b/drivers/net/wireless/ath/ath11k/thermal.h
index 83cb67686733..cdaf4e01d92e 100644
--- a/drivers/net/wireless/ath/ath11k/thermal.h
+++ b/drivers/net/wireless/ath/ath11k/thermal.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _ATH11K_THERMAL_
diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h
index 9535745fe026..235ab8ea715f 100644
--- a/drivers/net/wireless/ath/ath11k/trace.h
+++ b/drivers/net/wireless/ath/ath11k/trace.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index 2845b4313d3a..8a65fa04b48d 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/skbuff.h>
#include <linux/ctype.h>
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 100bb816b592..ff0a9a92beeb 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_WMI_H
@@ -1096,25 +1096,27 @@ enum wmi_tlv_vdev_param {
};
enum wmi_tlv_peer_flags {
- WMI_TLV_PEER_AUTH = 0x00000001,
- WMI_TLV_PEER_QOS = 0x00000002,
- WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004,
- WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010,
- WMI_TLV_PEER_APSD = 0x00000800,
- WMI_TLV_PEER_HT = 0x00001000,
- WMI_TLV_PEER_40MHZ = 0x00002000,
- WMI_TLV_PEER_STBC = 0x00008000,
- WMI_TLV_PEER_LDPC = 0x00010000,
- WMI_TLV_PEER_DYN_MIMOPS = 0x00020000,
- WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000,
- WMI_TLV_PEER_SPATIAL_MUX = 0x00200000,
- WMI_TLV_PEER_VHT = 0x02000000,
- WMI_TLV_PEER_80MHZ = 0x04000000,
- WMI_TLV_PEER_PMF = 0x08000000,
+ WMI_PEER_AUTH = 0x00000001,
+ WMI_PEER_QOS = 0x00000002,
+ WMI_PEER_NEED_PTK_4_WAY = 0x00000004,
+ WMI_PEER_NEED_GTK_2_WAY = 0x00000010,
+ WMI_PEER_HE = 0x00000400,
+ WMI_PEER_APSD = 0x00000800,
+ WMI_PEER_HT = 0x00001000,
+ WMI_PEER_40MHZ = 0x00002000,
+ WMI_PEER_STBC = 0x00008000,
+ WMI_PEER_LDPC = 0x00010000,
+ WMI_PEER_DYN_MIMOPS = 0x00020000,
+ WMI_PEER_STATIC_MIMOPS = 0x00040000,
+ WMI_PEER_SPATIAL_MUX = 0x00200000,
+ WMI_PEER_TWT_REQ = 0x00400000,
+ WMI_PEER_TWT_RESP = 0x00800000,
+ WMI_PEER_VHT = 0x02000000,
+ WMI_PEER_80MHZ = 0x04000000,
+ WMI_PEER_PMF = 0x08000000,
WMI_PEER_IS_P2P_CAPABLE = 0x20000000,
WMI_PEER_160MHZ = 0x40000000,
WMI_PEER_SAFEMODE_EN = 0x80000000,
-
};
/** Enum list of TLV Tags for each parameter structure type. */
@@ -2580,7 +2582,6 @@ struct wmi_service_available_event {
struct ath11k_pdev_wmi {
struct ath11k_wmi_base *wmi_ab;
enum ath11k_htc_ep_id eid;
- const struct wmi_peer_flags_map *peer_flags;
u32 rx_decap_mode;
wait_queue_head_t tx_ce_desc_wq;
};
@@ -4062,31 +4063,6 @@ struct wmi_unit_test_cmd {
#define MAX_SUPPORTED_RATES 128
-#define WMI_PEER_AUTH 0x00000001
-#define WMI_PEER_QOS 0x00000002
-#define WMI_PEER_NEED_PTK_4_WAY 0x00000004
-#define WMI_PEER_NEED_GTK_2_WAY 0x00000010
-#define WMI_PEER_HE 0x00000400
-#define WMI_PEER_APSD 0x00000800
-#define WMI_PEER_HT 0x00001000
-#define WMI_PEER_40MHZ 0x00002000
-#define WMI_PEER_STBC 0x00008000
-#define WMI_PEER_LDPC 0x00010000
-#define WMI_PEER_DYN_MIMOPS 0x00020000
-#define WMI_PEER_STATIC_MIMOPS 0x00040000
-#define WMI_PEER_SPATIAL_MUX 0x00200000
-#define WMI_PEER_TWT_REQ 0x00400000
-#define WMI_PEER_TWT_RESP 0x00800000
-#define WMI_PEER_VHT 0x02000000
-#define WMI_PEER_80MHZ 0x04000000
-#define WMI_PEER_PMF 0x08000000
-/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000.
- * Need to be cleaned up
- */
-#define WMI_PEER_IS_P2P_CAPABLE 0x20000000
-#define WMI_PEER_160MHZ 0x40000000
-#define WMI_PEER_SAFEMODE_EN 0x80000000
-
struct beacon_tmpl_params {
u8 vdev_id;
u32 tim_ie_offset;
@@ -5754,7 +5730,6 @@ struct ath11k_wmi_base {
struct completion unified_ready;
DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE);
wait_queue_head_t tx_credits_wq;
- const struct wmi_peer_flags_map *peer_flags;
u32 num_mem_chunks;
u32 rx_decap_mode;
struct wmi_host_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
diff --git a/drivers/net/wireless/ath/ath11k/wow.h b/drivers/net/wireless/ath/ath11k/wow.h
index 553ba850d910..c85811e3f42b 100644
--- a/drivers/net/wireless/ath/ath11k/wow.h
+++ b/drivers/net/wireless/ath/ath11k/wow.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _WOW_H_
diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig
index 4f9c514c13e7..e135d2b1b61d 100644
--- a/drivers/net/wireless/ath/ath12k/Kconfig
+++ b/drivers/net/wireless/ath/ath12k/Kconfig
@@ -2,7 +2,7 @@
config ATH12K
tristate "Qualcomm Technologies Wi-Fi 7 support (ath12k)"
depends on MAC80211 && HAS_DMA && PCI
- depends on CRYPTO_MICHAEL_MIC
+ select CRYPTO_MICHAEL_MIC
select QCOM_QMI_HELPERS
select MHI_BUS
select QRTR
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index b936760b5140..6c01b282fcd3 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -698,13 +698,15 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
ret = ath12k_core_rfkill_config(ab);
if (ret && ret != -EOPNOTSUPP) {
ath12k_err(ab, "failed to config rfkill: %d\n", ret);
- goto err_core_stop;
+ goto err_core_pdev_destroy;
}
mutex_unlock(&ab->core_lock);
return 0;
+err_core_pdev_destroy:
+ ath12k_core_pdev_destroy(ab);
err_core_stop:
ath12k_core_stop(ab);
ath12k_mac_destroy(ab);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 68c42ca44fcb..8458dc292821 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_CORE_H
@@ -199,6 +199,8 @@ enum ath12k_dev_flags {
ATH12K_FLAG_REGISTERED,
ATH12K_FLAG_QMI_FAIL,
ATH12K_FLAG_HTC_SUSPEND_COMPLETE,
+ ATH12K_FLAG_CE_IRQ_ENABLED,
+ ATH12K_FLAG_EXT_IRQ_ENABLED,
};
enum ath12k_monitor_flags {
@@ -467,7 +469,6 @@ struct ath12k {
struct ath12k_base *ab;
struct ath12k_pdev *pdev;
struct ieee80211_hw *hw;
- struct ieee80211_ops *ops;
struct ath12k_wmi_pdev *wmi;
struct ath12k_pdev_dp dp;
u8 mac_addr[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath12k/dbring.c b/drivers/net/wireless/ath/ath12k/dbring.c
index 8fbf868e6f7e..788160c84c68 100644
--- a/drivers/net/wireless/ath/ath12k/dbring.c
+++ b/drivers/net/wireless/ath/ath12k/dbring.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath12k/debug.c b/drivers/net/wireless/ath/ath12k/debug.c
index 45d33279e665..fe5a732ba9ec 100644
--- a/drivers/net/wireless/ath/ath12k/debug.c
+++ b/drivers/net/wireless/ath/ath12k/debug.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/vmalloc.h>
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index 6893466f61f0..a6f81f2f97ef 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <crypto/hash.h>
@@ -961,9 +961,7 @@ int ath12k_dp_service_srng(struct ath12k_base *ab,
struct ath12k_dp *dp = &ab->dp;
struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
- ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, 0,
- ab->hw_params->hal_params->rx_buf_rbm,
- true);
+ ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0);
}
/* TODO: Implement handler for other interrupts */
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index 61f765432516..1df3cdd46140 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_DP_H
@@ -31,7 +31,7 @@ struct dp_srng {
u32 ring_id;
};
-struct dp_rxdma_ring {
+struct dp_rxdma_mon_ring {
struct dp_srng refill_buf_ring;
struct idr bufs_idr;
/* Protects bufs_idr */
@@ -39,6 +39,11 @@ struct dp_rxdma_ring {
int bufs_max;
};
+struct dp_rxdma_ring {
+ struct dp_srng refill_buf_ring;
+ int bufs_max;
+};
+
#define ATH12K_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE)
struct dp_tx_ring {
@@ -353,8 +358,8 @@ struct ath12k_dp {
struct dp_rxdma_ring rx_refill_buf_ring;
struct dp_srng rx_mac_buf_ring[MAX_RXDMA_PER_PDEV];
struct dp_srng rxdma_err_dst_ring[MAX_RXDMA_PER_PDEV];
- struct dp_rxdma_ring rxdma_mon_buf_ring;
- struct dp_rxdma_ring tx_mon_buf_ring;
+ struct dp_rxdma_mon_ring rxdma_mon_buf_ring;
+ struct dp_rxdma_mon_ring tx_mon_buf_ring;
struct ath12k_reo_q_addr_lut reoq_lut;
};
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index f44bc5494ce7..be4b39f5fa80 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "dp_mon.h"
@@ -797,7 +797,7 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k_base *ab,
/* TODO: add msdu start parsing logic */
break;
case HAL_MON_BUF_ADDR: {
- struct dp_rxdma_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring;
+ struct dp_rxdma_mon_ring *buf_ring = &ab->dp.rxdma_mon_buf_ring;
struct dp_mon_packet_info *packet_info =
(struct dp_mon_packet_info *)tlv_data;
int buf_id = u32_get_bits(packet_info->cookie,
@@ -1091,7 +1091,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
spin_unlock_bh(&ar->ab->base_lock);
ath12k_dbg(ar->ab, ATH12K_DBG_DATA,
- "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
+ "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
msdu,
msdu->len,
peer ? peer->addr : NULL,
@@ -1104,6 +1104,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct
(status->bw == RATE_INFO_BW_40) ? "40" : "",
(status->bw == RATE_INFO_BW_80) ? "80" : "",
(status->bw == RATE_INFO_BW_160) ? "160" : "",
+ (status->bw == RATE_INFO_BW_320) ? "320" : "",
status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "",
status->rate_idx,
status->nss,
@@ -1259,7 +1260,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
}
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
- struct dp_rxdma_ring *buf_ring,
+ struct dp_rxdma_mon_ring *buf_ring,
int req_entries)
{
struct hal_mon_buf_ring *mon_buf;
@@ -1902,7 +1903,7 @@ ath12k_dp_mon_tx_parse_status_tlv(struct ath12k_base *ab,
}
case HAL_MON_BUF_ADDR: {
- struct dp_rxdma_ring *buf_ring = &ab->dp.tx_mon_buf_ring;
+ struct dp_rxdma_mon_ring *buf_ring = &ab->dp.tx_mon_buf_ring;
struct dp_mon_packet_info *packet_info =
(struct dp_mon_packet_info *)tlv_data;
int buf_id = u32_get_bits(packet_info->cookie,
@@ -2067,7 +2068,7 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id, int *budget,
struct ath12k_skb_rxcb *rxcb;
struct dp_srng *mon_dst_ring;
struct hal_srng *srng;
- struct dp_rxdma_ring *buf_ring;
+ struct dp_rxdma_mon_ring *buf_ring;
u64 cookie;
u32 ppdu_id;
int num_buffs_reaped = 0, srng_id, buf_id;
@@ -2480,7 +2481,7 @@ int ath12k_dp_mon_rx_process_stats(struct ath12k *ar, int mac_id,
struct ath12k_skb_rxcb *rxcb;
struct dp_srng *mon_dst_ring;
struct hal_srng *srng;
- struct dp_rxdma_ring *buf_ring;
+ struct dp_rxdma_mon_ring *buf_ring;
struct ath12k_sta *arsta = NULL;
struct ath12k_peer *peer;
u64 cookie;
diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.h b/drivers/net/wireless/ath/ath12k/dp_mon.h
index c18c385798a1..fb9e9c176ce5 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.h
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_DP_MON_H
@@ -80,7 +80,7 @@ ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
int mac_id, struct sk_buff *skb,
struct napi_struct *napi);
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
- struct dp_rxdma_ring *buf_ring,
+ struct dp_rxdma_mon_ring *buf_ring,
int req_entries);
int ath12k_dp_mon_srng_process(struct ath12k *ar, int mac_id,
int *budget, enum dp_monitor_mode monitor_mode,
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index 3543fadac4a5..1ee83f765929 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/ieee80211.h>
@@ -256,22 +256,20 @@ static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab)
}
/* Returns number of Rx buffers replenished */
-int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id,
+int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab,
struct dp_rxdma_ring *rx_ring,
- int req_entries,
- enum hal_rx_buf_return_buf_manager mgr,
- bool hw_cc)
+ int req_entries)
{
struct ath12k_buffer_addr *desc;
struct hal_srng *srng;
struct sk_buff *skb;
int num_free;
int num_remain;
- int buf_id;
u32 cookie;
dma_addr_t paddr;
struct ath12k_dp *dp = &ab->dp;
struct ath12k_rx_desc_info *rx_desc;
+ enum hal_rx_buf_return_buf_manager mgr = ab->hw_params->hal_params->rx_buf_rbm;
req_entries = min(req_entries, rx_ring->bufs_max);
@@ -307,42 +305,29 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id,
if (dma_mapping_error(ab->dev, paddr))
goto fail_free_skb;
- if (hw_cc) {
- spin_lock_bh(&dp->rx_desc_lock);
-
- /* Get desc from free list and store in used list
- * for cleanup purposes
- *
- * TODO: pass the removed descs rather than
- * add/read to optimize
- */
- rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list,
- struct ath12k_rx_desc_info,
- list);
- if (!rx_desc) {
- spin_unlock_bh(&dp->rx_desc_lock);
- goto fail_dma_unmap;
- }
-
- rx_desc->skb = skb;
- cookie = rx_desc->cookie;
- list_del(&rx_desc->list);
- list_add_tail(&rx_desc->list, &dp->rx_desc_used_list);
+ spin_lock_bh(&dp->rx_desc_lock);
+ /* Get desc from free list and store in used list
+ * for cleanup purposes
+ *
+ * TODO: pass the removed descs rather than
+ * add/read to optimize
+ */
+ rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list,
+ struct ath12k_rx_desc_info,
+ list);
+ if (!rx_desc) {
spin_unlock_bh(&dp->rx_desc_lock);
- } else {
- spin_lock_bh(&rx_ring->idr_lock);
- buf_id = idr_alloc(&rx_ring->bufs_idr, skb, 0,
- rx_ring->bufs_max * 3, GFP_ATOMIC);
- spin_unlock_bh(&rx_ring->idr_lock);
- if (buf_id < 0)
- goto fail_dma_unmap;
- cookie = u32_encode_bits(mac_id,
- DP_RXDMA_BUF_COOKIE_PDEV_ID) |
- u32_encode_bits(buf_id,
- DP_RXDMA_BUF_COOKIE_BUF_ID);
+ goto fail_dma_unmap;
}
+ rx_desc->skb = skb;
+ cookie = rx_desc->cookie;
+ list_del(&rx_desc->list);
+ list_add_tail(&rx_desc->list, &dp->rx_desc_used_list);
+
+ spin_unlock_bh(&dp->rx_desc_lock);
+
desc = ath12k_hal_srng_src_get_next_entry(ab, srng);
if (!desc)
goto fail_buf_unassign;
@@ -361,17 +346,11 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id,
return req_entries - num_remain;
fail_buf_unassign:
- if (hw_cc) {
- spin_lock_bh(&dp->rx_desc_lock);
- list_del(&rx_desc->list);
- list_add_tail(&rx_desc->list, &dp->rx_desc_free_list);
- rx_desc->skb = NULL;
- spin_unlock_bh(&dp->rx_desc_lock);
- } else {
- spin_lock_bh(&rx_ring->idr_lock);
- idr_remove(&rx_ring->bufs_idr, buf_id);
- spin_unlock_bh(&rx_ring->idr_lock);
- }
+ spin_lock_bh(&dp->rx_desc_lock);
+ list_del(&rx_desc->list);
+ list_add_tail(&rx_desc->list, &dp->rx_desc_free_list);
+ rx_desc->skb = NULL;
+ spin_unlock_bh(&dp->rx_desc_lock);
fail_dma_unmap:
dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb),
DMA_FROM_DEVICE);
@@ -385,8 +364,8 @@ fail_free_skb:
return req_entries - num_remain;
}
-static int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab,
- struct dp_rxdma_ring *rx_ring)
+static int ath12k_dp_rxdma_mon_buf_ring_free(struct ath12k_base *ab,
+ struct dp_rxdma_mon_ring *rx_ring)
{
struct sk_buff *skb;
int buf_id;
@@ -411,46 +390,49 @@ static int ath12k_dp_rxdma_buf_ring_free(struct ath12k_base *ab,
static int ath12k_dp_rxdma_buf_free(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
- struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
- ath12k_dp_rxdma_buf_ring_free(ab, rx_ring);
+ ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->rxdma_mon_buf_ring);
+
+ ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->tx_mon_buf_ring);
+
+ return 0;
+}
- rx_ring = &dp->rxdma_mon_buf_ring;
- ath12k_dp_rxdma_buf_ring_free(ab, rx_ring);
+static int ath12k_dp_rxdma_mon_ring_buf_setup(struct ath12k_base *ab,
+ struct dp_rxdma_mon_ring *rx_ring,
+ u32 ringtype)
+{
+ int num_entries;
- rx_ring = &dp->tx_mon_buf_ring;
- ath12k_dp_rxdma_buf_ring_free(ab, rx_ring);
+ num_entries = rx_ring->refill_buf_ring.size /
+ ath12k_hal_srng_get_entrysize(ab, ringtype);
+
+ rx_ring->bufs_max = num_entries;
+ ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries);
return 0;
}
static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab,
- struct dp_rxdma_ring *rx_ring,
- u32 ringtype)
+ struct dp_rxdma_ring *rx_ring)
{
int num_entries;
num_entries = rx_ring->refill_buf_ring.size /
- ath12k_hal_srng_get_entrysize(ab, ringtype);
+ ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF);
rx_ring->bufs_max = num_entries;
- if ((ringtype == HAL_RXDMA_MONITOR_BUF) || (ringtype == HAL_TX_MONITOR_BUF))
- ath12k_dp_mon_buf_replenish(ab, rx_ring, num_entries);
- else
- ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_entries,
- ab->hw_params->hal_params->rx_buf_rbm,
- ringtype == HAL_RXDMA_BUF);
+ ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries);
+
return 0;
}
static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
- struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
int ret;
- ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring,
- HAL_RXDMA_BUF);
+ ret = ath12k_dp_rxdma_ring_buf_setup(ab, &dp->rx_refill_buf_ring);
if (ret) {
ath12k_warn(ab,
"failed to setup HAL_RXDMA_BUF\n");
@@ -458,18 +440,18 @@ static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab)
}
if (ab->hw_params->rxdma1_enable) {
- rx_ring = &dp->rxdma_mon_buf_ring;
- ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring,
- HAL_RXDMA_MONITOR_BUF);
+ ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab,
+ &dp->rxdma_mon_buf_ring,
+ HAL_RXDMA_MONITOR_BUF);
if (ret) {
ath12k_warn(ab,
"failed to setup HAL_RXDMA_MONITOR_BUF\n");
return ret;
}
- rx_ring = &dp->tx_mon_buf_ring;
- ret = ath12k_dp_rxdma_ring_buf_setup(ab, rx_ring,
- HAL_TX_MONITOR_BUF);
+ ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab,
+ &dp->tx_mon_buf_ring,
+ HAL_TX_MONITOR_BUF);
if (ret) {
ath12k_warn(ab,
"failed to setup HAL_TX_MONITOR_BUF\n");
@@ -1339,9 +1321,6 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar,
u8 tid = HTT_PPDU_STATS_NON_QOS_TID;
bool is_ampdu = false;
- if (!usr_stats)
- return;
-
if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE)))
return;
@@ -2438,7 +2417,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
spin_unlock_bh(&ab->base_lock);
ath12k_dbg(ab, ATH12K_DBG_DATA,
- "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
+ "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
msdu,
msdu->len,
peer ? peer->addr : NULL,
@@ -2452,6 +2431,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap
(status->bw == RATE_INFO_BW_40) ? "40" : "",
(status->bw == RATE_INFO_BW_80) ? "80" : "",
(status->bw == RATE_INFO_BW_160) ? "160" : "",
+ (status->bw == RATE_INFO_BW_320) ? "320" : "",
status->enc_flags & RX_ENC_FLAG_SHORT_GI ? "sgi " : "",
status->rate_idx,
status->nss,
@@ -2714,9 +2694,7 @@ try_again:
if (!total_msdu_reaped)
goto exit;
- /* TODO: Move to implicit BM? */
- ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped,
- ab->hw_params->hal_params->rx_buf_rbm, true);
+ ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped);
ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list,
ring_id);
@@ -3494,8 +3472,7 @@ exit:
rx_ring = &dp->rx_refill_buf_ring;
- ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, tot_n_bufs_reaped,
- ab->hw_params->hal_params->rx_buf_rbm, true);
+ ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped);
return tot_n_bufs_reaped;
}
@@ -3808,8 +3785,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
if (!num_buffs_reaped)
goto done;
- ath12k_dp_rx_bufs_replenish(ab, 0, rx_ring, num_buffs_reaped,
- ab->hw_params->hal_params->rx_buf_rbm, true);
+ ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped);
rcu_read_lock();
for (i = 0; i < ab->num_radios; i++) {
@@ -4090,9 +4066,6 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab)
struct ath12k_dp *dp = &ab->dp;
int i, ret;
- idr_init(&dp->rx_refill_buf_ring.bufs_idr);
- spin_lock_init(&dp->rx_refill_buf_ring.idr_lock);
-
idr_init(&dp->rxdma_mon_buf_ring.bufs_idr);
spin_lock_init(&dp->rxdma_mon_buf_ring.idr_lock);
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index c955b5c859d1..05b3d5581dbe 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_DP_RX_H
#define ATH12K_DP_RX_H
@@ -116,11 +116,9 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id,
struct napi_struct *napi,
int budget);
-int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, int mac_id,
+int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab,
struct dp_rxdma_ring *rx_ring,
- int req_entries,
- enum hal_rx_buf_return_buf_manager mgr,
- bool hw_cc);
+ int req_entries);
int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar);
int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id);
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
index 492ca6ce6714..62f9cdbb811c 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c
index eca86fc25a60..a489369d8068 100644
--- a/drivers/net/wireless/ath/ath12k/hal.c
+++ b/drivers/net/wireless/ath/ath12k/hal.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/dma-mapping.h>
#include "hal_tx.h"
@@ -889,8 +889,8 @@ static u8 *ath12k_hw_wcn7850_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc)
static bool ath12k_hw_wcn7850_rx_desc_is_da_mcbc(struct hal_rx_desc *desc)
{
- return __le16_to_cpu(desc->u.wcn7850.msdu_end.info5) &
- RX_MSDU_END_INFO5_DA_IS_MCBC;
+ return __le32_to_cpu(desc->u.wcn7850.msdu_end.info13) &
+ RX_MSDU_END_INFO13_MCAST_BCAST;
}
static void ath12k_hw_wcn7850_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc,
diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h
index 66035a787c72..fc47e7e6b498 100644
--- a/drivers/net/wireless/ath/ath12k/hal.h
+++ b/drivers/net/wireless/ath/ath12k/hal.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HAL_H
diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c
index f6afbd8196bf..4f25eb9f7745 100644
--- a/drivers/net/wireless/ath/ath12k/hal_rx.c
+++ b/drivers/net/wireless/ath/ath12k/hal_rx.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "debug.h"
diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h
index fcfb6c819047..095216eabc01 100644
--- a/drivers/net/wireless/ath/ath12k/hal_rx.h
+++ b/drivers/net/wireless/ath/ath12k/hal_rx.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HAL_RX_H
@@ -61,6 +61,7 @@ enum hal_rx_bw {
HAL_RX_BW_40MHZ,
HAL_RX_BW_80MHZ,
HAL_RX_BW_160MHZ,
+ HAL_RX_BW_320MHZ,
HAL_RX_BW_MAX,
};
diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h
index 4095fd82b1b3..c653ca1f59b2 100644
--- a/drivers/net/wireless/ath/ath12k/hif.h
+++ b/drivers/net/wireless/ath/ath12k/hif.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HIF_H
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 2245fb510ba2..de60d988d860 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/types.h>
@@ -949,7 +949,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
.rx_mac_buf_ring = true,
.vdev_start_delay = true,
- .interface_modes = BIT(NL80211_IFTYPE_STATION),
+ .interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_AP),
.supports_monitor = false,
.idle_ps = true,
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index 2d6427cf41a4..d2622bfef942 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_HW_H
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index fc0d14ea328e..88cec54c6c2e 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <net/mac80211.h>
@@ -343,6 +343,9 @@ ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw)
case ATH12K_BW_160:
ret = RATE_INFO_BW_160;
break;
+ case ATH12K_BW_320:
+ ret = RATE_INFO_BW_320;
+ break;
}
return ret;
@@ -359,6 +362,8 @@ enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw b
return ATH12K_BW_80;
case RATE_INFO_BW_160:
return ATH12K_BW_160;
+ case RATE_INFO_BW_320:
+ return ATH12K_BW_320;
default:
return ATH12K_BW_20;
}
@@ -3726,6 +3731,9 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar,
case IEEE80211_STA_RX_BW_160:
bw = WMI_PEER_CHWIDTH_160MHZ;
break;
+ case IEEE80211_STA_RX_BW_320:
+ bw = WMI_PEER_CHWIDTH_320MHZ;
+ break;
default:
ath12k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n",
sta->deflink.bandwidth, sta->addr);
@@ -4987,7 +4995,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw,
if (ret) {
ath12k_warn(ar->ab, "failed to queue management frame %d\n",
ret);
- ieee80211_free_txskb(ar->hw, skb);
+ ieee80211_free_txskb(hw, skb);
}
return;
}
@@ -4995,7 +5003,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw,
ret = ath12k_dp_tx(ar, arvif, skb);
if (ret) {
ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret);
- ieee80211_free_txskb(ar->hw, skb);
+ ieee80211_free_txskb(hw, skb);
}
}
@@ -5596,7 +5604,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
goto err_peer_del;
param_id = WMI_VDEV_PARAM_RTS_THRESHOLD;
- param_value = ar->hw->wiphy->rts_threshold;
+ param_value = hw->wiphy->rts_threshold;
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value);
if (ret) {
@@ -6258,10 +6266,11 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar,
struct ieee80211_chanctx_conf *ctx)
{
struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx };
+ struct ieee80211_hw *hw = ar->hw;
lockdep_assert_held(&ar->conf_mutex);
- ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ ieee80211_iterate_active_interfaces_atomic(hw,
IEEE80211_IFACE_ITER_NORMAL,
ath12k_mac_change_chanctx_cnt_iter,
&arg);
@@ -6272,7 +6281,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar,
if (!arg.vifs)
return;
- ieee80211_iterate_active_interfaces_atomic(ar->hw,
+ ieee80211_iterate_active_interfaces_atomic(hw,
IEEE80211_IFACE_ITER_NORMAL,
ath12k_mac_change_chanctx_fill_iter,
&arg);
@@ -6380,8 +6389,8 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
}
if (ab->hw_params->vdev_start_delay &&
- (arvif->vdev_type == WMI_VDEV_TYPE_AP ||
- arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)) {
+ arvif->vdev_type != WMI_VDEV_TYPE_AP &&
+ arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) {
param.vdev_id = arvif->vdev_id;
param.peer_type = WMI_PEER_TYPE_DEFAULT;
param.peer_addr = ar->mac_addr;
@@ -6836,7 +6845,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
arvif->vdev_id, ret);
return ret;
}
- ieee80211_iterate_stations_atomic(ar->hw,
+ ieee80211_iterate_stations_atomic(hw,
ath12k_mac_disable_peer_fixed_rate,
arvif);
} else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask,
@@ -6882,14 +6891,14 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
return -EINVAL;
}
- ieee80211_iterate_stations_atomic(ar->hw,
+ ieee80211_iterate_stations_atomic(hw,
ath12k_mac_disable_peer_fixed_rate,
arvif);
mutex_lock(&ar->conf_mutex);
arvif->bitrate_mask = *mask;
- ieee80211_iterate_stations_atomic(ar->hw,
+ ieee80211_iterate_stations_atomic(hw,
ath12k_mac_set_bitrate_mask_iter,
arvif);
@@ -6927,7 +6936,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
ar->pdev->pdev_id);
ar->state = ATH12K_STATE_ON;
- ieee80211_wake_queues(ar->hw);
+ ieee80211_wake_queues(hw);
if (ab->is_reset) {
recovery_count = atomic_inc_return(&ab->recovery_count);
@@ -7151,6 +7160,7 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band)
static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
u32 supported_bands)
{
+ struct ieee80211_hw *hw = ar->hw;
struct ieee80211_supported_band *band;
struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap;
void *channels;
@@ -7176,7 +7186,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_g_rates_size;
band->bitrates = ath12k_g_rates;
- ar->hw->wiphy->bands[NL80211_BAND_2GHZ] = band;
+ hw->wiphy->bands[NL80211_BAND_2GHZ] = band;
if (ar->ab->hw_params->single_pdev_only) {
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP);
@@ -7203,7 +7213,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_a_rates_size;
band->bitrates = ath12k_a_rates;
- ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band;
+ hw->wiphy->bands[NL80211_BAND_6GHZ] = band;
ath12k_mac_update_ch_list(ar, band,
reg_cap->low_5ghz_chan,
reg_cap->high_5ghz_chan);
@@ -7225,7 +7235,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
band->channels = channels;
band->n_bitrates = ath12k_a_rates_size;
band->bitrates = ath12k_a_rates;
- ar->hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
+ hw->wiphy->bands[NL80211_BAND_5GHZ] = band;
if (ar->ab->hw_params->single_pdev_only) {
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP);
@@ -7244,6 +7254,8 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
static int ath12k_mac_setup_iface_combinations(struct ath12k *ar)
{
struct ath12k_base *ab = ar->ab;
+ struct ieee80211_hw *hw = ar->hw;
+ struct wiphy *wiphy = hw->wiphy;
struct ieee80211_iface_combination *combinations;
struct ieee80211_iface_limit *limits;
int n_limits, max_interfaces;
@@ -7294,8 +7306,8 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k *ar)
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80);
- ar->hw->wiphy->iface_combinations = combinations;
- ar->hw->wiphy->n_iface_combinations = 1;
+ wiphy->iface_combinations = combinations;
+ wiphy->n_iface_combinations = 1;
return 0;
}
@@ -7339,9 +7351,12 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = {
static void __ath12k_mac_unregister(struct ath12k *ar)
{
+ struct ieee80211_hw *hw = ar->hw;
+ struct wiphy *wiphy = hw->wiphy;
+
cancel_work_sync(&ar->regd_update_work);
- ieee80211_unregister_hw(ar->hw);
+ ieee80211_unregister_hw(hw);
idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar);
idr_destroy(&ar->txmgmt_idr);
@@ -7350,10 +7365,10 @@ static void __ath12k_mac_unregister(struct ath12k *ar)
kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
- kfree(ar->hw->wiphy->iface_combinations[0].limits);
- kfree(ar->hw->wiphy->iface_combinations);
+ kfree(wiphy->iface_combinations[0].limits);
+ kfree(wiphy->iface_combinations);
- SET_IEEE80211_DEV(ar->hw, NULL);
+ SET_IEEE80211_DEV(hw, NULL);
}
void ath12k_mac_unregister(struct ath12k_base *ab)
@@ -7375,6 +7390,8 @@ void ath12k_mac_unregister(struct ath12k_base *ab)
static int __ath12k_mac_register(struct ath12k *ar)
{
struct ath12k_base *ab = ar->ab;
+ struct ieee80211_hw *hw = ar->hw;
+ struct wiphy *wiphy = hw->wiphy;
struct ath12k_pdev_cap *cap = &ar->pdev->cap;
static const u32 cipher_suites[] = {
WLAN_CIPHER_SUITE_TKIP,
@@ -7392,9 +7409,9 @@ static int __ath12k_mac_register(struct ath12k *ar)
ath12k_pdev_caps_update(ar);
- SET_IEEE80211_PERM_ADDR(ar->hw, ar->mac_addr);
+ SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr);
- SET_IEEE80211_DEV(ar->hw, ab->dev);
+ SET_IEEE80211_DEV(hw, ab->dev);
ret = ath12k_mac_setup_channels_rates(ar,
cap->supported_bands);
@@ -7410,103 +7427,102 @@ static int __ath12k_mac_register(struct ath12k *ar)
goto err_free_channels;
}
- ar->hw->wiphy->available_antennas_rx = cap->rx_chain_mask;
- ar->hw->wiphy->available_antennas_tx = cap->tx_chain_mask;
+ wiphy->available_antennas_rx = cap->rx_chain_mask;
+ wiphy->available_antennas_tx = cap->tx_chain_mask;
- ar->hw->wiphy->interface_modes = ab->hw_params->interface_modes;
+ wiphy->interface_modes = ab->hw_params->interface_modes;
- if (ar->hw->wiphy->bands[NL80211_BAND_2GHZ] &&
- ar->hw->wiphy->bands[NL80211_BAND_5GHZ] &&
- ar->hw->wiphy->bands[NL80211_BAND_6GHZ])
- ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS);
+ if (wiphy->bands[NL80211_BAND_2GHZ] &&
+ wiphy->bands[NL80211_BAND_5GHZ] &&
+ wiphy->bands[NL80211_BAND_6GHZ])
+ ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
- ieee80211_hw_set(ar->hw, SIGNAL_DBM);
- ieee80211_hw_set(ar->hw, SUPPORTS_PS);
- ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
- ieee80211_hw_set(ar->hw, MFP_CAPABLE);
- ieee80211_hw_set(ar->hw, REPORTS_TX_ACK_STATUS);
- ieee80211_hw_set(ar->hw, HAS_RATE_CONTROL);
- ieee80211_hw_set(ar->hw, AP_LINK_PS);
- ieee80211_hw_set(ar->hw, SPECTRUM_MGMT);
- ieee80211_hw_set(ar->hw, CONNECTION_MONITOR);
- ieee80211_hw_set(ar->hw, SUPPORTS_PER_STA_GTK);
- ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
- ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
- ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
- ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
+ ieee80211_hw_set(hw, SIGNAL_DBM);
+ ieee80211_hw_set(hw, SUPPORTS_PS);
+ ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
+ ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, AP_LINK_PS);
+ ieee80211_hw_set(hw, SPECTRUM_MGMT);
+ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+ ieee80211_hw_set(hw, SUPPORTS_PER_STA_GTK);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+ ieee80211_hw_set(hw, QUEUE_CONTROL);
+ ieee80211_hw_set(hw, SUPPORTS_TX_FRAG);
+ ieee80211_hw_set(hw, REPORTS_LOW_ACK);
if (ht_cap & WMI_HT_CAP_ENABLED) {
- ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
- ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
- ieee80211_hw_set(ar->hw, SUPPORTS_REORDERING_BUFFER);
- ieee80211_hw_set(ar->hw, SUPPORTS_AMSDU_IN_AMPDU);
- ieee80211_hw_set(ar->hw, USES_RSS);
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+ ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
+ ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
+ ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
+ ieee80211_hw_set(hw, USES_RSS);
}
- ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
- ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+ wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
+ wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
/* TODO: Check if HT capability advertised from firmware is different
* for each band for a dual band capable radio. It will be tricky to
* handle it when the ht capability different for each band.
*/
if (ht_cap & WMI_HT_CAP_DYNAMIC_SMPS)
- ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
+ wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
- ar->hw->wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
- ar->hw->wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
+ wiphy->max_scan_ssids = WLAN_SCAN_PARAMS_MAX_SSID;
+ wiphy->max_scan_ie_len = WLAN_SCAN_PARAMS_MAX_IE_LEN;
- ar->hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL;
+ hw->max_listen_interval = ATH12K_MAX_HW_LISTEN_INTERVAL;
- ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
- ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
- ar->hw->wiphy->max_remain_on_channel_duration = 5000;
+ wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+ wiphy->max_remain_on_channel_duration = 5000;
- ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
- ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
+ wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+ wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
NL80211_FEATURE_AP_SCAN;
ar->max_num_stations = TARGET_NUM_STATIONS;
ar->max_num_peers = TARGET_NUM_PEERS_PDEV;
- ar->hw->wiphy->max_ap_assoc_sta = ar->max_num_stations;
+ wiphy->max_ap_assoc_sta = ar->max_num_stations;
- ar->hw->queues = ATH12K_HW_MAX_QUEUES;
- ar->hw->wiphy->tx_queue_len = ATH12K_QUEUE_LEN;
- ar->hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1;
- ar->hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
+ hw->queues = ATH12K_HW_MAX_QUEUES;
+ wiphy->tx_queue_len = ATH12K_QUEUE_LEN;
+ hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1;
+ hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
- ar->hw->vif_data_size = sizeof(struct ath12k_vif);
- ar->hw->sta_data_size = sizeof(struct ath12k_sta);
+ hw->vif_data_size = sizeof(struct ath12k_vif);
+ hw->sta_data_size = sizeof(struct ath12k_sta);
- wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
- wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR);
- ar->hw->wiphy->cipher_suites = cipher_suites;
- ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+ wiphy->cipher_suites = cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
- ar->hw->wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa;
- ar->hw->wiphy->num_iftype_ext_capab =
- ARRAY_SIZE(ath12k_iftypes_ext_capa);
+ wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa;
+ wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa);
if (ar->supports_6ghz) {
- wiphy_ext_feature_set(ar->hw->wiphy,
+ wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_FILS_DISCOVERY);
- wiphy_ext_feature_set(ar->hw->wiphy,
+ wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
}
- wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_PUNCT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT);
- ath12k_reg_init(ar);
+ ath12k_reg_init(hw);
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
- ar->hw->netdev_features = NETIF_F_HW_CSUM;
- ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
- ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
+ hw->netdev_features = NETIF_F_HW_CSUM;
+ ieee80211_hw_set(hw, SW_CRYPTO_CONTROL);
+ ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
}
- ret = ieee80211_register_hw(ar->hw);
+ ret = ieee80211_register_hw(hw);
if (ret) {
ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret);
goto err_free_if_combs;
@@ -7518,7 +7534,7 @@ static int __ath12k_mac_register(struct ath12k *ar)
* while. But that time is so short and in practise it make
* a difference in real life.
*/
- ar->hw->wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
+ wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR);
/* Apply the regd received during initialization */
ret = ath12k_regd_update(ar, true);
@@ -7530,11 +7546,11 @@ static int __ath12k_mac_register(struct ath12k *ar)
return 0;
err_unregister_hw:
- ieee80211_unregister_hw(ar->hw);
+ ieee80211_unregister_hw(hw);
err_free_if_combs:
- kfree(ar->hw->wiphy->iface_combinations[0].limits);
- kfree(ar->hw->wiphy->iface_combinations);
+ kfree(wiphy->iface_combinations[0].limits);
+ kfree(wiphy->iface_combinations);
err_free_channels:
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
@@ -7542,7 +7558,7 @@ err_free_channels:
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
err:
- SET_IEEE80211_DEV(ar->hw, NULL);
+ SET_IEEE80211_DEV(hw, NULL);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 59b4e8f5eee0..7c63bb628adc 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_MAC_H
@@ -43,6 +43,7 @@ enum ath12k_supported_bw {
ATH12K_BW_40 = 1,
ATH12K_BW_80 = 2,
ATH12K_BW_160 = 3,
+ ATH12K_BW_320 = 4,
};
extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c
index 39e640293cdc..d5441ddb374b 100644
--- a/drivers/net/wireless/ath/ath12k/mhi.c
+++ b/drivers/net/wireless/ath/ath12k/mhi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/msi.h>
@@ -251,6 +251,7 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci)
u32 user_base_data, base_vector;
int ret, num_vectors, i;
int *irq;
+ unsigned int msi_data;
ret = ath12k_pci_get_user_msi_assignment(ab,
"MHI", &num_vectors,
@@ -265,9 +266,15 @@ static int ath12k_mhi_get_msi(struct ath12k_pci *ab_pci)
if (!irq)
return -ENOMEM;
- for (i = 0; i < num_vectors; i++)
- irq[i] = ath12k_pci_get_msi_irq(ab->dev,
- base_vector + i);
+ msi_data = base_vector;
+ for (i = 0; i < num_vectors; i++) {
+ if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ irq[i] = ath12k_pci_get_msi_irq(ab->dev,
+ msi_data++);
+ else
+ irq[i] = ath12k_pci_get_msi_irq(ab->dev,
+ msi_data);
+ }
ab_pci->mhi_ctrl->irq = irq;
ab_pci->mhi_ctrl->nr_irqs = num_vectors;
@@ -374,6 +381,9 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci)
goto free_controller;
}
+ if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
+
mhi_ctrl->iova_start = 0;
mhi_ctrl->iova_stop = 0xffffffff;
mhi_ctrl->sbl_size = SZ_512K;
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 3006cd3fbe11..f0d2e2d8719c 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -60,6 +60,17 @@ static const struct ath12k_msi_config ath12k_msi_config[] = {
},
};
+static const struct ath12k_msi_config msi_config_one_msi = {
+ .total_vectors = 1,
+ .total_users = 4,
+ .users = (struct ath12k_msi_user[]) {
+ { .name = "MHI", .num_vectors = 3, .base_vector = 0 },
+ { .name = "CE", .num_vectors = 1, .base_vector = 0 },
+ { .name = "WAKE", .num_vectors = 1, .base_vector = 0 },
+ { .name = "DP", .num_vectors = 1, .base_vector = 0 },
+ },
+};
+
static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"bhi",
"mhi-er0",
@@ -355,16 +366,30 @@ static void ath12k_pci_free_irq(struct ath12k_base *ab)
static void ath12k_pci_ce_irq_enable(struct ath12k_base *ab, u16 ce_id)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
u32 irq_idx;
+ /* In case of one MSI vector, we handle irq enable/disable in a
+ * uniform way since we only have one irq
+ */
+ if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ return;
+
irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id;
enable_irq(ab->irq_num[irq_idx]);
}
static void ath12k_pci_ce_irq_disable(struct ath12k_base *ab, u16 ce_id)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
u32 irq_idx;
+ /* In case of one MSI vector, we handle irq enable/disable in a
+ * uniform way since we only have one irq
+ */
+ if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ return;
+
irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_id;
disable_irq_nosync(ab->irq_num[irq_idx]);
}
@@ -373,6 +398,8 @@ static void ath12k_pci_ce_irqs_disable(struct ath12k_base *ab)
{
int i;
+ clear_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
+
for (i = 0; i < ab->hw_params->ce_count; i++) {
if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
continue;
@@ -397,20 +424,27 @@ static void ath12k_pci_sync_ce_irqs(struct ath12k_base *ab)
static void ath12k_pci_ce_tasklet(struct tasklet_struct *t)
{
struct ath12k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);
+ int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
ath12k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);
- ath12k_pci_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);
+ enable_irq(ce_pipe->ab->irq_num[irq_idx]);
}
static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg)
{
struct ath12k_ce_pipe *ce_pipe = arg;
+ struct ath12k_base *ab = ce_pipe->ab;
+ int irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num;
+
+ if (!test_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
+ return IRQ_HANDLED;
/* last interrupt received for this CE */
ce_pipe->timestamp = jiffies;
- ath12k_pci_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);
+ disable_irq_nosync(ab->irq_num[irq_idx]);
+
tasklet_schedule(&ce_pipe->intr_tq);
return IRQ_HANDLED;
@@ -418,8 +452,15 @@ static irqreturn_t ath12k_pci_ce_interrupt_handler(int irq, void *arg)
static void ath12k_pci_ext_grp_disable(struct ath12k_ext_irq_grp *irq_grp)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(irq_grp->ab);
int i;
+ /* In case of one MSI vector, we handle irq enable/disable
+ * in a uniform way since we only have one irq
+ */
+ if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ return;
+
for (i = 0; i < irq_grp->num_irq; i++)
disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
}
@@ -428,6 +469,8 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab)
{
int i;
+ clear_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
+
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
@@ -440,8 +483,15 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab)
static void ath12k_pci_ext_grp_enable(struct ath12k_ext_irq_grp *irq_grp)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(irq_grp->ab);
int i;
+ /* In case of one MSI vector, we handle irq enable/disable in a
+ * uniform way since we only have one irq
+ */
+ if (!test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ return;
+
for (i = 0; i < irq_grp->num_irq; i++)
enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
}
@@ -467,11 +517,13 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
napi);
struct ath12k_base *ab = irq_grp->ab;
int work_done;
+ int i;
work_done = ath12k_dp_service_srng(ab, irq_grp, budget);
if (work_done < budget) {
napi_complete_done(napi, work_done);
- ath12k_pci_ext_grp_enable(irq_grp);
+ for (i = 0; i < irq_grp->num_irq; i++)
+ enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
}
if (work_done > budget)
@@ -483,13 +535,19 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget)
static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg)
{
struct ath12k_ext_irq_grp *irq_grp = arg;
+ struct ath12k_base *ab = irq_grp->ab;
+ int i;
+
+ if (!test_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags))
+ return IRQ_HANDLED;
ath12k_dbg(irq_grp->ab, ATH12K_DBG_PCI, "ext irq:%d\n", irq);
/* last interrupt received for this group */
irq_grp->timestamp = jiffies;
- ath12k_pci_ext_grp_disable(irq_grp);
+ for (i = 0; i < irq_grp->num_irq; i++)
+ disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
napi_schedule(&irq_grp->napi);
@@ -498,6 +556,7 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg)
static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
int i, j, ret, num_vectors = 0;
u32 user_base_data = 0, base_vector = 0, base_idx;
@@ -544,23 +603,32 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
ret = request_irq(irq, ath12k_pci_ext_interrupt_handler,
- IRQF_SHARED,
+ ab_pci->irq_flags,
"DP_EXT_IRQ", irq_grp);
if (ret) {
ath12k_err(ab, "failed request irq %d: %d\n",
vector, ret);
return ret;
}
-
- disable_irq_nosync(ab->irq_num[irq_idx]);
}
+ ath12k_pci_ext_grp_disable(irq_grp);
}
return 0;
}
+static int ath12k_pci_set_irq_affinity_hint(struct ath12k_pci *ab_pci,
+ const struct cpumask *m)
+{
+ if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ return 0;
+
+ return irq_set_affinity_hint(ab_pci->pdev->irq, m);
+}
+
static int ath12k_pci_config_irq(struct ath12k_base *ab)
{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
struct ath12k_ce_pipe *ce_pipe;
u32 msi_data_start;
u32 msi_data_count, msi_data_idx;
@@ -589,7 +657,7 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab)
tasklet_setup(&ce_pipe->intr_tq, ath12k_pci_ce_tasklet);
ret = request_irq(irq, ath12k_pci_ce_interrupt_handler,
- IRQF_SHARED, irq_name[irq_idx],
+ ab_pci->irq_flags, irq_name[irq_idx],
ce_pipe);
if (ret) {
ath12k_err(ab, "failed to request irq %d: %d\n",
@@ -626,6 +694,8 @@ static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab)
{
int i;
+ set_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags);
+
for (i = 0; i < ab->hw_params->ce_count; i++) {
if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
continue;
@@ -670,16 +740,27 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci)
msi_config->total_vectors,
msi_config->total_vectors,
PCI_IRQ_MSI);
- if (num_vectors != msi_config->total_vectors) {
- ath12k_err(ab, "failed to get %d MSI vectors, only %d available",
- msi_config->total_vectors, num_vectors);
- if (num_vectors >= 0)
- return -EINVAL;
- else
- return num_vectors;
+ if (num_vectors == msi_config->total_vectors) {
+ set_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
+ ab_pci->irq_flags = IRQF_SHARED;
+ } else {
+ num_vectors = pci_alloc_irq_vectors(ab_pci->pdev,
+ 1,
+ 1,
+ PCI_IRQ_MSI);
+ if (num_vectors < 0) {
+ ret = -EINVAL;
+ goto reset_msi_config;
+ }
+ clear_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags);
+ ab_pci->msi_config = &msi_config_one_msi;
+ ab_pci->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
+ ath12k_dbg(ab, ATH12K_DBG_PCI, "request MSI one vector\n");
}
+ ath12k_info(ab, "MSI vectors: %d\n", num_vectors);
+
ath12k_pci_msi_disable(ab_pci);
msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
@@ -700,6 +781,7 @@ static int ath12k_pci_msi_alloc(struct ath12k_pci *ab_pci)
free_msi_vector:
pci_free_irq_vectors(ab_pci->pdev);
+reset_msi_config:
return ret;
}
@@ -708,6 +790,25 @@ static void ath12k_pci_msi_free(struct ath12k_pci *ab_pci)
pci_free_irq_vectors(ab_pci->pdev);
}
+static int ath12k_pci_config_msi_data(struct ath12k_pci *ab_pci)
+{
+ struct msi_desc *msi_desc;
+
+ msi_desc = irq_get_msi_desc(ab_pci->pdev->irq);
+ if (!msi_desc) {
+ ath12k_err(ab_pci->ab, "msi_desc is NULL!\n");
+ pci_free_irq_vectors(ab_pci->pdev);
+ return -EINVAL;
+ }
+
+ ab_pci->msi_ep_base_data = msi_desc->msg.data;
+
+ ath12k_dbg(ab_pci->ab, ATH12K_DBG_PCI, "pci after request_irq msi_ep_base_data %d\n",
+ ab_pci->msi_ep_base_data);
+
+ return 0;
+}
+
static int ath12k_pci_claim(struct ath12k_pci *ab_pci, struct pci_dev *pdev)
{
struct ath12k_base *ab = ab_pci->ab;
@@ -891,11 +992,11 @@ int ath12k_pci_get_user_msi_assignment(struct ath12k_base *ab, char *user_name,
for (idx = 0; idx < msi_config->total_users; idx++) {
if (strcmp(user_name, msi_config->users[idx].name) == 0) {
*num_vectors = msi_config->users[idx].num_vectors;
- *user_base_data = msi_config->users[idx].base_vector
- + ab_pci->msi_ep_base_data;
- *base_vector = msi_config->users[idx].base_vector;
+ *base_vector = msi_config->users[idx].base_vector;
+ *user_base_data = *base_vector + ab_pci->msi_ep_base_data;
- ath12k_dbg(ab, ATH12K_DBG_PCI, "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
+ ath12k_dbg(ab, ATH12K_DBG_PCI,
+ "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n",
user_name, *num_vectors, *user_base_data,
*base_vector);
@@ -956,6 +1057,8 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab)
{
int i;
+ set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags);
+
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
@@ -1000,7 +1103,10 @@ int ath12k_pci_start(struct ath12k_base *ab)
set_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags);
- ath12k_pci_aspm_restore(ab_pci);
+ if (test_bit(ATH12K_PCI_FLAG_MULTI_MSI_VECTORS, &ab_pci->flags))
+ ath12k_pci_aspm_restore(ab_pci);
+ else
+ ath12k_info(ab, "leaving PCI ASPM disabled to avoid MHI M2 problems\n");
ath12k_pci_ce_irqs_enable(ab);
ath12k_ce_rx_post_buf(ab);
@@ -1262,10 +1368,16 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
if (ret)
goto err_pci_msi_free;
+ ret = ath12k_pci_set_irq_affinity_hint(ab_pci, cpumask_of(0));
+ if (ret) {
+ ath12k_err(ab, "failed to set irq affinity %d\n", ret);
+ goto err_pci_msi_free;
+ }
+
ret = ath12k_mhi_register(ab_pci);
if (ret) {
ath12k_err(ab, "failed to register mhi: %d\n", ret);
- goto err_pci_msi_free;
+ goto err_irq_affinity_cleanup;
}
ret = ath12k_hal_srng_init(ab);
@@ -1286,6 +1398,17 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
goto err_ce_free;
}
+ /* kernel may allocate a dummy vector before request_irq and
+ * then allocate a real vector when request_irq is called.
+ * So get msi_data here again to avoid spurious interrupt
+ * as msi_data will configured to srngs.
+ */
+ ret = ath12k_pci_config_msi_data(ab_pci);
+ if (ret) {
+ ath12k_err(ab, "failed to config msi_data: %d\n", ret);
+ goto err_free_irq;
+ }
+
ret = ath12k_core_init(ab);
if (ret) {
ath12k_err(ab, "failed to init core: %d\n", ret);
@@ -1308,6 +1431,9 @@ err_mhi_unregister:
err_pci_msi_free:
ath12k_pci_msi_free(ab_pci);
+err_irq_affinity_cleanup:
+ ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
+
err_pci_free_region:
ath12k_pci_free_region(ab_pci);
@@ -1322,6 +1448,8 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
struct ath12k_base *ab = pci_get_drvdata(pdev);
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
+ ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
+
if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath12k_pci_power_down(ab);
ath12k_qmi_deinit_service(ab);
@@ -1348,7 +1476,9 @@ qmi_fail:
static void ath12k_pci_shutdown(struct pci_dev *pdev)
{
struct ath12k_base *ab = pci_get_drvdata(pdev);
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
+ ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
ath12k_pci_power_down(ab);
}
diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h
index 0f24fd9395cd..b2edf32ada20 100644
--- a/drivers/net/wireless/ath/ath12k/pci.h
+++ b/drivers/net/wireless/ath/ath12k/pci.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_PCI_H
#define ATH12K_PCI_H
@@ -84,6 +84,7 @@ enum ath12k_pci_flags {
ATH12K_PCI_FLAG_INIT_DONE,
ATH12K_PCI_FLAG_IS_MSI_64,
ATH12K_PCI_ASPM_RESTORE,
+ ATH12K_PCI_FLAG_MULTI_MSI_VECTORS,
};
struct ath12k_pci_ops {
@@ -108,6 +109,7 @@ struct ath12k_pci {
/* enum ath12k_pci_flags */
unsigned long flags;
u16 link_ctl;
+ unsigned long irq_flags;
const struct ath12k_pci_ops *pci_ops;
};
diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h
index c6edb24cbedd..7b3500b5c8c2 100644
--- a/drivers/net/wireless/ath/ath12k/peer.h
+++ b/drivers/net/wireless/ath/ath12k/peer.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_PEER_H
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index f6e949c618d0..77a132f6bbd1 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/elf.h>
diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h
index e20d6511d1ca..e25bbaa125e8 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.h
+++ b/drivers/net/wireless/ath/ath12k/qmi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_QMI_H
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 5c006256c82a..f924bc13ccff 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/rtnetlink.h>
#include "core.h"
@@ -28,11 +28,11 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
}
};
-static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
+static bool ath12k_regdom_changes(struct ieee80211_hw *hw, char *alpha2)
{
const struct ieee80211_regdomain *regd;
- regd = rcu_dereference_rtnl(ar->hw->wiphy->regd);
+ regd = rcu_dereference_rtnl(hw->wiphy->regd);
/* This can happen during wiphy registration where the previous
* user request is received before we update the regd received
* from firmware.
@@ -71,7 +71,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
return;
}
- if (!ath12k_regdom_changes(ar, request->alpha2)) {
+ if (!ath12k_regdom_changes(hw, request->alpha2)) {
ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Country is already set\n");
return;
}
@@ -199,6 +199,7 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig,
int ath12k_regd_update(struct ath12k *ar, bool init)
{
+ struct ieee80211_hw *hw = ar->hw;
struct ieee80211_regdomain *regd, *regd_copy = NULL;
int ret, regd_len, pdev_id;
struct ath12k_base *ab;
@@ -246,9 +247,9 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
}
rtnl_lock();
- wiphy_lock(ar->hw->wiphy);
- ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy);
- wiphy_unlock(ar->hw->wiphy);
+ wiphy_lock(hw->wiphy);
+ ret = regulatory_set_wiphy_regd_sync(hw->wiphy, regd_copy);
+ wiphy_unlock(hw->wiphy);
rtnl_unlock();
kfree(regd_copy);
@@ -729,10 +730,10 @@ void ath12k_regd_update_work(struct work_struct *work)
}
}
-void ath12k_reg_init(struct ath12k *ar)
+void ath12k_reg_init(struct ieee80211_hw *hw)
{
- ar->hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
- ar->hw->wiphy->reg_notifier = ath12k_reg_notifier;
+ hw->wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED;
+ hw->wiphy->reg_notifier = ath12k_reg_notifier;
}
void ath12k_reg_free(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
index 35569f03042d..29c7ec3260da 100644
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_REG_H
@@ -89,7 +89,7 @@ enum ath12k_reg_phy_bitmap {
ATH12K_REG_PHY_BITMAP_NO11BE = BIT(6),
};
-void ath12k_reg_init(struct ath12k *ar);
+void ath12k_reg_init(struct ieee80211_hw *hw);
void ath12k_reg_free(struct ath12k_base *ab);
void ath12k_regd_update_work(struct work_struct *work);
struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h
index c4058abc516e..55f20c446ca9 100644
--- a/drivers/net/wireless/ath/ath12k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath12k/rx_desc.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_RX_DESC_H
#define ATH12K_RX_DESC_H
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 0e5bf5ce8d4c..11cc3005c0f9 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/skbuff.h>
#include <linux/ctype.h>
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 629373d67421..06e5b9b4049b 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH12K_WMI_H
@@ -1146,25 +1146,27 @@ enum wmi_tlv_vdev_param {
};
enum wmi_tlv_peer_flags {
- WMI_TLV_PEER_AUTH = 0x00000001,
- WMI_TLV_PEER_QOS = 0x00000002,
- WMI_TLV_PEER_NEED_PTK_4_WAY = 0x00000004,
- WMI_TLV_PEER_NEED_GTK_2_WAY = 0x00000010,
- WMI_TLV_PEER_APSD = 0x00000800,
- WMI_TLV_PEER_HT = 0x00001000,
- WMI_TLV_PEER_40MHZ = 0x00002000,
- WMI_TLV_PEER_STBC = 0x00008000,
- WMI_TLV_PEER_LDPC = 0x00010000,
- WMI_TLV_PEER_DYN_MIMOPS = 0x00020000,
- WMI_TLV_PEER_STATIC_MIMOPS = 0x00040000,
- WMI_TLV_PEER_SPATIAL_MUX = 0x00200000,
- WMI_TLV_PEER_VHT = 0x02000000,
- WMI_TLV_PEER_80MHZ = 0x04000000,
- WMI_TLV_PEER_PMF = 0x08000000,
+ WMI_PEER_AUTH = 0x00000001,
+ WMI_PEER_QOS = 0x00000002,
+ WMI_PEER_NEED_PTK_4_WAY = 0x00000004,
+ WMI_PEER_NEED_GTK_2_WAY = 0x00000010,
+ WMI_PEER_HE = 0x00000400,
+ WMI_PEER_APSD = 0x00000800,
+ WMI_PEER_HT = 0x00001000,
+ WMI_PEER_40MHZ = 0x00002000,
+ WMI_PEER_STBC = 0x00008000,
+ WMI_PEER_LDPC = 0x00010000,
+ WMI_PEER_DYN_MIMOPS = 0x00020000,
+ WMI_PEER_STATIC_MIMOPS = 0x00040000,
+ WMI_PEER_SPATIAL_MUX = 0x00200000,
+ WMI_PEER_TWT_REQ = 0x00400000,
+ WMI_PEER_TWT_RESP = 0x00800000,
+ WMI_PEER_VHT = 0x02000000,
+ WMI_PEER_80MHZ = 0x04000000,
+ WMI_PEER_PMF = 0x08000000,
WMI_PEER_IS_P2P_CAPABLE = 0x20000000,
WMI_PEER_160MHZ = 0x40000000,
WMI_PEER_SAFEMODE_EN = 0x80000000,
-
};
enum wmi_tlv_peer_flags_ext {
@@ -2220,6 +2222,7 @@ enum wmi_peer_chwidth {
WMI_PEER_CHWIDTH_40MHZ = 1,
WMI_PEER_CHWIDTH_80MHZ = 2,
WMI_PEER_CHWIDTH_160MHZ = 3,
+ WMI_PEER_CHWIDTH_320MHZ = 4,
};
enum wmi_beacon_gen_mode {
@@ -3844,31 +3847,6 @@ struct wmi_unit_test_cmd {
#define MAX_SUPPORTED_RATES 128
-#define WMI_PEER_AUTH 0x00000001
-#define WMI_PEER_QOS 0x00000002
-#define WMI_PEER_NEED_PTK_4_WAY 0x00000004
-#define WMI_PEER_NEED_GTK_2_WAY 0x00000010
-#define WMI_PEER_HE 0x00000400
-#define WMI_PEER_APSD 0x00000800
-#define WMI_PEER_HT 0x00001000
-#define WMI_PEER_40MHZ 0x00002000
-#define WMI_PEER_STBC 0x00008000
-#define WMI_PEER_LDPC 0x00010000
-#define WMI_PEER_DYN_MIMOPS 0x00020000
-#define WMI_PEER_STATIC_MIMOPS 0x00040000
-#define WMI_PEER_SPATIAL_MUX 0x00200000
-#define WMI_PEER_TWT_REQ 0x00400000
-#define WMI_PEER_TWT_RESP 0x00800000
-#define WMI_PEER_VHT 0x02000000
-#define WMI_PEER_80MHZ 0x04000000
-#define WMI_PEER_PMF 0x08000000
-/* TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000.
- * Need to be cleaned up
- */
-#define WMI_PEER_IS_P2P_CAPABLE 0x20000000
-#define WMI_PEER_160MHZ 0x40000000
-#define WMI_PEER_SAFEMODE_EN 0x80000000
-
struct ath12k_wmi_vht_rate_set_params {
__le32 tlv_header;
__le32 rx_max_rate;
@@ -4770,7 +4748,6 @@ struct wmi_probe_tmpl_cmd {
struct ath12k_wmi_pdev {
struct ath12k_wmi_base *wmi_ab;
enum ath12k_htc_ep_id eid;
- const struct wmi_peer_flags_map *peer_flags;
u32 rx_decap_mode;
};
@@ -4784,7 +4761,6 @@ struct ath12k_wmi_base {
struct completion unified_ready;
DECLARE_BITMAP(svc_map, WMI_MAX_EXT2_SERVICE);
wait_queue_head_t tx_credits_wq;
- const struct wmi_peer_flags_map *peer_flags;
u32 num_mem_chunks;
u32 rx_decap_mode;
struct ath12k_wmi_host_mem_chunk_arg mem_chunks[WMI_MAX_MEM_REQS];
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 08bd5d3b00f1..f27308ccb2f1 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -185,7 +185,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
return ret;
}
-static int ath_ahb_remove(struct platform_device *pdev)
+static void ath_ahb_remove(struct platform_device *pdev)
{
struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
@@ -193,7 +193,7 @@ static int ath_ahb_remove(struct platform_device *pdev)
u32 reg;
if (!hw)
- return 0;
+ return;
ah = hw->priv;
@@ -215,13 +215,11 @@ static int ath_ahb_remove(struct platform_device *pdev)
ath5k_deinit_ah(ah);
iounmap(ah->iobase);
ieee80211_free_hw(hw);
-
- return 0;
}
static struct platform_driver ath_ahb_driver = {
.probe = ath_ahb_probe,
- .remove = ath_ahb_remove,
+ .remove_new = ath_ahb_remove,
.driver = {
.name = "ar231x-wmac",
},
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h
index 693296ee9693..e85b713950b1 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath/ath5k/eeprom.h
@@ -489,7 +489,4 @@ struct ath5k_eeprom_info {
/* Spur mitigation data (fbin values for spur channels) */
u16 ee_spur_chans[AR5K_EEPROM_N_SPUR_CHANS][AR5K_EEPROM_N_FREQ_BANDS];
-
- /* Antenna raw switch tables */
- u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
};
diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
index 708c8969b503..a5eb43f30320 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
+++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
@@ -125,7 +125,7 @@ static void owl_rescan(struct pci_dev *pdev)
static void owl_fw_cb(const struct firmware *fw, void *context)
{
- struct owl_ctx *ctx = (struct owl_ctx *)context;
+ struct owl_ctx *ctx = context;
complete(&ctx->eeprom_load);
diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c
index 82de0fadbc95..7c13a1deb3ac 100644
--- a/drivers/net/wireless/ath/ath9k/common-init.c
+++ b/drivers/net/wireless/ath/ath9k/common-init.c
@@ -124,7 +124,7 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
int ath9k_cmn_init_channels_rates(struct ath_common *common)
{
- struct ath_hw *ah = (struct ath_hw *)common->ah;
+ struct ath_hw *ah = common->ah;
void *channels;
BUILD_BUG_ON(ARRAY_SIZE(ath9k_2ghz_chantable) +
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index a5349c72c332..4b27445a5fb8 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -471,7 +471,7 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0};
struct ath_hw *ah = spec_priv->ah;
struct ath_common *common = ath9k_hw_common(spec_priv->ah);
- struct ath_softc *sc = (struct ath_softc *)common->priv;
+ struct ath_softc *sc = common->priv;
u8 num_bins, *vdata = (u8 *)hdr;
struct ath_radar_info *radar_info;
int len = rs->rs_datalen;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index a0376a6787b8..d84e3ee7b5d9 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1376,7 +1376,7 @@ void ath9k_deinit_debug(struct ath_softc *sc)
int ath9k_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc *sc = common->priv;
sc->debug.debugfs_phy = debugfs_create_dir("ath9k",
sc->hw->wiphy->debugfsdir);
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 90cfe39aa433..0c7841f95228 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -70,7 +70,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev);
static void hif_usb_regout_cb(struct urb *urb)
{
- struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
+ struct cmd_buf *cmd = urb->context;
switch (urb->status) {
case 0:
@@ -134,7 +134,7 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
static void hif_usb_mgmt_cb(struct urb *urb)
{
- struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
+ struct cmd_buf *cmd = urb->context;
struct hif_device_usb *hif_dev;
unsigned long flags;
bool txok = true;
@@ -252,7 +252,7 @@ static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
static void hif_usb_tx_cb(struct urb *urb)
{
- struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
+ struct tx_buf *tx_buf = urb->context;
struct hif_device_usb *hif_dev;
bool txok = true;
@@ -687,7 +687,7 @@ invalid_pkt:
static void ath9k_hif_usb_rx_cb(struct urb *urb)
{
- struct rx_buf *rx_buf = (struct rx_buf *)urb->context;
+ struct rx_buf *rx_buf = urb->context;
struct hif_device_usb *hif_dev = rx_buf->hif_dev;
struct sk_buff *skb = rx_buf->skb;
int ret;
@@ -734,7 +734,7 @@ free:
static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
{
- struct rx_buf *rx_buf = (struct rx_buf *)urb->context;
+ struct rx_buf *rx_buf = urb->context;
struct hif_device_usb *hif_dev = rx_buf->hif_dev;
struct sk_buff *skb = rx_buf->skb;
int ret;
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index 278ddc713fdc..f7c6d9bc9311 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -482,7 +482,7 @@ void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv)
int ath9k_htc_init_debug(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
priv->hw->wiphy->debugfsdir);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index dae3d9c7b640..0aa5bdeb44a1 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -63,12 +63,12 @@ static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
static void ath9k_htc_op_ps_wakeup(struct ath_common *common)
{
- ath9k_htc_ps_wakeup((struct ath9k_htc_priv *) common->priv);
+ ath9k_htc_ps_wakeup(common->priv);
}
static void ath9k_htc_op_ps_restore(struct ath_common *common)
{
- ath9k_htc_ps_restore((struct ath9k_htc_priv *) common->priv);
+ ath9k_htc_ps_restore(common->priv);
}
static const struct ath_ps_ops ath9k_htc_ps_ops = {
@@ -235,7 +235,7 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
__be32 val, reg = cpu_to_be32(reg_offset);
int r;
@@ -257,7 +257,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
__be32 tmpaddr[8];
__be32 tmpval[8];
int i, ret;
@@ -282,7 +282,7 @@ static void ath9k_multi_regread(void *hw_priv, u32 *addr,
static void ath9k_regwrite_multi(struct ath_common *common)
{
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
u32 rsp_status;
int r;
@@ -303,7 +303,7 @@ static void ath9k_regwrite_single(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
const __be32 buf[2] = {
cpu_to_be32(reg_offset),
cpu_to_be32(val),
@@ -324,7 +324,7 @@ static void ath9k_regwrite_buffer(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
mutex_lock(&priv->wmi->multi_write_mutex);
@@ -347,7 +347,7 @@ static void ath9k_regwrite(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
if (atomic_read(&priv->wmi->mwrite_cnt))
ath9k_regwrite_buffer(hw_priv, val, reg_offset);
@@ -359,7 +359,7 @@ static void ath9k_enable_regwrite_buffer(void *hw_priv)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
atomic_inc(&priv->wmi->mwrite_cnt);
}
@@ -368,7 +368,7 @@ static void ath9k_regwrite_flush(void *hw_priv)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
atomic_dec(&priv->wmi->mwrite_cnt);
@@ -385,7 +385,7 @@ static void ath9k_reg_rmw_buffer(void *hw_priv,
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
u32 rsp_status;
int r;
@@ -423,7 +423,7 @@ static void ath9k_reg_rmw_flush(void *hw_priv)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
u32 rsp_status;
int r;
@@ -455,7 +455,7 @@ static void ath9k_enable_rmw_buffer(void *hw_priv)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags))
return;
@@ -468,7 +468,7 @@ static void ath9k_reg_rmw_single(void *hw_priv,
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
struct register_rmw buf, buf_ret;
int ret;
@@ -490,7 +490,7 @@ static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+ struct ath9k_htc_priv *priv = common->priv;
if (test_bit(HTC_FWFLAG_NO_RMW, &priv->fw_flags)) {
u32 val;
@@ -518,7 +518,7 @@ static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_hw *ah = (struct ath_hw *) common->ah;
+ struct ath_hw *ah = common->ah;
(void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
@@ -970,7 +970,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
err_init:
ath9k_stop_wmi(priv);
- hif_dev = (struct hif_device_usb *)htc_handle->hif_dev;
+ hif_dev = htc_handle->hif_dev;
ath9k_hif_usb_dealloc_urbs(hif_dev);
ath9k_destroy_wmi(priv);
err_free:
@@ -988,7 +988,7 @@ void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
ath9k_deinit_device(htc_handle->drv_priv);
ath9k_stop_wmi(htc_handle->drv_priv);
- ath9k_hif_usb_dealloc_urbs((struct hif_device_usb *)htc_handle->hif_dev);
+ ath9k_hif_usb_dealloc_urbs(htc_handle->hif_dev);
ath9k_destroy_wmi(htc_handle->drv_priv);
ieee80211_free_hw(htc_handle->drv_priv->hw);
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 800177021baf..efcaeccb055a 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -652,9 +652,10 @@ void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event)
struct ath9k_htc_tx_event *tx_pend;
int i;
- for (i = 0; i < txs->cnt; i++) {
- WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
+ if (WARN_ON_ONCE(txs->cnt > HTC_MAX_TX_STATUS))
+ return;
+ for (i = 0; i < txs->cnt; i++) {
__txs = &txs->txstatus[i];
skb = ath9k_htc_tx_get_packet(priv, __txs);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 99667aba289d..eb631fd3336d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -89,7 +89,7 @@ static void htc_process_target_rdy(struct htc_target *target,
void *buf)
{
struct htc_endpoint *endpoint;
- struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
+ struct htc_ready_msg *htc_ready_msg = buf;
target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 4f00400c7ffb..7fad7e75af6a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -151,12 +151,12 @@ static void ath9k_deinit_softc(struct ath_softc *sc);
static void ath9k_op_ps_wakeup(struct ath_common *common)
{
- ath9k_ps_wakeup((struct ath_softc *) common->priv);
+ ath9k_ps_wakeup(common->priv);
}
static void ath9k_op_ps_restore(struct ath_common *common)
{
- ath9k_ps_restore((struct ath_softc *) common->priv);
+ ath9k_ps_restore(common->priv);
}
static const struct ath_ps_ops ath9k_ps_ops = {
@@ -174,7 +174,7 @@ static void ath9k_iowrite32(void *hw_priv, u32 val, u32 reg_offset)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc *sc = common->priv;
if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) {
unsigned long flags;
@@ -189,7 +189,7 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc *sc = common->priv;
u32 val;
if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_ON) {
@@ -229,7 +229,7 @@ static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 cl
{
struct ath_hw *ah = hw_priv;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc *sc = common->priv;
unsigned long flags;
u32 val;
@@ -608,7 +608,7 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
}
/* devres manages the calibration values release on shutdown */
- ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL);
+ ah->nvmem_blob = devm_kmemdup(sc->dev, buf, len, GFP_KERNEL);
kfree(buf);
if (!ah->nvmem_blob)
return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 9d84003db800..d1e5767aab3c 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -304,7 +304,7 @@ fail_paprd:
void ath_ani_calibrate(struct timer_list *t)
{
struct ath_common *common = from_timer(common, t, ani.timer);
- struct ath_softc *sc = (struct ath_softc *)common->priv;
+ struct ath_softc *sc = common->priv;
struct ath_hw *ah = sc->sc_ah;
bool longcal = false;
bool shortcal = false;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1494feedb27d..c48ff0ffbfef 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2383,7 +2383,22 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw,
{
struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct cfg80211_chan_def *chandef = &sc->cur_chan->chandef;
+ struct ieee80211_channel *chan = chandef->chan;
+ int pos = chan->hw_value;
set_bit(ATH_OP_SCANNING, &common->op_flags);
+
+ /* Reset current survey */
+ if (!sc->cur_chan->offchannel) {
+ if (sc->cur_survey != &sc->survey[pos]) {
+ if (sc->cur_survey)
+ sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
+ sc->cur_survey = &sc->survey[pos];
+ }
+
+ memset(sc->cur_survey, 0, sizeof(struct survey_info));
+ sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
+ }
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 0633589b85c2..e655cd8bbf94 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -781,7 +781,7 @@ static const struct pci_device_id ath_pci_id_table[] = {
/* return bus cachesize in 4B word units */
static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
{
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc *sc = common->priv;
u8 u8tmp;
pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE, &u8tmp);
@@ -799,7 +799,7 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz)
static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
{
- struct ath_hw *ah = (struct ath_hw *) common->ah;
+ struct ath_hw *ah = common->ah;
common->ops->read(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
@@ -820,7 +820,7 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
/* Need to be called after we discover btcoex capabilities */
static void ath_pci_aspm_init(struct ath_common *common)
{
- struct ath_softc *sc = (struct ath_softc *) common->priv;
+ struct ath_softc *sc = common->priv;
struct ath_hw *ah = sc->sc_ah;
struct pci_dev *pdev = to_pci_dev(sc->dev);
struct pci_dev *parent;
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 2bd1163177f0..4e6b4df8562f 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -1644,7 +1644,7 @@ out_err:
return ret;
}
-static int wcn36xx_remove(struct platform_device *pdev)
+static void wcn36xx_remove(struct platform_device *pdev)
{
struct ieee80211_hw *hw = platform_get_drvdata(pdev);
struct wcn36xx *wcn = hw->priv;
@@ -1666,8 +1666,6 @@ static int wcn36xx_remove(struct platform_device *pdev)
mutex_destroy(&wcn->hal_mutex);
ieee80211_free_hw(hw);
-
- return 0;
}
static const struct of_device_id wcn36xx_of_match[] = {
@@ -1678,7 +1676,7 @@ MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
static struct platform_driver wcn36xx_driver = {
.probe = wcn36xx_probe,
- .remove = wcn36xx_remove,
+ .remove_new = wcn36xx_remove,
.driver = {
.name = "wcn36xx",
.of_match_table = wcn36xx_of_match,
@@ -1687,6 +1685,7 @@ static struct platform_driver wcn36xx_driver = {
module_platform_driver(wcn36xx_driver);
+MODULE_DESCRIPTION("Qualcomm Atheros WCN3660/3680 wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
MODULE_FIRMWARE(WLAN_NV_FILE);
diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig
index bafdd57b049a..7a2bb7a58ab7 100644
--- a/drivers/net/wireless/atmel/Kconfig
+++ b/drivers/net/wireless/atmel/Kconfig
@@ -12,41 +12,6 @@ config WLAN_VENDOR_ATMEL
if WLAN_VENDOR_ATMEL
-config ATMEL
- tristate "Atmel at76c50x chipset 802.11b support"
- depends on CFG80211 && (PCI || PCMCIA) && HAS_IOPORT
- select WIRELESS_EXT
- select WEXT_PRIV
- select FW_LOADER
- select CRC32
- help
- A driver 802.11b wireless cards based on the Atmel fast-vnet
- chips. This driver supports standard Linux wireless extensions.
-
- Many cards based on this chipset do not have flash memory
- and need their firmware loaded at start-up. If yours is
- one of these, you will need to provide a firmware image
- to be loaded into the card by the driver. The Atmel
- firmware package can be downloaded from
- <http://www.thekelleys.org.uk/atmel>
-
-config PCI_ATMEL
- tristate "Atmel at76c506 PCI cards"
- depends on ATMEL && PCI
- help
- Enable support for PCI and mini-PCI cards containing the
- Atmel at76c506 chip.
-
-config PCMCIA_ATMEL
- tristate "Atmel at76c502/at76c504 PCMCIA cards"
- depends on ATMEL && PCMCIA
- select WIRELESS_EXT
- select FW_LOADER
- select CRC32
- help
- Enable support for PCMCIA cards containing the
- Atmel at76c502 and at76c504 chips.
-
config AT76C50X_USB
tristate "Atmel at76c503/at76c505/at76c505a USB cards"
depends on MAC80211 && USB
diff --git a/drivers/net/wireless/atmel/Makefile b/drivers/net/wireless/atmel/Makefile
index 17e62805677d..8338d7098ba6 100644
--- a/drivers/net/wireless/atmel/Makefile
+++ b/drivers/net/wireless/atmel/Makefile
@@ -1,6 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ATMEL) += atmel.o
-obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o
-obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o
-
obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o
diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c
deleted file mode 100644
index 461dce21de2b..000000000000
--- a/drivers/net/wireless/atmel/atmel.c
+++ /dev/null
@@ -1,4452 +0,0 @@
-/*** -*- linux-c -*- **********************************************************
-
- Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
-
- Copyright 2000-2001 ATMEL Corporation.
- Copyright 2003-2004 Simon Kelley.
-
- This code was developed from version 2.1.1 of the Atmel drivers,
- released by Atmel corp. under the GPL in December 2002. It also
- includes code from the Linux aironet drivers (C) Benjamin Reed,
- and the Linux PCMCIA package, (C) David Hinds and the Linux wireless
- extensions, (C) Jean Tourrilhes.
-
- The firmware module for reading the MAC address of the card comes from
- net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright
- by him. net.russotto.AtmelMACFW is used under the GPL license version 2.
- This file contains the module in binary form and, under the terms
- of the GPL, in source form. The source is located at the end of the file.
-
- 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 Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Atmel wireless lan drivers; if not, see
- <http://www.gnu.org/licenses/>.
-
- For all queries about this code, please contact the current author,
- Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
-
- Credit is due to HP UK and Cambridge Online Systems Ltd for supplying
- hardware used during development of this driver.
-
-******************************************************************************/
-
-#include <linux/interrupt.h>
-
-#include <linux/kernel.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/delay.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <linux/crc32.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/device.h>
-#include <linux/moduleparam.h>
-#include <linux/firmware.h>
-#include <linux/jiffies.h>
-#include <net/cfg80211.h>
-#include "atmel.h"
-
-#define DRIVER_MAJOR 0
-#define DRIVER_MINOR 98
-
-MODULE_AUTHOR("Simon Kelley");
-MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
-MODULE_LICENSE("GPL");
-
-/* The name of the firmware file to be loaded
- over-rides any automatic selection */
-static char *firmware = NULL;
-module_param(firmware, charp, 0);
-
-/* table of firmware file names */
-static struct {
- AtmelFWType fw_type;
- const char *fw_file;
- const char *fw_file_ext;
-} fw_table[] = {
- { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" },
- { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" },
- { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" },
- { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" },
- { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" },
- { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" },
- { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" },
- { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" },
- { ATMEL_FW_TYPE_NONE, NULL, NULL }
-};
-MODULE_FIRMWARE("atmel_at76c502-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c502.bin");
-MODULE_FIRMWARE("atmel_at76c502d-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c502d.bin");
-MODULE_FIRMWARE("atmel_at76c502e-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c502e.bin");
-MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c502_3com.bin");
-MODULE_FIRMWARE("atmel_at76c504-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c504.bin");
-MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c504_2958.bin");
-MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c504a_2958.bin");
-MODULE_FIRMWARE("atmel_at76c506-wpa.bin");
-MODULE_FIRMWARE("atmel_at76c506.bin");
-
-#define MAX_SSID_LENGTH 32
-#define MGMT_JIFFIES (256 * HZ / 100)
-
-#define MAX_BSS_ENTRIES 64
-
-/* registers */
-#define GCR 0x00 /* (SIR0) General Configuration Register */
-#define BSR 0x02 /* (SIR1) Bank Switching Select Register */
-#define AR 0x04
-#define DR 0x08
-#define MR1 0x12 /* Mirror Register 1 */
-#define MR2 0x14 /* Mirror Register 2 */
-#define MR3 0x16 /* Mirror Register 3 */
-#define MR4 0x18 /* Mirror Register 4 */
-
-#define GPR1 0x0c
-#define GPR2 0x0e
-#define GPR3 0x10
-/*
- * Constants for the GCR register.
- */
-#define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */
-#define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */
-#define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */
-#define GCR_ENINT 0x0002 /* Enable Interrupts */
-#define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */
-
-#define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */
-#define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */
-/*
- *Constants for the MR registers.
- */
-#define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */
-#define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */
-#define MAC_INIT_OK 0x0002 /* MAC boot has been completed */
-
-#define MIB_MAX_DATA_BYTES 212
-#define MIB_HEADER_SIZE 4 /* first four fields */
-
-struct get_set_mib {
- u8 type;
- u8 size;
- u8 index;
- u8 reserved;
- u8 data[MIB_MAX_DATA_BYTES];
-};
-
-struct rx_desc {
- u32 Next;
- u16 MsduPos;
- u16 MsduSize;
-
- u8 State;
- u8 Status;
- u8 Rate;
- u8 Rssi;
- u8 LinkQuality;
- u8 PreambleType;
- u16 Duration;
- u32 RxTime;
-};
-
-#define RX_DESC_FLAG_VALID 0x80
-#define RX_DESC_FLAG_CONSUMED 0x40
-#define RX_DESC_FLAG_IDLE 0x00
-
-#define RX_STATUS_SUCCESS 0x00
-
-#define RX_DESC_MSDU_POS_OFFSET 4
-#define RX_DESC_MSDU_SIZE_OFFSET 6
-#define RX_DESC_FLAGS_OFFSET 8
-#define RX_DESC_STATUS_OFFSET 9
-#define RX_DESC_RSSI_OFFSET 11
-#define RX_DESC_LINK_QUALITY_OFFSET 12
-#define RX_DESC_PREAMBLE_TYPE_OFFSET 13
-#define RX_DESC_DURATION_OFFSET 14
-#define RX_DESC_RX_TIME_OFFSET 16
-
-struct tx_desc {
- u32 NextDescriptor;
- u16 TxStartOfFrame;
- u16 TxLength;
-
- u8 TxState;
- u8 TxStatus;
- u8 RetryCount;
-
- u8 TxRate;
-
- u8 KeyIndex;
- u8 ChiperType;
- u8 ChipreLength;
- u8 Reserved1;
-
- u8 Reserved;
- u8 PacketType;
- u16 HostTxLength;
-};
-
-#define TX_DESC_NEXT_OFFSET 0
-#define TX_DESC_POS_OFFSET 4
-#define TX_DESC_SIZE_OFFSET 6
-#define TX_DESC_FLAGS_OFFSET 8
-#define TX_DESC_STATUS_OFFSET 9
-#define TX_DESC_RETRY_OFFSET 10
-#define TX_DESC_RATE_OFFSET 11
-#define TX_DESC_KEY_INDEX_OFFSET 12
-#define TX_DESC_CIPHER_TYPE_OFFSET 13
-#define TX_DESC_CIPHER_LENGTH_OFFSET 14
-#define TX_DESC_PACKET_TYPE_OFFSET 17
-#define TX_DESC_HOST_LENGTH_OFFSET 18
-
-/*
- * Host-MAC interface
- */
-
-#define TX_STATUS_SUCCESS 0x00
-
-#define TX_FIRM_OWN 0x80
-#define TX_DONE 0x40
-
-#define TX_ERROR 0x01
-
-#define TX_PACKET_TYPE_DATA 0x01
-#define TX_PACKET_TYPE_MGMT 0x02
-
-#define ISR_EMPTY 0x00 /* no bits set in ISR */
-#define ISR_TxCOMPLETE 0x01 /* packet transmitted */
-#define ISR_RxCOMPLETE 0x02 /* packet received */
-#define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */
-#define ISR_FATAL_ERROR 0x08 /* Fatal error */
-#define ISR_COMMAND_COMPLETE 0x10 /* command completed */
-#define ISR_OUT_OF_RANGE 0x20 /* command completed */
-#define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */
-#define ISR_GENERIC_IRQ 0x80
-
-#define Local_Mib_Type 0x01
-#define Mac_Address_Mib_Type 0x02
-#define Mac_Mib_Type 0x03
-#define Statistics_Mib_Type 0x04
-#define Mac_Mgmt_Mib_Type 0x05
-#define Mac_Wep_Mib_Type 0x06
-#define Phy_Mib_Type 0x07
-#define Multi_Domain_MIB 0x08
-
-#define MAC_MGMT_MIB_CUR_BSSID_POS 14
-#define MAC_MIB_FRAG_THRESHOLD_POS 8
-#define MAC_MIB_RTS_THRESHOLD_POS 10
-#define MAC_MIB_SHORT_RETRY_POS 16
-#define MAC_MIB_LONG_RETRY_POS 17
-#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16
-#define MAC_MGMT_MIB_BEACON_PER_POS 0
-#define MAC_MGMT_MIB_STATION_ID_POS 6
-#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11
-#define MAC_MGMT_MIB_CUR_BSSID_POS 14
-#define MAC_MGMT_MIB_PS_MODE_POS 53
-#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54
-#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56
-#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57
-#define PHY_MIB_CHANNEL_POS 14
-#define PHY_MIB_RATE_SET_POS 20
-#define PHY_MIB_REG_DOMAIN_POS 26
-#define LOCAL_MIB_AUTO_TX_RATE_POS 3
-#define LOCAL_MIB_SSID_SIZE 5
-#define LOCAL_MIB_TX_PROMISCUOUS_POS 6
-#define LOCAL_MIB_TX_MGMT_RATE_POS 7
-#define LOCAL_MIB_TX_CONTROL_RATE_POS 8
-#define LOCAL_MIB_PREAMBLE_TYPE 9
-#define MAC_ADDR_MIB_MAC_ADDR_POS 0
-
-#define CMD_Set_MIB_Vars 0x01
-#define CMD_Get_MIB_Vars 0x02
-#define CMD_Scan 0x03
-#define CMD_Join 0x04
-#define CMD_Start 0x05
-#define CMD_EnableRadio 0x06
-#define CMD_DisableRadio 0x07
-#define CMD_SiteSurvey 0x0B
-
-#define CMD_STATUS_IDLE 0x00
-#define CMD_STATUS_COMPLETE 0x01
-#define CMD_STATUS_UNKNOWN 0x02
-#define CMD_STATUS_INVALID_PARAMETER 0x03
-#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04
-#define CMD_STATUS_TIME_OUT 0x07
-#define CMD_STATUS_IN_PROGRESS 0x08
-#define CMD_STATUS_REJECTED_RADIO_OFF 0x09
-#define CMD_STATUS_HOST_ERROR 0xFF
-#define CMD_STATUS_BUSY 0xFE
-
-#define CMD_BLOCK_COMMAND_OFFSET 0
-#define CMD_BLOCK_STATUS_OFFSET 1
-#define CMD_BLOCK_PARAMETERS_OFFSET 4
-
-#define SCAN_OPTIONS_SITE_SURVEY 0x80
-
-#define MGMT_FRAME_BODY_OFFSET 24
-#define MAX_AUTHENTICATION_RETRIES 3
-#define MAX_ASSOCIATION_RETRIES 3
-
-#define AUTHENTICATION_RESPONSE_TIME_OUT 1000
-
-#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */
-#define LOOP_RETRY_LIMIT 500000
-
-#define ACTIVE_MODE 1
-#define PS_MODE 2
-
-#define MAX_ENCRYPTION_KEYS 4
-#define MAX_ENCRYPTION_KEY_SIZE 40
-
-/*
- * 802.11 related definitions
- */
-
-/*
- * Regulatory Domains
- */
-
-#define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */
-#define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */
-#define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */
-#define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */
-#define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */
-#define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */
-#define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */
-#define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */
-
-#define BSS_TYPE_AD_HOC 1
-#define BSS_TYPE_INFRASTRUCTURE 2
-
-#define SCAN_TYPE_ACTIVE 0
-#define SCAN_TYPE_PASSIVE 1
-
-#define LONG_PREAMBLE 0
-#define SHORT_PREAMBLE 1
-#define AUTO_PREAMBLE 2
-
-#define DATA_FRAME_WS_HEADER_SIZE 30
-
-/* promiscuous mode control */
-#define PROM_MODE_OFF 0x0
-#define PROM_MODE_UNKNOWN 0x1
-#define PROM_MODE_CRC_FAILED 0x2
-#define PROM_MODE_DUPLICATED 0x4
-#define PROM_MODE_MGMT 0x8
-#define PROM_MODE_CTRL 0x10
-#define PROM_MODE_BAD_PROTOCOL 0x20
-
-#define IFACE_INT_STATUS_OFFSET 0
-#define IFACE_INT_MASK_OFFSET 1
-#define IFACE_LOCKOUT_HOST_OFFSET 2
-#define IFACE_LOCKOUT_MAC_OFFSET 3
-#define IFACE_FUNC_CTRL_OFFSET 28
-#define IFACE_MAC_STAT_OFFSET 30
-#define IFACE_GENERIC_INT_TYPE_OFFSET 32
-
-#define CIPHER_SUITE_NONE 0
-#define CIPHER_SUITE_WEP_64 1
-#define CIPHER_SUITE_TKIP 2
-#define CIPHER_SUITE_AES 3
-#define CIPHER_SUITE_CCX 4
-#define CIPHER_SUITE_WEP_128 5
-
-/*
- * IFACE MACROS & definitions
- */
-
-/*
- * FuncCtrl field:
- */
-#define FUNC_CTRL_TxENABLE 0x10
-#define FUNC_CTRL_RxENABLE 0x20
-#define FUNC_CTRL_INIT_COMPLETE 0x01
-
-/* A stub firmware image which reads the MAC address from NVRAM on the card.
- For copyright information and source see the end of this file. */
-static u8 mac_reader[] = {
- 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
- 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
- 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
- 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5,
- 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5,
- 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1,
- 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb,
- 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb,
- 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5,
- 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea,
- 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
- 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1,
- 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
- 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1,
- 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2,
- 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3,
- 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
- 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5,
- 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5,
- 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5,
- 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3,
- 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5,
- 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5,
- 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5,
- 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5,
- 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1,
- 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2,
- 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb,
- 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb,
- 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb,
- 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3,
- 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5,
- 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3,
- 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a,
- 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5,
- 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
- 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3,
- 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3,
- 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2,
- 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb,
- 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02,
- 0x00, 0x01, 0x00, 0x02
-};
-
-struct atmel_private {
- void *card; /* Bus dependent structure varies for PCcard */
- int (*present_callback)(void *); /* And callback which uses it */
- char firmware_id[32];
- AtmelFWType firmware_type;
- u8 *firmware;
- int firmware_length;
- struct timer_list management_timer;
- struct net_device *dev;
- struct device *sys_dev;
- struct iw_statistics wstats;
- spinlock_t irqlock, timerlock; /* spinlocks */
- enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type;
- enum {
- CARD_TYPE_PARALLEL_FLASH,
- CARD_TYPE_SPI_FLASH,
- CARD_TYPE_EEPROM
- } card_type;
- int do_rx_crc; /* If we need to CRC incoming packets */
- int probe_crc; /* set if we don't yet know */
- int crc_ok_cnt, crc_ko_cnt; /* counters for probing */
- u16 rx_desc_head;
- u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous;
- u16 tx_free_mem, tx_buff_head, tx_buff_tail;
-
- u16 frag_seq, frag_len, frag_no;
- u8 frag_source[6];
-
- u8 wep_is_on, default_key, exclude_unencrypted, encryption_level;
- u8 group_cipher_suite, pairwise_cipher_suite;
- u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
- int wep_key_len[MAX_ENCRYPTION_KEYS];
- int use_wpa, radio_on_broken; /* firmware dependent stuff. */
-
- u16 host_info_base;
- struct host_info_struct {
- /* NB this is matched to the hardware, don't change. */
- u8 volatile int_status;
- u8 volatile int_mask;
- u8 volatile lockout_host;
- u8 volatile lockout_mac;
-
- u16 tx_buff_pos;
- u16 tx_buff_size;
- u16 tx_desc_pos;
- u16 tx_desc_count;
-
- u16 rx_buff_pos;
- u16 rx_buff_size;
- u16 rx_desc_pos;
- u16 rx_desc_count;
-
- u16 build_version;
- u16 command_pos;
-
- u16 major_version;
- u16 minor_version;
-
- u16 func_ctrl;
- u16 mac_status;
- u16 generic_IRQ_type;
- u8 reserved[2];
- } host_info;
-
- enum {
- STATION_STATE_SCANNING,
- STATION_STATE_JOINNING,
- STATION_STATE_AUTHENTICATING,
- STATION_STATE_ASSOCIATING,
- STATION_STATE_READY,
- STATION_STATE_REASSOCIATING,
- STATION_STATE_DOWN,
- STATION_STATE_MGMT_ERROR
- } station_state;
-
- int operating_mode, power_mode;
- unsigned long last_qual;
- int beacons_this_sec;
- int channel;
- int reg_domain, config_reg_domain;
- int tx_rate;
- int auto_tx_rate;
- int rts_threshold;
- int frag_threshold;
- int long_retry, short_retry;
- int preamble;
- int default_beacon_period, beacon_period, listen_interval;
- int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum;
- int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt;
- enum {
- SITE_SURVEY_IDLE,
- SITE_SURVEY_IN_PROGRESS,
- SITE_SURVEY_COMPLETED
- } site_survey_state;
- unsigned long last_survey;
-
- int station_was_associated, station_is_associated;
- int fast_scan;
-
- struct bss_info {
- int channel;
- int SSIDsize;
- int RSSI;
- int UsingWEP;
- int preamble;
- int beacon_period;
- int BSStype;
- u8 BSSID[6];
- u8 SSID[MAX_SSID_LENGTH];
- } BSSinfo[MAX_BSS_ENTRIES];
- int BSS_list_entries, current_BSS;
- int connect_to_any_BSS;
- int SSID_size, new_SSID_size;
- u8 CurrentBSSID[6], BSSID[6];
- u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH];
- u64 last_beacon_timestamp;
- u8 rx_buf[MAX_WIRELESS_BODY];
-};
-
-static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16};
-
-static const struct {
- int reg_domain;
- int min, max;
- char *name;
-} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" },
- { REG_DOMAIN_DOC, 1, 11, "Canada" },
- { REG_DOMAIN_ETSI, 1, 13, "Europe" },
- { REG_DOMAIN_SPAIN, 10, 11, "Spain" },
- { REG_DOMAIN_FRANCE, 10, 13, "France" },
- { REG_DOMAIN_MKK, 14, 14, "MKK" },
- { REG_DOMAIN_MKK1, 1, 14, "MKK1" },
- { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} };
-
-static void build_wpa_mib(struct atmel_private *priv);
-static void atmel_copy_to_card(struct net_device *dev, u16 dest,
- const unsigned char *src, u16 len);
-static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest,
- u16 src, u16 len);
-static void atmel_set_gcr(struct net_device *dev, u16 mask);
-static void atmel_clear_gcr(struct net_device *dev, u16 mask);
-static int atmel_lock_mac(struct atmel_private *priv);
-static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data);
-static void atmel_command_irq(struct atmel_private *priv);
-static int atmel_validate_channel(struct atmel_private *priv, int channel);
-static void atmel_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr *header,
- u16 frame_len, u8 rssi);
-static void atmel_management_timer(struct timer_list *t);
-static void atmel_send_command(struct atmel_private *priv, int command,
- void *cmd, int cmd_size);
-static int atmel_send_command_wait(struct atmel_private *priv, int command,
- void *cmd, int cmd_size);
-static void atmel_transmit_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr *header,
- u8 *body, int body_len);
-
-static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index);
-static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index,
- u8 data);
-static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
- u16 data);
-static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
- const u8 *data, int data_len);
-static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
- u8 *data, int data_len);
-static void atmel_scan(struct atmel_private *priv, int specific_ssid);
-static void atmel_join_bss(struct atmel_private *priv, int bss_index);
-static void atmel_smooth_qual(struct atmel_private *priv);
-static void atmel_writeAR(struct net_device *dev, u16 data);
-static int probe_atmel_card(struct net_device *dev);
-static int reset_atmel_card(struct net_device *dev);
-static void atmel_enter_state(struct atmel_private *priv, int new_state);
-int atmel_open (struct net_device *dev);
-
-static inline u16 atmel_hi(struct atmel_private *priv, u16 offset)
-{
- return priv->host_info_base + offset;
-}
-
-static inline u16 atmel_co(struct atmel_private *priv, u16 offset)
-{
- return priv->host_info.command_pos + offset;
-}
-
-static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc)
-{
- return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset;
-}
-
-static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc)
-{
- return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset;
-}
-
-static inline u8 atmel_read8(struct net_device *dev, u16 offset)
-{
- return inb(dev->base_addr + offset);
-}
-
-static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data)
-{
- outb(data, dev->base_addr + offset);
-}
-
-static inline u16 atmel_read16(struct net_device *dev, u16 offset)
-{
- return inw(dev->base_addr + offset);
-}
-
-static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data)
-{
- outw(data, dev->base_addr + offset);
-}
-
-static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos)
-{
- atmel_writeAR(priv->dev, pos);
- return atmel_read8(priv->dev, DR);
-}
-
-static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data)
-{
- atmel_writeAR(priv->dev, pos);
- atmel_write8(priv->dev, DR, data);
-}
-
-static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos)
-{
- atmel_writeAR(priv->dev, pos);
- return atmel_read16(priv->dev, DR);
-}
-
-static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data)
-{
- atmel_writeAR(priv->dev, pos);
- atmel_write16(priv->dev, DR, data);
-}
-
-static const struct iw_handler_def atmel_handler_def;
-
-static void tx_done_irq(struct atmel_private *priv)
-{
- int i;
-
- for (i = 0;
- atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE &&
- i < priv->host_info.tx_desc_count;
- i++) {
- u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head));
- u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head));
- u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head));
-
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0);
-
- priv->tx_free_mem += msdu_size;
- priv->tx_desc_free++;
-
- if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size))
- priv->tx_buff_head = 0;
- else
- priv->tx_buff_head += msdu_size;
-
- if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1))
- priv->tx_desc_head++ ;
- else
- priv->tx_desc_head = 0;
-
- if (type == TX_PACKET_TYPE_DATA) {
- if (status == TX_STATUS_SUCCESS)
- priv->dev->stats.tx_packets++;
- else
- priv->dev->stats.tx_errors++;
- netif_wake_queue(priv->dev);
- }
- }
-}
-
-static u16 find_tx_buff(struct atmel_private *priv, u16 len)
-{
- u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail;
-
- if (priv->tx_desc_free == 3 || priv->tx_free_mem < len)
- return 0;
-
- if (bottom_free >= len)
- return priv->host_info.tx_buff_pos + priv->tx_buff_tail;
-
- if (priv->tx_free_mem - bottom_free >= len) {
- priv->tx_buff_tail = 0;
- return priv->host_info.tx_buff_pos;
- }
-
- return 0;
-}
-
-static void tx_update_descriptor(struct atmel_private *priv, int is_bcast,
- u16 len, u16 buff, u8 type)
-{
- atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff);
- atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len);
- if (!priv->use_wpa)
- atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len);
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type);
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate);
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0);
- if (priv->use_wpa) {
- int cipher_type, cipher_length;
- if (is_bcast) {
- cipher_type = priv->group_cipher_suite;
- if (cipher_type == CIPHER_SUITE_WEP_64 ||
- cipher_type == CIPHER_SUITE_WEP_128)
- cipher_length = 8;
- else if (cipher_type == CIPHER_SUITE_TKIP)
- cipher_length = 12;
- else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 ||
- priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) {
- cipher_type = priv->pairwise_cipher_suite;
- cipher_length = 8;
- } else {
- cipher_type = CIPHER_SUITE_NONE;
- cipher_length = 0;
- }
- } else {
- cipher_type = priv->pairwise_cipher_suite;
- if (cipher_type == CIPHER_SUITE_WEP_64 ||
- cipher_type == CIPHER_SUITE_WEP_128)
- cipher_length = 8;
- else if (cipher_type == CIPHER_SUITE_TKIP)
- cipher_length = 12;
- else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 ||
- priv->group_cipher_suite == CIPHER_SUITE_WEP_128) {
- cipher_type = priv->group_cipher_suite;
- cipher_length = 8;
- } else {
- cipher_type = CIPHER_SUITE_NONE;
- cipher_length = 0;
- }
- }
-
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail),
- cipher_type);
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail),
- cipher_length);
- }
- atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L);
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN);
- if (priv->tx_desc_previous != priv->tx_desc_tail)
- atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0);
- priv->tx_desc_previous = priv->tx_desc_tail;
- if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1))
- priv->tx_desc_tail++;
- else
- priv->tx_desc_tail = 0;
- priv->tx_desc_free--;
- priv->tx_free_mem -= len;
-}
-
-static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
-{
- struct atmel_private *priv = netdev_priv(dev);
- struct ieee80211_hdr header;
- unsigned long flags;
- u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-
- if (priv->card && priv->present_callback &&
- !(*priv->present_callback)(priv->card)) {
- dev->stats.tx_errors++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- if (priv->station_state != STATION_STATE_READY) {
- dev->stats.tx_errors++;
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- /* first ensure the timer func cannot run */
- spin_lock_bh(&priv->timerlock);
- /* then stop the hardware ISR */
- spin_lock_irqsave(&priv->irqlock, flags);
- /* nb doing the above in the opposite order will deadlock */
-
- /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the
- 12 first bytes (containing DA/SA) and put them in the appropriate
- fields of the Wireless Header. Thus the packet length is then the
- initial + 18 (+30-12) */
-
- if (!(buff = find_tx_buff(priv, len + 18))) {
- dev->stats.tx_dropped++;
- spin_unlock_irqrestore(&priv->irqlock, flags);
- spin_unlock_bh(&priv->timerlock);
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- }
-
- frame_ctl = IEEE80211_FTYPE_DATA;
- header.duration_id = 0;
- header.seq_ctrl = 0;
- if (priv->wep_is_on)
- frame_ctl |= IEEE80211_FCTL_PROTECTED;
- if (priv->operating_mode == IW_MODE_ADHOC) {
- skb_copy_from_linear_data(skb, &header.addr1, ETH_ALEN);
- memcpy(&header.addr2, dev->dev_addr, ETH_ALEN);
- memcpy(&header.addr3, priv->BSSID, ETH_ALEN);
- } else {
- frame_ctl |= IEEE80211_FCTL_TODS;
- memcpy(&header.addr1, priv->CurrentBSSID, ETH_ALEN);
- memcpy(&header.addr2, dev->dev_addr, ETH_ALEN);
- skb_copy_from_linear_data(skb, &header.addr3, ETH_ALEN);
- }
-
- if (priv->use_wpa)
- memcpy(&header.addr4, rfc1042_header, ETH_ALEN);
-
- header.frame_control = cpu_to_le16(frame_ctl);
- /* Copy the wireless header into the card */
- atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE);
- /* Copy the packet sans its 802.3 header addresses which have been replaced */
- atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12);
- priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE;
-
- /* low bit of first byte of destination tells us if broadcast */
- tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
- dev->stats.tx_bytes += len;
-
- spin_unlock_irqrestore(&priv->irqlock, flags);
- spin_unlock_bh(&priv->timerlock);
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-static void atmel_transmit_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr *header,
- u8 *body, int body_len)
-{
- u16 buff;
- int len = MGMT_FRAME_BODY_OFFSET + body_len;
-
- if (!(buff = find_tx_buff(priv, len)))
- return;
-
- atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET);
- atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len);
- priv->tx_buff_tail += len;
- tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);
-}
-
-static void fast_rx_path(struct atmel_private *priv,
- struct ieee80211_hdr *header,
- u16 msdu_size, u16 rx_packet_loc, u32 crc)
-{
- /* fast path: unfragmented packet copy directly into skbuf */
- u8 mac4[6];
- struct sk_buff *skb;
- unsigned char *skbp;
-
- /* get the final, mac 4 header field, this tells us encapsulation */
- atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6);
- msdu_size -= 6;
-
- if (priv->do_rx_crc) {
- crc = crc32_le(crc, mac4, 6);
- msdu_size -= 4;
- }
-
- if (!(skb = dev_alloc_skb(msdu_size + 14))) {
- priv->dev->stats.rx_dropped++;
- return;
- }
-
- skb_reserve(skb, 2);
- skbp = skb_put(skb, msdu_size + 12);
- atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size);
-
- if (priv->do_rx_crc) {
- u32 netcrc;
- crc = crc32_le(crc, skbp + 12, msdu_size);
- atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4);
- if ((crc ^ 0xffffffff) != netcrc) {
- priv->dev->stats.rx_crc_errors++;
- dev_kfree_skb(skb);
- return;
- }
- }
-
- memcpy(skbp, header->addr1, ETH_ALEN); /* destination address */
- if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
- memcpy(&skbp[ETH_ALEN], header->addr3, ETH_ALEN);
- else
- memcpy(&skbp[ETH_ALEN], header->addr2, ETH_ALEN); /* source address */
-
- skb->protocol = eth_type_trans(skb, priv->dev);
- skb->ip_summed = CHECKSUM_NONE;
- netif_rx(skb);
- priv->dev->stats.rx_bytes += 12 + msdu_size;
- priv->dev->stats.rx_packets++;
-}
-
-/* Test to see if the packet in card memory at packet_loc has a valid CRC
- It doesn't matter that this is slow: it is only used to proble the first few
- packets. */
-static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size)
-{
- int i = msdu_size - 4;
- u32 netcrc, crc = 0xffffffff;
-
- if (msdu_size < 4)
- return 0;
-
- atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4);
-
- atmel_writeAR(priv->dev, packet_loc);
- while (i--) {
- u8 octet = atmel_read8(priv->dev, DR);
- crc = crc32_le(crc, &octet, 1);
- }
-
- return (crc ^ 0xffffffff) == netcrc;
-}
-
-static void frag_rx_path(struct atmel_private *priv,
- struct ieee80211_hdr *header,
- u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no,
- u8 frag_no, int more_frags)
-{
- u8 mac4[ETH_ALEN];
- u8 source[ETH_ALEN];
- struct sk_buff *skb;
-
- if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
- memcpy(source, header->addr3, ETH_ALEN);
- else
- memcpy(source, header->addr2, ETH_ALEN);
-
- rx_packet_loc += 24; /* skip header */
-
- if (priv->do_rx_crc)
- msdu_size -= 4;
-
- if (frag_no == 0) { /* first fragment */
- atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, ETH_ALEN);
- msdu_size -= ETH_ALEN;
- rx_packet_loc += ETH_ALEN;
-
- if (priv->do_rx_crc)
- crc = crc32_le(crc, mac4, 6);
-
- priv->frag_seq = seq_no;
- priv->frag_no = 1;
- priv->frag_len = msdu_size;
- memcpy(priv->frag_source, source, ETH_ALEN);
- memcpy(&priv->rx_buf[ETH_ALEN], source, ETH_ALEN);
- memcpy(priv->rx_buf, header->addr1, ETH_ALEN);
-
- atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size);
-
- if (priv->do_rx_crc) {
- u32 netcrc;
- crc = crc32_le(crc, &priv->rx_buf[12], msdu_size);
- atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
- if ((crc ^ 0xffffffff) != netcrc) {
- priv->dev->stats.rx_crc_errors++;
- eth_broadcast_addr(priv->frag_source);
- }
- }
-
- } else if (priv->frag_no == frag_no &&
- priv->frag_seq == seq_no &&
- memcmp(priv->frag_source, source, ETH_ALEN) == 0) {
-
- atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len],
- rx_packet_loc, msdu_size);
- if (priv->do_rx_crc) {
- u32 netcrc;
- crc = crc32_le(crc,
- &priv->rx_buf[12 + priv->frag_len],
- msdu_size);
- atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4);
- if ((crc ^ 0xffffffff) != netcrc) {
- priv->dev->stats.rx_crc_errors++;
- eth_broadcast_addr(priv->frag_source);
- more_frags = 1; /* don't send broken assembly */
- }
- }
-
- priv->frag_len += msdu_size;
- priv->frag_no++;
-
- if (!more_frags) { /* last one */
- eth_broadcast_addr(priv->frag_source);
- if (!(skb = dev_alloc_skb(priv->frag_len + 14))) {
- priv->dev->stats.rx_dropped++;
- } else {
- skb_reserve(skb, 2);
- skb_put_data(skb, priv->rx_buf,
- priv->frag_len + 12);
- skb->protocol = eth_type_trans(skb, priv->dev);
- skb->ip_summed = CHECKSUM_NONE;
- netif_rx(skb);
- priv->dev->stats.rx_bytes += priv->frag_len + 12;
- priv->dev->stats.rx_packets++;
- }
- }
- } else
- priv->wstats.discard.fragment++;
-}
-
-static void rx_done_irq(struct atmel_private *priv)
-{
- int i;
- struct ieee80211_hdr header;
-
- for (i = 0;
- atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID &&
- i < priv->host_info.rx_desc_count;
- i++) {
-
- u16 msdu_size, rx_packet_loc, frame_ctl, seq_control;
- u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head));
- u32 crc = 0xffffffff;
-
- if (status != RX_STATUS_SUCCESS) {
- if (status == 0xc1) /* determined by experiment */
- priv->wstats.discard.nwid++;
- else
- priv->dev->stats.rx_errors++;
- goto next;
- }
-
- msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head));
- rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head));
-
- if (msdu_size < 30) {
- priv->dev->stats.rx_errors++;
- goto next;
- }
-
- /* Get header as far as end of seq_ctrl */
- atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24);
- frame_ctl = le16_to_cpu(header.frame_control);
- seq_control = le16_to_cpu(header.seq_ctrl);
-
- /* probe for CRC use here if needed once five packets have
- arrived with the same crc status, we assume we know what's
- happening and stop probing */
- if (priv->probe_crc) {
- if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) {
- priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size);
- } else {
- priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24);
- }
- if (priv->do_rx_crc) {
- if (priv->crc_ok_cnt++ > 5)
- priv->probe_crc = 0;
- } else {
- if (priv->crc_ko_cnt++ > 5)
- priv->probe_crc = 0;
- }
- }
-
- /* don't CRC header when WEP in use */
- if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) {
- crc = crc32_le(0xffffffff, (unsigned char *)&header, 24);
- }
- msdu_size -= 24; /* header */
-
- if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
- int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS;
- u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG;
- u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4;
-
- if (!more_fragments && packet_fragment_no == 0) {
- fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc);
- } else {
- frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc,
- packet_sequence_no, packet_fragment_no, more_fragments);
- }
- }
-
- if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
- /* copy rest of packet into buffer */
- atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size);
-
- /* we use the same buffer for frag reassembly and control packets */
- eth_broadcast_addr(priv->frag_source);
-
- if (priv->do_rx_crc) {
- /* last 4 octets is crc */
- msdu_size -= 4;
- crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size);
- if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) {
- priv->dev->stats.rx_crc_errors++;
- goto next;
- }
- }
-
- atmel_management_frame(priv, &header, msdu_size,
- atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head)));
- }
-
-next:
- /* release descriptor */
- atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED);
-
- if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1))
- priv->rx_desc_head++;
- else
- priv->rx_desc_head = 0;
- }
-}
-
-static irqreturn_t service_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *) dev_id;
- struct atmel_private *priv = netdev_priv(dev);
- u8 isr;
- int i = -1;
- static const u8 irq_order[] = {
- ISR_OUT_OF_RANGE,
- ISR_RxCOMPLETE,
- ISR_TxCOMPLETE,
- ISR_RxFRAMELOST,
- ISR_FATAL_ERROR,
- ISR_COMMAND_COMPLETE,
- ISR_IBSS_MERGE,
- ISR_GENERIC_IRQ
- };
-
- if (priv->card && priv->present_callback &&
- !(*priv->present_callback)(priv->card))
- return IRQ_HANDLED;
-
- /* In this state upper-level code assumes it can mess with
- the card unhampered by interrupts which may change register state.
- Note that even though the card shouldn't generate interrupts
- the inturrupt line may be shared. This allows card setup
- to go on without disabling interrupts for a long time. */
- if (priv->station_state == STATION_STATE_DOWN)
- return IRQ_NONE;
-
- atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */
-
- while (1) {
- if (!atmel_lock_mac(priv)) {
- /* failed to contact card */
- printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name);
- return IRQ_HANDLED;
- }
-
- isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET));
- atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
-
- if (!isr) {
- atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */
- return i == -1 ? IRQ_NONE : IRQ_HANDLED;
- }
-
- atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */
-
- for (i = 0; i < ARRAY_SIZE(irq_order); i++)
- if (isr & irq_order[i])
- break;
-
- if (!atmel_lock_mac(priv)) {
- /* failed to contact card */
- printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name);
- return IRQ_HANDLED;
- }
-
- isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET));
- isr ^= irq_order[i];
- atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr);
- atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
-
- switch (irq_order[i]) {
-
- case ISR_OUT_OF_RANGE:
- if (priv->operating_mode == IW_MODE_INFRA &&
- priv->station_state == STATION_STATE_READY) {
- priv->station_is_associated = 0;
- atmel_scan(priv, 1);
- }
- break;
-
- case ISR_RxFRAMELOST:
- priv->wstats.discard.misc++;
- fallthrough;
- case ISR_RxCOMPLETE:
- rx_done_irq(priv);
- break;
-
- case ISR_TxCOMPLETE:
- tx_done_irq(priv);
- break;
-
- case ISR_FATAL_ERROR:
- printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name);
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- break;
-
- case ISR_COMMAND_COMPLETE:
- atmel_command_irq(priv);
- break;
-
- case ISR_IBSS_MERGE:
- atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS,
- priv->CurrentBSSID, 6);
- /* The WPA stuff cares about the current AP address */
- if (priv->use_wpa)
- build_wpa_mib(priv);
- break;
- case ISR_GENERIC_IRQ:
- printk(KERN_INFO "%s: Generic_irq received.\n", dev->name);
- break;
- }
- }
-}
-
-static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
-{
- struct atmel_private *priv = netdev_priv(dev);
-
- /* update the link quality here in case we are seeing no beacons
- at all to drive the process */
- atmel_smooth_qual(priv);
-
- priv->wstats.status = priv->station_state;
-
- if (priv->operating_mode == IW_MODE_INFRA) {
- if (priv->station_state != STATION_STATE_READY) {
- priv->wstats.qual.qual = 0;
- priv->wstats.qual.level = 0;
- priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_INVALID);
- }
- priv->wstats.qual.noise = 0;
- priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
- } else {
- /* Quality levels cannot be determined in ad-hoc mode,
- because we can 'hear' more that one remote station. */
- priv->wstats.qual.qual = 0;
- priv->wstats.qual.level = 0;
- priv->wstats.qual.noise = 0;
- priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_INVALID
- | IW_QUAL_NOISE_INVALID;
- priv->wstats.miss.beacon = 0;
- }
-
- return &priv->wstats;
-}
-
-static int atmel_set_mac_address(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = p;
-
- eth_hw_addr_set(dev, addr->sa_data);
- return atmel_open(dev);
-}
-
-EXPORT_SYMBOL(atmel_open);
-
-int atmel_open(struct net_device *dev)
-{
- struct atmel_private *priv = netdev_priv(dev);
- int i, channel, err;
-
- /* any scheduled timer is no longer needed and might screw things up.. */
- del_timer_sync(&priv->management_timer);
-
- /* Interrupts will not touch the card once in this state... */
- priv->station_state = STATION_STATE_DOWN;
-
- if (priv->new_SSID_size) {
- memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size);
- priv->SSID_size = priv->new_SSID_size;
- priv->new_SSID_size = 0;
- }
- priv->BSS_list_entries = 0;
-
- priv->AuthenticationRequestRetryCnt = 0;
- priv->AssociationRequestRetryCnt = 0;
- priv->ReAssociationRequestRetryCnt = 0;
- priv->CurrentAuthentTransactionSeqNum = 0x0001;
- priv->ExpectedAuthentTransactionSeqNum = 0x0002;
-
- priv->site_survey_state = SITE_SURVEY_IDLE;
- priv->station_is_associated = 0;
-
- err = reset_atmel_card(dev);
- if (err)
- return err;
-
- if (priv->config_reg_domain) {
- priv->reg_domain = priv->config_reg_domain;
- atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain);
- } else {
- priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS);
- for (i = 0; i < ARRAY_SIZE(channel_table); i++)
- if (priv->reg_domain == channel_table[i].reg_domain)
- break;
- if (i == ARRAY_SIZE(channel_table)) {
- priv->reg_domain = REG_DOMAIN_MKK1;
- printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name);
- }
- }
-
- if ((channel = atmel_validate_channel(priv, priv->channel)))
- priv->channel = channel;
-
- /* this moves station_state on.... */
- atmel_scan(priv, 1);
-
- atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */
- return 0;
-}
-
-static int atmel_close(struct net_device *dev)
-{
- struct atmel_private *priv = netdev_priv(dev);
-
- /* Send event to userspace that we are disassociating */
- if (priv->station_state == STATION_STATE_READY) {
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
- }
-
- atmel_enter_state(priv, STATION_STATE_DOWN);
-
- if (priv->bus_type == BUS_TYPE_PCCARD)
- atmel_write16(dev, GCR, 0x0060);
- atmel_write16(dev, GCR, 0x0040);
- return 0;
-}
-
-static int atmel_validate_channel(struct atmel_private *priv, int channel)
-{
- /* check that channel is OK, if so return zero,
- else return suitable default channel */
- int i;
-
- for (i = 0; i < ARRAY_SIZE(channel_table); i++)
- if (priv->reg_domain == channel_table[i].reg_domain) {
- if (channel >= channel_table[i].min &&
- channel <= channel_table[i].max)
- return 0;
- else
- return channel_table[i].min;
- }
- return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-static int atmel_proc_show(struct seq_file *m, void *v)
-{
- struct atmel_private *priv = m->private;
- int i;
- char *s, *r, *c;
-
- seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR);
-
- if (priv->station_state != STATION_STATE_DOWN) {
- seq_printf(m,
- "Firmware version:\t%d.%d build %d\n"
- "Firmware location:\t",
- priv->host_info.major_version,
- priv->host_info.minor_version,
- priv->host_info.build_version);
-
- if (priv->card_type != CARD_TYPE_EEPROM)
- seq_puts(m, "on card\n");
- else if (priv->firmware)
- seq_printf(m, "%s loaded by host\n", priv->firmware_id);
- else
- seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id);
-
- switch (priv->card_type) {
- case CARD_TYPE_PARALLEL_FLASH:
- c = "Parallel flash";
- break;
- case CARD_TYPE_SPI_FLASH:
- c = "SPI flash\n";
- break;
- case CARD_TYPE_EEPROM:
- c = "EEPROM";
- break;
- default:
- c = "<unknown>";
- }
-
- r = "<unknown>";
- for (i = 0; i < ARRAY_SIZE(channel_table); i++)
- if (priv->reg_domain == channel_table[i].reg_domain)
- r = channel_table[i].name;
-
- seq_printf(m, "MAC memory type:\t%s\n", c);
- seq_printf(m, "Regulatory domain:\t%s\n", r);
- seq_printf(m, "Host CRC checking:\t%s\n",
- priv->do_rx_crc ? "On" : "Off");
- seq_printf(m, "WPA-capable firmware:\t%s\n",
- priv->use_wpa ? "Yes" : "No");
- }
-
- switch (priv->station_state) {
- case STATION_STATE_SCANNING:
- s = "Scanning";
- break;
- case STATION_STATE_JOINNING:
- s = "Joining";
- break;
- case STATION_STATE_AUTHENTICATING:
- s = "Authenticating";
- break;
- case STATION_STATE_ASSOCIATING:
- s = "Associating";
- break;
- case STATION_STATE_READY:
- s = "Ready";
- break;
- case STATION_STATE_REASSOCIATING:
- s = "Reassociating";
- break;
- case STATION_STATE_MGMT_ERROR:
- s = "Management error";
- break;
- case STATION_STATE_DOWN:
- s = "Down";
- break;
- default:
- s = "<unknown>";
- }
-
- seq_printf(m, "Current state:\t\t%s\n", s);
- return 0;
-}
-#endif
-
-static const struct net_device_ops atmel_netdev_ops = {
- .ndo_open = atmel_open,
- .ndo_stop = atmel_close,
- .ndo_set_mac_address = atmel_set_mac_address,
- .ndo_start_xmit = start_tx,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
- const AtmelFWType fw_type,
- struct device *sys_dev,
- int (*card_present)(void *), void *card)
-{
- struct net_device *dev;
- struct atmel_private *priv;
- int rc;
-
- /* Create the network device object. */
- dev = alloc_etherdev(sizeof(*priv));
- if (!dev)
- return NULL;
-
- if (dev_alloc_name(dev, dev->name) < 0) {
- printk(KERN_ERR "atmel: Couldn't get name!\n");
- goto err_out_free;
- }
-
- priv = netdev_priv(dev);
- priv->dev = dev;
- priv->sys_dev = sys_dev;
- priv->present_callback = card_present;
- priv->card = card;
- priv->firmware = NULL;
- priv->firmware_type = fw_type;
- if (firmware) /* module parameter */
- strscpy(priv->firmware_id, firmware, sizeof(priv->firmware_id));
- priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI;
- priv->station_state = STATION_STATE_DOWN;
- priv->do_rx_crc = 0;
- /* For PCMCIA cards, some chips need CRC, some don't
- so we have to probe. */
- if (priv->bus_type == BUS_TYPE_PCCARD) {
- priv->probe_crc = 1;
- priv->crc_ok_cnt = priv->crc_ko_cnt = 0;
- } else
- priv->probe_crc = 0;
- priv->last_qual = jiffies;
- priv->last_beacon_timestamp = 0;
- memset(priv->frag_source, 0xff, sizeof(priv->frag_source));
- eth_zero_addr(priv->BSSID);
- priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */
- priv->station_was_associated = 0;
-
- priv->last_survey = jiffies;
- priv->preamble = LONG_PREAMBLE;
- priv->operating_mode = IW_MODE_INFRA;
- priv->connect_to_any_BSS = 0;
- priv->config_reg_domain = 0;
- priv->reg_domain = 0;
- priv->tx_rate = 3;
- priv->auto_tx_rate = 1;
- priv->channel = 4;
- priv->power_mode = 0;
- priv->SSID[0] = '\0';
- priv->SSID_size = 0;
- priv->new_SSID_size = 0;
- priv->frag_threshold = 2346;
- priv->rts_threshold = 2347;
- priv->short_retry = 7;
- priv->long_retry = 4;
-
- priv->wep_is_on = 0;
- priv->default_key = 0;
- priv->encryption_level = 0;
- priv->exclude_unencrypted = 0;
- priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
- priv->use_wpa = 0;
- memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
- memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len));
-
- priv->default_beacon_period = priv->beacon_period = 100;
- priv->listen_interval = 1;
-
- timer_setup(&priv->management_timer, atmel_management_timer, 0);
- spin_lock_init(&priv->irqlock);
- spin_lock_init(&priv->timerlock);
-
- dev->netdev_ops = &atmel_netdev_ops;
- dev->wireless_handlers = &atmel_handler_def;
- dev->irq = irq;
- dev->base_addr = port;
-
- /* MTU range: 68 - 2312 */
- dev->min_mtu = 68;
- dev->max_mtu = MAX_WIRELESS_BODY - ETH_FCS_LEN;
-
- SET_NETDEV_DEV(dev, sys_dev);
-
- if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) {
- printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc);
- goto err_out_free;
- }
-
- if (!request_region(dev->base_addr, 32,
- priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) {
- goto err_out_irq;
- }
-
- if (register_netdev(dev))
- goto err_out_res;
-
- if (!probe_atmel_card(dev)) {
- unregister_netdev(dev);
- goto err_out_res;
- }
-
- netif_carrier_off(dev);
-
- if (!proc_create_single_data("driver/atmel", 0, NULL, atmel_proc_show,
- priv))
- printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
-
- printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n",
- dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr);
-
- return dev;
-
-err_out_res:
- release_region(dev->base_addr, 32);
-err_out_irq:
- free_irq(dev->irq, dev);
-err_out_free:
- free_netdev(dev);
- return NULL;
-}
-
-EXPORT_SYMBOL(init_atmel_card);
-
-void stop_atmel_card(struct net_device *dev)
-{
- struct atmel_private *priv = netdev_priv(dev);
-
- /* put a brick on it... */
- if (priv->bus_type == BUS_TYPE_PCCARD)
- atmel_write16(dev, GCR, 0x0060);
- atmel_write16(dev, GCR, 0x0040);
-
- del_timer_sync(&priv->management_timer);
- unregister_netdev(dev);
- remove_proc_entry("driver/atmel", NULL);
- free_irq(dev->irq, dev);
- kfree(priv->firmware);
- release_region(dev->base_addr, 32);
- free_netdev(dev);
-}
-
-EXPORT_SYMBOL(stop_atmel_card);
-
-static int atmel_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->essid;
- struct atmel_private *priv = netdev_priv(dev);
-
- /* Check if we asked for `any' */
- if (dwrq->flags == 0) {
- priv->connect_to_any_BSS = 1;
- } else {
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
- priv->connect_to_any_BSS = 0;
-
- /* Check the size of the string */
- if (dwrq->length > MAX_SSID_LENGTH)
- return -E2BIG;
- if (index != 0)
- return -EINVAL;
-
- memcpy(priv->new_SSID, extra, dwrq->length);
- priv->new_SSID_size = dwrq->length;
- }
-
- return -EINPROGRESS;
-}
-
-static int atmel_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->essid;
- struct atmel_private *priv = netdev_priv(dev);
-
- /* Get the current SSID */
- if (priv->new_SSID_size != 0) {
- memcpy(extra, priv->new_SSID, priv->new_SSID_size);
- dwrq->length = priv->new_SSID_size;
- } else {
- memcpy(extra, priv->SSID, priv->SSID_size);
- dwrq->length = priv->SSID_size;
- }
-
- dwrq->flags = !priv->connect_to_any_BSS; /* active */
-
- return 0;
-}
-
-static int atmel_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *awrq = &wrqu->ap_addr;
- struct atmel_private *priv = netdev_priv(dev);
- memcpy(awrq->sa_data, priv->CurrentBSSID, ETH_ALEN);
- awrq->sa_family = ARPHRD_ETHER;
-
- return 0;
-}
-
-static int atmel_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->encoding;
- struct atmel_private *priv = netdev_priv(dev);
-
- /* Basic checking: do we have a key to set ?
- * Note : with the new API, it's impossible to get a NULL pointer.
- * Therefore, we need to check a key size == 0 instead.
- * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
- * when no key is present (only change flags), but older versions
- * don't do it. - Jean II */
- if (dwrq->length > 0) {
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- int current_index = priv->default_key;
- /* Check the size of the key */
- if (dwrq->length > 13) {
- return -EINVAL;
- }
- /* Check the index (none -> use current) */
- if (index < 0 || index >= 4)
- index = current_index;
- else
- priv->default_key = index;
- /* Set the length */
- if (dwrq->length > 5)
- priv->wep_key_len[index] = 13;
- else
- if (dwrq->length > 0)
- priv->wep_key_len[index] = 5;
- else
- /* Disable the key */
- priv->wep_key_len[index] = 0;
- /* Check if the key is not marked as invalid */
- if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
- /* Cleanup */
- memset(priv->wep_keys[index], 0, 13);
- /* Copy the key in the driver */
- memcpy(priv->wep_keys[index], extra, dwrq->length);
- }
- /* WE specify that if a valid key is set, encryption
- * should be enabled (user may turn it off later)
- * This is also how "iwconfig ethX key on" works */
- if (index == current_index &&
- priv->wep_key_len[index] > 0) {
- priv->wep_is_on = 1;
- priv->exclude_unencrypted = 1;
- if (priv->wep_key_len[index] > 5) {
- priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
- priv->encryption_level = 2;
- } else {
- priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
- priv->encryption_level = 1;
- }
- }
- } else {
- /* Do we want to just set the transmit key index ? */
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- if (index >= 0 && index < 4) {
- priv->default_key = index;
- } else
- /* Don't complain if only change the mode */
- if (!(dwrq->flags & IW_ENCODE_MODE))
- return -EINVAL;
- }
- /* Read the flags */
- if (dwrq->flags & IW_ENCODE_DISABLED) {
- priv->wep_is_on = 0;
- priv->encryption_level = 0;
- priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
- } else {
- priv->wep_is_on = 1;
- if (priv->wep_key_len[priv->default_key] > 5) {
- priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
- priv->encryption_level = 2;
- } else {
- priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
- priv->encryption_level = 1;
- }
- }
- if (dwrq->flags & IW_ENCODE_RESTRICTED)
- priv->exclude_unencrypted = 1;
- if (dwrq->flags & IW_ENCODE_OPEN)
- priv->exclude_unencrypted = 0;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int atmel_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->encoding;
- struct atmel_private *priv = netdev_priv(dev);
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
- if (!priv->wep_is_on)
- dwrq->flags = IW_ENCODE_DISABLED;
- else {
- if (priv->exclude_unencrypted)
- dwrq->flags = IW_ENCODE_RESTRICTED;
- else
- dwrq->flags = IW_ENCODE_OPEN;
- }
- /* Which key do we want ? -1 -> tx index */
- if (index < 0 || index >= 4)
- index = priv->default_key;
- dwrq->flags |= index + 1;
- /* Copy the key to the user buffer */
- dwrq->length = priv->wep_key_len[index];
- if (dwrq->length > 16) {
- dwrq->length = 0;
- } else {
- memset(extra, 0, 16);
- memcpy(extra, priv->wep_keys[index], dwrq->length);
- }
-
- return 0;
-}
-
-static int atmel_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct atmel_private *priv = netdev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, key_len, alg = ext->alg, set_key = 1;
-
- /* Determine and validate the key index */
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > 4)
- return -EINVAL;
- idx--;
- } else
- idx = priv->default_key;
-
- if (encoding->flags & IW_ENCODE_DISABLED)
- alg = IW_ENCODE_ALG_NONE;
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- priv->default_key = idx;
- set_key = ext->key_len > 0 ? 1 : 0;
- }
-
- if (set_key) {
- /* Set the requested key first */
- switch (alg) {
- case IW_ENCODE_ALG_NONE:
- priv->wep_is_on = 0;
- priv->encryption_level = 0;
- priv->pairwise_cipher_suite = CIPHER_SUITE_NONE;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len > 5) {
- priv->wep_key_len[idx] = 13;
- priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128;
- priv->encryption_level = 2;
- } else if (ext->key_len > 0) {
- priv->wep_key_len[idx] = 5;
- priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64;
- priv->encryption_level = 1;
- } else {
- return -EINVAL;
- }
- priv->wep_is_on = 1;
- memset(priv->wep_keys[idx], 0, 13);
- key_len = min ((int)ext->key_len, priv->wep_key_len[idx]);
- memcpy(priv->wep_keys[idx], ext->key, key_len);
- break;
- default:
- return -EINVAL;
- }
- }
-
- return -EINPROGRESS;
-}
-
-static int atmel_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct atmel_private *priv = netdev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, max_key_len;
-
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > 4)
- return -EINVAL;
- idx--;
- } else
- idx = priv->default_key;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- if (!priv->wep_is_on) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- } else {
- if (priv->encryption_level > 0)
- ext->alg = IW_ENCODE_ALG_WEP;
- else
- return -EINVAL;
-
- ext->key_len = priv->wep_key_len[idx];
- memcpy(ext->key, priv->wep_keys[idx], ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- }
-
- return 0;
-}
-
-static int atmel_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct atmel_private *priv = netdev_priv(dev);
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_PRIVACY_INVOKED:
- /*
- * atmel does not use these parameters
- */
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- priv->exclude_unencrypted = param->value ? 1 : 0;
- break;
-
- case IW_AUTH_80211_AUTH_ALG: {
- if (param->value & IW_AUTH_ALG_SHARED_KEY) {
- priv->exclude_unencrypted = 1;
- } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
- priv->exclude_unencrypted = 0;
- } else
- return -EINVAL;
- break;
- }
-
- case IW_AUTH_WPA_ENABLED:
- /* Silently accept disable of WPA */
- if (param->value > 0)
- return -EOPNOTSUPP;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return -EINPROGRESS;
-}
-
-static int atmel_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct atmel_private *priv = netdev_priv(dev);
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = priv->exclude_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (priv->exclude_unencrypted == 1)
- param->value = IW_AUTH_ALG_SHARED_KEY;
- else
- param->value = IW_AUTH_ALG_OPEN_SYSTEM;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = 0;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-static int atmel_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- strcpy(wrqu->name, "IEEE 802.11-DS");
- return 0;
-}
-
-static int atmel_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->bitrate;
- struct atmel_private *priv = netdev_priv(dev);
-
- if (vwrq->fixed == 0) {
- priv->tx_rate = 3;
- priv->auto_tx_rate = 1;
- } else {
- priv->auto_tx_rate = 0;
-
- /* Which type of value ? */
- if ((vwrq->value < 4) && (vwrq->value >= 0)) {
- /* Setting by rate index */
- priv->tx_rate = vwrq->value;
- } else {
- /* Setting by frequency value */
- switch (vwrq->value) {
- case 1000000:
- priv->tx_rate = 0;
- break;
- case 2000000:
- priv->tx_rate = 1;
- break;
- case 5500000:
- priv->tx_rate = 2;
- break;
- case 11000000:
- priv->tx_rate = 3;
- break;
- default:
- return -EINVAL;
- }
- }
- }
-
- return -EINPROGRESS;
-}
-
-static int atmel_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- __u32 *uwrq = &wrqu->mode;
- struct atmel_private *priv = netdev_priv(dev);
-
- if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA)
- return -EINVAL;
-
- priv->operating_mode = *uwrq;
- return -EINPROGRESS;
-}
-
-static int atmel_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- __u32 *uwrq = &wrqu->mode;
- struct atmel_private *priv = netdev_priv(dev);
-
- *uwrq = priv->operating_mode;
- return 0;
-}
-
-static int atmel_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->bitrate;
- struct atmel_private *priv = netdev_priv(dev);
-
- if (priv->auto_tx_rate) {
- vwrq->fixed = 0;
- vwrq->value = 11000000;
- } else {
- vwrq->fixed = 1;
- switch (priv->tx_rate) {
- case 0:
- vwrq->value = 1000000;
- break;
- case 1:
- vwrq->value = 2000000;
- break;
- case 2:
- vwrq->value = 5500000;
- break;
- case 3:
- vwrq->value = 11000000;
- break;
- }
- }
- return 0;
-}
-
-static int atmel_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct atmel_private *priv = netdev_priv(dev);
- priv->power_mode = vwrq->disabled ? 0 : 1;
- return -EINPROGRESS;
-}
-
-static int atmel_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct atmel_private *priv = netdev_priv(dev);
- vwrq->disabled = priv->power_mode ? 0 : 1;
- vwrq->flags = IW_POWER_ON;
- return 0;
-}
-
-static int atmel_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->retry;
- struct atmel_private *priv = netdev_priv(dev);
-
- if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
- if (vwrq->flags & IW_RETRY_LONG)
- priv->long_retry = vwrq->value;
- else if (vwrq->flags & IW_RETRY_SHORT)
- priv->short_retry = vwrq->value;
- else {
- /* No modifier : set both */
- priv->long_retry = vwrq->value;
- priv->short_retry = vwrq->value;
- }
- return -EINPROGRESS;
- }
-
- return -EINVAL;
-}
-
-static int atmel_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->retry;
- struct atmel_private *priv = netdev_priv(dev);
-
- vwrq->disabled = 0; /* Can't be disabled */
-
- /* Note : by default, display the short retry number */
- if (vwrq->flags & IW_RETRY_LONG) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- vwrq->value = priv->long_retry;
- } else {
- vwrq->flags = IW_RETRY_LIMIT;
- vwrq->value = priv->short_retry;
- if (priv->long_retry != priv->short_retry)
- vwrq->flags |= IW_RETRY_SHORT;
- }
-
- return 0;
-}
-
-static int atmel_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->rts;
- struct atmel_private *priv = netdev_priv(dev);
- int rthr = vwrq->value;
-
- if (vwrq->disabled)
- rthr = 2347;
- if ((rthr < 0) || (rthr > 2347)) {
- return -EINVAL;
- }
- priv->rts_threshold = rthr;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int atmel_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->rts;
- struct atmel_private *priv = netdev_priv(dev);
-
- vwrq->value = priv->rts_threshold;
- vwrq->disabled = (vwrq->value >= 2347);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-static int atmel_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->frag;
- struct atmel_private *priv = netdev_priv(dev);
- int fthr = vwrq->value;
-
- if (vwrq->disabled)
- fthr = 2346;
- if ((fthr < 256) || (fthr > 2346)) {
- return -EINVAL;
- }
- fthr &= ~0x1; /* Get an even value - is it really needed ??? */
- priv->frag_threshold = fthr;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int atmel_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->frag;
- struct atmel_private *priv = netdev_priv(dev);
-
- vwrq->value = priv->frag_threshold;
- vwrq->disabled = (vwrq->value >= 2346);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-static int atmel_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *fwrq = &wrqu->freq;
- struct atmel_private *priv = netdev_priv(dev);
- int rc = -EINPROGRESS; /* Call commit handler */
-
- /* If setting by frequency, convert to a channel */
- if (fwrq->e == 1) {
- int f = fwrq->m / 100000;
-
- /* Hack to fall through... */
- fwrq->e = 0;
- fwrq->m = ieee80211_frequency_to_channel(f);
- }
- /* Setting by channel number */
- if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0)
- rc = -EOPNOTSUPP;
- else {
- int channel = fwrq->m;
- if (atmel_validate_channel(priv, channel) == 0) {
- priv->channel = channel;
- } else {
- rc = -EINVAL;
- }
- }
- return rc;
-}
-
-static int atmel_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *fwrq = &wrqu->freq;
- struct atmel_private *priv = netdev_priv(dev);
-
- fwrq->m = priv->channel;
- fwrq->e = 0;
- return 0;
-}
-
-static int atmel_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *dwrq,
- char *extra)
-{
- struct atmel_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
-
- if (priv->station_state == STATION_STATE_DOWN)
- return -EAGAIN;
-
- /* Timeout old surveys. */
- if (time_after(jiffies, priv->last_survey + 20 * HZ))
- priv->site_survey_state = SITE_SURVEY_IDLE;
- priv->last_survey = jiffies;
-
- /* Initiate a scan command */
- if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS)
- return -EBUSY;
-
- del_timer_sync(&priv->management_timer);
- spin_lock_irqsave(&priv->irqlock, flags);
-
- priv->site_survey_state = SITE_SURVEY_IN_PROGRESS;
- priv->fast_scan = 0;
- atmel_scan(priv, 0);
- spin_unlock_irqrestore(&priv->irqlock, flags);
-
- return 0;
-}
-
-static int atmel_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct atmel_private *priv = netdev_priv(dev);
- int i;
- char *current_ev = extra;
- struct iw_event iwe;
-
- if (priv->site_survey_state != SITE_SURVEY_COMPLETED)
- return -EAGAIN;
-
- for (i = 0; i < priv->BSS_list_entries; i++) {
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_ADDR_LEN);
-
- iwe.u.data.length = priv->BSSinfo[i].SSIDsize;
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, priv->BSSinfo[i].SSID);
-
- iwe.cmd = SIOCGIWMODE;
- iwe.u.mode = priv->BSSinfo[i].BSStype;
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_UINT_LEN);
-
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = priv->BSSinfo[i].channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_FREQ_LEN);
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.level = priv->BSSinfo[i].RSSI;
- iwe.u.qual.qual = iwe.u.qual.level;
- /* iwe.u.qual.noise = SOMETHING */
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_QUAL_LEN);
-
-
- iwe.cmd = SIOCGIWENCODE;
- if (priv->BSSinfo[i].UsingWEP)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, NULL);
- }
-
- /* Length of data */
- dwrq->length = (current_ev - extra);
- dwrq->flags = 0;
-
- return 0;
-}
-
-static int atmel_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct atmel_private *priv = netdev_priv(dev);
- struct iw_range *range = (struct iw_range *) extra;
- int k, i, j;
-
- dwrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
- range->min_nwid = 0x0000;
- range->max_nwid = 0x0000;
- range->num_channels = 0;
- for (j = 0; j < ARRAY_SIZE(channel_table); j++)
- if (priv->reg_domain == channel_table[j].reg_domain) {
- range->num_channels = channel_table[j].max - channel_table[j].min + 1;
- break;
- }
- if (range->num_channels != 0) {
- for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) {
- range->freq[k].i = i; /* List index */
-
- /* Values in MHz -> * 10^5 * 10 */
- range->freq[k].m = 100000 *
- ieee80211_channel_to_frequency(i, NL80211_BAND_2GHZ);
- range->freq[k++].e = 1;
- }
- range->num_frequency = k;
- }
-
- range->max_qual.qual = 100;
- range->max_qual.level = 100;
- range->max_qual.noise = 0;
- range->max_qual.updated = IW_QUAL_NOISE_INVALID;
-
- range->avg_qual.qual = 50;
- range->avg_qual.level = 50;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = IW_QUAL_NOISE_INVALID;
-
- range->sensitivity = 0;
-
- range->bitrate[0] = 1000000;
- range->bitrate[1] = 2000000;
- range->bitrate[2] = 5500000;
- range->bitrate[3] = 11000000;
- range->num_bitrates = 4;
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = 4;
-
- range->pmp_flags = IW_POWER_ON;
- range->pmt_flags = IW_POWER_ON;
- range->pm_capa = 0;
-
- range->we_version_source = WIRELESS_EXT;
- range->we_version_compiled = WIRELESS_EXT;
- range->retry_capa = IW_RETRY_LIMIT ;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = 0;
- range->min_retry = 1;
- range->max_retry = 65535;
-
- return 0;
-}
-
-static int atmel_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *awrq = &wrqu->ap_addr;
- struct atmel_private *priv = netdev_priv(dev);
- int i;
- static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
- unsigned long flags;
-
- if (awrq->sa_family != ARPHRD_ETHER)
- return -EINVAL;
-
- if (!memcmp(any, awrq->sa_data, 6) ||
- !memcmp(off, awrq->sa_data, 6)) {
- del_timer_sync(&priv->management_timer);
- spin_lock_irqsave(&priv->irqlock, flags);
- atmel_scan(priv, 1);
- spin_unlock_irqrestore(&priv->irqlock, flags);
- return 0;
- }
-
- for (i = 0; i < priv->BSS_list_entries; i++) {
- if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) {
- if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) {
- return -EINVAL;
- } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) {
- return -EINVAL;
- } else {
- del_timer_sync(&priv->management_timer);
- spin_lock_irqsave(&priv->irqlock, flags);
- atmel_join_bss(priv, i);
- spin_unlock_irqrestore(&priv->irqlock, flags);
- return 0;
- }
- }
- }
-
- return -EINVAL;
-}
-
-static int atmel_config_commit(struct net_device *dev,
- struct iw_request_info *info, /* NULL */
- union iwreq_data *zwrq, /* NULL */
- char *extra) /* NULL */
-{
- return atmel_open(dev);
-}
-
-static const iw_handler atmel_handler[] =
-{
- IW_HANDLER(SIOCSIWCOMMIT, atmel_config_commit),
- IW_HANDLER(SIOCGIWNAME, atmel_get_name),
- IW_HANDLER(SIOCSIWFREQ, atmel_set_freq),
- IW_HANDLER(SIOCGIWFREQ, atmel_get_freq),
- IW_HANDLER(SIOCSIWMODE, atmel_set_mode),
- IW_HANDLER(SIOCGIWMODE, atmel_get_mode),
- IW_HANDLER(SIOCGIWRANGE, atmel_get_range),
- IW_HANDLER(SIOCSIWAP, atmel_set_wap),
- IW_HANDLER(SIOCGIWAP, atmel_get_wap),
- IW_HANDLER(SIOCSIWSCAN, atmel_set_scan),
- IW_HANDLER(SIOCGIWSCAN, atmel_get_scan),
- IW_HANDLER(SIOCSIWESSID, atmel_set_essid),
- IW_HANDLER(SIOCGIWESSID, atmel_get_essid),
- IW_HANDLER(SIOCSIWRATE, atmel_set_rate),
- IW_HANDLER(SIOCGIWRATE, atmel_get_rate),
- IW_HANDLER(SIOCSIWRTS, atmel_set_rts),
- IW_HANDLER(SIOCGIWRTS, atmel_get_rts),
- IW_HANDLER(SIOCSIWFRAG, atmel_set_frag),
- IW_HANDLER(SIOCGIWFRAG, atmel_get_frag),
- IW_HANDLER(SIOCSIWRETRY, atmel_set_retry),
- IW_HANDLER(SIOCGIWRETRY, atmel_get_retry),
- IW_HANDLER(SIOCSIWENCODE, atmel_set_encode),
- IW_HANDLER(SIOCGIWENCODE, atmel_get_encode),
- IW_HANDLER(SIOCSIWPOWER, atmel_set_power),
- IW_HANDLER(SIOCGIWPOWER, atmel_get_power),
- IW_HANDLER(SIOCSIWAUTH, atmel_set_auth),
- IW_HANDLER(SIOCGIWAUTH, atmel_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, atmel_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, atmel_get_encodeext),
-};
-
-static const iw_handler atmel_private_handler[] =
-{
- NULL, /* SIOCIWFIRSTPRIV */
-};
-
-struct atmel_priv_ioctl {
- char id[32];
- unsigned char __user *data;
- unsigned short len;
-};
-
-#define ATMELFWL SIOCIWFIRSTPRIV
-#define ATMELIDIFC ATMELFWL + 1
-#define ATMELRD ATMELFWL + 2
-#define ATMELMAGIC 0x51807
-#define REGDOMAINSZ 20
-
-static const struct iw_priv_args atmel_private_args[] = {
- {
- .cmd = ATMELFWL,
- .set_args = IW_PRIV_TYPE_BYTE
- | IW_PRIV_SIZE_FIXED
- | sizeof(struct atmel_priv_ioctl),
- .get_args = IW_PRIV_TYPE_NONE,
- .name = "atmelfwl"
- }, {
- .cmd = ATMELIDIFC,
- .set_args = IW_PRIV_TYPE_NONE,
- .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "atmelidifc"
- }, {
- .cmd = ATMELRD,
- .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ,
- .get_args = IW_PRIV_TYPE_NONE,
- .name = "regdomain"
- },
-};
-
-static const struct iw_handler_def atmel_handler_def = {
- .num_standard = ARRAY_SIZE(atmel_handler),
- .num_private = ARRAY_SIZE(atmel_private_handler),
- .num_private_args = ARRAY_SIZE(atmel_private_args),
- .standard = atmel_handler,
- .private = atmel_private_handler,
- .private_args = (struct iw_priv_args *) atmel_private_args,
- .get_wireless_stats = atmel_get_wireless_stats
-};
-
-struct auth_body {
- __le16 alg;
- __le16 trans_seq;
- __le16 status;
- u8 el_id;
- u8 chall_text_len;
- u8 chall_text[253];
-};
-
-static void atmel_enter_state(struct atmel_private *priv, int new_state)
-{
- int old_state = priv->station_state;
-
- if (new_state == old_state)
- return;
-
- priv->station_state = new_state;
-
- if (new_state == STATION_STATE_READY) {
- netif_start_queue(priv->dev);
- netif_carrier_on(priv->dev);
- }
-
- if (old_state == STATION_STATE_READY) {
- netif_carrier_off(priv->dev);
- if (netif_running(priv->dev))
- netif_stop_queue(priv->dev);
- priv->last_beacon_timestamp = 0;
- }
-}
-
-static void atmel_scan(struct atmel_private *priv, int specific_ssid)
-{
- struct {
- u8 BSSID[ETH_ALEN];
- u8 SSID[MAX_SSID_LENGTH];
- u8 scan_type;
- u8 channel;
- __le16 BSS_type;
- __le16 min_channel_time;
- __le16 max_channel_time;
- u8 options;
- u8 SSID_size;
- } cmd;
-
- eth_broadcast_addr(cmd.BSSID);
-
- if (priv->fast_scan) {
- cmd.SSID_size = priv->SSID_size;
- memcpy(cmd.SSID, priv->SSID, priv->SSID_size);
- cmd.min_channel_time = cpu_to_le16(10);
- cmd.max_channel_time = cpu_to_le16(50);
- } else {
- priv->BSS_list_entries = 0;
- cmd.SSID_size = 0;
- cmd.min_channel_time = cpu_to_le16(10);
- cmd.max_channel_time = cpu_to_le16(120);
- }
-
- cmd.options = 0;
-
- if (!specific_ssid)
- cmd.options |= SCAN_OPTIONS_SITE_SURVEY;
-
- cmd.channel = (priv->channel & 0x7f);
- cmd.scan_type = SCAN_TYPE_ACTIVE;
- cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ?
- BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE);
-
- atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd));
-
- /* This must come after all hardware access to avoid being messed up
- by stuff happening in interrupt context after we leave STATE_DOWN */
- atmel_enter_state(priv, STATION_STATE_SCANNING);
-}
-
-static void join(struct atmel_private *priv, int type)
-{
- struct {
- u8 BSSID[6];
- u8 SSID[MAX_SSID_LENGTH];
- u8 BSS_type; /* this is a short in a scan command - weird */
- u8 channel;
- __le16 timeout;
- u8 SSID_size;
- u8 reserved;
- } cmd;
-
- cmd.SSID_size = priv->SSID_size;
- memcpy(cmd.SSID, priv->SSID, priv->SSID_size);
- memcpy(cmd.BSSID, priv->CurrentBSSID, ETH_ALEN);
- cmd.channel = (priv->channel & 0x7f);
- cmd.BSS_type = type;
- cmd.timeout = cpu_to_le16(2000);
-
- atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd));
-}
-
-static void start(struct atmel_private *priv, int type)
-{
- struct {
- u8 BSSID[6];
- u8 SSID[MAX_SSID_LENGTH];
- u8 BSS_type;
- u8 channel;
- u8 SSID_size;
- u8 reserved[3];
- } cmd;
-
- cmd.SSID_size = priv->SSID_size;
- memcpy(cmd.SSID, priv->SSID, priv->SSID_size);
- memcpy(cmd.BSSID, priv->BSSID, ETH_ALEN);
- cmd.BSS_type = type;
- cmd.channel = (priv->channel & 0x7f);
-
- atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd));
-}
-
-static void handle_beacon_probe(struct atmel_private *priv, u16 capability,
- u8 channel)
-{
- int rejoin = 0;
- int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
- SHORT_PREAMBLE : LONG_PREAMBLE;
-
- if (priv->preamble != new) {
- priv->preamble = new;
- rejoin = 1;
- atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new);
- }
-
- if (priv->channel != channel) {
- priv->channel = channel;
- rejoin = 1;
- atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel);
- }
-
- if (rejoin) {
- priv->station_is_associated = 0;
- atmel_enter_state(priv, STATION_STATE_JOINNING);
-
- if (priv->operating_mode == IW_MODE_INFRA)
- join(priv, BSS_TYPE_INFRASTRUCTURE);
- else
- join(priv, BSS_TYPE_AD_HOC);
- }
-}
-
-static void send_authentication_request(struct atmel_private *priv, u16 system,
- u8 *challenge, int challenge_len)
-{
- struct ieee80211_hdr header;
- struct auth_body auth;
-
- header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH);
- header.duration_id = cpu_to_le16(0x8000);
- header.seq_ctrl = 0;
- memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN);
- memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN);
- memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN);
-
- if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
- /* no WEP for authentication frames with TrSeqNo 1 */
- header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-
- auth.alg = cpu_to_le16(system);
-
- auth.status = 0;
- auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum);
- priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1;
- priv->CurrentAuthentTransactionSeqNum += 2;
-
- if (challenge_len != 0) {
- auth.el_id = 16; /* challenge_text */
- auth.chall_text_len = challenge_len;
- memcpy(auth.chall_text, challenge, challenge_len);
- atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len);
- } else {
- atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6);
- }
-}
-
-static void send_association_request(struct atmel_private *priv, int is_reassoc)
-{
- u8 *ssid_el_p;
- int bodysize;
- struct ieee80211_hdr header;
- struct ass_req_format {
- __le16 capability;
- __le16 listen_interval;
- u8 ap[ETH_ALEN]; /* nothing after here directly accessible */
- u8 ssid_el_id;
- u8 ssid_len;
- u8 ssid[MAX_SSID_LENGTH];
- u8 sup_rates_el_id;
- u8 sup_rates_len;
- u8 rates[4];
- } body;
-
- header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
- (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ));
- header.duration_id = cpu_to_le16(0x8000);
- header.seq_ctrl = 0;
-
- memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN);
- memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN);
- memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN);
-
- body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
- if (priv->wep_is_on)
- body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
- if (priv->preamble == SHORT_PREAMBLE)
- body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
-
- body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period);
-
- /* current AP address - only in reassoc frame */
- if (is_reassoc) {
- memcpy(body.ap, priv->CurrentBSSID, ETH_ALEN);
- ssid_el_p = &body.ssid_el_id;
- bodysize = 18 + priv->SSID_size;
- } else {
- ssid_el_p = &body.ap[0];
- bodysize = 12 + priv->SSID_size;
- }
-
- ssid_el_p[0] = WLAN_EID_SSID;
- ssid_el_p[1] = priv->SSID_size;
- memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size);
- ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES;
- ssid_el_p[3 + priv->SSID_size] = 4; /* len of supported rates */
- memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4);
-
- atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize);
-}
-
-static int is_frame_from_current_bss(struct atmel_private *priv,
- struct ieee80211_hdr *header)
-{
- if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS)
- return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0;
- else
- return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0;
-}
-
-static int retrieve_bss(struct atmel_private *priv)
-{
- int i;
- int max_rssi = -128;
- int max_index = -1;
-
- if (priv->BSS_list_entries == 0)
- return -1;
-
- if (priv->connect_to_any_BSS) {
- /* Select a BSS with the max-RSSI but of the same type and of
- the same WEP mode and that it is not marked as 'bad' (i.e.
- we had previously failed to connect to this BSS with the
- settings that we currently use) */
- priv->current_BSS = 0;
- for (i = 0; i < priv->BSS_list_entries; i++) {
- if (priv->operating_mode == priv->BSSinfo[i].BSStype &&
- ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) ||
- (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) &&
- !(priv->BSSinfo[i].channel & 0x80)) {
- max_rssi = priv->BSSinfo[i].RSSI;
- priv->current_BSS = max_index = i;
- }
- }
- return max_index;
- }
-
- for (i = 0; i < priv->BSS_list_entries; i++) {
- if (priv->SSID_size == priv->BSSinfo[i].SSIDsize &&
- memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 &&
- priv->operating_mode == priv->BSSinfo[i].BSStype &&
- atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) {
- if (priv->BSSinfo[i].RSSI >= max_rssi) {
- max_rssi = priv->BSSinfo[i].RSSI;
- max_index = i;
- }
- }
- }
- return max_index;
-}
-
-static void store_bss_info(struct atmel_private *priv,
- struct ieee80211_hdr *header, u16 capability,
- u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len,
- u8 *ssid, int is_beacon)
-{
- u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3;
- int i, index;
-
- for (index = -1, i = 0; i < priv->BSS_list_entries; i++)
- if (memcmp(bss, priv->BSSinfo[i].BSSID, ETH_ALEN) == 0)
- index = i;
-
- /* If we process a probe and an entry from this BSS exists
- we will update the BSS entry with the info from this BSS.
- If we process a beacon we will only update RSSI */
-
- if (index == -1) {
- if (priv->BSS_list_entries == MAX_BSS_ENTRIES)
- return;
- index = priv->BSS_list_entries++;
- memcpy(priv->BSSinfo[index].BSSID, bss, ETH_ALEN);
- priv->BSSinfo[index].RSSI = rssi;
- } else {
- if (rssi > priv->BSSinfo[index].RSSI)
- priv->BSSinfo[index].RSSI = rssi;
- if (is_beacon)
- return;
- }
-
- priv->BSSinfo[index].channel = channel;
- priv->BSSinfo[index].beacon_period = beacon_period;
- priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY;
- memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len);
- priv->BSSinfo[index].SSIDsize = ssid_len;
-
- if (capability & WLAN_CAPABILITY_IBSS)
- priv->BSSinfo[index].BSStype = IW_MODE_ADHOC;
- else if (capability & WLAN_CAPABILITY_ESS)
- priv->BSSinfo[index].BSStype = IW_MODE_INFRA;
-
- priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
- SHORT_PREAMBLE : LONG_PREAMBLE;
-}
-
-static void authenticate(struct atmel_private *priv, u16 frame_len)
-{
- struct auth_body *auth = (struct auth_body *)priv->rx_buf;
- u16 status = le16_to_cpu(auth->status);
- u16 trans_seq_no = le16_to_cpu(auth->trans_seq);
- u16 system = le16_to_cpu(auth->alg);
-
- if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) {
- /* no WEP */
- if (priv->station_was_associated) {
- atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
- send_association_request(priv, 1);
- return;
- } else {
- atmel_enter_state(priv, STATION_STATE_ASSOCIATING);
- send_association_request(priv, 0);
- return;
- }
- }
-
- if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) {
- int should_associate = 0;
- /* WEP */
- if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum)
- return;
-
- if (system == WLAN_AUTH_OPEN) {
- if (trans_seq_no == 0x0002) {
- should_associate = 1;
- }
- } else if (system == WLAN_AUTH_SHARED_KEY) {
- if (trans_seq_no == 0x0002 &&
- auth->el_id == WLAN_EID_CHALLENGE) {
- send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len);
- return;
- } else if (trans_seq_no == 0x0004) {
- should_associate = 1;
- }
- }
-
- if (should_associate) {
- if (priv->station_was_associated) {
- atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
- send_association_request(priv, 1);
- return;
- } else {
- atmel_enter_state(priv, STATION_STATE_ASSOCIATING);
- send_association_request(priv, 0);
- return;
- }
- }
- }
-
- if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
- /* Flip back and forth between WEP auth modes until the max
- * authentication tries has been exceeded.
- */
- if (system == WLAN_AUTH_OPEN) {
- priv->CurrentAuthentTransactionSeqNum = 0x001;
- priv->exclude_unencrypted = 1;
- send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0);
- return;
- } else if (system == WLAN_AUTH_SHARED_KEY
- && priv->wep_is_on) {
- priv->CurrentAuthentTransactionSeqNum = 0x001;
- priv->exclude_unencrypted = 0;
- send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0);
- return;
- } else if (priv->connect_to_any_BSS) {
- int bss_index;
-
- priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
-
- if ((bss_index = retrieve_bss(priv)) != -1) {
- atmel_join_bss(priv, bss_index);
- return;
- }
- }
- }
-
- priv->AuthenticationRequestRetryCnt = 0;
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
-}
-
-static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype)
-{
- struct ass_resp_format {
- __le16 capability;
- __le16 status;
- __le16 ass_id;
- u8 el_id;
- u8 length;
- u8 rates[4];
- } *ass_resp = (struct ass_resp_format *)priv->rx_buf;
-
- u16 status = le16_to_cpu(ass_resp->status);
- u16 ass_id = le16_to_cpu(ass_resp->ass_id);
- u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length;
-
- union iwreq_data wrqu;
-
- if (frame_len < 8 + rates_len)
- return;
-
- if (status == WLAN_STATUS_SUCCESS) {
- if (subtype == IEEE80211_STYPE_ASSOC_RESP)
- priv->AssociationRequestRetryCnt = 0;
- else
- priv->ReAssociationRequestRetryCnt = 0;
-
- atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff);
- atmel_set_mib(priv, Phy_Mib_Type,
- PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len);
- if (priv->power_mode == 0) {
- priv->listen_interval = 1;
- atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
- atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
- } else {
- priv->listen_interval = 2;
- atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_PS_MODE_POS, PS_MODE);
- atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2);
- }
-
- priv->station_is_associated = 1;
- priv->station_was_associated = 1;
- atmel_enter_state(priv, STATION_STATE_READY);
-
- /* Send association event to userspace */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
- return;
- }
-
- if (subtype == IEEE80211_STYPE_ASSOC_RESP &&
- status != WLAN_STATUS_ASSOC_DENIED_RATES &&
- status != WLAN_STATUS_CAPS_UNSUPPORTED &&
- priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) {
- mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
- priv->AssociationRequestRetryCnt++;
- send_association_request(priv, 0);
- return;
- }
-
- if (subtype == IEEE80211_STYPE_REASSOC_RESP &&
- status != WLAN_STATUS_ASSOC_DENIED_RATES &&
- status != WLAN_STATUS_CAPS_UNSUPPORTED &&
- priv->ReAssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) {
- mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
- priv->ReAssociationRequestRetryCnt++;
- send_association_request(priv, 1);
- return;
- }
-
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
-
- if (priv->connect_to_any_BSS) {
- int bss_index;
- priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
-
- if ((bss_index = retrieve_bss(priv)) != -1)
- atmel_join_bss(priv, bss_index);
- }
-}
-
-static void atmel_join_bss(struct atmel_private *priv, int bss_index)
-{
- struct bss_info *bss = &priv->BSSinfo[bss_index];
-
- memcpy(priv->CurrentBSSID, bss->BSSID, ETH_ALEN);
- memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize);
-
- /* The WPA stuff cares about the current AP address */
- if (priv->use_wpa)
- build_wpa_mib(priv);
-
- /* When switching to AdHoc turn OFF Power Save if needed */
-
- if (bss->BSStype == IW_MODE_ADHOC &&
- priv->operating_mode != IW_MODE_ADHOC &&
- priv->power_mode) {
- priv->power_mode = 0;
- priv->listen_interval = 1;
- atmel_set_mib8(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
- atmel_set_mib16(priv, Mac_Mgmt_Mib_Type,
- MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
- }
-
- priv->operating_mode = bss->BSStype;
- priv->channel = bss->channel & 0x7f;
- priv->beacon_period = bss->beacon_period;
-
- if (priv->preamble != bss->preamble) {
- priv->preamble = bss->preamble;
- atmel_set_mib8(priv, Local_Mib_Type,
- LOCAL_MIB_PREAMBLE_TYPE, bss->preamble);
- }
-
- if (!priv->wep_is_on && bss->UsingWEP) {
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
- return;
- }
-
- if (priv->wep_is_on && !bss->UsingWEP) {
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
- return;
- }
-
- atmel_enter_state(priv, STATION_STATE_JOINNING);
-
- if (priv->operating_mode == IW_MODE_INFRA)
- join(priv, BSS_TYPE_INFRASTRUCTURE);
- else
- join(priv, BSS_TYPE_AD_HOC);
-}
-
-static void restart_search(struct atmel_private *priv)
-{
- int bss_index;
-
- if (!priv->connect_to_any_BSS) {
- atmel_scan(priv, 1);
- } else {
- priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80;
-
- if ((bss_index = retrieve_bss(priv)) != -1)
- atmel_join_bss(priv, bss_index);
- else
- atmel_scan(priv, 0);
- }
-}
-
-static void smooth_rssi(struct atmel_private *priv, u8 rssi)
-{
- u8 old = priv->wstats.qual.level;
- u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */
-
- switch (priv->firmware_type) {
- case ATMEL_FW_TYPE_502E:
- max_rssi = 63; /* 502-rmfd-reve max by experiment */
- break;
- default:
- break;
- }
-
- rssi = rssi * 100 / max_rssi;
- if ((rssi + old) % 2)
- priv->wstats.qual.level = (rssi + old) / 2 + 1;
- else
- priv->wstats.qual.level = (rssi + old) / 2;
- priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
- priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID;
-}
-
-static void atmel_smooth_qual(struct atmel_private *priv)
-{
- unsigned long time_diff = (jiffies - priv->last_qual) / HZ;
- while (time_diff--) {
- priv->last_qual += HZ;
- priv->wstats.qual.qual = priv->wstats.qual.qual / 2;
- priv->wstats.qual.qual +=
- priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000;
- priv->beacons_this_sec = 0;
- }
- priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
- priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID;
-}
-
-/* deals with incoming management frames. */
-static void atmel_management_frame(struct atmel_private *priv,
- struct ieee80211_hdr *header,
- u16 frame_len, u8 rssi)
-{
- u16 subtype;
-
- subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE;
- switch (subtype) {
- case IEEE80211_STYPE_BEACON:
- case IEEE80211_STYPE_PROBE_RESP:
-
- /* beacon frame has multiple variable-length fields -
- never let an engineer loose with a data structure design. */
- {
- struct beacon_format {
- __le64 timestamp;
- __le16 interval;
- __le16 capability;
- u8 ssid_el_id;
- u8 ssid_length;
- /* ssid here */
- u8 rates_el_id;
- u8 rates_length;
- /* rates here */
- u8 ds_el_id;
- u8 ds_length;
- /* ds here */
- } *beacon = (struct beacon_format *)priv->rx_buf;
-
- u8 channel, rates_length, ssid_length;
- u64 timestamp = le64_to_cpu(beacon->timestamp);
- u16 beacon_interval = le16_to_cpu(beacon->interval);
- u16 capability = le16_to_cpu(beacon->capability);
- u8 *beaconp = priv->rx_buf;
- ssid_length = beacon->ssid_length;
- /* this blows chunks. */
- if (frame_len < 14 || frame_len < ssid_length + 15)
- return;
- rates_length = beaconp[beacon->ssid_length + 15];
- if (frame_len < ssid_length + rates_length + 18)
- return;
- if (ssid_length > MAX_SSID_LENGTH)
- return;
- channel = beaconp[ssid_length + rates_length + 18];
-
- if (priv->station_state == STATION_STATE_READY) {
- smooth_rssi(priv, rssi);
- if (is_frame_from_current_bss(priv, header)) {
- priv->beacons_this_sec++;
- atmel_smooth_qual(priv);
- if (priv->last_beacon_timestamp) {
- /* Note truncate this to 32 bits - kernel can't divide a long */
- u32 beacon_delay = timestamp - priv->last_beacon_timestamp;
- int beacons = beacon_delay / (beacon_interval * 1000);
- if (beacons > 1)
- priv->wstats.miss.beacon += beacons - 1;
- }
- priv->last_beacon_timestamp = timestamp;
- handle_beacon_probe(priv, capability, channel);
- }
- }
-
- if (priv->station_state == STATION_STATE_SCANNING)
- store_bss_info(priv, header, capability,
- beacon_interval, channel, rssi,
- ssid_length,
- &beacon->rates_el_id,
- subtype == IEEE80211_STYPE_BEACON);
- }
- break;
-
- case IEEE80211_STYPE_AUTH:
-
- if (priv->station_state == STATION_STATE_AUTHENTICATING)
- authenticate(priv, frame_len);
-
- break;
-
- case IEEE80211_STYPE_ASSOC_RESP:
- case IEEE80211_STYPE_REASSOC_RESP:
-
- if (priv->station_state == STATION_STATE_ASSOCIATING ||
- priv->station_state == STATION_STATE_REASSOCIATING)
- associate(priv, frame_len, subtype);
-
- break;
-
- case IEEE80211_STYPE_DISASSOC:
- if (priv->station_is_associated &&
- priv->operating_mode == IW_MODE_INFRA &&
- is_frame_from_current_bss(priv, header)) {
- priv->station_was_associated = 0;
- priv->station_is_associated = 0;
-
- atmel_enter_state(priv, STATION_STATE_JOINNING);
- join(priv, BSS_TYPE_INFRASTRUCTURE);
- }
-
- break;
-
- case IEEE80211_STYPE_DEAUTH:
- if (priv->operating_mode == IW_MODE_INFRA &&
- is_frame_from_current_bss(priv, header)) {
- priv->station_was_associated = 0;
-
- atmel_enter_state(priv, STATION_STATE_JOINNING);
- join(priv, BSS_TYPE_INFRASTRUCTURE);
- }
-
- break;
- }
-}
-
-/* run when timer expires */
-static void atmel_management_timer(struct timer_list *t)
-{
- struct atmel_private *priv = from_timer(priv, t, management_timer);
- unsigned long flags;
-
- /* Check if the card has been yanked. */
- if (priv->card && priv->present_callback &&
- !(*priv->present_callback)(priv->card))
- return;
-
- spin_lock_irqsave(&priv->irqlock, flags);
-
- switch (priv->station_state) {
-
- case STATION_STATE_AUTHENTICATING:
- if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) {
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
- priv->AuthenticationRequestRetryCnt = 0;
- restart_search(priv);
- } else {
- int auth = WLAN_AUTH_OPEN;
- priv->AuthenticationRequestRetryCnt++;
- priv->CurrentAuthentTransactionSeqNum = 0x0001;
- mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
- if (priv->wep_is_on && priv->exclude_unencrypted)
- auth = WLAN_AUTH_SHARED_KEY;
- send_authentication_request(priv, auth, NULL, 0);
- }
- break;
-
- case STATION_STATE_ASSOCIATING:
- if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) {
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
- priv->AssociationRequestRetryCnt = 0;
- restart_search(priv);
- } else {
- priv->AssociationRequestRetryCnt++;
- mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
- send_association_request(priv, 0);
- }
- break;
-
- case STATION_STATE_REASSOCIATING:
- if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) {
- atmel_enter_state(priv, STATION_STATE_MGMT_ERROR);
- priv->station_is_associated = 0;
- priv->ReAssociationRequestRetryCnt = 0;
- restart_search(priv);
- } else {
- priv->ReAssociationRequestRetryCnt++;
- mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
- send_association_request(priv, 1);
- }
- break;
-
- default:
- break;
- }
-
- spin_unlock_irqrestore(&priv->irqlock, flags);
-}
-
-static void atmel_command_irq(struct atmel_private *priv)
-{
- u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET));
- u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET));
- int fast_scan;
- union iwreq_data wrqu;
-
- if (status == CMD_STATUS_IDLE ||
- status == CMD_STATUS_IN_PROGRESS)
- return;
-
- switch (command) {
- case CMD_Start:
- if (status == CMD_STATUS_COMPLETE) {
- priv->station_was_associated = priv->station_is_associated;
- atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS,
- (u8 *)priv->CurrentBSSID, 6);
- atmel_enter_state(priv, STATION_STATE_READY);
- }
- break;
-
- case CMD_Scan:
- fast_scan = priv->fast_scan;
- priv->fast_scan = 0;
-
- if (status != CMD_STATUS_COMPLETE) {
- atmel_scan(priv, 1);
- } else {
- int bss_index = retrieve_bss(priv);
- int notify_scan_complete = 1;
- if (bss_index != -1) {
- atmel_join_bss(priv, bss_index);
- } else if (priv->operating_mode == IW_MODE_ADHOC &&
- priv->SSID_size != 0) {
- start(priv, BSS_TYPE_AD_HOC);
- } else {
- priv->fast_scan = !fast_scan;
- atmel_scan(priv, 1);
- notify_scan_complete = 0;
- }
- priv->site_survey_state = SITE_SURVEY_COMPLETED;
- if (notify_scan_complete) {
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
- }
- }
- break;
-
- case CMD_SiteSurvey:
- priv->fast_scan = 0;
-
- if (status != CMD_STATUS_COMPLETE)
- return;
-
- priv->site_survey_state = SITE_SURVEY_COMPLETED;
- if (priv->station_is_associated) {
- atmel_enter_state(priv, STATION_STATE_READY);
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
- } else {
- atmel_scan(priv, 1);
- }
- break;
-
- case CMD_Join:
- if (status == CMD_STATUS_COMPLETE) {
- if (priv->operating_mode == IW_MODE_ADHOC) {
- priv->station_was_associated = priv->station_is_associated;
- atmel_enter_state(priv, STATION_STATE_READY);
- } else {
- int auth = WLAN_AUTH_OPEN;
- priv->AuthenticationRequestRetryCnt = 0;
- atmel_enter_state(priv, STATION_STATE_AUTHENTICATING);
-
- mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES);
- priv->CurrentAuthentTransactionSeqNum = 0x0001;
- if (priv->wep_is_on && priv->exclude_unencrypted)
- auth = WLAN_AUTH_SHARED_KEY;
- send_authentication_request(priv, auth, NULL, 0);
- }
- return;
- }
-
- atmel_scan(priv, 1);
- }
-}
-
-static int atmel_wakeup_firmware(struct atmel_private *priv)
-{
- struct host_info_struct *iface = &priv->host_info;
- u16 mr1, mr3;
- int i;
-
- if (priv->card_type == CARD_TYPE_SPI_FLASH)
- atmel_set_gcr(priv->dev, GCR_REMAP);
-
- /* wake up on-board processor */
- atmel_clear_gcr(priv->dev, 0x0040);
- atmel_write16(priv->dev, BSR, BSS_SRAM);
-
- if (priv->card_type == CARD_TYPE_SPI_FLASH)
- mdelay(100);
-
- /* and wait for it */
- for (i = LOOP_RETRY_LIMIT; i; i--) {
- mr1 = atmel_read16(priv->dev, MR1);
- mr3 = atmel_read16(priv->dev, MR3);
-
- if (mr3 & MAC_BOOT_COMPLETE)
- break;
- if (mr1 & MAC_BOOT_COMPLETE &&
- priv->bus_type == BUS_TYPE_PCCARD)
- break;
- }
-
- if (i == 0) {
- printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name);
- return -EIO;
- }
-
- if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) {
- printk(KERN_ALERT "%s: card missing.\n", priv->dev->name);
- return -ENODEV;
- }
-
- /* now check for completion of MAC initialization through
- the FunCtrl field of the IFACE, poll MR1 to detect completion of
- MAC initialization, check completion status, set interrupt mask,
- enables interrupts and calls Tx and Rx initialization functions */
-
- atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE);
-
- for (i = LOOP_RETRY_LIMIT; i; i--) {
- mr1 = atmel_read16(priv->dev, MR1);
- mr3 = atmel_read16(priv->dev, MR3);
-
- if (mr3 & MAC_INIT_COMPLETE)
- break;
- if (mr1 & MAC_INIT_COMPLETE &&
- priv->bus_type == BUS_TYPE_PCCARD)
- break;
- }
-
- if (i == 0) {
- printk(KERN_ALERT "%s: MAC failed to initialise.\n",
- priv->dev->name);
- return -EIO;
- }
-
- /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */
- if ((mr3 & MAC_INIT_COMPLETE) &&
- !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) {
- printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name);
- return -EIO;
- }
- if ((mr1 & MAC_INIT_COMPLETE) &&
- !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) {
- printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name);
- return -EIO;
- }
-
- atmel_copy_to_host(priv->dev, (unsigned char *)iface,
- priv->host_info_base, sizeof(*iface));
-
- iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos);
- iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size);
- iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos);
- iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count);
- iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos);
- iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size);
- iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos);
- iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count);
- iface->build_version = le16_to_cpu(iface->build_version);
- iface->command_pos = le16_to_cpu(iface->command_pos);
- iface->major_version = le16_to_cpu(iface->major_version);
- iface->minor_version = le16_to_cpu(iface->minor_version);
- iface->func_ctrl = le16_to_cpu(iface->func_ctrl);
- iface->mac_status = le16_to_cpu(iface->mac_status);
-
- return 0;
-}
-
-/* determine type of memory and MAC address */
-static int probe_atmel_card(struct net_device *dev)
-{
- int rc = 0;
- struct atmel_private *priv = netdev_priv(dev);
- u8 addr[ETH_ALEN] = {};
-
- /* reset pccard */
- if (priv->bus_type == BUS_TYPE_PCCARD)
- atmel_write16(dev, GCR, 0x0060);
-
- atmel_write16(dev, GCR, 0x0040);
- msleep(500);
-
- if (atmel_read16(dev, MR2) == 0) {
- /* No stored firmware so load a small stub which just
- tells us the MAC address */
- int i;
- priv->card_type = CARD_TYPE_EEPROM;
- atmel_write16(dev, BSR, BSS_IRAM);
- atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader));
- atmel_set_gcr(dev, GCR_REMAP);
- atmel_clear_gcr(priv->dev, 0x0040);
- atmel_write16(dev, BSR, BSS_SRAM);
- for (i = LOOP_RETRY_LIMIT; i; i--)
- if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE)
- break;
- if (i == 0) {
- printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name);
- } else {
-
- atmel_copy_to_host(dev, addr, atmel_read16(dev, MR2), 6);
- eth_hw_addr_set(dev, addr);
- /* got address, now squash it again until the network
- interface is opened */
- if (priv->bus_type == BUS_TYPE_PCCARD)
- atmel_write16(dev, GCR, 0x0060);
- atmel_write16(dev, GCR, 0x0040);
- rc = 1;
- }
- } else if (atmel_read16(dev, MR4) == 0) {
- /* Mac address easy in this case. */
- priv->card_type = CARD_TYPE_PARALLEL_FLASH;
- atmel_write16(dev, BSR, 1);
- atmel_copy_to_host(dev, addr, 0xc000, 6);
- eth_hw_addr_set(dev, addr);
- atmel_write16(dev, BSR, 0x200);
- rc = 1;
- } else {
- /* Standard firmware in flash, boot it up and ask
- for the Mac Address */
- priv->card_type = CARD_TYPE_SPI_FLASH;
- if (atmel_wakeup_firmware(priv) == 0) {
- atmel_get_mib(priv, Mac_Address_Mib_Type, 0, addr, 6);
- eth_hw_addr_set(dev, addr);
-
- /* got address, now squash it again until the network
- interface is opened */
- if (priv->bus_type == BUS_TYPE_PCCARD)
- atmel_write16(dev, GCR, 0x0060);
- atmel_write16(dev, GCR, 0x0040);
- rc = 1;
- }
- }
-
- if (rc) {
- if (dev->dev_addr[0] == 0xFF) {
- static const u8 default_mac[] = {
- 0x00, 0x04, 0x25, 0x00, 0x00, 0x00
- };
- printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
- eth_hw_addr_set(dev, default_mac);
- }
- }
-
- return rc;
-}
-
-/* Move the encyption information on the MIB structure.
- This routine is for the pre-WPA firmware: later firmware has
- a different format MIB and a different routine. */
-static void build_wep_mib(struct atmel_private *priv)
-{
- struct { /* NB this is matched to the hardware, don't change. */
- u8 wep_is_on;
- u8 default_key; /* 0..3 */
- u8 reserved;
- u8 exclude_unencrypted;
-
- u32 WEPICV_error_count;
- u32 WEP_excluded_count;
-
- u8 wep_keys[MAX_ENCRYPTION_KEYS][13];
- u8 encryption_level; /* 0, 1, 2 */
- u8 reserved2[3];
- } mib;
- int i;
-
- mib.wep_is_on = priv->wep_is_on;
- if (priv->wep_is_on) {
- if (priv->wep_key_len[priv->default_key] > 5)
- mib.encryption_level = 2;
- else
- mib.encryption_level = 1;
- } else {
- mib.encryption_level = 0;
- }
-
- mib.default_key = priv->default_key;
- mib.exclude_unencrypted = priv->exclude_unencrypted;
-
- for (i = 0; i < MAX_ENCRYPTION_KEYS; i++)
- memcpy(mib.wep_keys[i], priv->wep_keys[i], 13);
-
- atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
-}
-
-static void build_wpa_mib(struct atmel_private *priv)
-{
- /* This is for the later (WPA enabled) firmware. */
-
- struct { /* NB this is matched to the hardware, don't change. */
- u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE];
- u8 receiver_address[ETH_ALEN];
- u8 wep_is_on;
- u8 default_key; /* 0..3 */
- u8 group_key;
- u8 exclude_unencrypted;
- u8 encryption_type;
- u8 reserved;
-
- u32 WEPICV_error_count;
- u32 WEP_excluded_count;
-
- u8 key_RSC[4][8];
- } mib;
-
- int i;
-
- mib.wep_is_on = priv->wep_is_on;
- mib.exclude_unencrypted = priv->exclude_unencrypted;
- memcpy(mib.receiver_address, priv->CurrentBSSID, ETH_ALEN);
-
- /* zero all the keys before adding in valid ones. */
- memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value));
-
- if (priv->wep_is_on) {
- /* There's a comment in the Atmel code to the effect that this
- is only valid when still using WEP, it may need to be set to
- something to use WPA */
- memset(mib.key_RSC, 0, sizeof(mib.key_RSC));
-
- mib.default_key = mib.group_key = 255;
- for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) {
- if (priv->wep_key_len[i] > 0) {
- memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE);
- if (i == priv->default_key) {
- mib.default_key = i;
- mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7;
- mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite;
- } else {
- mib.group_key = i;
- priv->group_cipher_suite = priv->pairwise_cipher_suite;
- mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1;
- mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite;
- }
- }
- }
- if (mib.default_key == 255)
- mib.default_key = mib.group_key != 255 ? mib.group_key : 0;
- if (mib.group_key == 255)
- mib.group_key = mib.default_key;
-
- }
-
- atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib));
-}
-
-static int reset_atmel_card(struct net_device *dev)
-{
- /* do everything necessary to wake up the hardware, including
- waiting for the lightning strike and throwing the knife switch....
-
- set all the Mib values which matter in the card to match
- their settings in the atmel_private structure. Some of these
- can be altered on the fly, but many (WEP, infrastructure or ad-hoc)
- can only be changed by tearing down the world and coming back through
- here.
-
- This routine is also responsible for initialising some
- hardware-specific fields in the atmel_private structure,
- including a copy of the firmware's hostinfo structure
- which is the route into the rest of the firmware datastructures. */
-
- struct atmel_private *priv = netdev_priv(dev);
- u8 configuration;
- int old_state = priv->station_state;
- int err = 0;
-
- /* data to add to the firmware names, in priority order
- this implemenents firmware versioning */
-
- static char *firmware_modifier[] = {
- "-wpa",
- "",
- NULL
- };
-
- /* reset pccard */
- if (priv->bus_type == BUS_TYPE_PCCARD)
- atmel_write16(priv->dev, GCR, 0x0060);
-
- /* stop card , disable interrupts */
- atmel_write16(priv->dev, GCR, 0x0040);
-
- if (priv->card_type == CARD_TYPE_EEPROM) {
- /* copy in firmware if needed */
- const struct firmware *fw_entry = NULL;
- const unsigned char *fw;
- int len = priv->firmware_length;
- if (!(fw = priv->firmware)) {
- if (priv->firmware_type == ATMEL_FW_TYPE_NONE) {
- if (strlen(priv->firmware_id) == 0) {
- printk(KERN_INFO
- "%s: card type is unknown: assuming at76c502 firmware is OK.\n",
- dev->name);
- printk(KERN_INFO
- "%s: if not, use the firmware= module parameter.\n",
- dev->name);
- strcpy(priv->firmware_id, "atmel_at76c502.bin");
- }
- err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev);
- if (err != 0) {
- printk(KERN_ALERT
- "%s: firmware %s is missing, cannot continue.\n",
- dev->name, priv->firmware_id);
- return err;
- }
- } else {
- int fw_index = 0;
- int success = 0;
-
- /* get firmware filename entry based on firmware type ID */
- while (fw_table[fw_index].fw_type != priv->firmware_type
- && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE)
- fw_index++;
-
- /* construct the actual firmware file name */
- if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) {
- int i;
- for (i = 0; firmware_modifier[i]; i++) {
- snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file,
- firmware_modifier[i], fw_table[fw_index].fw_file_ext);
- priv->firmware_id[31] = '\0';
- if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) {
- success = 1;
- break;
- }
- }
- }
- if (!success) {
- printk(KERN_ALERT
- "%s: firmware %s is missing, cannot start.\n",
- dev->name, priv->firmware_id);
- priv->firmware_id[0] = '\0';
- return -ENOENT;
- }
- }
-
- fw = fw_entry->data;
- len = fw_entry->size;
- }
-
- if (len <= 0x6000) {
- atmel_write16(priv->dev, BSR, BSS_IRAM);
- atmel_copy_to_card(priv->dev, 0, fw, len);
- atmel_set_gcr(priv->dev, GCR_REMAP);
- } else {
- /* Remap */
- atmel_set_gcr(priv->dev, GCR_REMAP);
- atmel_write16(priv->dev, BSR, BSS_IRAM);
- atmel_copy_to_card(priv->dev, 0, fw, 0x6000);
- atmel_write16(priv->dev, BSR, 0x2ff);
- atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000);
- }
-
- release_firmware(fw_entry);
- }
-
- err = atmel_wakeup_firmware(priv);
- if (err != 0)
- return err;
-
- /* Check the version and set the correct flag for wpa stuff,
- old and new firmware is incompatible.
- The pre-wpa 3com firmware reports major version 5,
- the wpa 3com firmware is major version 4 and doesn't need
- the 3com broken-ness filter. */
- priv->use_wpa = (priv->host_info.major_version == 4);
- priv->radio_on_broken = (priv->host_info.major_version == 5);
-
- /* unmask all irq sources */
- atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff);
-
- /* int Tx system and enable Tx */
- atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0);
- atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L);
- atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0);
- atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0);
-
- priv->tx_desc_free = priv->host_info.tx_desc_count;
- priv->tx_desc_head = 0;
- priv->tx_desc_tail = 0;
- priv->tx_desc_previous = 0;
- priv->tx_free_mem = priv->host_info.tx_buff_size;
- priv->tx_buff_head = 0;
- priv->tx_buff_tail = 0;
-
- configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET));
- atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET),
- configuration | FUNC_CTRL_TxENABLE);
-
- /* init Rx system and enable */
- priv->rx_desc_head = 0;
-
- configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET));
- atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET),
- configuration | FUNC_CTRL_RxENABLE);
-
- if (!priv->radio_on_broken) {
- if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) ==
- CMD_STATUS_REJECTED_RADIO_OFF) {
- printk(KERN_INFO "%s: cannot turn the radio on.\n",
- dev->name);
- return -EIO;
- }
- }
-
- /* set up enough MIB values to run. */
- atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate);
- atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF);
- atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold);
- atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold);
- atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry);
- atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry);
- atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble);
- atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS,
- priv->dev->dev_addr, 6);
- atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE);
- atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1);
- atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period);
- atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4);
- atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on);
- if (priv->use_wpa)
- build_wpa_mib(priv);
- else
- build_wep_mib(priv);
-
- if (old_state == STATION_STATE_READY) {
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
- }
-
- return 0;
-}
-
-static void atmel_send_command(struct atmel_private *priv, int command,
- void *cmd, int cmd_size)
-{
- if (cmd)
- atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET),
- cmd, cmd_size);
-
- atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command);
- atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0);
-}
-
-static int atmel_send_command_wait(struct atmel_private *priv, int command,
- void *cmd, int cmd_size)
-{
- int i, status;
-
- atmel_send_command(priv, command, cmd, cmd_size);
-
- for (i = 5000; i; i--) {
- status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET));
- if (status != CMD_STATUS_IDLE &&
- status != CMD_STATUS_IN_PROGRESS)
- break;
- udelay(20);
- }
-
- if (i == 0) {
- printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name);
- status = CMD_STATUS_HOST_ERROR;
- } else {
- if (command != CMD_EnableRadio)
- status = CMD_STATUS_COMPLETE;
- }
-
- return status;
-}
-
-static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index)
-{
- struct get_set_mib m;
- m.type = type;
- m.size = 1;
- m.index = index;
-
- atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
- return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE));
-}
-
-static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data)
-{
- struct get_set_mib m;
- m.type = type;
- m.size = 1;
- m.index = index;
- m.data[0] = data;
-
- atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1);
-}
-
-static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index,
- u16 data)
-{
- struct get_set_mib m;
- m.type = type;
- m.size = 2;
- m.index = index;
- m.data[0] = data;
- m.data[1] = data >> 8;
-
- atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2);
-}
-
-static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index,
- const u8 *data, int data_len)
-{
- struct get_set_mib m;
- m.type = type;
- m.size = data_len;
- m.index = index;
-
- if (data_len > MIB_MAX_DATA_BYTES)
- printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
-
- memcpy(m.data, data, data_len);
- atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
-}
-
-static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index,
- u8 *data, int data_len)
-{
- struct get_set_mib m;
- m.type = type;
- m.size = data_len;
- m.index = index;
-
- if (data_len > MIB_MAX_DATA_BYTES)
- printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name);
-
- atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len);
- atmel_copy_to_host(priv->dev, data,
- atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len);
-}
-
-static void atmel_writeAR(struct net_device *dev, u16 data)
-{
- int i;
- outw(data, dev->base_addr + AR);
- /* Address register appears to need some convincing..... */
- for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++)
- outw(data, dev->base_addr + AR);
-}
-
-static void atmel_copy_to_card(struct net_device *dev, u16 dest,
- const unsigned char *src, u16 len)
-{
- int i;
- atmel_writeAR(dev, dest);
- if (dest % 2) {
- atmel_write8(dev, DR, *src);
- src++; len--;
- }
- for (i = len; i > 1 ; i -= 2) {
- u8 lb = *src++;
- u8 hb = *src++;
- atmel_write16(dev, DR, lb | (hb << 8));
- }
- if (i)
- atmel_write8(dev, DR, *src);
-}
-
-static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest,
- u16 src, u16 len)
-{
- int i;
- atmel_writeAR(dev, src);
- if (src % 2) {
- *dest = atmel_read8(dev, DR);
- dest++; len--;
- }
- for (i = len; i > 1 ; i -= 2) {
- u16 hw = atmel_read16(dev, DR);
- *dest++ = hw;
- *dest++ = hw >> 8;
- }
- if (i)
- *dest = atmel_read8(dev, DR);
-}
-
-static void atmel_set_gcr(struct net_device *dev, u16 mask)
-{
- outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR);
-}
-
-static void atmel_clear_gcr(struct net_device *dev, u16 mask)
-{
- outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR);
-}
-
-static int atmel_lock_mac(struct atmel_private *priv)
-{
- int i, j = 20;
- retry:
- for (i = 5000; i; i--) {
- if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET)))
- break;
- udelay(20);
- }
-
- if (!i)
- return 0; /* timed out */
-
- atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1);
- if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) {
- atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);
- if (!j--)
- return 0; /* timed out */
- goto retry;
- }
-
- return 1;
-}
-
-static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data)
-{
- atmel_writeAR(priv->dev, pos);
- atmel_write16(priv->dev, DR, data); /* card is little-endian */
- atmel_write16(priv->dev, DR, data >> 16);
-}
-
-/***************************************************************************/
-/* There follows the source form of the MAC address reading firmware */
-/***************************************************************************/
-#if 0
-
-/* Copyright 2003 Matthew T. Russotto */
-/* But derived from the Atmel 76C502 firmware written by Atmel and */
-/* included in "atmel wireless lan drivers" package */
-/*
- This file is part of net.russotto.AtmelMACFW, hereto referred to
- as AtmelMACFW
-
- AtmelMACFW is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2
- as published by the Free Software Foundation.
-
- AtmelMACFW is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with AtmelMACFW; if not, see <http://www.gnu.org/licenses/>.
-
-****************************************************************************/
-/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */
-/* It will probably work on the 76C504 and 76C502 RFMD_3COM */
-/* It only works on SPI EEPROM versions of the card. */
-
-/* This firmware initializes the SPI controller and clock, reads the MAC */
-/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */
-/* address in MR2, and sets MR3 to 0x10 to indicate it is done */
-/* It also puts a complete copy of the EEPROM in SRAM with the offset in */
-/* MR4, for investigational purposes (maybe we can determine chip type */
-/* from that?) */
-
- .org 0
- .set MRBASE, 0x8000000
- .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */
- .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */
- .set SRAM_BASE, 0x02000000
- .set SP_BASE, 0x0F300000
- .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */
- .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */
- .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */
- .set STACK_BASE, 0x5600
- .set SP_SR, 0x10
- .set SP_TDRE, 2 /* status register bit -- TDR empty */
- .set SP_RDRF, 1 /* status register bit -- RDR full */
- .set SP_SWRST, 0x80
- .set SP_SPIEN, 0x1
- .set SP_CR, 0 /* control register */
- .set SP_MR, 4 /* mode register */
- .set SP_RDR, 0x08 /* Read Data Register */
- .set SP_TDR, 0x0C /* Transmit Data Register */
- .set SP_CSR0, 0x30 /* chip select registers */
- .set SP_CSR1, 0x34
- .set SP_CSR2, 0x38
- .set SP_CSR3, 0x3C
- .set NVRAM_CMD_RDSR, 5 /* read status register */
- .set NVRAM_CMD_READ, 3 /* read data */
- .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */
- .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the
- serial output, since SO is normally high. But it
- does cause 8 clock cycles and thus 8 bits to be
- clocked in to the chip. See Atmel's SPI
- controller (e.g. AT91M55800) timing and 4K
- SPI EEPROM manuals */
-
- .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */
- .set NVRAM_IMAGE, 0x02000200
- .set NVRAM_LENGTH, 0x0200
- .set MAC_ADDRESS_MIB, SRAM_BASE
- .set MAC_ADDRESS_LENGTH, 6
- .set MAC_BOOT_FLAG, 0x10
- .set MR1, 0
- .set MR2, 4
- .set MR3, 8
- .set MR4, 0xC
-RESET_VECTOR:
- b RESET_HANDLER
-UNDEF_VECTOR:
- b HALT1
-SWI_VECTOR:
- b HALT1
-IABORT_VECTOR:
- b HALT1
-DABORT_VECTOR:
-RESERVED_VECTOR:
- b HALT1
-IRQ_VECTOR:
- b HALT1
-FIQ_VECTOR:
- b HALT1
-HALT1: b HALT1
-RESET_HANDLER:
- mov r0, #CPSR_INITIAL
- msr CPSR_c, r0 /* This is probably unnecessary */
-
-/* I'm guessing this is initializing clock generator electronics for SPI */
- ldr r0, =SPI_CGEN_BASE
- mov r1, #0
- mov r1, r1, lsl #3
- orr r1, r1, #0
- str r1, [r0]
- ldr r1, [r0, #28]
- bic r1, r1, #16
- str r1, [r0, #28]
- mov r1, #1
- str r1, [r0, #8]
-
- ldr r0, =MRBASE
- mov r1, #0
- strh r1, [r0, #MR1]
- strh r1, [r0, #MR2]
- strh r1, [r0, #MR3]
- strh r1, [r0, #MR4]
-
- mov sp, #STACK_BASE
- bl SP_INIT
- mov r0, #10
- bl DELAY9
- bl GET_MAC_ADDR
- bl GET_WHOLE_NVRAM
- ldr r0, =MRBASE
- ldr r1, =MAC_ADDRESS_MIB
- strh r1, [r0, #MR2]
- ldr r1, =NVRAM_IMAGE
- strh r1, [r0, #MR4]
- mov r1, #MAC_BOOT_FLAG
- strh r1, [r0, #MR3]
-HALT2: b HALT2
-.func Get_Whole_NVRAM, GET_WHOLE_NVRAM
-GET_WHOLE_NVRAM:
- stmdb sp!, {lr}
- mov r2, #0 /* 0th bytes of NVRAM */
- mov r3, #NVRAM_LENGTH
- mov r1, #0 /* not used in routine */
- ldr r0, =NVRAM_IMAGE
- bl NVRAM_XFER
- ldmia sp!, {lr}
- bx lr
-.endfunc
-
-.func Get_MAC_Addr, GET_MAC_ADDR
-GET_MAC_ADDR:
- stmdb sp!, {lr}
- mov r2, #0x120 /* address of MAC Address within NVRAM */
- mov r3, #MAC_ADDRESS_LENGTH
- mov r1, #0 /* not used in routine */
- ldr r0, =MAC_ADDRESS_MIB
- bl NVRAM_XFER
- ldmia sp!, {lr}
- bx lr
-.endfunc
-.ltorg
-.func Delay9, DELAY9
-DELAY9:
- adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */
-DELAYLOOP:
- beq DELAY9_done
- subs r0, r0, #1
- b DELAYLOOP
-DELAY9_done:
- bx lr
-.endfunc
-
-.func SP_Init, SP_INIT
-SP_INIT:
- mov r1, #SP_SWRST
- ldr r0, =SP_BASE
- str r1, [r0, #SP_CR] /* reset the SPI */
- mov r1, #0
- str r1, [r0, #SP_CR] /* release SPI from reset state */
- mov r1, #SP_SPIEN
- str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/
- str r1, [r0, #SP_CR] /* enable the SPI */
-
-/* My guess would be this turns on the SPI clock */
- ldr r3, =SPI_CGEN_BASE
- ldr r1, [r3, #28]
- orr r1, r1, #0x2000
- str r1, [r3, #28]
-
- ldr r1, =0x2000c01
- str r1, [r0, #SP_CSR0]
- ldr r1, =0x2000201
- str r1, [r0, #SP_CSR1]
- str r1, [r0, #SP_CSR2]
- str r1, [r0, #SP_CSR3]
- ldr r1, [r0, #SP_SR]
- ldr r0, [r0, #SP_RDR]
- bx lr
-.endfunc
-.func NVRAM_Init, NVRAM_INIT
-NVRAM_INIT:
- ldr r1, =SP_BASE
- ldr r0, [r1, #SP_RDR]
- mov r0, #NVRAM_CMD_RDSR
- str r0, [r1, #SP_TDR]
-SP_loop1:
- ldr r0, [r1, #SP_SR]
- tst r0, #SP_TDRE
- beq SP_loop1
-
- mov r0, #SPI_8CLOCKS
- str r0, [r1, #SP_TDR]
-SP_loop2:
- ldr r0, [r1, #SP_SR]
- tst r0, #SP_TDRE
- beq SP_loop2
-
- ldr r0, [r1, #SP_RDR]
-SP_loop3:
- ldr r0, [r1, #SP_SR]
- tst r0, #SP_RDRF
- beq SP_loop3
-
- ldr r0, [r1, #SP_RDR]
- and r0, r0, #255
- bx lr
-.endfunc
-
-.func NVRAM_Xfer, NVRAM_XFER
- /* r0 = dest address */
- /* r1 = not used */
- /* r2 = src address within NVRAM */
- /* r3 = length */
-NVRAM_XFER:
- stmdb sp!, {r4, r5, lr}
- mov r5, r0 /* save r0 (dest address) */
- mov r4, r3 /* save r3 (length) */
- mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */
- and r0, r0, #8
- add r0, r0, #NVRAM_CMD_READ
- ldr r1, =NVRAM_SCRATCH
- strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */
- strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */
-_local1:
- bl NVRAM_INIT
- tst r0, #NVRAM_SR_RDY
- bne _local1
- mov r0, #20
- bl DELAY9
- mov r2, r4 /* length */
- mov r1, r5 /* dest address */
- mov r0, #2 /* bytes to transfer in command */
- bl NVRAM_XFER2
- ldmia sp!, {r4, r5, lr}
- bx lr
-.endfunc
-
-.func NVRAM_Xfer2, NVRAM_XFER2
-NVRAM_XFER2:
- stmdb sp!, {r4, r5, r6, lr}
- ldr r4, =SP_BASE
- mov r3, #0
- cmp r0, #0
- bls _local2
- ldr r5, =NVRAM_SCRATCH
-_local4:
- ldrb r6, [r5, r3]
- str r6, [r4, #SP_TDR]
-_local3:
- ldr r6, [r4, #SP_SR]
- tst r6, #SP_TDRE
- beq _local3
- add r3, r3, #1
- cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */
- blo _local4
-_local2:
- mov r3, #SPI_8CLOCKS
- str r3, [r4, #SP_TDR]
- ldr r0, [r4, #SP_RDR]
-_local5:
- ldr r0, [r4, #SP_SR]
- tst r0, #SP_RDRF
- beq _local5
- ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */
- mov r0, #0
- cmp r2, #0 /* r2 is # of bytes to copy in */
- bls _local6
-_local7:
- ldr r5, [r4, #SP_SR]
- tst r5, #SP_TDRE
- beq _local7
- str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */
-_local8:
- ldr r5, [r4, #SP_SR]
- tst r5, #SP_RDRF
- beq _local8
- ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */
- strb r5, [r1], #1 /* postindexed */
- add r0, r0, #1
- cmp r0, r2
- blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */
-_local6:
- mov r0, #200
- bl DELAY9
- ldmia sp!, {r4, r5, r6, lr}
- bx lr
-#endif
diff --git a/drivers/net/wireless/atmel/atmel.h b/drivers/net/wireless/atmel/atmel.h
deleted file mode 100644
index d2aa52cf6e8b..000000000000
--- a/drivers/net/wireless/atmel/atmel.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*** -*- linux-c -*- **********************************************************
-
- Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
-
- Copyright 2005 Dan Williams and Red Hat, Inc.
-
-
-******************************************************************************/
-
-#ifndef _ATMEL_H
-#define _ATMEL_H
-
-typedef enum {
- ATMEL_FW_TYPE_NONE = 0,
- ATMEL_FW_TYPE_502,
- ATMEL_FW_TYPE_502D,
- ATMEL_FW_TYPE_502E,
- ATMEL_FW_TYPE_502_3COM,
- ATMEL_FW_TYPE_504,
- ATMEL_FW_TYPE_504_2958,
- ATMEL_FW_TYPE_504A_2958,
- ATMEL_FW_TYPE_506
-} AtmelFWType;
-
-struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *,
- int (*present_func)(void *), void * );
-void stop_atmel_card( struct net_device *);
-int atmel_open( struct net_device * );
-
-#endif
diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c
deleted file mode 100644
index 58bba9875d36..000000000000
--- a/drivers/net/wireless/atmel/atmel_cs.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*** -*- linux-c -*- **********************************************************
-
- Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
-
- Copyright 2000-2001 ATMEL Corporation.
- Copyright 2003 Simon Kelley.
-
- This code was developed from version 2.1.1 of the Atmel drivers,
- released by Atmel corp. under the GPL in December 2002. It also
- includes code from the Linux aironet drivers (C) Benjamin Reed,
- and the Linux PCMCIA package, (C) David Hinds.
-
- For all queries about this code, please contact the current author,
- Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
-
- 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 Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This software is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Atmel wireless lan drivers; if not, see
- <http://www.gnu.org/licenses/>.
-
-******************************************************************************/
-
-#ifdef __IN_PCMCIA_PACKAGE__
-#include <pcmcia/k_compat.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/netdevice.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/ciscode.h>
-
-#include <asm/io.h>
-#include <linux/wireless.h>
-
-#include "atmel.h"
-
-
-/*====================================================================*/
-
-MODULE_AUTHOR("Simon Kelley");
-MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
-MODULE_LICENSE("GPL");
-
-/*====================================================================*/
-
-static int atmel_config(struct pcmcia_device *link);
-static void atmel_release(struct pcmcia_device *link);
-
-static void atmel_detach(struct pcmcia_device *p_dev);
-
-struct local_info {
- struct net_device *eth_dev;
-};
-
-static int atmel_probe(struct pcmcia_device *p_dev)
-{
- struct local_info *local;
- int ret;
-
- dev_dbg(&p_dev->dev, "atmel_attach()\n");
-
- /* Allocate space for private device-specific data */
- local = kzalloc(sizeof(*local), GFP_KERNEL);
- if (!local)
- return -ENOMEM;
-
- p_dev->priv = local;
-
- ret = atmel_config(p_dev);
- if (ret)
- goto err_free_priv;
-
- return 0;
-
-err_free_priv:
- kfree(p_dev->priv);
- return ret;
-}
-
-static void atmel_detach(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "atmel_detach\n");
-
- atmel_release(link);
-
- kfree(link->priv);
-}
-
-/* Call-back function to interrogate PCMCIA-specific information
- about the current existence of the card */
-static int card_present(void *arg)
-{
- struct pcmcia_device *link = (struct pcmcia_device *)arg;
-
- if (pcmcia_dev_present(link))
- return 1;
-
- return 0;
-}
-
-static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-}
-
-static int atmel_config(struct pcmcia_device *link)
-{
- int ret;
- const struct pcmcia_device_id *did;
-
- did = dev_get_drvdata(&link->dev);
-
- dev_dbg(&link->dev, "atmel_config\n");
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
- CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
-
- if (pcmcia_loop_config(link, atmel_config_check, NULL))
- goto failed;
-
- if (!link->irq) {
- dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config.");
- goto failed;
- }
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- ((struct local_info *)link->priv)->eth_dev =
- init_atmel_card(link->irq,
- link->resource[0]->start,
- did ? did->driver_info : ATMEL_FW_TYPE_NONE,
- &link->dev,
- card_present,
- link);
- if (!((struct local_info *)link->priv)->eth_dev)
- goto failed;
-
-
- return 0;
-
- failed:
- atmel_release(link);
- return -ENODEV;
-}
-
-static void atmel_release(struct pcmcia_device *link)
-{
- struct net_device *dev = ((struct local_info *)link->priv)->eth_dev;
-
- dev_dbg(&link->dev, "atmel_release\n");
-
- if (dev)
- stop_atmel_card(dev);
- ((struct local_info *)link->priv)->eth_dev = NULL;
-
- pcmcia_disable_device(link);
-}
-
-static int atmel_suspend(struct pcmcia_device *link)
-{
- struct local_info *local = link->priv;
-
- netif_device_detach(local->eth_dev);
-
- return 0;
-}
-
-static int atmel_resume(struct pcmcia_device *link)
-{
- struct local_info *local = link->priv;
-
- atmel_open(local->eth_dev);
- netif_device_attach(local->eth_dev);
-
- return 0;
-}
-
-/*====================================================================*/
-/* We use the driver_info field to store the correct firmware type for a card. */
-
-#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
- .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
- PCMCIA_DEV_ID_MATCH_CARD_ID, \
- .manf_id = (manf), \
- .card_id = (card), \
- .driver_info = (kernel_ulong_t)(info), }
-
-#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
- .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
- PCMCIA_DEV_ID_MATCH_PROD_ID2, \
- .prod_id = { (v1), (v2), NULL, NULL }, \
- .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
- .driver_info = (kernel_ulong_t)(info), }
-
-static const struct pcmcia_device_id atmel_ids[] = {
- PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
- PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
- PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
- PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
- PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
- PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
- PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
- PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
- PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
- PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
- PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
- PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
- PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
- PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
- PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
- PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
- PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
- PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
- PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
- PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
- PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
- PCMCIA_DEVICE_NULL
-};
-
-MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
-
-static struct pcmcia_driver atmel_driver = {
- .owner = THIS_MODULE,
- .name = "atmel_cs",
- .probe = atmel_probe,
- .remove = atmel_detach,
- .id_table = atmel_ids,
- .suspend = atmel_suspend,
- .resume = atmel_resume,
-};
-module_pcmcia_driver(atmel_driver);
-
-/*
- 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 Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- In addition:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/drivers/net/wireless/atmel/atmel_pci.c b/drivers/net/wireless/atmel/atmel_pci.c
deleted file mode 100644
index f428dc79d916..000000000000
--- a/drivers/net/wireless/atmel/atmel_pci.c
+++ /dev/null
@@ -1,65 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*** -*- linux-c -*- **********************************************************
-
- Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
-
- Copyright 2004 Simon Kelley.
-
-
-******************************************************************************/
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include "atmel.h"
-
-MODULE_AUTHOR("Simon Kelley");
-MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
-MODULE_LICENSE("GPL");
-
-static const struct pci_device_id card_ids[] = {
- { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, card_ids);
-
-static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *);
-static void atmel_pci_remove(struct pci_dev *);
-
-static struct pci_driver atmel_driver = {
- .name = "atmel",
- .id_table = card_ids,
- .probe = atmel_pci_probe,
- .remove = atmel_pci_remove,
-};
-
-
-static int atmel_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *pent)
-{
- struct net_device *dev;
-
- if (pci_enable_device(pdev))
- return -ENODEV;
-
- pci_set_master(pdev);
-
- dev = init_atmel_card(pdev->irq, pdev->resource[1].start,
- ATMEL_FW_TYPE_506,
- &pdev->dev, NULL, NULL);
- if (!dev) {
- pci_disable_device(pdev);
- return -ENODEV;
- }
-
- pci_set_drvdata(pdev, dev);
- return 0;
-}
-
-static void atmel_pci_remove(struct pci_dev *pdev)
-{
- stop_atmel_card(pci_get_drvdata(pdev));
-}
-
-module_pci_driver(atmel_driver);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c
index d55f3271d619..4f0c1e1a8e60 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/module.c
@@ -20,6 +20,7 @@ static void __exit brcmf_bca_exit(void)
brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_BCA, THIS_MODULE);
}
+MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Broadcom AP chipsets");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(BRCMFMAC);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 667462369a32..28d6a30cc010 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -866,7 +866,7 @@ struct wireless_dev *brcmf_apsta_add_vif(struct wiphy *wiphy, const char *name,
goto fail;
}
- strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+ strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name));
err = brcmf_net_attach(ifp, true);
if (err) {
bphy_err(drvr, "Registering netdevice failed\n");
@@ -3779,8 +3779,10 @@ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
if (req->channels[i] == chan)
break;
}
- if (i == req->n_channels)
- req->channels[req->n_channels++] = chan;
+ if (i == req->n_channels) {
+ req->n_channels++;
+ req->channels[i] = chan;
+ }
for (i = 0; i < req->n_ssids; i++) {
if (req->ssids[i].ssid_len == ssid_len &&
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
index a194b0e68eb5..b6d458e022fa 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
@@ -578,18 +578,16 @@ static int __init brcmf_common_pd_probe(struct platform_device *pdev)
return 0;
}
-static int brcmf_common_pd_remove(struct platform_device *pdev)
+static void brcmf_common_pd_remove(struct platform_device *pdev)
{
brcmf_dbg(INFO, "Enter\n");
if (brcmfmac_pdata->power_off)
brcmfmac_pdata->power_off();
-
- return 0;
}
static struct platform_driver brcmf_pd = {
- .remove = brcmf_common_pd_remove,
+ .remove_new = brcmf_common_pd_remove,
.driver = {
.name = BRCMFMAC_PDATA_NAME,
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c
index f82fbbe3ecef..90d06cda03a2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/module.c
@@ -20,6 +20,7 @@ static void __exit brcmf_cyw_exit(void)
brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_CYW, THIS_MODULE);
}
+MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Cypress/Infineon chipsets");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(BRCMFMAC);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
index d4492d02e4ea..6e0c90f4718b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
@@ -2334,7 +2334,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
goto fail;
}
- strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+ strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name));
ifp->ndev->name_assign_type = name_assign_type;
err = brcmf_net_attach(ifp, true);
if (err) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 80220685f5e4..d7fb88bb6ae1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -2707,7 +2707,6 @@ MODULE_DEVICE_TABLE(pci, brcmf_pcie_devid_table);
static struct pci_driver brcmf_pciedrvr = {
- .node = {},
.name = KBUILD_MODNAME,
.id_table = brcmf_pcie_devid_table,
.probe = brcmf_pcie_probe,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 2178675ae1a4..0ccf735316c2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1581,7 +1581,7 @@ static int brcmf_usb_reset_device(struct device *dev, void *notused)
void brcmf_usb_exit(void)
{
- struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+ struct device_driver *drv = &brcmf_usbdrvr.driver;
int ret;
brcmf_dbg(USB, "Enter\n");
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c
index 02918d434556..b66135e3cff4 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/module.c
@@ -20,6 +20,7 @@ static void __exit brcmf_wcc_exit(void)
brcmf_fwvid_unregister_vendor(BRCMF_FWVENDOR_WCC, THIS_MODULE);
}
+MODULE_DESCRIPTION("Broadcom FullMAC WLAN driver plugin for Broadcom mobility chipsets");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_IMPORT_NS(BRCMFMAC);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
index 5a6d9c86552a..f6962e558d7c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c
@@ -341,7 +341,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
/* store the country code for passing up as a regulatory hint */
wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len);
if (brcms_c_country_valid(ccode))
- strncpy(wlc->pub->srom_ccode, ccode, ccode_len);
+ memcpy(wlc->pub->srom_ccode, ccode, ccode_len);
/*
* If no custom world domain is found in the SROM, use the
@@ -354,10 +354,10 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
}
/* save default country for exiting 11d regulatory mode */
- strncpy(wlc->country_default, ccode, ccode_len);
+ memcpy(wlc->country_default, ccode, ccode_len);
/* initialize autocountry_default to driver default */
- strncpy(wlc->autocountry_default, ccode, ccode_len);
+ memcpy(wlc->autocountry_default, ccode, ccode_len);
brcms_c_set_country(wlc_cm, wlc_cm->world_regd);
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
index b7df576bb84d..3d5c1ef8f7f2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/dma.c
@@ -584,8 +584,7 @@ struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc,
rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase);
/* make a private copy of our callers name */
- strncpy(di->name, name, MAXNAMEL);
- di->name[MAXNAMEL - 1] = '\0';
+ strscpy(di->name, name, sizeof(di->name));
di->dmadev = core->dma_dev;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
index b3663c5ef382..34460b5815d0 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
@@ -5551,8 +5551,8 @@ int brcms_c_module_register(struct brcms_pub *pub,
/* find an empty entry and just add, no duplication check! */
for (i = 0; i < BRCMS_MAXMODULES; i++) {
if (wlc->modulecb[i].name[0] == '\0') {
- strncpy(wlc->modulecb[i].name, name,
- sizeof(wlc->modulecb[i].name) - 1);
+ strscpy(wlc->modulecb[i].name, name,
+ sizeof(wlc->modulecb[i].name));
wlc->modulecb[i].hdl = hdl;
wlc->modulecb[i].down_fn = d_fn;
return 0;
diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig
deleted file mode 100644
index b40ee25aca99..000000000000
--- a/drivers/net/wireless/cisco/Kconfig
+++ /dev/null
@@ -1,59 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config WLAN_VENDOR_CISCO
- bool "Cisco devices"
- default y
- help
- If you have a wireless 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 these cards. If you say Y, you will be asked for
- your specific card in the following questions.
-
-if WLAN_VENDOR_CISCO
-
-config AIRO
- tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
- depends on CFG80211 && (PCI || BROKEN)
- select WIRELESS_EXT
- select CRYPTO
- select CRYPTO_SKCIPHER
- select WEXT_SPY
- select WEXT_PRIV
- help
- This is the standard Linux driver to support Cisco/Aironet ISA and
- PCI 802.11 wireless cards.
- It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
- - with or without encryption) as well as card before the Cisco
- acquisition (Aironet 4500, Aironet 4800, Aironet 4800B).
-
- This driver support both the standard Linux Wireless Extensions
- and Cisco proprietary API, so both the Linux Wireless Tools and the
- Cisco Linux utilities can be used to configure the card.
-
- The driver can be compiled as a module and will be named "airo".
-
-config AIRO_CS
- tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
- depends on CFG80211 && PCMCIA
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select CRYPTO
- select CRYPTO_AES
- select CRYPTO_CTR
- help
- This is the standard Linux driver to support Cisco/Aironet PCMCIA
- 802.11 wireless cards. This driver is the same as the Aironet
- driver part of the Linux Pcmcia package.
- It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
- - with or without encryption) as well as card before the Cisco
- acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also
- supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom
- 802.11b cards.
-
- This driver support both the standard Linux Wireless Extensions
- and Cisco proprietary API, so both the Linux Wireless Tools and the
- Cisco Linux utilities can be used to configure the card.
-
-endif # WLAN_VENDOR_CISCO
diff --git a/drivers/net/wireless/cisco/Makefile b/drivers/net/wireless/cisco/Makefile
deleted file mode 100644
index 506a19ce375f..000000000000
--- a/drivers/net/wireless/cisco/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_AIRO) += airo.o
-obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
deleted file mode 100644
index dbd13f7aa3e6..000000000000
--- a/drivers/net/wireless/cisco/airo.c
+++ /dev/null
@@ -1,8288 +0,0 @@
-/*======================================================================
-
- Aironet driver for 4500 and 4800 series cards
-
- This code is released under both the GPL version 2 and BSD licenses.
- Either license may be used. The respective licenses are found at
- the end of this file.
-
- This code was developed by Benjamin Reed <breed@users.sourceforge.net>
- including portions of which come from the Aironet PC4500
- Developer's Reference Manual and used with permission. Copyright
- (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use
- code in the Developer's manual was granted for this driver by
- Aironet. Major code contributions were received from Javier Achirica
- <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>.
- Code was also integrated from the Cisco Aironet driver for Linux.
- Support for MPI350 cards was added by Fabrice Bellet
- <fabrice@bellet.info>.
-
-======================================================================*/
-
-#include <linux/err.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/bitops.h>
-#include <linux/scatterlist.h>
-#include <linux/crypto.h>
-#include <linux/io.h>
-#include <asm/unaligned.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/uaccess.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-
-#include <crypto/aes.h>
-#include <crypto/skcipher.h>
-
-#include <net/cfg80211.h>
-#include <net/iw_handler.h>
-
-#include "airo.h"
-
-#define DRV_NAME "airo"
-
-#ifdef CONFIG_PCI
-static const struct pci_device_id card_ids[] = {
- { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
- { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, card_ids);
-
-static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
-static void airo_pci_remove(struct pci_dev *);
-static int __maybe_unused airo_pci_suspend(struct device *dev);
-static int __maybe_unused airo_pci_resume(struct device *dev);
-
-static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops,
- airo_pci_suspend,
- airo_pci_resume);
-
-static struct pci_driver airo_driver = {
- .name = DRV_NAME,
- .id_table = card_ids,
- .probe = airo_pci_probe,
- .remove = airo_pci_remove,
- .driver.pm = &airo_pci_pm_ops,
-};
-#endif /* CONFIG_PCI */
-
-/* Include Wireless Extension definition and check version - Jean II */
-#include <linux/wireless.h>
-#define WIRELESS_SPY /* enable iwspy support */
-
-#define CISCO_EXT /* enable Cisco extensions */
-#ifdef CISCO_EXT
-#include <linux/delay.h>
-#endif
-
-/* Hack to do some power saving */
-#define POWER_ON_DOWN
-
-/* As you can see this list is HUGH!
- I really don't know what a lot of these counts are about, but they
- are all here for completeness. If the IGNLABEL macro is put in
- infront of the label, that statistic will not be included in the list
- of statistics in the /proc filesystem */
-
-#define IGNLABEL(comment) NULL
-static const char *statsLabels[] = {
- "RxOverrun",
- IGNLABEL("RxPlcpCrcErr"),
- IGNLABEL("RxPlcpFormatErr"),
- IGNLABEL("RxPlcpLengthErr"),
- "RxMacCrcErr",
- "RxMacCrcOk",
- "RxWepErr",
- "RxWepOk",
- "RetryLong",
- "RetryShort",
- "MaxRetries",
- "NoAck",
- "NoCts",
- "RxAck",
- "RxCts",
- "TxAck",
- "TxRts",
- "TxCts",
- "TxMc",
- "TxBc",
- "TxUcFrags",
- "TxUcPackets",
- "TxBeacon",
- "RxBeacon",
- "TxSinColl",
- "TxMulColl",
- "DefersNo",
- "DefersProt",
- "DefersEngy",
- "DupFram",
- "RxFragDisc",
- "TxAged",
- "RxAged",
- "LostSync-MaxRetry",
- "LostSync-MissedBeacons",
- "LostSync-ArlExceeded",
- "LostSync-Deauth",
- "LostSync-Disassoced",
- "LostSync-TsfTiming",
- "HostTxMc",
- "HostTxBc",
- "HostTxUc",
- "HostTxFail",
- "HostRxMc",
- "HostRxBc",
- "HostRxUc",
- "HostRxDiscard",
- IGNLABEL("HmacTxMc"),
- IGNLABEL("HmacTxBc"),
- IGNLABEL("HmacTxUc"),
- IGNLABEL("HmacTxFail"),
- IGNLABEL("HmacRxMc"),
- IGNLABEL("HmacRxBc"),
- IGNLABEL("HmacRxUc"),
- IGNLABEL("HmacRxDiscard"),
- IGNLABEL("HmacRxAccepted"),
- "SsidMismatch",
- "ApMismatch",
- "RatesMismatch",
- "AuthReject",
- "AuthTimeout",
- "AssocReject",
- "AssocTimeout",
- IGNLABEL("ReasonOutsideTable"),
- IGNLABEL("ReasonStatus1"),
- IGNLABEL("ReasonStatus2"),
- IGNLABEL("ReasonStatus3"),
- IGNLABEL("ReasonStatus4"),
- IGNLABEL("ReasonStatus5"),
- IGNLABEL("ReasonStatus6"),
- IGNLABEL("ReasonStatus7"),
- IGNLABEL("ReasonStatus8"),
- IGNLABEL("ReasonStatus9"),
- IGNLABEL("ReasonStatus10"),
- IGNLABEL("ReasonStatus11"),
- IGNLABEL("ReasonStatus12"),
- IGNLABEL("ReasonStatus13"),
- IGNLABEL("ReasonStatus14"),
- IGNLABEL("ReasonStatus15"),
- IGNLABEL("ReasonStatus16"),
- IGNLABEL("ReasonStatus17"),
- IGNLABEL("ReasonStatus18"),
- IGNLABEL("ReasonStatus19"),
- "RxMan",
- "TxMan",
- "RxRefresh",
- "TxRefresh",
- "RxPoll",
- "TxPoll",
- "HostRetries",
- "LostSync-HostReq",
- "HostTxBytes",
- "HostRxBytes",
- "ElapsedUsec",
- "ElapsedSec",
- "LostSyncBetterAP",
- "PrivacyMismatch",
- "Jammed",
- "DiscRxNotWepped",
- "PhyEleMismatch",
- (char*)-1 };
-#ifndef RUN_AT
-#define RUN_AT(x) (jiffies+(x))
-#endif
-
-
-/* These variables are for insmod, since it seems that the rates
- can only be set in setup_card. Rates should be a comma separated
- (no spaces) list of rates (up to 8). */
-
-static int rates[8];
-static char *ssids[3];
-
-static int io[4];
-static int irq[4];
-
-static
-int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
- 0 means no limit. For old cards this was 4 */
-
-static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
-static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
- the bap, needed on some older cards and buses. */
-static int adhoc;
-
-static int probe = 1;
-
-static kuid_t proc_kuid;
-static int proc_uid /* = 0 */;
-
-static kgid_t proc_kgid;
-static int proc_gid /* = 0 */;
-
-static int airo_perm = 0555;
-
-static int proc_perm = 0644;
-
-MODULE_AUTHOR("Benjamin Reed");
-MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. "
- "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs.");
-MODULE_LICENSE("Dual BSD/GPL");
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_array(rates, int, NULL, 0);
-module_param_array(ssids, charp, NULL, 0);
-module_param(auto_wep, int, 0);
-MODULE_PARM_DESC(auto_wep,
- "If non-zero, the driver will keep looping through the authentication options until an association is made. "
- "The value of auto_wep is number of the wep keys to check. "
- "A value of 2 will try using the key at index 0 and index 1.");
-module_param(aux_bap, int, 0);
-MODULE_PARM_DESC(aux_bap,
- "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. "
- "Before switching it checks that the switch is needed.");
-module_param(maxencrypt, int, 0);
-MODULE_PARM_DESC(maxencrypt,
- "The maximum speed that the card can do encryption. "
- "Units are in 512kbs. "
- "Zero (default) means there is no limit. "
- "Older cards used to be limited to 2mbs (4).");
-module_param(adhoc, int, 0);
-MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
-module_param(probe, int, 0);
-MODULE_PARM_DESC(probe, "If zero, the driver won't start the card.");
-
-module_param(proc_uid, int, 0);
-MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to.");
-module_param(proc_gid, int, 0);
-MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to.");
-module_param(airo_perm, int, 0);
-MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet.");
-module_param(proc_perm, int, 0);
-MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
-
-/* This is a kind of sloppy hack to get this information to OUT4500 and
- IN4500. I would be extremely interested in the situation where this
- doesn't work though!!! */
-static int do8bitIO /* = 0 */;
-
-/* Return codes */
-#define SUCCESS 0
-#define ERROR -1
-#define NO_PACKET -2
-
-/* Commands */
-#define NOP2 0x0000
-#define MAC_ENABLE 0x0001
-#define MAC_DISABLE 0x0002
-#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
-#define CMD_SOFTRESET 0x0004
-#define HOSTSLEEP 0x0005
-#define CMD_MAGIC_PKT 0x0006
-#define CMD_SETWAKEMASK 0x0007
-#define CMD_READCFG 0x0008
-#define CMD_SETMODE 0x0009
-#define CMD_ALLOCATETX 0x000a
-#define CMD_TRANSMIT 0x000b
-#define CMD_DEALLOCATETX 0x000c
-#define NOP 0x0010
-#define CMD_WORKAROUND 0x0011
-#define CMD_ALLOCATEAUX 0x0020
-#define CMD_ACCESS 0x0021
-#define CMD_PCIBAP 0x0022
-#define CMD_PCIAUX 0x0023
-#define CMD_ALLOCBUF 0x0028
-#define CMD_GETTLV 0x0029
-#define CMD_PUTTLV 0x002a
-#define CMD_DELTLV 0x002b
-#define CMD_FINDNEXTTLV 0x002c
-#define CMD_PSPNODES 0x0030
-#define CMD_SETCW 0x0031
-#define CMD_SETPCF 0x0032
-#define CMD_SETPHYREG 0x003e
-#define CMD_TXTEST 0x003f
-#define MAC_ENABLETX 0x0101
-#define CMD_LISTBSS 0x0103
-#define CMD_SAVECFG 0x0108
-#define CMD_ENABLEAUX 0x0111
-#define CMD_WRITERID 0x0121
-#define CMD_USEPSPNODES 0x0130
-#define MAC_ENABLERX 0x0201
-
-/* Command errors */
-#define ERROR_QUALIF 0x00
-#define ERROR_ILLCMD 0x01
-#define ERROR_ILLFMT 0x02
-#define ERROR_INVFID 0x03
-#define ERROR_INVRID 0x04
-#define ERROR_LARGE 0x05
-#define ERROR_NDISABL 0x06
-#define ERROR_ALLOCBSY 0x07
-#define ERROR_NORD 0x0B
-#define ERROR_NOWR 0x0C
-#define ERROR_INVFIDTX 0x0D
-#define ERROR_TESTACT 0x0E
-#define ERROR_TAGNFND 0x12
-#define ERROR_DECODE 0x20
-#define ERROR_DESCUNAV 0x21
-#define ERROR_BADLEN 0x22
-#define ERROR_MODE 0x80
-#define ERROR_HOP 0x81
-#define ERROR_BINTER 0x82
-#define ERROR_RXMODE 0x83
-#define ERROR_MACADDR 0x84
-#define ERROR_RATES 0x85
-#define ERROR_ORDER 0x86
-#define ERROR_SCAN 0x87
-#define ERROR_AUTH 0x88
-#define ERROR_PSMODE 0x89
-#define ERROR_RTYPE 0x8A
-#define ERROR_DIVER 0x8B
-#define ERROR_SSID 0x8C
-#define ERROR_APLIST 0x8D
-#define ERROR_AUTOWAKE 0x8E
-#define ERROR_LEAP 0x8F
-
-/* Registers */
-#define COMMAND 0x00
-#define PARAM0 0x02
-#define PARAM1 0x04
-#define PARAM2 0x06
-#define STATUS 0x08
-#define RESP0 0x0a
-#define RESP1 0x0c
-#define RESP2 0x0e
-#define LINKSTAT 0x10
-#define SELECT0 0x18
-#define OFFSET0 0x1c
-#define RXFID 0x20
-#define TXALLOCFID 0x22
-#define TXCOMPLFID 0x24
-#define DATA0 0x36
-#define EVSTAT 0x30
-#define EVINTEN 0x32
-#define EVACK 0x34
-#define SWS0 0x28
-#define SWS1 0x2a
-#define SWS2 0x2c
-#define SWS3 0x2e
-#define AUXPAGE 0x3A
-#define AUXOFF 0x3C
-#define AUXDATA 0x3E
-
-#define FID_TX 1
-#define FID_RX 2
-/* Offset into aux memory for descriptors */
-#define AUX_OFFSET 0x800
-/* Size of allocated packets */
-#define PKTSIZE 1840
-#define RIDSIZE 2048
-/* Size of the transmit queue */
-#define MAXTXQ 64
-
-/* BAP selectors */
-#define BAP0 0 /* Used for receiving packets */
-#define BAP1 2 /* Used for xmiting packets and working with RIDS */
-
-/* Flags */
-#define COMMAND_BUSY 0x8000
-
-#define BAP_BUSY 0x8000
-#define BAP_ERR 0x4000
-#define BAP_DONE 0x2000
-
-#define PROMISC 0xffff
-#define NOPROMISC 0x0000
-
-#define EV_CMD 0x10
-#define EV_CLEARCOMMANDBUSY 0x4000
-#define EV_RX 0x01
-#define EV_TX 0x02
-#define EV_TXEXC 0x04
-#define EV_ALLOC 0x08
-#define EV_LINK 0x80
-#define EV_AWAKE 0x100
-#define EV_TXCPY 0x400
-#define EV_UNKNOWN 0x800
-#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
-#define EV_AWAKEN 0x2000
-#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC)
-
-#ifdef CHECK_UNKNOWN_INTS
-#define IGNORE_INTS (EV_CMD | EV_UNKNOWN)
-#else
-#define IGNORE_INTS (~STATUS_INTS)
-#endif
-
-/* RID TYPES */
-#define RID_RW 0x20
-
-/* The RIDs */
-#define RID_CAPABILITIES 0xFF00
-#define RID_APINFO 0xFF01
-#define RID_RADIOINFO 0xFF02
-#define RID_UNKNOWN3 0xFF03
-#define RID_RSSI 0xFF04
-#define RID_CONFIG 0xFF10
-#define RID_SSID 0xFF11
-#define RID_APLIST 0xFF12
-#define RID_DRVNAME 0xFF13
-#define RID_ETHERENCAP 0xFF14
-#define RID_WEP_TEMP 0xFF15
-#define RID_WEP_PERM 0xFF16
-#define RID_MODULATION 0xFF17
-#define RID_OPTIONS 0xFF18
-#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
-#define RID_FACTORYCONFIG 0xFF21
-#define RID_UNKNOWN22 0xFF22
-#define RID_LEAPUSERNAME 0xFF23
-#define RID_LEAPPASSWORD 0xFF24
-#define RID_STATUS 0xFF50
-#define RID_BEACON_HST 0xFF51
-#define RID_BUSY_HST 0xFF52
-#define RID_RETRIES_HST 0xFF53
-#define RID_UNKNOWN54 0xFF54
-#define RID_UNKNOWN55 0xFF55
-#define RID_UNKNOWN56 0xFF56
-#define RID_MIC 0xFF57
-#define RID_STATS16 0xFF60
-#define RID_STATS16DELTA 0xFF61
-#define RID_STATS16DELTACLEAR 0xFF62
-#define RID_STATS 0xFF68
-#define RID_STATSDELTA 0xFF69
-#define RID_STATSDELTACLEAR 0xFF6A
-#define RID_ECHOTEST_RID 0xFF70
-#define RID_ECHOTEST_RESULTS 0xFF71
-#define RID_BSSLISTFIRST 0xFF72
-#define RID_BSSLISTNEXT 0xFF73
-#define RID_WPA_BSSLISTFIRST 0xFF74
-#define RID_WPA_BSSLISTNEXT 0xFF75
-
-typedef struct {
- u16 cmd;
- u16 parm0;
- u16 parm1;
- u16 parm2;
-} Cmd;
-
-typedef struct {
- u16 status;
- u16 rsp0;
- u16 rsp1;
- u16 rsp2;
-} Resp;
-
-/*
- * Rids and endian-ness: The Rids will always be in cpu endian, since
- * this all the patches from the big-endian guys end up doing that.
- * so all rid access should use the read/writeXXXRid routines.
- */
-
-/* This structure came from an email sent to me from an engineer at
- aironet for inclusion into this driver */
-typedef struct WepKeyRid WepKeyRid;
-struct WepKeyRid {
- __le16 len;
- __le16 kindex;
- u8 mac[ETH_ALEN];
- __le16 klen;
- u8 key[16];
-} __packed;
-
-/* These structures are from the Aironet's PC4500 Developers Manual */
-typedef struct Ssid Ssid;
-struct Ssid {
- __le16 len;
- u8 ssid[32];
-} __packed;
-
-typedef struct SsidRid SsidRid;
-struct SsidRid {
- __le16 len;
- Ssid ssids[3];
-} __packed;
-
-typedef struct ModulationRid ModulationRid;
-struct ModulationRid {
- __le16 len;
- __le16 modulation;
-#define MOD_DEFAULT cpu_to_le16(0)
-#define MOD_CCK cpu_to_le16(1)
-#define MOD_MOK cpu_to_le16(2)
-} __packed;
-
-typedef struct ConfigRid ConfigRid;
-struct ConfigRid {
- __le16 len; /* sizeof(ConfigRid) */
- __le16 opmode; /* operating mode */
-#define MODE_STA_IBSS cpu_to_le16(0)
-#define MODE_STA_ESS cpu_to_le16(1)
-#define MODE_AP cpu_to_le16(2)
-#define MODE_AP_RPTR cpu_to_le16(3)
-#define MODE_CFG_MASK cpu_to_le16(0xff)
-#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */
-#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */
-#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extensions */
-#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */
-#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */
-#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */
-#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */
-#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */
-#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */
- __le16 rmode; /* receive mode */
-#define RXMODE_BC_MC_ADDR cpu_to_le16(0)
-#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */
-#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */
-#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */
-#define RXMODE_RFMON_ANYBSS cpu_to_le16(4)
-#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */
-#define RXMODE_MASK cpu_to_le16(255)
-#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */
-#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER)
-#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */
- __le16 fragThresh;
- __le16 rtsThres;
- u8 macAddr[ETH_ALEN];
- u8 rates[8];
- __le16 shortRetryLimit;
- __le16 longRetryLimit;
- __le16 txLifetime; /* in kusec */
- __le16 rxLifetime; /* in kusec */
- __le16 stationary;
- __le16 ordering;
- __le16 u16deviceType; /* for overriding device type */
- __le16 cfpRate;
- __le16 cfpDuration;
- __le16 _reserved1[3];
- /*---------- Scanning/Associating ----------*/
- __le16 scanMode;
-#define SCANMODE_ACTIVE cpu_to_le16(0)
-#define SCANMODE_PASSIVE cpu_to_le16(1)
-#define SCANMODE_AIROSCAN cpu_to_le16(2)
- __le16 probeDelay; /* in kusec */
- __le16 probeEnergyTimeout; /* in kusec */
- __le16 probeResponseTimeout;
- __le16 beaconListenTimeout;
- __le16 joinNetTimeout;
- __le16 authTimeout;
- __le16 authType;
-#define AUTH_OPEN cpu_to_le16(0x1)
-#define AUTH_ENCRYPT cpu_to_le16(0x101)
-#define AUTH_SHAREDKEY cpu_to_le16(0x102)
-#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200)
- __le16 associationTimeout;
- __le16 specifiedApTimeout;
- __le16 offlineScanInterval;
- __le16 offlineScanDuration;
- __le16 linkLossDelay;
- __le16 maxBeaconLostTime;
- __le16 refreshInterval;
-#define DISABLE_REFRESH cpu_to_le16(0xFFFF)
- __le16 _reserved1a[1];
- /*---------- Power save operation ----------*/
- __le16 powerSaveMode;
-#define POWERSAVE_CAM cpu_to_le16(0)
-#define POWERSAVE_PSP cpu_to_le16(1)
-#define POWERSAVE_PSPCAM cpu_to_le16(2)
- __le16 sleepForDtims;
- __le16 listenInterval;
- __le16 fastListenInterval;
- __le16 listenDecay;
- __le16 fastListenDelay;
- __le16 _reserved2[2];
- /*---------- Ap/Ibss config items ----------*/
- __le16 beaconPeriod;
- __le16 atimDuration;
- __le16 hopPeriod;
- __le16 channelSet;
- __le16 channel;
- __le16 dtimPeriod;
- __le16 bridgeDistance;
- __le16 radioID;
- /*---------- Radio configuration ----------*/
- __le16 radioType;
-#define RADIOTYPE_DEFAULT cpu_to_le16(0)
-#define RADIOTYPE_802_11 cpu_to_le16(1)
-#define RADIOTYPE_LEGACY cpu_to_le16(2)
- u8 rxDiversity;
- u8 txDiversity;
- __le16 txPower;
-#define TXPOWER_DEFAULT 0
- __le16 rssiThreshold;
-#define RSSI_DEFAULT 0
- __le16 modulation;
-#define PREAMBLE_AUTO cpu_to_le16(0)
-#define PREAMBLE_LONG cpu_to_le16(1)
-#define PREAMBLE_SHORT cpu_to_le16(2)
- __le16 preamble;
- __le16 homeProduct;
- __le16 radioSpecific;
- /*---------- Aironet Extensions ----------*/
- u8 nodeName[16];
- __le16 arlThreshold;
- __le16 arlDecay;
- __le16 arlDelay;
- __le16 _reserved4[1];
- /*---------- Aironet Extensions ----------*/
- u8 magicAction;
-#define MAGIC_ACTION_STSCHG 1
-#define MAGIC_ACTION_RESUME 2
-#define MAGIC_IGNORE_MCAST (1<<8)
-#define MAGIC_IGNORE_BCAST (1<<9)
-#define MAGIC_SWITCH_TO_PSP (0<<10)
-#define MAGIC_STAY_IN_CAM (1<<10)
- u8 magicControl;
- __le16 autoWake;
-} __packed;
-
-typedef struct StatusRid StatusRid;
-struct StatusRid {
- __le16 len;
- u8 mac[ETH_ALEN];
- __le16 mode;
- __le16 errorCode;
- __le16 sigQuality;
- __le16 SSIDlen;
- char SSID[32];
- char apName[16];
- u8 bssid[4][ETH_ALEN];
- __le16 beaconPeriod;
- __le16 dimPeriod;
- __le16 atimDuration;
- __le16 hopPeriod;
- __le16 channelSet;
- __le16 channel;
- __le16 hopsToBackbone;
- __le16 apTotalLoad;
- __le16 generatedLoad;
- __le16 accumulatedArl;
- __le16 signalQuality;
- __le16 currentXmitRate;
- __le16 apDevExtensions;
- __le16 normalizedSignalStrength;
- __le16 shortPreamble;
- u8 apIP[4];
- u8 noisePercent; /* Noise percent in last second */
- u8 noisedBm; /* Noise dBm in last second */
- u8 noiseAvePercent; /* Noise percent in last minute */
- u8 noiseAvedBm; /* Noise dBm in last minute */
- u8 noiseMaxPercent; /* Highest noise percent in last minute */
- u8 noiseMaxdBm; /* Highest noise dbm in last minute */
- __le16 load;
- u8 carrier[4];
- __le16 assocStatus;
-#define STAT_NOPACKETS 0
-#define STAT_NOCARRIERSET 10
-#define STAT_GOTCARRIERSET 11
-#define STAT_WRONGSSID 20
-#define STAT_BADCHANNEL 25
-#define STAT_BADBITRATES 30
-#define STAT_BADPRIVACY 35
-#define STAT_APFOUND 40
-#define STAT_APREJECTED 50
-#define STAT_AUTHENTICATING 60
-#define STAT_DEAUTHENTICATED 61
-#define STAT_AUTHTIMEOUT 62
-#define STAT_ASSOCIATING 70
-#define STAT_DEASSOCIATED 71
-#define STAT_ASSOCTIMEOUT 72
-#define STAT_NOTAIROAP 73
-#define STAT_ASSOCIATED 80
-#define STAT_LEAPING 90
-#define STAT_LEAPFAILED 91
-#define STAT_LEAPTIMEDOUT 92
-#define STAT_LEAPCOMPLETE 93
-} __packed;
-
-typedef struct StatsRid StatsRid;
-struct StatsRid {
- __le16 len;
- __le16 spacer;
- __le32 vals[100];
-} __packed;
-
-typedef struct APListRid APListRid;
-struct APListRid {
- __le16 len;
- u8 ap[4][ETH_ALEN];
-} __packed;
-
-typedef struct CapabilityRid CapabilityRid;
-struct CapabilityRid {
- __le16 len;
- char oui[3];
- char zero;
- __le16 prodNum;
- char manName[32];
- char prodName[16];
- char prodVer[8];
- char factoryAddr[ETH_ALEN];
- char aironetAddr[ETH_ALEN];
- __le16 radioType;
- __le16 country;
- char callid[ETH_ALEN];
- char supportedRates[8];
- char rxDiversity;
- char txDiversity;
- __le16 txPowerLevels[8];
- __le16 hardVer;
- __le16 hardCap;
- __le16 tempRange;
- __le16 softVer;
- __le16 softSubVer;
- __le16 interfaceVer;
- __le16 softCap;
- __le16 bootBlockVer;
- __le16 requiredHard;
- __le16 extSoftCap;
-} __packed;
-
-/* Only present on firmware >= 5.30.17 */
-typedef struct BSSListRidExtra BSSListRidExtra;
-struct BSSListRidExtra {
- __le16 unknown[4];
- u8 fixed[12]; /* WLAN management frame */
- u8 iep[624];
-} __packed;
-
-typedef struct BSSListRid BSSListRid;
-struct BSSListRid {
- __le16 len;
- __le16 index; /* First is 0 and 0xffff means end of list */
-#define RADIO_FH 1 /* Frequency hopping radio type */
-#define RADIO_DS 2 /* Direct sequence radio type */
-#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
- __le16 radioType;
- u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
- u8 zero;
- u8 ssidLen;
- u8 ssid[32];
- __le16 dBm;
-#define CAP_ESS cpu_to_le16(1<<0)
-#define CAP_IBSS cpu_to_le16(1<<1)
-#define CAP_PRIVACY cpu_to_le16(1<<4)
-#define CAP_SHORTHDR cpu_to_le16(1<<5)
- __le16 cap;
- __le16 beaconInterval;
- u8 rates[8]; /* Same as rates for config rid */
- struct { /* For frequency hopping only */
- __le16 dwell;
- u8 hopSet;
- u8 hopPattern;
- u8 hopIndex;
- u8 fill;
- } fh;
- __le16 dsChannel;
- __le16 atimWindow;
-
- /* Only present on firmware >= 5.30.17 */
- BSSListRidExtra extra;
-} __packed;
-
-typedef struct {
- BSSListRid bss;
- struct list_head list;
-} BSSListElement;
-
-typedef struct tdsRssiEntry tdsRssiEntry;
-struct tdsRssiEntry {
- u8 rssipct;
- u8 rssidBm;
-} __packed;
-
-typedef struct tdsRssiRid tdsRssiRid;
-struct tdsRssiRid {
- u16 len;
- tdsRssiEntry x[256];
-} __packed;
-
-typedef struct MICRid MICRid;
-struct MICRid {
- __le16 len;
- __le16 state;
- __le16 multicastValid;
- u8 multicast[16];
- __le16 unicastValid;
- u8 unicast[16];
-} __packed;
-
-typedef struct MICBuffer MICBuffer;
-struct MICBuffer {
- __be16 typelen;
-
- union {
- u8 snap[8];
- struct {
- u8 dsap;
- u8 ssap;
- u8 control;
- u8 orgcode[3];
- u8 fieldtype[2];
- } llc;
- } u;
- __be32 mic;
- __be32 seq;
-} __packed;
-
-typedef struct {
- u8 da[ETH_ALEN];
- u8 sa[ETH_ALEN];
-} etherHead;
-
-#define TXCTL_TXOK (1<<1) /* report if tx is ok */
-#define TXCTL_TXEX (1<<2) /* report if tx fails */
-#define TXCTL_802_3 (0<<3) /* 802.3 packet */
-#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */
-#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */
-#define TXCTL_LLC (1<<4) /* payload is llc */
-#define TXCTL_RELEASE (0<<5) /* release after completion */
-#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */
-
-#define BUSY_FID 0x10000
-
-#ifdef CISCO_EXT
-#define AIROMAGIC 0xa55a
-/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */
-#ifdef SIOCIWFIRSTPRIV
-#ifdef SIOCDEVPRIVATE
-#define AIROOLDIOCTL SIOCDEVPRIVATE
-#define AIROOLDIDIFC AIROOLDIOCTL + 1
-#endif /* SIOCDEVPRIVATE */
-#else /* SIOCIWFIRSTPRIV */
-#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably
- * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root
- * only and don't return the modified struct ifreq to the application which
- * is usually a problem. - Jean II */
-#define AIROIOCTL SIOCIWFIRSTPRIV
-#define AIROIDIFC AIROIOCTL + 1
-
-/* Ioctl constants to be used in airo_ioctl.command */
-
-#define AIROGCAP 0 // Capability rid
-#define AIROGCFG 1 // USED A LOT
-#define AIROGSLIST 2 // System ID list
-#define AIROGVLIST 3 // List of specified AP's
-#define AIROGDRVNAM 4 // NOTUSED
-#define AIROGEHTENC 5 // NOTUSED
-#define AIROGWEPKTMP 6
-#define AIROGWEPKNV 7
-#define AIROGSTAT 8
-#define AIROGSTATSC32 9
-#define AIROGSTATSD32 10
-#define AIROGMICRID 11
-#define AIROGMICSTATS 12
-#define AIROGFLAGS 13
-#define AIROGID 14
-#define AIRORRID 15
-#define AIRORSWVERSION 17
-
-/* Leave gap of 40 commands after AIROGSTATSD32 for future */
-
-#define AIROPCAP AIROGSTATSD32 + 40
-#define AIROPVLIST AIROPCAP + 1
-#define AIROPSLIST AIROPVLIST + 1
-#define AIROPCFG AIROPSLIST + 1
-#define AIROPSIDS AIROPCFG + 1
-#define AIROPAPLIST AIROPSIDS + 1
-#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */
-#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */
-#define AIROPSTCLR AIROPMACOFF + 1
-#define AIROPWEPKEY AIROPSTCLR + 1
-#define AIROPWEPKEYNV AIROPWEPKEY + 1
-#define AIROPLEAPPWD AIROPWEPKEYNV + 1
-#define AIROPLEAPUSR AIROPLEAPPWD + 1
-
-/* Flash codes */
-
-#define AIROFLSHRST AIROPWEPKEYNV + 40
-#define AIROFLSHGCHR AIROFLSHRST + 1
-#define AIROFLSHSTFL AIROFLSHGCHR + 1
-#define AIROFLSHPCHR AIROFLSHSTFL + 1
-#define AIROFLPUTBUF AIROFLSHPCHR + 1
-#define AIRORESTART AIROFLPUTBUF + 1
-
-#define FLASHSIZE 32768
-#define AUXMEMSIZE (256 * 1024)
-
-typedef struct aironet_ioctl {
- unsigned short command; // What to do
- unsigned short len; // Len of data
- unsigned short ridnum; // rid number
- unsigned char __user *data; // d-data
-} aironet_ioctl;
-
-static const char swversion[] = "2.1";
-#endif /* CISCO_EXT */
-
-#define NUM_MODULES 2
-#define MIC_MSGLEN_MAX 2400
-#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
-#define AIRO_DEF_MTU 2312
-
-typedef struct {
- u32 size; // size
- u8 enabled; // MIC enabled or not
- u32 rxSuccess; // successful packets received
- u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison
- u32 rxNotMICed; // pkts dropped due to not being MIC'd
- u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed
- u32 rxWrongSequence; // pkts dropped due to sequence number violation
- u32 reserve[32];
-} mic_statistics;
-
-typedef struct {
- __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
- u64 accum; // accumulated mic, reduced to u32 in final()
- int position; // current position (byte offset) in message
- union {
- u8 d8[4];
- __be32 d32;
- } part; // saves partial message word across update() calls
-} emmh32_context;
-
-typedef struct {
- emmh32_context seed; // Context - the seed
- u32 rx; // Received sequence number
- u32 tx; // Tx sequence number
- u32 window; // Start of window
- u8 valid; // Flag to say if context is valid or not
- u8 key[16];
-} miccntx;
-
-typedef struct {
- miccntx mCtx; // Multicast context
- miccntx uCtx; // Unicast context
-} mic_module;
-
-typedef struct {
- unsigned int rid: 16;
- unsigned int len: 15;
- unsigned int valid: 1;
- dma_addr_t host_addr;
-} Rid;
-
-typedef struct {
- unsigned int offset: 15;
- unsigned int eoc: 1;
- unsigned int len: 15;
- unsigned int valid: 1;
- dma_addr_t host_addr;
-} TxFid;
-
-struct rx_hdr {
- __le16 status, len;
- u8 rssi[2];
- u8 rate;
- u8 freq;
- __le16 tmp[4];
-} __packed;
-
-typedef struct {
- unsigned int ctl: 15;
- unsigned int rdy: 1;
- unsigned int len: 15;
- unsigned int valid: 1;
- dma_addr_t host_addr;
-} RxFid;
-
-/*
- * Host receive descriptor
- */
-typedef struct {
- unsigned char __iomem *card_ram_off; /* offset into card memory of the
- desc */
- RxFid rx_desc; /* card receive descriptor */
- char *virtual_host_addr; /* virtual address of host receive
- buffer */
- int pending;
-} HostRxDesc;
-
-/*
- * Host transmit descriptor
- */
-typedef struct {
- unsigned char __iomem *card_ram_off; /* offset into card memory of the
- desc */
- TxFid tx_desc; /* card transmit descriptor */
- char *virtual_host_addr; /* virtual address of host receive
- buffer */
- int pending;
-} HostTxDesc;
-
-/*
- * Host RID descriptor
- */
-typedef struct {
- unsigned char __iomem *card_ram_off; /* offset into card memory of the
- descriptor */
- Rid rid_desc; /* card RID descriptor */
- char *virtual_host_addr; /* virtual address of host receive
- buffer */
-} HostRidDesc;
-
-typedef struct {
- u16 sw0;
- u16 sw1;
- u16 status;
- u16 len;
-#define HOST_SET (1 << 0)
-#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */
-#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */
-#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */
-#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */
-#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */
-#define HOST_CLR_AID (1 << 7) /* clear AID failure */
-#define HOST_RTS (1 << 9) /* Force RTS use */
-#define HOST_SHORT (1 << 10) /* Do short preamble */
- u16 ctl;
- u16 aid;
- u16 retries;
- u16 fill;
-} TxCtlHdr;
-
-typedef struct {
- u16 ctl;
- u16 duration;
- char addr1[6];
- char addr2[6];
- char addr3[6];
- u16 seq;
- char addr4[6];
-} WifiHdr;
-
-
-typedef struct {
- TxCtlHdr ctlhdr;
- u16 fill1;
- u16 fill2;
- WifiHdr wifihdr;
- u16 gaplen;
- u16 status;
-} WifiCtlHdr;
-
-static WifiCtlHdr wifictlhdr8023 = {
- .ctlhdr = {
- .ctl = HOST_DONT_RLSE,
- }
-};
-
-// A few details needed for WEP (Wireless Equivalent Privacy)
-#define MAX_KEY_SIZE 13 // 128 (?) bits
-#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP
-typedef struct wep_key_t {
- u16 len;
- u8 key[16]; /* 40-bit and 104-bit keys */
-} wep_key_t;
-
-/* List of Wireless Handlers (new API) */
-static const struct iw_handler_def airo_handler_def;
-
-static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
-
-struct airo_info;
-
-static int get_dec_u16(char *buffer, int *start, int limit);
-static void OUT4500(struct airo_info *, u16 reg, u16 value);
-static unsigned short IN4500(struct airo_info *, u16 reg);
-static u16 setup_card(struct airo_info*, struct net_device *dev, int lock);
-static int enable_MAC(struct airo_info *ai, int lock);
-static void disable_MAC(struct airo_info *ai, int lock);
-static void enable_interrupts(struct airo_info*);
-static void disable_interrupts(struct airo_info*);
-static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp,
- bool may_sleep);
-static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
-static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
- int whichbap);
-static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
- int whichbap);
-static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen,
- int whichbap);
-static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
-static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
-static int PC4500_writerid(struct airo_info*, u16 rid, const void
- *pBuf, int len, int lock);
-static int do_writerid(struct airo_info*, u16 rid, const void *rid_data,
- int len, int dummy);
-static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
-static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket,
- bool may_sleep);
-static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket,
- bool may_sleep);
-
-static int mpi_send_packet(struct net_device *dev);
-static void mpi_unmap_card(struct pci_dev *pci);
-static void mpi_receive_802_3(struct airo_info *ai);
-static void mpi_receive_802_11(struct airo_info *ai);
-static int waitbusy(struct airo_info *ai);
-
-static irqreturn_t airo_interrupt(int irq, void* dev_id);
-static int airo_thread(void *data);
-static void timer_func(struct net_device *dev);
-static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd);
-static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev);
-#ifdef CISCO_EXT
-static int readrids(struct net_device *dev, aironet_ioctl *comp);
-static int writerids(struct net_device *dev, aironet_ioctl *comp);
-static int flashcard(struct net_device *dev, aironet_ioctl *comp);
-#endif /* CISCO_EXT */
-static void micinit(struct airo_info *ai);
-static int micsetup(struct airo_info *ai);
-static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
-static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
-
-static u8 airo_rssi_to_dbm(tdsRssiEntry *rssi_rid, u8 rssi);
-static u8 airo_dbm_to_pct(tdsRssiEntry *rssi_rid, u8 dbm);
-
-static void airo_networks_free(struct airo_info *ai);
-
-struct airo_info {
- struct net_device *dev;
- struct list_head dev_list;
- /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
- use the high bit to mark whether it is in use. */
-#define MAX_FIDS 6
-#define MPI_MAX_FIDS 1
- u32 fids[MAX_FIDS];
- ConfigRid config;
- char keyindex; // Used with auto wep
- char defindex; // Used with auto wep
- struct proc_dir_entry *proc_entry;
- spinlock_t aux_lock;
-#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
-#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
-#define FLAG_RADIO_MASK 0x03
-#define FLAG_ENABLED 2
-#define FLAG_ADHOC 3 /* Needed by MIC */
-#define FLAG_MIC_CAPABLE 4
-#define FLAG_UPDATE_MULTI 5
-#define FLAG_UPDATE_UNI 6
-#define FLAG_802_11 7
-#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
-#define FLAG_PENDING_XMIT 9
-#define FLAG_PENDING_XMIT11 10
-#define FLAG_MPI 11
-#define FLAG_REGISTERED 12
-#define FLAG_COMMIT 13
-#define FLAG_RESET 14
-#define FLAG_FLASHING 15
-#define FLAG_WPA_CAPABLE 16
- unsigned long flags;
-#define JOB_DIE 0
-#define JOB_XMIT 1
-#define JOB_XMIT11 2
-#define JOB_STATS 3
-#define JOB_PROMISC 4
-#define JOB_MIC 5
-#define JOB_EVENT 6
-#define JOB_AUTOWEP 7
-#define JOB_SCAN_RESULTS 9
- unsigned long jobs;
- int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen,
- int whichbap);
- unsigned short *flash;
- tdsRssiEntry *rssi;
- struct task_struct *list_bss_task;
- struct task_struct *airo_thread_task;
- struct semaphore sem;
- wait_queue_head_t thr_wait;
- unsigned long expires;
- struct {
- struct sk_buff *skb;
- int fid;
- } xmit, xmit11;
- struct net_device *wifidev;
- struct iw_statistics wstats; // wireless stats
- unsigned long scan_timeout; /* Time scan should be read */
- struct iw_spy_data spy_data;
- struct iw_public_data wireless_data;
- /* MIC stuff */
- struct crypto_sync_skcipher *tfm;
- mic_module mod[2];
- mic_statistics micstats;
- HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
- HostTxDesc txfids[MPI_MAX_FIDS];
- HostRidDesc config_desc;
- unsigned long ridbus; // phys addr of config_desc
- struct sk_buff_head txq;// tx queue used by mpi350 code
- struct pci_dev *pci;
- unsigned char __iomem *pcimem;
- unsigned char __iomem *pciaux;
- unsigned char *shared;
- dma_addr_t shared_dma;
- pm_message_t power;
- SsidRid *SSID;
- APListRid APList;
-#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
- char proc_name[IFNAMSIZ];
-
- int wep_capable;
- int max_wep_idx;
- int last_auth;
-
- /* WPA-related stuff */
- unsigned int bssListFirst;
- unsigned int bssListNext;
- unsigned int bssListRidLen;
-
- struct list_head network_list;
- struct list_head network_free_list;
- BSSListElement *networks;
-};
-
-static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen,
- int whichbap)
-{
- return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
-}
-
-static int setup_proc_entry(struct net_device *dev,
- struct airo_info *apriv);
-static int takedown_proc_entry(struct net_device *dev,
- struct airo_info *apriv);
-
-static int cmdreset(struct airo_info *ai);
-static int setflashmode(struct airo_info *ai);
-static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime);
-static int flashputbuf(struct airo_info *ai);
-static int flashrestart(struct airo_info *ai, struct net_device *dev);
-
-#define airo_print(type, name, fmt, args...) \
- printk(type DRV_NAME "(%s): " fmt "\n", name, ##args)
-
-#define airo_print_info(name, fmt, args...) \
- airo_print(KERN_INFO, name, fmt, ##args)
-
-#define airo_print_dbg(name, fmt, args...) \
- airo_print(KERN_DEBUG, name, fmt, ##args)
-
-#define airo_print_warn(name, fmt, args...) \
- airo_print(KERN_WARNING, name, fmt, ##args)
-
-#define airo_print_err(name, fmt, args...) \
- airo_print(KERN_ERR, name, fmt, ##args)
-
-#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash)
-
-/***********************************************************************
- * MIC ROUTINES *
- ***********************************************************************
- */
-
-static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq);
-static void MoveWindow(miccntx *context, u32 micSeq);
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
- struct crypto_sync_skcipher *tfm);
-static void emmh32_init(emmh32_context *context);
-static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
-static void emmh32_final(emmh32_context *context, u8 digest[4]);
-static int flashpchar(struct airo_info *ai, int byte, int dwelltime);
-
-static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len,
- struct crypto_sync_skcipher *tfm)
-{
- /* If the current MIC context is valid and its key is the same as
- * the MIC register, there's nothing to do.
- */
- if (cur->valid && (memcmp(cur->key, key, key_len) == 0))
- return;
-
- /* Age current mic Context */
- memcpy(old, cur, sizeof(*cur));
-
- /* Initialize new context */
- memcpy(cur->key, key, key_len);
- cur->window = 33; /* Window always points to the middle */
- cur->rx = 0; /* Rx Sequence numbers */
- cur->tx = 0; /* Tx sequence numbers */
- cur->valid = 1; /* Key is now valid */
-
- /* Give key to mic seed */
- emmh32_setseed(&cur->seed, key, key_len, tfm);
-}
-
-/* micinit - Initialize mic seed */
-
-static void micinit(struct airo_info *ai)
-{
- MICRid mic_rid;
-
- clear_bit(JOB_MIC, &ai->jobs);
- PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
- up(&ai->sem);
-
- ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0;
- if (!ai->micstats.enabled) {
- /* So next time we have a valid key and mic is enabled, we will
- * update the sequence number if the key is the same as before.
- */
- ai->mod[0].uCtx.valid = 0;
- ai->mod[0].mCtx.valid = 0;
- return;
- }
-
- if (mic_rid.multicastValid) {
- age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx,
- mic_rid.multicast, sizeof(mic_rid.multicast),
- ai->tfm);
- }
-
- if (mic_rid.unicastValid) {
- age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx,
- mic_rid.unicast, sizeof(mic_rid.unicast),
- ai->tfm);
- }
-}
-
-/* micsetup - Get ready for business */
-
-static int micsetup(struct airo_info *ai)
-{
- int i;
-
- if (ai->tfm == NULL)
- ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0);
-
- if (IS_ERR(ai->tfm)) {
- airo_print_err(ai->dev->name, "failed to load transform for AES");
- ai->tfm = NULL;
- return ERROR;
- }
-
- for (i = 0; i < NUM_MODULES; i++) {
- memset(&ai->mod[i].mCtx, 0, sizeof(miccntx));
- memset(&ai->mod[i].uCtx, 0, sizeof(miccntx));
- }
- return SUCCESS;
-}
-
-static const u8 micsnap[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02};
-
-/*===========================================================================
- * Description: Mic a packet
- *
- * Inputs: etherHead * pointer to an 802.3 frame
- *
- * Returns: BOOLEAN if successful, otherwise false.
- * PacketTxLen will be updated with the mic'd packets size.
- *
- * Caveats: It is assumed that the frame buffer will already
- * be big enough to hold the largets mic message possible.
- * (No memory allocation is done here).
- *
- * Author: sbraneky (10/15/01)
- * Merciless hacks by rwilcher (1/14/02)
- */
-
-static int encapsulate(struct airo_info *ai, etherHead *frame, MICBuffer *mic, int payLen)
-{
- miccntx *context;
-
- // Determine correct context
- // If not adhoc, always use unicast key
-
- if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
- context = &ai->mod[0].mCtx;
- else
- context = &ai->mod[0].uCtx;
-
- if (!context->valid)
- return ERROR;
-
- mic->typelen = htons(payLen + 16); //Length of Mic'd packet
-
- memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
-
- // Add Tx sequence
- mic->seq = htonl(context->tx);
- context->tx += 2;
-
- emmh32_init(&context->seed); // Mic the packet
- emmh32_update(&context->seed, frame->da, ETH_ALEN * 2); // DA, SA
- emmh32_update(&context->seed, (u8*)&mic->typelen, 10); // Type/Length and Snap
- emmh32_update(&context->seed, (u8*)&mic->seq, sizeof(mic->seq)); //SEQ
- emmh32_update(&context->seed, (u8*)(frame + 1), payLen); //payload
- emmh32_final(&context->seed, (u8*)&mic->mic);
-
- /* New Type/length ?????????? */
- mic->typelen = 0; //Let NIC know it could be an oversized packet
- return SUCCESS;
-}
-
-typedef enum {
- NONE,
- NOMIC,
- NOMICPLUMMED,
- SEQUENCE,
- INCORRECTMIC,
-} mic_error;
-
-/*===========================================================================
- * Description: Decapsulates a MIC'd packet and returns the 802.3 packet
- * (removes the MIC stuff) if packet is a valid packet.
- *
- * Inputs: etherHead pointer to the 802.3 packet
- *
- * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
- *
- * Author: sbraneky (10/15/01)
- * Merciless hacks by rwilcher (1/14/02)
- *---------------------------------------------------------------------------
- */
-
-static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
-{
- int i;
- u32 micSEQ;
- miccntx *context;
- u8 digest[4];
- mic_error micError = NONE;
-
- // Check if the packet is a Mic'd packet
-
- if (!ai->micstats.enabled) {
- //No Mic set or Mic OFF but we received a MIC'd packet.
- if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
- ai->micstats.rxMICPlummed++;
- return ERROR;
- }
- return SUCCESS;
- }
-
- if (ntohs(mic->typelen) == 0x888E)
- return SUCCESS;
-
- if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
- // Mic enabled but packet isn't Mic'd
- ai->micstats.rxMICPlummed++;
- return ERROR;
- }
-
- micSEQ = ntohl(mic->seq); //store SEQ as CPU order
-
- //At this point we a have a mic'd packet and mic is enabled
- //Now do the mic error checking.
-
- //Receive seq must be odd
- if ((micSEQ & 1) == 0) {
- ai->micstats.rxWrongSequence++;
- return ERROR;
- }
-
- for (i = 0; i < NUM_MODULES; i++) {
- int mcast = eth->da[0] & 1;
- //Determine proper context
- context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
-
- //Make sure context is valid
- if (!context->valid) {
- if (i == 0)
- micError = NOMICPLUMMED;
- continue;
- }
- //DeMic it
-
- if (!mic->typelen)
- mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
-
- emmh32_init(&context->seed);
- emmh32_update(&context->seed, eth->da, ETH_ALEN*2);
- emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap));
- emmh32_update(&context->seed, (u8 *)&mic->seq, sizeof(mic->seq));
- emmh32_update(&context->seed, (u8 *)(eth + 1), payLen);
- //Calculate MIC
- emmh32_final(&context->seed, digest);
-
- if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
- //Invalid Mic
- if (i == 0)
- micError = INCORRECTMIC;
- continue;
- }
-
- //Check Sequence number if mics pass
- if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
- ai->micstats.rxSuccess++;
- return SUCCESS;
- }
- if (i == 0)
- micError = SEQUENCE;
- }
-
- // Update statistics
- switch (micError) {
- case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break;
- case SEQUENCE: ai->micstats.rxWrongSequence++; break;
- case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
- case NONE: break;
- case NOMIC: break;
- }
- return ERROR;
-}
-
-/*===========================================================================
- * Description: Checks the Rx Seq number to make sure it is valid
- * and hasn't already been received
- *
- * Inputs: miccntx - mic context to check seq against
- * micSeq - the Mic seq number
- *
- * Returns: TRUE if valid otherwise FALSE.
- *
- * Author: sbraneky (10/15/01)
- * Merciless hacks by rwilcher (1/14/02)
- *---------------------------------------------------------------------------
- */
-
-static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq)
-{
- u32 seq, index;
-
- //Allow for the ap being rebooted - if it is then use the next
- //sequence number of the current sequence number - might go backwards
-
- if (mcast) {
- if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
- clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
- context->window = (micSeq > 33) ? micSeq : 33;
- context->rx = 0; // Reset rx
- }
- } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
- clear_bit (FLAG_UPDATE_UNI, &ai->flags);
- context->window = (micSeq > 33) ? micSeq : 33; // Move window
- context->rx = 0; // Reset rx
- }
-
- //Make sequence number relative to START of window
- seq = micSeq - (context->window - 33);
-
- //Too old of a SEQ number to check.
- if ((s32)seq < 0)
- return ERROR;
-
- if (seq > 64) {
- //Window is infinite forward
- MoveWindow(context, micSeq);
- return SUCCESS;
- }
-
- // We are in the window. Now check the context rx bit to see if it was already sent
- seq >>= 1; //divide by 2 because we only have odd numbers
- index = 1 << seq; //Get an index number
-
- if (!(context->rx & index)) {
- //micSEQ falls inside the window.
- //Add seqence number to the list of received numbers.
- context->rx |= index;
-
- MoveWindow(context, micSeq);
-
- return SUCCESS;
- }
- return ERROR;
-}
-
-static void MoveWindow(miccntx *context, u32 micSeq)
-{
- u32 shift;
-
- //Move window if seq greater than the middle of the window
- if (micSeq > context->window) {
- shift = (micSeq - context->window) >> 1;
-
- //Shift out old
- if (shift < 32)
- context->rx >>= shift;
- else
- context->rx = 0;
-
- context->window = micSeq; //Move window
- }
-}
-
-/*==============================================*/
-/*========== EMMH ROUTINES ====================*/
-/*==============================================*/
-
-/* mic accumulate */
-#define MIC_ACCUM(val) \
- context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]);
-
-/* expand the key to fill the MMH coefficient array */
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
- struct crypto_sync_skcipher *tfm)
-{
- /* take the keying material, expand if necessary, truncate at 16-bytes */
- /* run through AES counter mode to generate context->coeff[] */
-
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
- struct scatterlist sg;
- u8 iv[AES_BLOCK_SIZE] = {};
- int ret;
-
- crypto_sync_skcipher_setkey(tfm, pkey, 16);
-
- memset(context->coeff, 0, sizeof(context->coeff));
- sg_init_one(&sg, context->coeff, sizeof(context->coeff));
-
- skcipher_request_set_sync_tfm(req, tfm);
- skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv);
-
- ret = crypto_skcipher_encrypt(req);
- WARN_ON_ONCE(ret);
-}
-
-/* prepare for calculation of a new mic */
-static void emmh32_init(emmh32_context *context)
-{
- /* prepare for new mic calculation */
- context->accum = 0;
- context->position = 0;
-}
-
-/* add some bytes to the mic calculation */
-static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
-{
- int coeff_position, byte_position;
-
- if (len == 0) return;
-
- coeff_position = context->position >> 2;
-
- /* deal with partial 32-bit word left over from last update */
- byte_position = context->position & 3;
- if (byte_position) {
- /* have a partial word in part to deal with */
- do {
- if (len == 0) return;
- context->part.d8[byte_position++] = *pOctets++;
- context->position++;
- len--;
- } while (byte_position < 4);
- MIC_ACCUM(ntohl(context->part.d32));
- }
-
- /* deal with full 32-bit words */
- while (len >= 4) {
- MIC_ACCUM(ntohl(*(__be32 *)pOctets));
- context->position += 4;
- pOctets += 4;
- len -= 4;
- }
-
- /* deal with partial 32-bit word that will be left over from this update */
- byte_position = 0;
- while (len > 0) {
- context->part.d8[byte_position++] = *pOctets++;
- context->position++;
- len--;
- }
-}
-
-/* mask used to zero empty bytes for final partial word */
-static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
-
-/* calculate the mic */
-static void emmh32_final(emmh32_context *context, u8 digest[4])
-{
- int coeff_position, byte_position;
- u32 val;
-
- u64 sum, utmp;
- s64 stmp;
-
- coeff_position = context->position >> 2;
-
- /* deal with partial 32-bit word left over from last update */
- byte_position = context->position & 3;
- if (byte_position) {
- /* have a partial word in part to deal with */
- val = ntohl(context->part.d32);
- MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
- }
-
- /* reduce the accumulated u64 to a 32-bit MIC */
- sum = context->accum;
- stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15);
- utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
- sum = utmp & 0xffffffffLL;
- if (utmp > 0x10000000fLL)
- sum -= 15;
-
- val = (u32)sum;
- digest[0] = (val>>24) & 0xFF;
- digest[1] = (val>>16) & 0xFF;
- digest[2] = (val>>8) & 0xFF;
- digest[3] = val & 0xFF;
-}
-
-static int readBSSListRid(struct airo_info *ai, int first,
- BSSListRid *list)
-{
- Cmd cmd;
- Resp rsp;
-
- if (first == 1) {
- if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LISTBSS;
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
- ai->list_bss_task = current;
- issuecommand(ai, &cmd, &rsp, true);
- up(&ai->sem);
- /* Let the command take effect */
- schedule_timeout_uninterruptible(3 * HZ);
- ai->list_bss_task = NULL;
- }
- return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
- list, ai->bssListRidLen, 1);
-}
-
-static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock)
-{
- return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
- wkr, sizeof(*wkr), lock);
-}
-
-static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock)
-{
- int rc;
- rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock);
- if (rc!=SUCCESS)
- airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
- if (perm) {
- rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock);
- if (rc!=SUCCESS)
- airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
- }
- return rc;
-}
-
-static int readSsidRid(struct airo_info*ai, SsidRid *ssidr)
-{
- return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
-}
-
-static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock)
-{
- return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock);
-}
-
-static int readConfigRid(struct airo_info *ai, int lock)
-{
- int rc;
- ConfigRid cfg;
-
- if (ai->config.len)
- return SUCCESS;
-
- rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
- if (rc != SUCCESS)
- return rc;
-
- ai->config = cfg;
- return SUCCESS;
-}
-
-static inline void checkThrottle(struct airo_info *ai)
-{
- int i;
-/* Old hardware had a limit on encryption speed */
- if (ai->config.authType != AUTH_OPEN && maxencrypt) {
- for (i = 0; i<8; i++) {
- if (ai->config.rates[i] > maxencrypt) {
- ai->config.rates[i] = 0;
- }
- }
- }
-}
-
-static int writeConfigRid(struct airo_info *ai, int lock)
-{
- ConfigRid cfgr;
-
- if (!test_bit (FLAG_COMMIT, &ai->flags))
- return SUCCESS;
-
- clear_bit (FLAG_COMMIT, &ai->flags);
- clear_bit (FLAG_RESET, &ai->flags);
- checkThrottle(ai);
- cfgr = ai->config;
-
- if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS)
- set_bit(FLAG_ADHOC, &ai->flags);
- else
- clear_bit(FLAG_ADHOC, &ai->flags);
-
- return PC4500_writerid(ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
-}
-
-static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock)
-{
- return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
-}
-
-static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock)
-{
- return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
-}
-
-static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock)
-{
- return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
-}
-
-static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock)
-{
- return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
-}
-
-static void try_auto_wep(struct airo_info *ai)
-{
- if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) {
- ai->expires = RUN_AT(3*HZ);
- wake_up_interruptible(&ai->thr_wait);
- }
-}
-
-static int airo_open(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
- int rc = 0;
-
- if (test_bit(FLAG_FLASHING, &ai->flags))
- return -EIO;
-
- /* Make sure the card is configured.
- * Wireless Extensions may postpone config changes until the card
- * is open (to pipeline changes and speed-up card setup). If
- * those changes are not yet committed, do it now - Jean II */
- if (test_bit(FLAG_COMMIT, &ai->flags)) {
- disable_MAC(ai, 1);
- writeConfigRid(ai, 1);
- }
-
- if (ai->wifidev != dev) {
- clear_bit(JOB_DIE, &ai->jobs);
- ai->airo_thread_task = kthread_run(airo_thread, dev, "%s",
- dev->name);
- if (IS_ERR(ai->airo_thread_task))
- return (int)PTR_ERR(ai->airo_thread_task);
-
- rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
- dev->name, dev);
- if (rc) {
- airo_print_err(dev->name,
- "register interrupt %d failed, rc %d",
- dev->irq, rc);
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
- return rc;
- }
-
- /* Power on the MAC controller (which may have been disabled) */
- clear_bit(FLAG_RADIO_DOWN, &ai->flags);
- enable_interrupts(ai);
-
- try_auto_wep(ai);
- }
- enable_MAC(ai, 1);
-
- netif_start_queue(dev);
- return 0;
-}
-
-static netdev_tx_t mpi_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- int npacks, pending;
- unsigned long flags;
- struct airo_info *ai = dev->ml_priv;
-
- if (!skb) {
- airo_print_err(dev->name, "%s: skb == NULL!",__func__);
- return NETDEV_TX_OK;
- }
- if (skb_padto(skb, ETH_ZLEN)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- npacks = skb_queue_len (&ai->txq);
-
- if (npacks >= MAXTXQ - 1) {
- netif_stop_queue (dev);
- if (npacks > MAXTXQ) {
- dev->stats.tx_fifo_errors++;
- return NETDEV_TX_BUSY;
- }
- skb_queue_tail (&ai->txq, skb);
- return NETDEV_TX_OK;
- }
-
- spin_lock_irqsave(&ai->aux_lock, flags);
- skb_queue_tail (&ai->txq, skb);
- pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- netif_wake_queue (dev);
-
- if (pending == 0) {
- set_bit(FLAG_PENDING_XMIT, &ai->flags);
- mpi_send_packet (dev);
- }
- return NETDEV_TX_OK;
-}
-
-/*
- * @mpi_send_packet
- *
- * Attempt to transmit a packet. Can be called from interrupt
- * or transmit . return number of packets we tried to send
- */
-
-static int mpi_send_packet (struct net_device *dev)
-{
- struct sk_buff *skb;
- unsigned char *buffer;
- s16 len;
- __le16 *payloadLen;
- struct airo_info *ai = dev->ml_priv;
- u8 *sendbuf;
-
- /* get a packet to send */
-
- if ((skb = skb_dequeue(&ai->txq)) == NULL) {
- airo_print_err(dev->name,
- "%s: Dequeue'd zero in send_packet()",
- __func__);
- return 0;
- }
-
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- buffer = skb->data;
-
- ai->txfids[0].tx_desc.offset = 0;
- ai->txfids[0].tx_desc.valid = 1;
- ai->txfids[0].tx_desc.eoc = 1;
- ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
-
-/*
- * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
- * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
- * is immediately after it. ------------------------------------------------
- * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
- * ------------------------------------------------
- */
-
- memcpy(ai->txfids[0].virtual_host_addr,
- (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
-
- payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
- sizeof(wifictlhdr8023));
- sendbuf = ai->txfids[0].virtual_host_addr +
- sizeof(wifictlhdr8023) + 2 ;
-
- /*
- * Firmware automatically puts 802 header on so
- * we don't need to account for it in the length
- */
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
- (ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
- MICBuffer pMic;
-
- if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
- return ERROR;
-
- *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
- ai->txfids[0].tx_desc.len += sizeof(pMic);
- /* copy data into airo dma buffer */
- memcpy (sendbuf, buffer, sizeof(etherHead));
- buffer += sizeof(etherHead);
- sendbuf += sizeof(etherHead);
- memcpy (sendbuf, &pMic, sizeof(pMic));
- sendbuf += sizeof(pMic);
- memcpy (sendbuf, buffer, len - sizeof(etherHead));
- } else {
- *payloadLen = cpu_to_le16(len - sizeof(etherHead));
-
- netif_trans_update(dev);
-
- /* copy data into airo dma buffer */
- memcpy(sendbuf, buffer, len);
- }
-
- memcpy_toio(ai->txfids[0].card_ram_off,
- &ai->txfids[0].tx_desc, sizeof(TxFid));
-
- OUT4500(ai, EVACK, 8);
-
- dev_kfree_skb_any(skb);
- return 1;
-}
-
-static void get_tx_error(struct airo_info *ai, s32 fid)
-{
- __le16 status;
-
- if (fid < 0)
- status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
- else {
- if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
- return;
- bap_read(ai, &status, 2, BAP0);
- }
- if (le16_to_cpu(status) & 2) /* Too many retries */
- ai->dev->stats.tx_aborted_errors++;
- if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
- ai->dev->stats.tx_heartbeat_errors++;
- if (le16_to_cpu(status) & 8) /* Aid fail */
- { }
- if (le16_to_cpu(status) & 0x10) /* MAC disabled */
- ai->dev->stats.tx_carrier_errors++;
- if (le16_to_cpu(status) & 0x20) /* Association lost */
- { }
- /* We produce a TXDROP event only for retry or lifetime
- * exceeded, because that's the only status that really mean
- * that this particular node went away.
- * Other errors means that *we* screwed up. - Jean II */
- if ((le16_to_cpu(status) & 2) ||
- (le16_to_cpu(status) & 4)) {
- union iwreq_data wrqu;
- char junk[0x18];
-
- /* Faster to skip over useless data than to do
- * another bap_setup(). We are at offset 0x6 and
- * need to go to 0x18 and read 6 bytes - Jean II */
- bap_read(ai, (__le16 *) junk, 0x18, BAP0);
-
- /* Copy 802.11 dest address.
- * We use the 802.11 header because the frame may
- * not be 802.3 or may be mangled...
- * In Ad-Hoc mode, it will be the node address.
- * In managed mode, it will be most likely the AP addr
- * User space will figure out how to convert it to
- * whatever it needs (IP address or else).
- * - Jean II */
- memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
- }
-}
-
-static void airo_end_xmit(struct net_device *dev, bool may_sleep)
-{
- u16 status;
- int i;
- struct airo_info *priv = dev->ml_priv;
- struct sk_buff *skb = priv->xmit.skb;
- int fid = priv->xmit.fid;
- u32 *fids = priv->fids;
-
- clear_bit(JOB_XMIT, &priv->jobs);
- clear_bit(FLAG_PENDING_XMIT, &priv->flags);
- status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep);
- up(&priv->sem);
-
- i = 0;
- if (status == SUCCESS) {
- netif_trans_update(dev);
- for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
- } else {
- priv->fids[fid] &= 0xffff;
- dev->stats.tx_window_errors++;
- }
- if (i < MAX_FIDS / 2)
- netif_wake_queue(dev);
- dev_kfree_skb(skb);
-}
-
-static netdev_tx_t airo_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- s16 len;
- int i, j;
- struct airo_info *priv = dev->ml_priv;
- u32 *fids = priv->fids;
-
- if (skb == NULL) {
- airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return NETDEV_TX_OK;
- }
- if (skb_padto(skb, ETH_ZLEN)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
-
- /* Find a vacant FID */
- for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++);
- for (j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++);
-
- if (j >= MAX_FIDS / 2) {
- netif_stop_queue(dev);
-
- if (i == MAX_FIDS / 2) {
- dev->stats.tx_fifo_errors++;
- return NETDEV_TX_BUSY;
- }
- }
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- /* Mark fid as used & save length for later */
- fids[i] |= (len << 16);
- priv->xmit.skb = skb;
- priv->xmit.fid = i;
- if (down_trylock(&priv->sem) != 0) {
- set_bit(FLAG_PENDING_XMIT, &priv->flags);
- netif_stop_queue(dev);
- set_bit(JOB_XMIT, &priv->jobs);
- wake_up_interruptible(&priv->thr_wait);
- } else
- airo_end_xmit(dev, false);
- return NETDEV_TX_OK;
-}
-
-static void airo_end_xmit11(struct net_device *dev, bool may_sleep)
-{
- u16 status;
- int i;
- struct airo_info *priv = dev->ml_priv;
- struct sk_buff *skb = priv->xmit11.skb;
- int fid = priv->xmit11.fid;
- u32 *fids = priv->fids;
-
- clear_bit(JOB_XMIT11, &priv->jobs);
- clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
- status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep);
- up(&priv->sem);
-
- i = MAX_FIDS / 2;
- if (status == SUCCESS) {
- netif_trans_update(dev);
- for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
- } else {
- priv->fids[fid] &= 0xffff;
- dev->stats.tx_window_errors++;
- }
- if (i < MAX_FIDS)
- netif_wake_queue(dev);
- dev_kfree_skb(skb);
-}
-
-static netdev_tx_t airo_start_xmit11(struct sk_buff *skb,
- struct net_device *dev)
-{
- s16 len;
- int i, j;
- struct airo_info *priv = dev->ml_priv;
- u32 *fids = priv->fids;
-
- if (test_bit(FLAG_MPI, &priv->flags)) {
- /* Not implemented yet for MPI350 */
- netif_stop_queue(dev);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
-
- if (skb == NULL) {
- airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return NETDEV_TX_OK;
- }
- if (skb_padto(skb, ETH_ZLEN)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
-
- /* Find a vacant FID */
- for (i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++);
- for (j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++);
-
- if (j >= MAX_FIDS) {
- netif_stop_queue(dev);
-
- if (i == MAX_FIDS) {
- dev->stats.tx_fifo_errors++;
- return NETDEV_TX_BUSY;
- }
- }
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- /* Mark fid as used & save length for later */
- fids[i] |= (len << 16);
- priv->xmit11.skb = skb;
- priv->xmit11.fid = i;
- if (down_trylock(&priv->sem) != 0) {
- set_bit(FLAG_PENDING_XMIT11, &priv->flags);
- netif_stop_queue(dev);
- set_bit(JOB_XMIT11, &priv->jobs);
- wake_up_interruptible(&priv->thr_wait);
- } else
- airo_end_xmit11(dev, false);
- return NETDEV_TX_OK;
-}
-
-static void airo_read_stats(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
- StatsRid stats_rid;
- __le32 *vals = stats_rid.vals;
-
- clear_bit(JOB_STATS, &ai->jobs);
- if (ai->power.event) {
- up(&ai->sem);
- return;
- }
- readStatsRid(ai, &stats_rid, RID_STATS, 0);
- up(&ai->sem);
-
- dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
- le32_to_cpu(vals[45]);
- dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
- le32_to_cpu(vals[41]);
- dev->stats.rx_bytes = le32_to_cpu(vals[92]);
- dev->stats.tx_bytes = le32_to_cpu(vals[91]);
- dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
- le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
- dev->stats.tx_errors = le32_to_cpu(vals[42]) +
- dev->stats.tx_fifo_errors;
- dev->stats.multicast = le32_to_cpu(vals[43]);
- dev->stats.collisions = le32_to_cpu(vals[89]);
-
- /* detailed rx_errors: */
- dev->stats.rx_length_errors = le32_to_cpu(vals[3]);
- dev->stats.rx_crc_errors = le32_to_cpu(vals[4]);
- dev->stats.rx_frame_errors = le32_to_cpu(vals[2]);
- dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
-}
-
-static struct net_device_stats *airo_get_stats(struct net_device *dev)
-{
- struct airo_info *local = dev->ml_priv;
-
- if (!test_bit(JOB_STATS, &local->jobs)) {
- set_bit(JOB_STATS, &local->jobs);
- wake_up_interruptible(&local->thr_wait);
- }
-
- return &dev->stats;
-}
-
-static void airo_set_promisc(struct airo_info *ai, bool may_sleep)
-{
- Cmd cmd;
- Resp rsp;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_SETMODE;
- clear_bit(JOB_PROMISC, &ai->jobs);
- cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
- issuecommand(ai, &cmd, &rsp, may_sleep);
- up(&ai->sem);
-}
-
-static void airo_set_multicast_list(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
-
- if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
- change_bit(FLAG_PROMISC, &ai->flags);
- if (down_trylock(&ai->sem) != 0) {
- set_bit(JOB_PROMISC, &ai->jobs);
- wake_up_interruptible(&ai->thr_wait);
- } else
- airo_set_promisc(ai, false);
- }
-
- if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
- /* Turn on multicast. (Should be already setup...) */
- }
-}
-
-static int airo_set_mac_address(struct net_device *dev, void *p)
-{
- struct airo_info *ai = dev->ml_priv;
- struct sockaddr *addr = p;
-
- readConfigRid(ai, 1);
- memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
- set_bit (FLAG_COMMIT, &ai->flags);
- disable_MAC(ai, 1);
- writeConfigRid (ai, 1);
- enable_MAC(ai, 1);
- dev_addr_set(ai->dev, addr->sa_data);
- if (ai->wifidev)
- dev_addr_set(ai->wifidev, addr->sa_data);
- return 0;
-}
-
-static LIST_HEAD(airo_devices);
-
-static void add_airo_dev(struct airo_info *ai)
-{
- /* Upper layers already keep track of PCI devices,
- * so we only need to remember our non-PCI cards. */
- if (!ai->pci)
- list_add_tail(&ai->dev_list, &airo_devices);
-}
-
-static void del_airo_dev(struct airo_info *ai)
-{
- if (!ai->pci)
- list_del(&ai->dev_list);
-}
-
-static int airo_close(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
-
- netif_stop_queue(dev);
-
- if (ai->wifidev != dev) {
-#ifdef POWER_ON_DOWN
- /* Shut power to the card. The idea is that the user can save
- * power when he doesn't need the card with "ifconfig down".
- * That's the method that is most friendly towards the network
- * stack (i.e. the network stack won't try to broadcast
- * anything on the interface and routes are gone. Jean II */
- set_bit(FLAG_RADIO_DOWN, &ai->flags);
- disable_MAC(ai, 1);
-#endif
- disable_interrupts(ai);
-
- free_irq(dev->irq, dev);
-
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
- }
- return 0;
-}
-
-void stop_airo_card(struct net_device *dev, int freeres)
-{
- struct airo_info *ai = dev->ml_priv;
-
- set_bit(FLAG_RADIO_DOWN, &ai->flags);
- disable_MAC(ai, 1);
- disable_interrupts(ai);
- takedown_proc_entry(dev, ai);
- if (test_bit(FLAG_REGISTERED, &ai->flags)) {
- unregister_netdev(dev);
- if (ai->wifidev) {
- unregister_netdev(ai->wifidev);
- free_netdev(ai->wifidev);
- ai->wifidev = NULL;
- }
- clear_bit(FLAG_REGISTERED, &ai->flags);
- }
- /*
- * Clean out tx queue
- */
- if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
- struct sk_buff *skb = NULL;
- for (;(skb = skb_dequeue(&ai->txq));)
- dev_kfree_skb(skb);
- }
-
- airo_networks_free (ai);
-
- kfree(ai->flash);
- kfree(ai->rssi);
- kfree(ai->SSID);
- if (freeres) {
- /* PCMCIA frees this stuff, so only for PCI and ISA */
- release_region(dev->base_addr, 64);
- if (test_bit(FLAG_MPI, &ai->flags)) {
- if (ai->pci)
- mpi_unmap_card(ai->pci);
- if (ai->pcimem)
- iounmap(ai->pcimem);
- if (ai->pciaux)
- iounmap(ai->pciaux);
- dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN,
- ai->shared, ai->shared_dma);
- }
- }
- crypto_free_sync_skcipher(ai->tfm);
- del_airo_dev(ai);
- free_netdev(dev);
-}
-
-EXPORT_SYMBOL(stop_airo_card);
-
-static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
- return ETH_ALEN;
-}
-
-static void mpi_unmap_card(struct pci_dev *pci)
-{
- unsigned long mem_start = pci_resource_start(pci, 1);
- unsigned long mem_len = pci_resource_len(pci, 1);
- unsigned long aux_start = pci_resource_start(pci, 2);
- unsigned long aux_len = AUXMEMSIZE;
-
- release_mem_region(aux_start, aux_len);
- release_mem_region(mem_start, mem_len);
-}
-
-/*************************************************************
- * This routine assumes that descriptors have been setup .
- * Run at insmod time or after reset when the descriptors
- * have been initialized . Returns 0 if all is well nz
- * otherwise . Does not allocate memory but sets up card
- * using previously allocated descriptors.
- */
-static int mpi_init_descriptors (struct airo_info *ai)
-{
- Cmd cmd;
- Resp rsp;
- int i;
- int rc = SUCCESS;
-
- /* Alloc card RX descriptors */
- netif_stop_queue(ai->dev);
-
- memset(&rsp, 0, sizeof(rsp));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.cmd = CMD_ALLOCATEAUX;
- cmd.parm0 = FID_RX;
- cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
- cmd.parm2 = MPI_MAX_FIDS;
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc != SUCCESS) {
- airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
- return rc;
- }
-
- for (i = 0; i<MPI_MAX_FIDS; i++) {
- memcpy_toio(ai->rxfids[i].card_ram_off,
- &ai->rxfids[i].rx_desc, sizeof(RxFid));
- }
-
- /* Alloc card TX descriptors */
-
- memset(&rsp, 0, sizeof(rsp));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.cmd = CMD_ALLOCATEAUX;
- cmd.parm0 = FID_TX;
- cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
- cmd.parm2 = MPI_MAX_FIDS;
-
- for (i = 0; i<MPI_MAX_FIDS; i++) {
- ai->txfids[i].tx_desc.valid = 1;
- memcpy_toio(ai->txfids[i].card_ram_off,
- &ai->txfids[i].tx_desc, sizeof(TxFid));
- }
- ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
-
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc != SUCCESS) {
- airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
- return rc;
- }
-
- /* Alloc card Rid descriptor */
- memset(&rsp, 0, sizeof(rsp));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.cmd = CMD_ALLOCATEAUX;
- cmd.parm0 = RID_RW;
- cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
- cmd.parm2 = 1; /* Magic number... */
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc != SUCCESS) {
- airo_print_err(ai->dev->name, "Couldn't allocate RID");
- return rc;
- }
-
- memcpy_toio(ai->config_desc.card_ram_off,
- &ai->config_desc.rid_desc, sizeof(Rid));
-
- return rc;
-}
-
-/*
- * We are setting up three things here:
- * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
- * 2) Map PCI memory for issuing commands.
- * 3) Allocate memory (shared) to send and receive ethernet frames.
- */
-static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
-{
- unsigned long mem_start, mem_len, aux_start, aux_len;
- int rc = -1;
- int i;
- dma_addr_t busaddroff;
- unsigned char *vpackoff;
- unsigned char __iomem *pciaddroff;
-
- mem_start = pci_resource_start(pci, 1);
- mem_len = pci_resource_len(pci, 1);
- aux_start = pci_resource_start(pci, 2);
- aux_len = AUXMEMSIZE;
-
- if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
- airo_print_err("", "Couldn't get region %x[%x]",
- (int)mem_start, (int)mem_len);
- goto out;
- }
- if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
- airo_print_err("", "Couldn't get region %x[%x]",
- (int)aux_start, (int)aux_len);
- goto free_region1;
- }
-
- ai->pcimem = ioremap(mem_start, mem_len);
- if (!ai->pcimem) {
- airo_print_err("", "Couldn't map region %x[%x]",
- (int)mem_start, (int)mem_len);
- goto free_region2;
- }
- ai->pciaux = ioremap(aux_start, aux_len);
- if (!ai->pciaux) {
- airo_print_err("", "Couldn't map region %x[%x]",
- (int)aux_start, (int)aux_len);
- goto free_memmap;
- }
-
- /* Reserve PKTSIZE for each fid and 2K for the Rids */
- ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN,
- &ai->shared_dma, GFP_KERNEL);
- if (!ai->shared) {
- airo_print_err("", "Couldn't alloc_coherent %d",
- PCI_SHARED_LEN);
- goto free_auxmap;
- }
-
- /*
- * Setup descriptor RX, TX, CONFIG
- */
- busaddroff = ai->shared_dma;
- pciaddroff = ai->pciaux + AUX_OFFSET;
- vpackoff = ai->shared;
-
- /* RX descriptor setup */
- for (i = 0; i < MPI_MAX_FIDS; i++) {
- ai->rxfids[i].pending = 0;
- ai->rxfids[i].card_ram_off = pciaddroff;
- ai->rxfids[i].virtual_host_addr = vpackoff;
- ai->rxfids[i].rx_desc.host_addr = busaddroff;
- ai->rxfids[i].rx_desc.valid = 1;
- ai->rxfids[i].rx_desc.len = PKTSIZE;
- ai->rxfids[i].rx_desc.rdy = 0;
-
- pciaddroff += sizeof(RxFid);
- busaddroff += PKTSIZE;
- vpackoff += PKTSIZE;
- }
-
- /* TX descriptor setup */
- for (i = 0; i < MPI_MAX_FIDS; i++) {
- ai->txfids[i].card_ram_off = pciaddroff;
- ai->txfids[i].virtual_host_addr = vpackoff;
- ai->txfids[i].tx_desc.valid = 1;
- ai->txfids[i].tx_desc.host_addr = busaddroff;
- memcpy(ai->txfids[i].virtual_host_addr,
- &wifictlhdr8023, sizeof(wifictlhdr8023));
-
- pciaddroff += sizeof(TxFid);
- busaddroff += PKTSIZE;
- vpackoff += PKTSIZE;
- }
- ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
-
- /* Rid descriptor setup */
- ai->config_desc.card_ram_off = pciaddroff;
- ai->config_desc.virtual_host_addr = vpackoff;
- ai->config_desc.rid_desc.host_addr = busaddroff;
- ai->ridbus = busaddroff;
- ai->config_desc.rid_desc.rid = 0;
- ai->config_desc.rid_desc.len = RIDSIZE;
- ai->config_desc.rid_desc.valid = 1;
- pciaddroff += sizeof(Rid);
- busaddroff += RIDSIZE;
- vpackoff += RIDSIZE;
-
- /* Tell card about descriptors */
- if (mpi_init_descriptors (ai) != SUCCESS)
- goto free_shared;
-
- return 0;
- free_shared:
- dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared,
- ai->shared_dma);
- free_auxmap:
- iounmap(ai->pciaux);
- free_memmap:
- iounmap(ai->pcimem);
- free_region2:
- release_mem_region(aux_start, aux_len);
- free_region1:
- release_mem_region(mem_start, mem_len);
- out:
- return rc;
-}
-
-static const struct header_ops airo_header_ops = {
- .parse = wll_header_parse,
-};
-
-static const struct net_device_ops airo11_netdev_ops = {
- .ndo_open = airo_open,
- .ndo_stop = airo_close,
- .ndo_start_xmit = airo_start_xmit11,
- .ndo_get_stats = airo_get_stats,
- .ndo_set_mac_address = airo_set_mac_address,
- .ndo_siocdevprivate = airo_siocdevprivate,
-};
-
-static void wifi_setup(struct net_device *dev)
-{
- dev->netdev_ops = &airo11_netdev_ops;
- dev->header_ops = &airo_header_ops;
- dev->wireless_handlers = &airo_handler_def;
-
- dev->type = ARPHRD_IEEE80211;
- dev->hard_header_len = ETH_HLEN;
- dev->mtu = AIRO_DEF_MTU;
- dev->min_mtu = 68;
- dev->max_mtu = MIC_MSGLEN_MAX;
- dev->addr_len = ETH_ALEN;
- dev->tx_queue_len = 100;
-
- eth_broadcast_addr(dev->broadcast);
-
- dev->flags = IFF_BROADCAST|IFF_MULTICAST;
-}
-
-static struct net_device *init_wifidev(struct airo_info *ai,
- struct net_device *ethdev)
-{
- int err;
- struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN,
- wifi_setup);
- if (!dev)
- return NULL;
- dev->ml_priv = ethdev->ml_priv;
- dev->irq = ethdev->irq;
- dev->base_addr = ethdev->base_addr;
- dev->wireless_data = ethdev->wireless_data;
- SET_NETDEV_DEV(dev, ethdev->dev.parent);
- eth_hw_addr_inherit(dev, ethdev);
- err = register_netdev(dev);
- if (err<0) {
- free_netdev(dev);
- return NULL;
- }
- return dev;
-}
-
-static int reset_card(struct net_device *dev, int lock)
-{
- struct airo_info *ai = dev->ml_priv;
-
- if (lock && down_interruptible(&ai->sem))
- return -1;
- waitbusy (ai);
- OUT4500(ai, COMMAND, CMD_SOFTRESET);
- msleep(200);
- waitbusy (ai);
- msleep(200);
- if (lock)
- up(&ai->sem);
- return 0;
-}
-
-#define AIRO_MAX_NETWORK_COUNT 64
-static int airo_networks_allocate(struct airo_info *ai)
-{
- if (ai->networks)
- return 0;
-
- ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement),
- GFP_KERNEL);
- if (!ai->networks) {
- airo_print_warn("", "Out of memory allocating beacons");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void airo_networks_free(struct airo_info *ai)
-{
- kfree(ai->networks);
- ai->networks = NULL;
-}
-
-static void airo_networks_initialize(struct airo_info *ai)
-{
- int i;
-
- INIT_LIST_HEAD(&ai->network_free_list);
- INIT_LIST_HEAD(&ai->network_list);
- for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
- list_add_tail(&ai->networks[i].list,
- &ai->network_free_list);
-}
-
-static const struct net_device_ops airo_netdev_ops = {
- .ndo_open = airo_open,
- .ndo_stop = airo_close,
- .ndo_start_xmit = airo_start_xmit,
- .ndo_get_stats = airo_get_stats,
- .ndo_set_rx_mode = airo_set_multicast_list,
- .ndo_set_mac_address = airo_set_mac_address,
- .ndo_siocdevprivate = airo_siocdevprivate,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static const struct net_device_ops mpi_netdev_ops = {
- .ndo_open = airo_open,
- .ndo_stop = airo_close,
- .ndo_start_xmit = mpi_start_xmit,
- .ndo_get_stats = airo_get_stats,
- .ndo_set_rx_mode = airo_set_multicast_list,
- .ndo_set_mac_address = airo_set_mac_address,
- .ndo_siocdevprivate = airo_siocdevprivate,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-
-static struct net_device *_init_airo_card(unsigned short irq, int port,
- int is_pcmcia, struct pci_dev *pci,
- struct device *dmdev)
-{
- struct net_device *dev;
- struct airo_info *ai;
- int i, rc;
- CapabilityRid cap_rid;
-
- /* Create the network device object. */
- dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup);
- if (!dev) {
- airo_print_err("", "Couldn't alloc_etherdev");
- return NULL;
- }
-
- ai = dev->ml_priv = netdev_priv(dev);
- ai->wifidev = NULL;
- ai->flags = 1 << FLAG_RADIO_DOWN;
- ai->jobs = 0;
- ai->dev = dev;
- if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
- airo_print_dbg("", "Found an MPI350 card");
- set_bit(FLAG_MPI, &ai->flags);
- }
- spin_lock_init(&ai->aux_lock);
- sema_init(&ai->sem, 1);
- ai->config.len = 0;
- ai->pci = pci;
- init_waitqueue_head (&ai->thr_wait);
- ai->tfm = NULL;
- add_airo_dev(ai);
- ai->APList.len = cpu_to_le16(sizeof(struct APListRid));
-
- if (airo_networks_allocate (ai))
- goto err_out_free;
- airo_networks_initialize (ai);
-
- skb_queue_head_init (&ai->txq);
-
- /* The Airo-specific entries in the device structure. */
- if (test_bit(FLAG_MPI,&ai->flags))
- dev->netdev_ops = &mpi_netdev_ops;
- else
- dev->netdev_ops = &airo_netdev_ops;
- dev->wireless_handlers = &airo_handler_def;
- ai->wireless_data.spy_data = &ai->spy_data;
- dev->wireless_data = &ai->wireless_data;
- dev->irq = irq;
- dev->base_addr = port;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->max_mtu = MIC_MSGLEN_MAX;
-
- SET_NETDEV_DEV(dev, dmdev);
-
- reset_card (dev, 1);
- msleep(400);
-
- if (!is_pcmcia) {
- if (!request_region(dev->base_addr, 64, DRV_NAME)) {
- rc = -EBUSY;
- airo_print_err(dev->name, "Couldn't request region");
- goto err_out_nets;
- }
- }
-
- if (test_bit(FLAG_MPI,&ai->flags)) {
- if (mpi_map_card(ai, pci)) {
- airo_print_err("", "Could not map memory");
- goto err_out_res;
- }
- }
-
- if (probe) {
- if (setup_card(ai, dev, 1) != SUCCESS) {
- airo_print_err(dev->name, "MAC could not be enabled");
- rc = -EIO;
- goto err_out_map;
- }
- } else if (!test_bit(FLAG_MPI,&ai->flags)) {
- ai->bap_read = fast_bap_read;
- set_bit(FLAG_FLASHING, &ai->flags);
- }
-
- strcpy(dev->name, "eth%d");
- rc = register_netdev(dev);
- if (rc) {
- airo_print_err(dev->name, "Couldn't register_netdev");
- goto err_out_map;
- }
- ai->wifidev = init_wifidev(ai, dev);
- if (!ai->wifidev)
- goto err_out_reg;
-
- rc = readCapabilityRid(ai, &cap_rid, 1);
- if (rc != SUCCESS) {
- rc = -EIO;
- goto err_out_wifi;
- }
- /* WEP capability discovery */
- ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0;
- ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0;
-
- airo_print_info(dev->name, "Firmware version %x.%x.%02d",
- ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF),
- (le16_to_cpu(cap_rid.softVer) & 0xFF),
- le16_to_cpu(cap_rid.softSubVer));
-
- /* Test for WPA support */
- /* Only firmware versions 5.30.17 or better can do WPA */
- if (le16_to_cpu(cap_rid.softVer) > 0x530
- || (le16_to_cpu(cap_rid.softVer) == 0x530
- && le16_to_cpu(cap_rid.softSubVer) >= 17)) {
- airo_print_info(ai->dev->name, "WPA supported.");
-
- set_bit(FLAG_WPA_CAPABLE, &ai->flags);
- ai->bssListFirst = RID_WPA_BSSLISTFIRST;
- ai->bssListNext = RID_WPA_BSSLISTNEXT;
- ai->bssListRidLen = sizeof(BSSListRid);
- } else {
- airo_print_info(ai->dev->name, "WPA unsupported with firmware "
- "versions older than 5.30.17.");
-
- ai->bssListFirst = RID_BSSLISTFIRST;
- ai->bssListNext = RID_BSSLISTNEXT;
- ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
- }
-
- set_bit(FLAG_REGISTERED,&ai->flags);
- airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
-
- /* Allocate the transmit buffers */
- if (probe && !test_bit(FLAG_MPI,&ai->flags))
- for (i = 0; i < MAX_FIDS; i++)
- ai->fids[i] = transmit_allocate(ai, AIRO_DEF_MTU, i>=MAX_FIDS/2);
-
- if (setup_proc_entry(dev, dev->ml_priv) < 0)
- goto err_out_wifi;
-
- return dev;
-
-err_out_wifi:
- unregister_netdev(ai->wifidev);
- free_netdev(ai->wifidev);
-err_out_reg:
- unregister_netdev(dev);
-err_out_map:
- if (test_bit(FLAG_MPI,&ai->flags) && pci) {
- dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared,
- ai->shared_dma);
- iounmap(ai->pciaux);
- iounmap(ai->pcimem);
- mpi_unmap_card(ai->pci);
- }
-err_out_res:
- if (!is_pcmcia)
- release_region(dev->base_addr, 64);
-err_out_nets:
- airo_networks_free(ai);
-err_out_free:
- del_airo_dev(ai);
- free_netdev(dev);
- return NULL;
-}
-
-struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia,
- struct device *dmdev)
-{
- return _init_airo_card (irq, port, is_pcmcia, NULL, dmdev);
-}
-
-EXPORT_SYMBOL(init_airo_card);
-
-static int waitbusy (struct airo_info *ai)
-{
- int delay = 0;
- while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) {
- udelay (10);
- if ((++delay % 20) == 0)
- OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- }
- return delay < 10000;
-}
-
-int reset_airo_card(struct net_device *dev)
-{
- int i;
- struct airo_info *ai = dev->ml_priv;
-
- if (reset_card (dev, 1))
- return -1;
-
- if (setup_card(ai, dev, 1) != SUCCESS) {
- airo_print_err(dev->name, "MAC could not be enabled");
- return -1;
- }
- airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
- /* Allocate the transmit buffers if needed */
- if (!test_bit(FLAG_MPI,&ai->flags))
- for (i = 0; i < MAX_FIDS; i++)
- ai->fids[i] = transmit_allocate (ai, AIRO_DEF_MTU, i>=MAX_FIDS/2);
-
- enable_interrupts(ai);
- netif_wake_queue(dev);
- return 0;
-}
-
-EXPORT_SYMBOL(reset_airo_card);
-
-static void airo_send_event(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
- union iwreq_data wrqu;
- StatusRid status_rid;
-
- clear_bit(JOB_EVENT, &ai->jobs);
- PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
- up(&ai->sem);
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void airo_process_scan_results (struct airo_info *ai)
-{
- union iwreq_data wrqu;
- BSSListRid bss;
- int rc;
- BSSListElement * loop_net;
- BSSListElement * tmp_net;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
- list_move_tail (&loop_net->list, &ai->network_free_list);
- /* Don't blow away ->list, just BSS data */
- memset (loop_net, 0, sizeof (loop_net->bss));
- }
-
- /* Try to read the first entry of the scan result */
- rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
- if ((rc) || (bss.index == cpu_to_le16(0xffff))) {
- /* No scan results */
- goto out;
- }
-
- /* Read and parse all entries */
- tmp_net = NULL;
- while ((!rc) && (bss.index != cpu_to_le16(0xffff))) {
- /* Grab a network off the free list */
- if (!list_empty(&ai->network_free_list)) {
- tmp_net = list_entry(ai->network_free_list.next,
- BSSListElement, list);
- list_del(ai->network_free_list.next);
- }
-
- if (tmp_net != NULL) {
- memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
- list_add_tail(&tmp_net->list, &ai->network_list);
- tmp_net = NULL;
- }
-
- /* Read next entry */
- rc = PC4500_readrid(ai, ai->bssListNext,
- &bss, ai->bssListRidLen, 0);
- }
-
-out:
- /* write APList back (we cleared it in airo_set_scan) */
- disable_MAC(ai, 2);
- writeAPListRid(ai, &ai->APList, 0);
- enable_MAC(ai, 0);
-
- ai->scan_timeout = 0;
- clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
- up(&ai->sem);
-
- /* Send an empty event to user space.
- * We don't send the received data on
- * the event because it would require
- * us to do complex transcoding, and
- * we want to minimise the work done in
- * the irq handler. Use a request to
- * extract the data - Jean II */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static int airo_thread(void *data)
-{
- struct net_device *dev = data;
- struct airo_info *ai = dev->ml_priv;
- int locked;
-
- set_freezable();
- while (1) {
- /* make swsusp happy with our thread */
- try_to_freeze();
-
- if (test_bit(JOB_DIE, &ai->jobs))
- break;
-
- if (ai->jobs) {
- locked = down_interruptible(&ai->sem);
- } else {
- wait_queue_entry_t wait;
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&ai->thr_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (ai->jobs)
- break;
- if (ai->expires || ai->scan_timeout) {
- if (ai->scan_timeout &&
- time_after_eq(jiffies, ai->scan_timeout)) {
- set_bit(JOB_SCAN_RESULTS, &ai->jobs);
- break;
- } else if (ai->expires &&
- time_after_eq(jiffies, ai->expires)) {
- set_bit(JOB_AUTOWEP, &ai->jobs);
- break;
- }
- if (!kthread_should_stop() &&
- !freezing(current)) {
- unsigned long wake_at;
- if (!ai->expires || !ai->scan_timeout) {
- wake_at = max(ai->expires,
- ai->scan_timeout);
- } else {
- wake_at = min(ai->expires,
- ai->scan_timeout);
- }
- schedule_timeout(wake_at - jiffies);
- continue;
- }
- } else if (!kthread_should_stop() &&
- !freezing(current)) {
- schedule();
- continue;
- }
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&ai->thr_wait, &wait);
- locked = 1;
- }
-
- if (locked)
- continue;
-
- if (test_bit(JOB_DIE, &ai->jobs)) {
- up(&ai->sem);
- break;
- }
-
- if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
- up(&ai->sem);
- continue;
- }
-
- if (test_bit(JOB_XMIT, &ai->jobs))
- airo_end_xmit(dev, true);
- else if (test_bit(JOB_XMIT11, &ai->jobs))
- airo_end_xmit11(dev, true);
- else if (test_bit(JOB_STATS, &ai->jobs))
- airo_read_stats(dev);
- else if (test_bit(JOB_PROMISC, &ai->jobs))
- airo_set_promisc(ai, true);
- else if (test_bit(JOB_MIC, &ai->jobs))
- micinit(ai);
- else if (test_bit(JOB_EVENT, &ai->jobs))
- airo_send_event(dev);
- else if (test_bit(JOB_AUTOWEP, &ai->jobs))
- timer_func(dev);
- else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
- airo_process_scan_results(ai);
- else /* Shouldn't get here, but we make sure to unlock */
- up(&ai->sem);
- }
-
- return 0;
-}
-
-static int header_len(__le16 ctl)
-{
- u16 fc = le16_to_cpu(ctl);
- switch (fc & 0xc) {
- case 4:
- if ((fc & 0xe0) == 0xc0)
- return 10; /* one-address control packet */
- return 16; /* two-address control packet */
- case 8:
- if ((fc & 0x300) == 0x300)
- return 30; /* WDS packet */
- }
- return 24;
-}
-
-static void airo_handle_cisco_mic(struct airo_info *ai)
-{
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) {
- set_bit(JOB_MIC, &ai->jobs);
- wake_up_interruptible(&ai->thr_wait);
- }
-}
-
-/* Airo Status codes */
-#define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */
-#define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */
-#define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
-#define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */
-#define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
-#define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */
-#define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */
-#define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */
-#define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */
-#define STAT_ASSOC 0x0400 /* Associated */
-#define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */
-
-static void airo_print_status(const char *devname, u16 status)
-{
- u8 reason = status & 0xFF;
-
- switch (status & 0xFF00) {
- case STAT_NOBEACON:
- switch (status) {
- case STAT_NOBEACON:
- airo_print_dbg(devname, "link lost (missed beacons)");
- break;
- case STAT_MAXRETRIES:
- case STAT_MAXARL:
- airo_print_dbg(devname, "link lost (max retries)");
- break;
- case STAT_FORCELOSS:
- airo_print_dbg(devname, "link lost (local choice)");
- break;
- case STAT_TSFSYNC:
- airo_print_dbg(devname, "link lost (TSF sync lost)");
- break;
- default:
- airo_print_dbg(devname, "unknown status %x\n", status);
- break;
- }
- break;
- case STAT_DEAUTH:
- airo_print_dbg(devname, "deauthenticated (reason: %d)", reason);
- break;
- case STAT_DISASSOC:
- airo_print_dbg(devname, "disassociated (reason: %d)", reason);
- break;
- case STAT_ASSOC_FAIL:
- airo_print_dbg(devname, "association failed (reason: %d)",
- reason);
- break;
- case STAT_AUTH_FAIL:
- airo_print_dbg(devname, "authentication failed (reason: %d)",
- reason);
- break;
- case STAT_ASSOC:
- case STAT_REASSOC:
- break;
- default:
- airo_print_dbg(devname, "unknown status %x\n", status);
- break;
- }
-}
-
-static void airo_handle_link(struct airo_info *ai)
-{
- union iwreq_data wrqu;
- int scan_forceloss = 0;
- u16 status;
-
- /* Get new status and acknowledge the link change */
- status = le16_to_cpu(IN4500(ai, LINKSTAT));
- OUT4500(ai, EVACK, EV_LINK);
-
- if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0))
- scan_forceloss = 1;
-
- airo_print_status(ai->dev->name, status);
-
- if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) {
- if (auto_wep)
- ai->expires = 0;
- if (ai->list_bss_task)
- wake_up_process(ai->list_bss_task);
- set_bit(FLAG_UPDATE_UNI, &ai->flags);
- set_bit(FLAG_UPDATE_MULTI, &ai->flags);
-
- set_bit(JOB_EVENT, &ai->jobs);
- wake_up_interruptible(&ai->thr_wait);
-
- netif_carrier_on(ai->dev);
- } else if (!scan_forceloss) {
- if (auto_wep && !ai->expires) {
- ai->expires = RUN_AT(3*HZ);
- wake_up_interruptible(&ai->thr_wait);
- }
-
- /* Send event to user space */
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL);
- netif_carrier_off(ai->dev);
- } else {
- netif_carrier_off(ai->dev);
- }
-}
-
-static void airo_handle_rx(struct airo_info *ai)
-{
- struct sk_buff *skb = NULL;
- __le16 fc, v, *buffer, tmpbuf[4];
- u16 len, hdrlen = 0, gap, fid;
- struct rx_hdr hdr;
- int success = 0;
-
- if (test_bit(FLAG_MPI, &ai->flags)) {
- if (test_bit(FLAG_802_11, &ai->flags))
- mpi_receive_802_11(ai);
- else
- mpi_receive_802_3(ai);
- OUT4500(ai, EVACK, EV_RX);
- return;
- }
-
- fid = IN4500(ai, RXFID);
-
- /* Get the packet length */
- if (test_bit(FLAG_802_11, &ai->flags)) {
- bap_setup (ai, fid, 4, BAP0);
- bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0);
- /* Bad CRC. Ignore packet */
- if (le16_to_cpu(hdr.status) & 2)
- hdr.len = 0;
- if (ai->wifidev == NULL)
- hdr.len = 0;
- } else {
- bap_setup(ai, fid, 0x36, BAP0);
- bap_read(ai, &hdr.len, 2, BAP0);
- }
- len = le16_to_cpu(hdr.len);
-
- if (len > AIRO_DEF_MTU) {
- airo_print_err(ai->dev->name, "Bad size %d", len);
- goto done;
- }
- if (len == 0)
- goto done;
-
- if (test_bit(FLAG_802_11, &ai->flags)) {
- bap_read(ai, &fc, sizeof (fc), BAP0);
- hdrlen = header_len(fc);
- } else
- hdrlen = ETH_ALEN * 2;
-
- skb = dev_alloc_skb(len + hdrlen + 2 + 2);
- if (!skb) {
- ai->dev->stats.rx_dropped++;
- goto done;
- }
-
- skb_reserve(skb, 2); /* This way the IP header is aligned */
- buffer = skb_put(skb, len + hdrlen);
- if (test_bit(FLAG_802_11, &ai->flags)) {
- buffer[0] = fc;
- bap_read(ai, buffer + 1, hdrlen - 2, BAP0);
- if (hdrlen == 24)
- bap_read(ai, tmpbuf, 6, BAP0);
-
- bap_read(ai, &v, sizeof(v), BAP0);
- gap = le16_to_cpu(v);
- if (gap) {
- if (gap <= 8) {
- bap_read(ai, tmpbuf, gap, BAP0);
- } else {
- airo_print_err(ai->dev->name, "gaplen too "
- "big. Problems will follow...");
- }
- }
- bap_read(ai, buffer + hdrlen/2, len, BAP0);
- } else {
- MICBuffer micbuf;
-
- bap_read(ai, buffer, ETH_ALEN * 2, BAP0);
- if (ai->micstats.enabled) {
- bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0);
- if (ntohs(micbuf.typelen) > 0x05DC)
- bap_setup(ai, fid, 0x44, BAP0);
- else {
- if (len <= sizeof (micbuf)) {
- dev_kfree_skb_irq(skb);
- goto done;
- }
-
- len -= sizeof(micbuf);
- skb_trim(skb, len + hdrlen);
- }
- }
-
- bap_read(ai, buffer + ETH_ALEN, len, BAP0);
- if (decapsulate(ai, &micbuf, (etherHead*) buffer, len))
- dev_kfree_skb_irq (skb);
- else
- success = 1;
- }
-
-#ifdef WIRELESS_SPY
- if (success && (ai->spy_data.spy_number > 0)) {
- char *sa;
- struct iw_quality wstats;
-
- /* Prepare spy data : addr + qual */
- if (!test_bit(FLAG_802_11, &ai->flags)) {
- sa = (char *) buffer + 6;
- bap_setup(ai, fid, 8, BAP0);
- bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0);
- } else
- sa = (char *) buffer + 10;
- wstats.qual = hdr.rssi[0];
- if (ai->rssi)
- wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
- else
- wstats.level = (hdr.rssi[1] + 321) / 2;
- wstats.noise = ai->wstats.qual.noise;
- wstats.updated = IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_QUAL_UPDATED
- | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(ai->dev, sa, &wstats);
- }
-#endif /* WIRELESS_SPY */
-
-done:
- OUT4500(ai, EVACK, EV_RX);
-
- if (success) {
- if (test_bit(FLAG_802_11, &ai->flags)) {
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->dev = ai->wifidev;
- skb->protocol = htons(ETH_P_802_2);
- } else
- skb->protocol = eth_type_trans(skb, ai->dev);
- skb->ip_summed = CHECKSUM_NONE;
-
- netif_rx(skb);
- }
-}
-
-static void airo_handle_tx(struct airo_info *ai, u16 status)
-{
- int i, index = -1;
- u16 fid;
-
- if (test_bit(FLAG_MPI, &ai->flags)) {
- unsigned long flags;
-
- if (status & EV_TXEXC)
- get_tx_error(ai, -1);
-
- spin_lock_irqsave(&ai->aux_lock, flags);
- if (!skb_queue_empty(&ai->txq)) {
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- mpi_send_packet(ai->dev);
- } else {
- clear_bit(FLAG_PENDING_XMIT, &ai->flags);
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- netif_wake_queue(ai->dev);
- }
- OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
- return;
- }
-
- fid = IN4500(ai, TXCOMPLFID);
-
- for (i = 0; i < MAX_FIDS; i++) {
- if ((ai->fids[i] & 0xffff) == fid)
- index = i;
- }
-
- if (index != -1) {
- if (status & EV_TXEXC)
- get_tx_error(ai, index);
-
- OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC));
-
- /* Set up to be used again */
- ai->fids[index] &= 0xffff;
- if (index < MAX_FIDS / 2) {
- if (!test_bit(FLAG_PENDING_XMIT, &ai->flags))
- netif_wake_queue(ai->dev);
- } else {
- if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags))
- netif_wake_queue(ai->wifidev);
- }
- } else {
- OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
- airo_print_err(ai->dev->name, "Unallocated FID was used to xmit");
- }
-}
-
-static irqreturn_t airo_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- u16 status, savedInterrupts = 0;
- struct airo_info *ai = dev->ml_priv;
- int handled = 0;
-
- if (!netif_device_present(dev))
- return IRQ_NONE;
-
- for (;;) {
- status = IN4500(ai, EVSTAT);
- if (!(status & STATUS_INTS) || (status == 0xffff))
- break;
-
- handled = 1;
-
- if (status & EV_AWAKE) {
- OUT4500(ai, EVACK, EV_AWAKE);
- OUT4500(ai, EVACK, EV_AWAKE);
- }
-
- if (!savedInterrupts) {
- savedInterrupts = IN4500(ai, EVINTEN);
- OUT4500(ai, EVINTEN, 0);
- }
-
- if (status & EV_MIC) {
- OUT4500(ai, EVACK, EV_MIC);
- airo_handle_cisco_mic(ai);
- }
-
- if (status & EV_LINK) {
- /* Link status changed */
- airo_handle_link(ai);
- }
-
- /* Check to see if there is something to receive */
- if (status & EV_RX)
- airo_handle_rx(ai);
-
- /* Check to see if a packet has been transmitted */
- if (status & (EV_TX | EV_TXCPY | EV_TXEXC))
- airo_handle_tx(ai, status);
-
- if (status & ~STATUS_INTS & ~IGNORE_INTS) {
- airo_print_warn(ai->dev->name, "Got weird status %x",
- status & ~STATUS_INTS & ~IGNORE_INTS);
- }
- }
-
- if (savedInterrupts)
- OUT4500(ai, EVINTEN, savedInterrupts);
-
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Routines to talk to the card
- */
-
-/*
- * This was originally written for the 4500, hence the name
- * NOTE: If use with 8bit mode and SMP bad things will happen!
- * Why would some one do 8 bit IO in an SMP machine?!?
- */
-static void OUT4500(struct airo_info *ai, u16 reg, u16 val)
-{
- if (test_bit(FLAG_MPI,&ai->flags))
- reg <<= 1;
- if (!do8bitIO)
- outw(val, ai->dev->base_addr + reg);
- else {
- outb(val & 0xff, ai->dev->base_addr + reg);
- outb(val >> 8, ai->dev->base_addr + reg + 1);
- }
-}
-
-static u16 IN4500(struct airo_info *ai, u16 reg)
-{
- unsigned short rc;
-
- if (test_bit(FLAG_MPI,&ai->flags))
- reg <<= 1;
- if (!do8bitIO)
- rc = inw(ai->dev->base_addr + reg);
- else {
- rc = inb(ai->dev->base_addr + reg);
- rc += ((int)inb(ai->dev->base_addr + reg + 1)) << 8;
- }
- return rc;
-}
-
-static int enable_MAC(struct airo_info *ai, int lock)
-{
- int rc;
- Cmd cmd;
- Resp rsp;
-
- /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
- * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
- * Note : we could try to use !netif_running(dev) in enable_MAC()
- * instead of this flag, but I don't trust it *within* the
- * open/close functions, and testing both flags together is
- * "cheaper" - Jean II */
- if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
-
- if (lock && down_interruptible(&ai->sem))
- return -ERESTARTSYS;
-
- if (!test_bit(FLAG_ENABLED, &ai->flags)) {
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = MAC_ENABLE;
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc == SUCCESS)
- set_bit(FLAG_ENABLED, &ai->flags);
- } else
- rc = SUCCESS;
-
- if (lock)
- up(&ai->sem);
-
- if (rc)
- airo_print_err(ai->dev->name, "Cannot enable MAC");
- else if ((rsp.status & 0xFF00) != 0) {
- airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
- "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
- rc = ERROR;
- }
- return rc;
-}
-
-static void disable_MAC(struct airo_info *ai, int lock)
-{
- Cmd cmd;
- Resp rsp;
-
- if (lock == 1 && down_interruptible(&ai->sem))
- return;
-
- if (test_bit(FLAG_ENABLED, &ai->flags)) {
- if (lock != 2) /* lock == 2 means don't disable carrier */
- netif_carrier_off(ai->dev);
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = MAC_DISABLE; // disable in case already enabled
- issuecommand(ai, &cmd, &rsp, true);
- clear_bit(FLAG_ENABLED, &ai->flags);
- }
- if (lock == 1)
- up(&ai->sem);
-}
-
-static void enable_interrupts(struct airo_info *ai)
-{
- /* Enable the interrupts */
- OUT4500(ai, EVINTEN, STATUS_INTS);
-}
-
-static void disable_interrupts(struct airo_info *ai)
-{
- OUT4500(ai, EVINTEN, 0);
-}
-
-static void mpi_receive_802_3(struct airo_info *ai)
-{
- RxFid rxd;
- int len = 0;
- struct sk_buff *skb;
- char *buffer;
- int off = 0;
- MICBuffer micbuf;
-
- memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
- /* Make sure we got something */
- if (rxd.rdy && rxd.valid == 0) {
- len = rxd.len + 12;
- if (len < 12 || len > 2048)
- goto badrx;
-
- skb = dev_alloc_skb(len);
- if (!skb) {
- ai->dev->stats.rx_dropped++;
- goto badrx;
- }
- buffer = skb_put(skb, len);
- memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
- if (ai->micstats.enabled) {
- memcpy(&micbuf,
- ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
- sizeof(micbuf));
- if (ntohs(micbuf.typelen) <= 0x05DC) {
- if (len <= sizeof(micbuf) + ETH_ALEN * 2)
- goto badmic;
-
- off = sizeof(micbuf);
- skb_trim (skb, len - off);
- }
- }
- memcpy(buffer + ETH_ALEN * 2,
- ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
- len - ETH_ALEN * 2 - off);
- if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
-badmic:
- dev_kfree_skb_irq (skb);
- goto badrx;
- }
-#ifdef WIRELESS_SPY
- if (ai->spy_data.spy_number > 0) {
- char *sa;
- struct iw_quality wstats;
- /* Prepare spy data : addr + qual */
- sa = buffer + ETH_ALEN;
- wstats.qual = 0; /* XXX Where do I get that info from ??? */
- wstats.level = 0;
- wstats.updated = 0;
- /* Update spy records */
- wireless_spy_update(ai->dev, sa, &wstats);
- }
-#endif /* WIRELESS_SPY */
-
- skb->ip_summed = CHECKSUM_NONE;
- skb->protocol = eth_type_trans(skb, ai->dev);
- netif_rx(skb);
- }
-badrx:
- if (rxd.valid == 0) {
- rxd.valid = 1;
- rxd.rdy = 0;
- rxd.len = PKTSIZE;
- memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
- }
-}
-
-static void mpi_receive_802_11(struct airo_info *ai)
-{
- RxFid rxd;
- struct sk_buff *skb = NULL;
- u16 len, hdrlen = 0;
- __le16 fc;
- struct rx_hdr hdr;
- u16 gap;
- u16 *buffer;
- char *ptr = ai->rxfids[0].virtual_host_addr + 4;
-
- memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
- memcpy ((char *)&hdr, ptr, sizeof(hdr));
- ptr += sizeof(hdr);
- /* Bad CRC. Ignore packet */
- if (le16_to_cpu(hdr.status) & 2)
- hdr.len = 0;
- if (ai->wifidev == NULL)
- hdr.len = 0;
- len = le16_to_cpu(hdr.len);
- if (len > AIRO_DEF_MTU) {
- airo_print_err(ai->dev->name, "Bad size %d", len);
- goto badrx;
- }
- if (len == 0)
- goto badrx;
-
- fc = get_unaligned((__le16 *)ptr);
- hdrlen = header_len(fc);
-
- skb = dev_alloc_skb(len + hdrlen + 2);
- if (!skb) {
- ai->dev->stats.rx_dropped++;
- goto badrx;
- }
- buffer = skb_put(skb, len + hdrlen);
- memcpy ((char *)buffer, ptr, hdrlen);
- ptr += hdrlen;
- if (hdrlen == 24)
- ptr += 6;
- gap = get_unaligned_le16(ptr);
- ptr += sizeof(__le16);
- if (gap) {
- if (gap <= 8)
- ptr += gap;
- else
- airo_print_err(ai->dev->name,
- "gaplen too big. Problems will follow...");
- }
- memcpy ((char *)buffer + hdrlen, ptr, len);
- ptr += len;
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- if (ai->spy_data.spy_number > 0) {
- char *sa;
- struct iw_quality wstats;
- /* Prepare spy data : addr + qual */
- sa = (char*)buffer + 10;
- wstats.qual = hdr.rssi[0];
- if (ai->rssi)
- wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
- else
- wstats.level = (hdr.rssi[1] + 321) / 2;
- wstats.noise = ai->wstats.qual.noise;
- wstats.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(ai->dev, sa, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->dev = ai->wifidev;
- skb->protocol = htons(ETH_P_802_2);
- skb->ip_summed = CHECKSUM_NONE;
- netif_rx(skb);
-
-badrx:
- if (rxd.valid == 0) {
- rxd.valid = 1;
- rxd.rdy = 0;
- rxd.len = PKTSIZE;
- memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
- }
-}
-
-static inline void set_auth_type(struct airo_info *local, int auth_type)
-{
- local->config.authType = auth_type;
- /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT).
- * Used by airo_set_auth()
- */
- if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT)
- local->last_auth = auth_type;
-}
-
-static int noinline_for_stack airo_readconfig(struct airo_info *ai,
- struct net_device *dev, int lock)
-{
- int i, status;
- /* large variables, so don't inline this function,
- * maybe change to kmalloc
- */
- tdsRssiRid rssi_rid;
- CapabilityRid cap_rid;
-
- kfree(ai->SSID);
- ai->SSID = NULL;
- // general configuration (read/modify/write)
- status = readConfigRid(ai, lock);
- if (status != SUCCESS) return ERROR;
-
- status = readCapabilityRid(ai, &cap_rid, lock);
- if (status != SUCCESS) return ERROR;
-
- status = PC4500_readrid(ai, RID_RSSI, &rssi_rid, sizeof(rssi_rid), lock);
- if (status == SUCCESS) {
- if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
- memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
- }
- else {
- kfree(ai->rssi);
- ai->rssi = NULL;
- if (cap_rid.softCap & cpu_to_le16(8))
- ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
- else
- airo_print_warn(ai->dev->name, "unknown received signal "
- "level scale");
- }
- ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
- set_auth_type(ai, AUTH_OPEN);
- ai->config.modulation = MOD_CCK;
-
- if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) &&
- (cap_rid.extSoftCap & cpu_to_le16(1)) &&
- micsetup(ai) == SUCCESS) {
- ai->config.opmode |= MODE_MIC;
- set_bit(FLAG_MIC_CAPABLE, &ai->flags);
- }
-
- /* Save off the MAC */
- eth_hw_addr_set(dev, ai->config.macAddr);
-
- /* Check to see if there are any insmod configured
- rates to add */
- if (rates[0]) {
- memset(ai->config.rates, 0, sizeof(ai->config.rates));
- for (i = 0; i < 8 && rates[i]; i++) {
- ai->config.rates[i] = rates[i];
- }
- }
- set_bit (FLAG_COMMIT, &ai->flags);
-
- return SUCCESS;
-}
-
-
-static u16 setup_card(struct airo_info *ai, struct net_device *dev, int lock)
-{
- Cmd cmd;
- Resp rsp;
- int status;
- SsidRid mySsid;
- __le16 lastindex;
- WepKeyRid wkr;
- int rc;
-
- memset(&mySsid, 0, sizeof(mySsid));
- kfree (ai->flash);
- ai->flash = NULL;
-
- /* The NOP is the first step in getting the card going */
- cmd.cmd = NOP;
- cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
- if (lock && down_interruptible(&ai->sem))
- return ERROR;
- if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
- if (lock)
- up(&ai->sem);
- return ERROR;
- }
- disable_MAC(ai, 0);
-
- // Let's figure out if we need to use the AUX port
- if (!test_bit(FLAG_MPI,&ai->flags)) {
- cmd.cmd = CMD_ENABLEAUX;
- if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
- if (lock)
- up(&ai->sem);
- airo_print_err(ai->dev->name, "Error checking for AUX port");
- return ERROR;
- }
- if (!aux_bap || rsp.status & 0xff00) {
- ai->bap_read = fast_bap_read;
- airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
- } else {
- ai->bap_read = aux_bap_read;
- airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
- }
- }
- if (lock)
- up(&ai->sem);
- if (ai->config.len == 0) {
- status = airo_readconfig(ai, dev, lock);
- if (status != SUCCESS)
- return ERROR;
- }
-
- /* Setup the SSIDs if present */
- if (ssids[0]) {
- int i;
- for (i = 0; i < 3 && ssids[i]; i++) {
- size_t len = strlen(ssids[i]);
- if (len > 32)
- len = 32;
- mySsid.ssids[i].len = cpu_to_le16(len);
- memcpy(mySsid.ssids[i].ssid, ssids[i], len);
- }
- mySsid.len = cpu_to_le16(sizeof(mySsid));
- }
-
- status = writeConfigRid(ai, lock);
- if (status != SUCCESS) return ERROR;
-
- /* Set up the SSID list */
- if (ssids[0]) {
- status = writeSsidRid(ai, &mySsid, lock);
- if (status != SUCCESS) return ERROR;
- }
-
- status = enable_MAC(ai, lock);
- if (status != SUCCESS)
- return ERROR;
-
- /* Grab the initial wep key, we gotta save it for auto_wep */
- rc = readWepKeyRid(ai, &wkr, 1, lock);
- if (rc == SUCCESS) do {
- lastindex = wkr.kindex;
- if (wkr.kindex == cpu_to_le16(0xffff)) {
- ai->defindex = wkr.mac[0];
- }
- rc = readWepKeyRid(ai, &wkr, 0, lock);
- } while (lastindex != wkr.kindex);
-
- try_auto_wep(ai);
-
- return SUCCESS;
-}
-
-static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp,
- bool may_sleep)
-{
- // Im really paranoid about letting it run forever!
- int max_tries = 600000;
-
- if (IN4500(ai, EVSTAT) & EV_CMD)
- OUT4500(ai, EVACK, EV_CMD);
-
- OUT4500(ai, PARAM0, pCmd->parm0);
- OUT4500(ai, PARAM1, pCmd->parm1);
- OUT4500(ai, PARAM2, pCmd->parm2);
- OUT4500(ai, COMMAND, pCmd->cmd);
-
- while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
- if ((IN4500(ai, COMMAND)) == pCmd->cmd)
- // PC4500 didn't notice command, try again
- OUT4500(ai, COMMAND, pCmd->cmd);
- if (may_sleep && (max_tries & 255) == 0)
- cond_resched();
- }
-
- if (max_tries == -1) {
- airo_print_err(ai->dev->name,
- "Max tries exceeded when issuing command");
- if (IN4500(ai, COMMAND) & COMMAND_BUSY)
- OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- return ERROR;
- }
-
- // command completed
- pRsp->status = IN4500(ai, STATUS);
- pRsp->rsp0 = IN4500(ai, RESP0);
- pRsp->rsp1 = IN4500(ai, RESP1);
- pRsp->rsp2 = IN4500(ai, RESP2);
- if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
- airo_print_err(ai->dev->name,
- "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
- pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
- pRsp->rsp2);
-
- // clear stuck command busy if necessary
- if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
- OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- }
- // acknowledge processing the status/response
- OUT4500(ai, EVACK, EV_CMD);
-
- return SUCCESS;
-}
-
-/* Sets up the bap to start exchange data. whichbap should
- * be one of the BAP0 or BAP1 defines. Locks should be held before
- * calling! */
-static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap)
-{
- int timeout = 50;
- int max_tries = 3;
-
- OUT4500(ai, SELECT0+whichbap, rid);
- OUT4500(ai, OFFSET0+whichbap, offset);
- while (1) {
- int status = IN4500(ai, OFFSET0+whichbap);
- if (status & BAP_BUSY) {
- /* This isn't really a timeout, but its kinda
- close */
- if (timeout--) {
- continue;
- }
- } else if (status & BAP_ERR) {
- /* invalid rid or offset */
- airo_print_err(ai->dev->name, "BAP error %x %d",
- status, whichbap);
- return ERROR;
- } else if (status & BAP_DONE) { // success
- return SUCCESS;
- }
- if (!(max_tries--)) {
- airo_print_err(ai->dev->name,
- "BAP setup error too many retries\n");
- return ERROR;
- }
- // -- PC4500 missed it, try again
- OUT4500(ai, SELECT0+whichbap, rid);
- OUT4500(ai, OFFSET0+whichbap, offset);
- timeout = 50;
- }
-}
-
-/* should only be called by aux_bap_read. This aux function and the
- following use concepts not documented in the developers guide. I
- got them from a patch given to my by Aironet */
-static u16 aux_setup(struct airo_info *ai, u16 page,
- u16 offset, u16 *len)
-{
- u16 next;
-
- OUT4500(ai, AUXPAGE, page);
- OUT4500(ai, AUXOFF, 0);
- next = IN4500(ai, AUXDATA);
- *len = IN4500(ai, AUXDATA)&0xff;
- if (offset != 4) OUT4500(ai, AUXOFF, offset);
- return next;
-}
-
-/* requires call to bap_setup() first */
-static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst,
- int bytelen, int whichbap)
-{
- u16 len;
- u16 page;
- u16 offset;
- u16 next;
- int words;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&ai->aux_lock, flags);
- page = IN4500(ai, SWS0+whichbap);
- offset = IN4500(ai, SWS2+whichbap);
- next = aux_setup(ai, page, offset, &len);
- words = (bytelen+1)>>1;
-
- for (i = 0; i<words;) {
- int count;
- count = (len>>1) < (words-i) ? (len>>1) : (words-i);
- if (!do8bitIO)
- insw(ai->dev->base_addr+DATA0+whichbap,
- pu16Dst+i, count);
- else
- insb(ai->dev->base_addr+DATA0+whichbap,
- pu16Dst+i, count << 1);
- i += count;
- if (i<words) {
- next = aux_setup(ai, next, 4, &len);
- }
- }
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- return SUCCESS;
-}
-
-
-/* requires call to bap_setup() first */
-static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst,
- int bytelen, int whichbap)
-{
- bytelen = (bytelen + 1) & (~1); // round up to even value
- if (!do8bitIO)
- insw(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1);
- else
- insb(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen);
- return SUCCESS;
-}
-
-/* requires call to bap_setup() first */
-static int bap_write(struct airo_info *ai, const __le16 *pu16Src,
- int bytelen, int whichbap)
-{
- bytelen = (bytelen + 1) & (~1); // round up to even value
- if (!do8bitIO)
- outsw(ai->dev->base_addr+DATA0+whichbap,
- pu16Src, bytelen>>1);
- else
- outsb(ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen);
- return SUCCESS;
-}
-
-static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
-{
- Cmd cmd; /* for issuing commands */
- Resp rsp; /* response from commands */
- u16 status;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = accmd;
- cmd.parm0 = rid;
- status = issuecommand(ai, &cmd, &rsp, true);
- if (status != 0) return status;
- if ((rsp.status & 0x7F00) != 0) {
- return (accmd << 8) + (rsp.rsp0 & 0xFF);
- }
- return 0;
-}
-
-/* Note, that we are using BAP1 which is also used by transmit, so
- * we must get a lock. */
-static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
-{
- u16 status;
- int rc = SUCCESS;
-
- if (lock) {
- if (down_interruptible(&ai->sem))
- return ERROR;
- }
- if (test_bit(FLAG_MPI,&ai->flags)) {
- Cmd cmd;
- Resp rsp;
-
- memset(&cmd, 0, sizeof(cmd));
- memset(&rsp, 0, sizeof(rsp));
- ai->config_desc.rid_desc.valid = 1;
- ai->config_desc.rid_desc.len = RIDSIZE;
- ai->config_desc.rid_desc.rid = 0;
- ai->config_desc.rid_desc.host_addr = ai->ridbus;
-
- cmd.cmd = CMD_ACCESS;
- cmd.parm0 = rid;
-
- memcpy_toio(ai->config_desc.card_ram_off,
- &ai->config_desc.rid_desc, sizeof(Rid));
-
- rc = issuecommand(ai, &cmd, &rsp, true);
-
- if (rsp.status & 0x7f00)
- rc = rsp.rsp0;
- if (!rc)
- memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
- goto done;
- } else {
- if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
- rc = status;
- goto done;
- }
- if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
- rc = ERROR;
- goto done;
- }
- // read the rid length field
- bap_read(ai, pBuf, 2, BAP1);
- // length for remaining part of rid
- len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
-
- if (len <= 2) {
- airo_print_err(ai->dev->name,
- "Rid %x has a length of %d which is too short",
- (int)rid, (int)len);
- rc = ERROR;
- goto done;
- }
- // read remainder of the rid
- rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
- }
-done:
- if (lock)
- up(&ai->sem);
- return rc;
-}
-
-/* Note, that we are using BAP1 which is also used by transmit, so
- * make sure this isn't called when a transmit is happening */
-static int PC4500_writerid(struct airo_info *ai, u16 rid,
- const void *pBuf, int len, int lock)
-{
- u16 status;
- int rc = SUCCESS;
-
- *(__le16*)pBuf = cpu_to_le16((u16)len);
-
- if (lock) {
- if (down_interruptible(&ai->sem))
- return ERROR;
- }
- if (test_bit(FLAG_MPI,&ai->flags)) {
- Cmd cmd;
- Resp rsp;
-
- if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
- airo_print_err(ai->dev->name,
- "%s: MAC should be disabled (rid=%04x)",
- __func__, rid);
- memset(&cmd, 0, sizeof(cmd));
- memset(&rsp, 0, sizeof(rsp));
-
- ai->config_desc.rid_desc.valid = 1;
- ai->config_desc.rid_desc.len = *((u16 *)pBuf);
- ai->config_desc.rid_desc.rid = 0;
-
- cmd.cmd = CMD_WRITERID;
- cmd.parm0 = rid;
-
- memcpy_toio(ai->config_desc.card_ram_off,
- &ai->config_desc.rid_desc, sizeof(Rid));
-
- if (len < 4 || len > 2047) {
- airo_print_err(ai->dev->name, "%s: len=%d", __func__, len);
- rc = -1;
- } else {
- memcpy(ai->config_desc.virtual_host_addr,
- pBuf, len);
-
- rc = issuecommand(ai, &cmd, &rsp, true);
- if ((rc & 0xff00) != 0) {
- airo_print_err(ai->dev->name, "%s: Write rid Error %d",
- __func__, rc);
- airo_print_err(ai->dev->name, "%s: Cmd=%04x",
- __func__, cmd.cmd);
- }
-
- if ((rsp.status & 0x7f00))
- rc = rsp.rsp0;
- }
- } else {
- // --- first access so that we can write the rid data
- if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
- rc = status;
- goto done;
- }
- // --- now write the rid data
- if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
- rc = ERROR;
- goto done;
- }
- bap_write(ai, pBuf, len, BAP1);
- // ---now commit the rid data
- rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
- }
-done:
- if (lock)
- up(&ai->sem);
- return rc;
-}
-
-/* Allocates a FID to be used for transmitting packets. We only use
- one for now. */
-static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
-{
- unsigned int loop = 3000;
- Cmd cmd;
- Resp rsp;
- u16 txFid;
- __le16 txControl;
-
- cmd.cmd = CMD_ALLOCATETX;
- cmd.parm0 = lenPayload;
- if (down_interruptible(&ai->sem))
- return ERROR;
- if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
- txFid = ERROR;
- goto done;
- }
- if ((rsp.status & 0xFF00) != 0) {
- txFid = ERROR;
- goto done;
- }
- /* wait for the allocate event/indication
- * It makes me kind of nervous that this can just sit here and spin,
- * but in practice it only loops like four times. */
- while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
- if (!loop) {
- txFid = ERROR;
- goto done;
- }
-
- // get the allocated fid and acknowledge
- txFid = IN4500(ai, TXALLOCFID);
- OUT4500(ai, EVACK, EV_ALLOC);
-
- /* The CARD is pretty cool since it converts the ethernet packet
- * into 802.11. Also note that we don't release the FID since we
- * will be using the same one over and over again. */
- /* We only have to setup the control once since we are not
- * releasing the fid. */
- if (raw)
- txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
- | TXCTL_ETHERNET | TXCTL_NORELEASE);
- else
- txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
- | TXCTL_ETHERNET | TXCTL_NORELEASE);
- if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
- txFid = ERROR;
- else
- bap_write(ai, &txControl, sizeof(txControl), BAP1);
-
-done:
- up(&ai->sem);
-
- return txFid;
-}
-
-/* In general BAP1 is dedicated to transmiting packets. However,
- since we need a BAP when accessing RIDs, we also use BAP1 for that.
- Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket,
- bool may_sleep)
-{
- __le16 payloadLen;
- Cmd cmd;
- Resp rsp;
- int miclen = 0;
- u16 txFid = len;
- MICBuffer pMic;
-
- len >>= 16;
-
- if (len <= ETH_ALEN * 2) {
- airo_print_warn(ai->dev->name, "Short packet %d", len);
- return ERROR;
- }
- len -= ETH_ALEN * 2;
-
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
- (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
- if (encapsulate(ai, (etherHead *)pPacket,&pMic, len) != SUCCESS)
- return ERROR;
- miclen = sizeof(pMic);
- }
- // packet is destination[6], source[6], payload[len-12]
- // write the payload length and dst/src/payload
- if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
- /* The hardware addresses aren't counted as part of the payload, so
- * we have to subtract the 12 bytes for the addresses off */
- payloadLen = cpu_to_le16(len + miclen);
- bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1);
- bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1);
- if (miclen)
- bap_write(ai, (__le16*)&pMic, miclen, BAP1);
- bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1);
- // issue the transmit command
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_TRANSMIT;
- cmd.parm0 = txFid;
- if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS)
- return ERROR;
- if ((rsp.status & 0xFF00) != 0) return ERROR;
- return SUCCESS;
-}
-
-static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket,
- bool may_sleep)
-{
- __le16 fc, payloadLen;
- Cmd cmd;
- Resp rsp;
- int hdrlen;
- static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
- /* padding of header to full size + le16 gaplen (6) + gaplen bytes */
- u16 txFid = len;
- len >>= 16;
-
- fc = *(__le16*)pPacket;
- hdrlen = header_len(fc);
-
- if (len < hdrlen) {
- airo_print_warn(ai->dev->name, "Short packet %d", len);
- return ERROR;
- }
-
- /* packet is 802.11 header + payload
- * write the payload length and dst/src/payload */
- if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
- /* The 802.11 header aren't counted as part of the payload, so
- * we have to subtract the header bytes off */
- payloadLen = cpu_to_le16(len-hdrlen);
- bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1);
- if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
- bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1);
- bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
-
- bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1);
- // issue the transmit command
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_TRANSMIT;
- cmd.parm0 = txFid;
- if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS)
- return ERROR;
- if ((rsp.status & 0xFF00) != 0) return ERROR;
- return SUCCESS;
-}
-
-/*
- * This is the proc_fs routines. It is a bit messier than I would
- * like! Feel free to clean it up!
- */
-
-static ssize_t proc_read(struct file *file,
- char __user *buffer,
- size_t len,
- loff_t *offset);
-
-static ssize_t proc_write(struct file *file,
- const char __user *buffer,
- size_t len,
- loff_t *offset);
-static int proc_close(struct inode *inode, struct file *file);
-
-static int proc_stats_open(struct inode *inode, struct file *file);
-static int proc_statsdelta_open(struct inode *inode, struct file *file);
-static int proc_status_open(struct inode *inode, struct file *file);
-static int proc_SSID_open(struct inode *inode, struct file *file);
-static int proc_APList_open(struct inode *inode, struct file *file);
-static int proc_BSSList_open(struct inode *inode, struct file *file);
-static int proc_config_open(struct inode *inode, struct file *file);
-static int proc_wepkey_open(struct inode *inode, struct file *file);
-
-static const struct proc_ops proc_statsdelta_ops = {
- .proc_read = proc_read,
- .proc_open = proc_statsdelta_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_stats_ops = {
- .proc_read = proc_read,
- .proc_open = proc_stats_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_status_ops = {
- .proc_read = proc_read,
- .proc_open = proc_status_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_SSID_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_SSID_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_BSSList_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_BSSList_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_APList_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_APList_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_config_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_config_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_wepkey_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_wepkey_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static struct proc_dir_entry *airo_entry;
-
-struct proc_data {
- int release_buffer;
- int readlen;
- char *rbuffer;
- int writelen;
- int maxwritelen;
- char *wbuffer;
- void (*on_close) (struct inode *, struct file *);
-};
-
-static int setup_proc_entry(struct net_device *dev,
- struct airo_info *apriv)
-{
- struct proc_dir_entry *entry;
-
- /* First setup the device directory */
- strcpy(apriv->proc_name, dev->name);
- apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
- airo_entry);
- if (!apriv->proc_entry)
- return -ENOMEM;
- proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid);
-
- /* Setup the StatsDelta */
- entry = proc_create_data("StatsDelta", 0444 & proc_perm,
- apriv->proc_entry, &proc_statsdelta_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the Stats */
- entry = proc_create_data("Stats", 0444 & proc_perm,
- apriv->proc_entry, &proc_stats_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the Status */
- entry = proc_create_data("Status", 0444 & proc_perm,
- apriv->proc_entry, &proc_status_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the Config */
- entry = proc_create_data("Config", proc_perm,
- apriv->proc_entry, &proc_config_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the SSID */
- entry = proc_create_data("SSID", proc_perm,
- apriv->proc_entry, &proc_SSID_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the APList */
- entry = proc_create_data("APList", proc_perm,
- apriv->proc_entry, &proc_APList_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the BSSList */
- entry = proc_create_data("BSSList", proc_perm,
- apriv->proc_entry, &proc_BSSList_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the WepKey */
- entry = proc_create_data("WepKey", proc_perm,
- apriv->proc_entry, &proc_wepkey_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
- return 0;
-
-fail:
- remove_proc_subtree(apriv->proc_name, airo_entry);
- return -ENOMEM;
-}
-
-static int takedown_proc_entry(struct net_device *dev,
- struct airo_info *apriv)
-{
- remove_proc_subtree(apriv->proc_name, airo_entry);
- return 0;
-}
-
-/*
- * What we want from the proc_fs is to be able to efficiently read
- * and write the configuration. To do this, we want to read the
- * configuration when the file is opened and write it when the file is
- * closed. So basically we allocate a read buffer at open and fill it
- * with data, and allocate a write buffer and read it at close.
- */
-
-/*
- * The read routine is generic, it relies on the preallocated rbuffer
- * to supply the data.
- */
-static ssize_t proc_read(struct file *file,
- char __user *buffer,
- size_t len,
- loff_t *offset)
-{
- struct proc_data *priv = file->private_data;
-
- if (!priv->rbuffer)
- return -EINVAL;
-
- return simple_read_from_buffer(buffer, len, offset, priv->rbuffer,
- priv->readlen);
-}
-
-/*
- * The write routine is generic, it fills in a preallocated rbuffer
- * to supply the data.
- */
-static ssize_t proc_write(struct file *file,
- const char __user *buffer,
- size_t len,
- loff_t *offset)
-{
- ssize_t ret;
- struct proc_data *priv = file->private_data;
-
- if (!priv->wbuffer)
- return -EINVAL;
-
- ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset,
- buffer, len);
- if (ret > 0)
- priv->writelen = max_t(int, priv->writelen, *offset);
-
- return ret;
-}
-
-static int proc_status_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *apriv = dev->ml_priv;
- CapabilityRid cap_rid;
- StatusRid status_rid;
- u16 mode;
- int i;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
-
- readStatusRid(apriv, &status_rid, 1);
- readCapabilityRid(apriv, &cap_rid, 1);
-
- mode = le16_to_cpu(status_rid.mode);
-
- i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
- mode & 1 ? "CFG ": "",
- mode & 2 ? "ACT ": "",
- mode & 0x10 ? "SYN ": "",
- mode & 0x20 ? "LNK ": "",
- mode & 0x40 ? "LEAP ": "",
- mode & 0x80 ? "PRIV ": "",
- mode & 0x100 ? "KEY ": "",
- mode & 0x200 ? "WEP ": "",
- mode & 0x8000 ? "ERR ": "");
- sprintf(data->rbuffer+i, "Mode: %x\n"
- "Signal Strength: %d\n"
- "Signal Quality: %d\n"
- "SSID: %-.*s\n"
- "AP: %-.16s\n"
- "Freq: %d\n"
- "BitRate: %dmbs\n"
- "Driver Version: %s\n"
- "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
- "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
- "Software Version: %x\nSoftware Subversion: %x\n"
- "Boot block version: %x\n",
- le16_to_cpu(status_rid.mode),
- le16_to_cpu(status_rid.normalizedSignalStrength),
- le16_to_cpu(status_rid.signalQuality),
- le16_to_cpu(status_rid.SSIDlen),
- status_rid.SSID,
- status_rid.apName,
- le16_to_cpu(status_rid.channel),
- le16_to_cpu(status_rid.currentXmitRate) / 2,
- version,
- cap_rid.prodName,
- cap_rid.manName,
- cap_rid.prodVer,
- le16_to_cpu(cap_rid.radioType),
- le16_to_cpu(cap_rid.country),
- le16_to_cpu(cap_rid.hardVer),
- le16_to_cpu(cap_rid.softVer),
- le16_to_cpu(cap_rid.softSubVer),
- le16_to_cpu(cap_rid.bootBlockVer));
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_stats_rid_open(struct inode*, struct file*, u16);
-static int proc_statsdelta_open(struct inode *inode,
- struct file *file)
-{
- if (file->f_mode&FMODE_WRITE) {
- return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
- }
- return proc_stats_rid_open(inode, file, RID_STATSDELTA);
-}
-
-static int proc_stats_open(struct inode *inode, struct file *file)
-{
- return proc_stats_rid_open(inode, file, RID_STATS);
-}
-
-static int proc_stats_rid_open(struct inode *inode,
- struct file *file,
- u16 rid)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *apriv = dev->ml_priv;
- StatsRid stats;
- int i, j;
- __le32 *vals = stats.vals;
- int len;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(4096, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
-
- readStatsRid(apriv, &stats, rid, 1);
- len = le16_to_cpu(stats.len);
-
- j = 0;
- for (i = 0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
- if (!statsLabels[i]) continue;
- if (j+strlen(statsLabels[i])+16>4096) {
- airo_print_warn(apriv->dev->name,
- "Potentially disastrous buffer overflow averted!");
- break;
- }
- j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i],
- le32_to_cpu(vals[i]));
- }
- if (i*4 >= len) {
- airo_print_warn(apriv->dev->name, "Got a short rid");
- }
- data->readlen = j;
- return 0;
-}
-
-static int get_dec_u16(char *buffer, int *start, int limit)
-{
- u16 value;
- int valid = 0;
- for (value = 0; *start < limit && buffer[*start] >= '0' &&
- buffer[*start] <= '9'; (*start)++) {
- valid = 1;
- value *= 10;
- value += buffer[*start] - '0';
- }
- if (!valid) return -1;
- return value;
-}
-
-static int airo_config_commit(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra);
-
-static inline int sniffing_mode(struct airo_info *ai)
-{
- return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >=
- le16_to_cpu(RXMODE_RFMON);
-}
-
-static void proc_config_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- char *line;
-
- if (!data->writelen) return;
-
- readConfigRid(ai, 1);
- set_bit (FLAG_COMMIT, &ai->flags);
-
- line = data->wbuffer;
- while (line[0]) {
-/*** Mode processing */
- if (!strncmp(line, "Mode: ", 6)) {
- line += 6;
- if (sniffing_mode(ai))
- set_bit (FLAG_RESET, &ai->flags);
- ai->config.rmode &= ~RXMODE_FULL_MASK;
- clear_bit (FLAG_802_11, &ai->flags);
- ai->config.opmode &= ~MODE_CFG_MASK;
- ai->config.scanMode = SCANMODE_ACTIVE;
- if (line[0] == 'a') {
- ai->config.opmode |= MODE_STA_IBSS;
- } else {
- ai->config.opmode |= MODE_STA_ESS;
- if (line[0] == 'r') {
- ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
- ai->config.scanMode = SCANMODE_PASSIVE;
- set_bit (FLAG_802_11, &ai->flags);
- } else if (line[0] == 'y') {
- ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
- ai->config.scanMode = SCANMODE_PASSIVE;
- set_bit (FLAG_802_11, &ai->flags);
- } else if (line[0] == 'l')
- ai->config.rmode |= RXMODE_LANMON;
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- }
-
-/*** Radio status */
- else if (!strncmp(line,"Radio: ", 7)) {
- line += 7;
- if (!strncmp(line,"off", 3)) {
- set_bit (FLAG_RADIO_OFF, &ai->flags);
- } else {
- clear_bit (FLAG_RADIO_OFF, &ai->flags);
- }
- }
-/*** NodeName processing */
- else if (!strncmp(line, "NodeName: ", 10)) {
- int j;
-
- line += 10;
- memset(ai->config.nodeName, 0, 16);
-/* Do the name, assume a space between the mode and node name */
- for (j = 0; j < 16 && line[j] != '\n'; j++) {
- ai->config.nodeName[j] = line[j];
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- }
-
-/*** PowerMode processing */
- else if (!strncmp(line, "PowerMode: ", 11)) {
- line += 11;
- if (!strncmp(line, "PSPCAM", 6)) {
- ai->config.powerSaveMode = POWERSAVE_PSPCAM;
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "PSP", 3)) {
- ai->config.powerSaveMode = POWERSAVE_PSP;
- set_bit (FLAG_COMMIT, &ai->flags);
- } else {
- ai->config.powerSaveMode = POWERSAVE_CAM;
- set_bit (FLAG_COMMIT, &ai->flags);
- }
- } else if (!strncmp(line, "DataRates: ", 11)) {
- int v, i = 0, k = 0; /* i is index into line,
- k is index to rates */
-
- line += 11;
- while ((v = get_dec_u16(line, &i, 3))!=-1) {
- ai->config.rates[k++] = (u8)v;
- line += i + 1;
- i = 0;
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "Channel: ", 9)) {
- int v, i = 0;
- line += 9;
- v = get_dec_u16(line, &i, i+3);
- if (v != -1) {
- ai->config.channelSet = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- }
- } else if (!strncmp(line, "XmitPower: ", 11)) {
- int v, i = 0;
- line += 11;
- v = get_dec_u16(line, &i, i+3);
- if (v != -1) {
- ai->config.txPower = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- }
- } else if (!strncmp(line, "WEP: ", 5)) {
- line += 5;
- switch(line[0]) {
- case 's':
- set_auth_type(ai, AUTH_SHAREDKEY);
- break;
- case 'e':
- set_auth_type(ai, AUTH_ENCRYPT);
- break;
- default:
- set_auth_type(ai, AUTH_OPEN);
- break;
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "LongRetryLimit: ", 16)) {
- int v, i = 0;
-
- line += 16;
- v = get_dec_u16(line, &i, 3);
- v = (v<0) ? 0 : ((v>255) ? 255 : v);
- ai->config.longRetryLimit = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "ShortRetryLimit: ", 17)) {
- int v, i = 0;
-
- line += 17;
- v = get_dec_u16(line, &i, 3);
- v = (v<0) ? 0 : ((v>255) ? 255 : v);
- ai->config.shortRetryLimit = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "RTSThreshold: ", 14)) {
- int v, i = 0;
-
- line += 14;
- v = get_dec_u16(line, &i, 4);
- v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
- ai->config.rtsThres = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "TXMSDULifetime: ", 16)) {
- int v, i = 0;
-
- line += 16;
- v = get_dec_u16(line, &i, 5);
- v = (v<0) ? 0 : v;
- ai->config.txLifetime = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "RXMSDULifetime: ", 16)) {
- int v, i = 0;
-
- line += 16;
- v = get_dec_u16(line, &i, 5);
- v = (v<0) ? 0 : v;
- ai->config.rxLifetime = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "TXDiversity: ", 13)) {
- ai->config.txDiversity =
- (line[13]=='l') ? 1 :
- ((line[13]=='r')? 2: 3);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "RXDiversity: ", 13)) {
- ai->config.rxDiversity =
- (line[13]=='l') ? 1 :
- ((line[13]=='r')? 2: 3);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "FragThreshold: ", 15)) {
- int v, i = 0;
-
- line += 15;
- v = get_dec_u16(line, &i, 4);
- v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
- v = v & 0xfffe; /* Make sure its even */
- ai->config.fragThresh = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "Modulation: ", 12)) {
- line += 12;
- switch(*line) {
- case 'd': ai->config.modulation = MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 'c': ai->config.modulation = MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 'm': ai->config.modulation = MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
- default: airo_print_warn(ai->dev->name, "Unknown modulation");
- }
- } else if (!strncmp(line, "Preamble: ", 10)) {
- line += 10;
- switch(*line) {
- case 'a': ai->config.preamble = PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 'l': ai->config.preamble = PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 's': ai->config.preamble = PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
- default: airo_print_warn(ai->dev->name, "Unknown preamble");
- }
- } else {
- airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
- }
- while (line[0] && line[0] != '\n') line++;
- if (line[0]) line++;
- }
- airo_config_commit(dev, NULL, NULL, NULL);
-}
-
-static const char *get_rmode(__le16 mode)
-{
- switch(mode & RXMODE_MASK) {
- case RXMODE_RFMON: return "rfmon";
- case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
- case RXMODE_LANMON: return "lanmon";
- }
- return "ESS";
-}
-
-static int proc_config_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i;
- __le16 mode;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- if ((data->wbuffer = kzalloc(2048, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->maxwritelen = 2048;
- data->on_close = proc_config_on_close;
-
- readConfigRid(ai, 1);
-
- mode = ai->config.opmode & MODE_CFG_MASK;
- i = sprintf(data->rbuffer,
- "Mode: %s\n"
- "Radio: %s\n"
- "NodeName: %-16s\n"
- "PowerMode: %s\n"
- "DataRates: %d %d %d %d %d %d %d %d\n"
- "Channel: %d\n"
- "XmitPower: %d\n",
- mode == MODE_STA_IBSS ? "adhoc" :
- mode == MODE_STA_ESS ? get_rmode(ai->config.rmode):
- mode == MODE_AP ? "AP" :
- mode == MODE_AP_RPTR ? "AP RPTR" : "Error",
- test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
- ai->config.nodeName,
- ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" :
- ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" :
- ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" :
- "Error",
- (int)ai->config.rates[0],
- (int)ai->config.rates[1],
- (int)ai->config.rates[2],
- (int)ai->config.rates[3],
- (int)ai->config.rates[4],
- (int)ai->config.rates[5],
- (int)ai->config.rates[6],
- (int)ai->config.rates[7],
- le16_to_cpu(ai->config.channelSet),
- le16_to_cpu(ai->config.txPower)
- );
- sprintf(data->rbuffer + i,
- "LongRetryLimit: %d\n"
- "ShortRetryLimit: %d\n"
- "RTSThreshold: %d\n"
- "TXMSDULifetime: %d\n"
- "RXMSDULifetime: %d\n"
- "TXDiversity: %s\n"
- "RXDiversity: %s\n"
- "FragThreshold: %d\n"
- "WEP: %s\n"
- "Modulation: %s\n"
- "Preamble: %s\n",
- le16_to_cpu(ai->config.longRetryLimit),
- le16_to_cpu(ai->config.shortRetryLimit),
- le16_to_cpu(ai->config.rtsThres),
- le16_to_cpu(ai->config.txLifetime),
- le16_to_cpu(ai->config.rxLifetime),
- ai->config.txDiversity == 1 ? "left" :
- ai->config.txDiversity == 2 ? "right" : "both",
- ai->config.rxDiversity == 1 ? "left" :
- ai->config.rxDiversity == 2 ? "right" : "both",
- le16_to_cpu(ai->config.fragThresh),
- ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
- ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
- ai->config.modulation == MOD_DEFAULT ? "default" :
- ai->config.modulation == MOD_CCK ? "cck" :
- ai->config.modulation == MOD_MOK ? "mok" : "error",
- ai->config.preamble == PREAMBLE_AUTO ? "auto" :
- ai->config.preamble == PREAMBLE_LONG ? "long" :
- ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
- );
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static void proc_SSID_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- SsidRid SSID_rid;
- int i;
- char *p = data->wbuffer;
- char *end = p + data->writelen;
-
- if (!data->writelen)
- return;
-
- *end = '\n'; /* sentinel; we have space for it */
-
- memset(&SSID_rid, 0, sizeof(SSID_rid));
-
- for (i = 0; i < 3 && p < end; i++) {
- int j = 0;
- /* copy up to 32 characters from this line */
- while (*p != '\n' && j < 32)
- SSID_rid.ssids[i].ssid[j++] = *p++;
- if (j == 0)
- break;
- SSID_rid.ssids[i].len = cpu_to_le16(j);
- /* skip to the beginning of the next line */
- while (*p++ != '\n')
- ;
- }
- if (i)
- SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
- disable_MAC(ai, 1);
- writeSsidRid(ai, &SSID_rid, 1);
- enable_MAC(ai, 1);
-}
-
-static void proc_APList_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- APListRid *APList_rid = &ai->APList;
- int i;
-
- if (!data->writelen) return;
-
- memset(APList_rid, 0, sizeof(*APList_rid));
- APList_rid->len = cpu_to_le16(sizeof(*APList_rid));
-
- for (i = 0; i < 4 && data->writelen >= (i + 1) * 6 * 3; i++)
- mac_pton(data->wbuffer + i * 6 * 3, APList_rid->ap[i]);
-
- disable_MAC(ai, 1);
- writeAPListRid(ai, APList_rid, 1);
- enable_MAC(ai, 1);
-}
-
-/* This function wraps PC4500_writerid with a MAC disable */
-static int do_writerid(struct airo_info *ai, u16 rid, const void *rid_data,
- int len, int dummy)
-{
- int rc;
-
- disable_MAC(ai, 1);
- rc = PC4500_writerid(ai, rid, rid_data, len, 1);
- enable_MAC(ai, 1);
- return rc;
-}
-
-/* Returns the WEP key at the specified index, or -1 if that key does
- * not exist. The buffer is assumed to be at least 16 bytes in length.
- */
-static int get_wep_key(struct airo_info *ai, u16 index, char *buf, u16 buflen)
-{
- WepKeyRid wkr;
- int rc;
- __le16 lastindex;
-
- rc = readWepKeyRid(ai, &wkr, 1, 1);
- if (rc != SUCCESS)
- return -1;
- do {
- lastindex = wkr.kindex;
- if (le16_to_cpu(wkr.kindex) == index) {
- int klen = min_t(int, buflen, le16_to_cpu(wkr.klen));
- memcpy(buf, wkr.key, klen);
- return klen;
- }
- rc = readWepKeyRid(ai, &wkr, 0, 1);
- if (rc != SUCCESS)
- return -1;
- } while (lastindex != wkr.kindex);
- return -1;
-}
-
-static int get_wep_tx_idx(struct airo_info *ai)
-{
- WepKeyRid wkr;
- int rc;
- __le16 lastindex;
-
- rc = readWepKeyRid(ai, &wkr, 1, 1);
- if (rc != SUCCESS)
- return -1;
- do {
- lastindex = wkr.kindex;
- if (wkr.kindex == cpu_to_le16(0xffff))
- return wkr.mac[0];
- rc = readWepKeyRid(ai, &wkr, 0, 1);
- if (rc != SUCCESS)
- return -1;
- } while (lastindex != wkr.kindex);
- return -1;
-}
-
-static int set_wep_key(struct airo_info *ai, u16 index, const u8 *key,
- u16 keylen, int perm, int lock)
-{
- static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
- WepKeyRid wkr;
- int rc;
-
- if (WARN_ON(keylen == 0))
- return -1;
-
- memset(&wkr, 0, sizeof(wkr));
- wkr.len = cpu_to_le16(sizeof(wkr));
- wkr.kindex = cpu_to_le16(index);
- wkr.klen = cpu_to_le16(keylen);
- memcpy(wkr.key, key, keylen);
- memcpy(wkr.mac, macaddr, ETH_ALEN);
-
- if (perm) disable_MAC(ai, lock);
- rc = writeWepKeyRid(ai, &wkr, perm, lock);
- if (perm) enable_MAC(ai, lock);
- return rc;
-}
-
-static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock)
-{
- WepKeyRid wkr;
- int rc;
-
- memset(&wkr, 0, sizeof(wkr));
- wkr.len = cpu_to_le16(sizeof(wkr));
- wkr.kindex = cpu_to_le16(0xffff);
- wkr.mac[0] = (char)index;
-
- if (perm) {
- ai->defindex = (char)index;
- disable_MAC(ai, lock);
- }
-
- rc = writeWepKeyRid(ai, &wkr, perm, lock);
-
- if (perm)
- enable_MAC(ai, lock);
- return rc;
-}
-
-static void proc_wepkey_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i, rc;
- u8 key[16];
- u16 index = 0;
- int j = 0;
-
- memset(key, 0, sizeof(key));
-
- data = file->private_data;
- if (!data->writelen) return;
-
- if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
- (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
- index = data->wbuffer[0] - '0';
- if (data->wbuffer[1] == '\n') {
- rc = set_wep_tx_idx(ai, index, 1, 1);
- if (rc < 0) {
- airo_print_err(ai->dev->name, "failed to set "
- "WEP transmit index to %d: %d.",
- index, rc);
- }
- return;
- }
- j = 2;
- } else {
- airo_print_err(ai->dev->name, "WepKey passed invalid key index");
- return;
- }
-
- for (i = 0; i < 16*3 && data->wbuffer[i+j]; i++) {
- int val;
-
- if (i % 3 == 2)
- continue;
-
- val = hex_to_bin(data->wbuffer[i+j]);
- if (val < 0) {
- airo_print_err(ai->dev->name, "WebKey passed invalid key hex");
- return;
- }
- switch(i%3) {
- case 0:
- key[i/3] = (u8)val << 4;
- break;
- case 1:
- key[i/3] |= (u8)val;
- break;
- }
- }
-
- rc = set_wep_key(ai, index, key, i/3, 1, 1);
- if (rc < 0) {
- airo_print_err(ai->dev->name, "failed to set WEP key at index "
- "%d: %d.", index, rc);
- }
-}
-
-static int proc_wepkey_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- char *ptr;
- WepKeyRid wkr;
- __le16 lastindex;
- int j = 0;
- int rc;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- memset(&wkr, 0, sizeof(wkr));
- data = file->private_data;
- if ((data->rbuffer = kzalloc(180, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 80;
- if ((data->wbuffer = kzalloc(80, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->on_close = proc_wepkey_on_close;
-
- ptr = data->rbuffer;
- strcpy(ptr, "No wep keys\n");
- rc = readWepKeyRid(ai, &wkr, 1, 1);
- if (rc == SUCCESS) do {
- lastindex = wkr.kindex;
- if (wkr.kindex == cpu_to_le16(0xffff)) {
- j += sprintf(ptr+j, "Tx key = %d\n",
- (int)wkr.mac[0]);
- } else {
- j += sprintf(ptr+j, "Key %d set with length = %d\n",
- le16_to_cpu(wkr.kindex),
- le16_to_cpu(wkr.klen));
- }
- readWepKeyRid(ai, &wkr, 0, 1);
- } while ((lastindex != wkr.kindex) && (j < 180-30));
-
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_SSID_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i;
- char *ptr;
- SsidRid SSID_rid;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 33*3;
- /* allocate maxwritelen + 1; we'll want a sentinel */
- if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->on_close = proc_SSID_on_close;
-
- readSsidRid(ai, &SSID_rid);
- ptr = data->rbuffer;
- for (i = 0; i < 3; i++) {
- int j;
- size_t len = le16_to_cpu(SSID_rid.ssids[i].len);
- if (!len)
- break;
- if (len > 32)
- len = 32;
- for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++)
- *ptr++ = SSID_rid.ssids[i].ssid[j];
- *ptr++ = '\n';
- }
- *ptr = '\0';
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_APList_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i;
- char *ptr;
- APListRid *APList_rid = &ai->APList;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 4*6*3;
- if ((data->wbuffer = kzalloc(data->maxwritelen, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->on_close = proc_APList_on_close;
-
- ptr = data->rbuffer;
- for (i = 0; i < 4; i++) {
-// We end when we find a zero MAC
- if (!*(int*)APList_rid->ap[i] &&
- !*(int*)&APList_rid->ap[i][2]) break;
- ptr += sprintf(ptr, "%pM\n", APList_rid->ap[i]);
- }
- if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
-
- *ptr = '\0';
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_BSSList_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- char *ptr;
- BSSListRid BSSList_rid;
- int rc;
- /* If doLoseSync is not 1, we won't do a Lose Sync */
- int doLoseSync = -1;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(1024, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 0;
- data->wbuffer = NULL;
- data->on_close = NULL;
-
- if (file->f_mode & FMODE_WRITE) {
- if (!(file->f_mode & FMODE_READ)) {
- Cmd cmd;
- Resp rsp;
-
- if (ai->flags & FLAG_RADIO_MASK) {
- kfree(data->rbuffer);
- kfree(file->private_data);
- return -ENETDOWN;
- }
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LISTBSS;
- if (down_interruptible(&ai->sem)) {
- kfree(data->rbuffer);
- kfree(file->private_data);
- return -ERESTARTSYS;
- }
- issuecommand(ai, &cmd, &rsp, true);
- up(&ai->sem);
- data->readlen = 0;
- return 0;
- }
- doLoseSync = 1;
- }
- ptr = data->rbuffer;
- /* There is a race condition here if there are concurrent opens.
- Since it is a rare condition, we'll just live with it, otherwise
- we have to add a spin lock... */
- rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
- while (rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
- ptr += sprintf(ptr, "%pM %.*s rssi = %d",
- BSSList_rid.bssid,
- (int)BSSList_rid.ssidLen,
- BSSList_rid.ssid,
- le16_to_cpu(BSSList_rid.dBm));
- ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
- le16_to_cpu(BSSList_rid.dsChannel),
- BSSList_rid.cap & CAP_ESS ? "ESS" : "",
- BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
- BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
- BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
- rc = readBSSListRid(ai, 0, &BSSList_rid);
- }
- *ptr = '\0';
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
-
- if (data->on_close != NULL)
- data->on_close(inode, file);
- kfree(data->rbuffer);
- kfree(data->wbuffer);
- kfree(data);
- return 0;
-}
-
-/* Since the card doesn't automatically switch to the right WEP mode,
- we will make it do it. If the card isn't associated, every secs we
- will switch WEP modes to see if that will help. If the card is
- associated we will check every minute to see if anything has
- changed. */
-static void timer_func(struct net_device *dev)
-{
- struct airo_info *apriv = dev->ml_priv;
-
-/* We don't have a link so try changing the authtype */
- readConfigRid(apriv, 0);
- disable_MAC(apriv, 0);
- switch(apriv->config.authType) {
- case AUTH_ENCRYPT:
-/* So drop to OPEN */
- apriv->config.authType = AUTH_OPEN;
- break;
- case AUTH_SHAREDKEY:
- if (apriv->keyindex < auto_wep) {
- set_wep_tx_idx(apriv, apriv->keyindex, 0, 0);
- apriv->config.authType = AUTH_SHAREDKEY;
- apriv->keyindex++;
- } else {
- /* Drop to ENCRYPT */
- apriv->keyindex = 0;
- set_wep_tx_idx(apriv, apriv->defindex, 0, 0);
- apriv->config.authType = AUTH_ENCRYPT;
- }
- break;
- default: /* We'll escalate to SHAREDKEY */
- apriv->config.authType = AUTH_SHAREDKEY;
- }
- set_bit (FLAG_COMMIT, &apriv->flags);
- writeConfigRid(apriv, 0);
- enable_MAC(apriv, 0);
- up(&apriv->sem);
-
-/* Schedule check to see if the change worked */
- clear_bit(JOB_AUTOWEP, &apriv->jobs);
- apriv->expires = RUN_AT(HZ*3);
-}
-
-#ifdef CONFIG_PCI
-static int airo_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *pent)
-{
- struct net_device *dev;
-
- if (pci_enable_device(pdev))
- return -ENODEV;
- pci_set_master(pdev);
-
- if (pdev->device == 0x5000 || pdev->device == 0xa504)
- dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
- else
- dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
- if (!dev) {
- pci_disable_device(pdev);
- return -ENODEV;
- }
-
- pci_set_drvdata(pdev, dev);
- return 0;
-}
-
-static void airo_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
-
- airo_print_info(dev->name, "Unregistering...");
- stop_airo_card(dev, 1);
- pci_disable_device(pdev);
-}
-
-static int __maybe_unused airo_pci_suspend(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
- struct airo_info *ai = dev->ml_priv;
- Cmd cmd;
- Resp rsp;
-
- if (!ai->SSID)
- ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL);
- if (!ai->SSID)
- return -ENOMEM;
- readSsidRid(ai, ai->SSID);
- memset(&cmd, 0, sizeof(cmd));
- /* the lock will be released at the end of the resume callback */
- if (down_interruptible(&ai->sem))
- return -EAGAIN;
- disable_MAC(ai, 0);
- netif_device_detach(dev);
- ai->power = PMSG_SUSPEND;
- cmd.cmd = HOSTSLEEP;
- issuecommand(ai, &cmd, &rsp, true);
-
- device_wakeup_enable(dev_d);
- return 0;
-}
-
-static int __maybe_unused airo_pci_resume(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
- struct airo_info *ai = dev->ml_priv;
- pci_power_t prev_state = to_pci_dev(dev_d)->current_state;
-
- device_wakeup_disable(dev_d);
-
- if (prev_state != PCI_D1) {
- reset_card(dev, 0);
- mpi_init_descriptors(ai);
- setup_card(ai, dev, 0);
- clear_bit(FLAG_RADIO_OFF, &ai->flags);
- clear_bit(FLAG_PENDING_XMIT, &ai->flags);
- } else {
- OUT4500(ai, EVACK, EV_AWAKEN);
- OUT4500(ai, EVACK, EV_AWAKEN);
- msleep(100);
- }
-
- set_bit(FLAG_COMMIT, &ai->flags);
- disable_MAC(ai, 0);
- msleep(200);
- if (ai->SSID) {
- writeSsidRid(ai, ai->SSID, 0);
- kfree(ai->SSID);
- ai->SSID = NULL;
- }
- writeAPListRid(ai, &ai->APList, 0);
- writeConfigRid(ai, 0);
- enable_MAC(ai, 0);
- ai->power = PMSG_ON;
- netif_device_attach(dev);
- netif_wake_queue(dev);
- enable_interrupts(ai);
- up(&ai->sem);
- return 0;
-}
-#endif
-
-static int __init airo_init_module(void)
-{
- int i;
-
- proc_kuid = make_kuid(&init_user_ns, proc_uid);
- proc_kgid = make_kgid(&init_user_ns, proc_gid);
- if (!uid_valid(proc_kuid) || !gid_valid(proc_kgid))
- return -EINVAL;
-
- airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);
-
- if (airo_entry)
- proc_set_user(airo_entry, proc_kuid, proc_kgid);
-
- for (i = 0; i < 4 && io[i] && irq[i]; i++) {
- airo_print_info("", "Trying to configure ISA adapter at irq=%d "
- "io = 0x%x", irq[i], io[i]);
- if (init_airo_card(irq[i], io[i], 0, NULL)) {
- /* do nothing */ ;
- }
- }
-
-#ifdef CONFIG_PCI
- airo_print_info("", "Probing for PCI adapters");
- i = pci_register_driver(&airo_driver);
- airo_print_info("", "Finished probing for PCI adapters");
-
- if (i) {
- remove_proc_entry("driver/aironet", NULL);
- return i;
- }
-#endif
-
- /* Always exit with success, as we are a library module
- * as well as a driver module
- */
- return 0;
-}
-
-static void __exit airo_cleanup_module(void)
-{
- struct airo_info *ai;
- while (!list_empty(&airo_devices)) {
- ai = list_entry(airo_devices.next, struct airo_info, dev_list);
- airo_print_info(ai->dev->name, "Unregistering...");
- stop_airo_card(ai->dev, 1);
- }
-#ifdef CONFIG_PCI
- pci_unregister_driver(&airo_driver);
-#endif
- remove_proc_entry("driver/aironet", NULL);
-}
-
-/*
- * Initial Wireless Extension code for Aironet driver by :
- * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 17 November 00
- * Conversion to new driver API by :
- * Jean Tourrilhes <jt@hpl.hp.com> - HPL - 26 March 02
- * Javier also did a good amount of work here, adding some new extensions
- * and fixing my code. Let's just say that without him this code just
- * would not work at all... - Jean II
- */
-
-static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
-{
- if (!rssi_rid)
- return 0;
-
- return (0x100 - rssi_rid[rssi].rssidBm);
-}
-
-static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
-{
- int i;
-
- if (!rssi_rid)
- return 0;
-
- for (i = 0; i < 256; i++)
- if (rssi_rid[i].rssidBm == dbm)
- return rssi_rid[i].rssipct;
-
- return 0;
-}
-
-
-static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
-{
- int quality = 0;
- u16 sq;
-
- if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f))
- return 0;
-
- if (!(cap_rid->hardCap & cpu_to_le16(8)))
- return 0;
-
- sq = le16_to_cpu(status_rid->signalQuality);
- if (memcmp(cap_rid->prodName, "350", 3))
- if (sq > 0x20)
- quality = 0;
- else
- quality = 0x20 - sq;
- else
- if (sq > 0xb0)
- quality = 0;
- else if (sq < 0x10)
- quality = 0xa0;
- else
- quality = 0xb0 - sq;
- return quality;
-}
-
-#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
-#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50)
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get protocol name
- */
-static int airo_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *cwrq,
- char *extra)
-{
- strcpy(cwrq->name, "IEEE 802.11-DS");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set frequency
- */
-static int airo_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *fwrq = &wrqu->freq;
- struct airo_info *local = dev->ml_priv;
- int rc = -EINPROGRESS; /* Call commit handler */
-
- /* If setting by frequency, convert to a channel */
- if (fwrq->e == 1) {
- int f = fwrq->m / 100000;
-
- /* Hack to fall through... */
- fwrq->e = 0;
- fwrq->m = ieee80211_frequency_to_channel(f);
- }
- /* Setting by channel number */
- if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0)
- rc = -EOPNOTSUPP;
- else {
- int channel = fwrq->m;
- /* We should do a better check than that,
- * based on the card capability !!! */
- if ((channel < 1) || (channel > 14)) {
- airo_print_dbg(dev->name, "New channel value of %d is invalid!",
- fwrq->m);
- rc = -EINVAL;
- } else {
- readConfigRid(local, 1);
- /* Yes ! We can set it !!! */
- local->config.channelSet = cpu_to_le16(channel);
- set_bit (FLAG_COMMIT, &local->flags);
- }
- }
- return rc;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get frequency
- */
-static int airo_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *fwrq = &wrqu->freq;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
- int ch;
-
- readConfigRid(local, 1);
- if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS)
- status_rid.channel = local->config.channelSet;
- else
- readStatusRid(local, &status_rid, 1);
-
- ch = le16_to_cpu(status_rid.channel);
- if ((ch > 0) && (ch < 15)) {
- fwrq->m = 100000 *
- ieee80211_channel_to_frequency(ch, NL80211_BAND_2GHZ);
- fwrq->e = 1;
- } else {
- fwrq->m = ch;
- fwrq->e = 0;
- }
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set ESSID
- */
-static int airo_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->essid;
- struct airo_info *local = dev->ml_priv;
- SsidRid SSID_rid; /* SSIDs */
-
- /* Reload the list of current SSID */
- readSsidRid(local, &SSID_rid);
-
- /* Check if we asked for `any' */
- if (dwrq->flags == 0) {
- /* Just send an empty SSID list */
- memset(&SSID_rid, 0, sizeof(SSID_rid));
- } else {
- unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
- /* Check the size of the string */
- if (dwrq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG ;
-
- /* Check if index is valid */
- if (index >= ARRAY_SIZE(SSID_rid.ssids))
- return -EINVAL;
-
- /* Set the SSID */
- memset(SSID_rid.ssids[index].ssid, 0,
- sizeof(SSID_rid.ssids[index].ssid));
- memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
- SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length);
- }
- SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
- /* Write it to the card */
- disable_MAC(local, 1);
- writeSsidRid(local, &SSID_rid, 1);
- enable_MAC(local, 1);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get ESSID
- */
-static int airo_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->essid;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
-
- readStatusRid(local, &status_rid, 1);
-
- /* Note : if dwrq->flags != 0, we should
- * get the relevant SSID from the SSID list... */
-
- /* Get the current SSID */
- memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen));
- /* If none, we may want to get the one that was set */
-
- /* Push it out ! */
- dwrq->length = le16_to_cpu(status_rid.SSIDlen);
- dwrq->flags = 1; /* active */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set AP address
- */
-static int airo_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *awrq = &wrqu->ap_addr;
- struct airo_info *local = dev->ml_priv;
- Cmd cmd;
- Resp rsp;
- APListRid *APList_rid = &local->APList;
-
- if (awrq->sa_family != ARPHRD_ETHER)
- return -EINVAL;
- else if (is_broadcast_ether_addr(awrq->sa_data) ||
- is_zero_ether_addr(awrq->sa_data)) {
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LOSE_SYNC;
- if (down_interruptible(&local->sem))
- return -ERESTARTSYS;
- issuecommand(local, &cmd, &rsp, true);
- up(&local->sem);
- } else {
- memset(APList_rid, 0, sizeof(*APList_rid));
- APList_rid->len = cpu_to_le16(sizeof(*APList_rid));
- memcpy(APList_rid->ap[0], awrq->sa_data, ETH_ALEN);
- disable_MAC(local, 1);
- writeAPListRid(local, APList_rid, 1);
- enable_MAC(local, 1);
- }
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get AP address
- */
-static int airo_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *awrq = &wrqu->ap_addr;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
-
- readStatusRid(local, &status_rid, 1);
-
- /* Tentative. This seems to work, wow, I'm lucky !!! */
- memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
- awrq->sa_family = ARPHRD_ETHER;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Nickname
- */
-static int airo_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
-
- /* Check the size of the string */
- if (dwrq->length > 16) {
- return -E2BIG;
- }
- readConfigRid(local, 1);
- memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
- memcpy(local->config.nodeName, extra, dwrq->length);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Nickname
- */
-static int airo_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- strncpy(extra, local->config.nodeName, 16);
- extra[16] = '\0';
- dwrq->length = strlen(extra);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Bit-Rate
- */
-static int airo_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->bitrate;
- struct airo_info *local = dev->ml_priv;
- CapabilityRid cap_rid; /* Card capability info */
- u8 brate = 0;
- int i;
-
- /* First : get a valid bit rate value */
- readCapabilityRid(local, &cap_rid, 1);
-
- /* Which type of value ? */
- if ((vwrq->value < 8) && (vwrq->value >= 0)) {
- /* Setting by rate index */
- /* Find value in the magic rate table */
- brate = cap_rid.supportedRates[vwrq->value];
- } else {
- /* Setting by frequency value */
- u8 normvalue = (u8) (vwrq->value/500000);
-
- /* Check if rate is valid */
- for (i = 0 ; i < 8 ; i++) {
- if (normvalue == cap_rid.supportedRates[i]) {
- brate = normvalue;
- break;
- }
- }
- }
- /* -1 designed the max rate (mostly auto mode) */
- if (vwrq->value == -1) {
- /* Get the highest available rate */
- for (i = 0 ; i < 8 ; i++) {
- if (cap_rid.supportedRates[i] == 0)
- break;
- }
- if (i != 0)
- brate = cap_rid.supportedRates[i - 1];
- }
- /* Check that it is valid */
- if (brate == 0) {
- return -EINVAL;
- }
-
- readConfigRid(local, 1);
- /* Now, check if we want a fixed or auto value */
- if (vwrq->fixed == 0) {
- /* Fill all the rates up to this max rate */
- memset(local->config.rates, 0, 8);
- for (i = 0 ; i < 8 ; i++) {
- local->config.rates[i] = cap_rid.supportedRates[i];
- if (local->config.rates[i] == brate)
- break;
- }
- } else {
- /* Fixed mode */
- /* One rate, fixed */
- memset(local->config.rates, 0, 8);
- local->config.rates[0] = brate;
- }
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Bit-Rate
- */
-static int airo_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->bitrate;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
- int ret;
-
- ret = readStatusRid(local, &status_rid, 1);
- if (ret)
- return -EBUSY;
-
- vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000;
- /* If more than one rate, set auto */
- readConfigRid(local, 1);
- vwrq->fixed = (local->config.rates[1] == 0);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set RTS threshold
- */
-static int airo_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->rts;
- struct airo_info *local = dev->ml_priv;
- int rthr = vwrq->value;
-
- if (vwrq->disabled)
- rthr = AIRO_DEF_MTU;
- if ((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
- return -EINVAL;
- }
- readConfigRid(local, 1);
- local->config.rtsThres = cpu_to_le16(rthr);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get RTS threshold
- */
-static int airo_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->rts;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.rtsThres);
- vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Fragmentation threshold
- */
-static int airo_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->frag;
- struct airo_info *local = dev->ml_priv;
- int fthr = vwrq->value;
-
- if (vwrq->disabled)
- fthr = AIRO_DEF_MTU;
- if ((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
- return -EINVAL;
- }
- fthr &= ~0x1; /* Get an even value - is it really needed ??? */
- readConfigRid(local, 1);
- local->config.fragThresh = cpu_to_le16(fthr);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Fragmentation threshold
- */
-static int airo_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->frag;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.fragThresh);
- vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Mode of Operation
- */
-static int airo_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *uwrq,
- char *extra)
-{
- __u32 mode = uwrq->mode;
- struct airo_info *local = dev->ml_priv;
- int reset = 0;
-
- readConfigRid(local, 1);
- if (sniffing_mode(local))
- reset = 1;
-
- switch (mode) {
- case IW_MODE_ADHOC:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_STA_IBSS;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_INFRA:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_STA_ESS;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_MASTER:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_AP;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_REPEAT:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_AP_RPTR;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_MONITOR:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_STA_ESS;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
- local->config.scanMode = SCANMODE_PASSIVE;
- set_bit (FLAG_802_11, &local->flags);
- break;
- default:
- return -EINVAL;
- }
- if (reset)
- set_bit (FLAG_RESET, &local->flags);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Mode of Operation
- */
-static int airo_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *uwrq,
- char *extra)
-{
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- /* If not managed, assume it's ad-hoc */
- switch (local->config.opmode & MODE_CFG_MASK) {
- case MODE_STA_ESS:
- uwrq->mode = IW_MODE_INFRA;
- break;
- case MODE_AP:
- uwrq->mode = IW_MODE_MASTER;
- break;
- case MODE_AP_RPTR:
- uwrq->mode = IW_MODE_REPEAT;
- break;
- default:
- uwrq->mode = IW_MODE_ADHOC;
- }
-
- return 0;
-}
-
-static inline int valid_index(struct airo_info *ai, int index)
-{
- return (index >= 0) && (index <= ai->max_wep_idx);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Encryption Key
- */
-static int airo_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->encoding;
- struct airo_info *local = dev->ml_priv;
- int perm = (dwrq->flags & IW_ENCODE_TEMP ? 0 : 1);
- __le16 currentAuthType = local->config.authType;
- int rc = 0;
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- /* Basic checking: do we have a key to set ?
- * Note : with the new API, it's impossible to get a NULL pointer.
- * Therefore, we need to check a key size == 0 instead.
- * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
- * when no key is present (only change flags), but older versions
- * don't do it. - Jean II */
- if (dwrq->length > 0) {
- wep_key_t key;
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- int current_index;
-
- /* Check the size of the key */
- if (dwrq->length > MAX_KEY_SIZE) {
- return -EINVAL;
- }
-
- current_index = get_wep_tx_idx(local);
- if (current_index < 0)
- current_index = 0;
-
- /* Check the index (none -> use current) */
- if (!valid_index(local, index))
- index = current_index;
-
- /* Set the length */
- if (dwrq->length > MIN_KEY_SIZE)
- key.len = MAX_KEY_SIZE;
- else
- key.len = MIN_KEY_SIZE;
- /* Check if the key is not marked as invalid */
- if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
- /* Cleanup */
- memset(key.key, 0, MAX_KEY_SIZE);
- /* Copy the key in the driver */
- memcpy(key.key, extra, dwrq->length);
- /* Send the key to the card */
- rc = set_wep_key(local, index, key.key, key.len, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set"
- " WEP key at index %d: %d.",
- index, rc);
- return rc;
- }
- }
- /* WE specify that if a valid key is set, encryption
- * should be enabled (user may turn it off later)
- * This is also how "iwconfig ethX key on" works */
- if ((index == current_index) && (key.len > 0) &&
- (local->config.authType == AUTH_OPEN))
- set_auth_type(local, AUTH_ENCRYPT);
- } else {
- /* Do we want to just set the transmit key index ? */
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- if (valid_index(local, index)) {
- rc = set_wep_tx_idx(local, index, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set"
- " WEP transmit index to %d: %d.",
- index, rc);
- return rc;
- }
- } else {
- /* Don't complain if only change the mode */
- if (!(dwrq->flags & IW_ENCODE_MODE))
- return -EINVAL;
- }
- }
- /* Read the flags */
- if (dwrq->flags & IW_ENCODE_DISABLED)
- set_auth_type(local, AUTH_OPEN); /* disable encryption */
- if (dwrq->flags & IW_ENCODE_RESTRICTED)
- set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */
- if (dwrq->flags & IW_ENCODE_OPEN)
- set_auth_type(local, AUTH_ENCRYPT); /* Only Wep */
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Encryption Key
- */
-static int airo_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->encoding;
- struct airo_info *local = dev->ml_priv;
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- int wep_key_len;
- u8 buf[16];
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- /* Check encryption mode */
- switch(local->config.authType) {
- case AUTH_ENCRYPT:
- dwrq->flags = IW_ENCODE_OPEN;
- break;
- case AUTH_SHAREDKEY:
- dwrq->flags = IW_ENCODE_RESTRICTED;
- break;
- default:
- case AUTH_OPEN:
- dwrq->flags = IW_ENCODE_DISABLED;
- break;
- }
- /* We can't return the key, so set the proper flag and return zero */
- dwrq->flags |= IW_ENCODE_NOKEY;
- memset(extra, 0, 16);
-
- /* Which key do we want ? -1 -> tx index */
- if (!valid_index(local, index)) {
- index = get_wep_tx_idx(local);
- if (index < 0)
- index = 0;
- }
- dwrq->flags |= index + 1;
-
- /* Copy the key to the user buffer */
- wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf));
- if (wep_key_len < 0) {
- dwrq->length = 0;
- } else {
- dwrq->length = wep_key_len;
- memcpy(extra, buf, dwrq->length);
- }
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set extended Encryption parameters
- */
-static int airo_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int perm = (encoding->flags & IW_ENCODE_TEMP ? 0 : 1);
- __le16 currentAuthType = local->config.authType;
- int idx, key_len, alg = ext->alg, set_key = 1, rc;
- wep_key_t key;
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- /* Determine and validate the key index */
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (!valid_index(local, idx - 1))
- return -EINVAL;
- idx--;
- } else {
- idx = get_wep_tx_idx(local);
- if (idx < 0)
- idx = 0;
- }
-
- if (encoding->flags & IW_ENCODE_DISABLED)
- alg = IW_ENCODE_ALG_NONE;
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- /* Only set transmit key index here, actual
- * key is set below if needed.
- */
- rc = set_wep_tx_idx(local, idx, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set "
- "WEP transmit index to %d: %d.",
- idx, rc);
- return rc;
- }
- set_key = ext->key_len > 0 ? 1 : 0;
- }
-
- if (set_key) {
- /* Set the requested key first */
- memset(key.key, 0, MAX_KEY_SIZE);
- switch (alg) {
- case IW_ENCODE_ALG_NONE:
- key.len = 0;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len > MIN_KEY_SIZE) {
- key.len = MAX_KEY_SIZE;
- } else if (ext->key_len > 0) {
- key.len = MIN_KEY_SIZE;
- } else {
- return -EINVAL;
- }
- key_len = min (ext->key_len, key.len);
- memcpy(key.key, ext->key, key_len);
- break;
- default:
- return -EINVAL;
- }
- if (key.len == 0) {
- rc = set_wep_tx_idx(local, idx, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name,
- "failed to set WEP transmit index to %d: %d.",
- idx, rc);
- return rc;
- }
- } else {
- rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name,
- "failed to set WEP key at index %d: %d.",
- idx, rc);
- return rc;
- }
- }
- }
-
- /* Read the flags */
- if (encoding->flags & IW_ENCODE_DISABLED)
- set_auth_type(local, AUTH_OPEN); /* disable encryption */
- if (encoding->flags & IW_ENCODE_RESTRICTED)
- set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */
- if (encoding->flags & IW_ENCODE_OPEN)
- set_auth_type(local, AUTH_ENCRYPT);
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get extended Encryption parameters
- */
-static int airo_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, max_key_len, wep_key_len;
- u8 buf[16];
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (!valid_index(local, idx - 1))
- return -EINVAL;
- idx--;
- } else {
- idx = get_wep_tx_idx(local);
- if (idx < 0)
- idx = 0;
- }
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- /* Check encryption mode */
- switch(local->config.authType) {
- case AUTH_ENCRYPT:
- encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
- break;
- case AUTH_SHAREDKEY:
- encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
- break;
- default:
- case AUTH_OPEN:
- encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
- break;
- }
- /* We can't return the key, so set the proper flag and return zero */
- encoding->flags |= IW_ENCODE_NOKEY;
- memset(extra, 0, 16);
-
- /* Copy the key to the user buffer */
- wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf));
- if (wep_key_len < 0) {
- ext->key_len = 0;
- } else {
- ext->key_len = wep_key_len;
- memcpy(extra, buf, ext->key_len);
- }
-
- return 0;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set extended authentication parameters
- */
-static int airo_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_param *param = &wrqu->param;
- __le16 currentAuthType = local->config.authType;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_PRIVACY_INVOKED:
- /*
- * airo does not use these parameters
- */
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- if (param->value) {
- /* Only change auth type if unencrypted */
- if (currentAuthType == AUTH_OPEN)
- set_auth_type(local, AUTH_ENCRYPT);
- } else {
- set_auth_type(local, AUTH_OPEN);
- }
-
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
- break;
-
- case IW_AUTH_80211_AUTH_ALG: {
- if (param->value & IW_AUTH_ALG_SHARED_KEY) {
- set_auth_type(local, AUTH_SHAREDKEY);
- } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
- /* We don't know here if WEP open system or
- * unencrypted mode was requested - so use the
- * last mode (of these two) used last time
- */
- set_auth_type(local, local->last_auth);
- } else
- return -EINVAL;
-
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
- break;
- }
-
- case IW_AUTH_WPA_ENABLED:
- /* Silently accept disable of WPA */
- if (param->value > 0)
- return -EOPNOTSUPP;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return -EINPROGRESS;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get extended authentication parameters
- */
-static int airo_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_param *param = &wrqu->param;
- __le16 currentAuthType = local->config.authType;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_DROP_UNENCRYPTED:
- switch (currentAuthType) {
- case AUTH_SHAREDKEY:
- case AUTH_ENCRYPT:
- param->value = 1;
- break;
- default:
- param->value = 0;
- break;
- }
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- switch (currentAuthType) {
- case AUTH_SHAREDKEY:
- param->value = IW_AUTH_ALG_SHARED_KEY;
- break;
- case AUTH_ENCRYPT:
- default:
- param->value = IW_AUTH_ALG_OPEN_SYSTEM;
- break;
- }
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = 0;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Tx-Power
- */
-static int airo_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->txpower;
- struct airo_info *local = dev->ml_priv;
- CapabilityRid cap_rid; /* Card capability info */
- int i;
- int rc = -EINVAL;
- __le16 v = cpu_to_le16(vwrq->value);
-
- readCapabilityRid(local, &cap_rid, 1);
-
- if (vwrq->disabled) {
- set_bit (FLAG_RADIO_OFF, &local->flags);
- set_bit (FLAG_COMMIT, &local->flags);
- return -EINPROGRESS; /* Call commit handler */
- }
- if (vwrq->flags != IW_TXPOW_MWATT) {
- return -EINVAL;
- }
- clear_bit (FLAG_RADIO_OFF, &local->flags);
- for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++)
- if (v == cap_rid.txPowerLevels[i]) {
- readConfigRid(local, 1);
- local->config.txPower = v;
- set_bit (FLAG_COMMIT, &local->flags);
- rc = -EINPROGRESS; /* Call commit handler */
- break;
- }
- return rc;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Tx-Power
- */
-static int airo_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->txpower;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.txPower);
- vwrq->fixed = 1; /* No power control */
- vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
- vwrq->flags = IW_TXPOW_MWATT;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Retry limits
- */
-static int airo_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->retry;
- struct airo_info *local = dev->ml_priv;
- int rc = -EINVAL;
-
- if (vwrq->disabled) {
- return -EINVAL;
- }
- readConfigRid(local, 1);
- if (vwrq->flags & IW_RETRY_LIMIT) {
- __le16 v = cpu_to_le16(vwrq->value);
- if (vwrq->flags & IW_RETRY_LONG)
- local->config.longRetryLimit = v;
- else if (vwrq->flags & IW_RETRY_SHORT)
- local->config.shortRetryLimit = v;
- else {
- /* No modifier : set both */
- local->config.longRetryLimit = v;
- local->config.shortRetryLimit = v;
- }
- set_bit (FLAG_COMMIT, &local->flags);
- rc = -EINPROGRESS; /* Call commit handler */
- }
- if (vwrq->flags & IW_RETRY_LIFETIME) {
- local->config.txLifetime = cpu_to_le16(vwrq->value / 1024);
- set_bit (FLAG_COMMIT, &local->flags);
- rc = -EINPROGRESS; /* Call commit handler */
- }
- return rc;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Retry limits
- */
-static int airo_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->retry;
- struct airo_info *local = dev->ml_priv;
-
- vwrq->disabled = 0; /* Can't be disabled */
-
- readConfigRid(local, 1);
- /* Note : by default, display the min retry number */
- if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- vwrq->flags = IW_RETRY_LIFETIME;
- vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024;
- } else if ((vwrq->flags & IW_RETRY_LONG)) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- vwrq->value = le16_to_cpu(local->config.longRetryLimit);
- } else {
- vwrq->flags = IW_RETRY_LIMIT;
- vwrq->value = le16_to_cpu(local->config.shortRetryLimit);
- if (local->config.shortRetryLimit != local->config.longRetryLimit)
- vwrq->flags |= IW_RETRY_SHORT;
- }
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get range info
- */
-static int airo_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
- struct iw_range *range = (struct iw_range *) extra;
- CapabilityRid cap_rid; /* Card capability info */
- int i;
- int k;
-
- readCapabilityRid(local, &cap_rid, 1);
-
- dwrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(*range));
- range->min_nwid = 0x0000;
- range->max_nwid = 0x0000;
- range->num_channels = 14;
- /* Should be based on cap_rid.country to give only
- * what the current card support */
- k = 0;
- for (i = 0; i < 14; i++) {
- range->freq[k].i = i + 1; /* List index */
- range->freq[k].m = 100000 *
- ieee80211_channel_to_frequency(i + 1, NL80211_BAND_2GHZ);
- range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
- }
- range->num_frequency = k;
-
- range->sensitivity = 65535;
-
- /* Hum... Should put the right values there */
- if (local->rssi)
- range->max_qual.qual = 100; /* % */
- else
- range->max_qual.qual = airo_get_max_quality(&cap_rid);
- range->max_qual.level = 0x100 - 120; /* -120 dBm */
- range->max_qual.noise = 0x100 - 120; /* -120 dBm */
-
- /* Experimental measurements - boundary 11/5.5 Mb/s */
- /* Note : with or without the (local->rssi), results
- * are somewhat different. - Jean II */
- if (local->rssi) {
- range->avg_qual.qual = 50; /* % */
- range->avg_qual.level = 0x100 - 70; /* -70 dBm */
- } else {
- range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
- range->avg_qual.level = 0x100 - 80; /* -80 dBm */
- }
- range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
-
- for (i = 0 ; i < 8 ; i++) {
- range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
- if (range->bitrate[i] == 0)
- break;
- }
- range->num_bitrates = i;
-
- /* Set an indication of the max TCP throughput
- * in bit/s that we can expect using this interface.
- * May be use for QoS stuff... Jean II */
- if (i > 2)
- range->throughput = 5000 * 1000;
- else
- range->throughput = 1500 * 1000;
-
- range->min_rts = 0;
- range->max_rts = AIRO_DEF_MTU;
- range->min_frag = 256;
- range->max_frag = AIRO_DEF_MTU;
-
- if (cap_rid.softCap & cpu_to_le16(2)) {
- // WEP: RC4 40 bits
- range->encoding_size[0] = 5;
- // RC4 ~128 bits
- if (cap_rid.softCap & cpu_to_le16(0x100)) {
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- } else
- range->num_encoding_sizes = 1;
- range->max_encoding_tokens =
- cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1;
- } else {
- range->num_encoding_sizes = 0;
- range->max_encoding_tokens = 0;
- }
- range->min_pmp = 0;
- range->max_pmp = 5000000; /* 5 secs */
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1024; /* ??? */
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
-
- /* Transmit Power - values are in mW */
- for (i = 0 ; i < 8 ; i++) {
- range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]);
- if (range->txpower[i] == 0)
- break;
- }
- range->num_txpower = i;
- range->txpower_capa = IW_TXPOW_MWATT;
- range->we_version_source = 19;
- range->we_version_compiled = WIRELESS_EXT;
- range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = IW_RETRY_LIFETIME;
- range->min_retry = 1;
- range->max_retry = 65535;
- range->min_r_time = 1024;
- range->max_r_time = 65535 * 1024;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
- range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Power Management
- */
-static int airo_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- if (vwrq->disabled) {
- if (sniffing_mode(local))
- return -EINVAL;
- local->config.powerSaveMode = POWERSAVE_CAM;
- local->config.rmode &= ~RXMODE_MASK;
- local->config.rmode |= RXMODE_BC_MC_ADDR;
- set_bit (FLAG_COMMIT, &local->flags);
- return -EINPROGRESS; /* Call commit handler */
- }
- if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024);
- local->config.powerSaveMode = POWERSAVE_PSPCAM;
- set_bit (FLAG_COMMIT, &local->flags);
- } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- local->config.fastListenInterval =
- local->config.listenInterval =
- cpu_to_le16((vwrq->value + 500) / 1024);
- local->config.powerSaveMode = POWERSAVE_PSPCAM;
- set_bit (FLAG_COMMIT, &local->flags);
- }
- switch (vwrq->flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- if (sniffing_mode(local))
- return -EINVAL;
- local->config.rmode &= ~RXMODE_MASK;
- local->config.rmode |= RXMODE_ADDR;
- set_bit (FLAG_COMMIT, &local->flags);
- break;
- case IW_POWER_ALL_R:
- if (sniffing_mode(local))
- return -EINVAL;
- local->config.rmode &= ~RXMODE_MASK;
- local->config.rmode |= RXMODE_BC_MC_ADDR;
- set_bit (FLAG_COMMIT, &local->flags);
- break;
- case IW_POWER_ON:
- /* This is broken, fixme ;-) */
- break;
- default:
- return -EINVAL;
- }
- // Note : we may want to factor local->need_commit here
- // Note2 : may also want to factor RXMODE_RFMON test
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Power Management
- */
-static int airo_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct airo_info *local = dev->ml_priv;
- __le16 mode;
-
- readConfigRid(local, 1);
- mode = local->config.powerSaveMode;
- if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
- return 0;
- if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024;
- vwrq->flags = IW_POWER_TIMEOUT;
- } else {
- vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024;
- vwrq->flags = IW_POWER_PERIOD;
- }
- if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR)
- vwrq->flags |= IW_POWER_UNICAST_R;
- else
- vwrq->flags |= IW_POWER_ALL_R;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Sensitivity
- */
-static int airo_set_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->sens;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- local->config.rssiThreshold =
- cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Sensitivity
- */
-static int airo_get_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->sens;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.rssiThreshold);
- vwrq->disabled = (vwrq->value == 0);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get AP List
- * Note : this is deprecated in favor of IWSCAN
- */
-static int airo_get_aplist(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
- struct sockaddr *address = (struct sockaddr *) extra;
- struct iw_quality *qual;
- BSSListRid BSSList;
- int i;
- int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
-
- qual = kmalloc_array(IW_MAX_AP, sizeof(*qual), GFP_KERNEL);
- if (!qual)
- return -ENOMEM;
-
- for (i = 0; i < IW_MAX_AP; i++) {
- u16 dBm;
- if (readBSSListRid(local, loseSync, &BSSList))
- break;
- loseSync = 0;
- memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
- address[i].sa_family = ARPHRD_ETHER;
- dBm = le16_to_cpu(BSSList.dBm);
- if (local->rssi) {
- qual[i].level = 0x100 - dBm;
- qual[i].qual = airo_dbm_to_pct(local->rssi, dBm);
- qual[i].updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- } else {
- qual[i].level = (dBm + 321) / 2;
- qual[i].qual = 0;
- qual[i].updated = IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- }
- qual[i].noise = local->wstats.qual.noise;
- if (BSSList.index == cpu_to_le16(0xffff))
- break;
- }
- if (!i) {
- StatusRid status_rid; /* Card status info */
- readStatusRid(local, &status_rid, 1);
- for (i = 0;
- i < min(IW_MAX_AP, 4) &&
- (status_rid.bssid[i][0]
- & status_rid.bssid[i][1]
- & status_rid.bssid[i][2]
- & status_rid.bssid[i][3]
- & status_rid.bssid[i][4]
- & status_rid.bssid[i][5])!=0xff &&
- (status_rid.bssid[i][0]
- | status_rid.bssid[i][1]
- | status_rid.bssid[i][2]
- | status_rid.bssid[i][3]
- | status_rid.bssid[i][4]
- | status_rid.bssid[i][5]);
- i++) {
- memcpy(address[i].sa_data,
- status_rid.bssid[i], ETH_ALEN);
- address[i].sa_family = ARPHRD_ETHER;
- }
- } else {
- dwrq->flags = 1; /* Should be define'd */
- memcpy(extra + sizeof(struct sockaddr) * i, qual,
- sizeof(struct iw_quality) * i);
- }
- dwrq->length = i;
-
- kfree(qual);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : Initiate Scan
- */
-static int airo_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct airo_info *ai = dev->ml_priv;
- Cmd cmd;
- Resp rsp;
- int wake = 0;
- APListRid APList_rid_empty;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
- if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
-
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
-
- /* If there's already a scan in progress, don't
- * trigger another one. */
- if (ai->scan_timeout > 0)
- goto out;
-
- /* Clear APList as it affects scan results */
- memset(&APList_rid_empty, 0, sizeof(APList_rid_empty));
- APList_rid_empty.len = cpu_to_le16(sizeof(APList_rid_empty));
- disable_MAC(ai, 2);
- writeAPListRid(ai, &APList_rid_empty, 0);
- enable_MAC(ai, 0);
-
- /* Initiate a scan command */
- ai->scan_timeout = RUN_AT(3*HZ);
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LISTBSS;
- issuecommand(ai, &cmd, &rsp, true);
- wake = 1;
-
-out:
- up(&ai->sem);
- if (wake)
- wake_up_interruptible(&ai->thr_wait);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Translate scan data returned from the card to a card independent
- * format that the Wireless Tools will understand - Jean II
- */
-static inline char *airo_translate_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- BSSListRid *bss)
-{
- struct airo_info *ai = dev->ml_priv;
- struct iw_event iwe; /* Temporary buffer */
- __le16 capabilities;
- char * current_val; /* For rates */
- int i;
- char * buf;
- u16 dBm;
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- iwe.u.data.length = bss->ssidLen;
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->ssid);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- capabilities = bss->cap;
- if (capabilities & (CAP_ESS | CAP_IBSS)) {
- if (capabilities & CAP_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- /* Add frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
- iwe.u.freq.m = 100000 *
- ieee80211_channel_to_frequency(iwe.u.freq.m, NL80211_BAND_2GHZ);
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- dBm = le16_to_cpu(bss->dBm);
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- if (ai->rssi) {
- iwe.u.qual.level = 0x100 - dBm;
- iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- } else {
- iwe.u.qual.level = (dBm + 321) / 2;
- iwe.u.qual.qual = 0;
- iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- }
- iwe.u.qual.noise = ai->wstats.qual.noise;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & CAP_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->ssid);
-
- /* Rate : stuffing multiple values in a single event require a bit
- * more of magic - Jean II */
- current_val = current_ev + iwe_stream_lcp_len(info);
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- /* Max 8 values */
- for (i = 0 ; i < 8 ; i++) {
- /* NULL terminated */
- if (bss->rates[i] == 0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, current_ev,
- current_val, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
-
- /* Beacon interval */
- buf = kmalloc(30, GFP_KERNEL);
- if (buf) {
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "bcn_int=%d", bss->beaconInterval);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
- kfree(buf);
- }
-
- /* Put WPA/RSN Information Elements into the event stream */
- if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
- unsigned int num_null_ies = 0;
- u16 length = sizeof (bss->extra.iep);
- u8 *ie = (void *)&bss->extra.iep;
-
- while ((length >= 2) && (num_null_ies < 2)) {
- if (2 + ie[1] > length) {
- /* Invalid element, don't continue parsing IE */
- break;
- }
-
- switch (ie[0]) {
- case WLAN_EID_SSID:
- /* Two zero-length SSID elements
- * mean we're done parsing elements */
- if (!ie[1])
- num_null_ies++;
- break;
-
- case WLAN_EID_VENDOR_SPECIFIC:
- if (ie[1] >= 4 &&
- ie[2] == 0x00 &&
- ie[3] == 0x50 &&
- ie[4] == 0xf2 &&
- ie[5] == 0x01) {
- iwe.cmd = IWEVGENIE;
- /* 64 is an arbitrary cut-off */
- iwe.u.data.length = min(ie[1] + 2,
- 64);
- current_ev = iwe_stream_add_point(
- info, current_ev,
- end_buf, &iwe, ie);
- }
- break;
-
- case WLAN_EID_RSN:
- iwe.cmd = IWEVGENIE;
- /* 64 is an arbitrary cut-off */
- iwe.u.data.length = min(ie[1] + 2, 64);
- current_ev = iwe_stream_add_point(
- info, current_ev, end_buf,
- &iwe, ie);
- break;
-
- default:
- break;
- }
-
- length -= 2 + ie[1];
- ie += 2 + ie[1];
- }
- }
- return current_ev;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : Read Scan Results
- */
-static int airo_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *ai = dev->ml_priv;
- BSSListElement *net;
- int err = 0;
- char *current_ev = extra;
-
- /* If a scan is in-progress, return -EAGAIN */
- if (ai->scan_timeout > 0)
- return -EAGAIN;
-
- if (down_interruptible(&ai->sem))
- return -EAGAIN;
-
- list_for_each_entry (net, &ai->network_list, list) {
- /* Translate to WE format this entry */
- current_ev = airo_translate_scan(dev, info, current_ev,
- extra + dwrq->length,
- &net->bss);
-
- /* Check if there is space for one more entry */
- if ((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
-
- /* Length of data */
- dwrq->length = (current_ev - extra);
- dwrq->flags = 0; /* todo */
-
-out:
- up(&ai->sem);
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Commit handler : called after a bunch of SET operations
- */
-static int airo_config_commit(struct net_device *dev,
- struct iw_request_info *info, /* NULL */
- union iwreq_data *wrqu, /* NULL */
- char *extra) /* NULL */
-{
- struct airo_info *local = dev->ml_priv;
-
- if (!test_bit (FLAG_COMMIT, &local->flags))
- return 0;
-
- /* Some of the "SET" function may have modified some of the
- * parameters. It's now time to commit them in the card */
- disable_MAC(local, 1);
- if (test_bit (FLAG_RESET, &local->flags)) {
- SsidRid SSID_rid;
-
- readSsidRid(local, &SSID_rid);
- if (test_bit(FLAG_MPI,&local->flags))
- setup_card(local, dev, 1);
- else
- reset_airo_card(dev);
- disable_MAC(local, 1);
- writeSsidRid(local, &SSID_rid, 1);
- writeAPListRid(local, &local->APList, 1);
- }
- if (down_interruptible(&local->sem))
- return -ERESTARTSYS;
- writeConfigRid(local, 0);
- enable_MAC(local, 0);
- if (test_bit (FLAG_RESET, &local->flags))
- airo_set_promisc(local, true);
- else
- up(&local->sem);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Structures to export the Wireless Handlers
- */
-
-static const struct iw_priv_args airo_private_args[] = {
-/*{ cmd, set_args, get_args, name } */
- { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
- IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
- { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
-};
-
-static const iw_handler airo_handler[] =
-{
- IW_HANDLER(SIOCSIWCOMMIT, airo_config_commit),
- IW_HANDLER(SIOCGIWNAME, airo_get_name),
- IW_HANDLER(SIOCSIWFREQ, airo_set_freq),
- IW_HANDLER(SIOCGIWFREQ, airo_get_freq),
- IW_HANDLER(SIOCSIWMODE, airo_set_mode),
- IW_HANDLER(SIOCGIWMODE, airo_get_mode),
- IW_HANDLER(SIOCSIWSENS, airo_set_sens),
- IW_HANDLER(SIOCGIWSENS, airo_get_sens),
- IW_HANDLER(SIOCGIWRANGE, airo_get_range),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, airo_set_wap),
- IW_HANDLER(SIOCGIWAP, airo_get_wap),
- IW_HANDLER(SIOCGIWAPLIST, airo_get_aplist),
- IW_HANDLER(SIOCSIWSCAN, airo_set_scan),
- IW_HANDLER(SIOCGIWSCAN, airo_get_scan),
- IW_HANDLER(SIOCSIWESSID, airo_set_essid),
- IW_HANDLER(SIOCGIWESSID, airo_get_essid),
- IW_HANDLER(SIOCSIWNICKN, airo_set_nick),
- IW_HANDLER(SIOCGIWNICKN, airo_get_nick),
- IW_HANDLER(SIOCSIWRATE, airo_set_rate),
- IW_HANDLER(SIOCGIWRATE, airo_get_rate),
- IW_HANDLER(SIOCSIWRTS, airo_set_rts),
- IW_HANDLER(SIOCGIWRTS, airo_get_rts),
- IW_HANDLER(SIOCSIWFRAG, airo_set_frag),
- IW_HANDLER(SIOCGIWFRAG, airo_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, airo_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, airo_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, airo_set_retry),
- IW_HANDLER(SIOCGIWRETRY, airo_get_retry),
- IW_HANDLER(SIOCSIWENCODE, airo_set_encode),
- IW_HANDLER(SIOCGIWENCODE, airo_get_encode),
- IW_HANDLER(SIOCSIWPOWER, airo_set_power),
- IW_HANDLER(SIOCGIWPOWER, airo_get_power),
- IW_HANDLER(SIOCSIWAUTH, airo_set_auth),
- IW_HANDLER(SIOCGIWAUTH, airo_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, airo_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, airo_get_encodeext),
-};
-
-/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
- * We want to force the use of the ioctl code, because those can't be
- * won't work the iw_handler code (because they simultaneously read
- * and write data and iw_handler can't do that).
- * Note that it's perfectly legal to read/write on a single ioctl command,
- * you just can't use iwpriv and need to force it via the ioctl handler.
- * Jean II */
-static const iw_handler airo_private_handler[] =
-{
- NULL, /* SIOCIWFIRSTPRIV */
-};
-
-static const struct iw_handler_def airo_handler_def =
-{
- .num_standard = ARRAY_SIZE(airo_handler),
- .num_private = ARRAY_SIZE(airo_private_handler),
- .num_private_args = ARRAY_SIZE(airo_private_args),
- .standard = airo_handler,
- .private = airo_private_handler,
- .private_args = airo_private_args,
- .get_wireless_stats = airo_get_wireless_stats,
-};
-
-/*
- * This defines the configuration part of the Wireless Extensions
- * Note : irq and spinlock protection will occur in the subroutines
- *
- * TODO :
- * o Check input value more carefully and fill correct values in range
- * o Test and shakeout the bugs (if any)
- *
- * Jean II
- *
- * Javier Achirica did a great job of merging code from the unnamed CISCO
- * developer that added support for flashing the card.
- */
-static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq,
- void __user *data, int cmd)
-{
- int rc = 0;
- struct airo_info *ai = dev->ml_priv;
-
- if (ai->power.event)
- return 0;
-
- switch (cmd) {
-#ifdef CISCO_EXT
- case AIROIDIFC:
-#ifdef AIROOLDIDIFC
- case AIROOLDIDIFC:
-#endif
- {
- int val = AIROMAGIC;
- aironet_ioctl com;
- if (copy_from_user(&com, data, sizeof(com)))
- rc = -EFAULT;
- else if (copy_to_user(com.data, (char *)&val, sizeof(val)))
- rc = -EFAULT;
- }
- break;
-
- case AIROIOCTL:
-#ifdef AIROOLDIOCTL
- case AIROOLDIOCTL:
-#endif
- /* Get the command struct and hand it off for evaluation by
- * the proper subfunction
- */
- {
- aironet_ioctl com;
- if (copy_from_user(&com, data, sizeof(com))) {
- rc = -EFAULT;
- break;
- }
-
- /* Separate R/W functions bracket legality here
- */
- if (com.command == AIRORSWVERSION) {
- if (copy_to_user(com.data, swversion, sizeof(swversion)))
- rc = -EFAULT;
- else
- rc = 0;
- }
- else if (com.command <= AIRORRID)
- rc = readrids(dev,&com);
- else if (com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2))
- rc = writerids(dev,&com);
- else if (com.command >= AIROFLSHRST && com.command <= AIRORESTART)
- rc = flashcard(dev,&com);
- else
- rc = -EINVAL; /* Bad command in ioctl */
- }
- break;
-#endif /* CISCO_EXT */
-
- // All other calls are currently unsupported
- default:
- rc = -EOPNOTSUPP;
- }
- return rc;
-}
-
-/*
- * Get the Wireless stats out of the driver
- * Note : irq and spinlock protection will occur in the subroutines
- *
- * TODO :
- * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
- *
- * Jean
- */
-static void airo_read_wireless_stats(struct airo_info *local)
-{
- StatusRid status_rid;
- StatsRid stats_rid;
- CapabilityRid cap_rid;
- __le32 *vals = stats_rid.vals;
-
- /* Get stats out of the card */
- if (local->power.event)
- return;
-
- readCapabilityRid(local, &cap_rid, 0);
- readStatusRid(local, &status_rid, 0);
- readStatsRid(local, &stats_rid, RID_STATS, 0);
-
- /* The status */
- local->wstats.status = le16_to_cpu(status_rid.mode);
-
- /* Signal quality and co */
- if (local->rssi) {
- local->wstats.qual.level =
- airo_rssi_to_dbm(local->rssi,
- le16_to_cpu(status_rid.sigQuality));
- /* normalizedSignalStrength appears to be a percentage */
- local->wstats.qual.qual =
- le16_to_cpu(status_rid.normalizedSignalStrength);
- } else {
- local->wstats.qual.level =
- (le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2;
- local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
- }
- if (le16_to_cpu(status_rid.len) >= 124) {
- local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
- local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- } else {
- local->wstats.qual.noise = 0;
- local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM;
- }
-
- /* Packets discarded in the wireless adapter due to wireless
- * specific problems */
- local->wstats.discard.nwid = le32_to_cpu(vals[56]) +
- le32_to_cpu(vals[57]) +
- le32_to_cpu(vals[58]); /* SSID Mismatch */
- local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */
- local->wstats.discard.fragment = le32_to_cpu(vals[30]);
- local->wstats.discard.retries = le32_to_cpu(vals[10]);
- local->wstats.discard.misc = le32_to_cpu(vals[1]) +
- le32_to_cpu(vals[32]);
- local->wstats.miss.beacon = le32_to_cpu(vals[34]);
-}
-
-static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
-{
- struct airo_info *local = dev->ml_priv;
-
- if (!down_interruptible(&local->sem)) {
- airo_read_wireless_stats(local);
- up(&local->sem);
- }
- return &local->wstats;
-}
-
-#ifdef CISCO_EXT
-/*
- * This just translates from driver IOCTL codes to the command codes to
- * feed to the radio's host interface. Things can be added/deleted
- * as needed. This represents the READ side of control I/O to
- * the card
- */
-static int readrids(struct net_device *dev, aironet_ioctl *comp)
-{
- unsigned short ridcode;
- unsigned char *iobuf;
- int len;
- struct airo_info *ai = dev->ml_priv;
-
- if (test_bit(FLAG_FLASHING, &ai->flags))
- return -EIO;
-
- switch(comp->command)
- {
- case AIROGCAP: ridcode = RID_CAPABILITIES; break;
- case AIROGCFG: ridcode = RID_CONFIG;
- if (test_bit(FLAG_COMMIT, &ai->flags)) {
- disable_MAC (ai, 1);
- writeConfigRid (ai, 1);
- enable_MAC(ai, 1);
- }
- break;
- case AIROGSLIST: ridcode = RID_SSID; break;
- case AIROGVLIST: ridcode = RID_APLIST; break;
- case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
- case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
- case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break;
- case AIROGWEPKNV: ridcode = RID_WEP_PERM; break;
- case AIROGSTAT: ridcode = RID_STATUS; break;
- case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
- case AIROGSTATSC32: ridcode = RID_STATS; break;
- case AIROGMICSTATS:
- if (copy_to_user(comp->data, &ai->micstats,
- min((int)comp->len, (int)sizeof(ai->micstats))))
- return -EFAULT;
- return 0;
- case AIRORRID: ridcode = comp->ridnum; break;
- default:
- return -EINVAL;
- }
-
- if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) {
- /* Only super-user can read WEP keys */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- }
-
- if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- PC4500_readrid(ai, ridcode, iobuf, RIDSIZE, 1);
- /* get the count of bytes in the rid docs say 1st 2 bytes is it.
- * then return it to the user
- * 9/22/2000 Honor user given length
- */
- len = comp->len;
-
- if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
- kfree (iobuf);
- return -EFAULT;
- }
- kfree (iobuf);
- return 0;
-}
-
-/*
- * Danger Will Robinson write the rids here
- */
-
-static int writerids(struct net_device *dev, aironet_ioctl *comp)
-{
- struct airo_info *ai = dev->ml_priv;
- int ridcode;
- int enabled;
- int (*writer)(struct airo_info *, u16 rid, const void *, int, int);
- unsigned char *iobuf;
-
- /* Only super-user can write RIDs */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (test_bit(FLAG_FLASHING, &ai->flags))
- return -EIO;
-
- ridcode = 0;
- writer = do_writerid;
-
- switch(comp->command)
- {
- case AIROPSIDS: ridcode = RID_SSID; break;
- case AIROPCAP: ridcode = RID_CAPABILITIES; break;
- case AIROPAPLIST: ridcode = RID_APLIST; break;
- case AIROPCFG: ai->config.len = 0;
- clear_bit(FLAG_COMMIT, &ai->flags);
- ridcode = RID_CONFIG; break;
- case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
- case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
- case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
- case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
- break;
- case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
- case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
-
- /* this is not really a rid but a command given to the card
- * same with MAC off
- */
- case AIROPMACON:
- if (enable_MAC(ai, 1) != 0)
- return -EIO;
- return 0;
-
- /*
- * Evidently this code in the airo driver does not get a symbol
- * as disable_MAC. it's probably so short the compiler does not gen one.
- */
- case AIROPMACOFF:
- disable_MAC(ai, 1);
- return 0;
-
- /* This command merely clears the counts does not actually store any data
- * only reads rid. But as it changes the cards state, I put it in the
- * writerid routines.
- */
- case AIROPSTCLR:
- if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- PC4500_readrid(ai, RID_STATSDELTACLEAR, iobuf, RIDSIZE, 1);
-
- enabled = ai->micstats.enabled;
- memset(&ai->micstats, 0, sizeof(ai->micstats));
- ai->micstats.enabled = enabled;
-
- if (copy_to_user(comp->data, iobuf,
- min((int)comp->len, (int)RIDSIZE))) {
- kfree (iobuf);
- return -EFAULT;
- }
- kfree (iobuf);
- return 0;
-
- default:
- return -EOPNOTSUPP; /* Blarg! */
- }
- if (comp->len > RIDSIZE)
- return -EINVAL;
-
- if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- if (copy_from_user(iobuf, comp->data, comp->len)) {
- kfree (iobuf);
- return -EFAULT;
- }
-
- if (comp->command == AIROPCFG) {
- ConfigRid *cfg = (ConfigRid *)iobuf;
-
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
- cfg->opmode |= MODE_MIC;
-
- if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS)
- set_bit (FLAG_ADHOC, &ai->flags);
- else
- clear_bit (FLAG_ADHOC, &ai->flags);
- }
-
- if ((*writer)(ai, ridcode, iobuf, comp->len, 1)) {
- kfree (iobuf);
- return -EIO;
- }
- kfree (iobuf);
- return 0;
-}
-
-/*****************************************************************************
- * Ancillary flash / mod functions much black magic lurkes here *
- *****************************************************************************
- */
-
-/*
- * Flash command switch table
- */
-
-static int flashcard(struct net_device *dev, aironet_ioctl *comp)
-{
- int z;
-
- /* Only super-user can modify flash */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch(comp->command)
- {
- case AIROFLSHRST:
- return cmdreset((struct airo_info *)dev->ml_priv);
-
- case AIROFLSHSTFL:
- if (!AIRO_FLASH(dev) &&
- (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- return setflashmode((struct airo_info *)dev->ml_priv);
-
- case AIROFLSHGCHR: /* Get char from aux */
- if (comp->len != sizeof(int))
- return -EINVAL;
- if (copy_from_user(&z, comp->data, comp->len))
- return -EFAULT;
- return flashgchar((struct airo_info *)dev->ml_priv, z, 8000);
-
- case AIROFLSHPCHR: /* Send char to card. */
- if (comp->len != sizeof(int))
- return -EINVAL;
- if (copy_from_user(&z, comp->data, comp->len))
- return -EFAULT;
- return flashpchar((struct airo_info *)dev->ml_priv, z, 8000);
-
- case AIROFLPUTBUF: /* Send 32k to card */
- if (!AIRO_FLASH(dev))
- return -ENOMEM;
- if (comp->len > FLASHSIZE)
- return -EINVAL;
- if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len))
- return -EFAULT;
-
- flashputbuf((struct airo_info *)dev->ml_priv);
- return 0;
-
- case AIRORESTART:
- if (flashrestart((struct airo_info *)dev->ml_priv, dev))
- return -EIO;
- return 0;
- }
- return -EINVAL;
-}
-
-#define FLASH_COMMAND 0x7e7e
-
-/*
- * STEP 1)
- * Disable MAC and do soft reset on
- * card.
- */
-
-static int cmdreset(struct airo_info *ai)
-{
- disable_MAC(ai, 1);
-
- if (!waitbusy (ai)) {
- airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
- return -EBUSY;
- }
-
- OUT4500(ai, COMMAND, CMD_SOFTRESET);
-
- ssleep(1); /* WAS 600 12/7/00 */
-
- if (!waitbusy (ai)) {
- airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
- return -EBUSY;
- }
- return 0;
-}
-
-/* STEP 2)
- * Put the card in legendary flash
- * mode
- */
-
-static int setflashmode (struct airo_info *ai)
-{
- set_bit (FLAG_FLASHING, &ai->flags);
-
- OUT4500(ai, SWS0, FLASH_COMMAND);
- OUT4500(ai, SWS1, FLASH_COMMAND);
- if (probe) {
- OUT4500(ai, SWS0, FLASH_COMMAND);
- OUT4500(ai, COMMAND, 0x10);
- } else {
- OUT4500(ai, SWS2, FLASH_COMMAND);
- OUT4500(ai, SWS3, FLASH_COMMAND);
- OUT4500(ai, COMMAND, 0);
- }
- msleep(500); /* 500ms delay */
-
- if (!waitbusy(ai)) {
- clear_bit (FLAG_FLASHING, &ai->flags);
- airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
- return -EIO;
- }
- return 0;
-}
-
-/* Put character to SWS0 wait for dwelltime
- * x 50us for echo .
- */
-
-static int flashpchar(struct airo_info *ai, int byte, int dwelltime)
-{
- int echo;
- int waittime;
-
- byte |= 0x8000;
-
- if (dwelltime == 0)
- dwelltime = 200;
-
- waittime = dwelltime;
-
- /* Wait for busy bit d15 to go false indicating buffer empty */
- while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
- udelay (50);
- waittime -= 50;
- }
-
- /* timeout for busy clear wait */
- if (waittime <= 0) {
- airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
- return -EBUSY;
- }
-
- /* Port is clear now write byte and wait for it to echo back */
- do {
- OUT4500(ai, SWS0, byte);
- udelay(50);
- dwelltime -= 50;
- echo = IN4500(ai, SWS1);
- } while (dwelltime >= 0 && echo != byte);
-
- OUT4500(ai, SWS1, 0);
-
- return (echo == byte) ? 0 : -EIO;
-}
-
-/*
- * Get a character from the card matching matchbyte
- * Step 3)
- */
-static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime)
-{
- int rchar;
- unsigned char rbyte = 0;
-
- do {
- rchar = IN4500(ai, SWS1);
-
- if (dwelltime && !(0x8000 & rchar)) {
- dwelltime -= 10;
- mdelay(10);
- continue;
- }
- rbyte = 0xff & rchar;
-
- if ((rbyte == matchbyte) && (0x8000 & rchar)) {
- OUT4500(ai, SWS1, 0);
- return 0;
- }
- if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
- break;
- OUT4500(ai, SWS1, 0);
-
- } while (dwelltime > 0);
- return -EIO;
-}
-
-/*
- * Transfer 32k of firmware data from user buffer to our buffer and
- * send to the card
- */
-
-static int flashputbuf(struct airo_info *ai)
-{
- int nwords;
-
- /* Write stuff */
- if (test_bit(FLAG_MPI,&ai->flags))
- memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
- else {
- OUT4500(ai, AUXPAGE, 0x100);
- OUT4500(ai, AUXOFF, 0);
-
- for (nwords = 0; nwords != FLASHSIZE / 2; nwords++) {
- OUT4500(ai, AUXDATA, ai->flash[nwords] & 0xffff);
- }
- }
- OUT4500(ai, SWS0, 0x8000);
-
- return 0;
-}
-
-/*
- *
- */
-static int flashrestart(struct airo_info *ai, struct net_device *dev)
-{
- int i, status;
-
- ssleep(1); /* Added 12/7/00 */
- clear_bit (FLAG_FLASHING, &ai->flags);
- if (test_bit(FLAG_MPI, &ai->flags)) {
- status = mpi_init_descriptors(ai);
- if (status != SUCCESS)
- return status;
- }
- status = setup_card(ai, dev, 1);
-
- if (!test_bit(FLAG_MPI,&ai->flags))
- for (i = 0; i < MAX_FIDS; i++) {
- ai->fids[i] = transmit_allocate
- (ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2);
- }
-
- ssleep(1); /* Added 12/7/00 */
- return status;
-}
-#endif /* CISCO_EXT */
-
-/*
- 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 Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- In addition:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-
-module_init(airo_init_module);
-module_exit(airo_cleanup_module);
diff --git a/drivers/net/wireless/cisco/airo.h b/drivers/net/wireless/cisco/airo.h
deleted file mode 100644
index 8a02977a2e2b..000000000000
--- a/drivers/net/wireless/cisco/airo.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _AIRO_H_
-#define _AIRO_H_
-
-struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia,
- struct device *dmdev);
-int reset_airo_card(struct net_device *dev);
-void stop_airo_card(struct net_device *dev, int freeres);
-
-#endif /* _AIRO_H_ */
diff --git a/drivers/net/wireless/cisco/airo_cs.c b/drivers/net/wireless/cisco/airo_cs.c
deleted file mode 100644
index fcfe4c6d62f0..000000000000
--- a/drivers/net/wireless/cisco/airo_cs.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*======================================================================
-
- Aironet driver for 4500 and 4800 series cards
-
- This code is released under both the GPL version 2 and BSD licenses.
- Either license may be used. The respective licenses are found at
- the end of this file.
-
- This code was developed by Benjamin Reed <breed@users.sourceforge.net>
- including portions of which come from the Aironet PC4500
- Developer's Reference Manual and used with permission. Copyright
- (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use
- code in the Developer's manual was granted for this driver by
- Aironet.
-
- In addition this module was derived from dummy_cs.
- The initial developer of dummy_cs is David A. Hinds
- <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
- are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-
-======================================================================*/
-
-#ifdef __IN_PCMCIA_PACKAGE__
-#include <pcmcia/k_compat.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/netdevice.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <linux/io.h>
-
-#include "airo.h"
-
-
-/*====================================================================*/
-
-MODULE_AUTHOR("Benjamin Reed");
-MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet "
- "cards. This is the module that links the PCMCIA card "
- "with the airo module.");
-MODULE_LICENSE("Dual BSD/GPL");
-
-/*====================================================================*/
-
-static int airo_config(struct pcmcia_device *link);
-static void airo_release(struct pcmcia_device *link);
-
-static void airo_detach(struct pcmcia_device *p_dev);
-
-struct local_info {
- struct net_device *eth_dev;
-};
-
-static int airo_probe(struct pcmcia_device *p_dev)
-{
- struct local_info *local;
-
- dev_dbg(&p_dev->dev, "airo_attach()\n");
-
- /* Allocate space for private device-specific data */
- local = kzalloc(sizeof(*local), GFP_KERNEL);
- if (!local)
- return -ENOMEM;
-
- p_dev->priv = local;
-
- return airo_config(p_dev);
-} /* airo_attach */
-
-static void airo_detach(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "airo_detach\n");
-
- airo_release(link);
-
- if (((struct local_info *)link->priv)->eth_dev) {
- stop_airo_card(((struct local_info *)link->priv)->eth_dev,
- 0);
- }
- ((struct local_info *)link->priv)->eth_dev = NULL;
-
- kfree(link->priv);
-} /* airo_detach */
-
-static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-}
-
-
-static int airo_config(struct pcmcia_device *link)
-{
- int ret;
-
- dev_dbg(&link->dev, "airo_config\n");
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
- CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
-
- ret = pcmcia_loop_config(link, airo_cs_config_check, NULL);
- if (ret)
- goto failed;
-
- if (!link->irq)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
- ((struct local_info *)link->priv)->eth_dev =
- init_airo_card(link->irq,
- link->resource[0]->start, 1, &link->dev);
- if (!((struct local_info *)link->priv)->eth_dev)
- goto failed;
-
- return 0;
-
- failed:
- airo_release(link);
- return -ENODEV;
-} /* airo_config */
-
-static void airo_release(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "airo_release\n");
- pcmcia_disable_device(link);
-}
-
-static int airo_suspend(struct pcmcia_device *link)
-{
- struct local_info *local = link->priv;
-
- netif_device_detach(local->eth_dev);
-
- return 0;
-}
-
-static int airo_resume(struct pcmcia_device *link)
-{
- struct local_info *local = link->priv;
-
- if (link->open) {
- reset_airo_card(local->eth_dev);
- netif_device_attach(local->eth_dev);
- }
-
- return 0;
-}
-
-static const struct pcmcia_device_id airo_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
- PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
- PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
- PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007),
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, airo_ids);
-
-static struct pcmcia_driver airo_driver = {
- .owner = THIS_MODULE,
- .name = "airo_cs",
- .probe = airo_probe,
- .remove = airo_detach,
- .id_table = airo_ids,
- .suspend = airo_suspend,
- .resume = airo_resume,
-};
-module_pcmcia_driver(airo_driver);
-
-/*
- 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 Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- In addition:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
index 69276266ce6f..70e420df1643 100644
--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
@@ -4231,8 +4231,6 @@ il4965_rx_handle(struct il_priv *il)
fill_rx = 1;
while (i != r) {
- int len;
-
rxb = rxq->queue[i];
/* If an RXB doesn't have a Rx queue slot associated with it,
@@ -4246,10 +4244,6 @@ il4965_rx_handle(struct il_priv *il)
PAGE_SIZE << il->hw_params.rx_page_order,
DMA_FROM_DEVICE);
pkt = rxb_addr(rxb);
-
- len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK;
- len += sizeof(u32); /* account for status word */
-
reclaim = il_need_reclaim(il, pkt);
/* Based on type of command response or notification,
diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c
index 054fef680aba..17570d62c896 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -541,6 +541,9 @@ il_leds_init(struct il_priv *il)
il->led.name =
kasprintf(GFP_KERNEL, "%s-led", wiphy_name(il->hw->wiphy));
+ if (!il->led.name)
+ return;
+
il->led.brightness_set = il_led_brightness_set;
il->led.blink_set = il_led_blink_set;
il->led.max_brightness = 1;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index b96f30d11644..dcc4810cb324 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -618,7 +618,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
&tbl_rev);
if (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 2) {
- ret = PTR_ERR(wifi_pkg);
+ ret = -EINVAL;
goto out_free;
}
@@ -634,7 +634,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
&tbl_rev);
if (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 1) {
- ret = PTR_ERR(wifi_pkg);
+ ret = -EINVAL;
goto out_free;
}
@@ -650,7 +650,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
&tbl_rev);
if (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 0) {
- ret = PTR_ERR(wifi_pkg);
+ ret = -EINVAL;
goto out_free;
}
@@ -707,7 +707,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
&tbl_rev);
if (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 2) {
- ret = PTR_ERR(wifi_pkg);
+ ret = -EINVAL;
goto out_free;
}
@@ -723,7 +723,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
&tbl_rev);
if (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 1) {
- ret = PTR_ERR(wifi_pkg);
+ ret = -EINVAL;
goto out_free;
}
@@ -739,7 +739,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
&tbl_rev);
if (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 0) {
- ret = PTR_ERR(wifi_pkg);
+ ret = -EINVAL;
goto out_free;
}
@@ -1116,6 +1116,9 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
goto read_table;
}
+ ret = PTR_ERR(wifi_pkg);
+ goto out_free;
+
read_table:
fwrt->ppag_ver = tbl_rev;
flags = &wifi_pkg->package.elements[1];
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
index 7b18e098b125..b740c65a7dca 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/debug.h
@@ -60,6 +60,12 @@ enum iwl_debug_cmds {
*/
FW_DUMP_COMPLETE_CMD = 0xB,
/**
+ * @FW_CLEAR_BUFFER:
+ * clears the firmware's internal buffer
+ * no payload
+ */
+ FW_CLEAR_BUFFER = 0xD,
+ /**
* @MFU_ASSERT_DUMP_NTF:
* &struct iwl_mfu_assert_dump_notif
*/
@@ -531,7 +537,7 @@ enum iwl_fw_dbg_config_cmd_type {
}; /* LDBG_CFG_CMD_TYPE_API_E_VER_1 */
/* this token disables debug asserts in the firmware */
-#define IWL_FW_DBG_CONFIG_TOKEN 0x00011301
+#define IWL_FW_DBG_CONFIG_TOKEN 0x00010001
/**
* struct iwl_fw_dbg_config_cmd - configure FW debug
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
index dfe0bebabc81..7ec959244ffc 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -269,6 +269,9 @@ struct iwl_nvm_access_complete_cmd {
__le32 reserved;
} __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */
+#define IWL_MCC_US 0x5553
+#define IWL_MCC_CANADA 0x4341
+
/**
* struct iwl_mcc_update_cmd - Request the device to update geographic
* regulatory profile according to the given MCC (Mobile Country Code).
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h
index 9c69d3674384..e6c0f928a6bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/txq.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2005-2014, 2019-2021, 2023 Intel Corporation
+ * Copyright (C) 2005-2014, 2019-2021, 2023-2024 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2016-2017 Intel Deutschland GmbH
*/
@@ -66,6 +66,16 @@ enum iwl_gen2_tx_fifo {
IWL_GEN2_TRIG_TX_FIFO_VO,
};
+enum iwl_bz_tx_fifo {
+ IWL_BZ_EDCA_TX_FIFO_BK,
+ IWL_BZ_EDCA_TX_FIFO_BE,
+ IWL_BZ_EDCA_TX_FIFO_VI,
+ IWL_BZ_EDCA_TX_FIFO_VO,
+ IWL_BZ_TRIG_TX_FIFO_BK,
+ IWL_BZ_TRIG_TX_FIFO_BE,
+ IWL_BZ_TRIG_TX_FIFO_VI,
+ IWL_BZ_TRIG_TX_FIFO_VO,
+};
/**
* enum iwl_tx_queue_cfg_actions - TXQ config options
* @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
index 3975a53a9f20..80fda056e46a 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2005-2014, 2018-2023 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2024 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
*/
@@ -19,7 +19,6 @@
* @fwrt_ptr: pointer to the buffer coming from fwrt
* @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the
* transport's data.
- * @trans_len: length of the valid data in trans_ptr
* @fwrt_len: length of the valid data in fwrt_ptr
*/
struct iwl_fw_dump_ptrs {
@@ -880,10 +879,10 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt,
cpu_to_le32(fwrt->trans->hw_rev_step);
memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable,
sizeof(dump_info->fw_human_readable));
- strncpy(dump_info->dev_human_readable, fwrt->trans->name,
- sizeof(dump_info->dev_human_readable) - 1);
- strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name,
- sizeof(dump_info->bus_human_readable) - 1);
+ strscpy_pad(dump_info->dev_human_readable, fwrt->trans->name,
+ sizeof(dump_info->dev_human_readable));
+ strscpy_pad(dump_info->bus_human_readable, fwrt->dev->bus->name,
+ sizeof(dump_info->bus_human_readable));
dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs;
dump_info->lmac_err_id[0] =
cpu_to_le32(fwrt->dump.lmac_err_id[0]);
@@ -3395,3 +3394,22 @@ void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt)
iwl_trans_send_cmd(fwrt->trans, &hcmd);
}
IWL_EXPORT_SYMBOL(iwl_fw_disable_dbg_asserts);
+
+void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt)
+{
+ struct iwl_fw_dbg_params params = {0};
+
+ iwl_fw_dbg_stop_sync(fwrt);
+
+ if (fw_has_api(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR)) {
+ struct iwl_host_cmd hcmd = {
+ .id = WIDE_ID(DEBUG_GROUP, FW_CLEAR_BUFFER),
+ };
+ iwl_trans_send_cmd(fwrt->trans, &hcmd);
+ }
+
+ iwl_dbg_tlv_init_cfg(fwrt);
+ iwl_fw_dbg_stop_restart_recording(fwrt, &params, false);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_dbg_clear_monitor_buf);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
index 66b233250c7c..eb38c686b5cb 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h
@@ -330,6 +330,7 @@ void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt,
u32 timepoint,
u32 timepoint_data);
void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt);
+void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt);
#define IWL_FW_CHECK_FAILED(_obj, _fmt, ...) \
IWL_ERR_LIMIT(_obj, _fmt, __VA_ARGS__)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h
index 03f6e520145f..bfc39bd5bbc6 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/file.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h
@@ -20,7 +20,7 @@ struct iwl_ucode_header {
__le32 init_size; /* bytes of init code */
__le32 init_data_size; /* bytes of init data */
__le32 boot_size; /* bytes of bootstrap code */
- u8 data[0]; /* in same order as sizes */
+ u8 data[]; /* in same order as sizes */
} v1;
struct {
__le32 build; /* build number */
@@ -29,7 +29,7 @@ struct iwl_ucode_header {
__le32 init_size; /* bytes of init code */
__le32 init_data_size; /* bytes of init data */
__le32 boot_size; /* bytes of bootstrap code */
- u8 data[0]; /* in same order as sizes */
+ u8 data[]; /* in same order as sizes */
} v2;
} u;
};
@@ -243,6 +243,10 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t;
* version tables.
* @IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG: This ucode supports v3 of
* SCAN_CONFIG_DB_CMD_API_S.
+ * @IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX: Firmware offloaded the station disable tx
+ * logic.
+ * @IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR: Firmware supports clearing the debug
+ * internal buffer
*
* @NUM_IWL_UCODE_TLV_API: number of bits used
*/
@@ -280,6 +284,9 @@ enum iwl_ucode_tlv_api {
IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57,
IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER = (__force iwl_ucode_tlv_api_t)58,
IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59,
+ /* API Set 2 */
+ IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX = (__force iwl_ucode_tlv_api_t)66,
+ IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR = (__force iwl_ucode_tlv_api_t)67,
NUM_IWL_UCODE_TLV_API
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
index 02ded22295c1..ae6f1cd4d660 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h
@@ -377,7 +377,6 @@ struct iwl_cfg {
u16 nvm_calib_ver;
u32 rx_with_siso_diversity:1,
tx_with_siso_diversity:1,
- bt_shared_single_ant:1,
internal_wimax_coex:1,
host_interrupt_operation_mode:1,
high_temp:1,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index a4df67ff21ba..4511d7fb2279 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -354,6 +354,8 @@ enum {
#define CSR_HW_RF_ID_TYPE_GF (0x0010D000)
#define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000)
#define CSR_HW_RF_ID_TYPE_MS (0x00111000)
+#define CSR_HW_RF_ID_TYPE_FM (0x00112000)
+#define CSR_HW_RF_ID_TYPE_WP (0x00113000)
/* HW_RF CHIP STEP */
#define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index b658cf228fbe..72075720969c 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2018-2023 Intel Corporation
+ * Copyright (C) 2018-2024 Intel Corporation
*/
#include <linux/firmware.h>
#include "iwl-drv.h"
@@ -1096,7 +1096,7 @@ static int iwl_dbg_tlv_override_trig_node(struct iwl_fw_runtime *fwrt,
node_trig = (void *)node_tlv->data;
}
- memcpy(node_trig->data + offset, trig->data, trig_data_len);
+ memcpy((u8 *)node_trig->data + offset, trig->data, trig_data_len);
node_tlv->length = cpu_to_le32(size);
if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG) {
@@ -1274,7 +1274,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync,
return 0;
}
-static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt)
+void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt)
{
enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest;
int ret, i;
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h
index 06fb7d665390..7ed6329fd8ca 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h
@@ -57,6 +57,7 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_time_point tp_id,
union iwl_dbg_tlv_tp_data *tp_data,
bool sync);
+void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt);
static inline void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt,
enum iwl_fw_ini_time_point tp_id,
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
index 347fd95c4e3a..2c280a2fe3df 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h
@@ -3,7 +3,7 @@
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
+ * Copyright(c) 2018 - 2019, 2023 Intel Corporation
*****************************************************************************/
#if !defined(__IWLWIFI_DEVICE_TRACE_DATA) || defined(TRACE_HEADER_MULTI_READ)
@@ -36,20 +36,17 @@ TRACE_EVENT(iwlwifi_dev_tx_tb,
TRACE_EVENT(iwlwifi_dev_rx_data,
TP_PROTO(const struct device *dev,
- const struct iwl_trans *trans,
- void *rxbuf, size_t len),
- TP_ARGS(dev, trans, rxbuf, len),
+ void *rxbuf, size_t len, size_t start),
+ TP_ARGS(dev, rxbuf, len, start),
TP_STRUCT__entry(
DEV_ENTRY
- __dynamic_array(u8, data,
- len - iwl_rx_trace_len(trans, rxbuf, len, NULL))
+ __dynamic_array(u8, data, len - start)
),
TP_fast_assign(
- size_t offs = iwl_rx_trace_len(trans, rxbuf, len, NULL);
DEV_ASSIGN;
- if (offs < len)
+ if (start < len)
memcpy(__get_dynamic_array(data),
- ((u8 *)rxbuf) + offs, len - offs);
+ ((u8 *)rxbuf) + start, len - start);
),
TP_printk("[%s] RX frame data", __get_str(dev))
);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
index 46ed723f138a..e656bf6bc003 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-iwlwifi.h
@@ -4,7 +4,7 @@
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Mobile Communications GmbH
* Copyright(c) 2016 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 Intel Corporation
+ * Copyright(c) 2018, 2023 Intel Corporation
*****************************************************************************/
#if !defined(__IWLWIFI_DEVICE_TRACE_IWLWIFI) || defined(TRACE_HEADER_MULTI_READ)
@@ -50,23 +50,20 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
);
TRACE_EVENT(iwlwifi_dev_rx,
- TP_PROTO(const struct device *dev, const struct iwl_trans *trans,
- struct iwl_rx_packet *pkt, size_t len),
- TP_ARGS(dev, trans, pkt, len),
+ TP_PROTO(const struct device *dev,
+ struct iwl_rx_packet *pkt, size_t len, size_t trace_len,
+ size_t hdr_offset),
+ TP_ARGS(dev, pkt, len, trace_len, hdr_offset),
TP_STRUCT__entry(
DEV_ENTRY
__field(u16, cmd)
__field(u8, hdr_offset)
- __dynamic_array(u8, rxbuf,
- iwl_rx_trace_len(trans, pkt, len, NULL))
+ __dynamic_array(u8, rxbuf, trace_len)
),
TP_fast_assign(
- size_t hdr_offset = 0;
-
DEV_ASSIGN;
__entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
- memcpy(__get_dynamic_array(rxbuf), pkt,
- iwl_rx_trace_len(trans, pkt, len, &hdr_offset));
+ memcpy(__get_dynamic_array(rxbuf), pkt, trace_len);
__entry->hdr_offset = hdr_offset;
),
TP_printk("[%s] RX cmd %#.2x",
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
index e46639b097f4..7e686297963d 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.c
@@ -2,7 +2,7 @@
/******************************************************************************
*
* Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018, 2023 Intel Corporation
*****************************************************************************/
#include <linux/module.h>
@@ -20,4 +20,17 @@
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_wrap_event);
-#endif
+#else
+#include "iwl-devtrace.h"
+#endif /* __CHECKER__ */
+
+void __trace_iwlwifi_dev_rx(struct iwl_trans *trans, void *pkt, size_t len)
+{
+ size_t hdr_offset = 0, trace_len;
+
+ trace_len = iwl_rx_trace_len(trans, pkt, len, &hdr_offset);
+ trace_iwlwifi_dev_rx(trans->dev, pkt, len, trace_len, hdr_offset);
+
+ if (trace_len < len)
+ trace_iwlwifi_dev_rx_data(trans->dev, pkt, len, trace_len);
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
index 01fb7b900a6d..c3e09f4fefeb 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace.h
@@ -7,12 +7,12 @@
*****************************************************************************/
#ifndef __IWLWIFI_DEVICE_TRACE
+#define __IWLWIFI_DEVICE_TRACE
#include <linux/skbuff.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <net/mac80211.h>
#include "iwl-trans.h"
-#if !defined(__IWLWIFI_DEVICE_TRACE)
static inline bool iwl_trace_data(struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -70,9 +70,6 @@ static inline size_t iwl_rx_trace_len(const struct iwl_trans *trans,
return sizeof(__le32) + sizeof(*cmd) + trans->rx_mpdu_cmd_hdr_size +
ieee80211_hdrlen(hdr->frame_control);
}
-#endif
-
-#define __IWLWIFI_DEVICE_TRACE
#include <linux/tracepoint.h>
#include <linux/device.h>
@@ -98,4 +95,20 @@ static inline void trace_ ## name(proto) {}
#include "iwl-devtrace-data.h"
#include "iwl-devtrace-iwlwifi.h"
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+DECLARE_TRACEPOINT(iwlwifi_dev_rx);
+DECLARE_TRACEPOINT(iwlwifi_dev_rx_data);
+#endif
+
+void __trace_iwlwifi_dev_rx(struct iwl_trans *trans, void *pkt, size_t len);
+
+static inline void maybe_trace_iwlwifi_dev_rx(struct iwl_trans *trans,
+ void *pkt, size_t len)
+{
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+ if (tracepoint_enabled(iwlwifi_dev_rx) ||
+ tracepoint_enabled(iwlwifi_dev_rx_data))
+ __trace_iwlwifi_dev_rx(trans, pkt, len);
+#endif
+}
#endif /* __IWLWIFI_DEVICE_TRACE */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
index ffe2670720c9..abf8001bdac1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c
@@ -128,6 +128,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv)
kfree(drv->fw.ucode_capa.cmd_versions);
kfree(drv->fw.phy_integration_ver);
kfree(drv->trans->dbg.pc_data);
+ drv->trans->dbg.pc_data = NULL;
for (i = 0; i < IWL_UCODE_TYPE_MAX; i++)
iwl_free_fw_img(drv, drv->fw.img + i);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 6015e1255d2a..2f6774ec37b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -668,7 +668,6 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = {
.has_eht = true,
.eht_cap_elem = {
.mac_cap_info[0] =
- IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
IEEE80211_EHT_MAC_CAP0_OM_CONTROL |
IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 |
IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 |
@@ -793,7 +792,6 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = {
.has_eht = true,
.eht_cap_elem = {
.mac_cap_info[0] =
- IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
IEEE80211_EHT_MAC_CAP0_OM_CONTROL |
IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 |
IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2,
@@ -1020,8 +1018,7 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
if (CSR_HW_REV_TYPE(trans->hw_rev) == IWL_CFG_MAC_TYPE_GL &&
iftype_data->eht_cap.has_eht) {
iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] &=
- ~(IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
- IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 |
+ ~(IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 |
IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2);
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[3] &=
~(IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO |
@@ -1029,7 +1026,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
- IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK);
+ IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK |
+ IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK);
iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] &=
~(IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO |
IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP);
@@ -1608,10 +1606,17 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan,
/* Set the GO concurrent flag only in case that NO_IR is set.
* Otherwise it is meaningless
*/
- if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) &&
- (flags & NL80211_RRF_NO_IR))
- flags |= NL80211_RRF_GO_CONCURRENT;
-
+ if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT)) {
+ if (flags & NL80211_RRF_NO_IR)
+ flags |= NL80211_RRF_GO_CONCURRENT;
+ if (flags & NL80211_RRF_DFS) {
+ flags |= NL80211_RRF_DFS_CONCURRENT;
+ /* Our device doesn't set active bit for DFS channels
+ * however, once marked as DFS no-ir is not needed.
+ */
+ flags &= ~NL80211_RRF_NO_IR;
+ }
+ }
/*
* reg_capa is per regulatory domain so apply it for every channel
*/
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
index af5f9b210f22..3dc618a7c70f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h
@@ -64,8 +64,6 @@ struct iwl_cfg;
* received on the RSS queue(s). The queue parameter indicates which of the
* RSS queues received this frame; it will always be non-zero.
* This method must not sleep.
- * @async_cb: called when an ASYNC command with CMD_WANT_ASYNC_CALLBACK set
- * completes. Must be atomic.
* @queue_full: notifies that a HW queue is full.
* Must be atomic and called with BH disabled.
* @queue_not_full: notifies that a HW queue is not full any more.
@@ -96,8 +94,6 @@ struct iwl_op_mode_ops {
struct iwl_rx_cmd_buffer *rxb);
void (*rx_rss)(struct iwl_op_mode *op_mode, struct napi_struct *napi,
struct iwl_rx_cmd_buffer *rxb, unsigned int queue);
- void (*async_cb)(struct iwl_op_mode *op_mode,
- const struct iwl_device_cmd *cmd);
void (*queue_full)(struct iwl_op_mode *op_mode, int queue);
void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue);
bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state);
@@ -147,13 +143,6 @@ static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode,
op_mode->ops->rx_rss(op_mode, napi, rxb, queue);
}
-static inline void iwl_op_mode_async_cb(struct iwl_op_mode *op_mode,
- const struct iwl_device_cmd *cmd)
-{
- if (op_mode->ops->async_cb)
- op_mode->ops->async_cb(op_mode, cmd);
-}
-
static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode,
int queue)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
index 4bd759432d44..f95098c21c7d 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c
@@ -172,10 +172,6 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
return -EIO;
}
- if (WARN_ON((cmd->flags & CMD_WANT_ASYNC_CALLBACK) &&
- !(cmd->flags & CMD_ASYNC)))
- return -EINVAL;
-
if (!(cmd->flags & CMD_ASYNC))
lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
index 05e72a2125b3..5789a8735976 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h
@@ -110,8 +110,7 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt)
* @CMD_WANT_SKB: Not valid with CMD_ASYNC. The caller needs the buffer of
* the response. The caller needs to call iwl_free_resp when done.
* @CMD_SEND_IN_RFKILL: Send the command even if the NIC is in RF-kill.
- * @CMD_WANT_ASYNC_CALLBACK: the op_mode's async callback function must be
- * called after this command completes. Valid only with CMD_ASYNC.
+ * @CMD_BLOCK_TXQS: Block TXQs while the comment is executing.
* @CMD_SEND_IN_D3: Allow the command to be sent in D3 mode, relevant to
* SUSPEND and RESUME commands. We are in D3 mode when we set
* trans->system_pm_mode to IWL_PLAT_PM_MODE_D3.
@@ -120,7 +119,7 @@ enum CMD_MODE {
CMD_ASYNC = BIT(0),
CMD_WANT_SKB = BIT(1),
CMD_SEND_IN_RFKILL = BIT(2),
- CMD_WANT_ASYNC_CALLBACK = BIT(3),
+ CMD_BLOCK_TXQS = BIT(3),
CMD_SEND_IN_D3 = BIT(4),
};
@@ -534,11 +533,6 @@ struct iwl_pnvm_image {
* @wait_txq_empty: wait until specific tx queue is empty. May sleep.
* @freeze_txq_timer: prevents the timer of the queue from firing until the
* queue is set to awake. Must be atomic.
- * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note
- * that the transport needs to refcount the calls since this function
- * will be called several times with block = true, and then the queues
- * need to be unblocked only after the same number of calls with
- * block = false.
* @write8: write a u8 to a register at offset ofs from the BAR
* @write32: write a u32 to a register at offset ofs from the BAR
* @read32: read a u32 register at offset ofs from the BAR
@@ -613,7 +607,6 @@ struct iwl_trans_ops {
int (*wait_txq_empty)(struct iwl_trans *trans, int queue);
void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs,
bool freeze);
- void (*block_txq_ptrs)(struct iwl_trans *trans, bool block);
void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val);
void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val);
@@ -1323,7 +1316,7 @@ iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue,
struct iwl_trans_rxq_dma_data *data)
{
if (WARN_ON_ONCE(!trans->ops->rxq_dma_data))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
return trans->ops->rxq_dma_data(trans, queue, data);
}
@@ -1345,7 +1338,7 @@ iwl_trans_txq_alloc(struct iwl_trans *trans,
might_sleep();
if (WARN_ON_ONCE(!trans->ops->txq_alloc))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
@@ -1407,23 +1400,11 @@ static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans,
trans->ops->freeze_txq_timer(trans, txqs, freeze);
}
-static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans,
- bool block)
-{
- if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
- IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
- return;
- }
-
- if (trans->ops->block_txq_ptrs)
- trans->ops->block_txq_ptrs(trans, block);
-}
-
static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans,
u32 txqs)
{
if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/* No need to wait if the firmware is not alive */
if (trans->state != IWL_TRANS_FW_ALIVE) {
@@ -1437,7 +1418,7 @@ static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans,
static inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue)
{
if (WARN_ON_ONCE(!trans->ops->wait_txq_empty))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) {
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
index 5a5b1128e75c..9fe1761691ec 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2013-2014, 2018-2020, 2022 Intel Corporation
+ * Copyright (C) 2013-2014, 2018-2020, 2022-2023 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
*/
#include <linux/ieee80211.h>
@@ -116,11 +116,6 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif)
ret = BT_COEX_TX_DIS_LUT;
- if (mvm->cfg->bt_shared_single_ant) {
- rcu_read_unlock();
- return ret;
- }
-
phy_ctx_id = *((u16 *)chanctx_conf->drv_priv);
primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id);
secondary_ch_phy_id =
@@ -383,13 +378,12 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm,
/*
* don't reduce the Tx power if one of these is true:
* we are in LOOSE
- * single share antenna product
* BT is inactive
* we are not associated
*/
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
- mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc ||
- le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
+ le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF ||
+ !vif->cfg.assoc) {
iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id, false);
/* FIXME: should this be per link? */
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
@@ -570,7 +564,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* Check if rssi is good enough for reduced Tx power, but not in loose
* scheme.
*/
- if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant ||
+ if (rssi_event == RSSI_EVENT_LOW ||
iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT)
ret = iwl_mvm_bt_coex_reduced_txp(mvm,
mvmvif->deflink.ap_sta_id,
@@ -639,10 +633,6 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm,
bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
{
- /* there is no other antenna, shared antenna is always available */
- if (mvm->cfg->bt_shared_single_ant)
- return true;
-
if (ant & mvm->cfg->non_shared_ant)
return true;
@@ -652,10 +642,6 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant)
bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm)
{
- /* there is no other antenna, shared antenna is always available */
- if (mvm->cfg->bt_shared_single_ant)
- return true;
-
return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 92c45571bd69..05b64176859e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1130,14 +1130,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
return ret;
}
- /*
- * This needs to be unlocked due to lock ordering
- * constraints. Since we're in the suspend path
- * that isn't really a problem though.
- */
- mutex_unlock(&mvm->mutex);
ret = iwl_mvm_wowlan_config_key_params(mvm, vif);
- mutex_lock(&mvm->mutex);
if (ret)
return ret;
@@ -1286,7 +1279,9 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
mvm->net_detect = true;
} else {
- struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
+ struct iwl_wowlan_config_cmd wowlan_config_cmd = {
+ .offloading_tid = 0,
+ };
wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id;
@@ -1298,6 +1293,11 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
goto out_noreset;
}
+ ret = iwl_mvm_sta_ensure_queue(
+ mvm, ap_sta->txq[wowlan_config_cmd.offloading_tid]);
+ if (ret)
+ goto out_noreset;
+
ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
vif, mvmvif, ap_sta);
if (ret)
@@ -2497,7 +2497,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
struct iwl_wowlan_status_data *status)
{
int i;
- bool keep;
+ bool keep = false;
struct iwl_mvm_sta *mvm_ap_sta;
if (!status)
@@ -2525,18 +2525,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
mvm_ap_sta->tid_data[i].seq_number >> 4);
}
- /* now we have all the data we need, unlock to avoid mac80211 issues */
- mutex_unlock(&mvm->mutex);
-
iwl_mvm_report_wakeup_reasons(mvm, vif, status);
keep = iwl_mvm_setup_connection_keep(mvm, vif, status);
-
- return keep;
-
out_unlock:
mutex_unlock(&mvm->mutex);
- return false;
+ return keep;
}
#define ND_QUERY_BUF_LEN (sizeof(struct iwl_scan_offload_profile_match) * \
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 329c545f65fd..edc8204f7c0e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1521,7 +1521,7 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm,
/* supporting only MQ RX */
if (!mvm->trans->trans_cfg->mq_rx_supported)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
rxb._page = alloc_pages(GFP_ATOMIC, 0);
if (!rxb._page)
@@ -1714,6 +1714,20 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
return count;
}
+static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&mvm->mutex);
+ iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt);
+ mutex_unlock(&mvm->mutex);
+
+ return count;
+}
+
static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm,
char *buf, size_t count,
loff_t *ppos)
@@ -1815,7 +1829,7 @@ static ssize_t _iwl_dbgfs_link_sta_##name##_write(struct file *file, \
char buf[buflen] = {}; \
size_t buf_size = min(count, sizeof(buf) - 1); \
\
- if (copy_from_user(buf, user_buf, sizeof(buf))) \
+ if (copy_from_user(buf, user_buf, buf_size)) \
return -EFAULT; \
\
return _iwl_dbgfs_link_sta_wrap_write(iwl_dbgfs_##name##_write, \
@@ -2166,6 +2180,7 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_clear, 64);
MVM_DEBUGFS_WRITE_FILE_OPS(dbg_time_point, 64);
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
@@ -2372,6 +2387,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600);
MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200);
+ MVM_DEBUGFS_ADD_FILE(fw_dbg_clear, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(dbg_time_point, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200);
MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
index 10b9219b3bfd..8f10590f9cdd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-responder.c
@@ -39,7 +39,7 @@ static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef,
*ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef);
break;
default:
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
return 0;
@@ -77,7 +77,7 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef,
}
fallthrough;
default:
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
return 0;
@@ -291,7 +291,7 @@ iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm,
default:
IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n",
cmd_ver);
- ret = -ENOTSUPP;
+ ret = -EOPNOTSUPP;
}
return ret;
@@ -333,7 +333,7 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm,
if (cmd_ver < 3) {
IWL_ERR(mvm, "Adding PASN station not supported by FW\n");
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
if ((!hltk || !hltk_len) && (!tk || !tk_len)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 403bd17b8b7a..1252084662c6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -27,9 +27,6 @@
#define MVM_UCODE_ALIVE_TIMEOUT (2 * HZ)
#define MVM_UCODE_CALIB_TIMEOUT (2 * HZ)
-#define IWL_TAS_US_MCC 0x5553
-#define IWL_TAS_CANADA_MCC 0x4341
-
#define IWL_UATS_VLP_AP_SUPPORTED BIT(29)
#define IWL_UATS_AFC_AP_SUPPORTED BIT(30)
@@ -1234,10 +1231,10 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
dmi_get_system_info(DMI_SYS_VENDOR));
if ((!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array,
&cmd.v4.block_list_size,
- IWL_TAS_US_MCC)) ||
+ IWL_MCC_US)) ||
(!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array,
&cmd.v4.block_list_size,
- IWL_TAS_CANADA_MCC))) {
+ IWL_MCC_CANADA))) {
IWL_DEBUG_RADIO(mvm,
"Unable to add US/Canada to TAS block list, disabling TAS\n");
return;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
index c4f96125cf33..25a5a31e63c2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
@@ -31,6 +31,17 @@ const u8 iwl_mvm_ac_to_gen2_tx_fifo[] = {
IWL_GEN2_TRIG_TX_FIFO_BK,
};
+const u8 iwl_mvm_ac_to_bz_tx_fifo[] = {
+ IWL_BZ_EDCA_TX_FIFO_VO,
+ IWL_BZ_EDCA_TX_FIFO_VI,
+ IWL_BZ_EDCA_TX_FIFO_BE,
+ IWL_BZ_EDCA_TX_FIFO_BK,
+ IWL_BZ_TRIG_TX_FIFO_VO,
+ IWL_BZ_TRIG_TX_FIFO_VI,
+ IWL_BZ_TRIG_TX_FIFO_BE,
+ IWL_BZ_TRIG_TX_FIFO_BK,
+};
+
struct iwl_mvm_mac_iface_iterator_data {
struct iwl_mvm *mvm;
struct ieee80211_vif *vif;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index a64600f0ed9f..53e26c3c3a9a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -152,6 +152,16 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy,
mvm->lar_regdom_set = true;
mvm->mcc_src = src_id;
+ /* Some kind of regulatory mess means we need to currently disallow
+ * puncturing in the US and Canada. Do that here, at least until we
+ * figure out the new chanctx APIs for puncturing.
+ */
+ if (resp->mcc == cpu_to_le16(IWL_MCC_US) ||
+ resp->mcc == cpu_to_le16(IWL_MCC_CANADA))
+ ieee80211_hw_set(mvm->hw, DISALLOW_PUNCTURING);
+ else
+ __clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING, mvm->hw->flags);
+
iwl_mei_set_country_code(__le16_to_cpu(resp->mcc));
out:
@@ -288,7 +298,7 @@ int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
/* This has been tested on those devices only */
if (mvm->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_9000 &&
mvm->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_22000)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (!mvm->nvm_data)
return -EBUSY;
@@ -517,6 +527,10 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |
REGULATORY_DISABLE_BEACON_HINTS;
+ if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210)
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_DFS_CONCURRENT);
+
hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
hw->wiphy->flags |= WIPHY_FLAG_SPLIT_SCAN_6GHZ;
@@ -1586,7 +1600,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
*/
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC) {
- iwl_mvm_vif_dbgfs_add_link(mvm, vif);
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ iwl_mvm_vif_dbgfs_add_link(mvm, vif);
ret = 0;
goto out;
}
@@ -1626,7 +1641,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
iwl_mvm_chandef_get_primary_80(&vif->bss_conf.chandef);
}
- iwl_mvm_vif_dbgfs_add_link(mvm, vif);
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ iwl_mvm_vif_dbgfs_add_link(mvm, vif);
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
@@ -3671,6 +3687,9 @@ iwl_mvm_sta_state_notexist_to_none(struct iwl_mvm *mvm,
NL80211_TDLS_SETUP);
}
+ if (ret)
+ return ret;
+
for_each_sta_active_link(vif, sta, link_sta, i)
link_sta->agg.max_rc_amsdu_len = 1;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index ff6cb064051b..893b69fc841b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -81,7 +81,8 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS);
}
- iwl_mvm_vif_dbgfs_add_link(mvm, vif);
+ if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ iwl_mvm_vif_dbgfs_add_link(mvm, vif);
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
@@ -271,17 +272,17 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
}
}
+ mvmvif->link[link_id]->phy_ctxt = phy_ctxt;
+
if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
mvmvif->link[link_id]->listen_lmac = true;
ret = iwl_mvm_esr_mode_active(mvm, vif);
if (ret) {
IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret);
- return ret;
+ goto out;
}
}
- mvmvif->link[link_id]->phy_ctxt = phy_ctxt;
-
if (switching_chanctx) {
/* reactivate if we turned this off during channel switch */
if (vif->type == NL80211_IFTYPE_AP)
@@ -437,6 +438,9 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
mvmvif->ap_ibss_active = false;
}
+ iwl_mvm_link_changed(mvm, vif, link_conf,
+ LINK_CONTEXT_MODIFY_ACTIVE, false);
+
if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
int ret = iwl_mvm_esr_mode_inactive(mvm, vif);
@@ -448,9 +452,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_MONITOR)
iwl_mvm_mld_rm_snif_sta(mvm, vif);
- iwl_mvm_link_changed(mvm, vif, link_conf,
- LINK_CONTEXT_MODIFY_ACTIVE, false);
-
if (switching_chanctx)
return;
mvmvif->link[link_id]->phy_ctxt = NULL;
@@ -716,7 +717,7 @@ void iwl_mvm_mld_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
}
}
- if (WARN_ON(!new_active_links))
+ if (!new_active_links)
return;
if (vif->active_links != new_active_links)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 6af606e5da65..1628bf55458f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -874,6 +874,9 @@ void iwl_mvm_mld_sta_modify_disable_tx(struct iwl_mvm *mvm,
cmd.sta_id = cpu_to_le32(mvmsta->deflink.sta_id);
cmd.disable = cpu_to_le32(disable);
+ if (WARN_ON(iwl_mvm_has_no_host_disable_tx(mvm)))
+ return;
+
ret = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(MAC_CONF_GROUP, STA_DISABLE_TX_CMD),
CMD_ASYNC, sizeof(cmd), &cmd);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index f2af3e571409..81dbef6947f5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -947,6 +947,7 @@ struct iwl_mvm {
/* the vif that requested the current scan */
struct iwl_mvm_vif *scan_vif;
+ u8 scan_link_id;
/* rx chain antennas set through debugfs for the scan command */
u8 scan_rx_ant;
@@ -1513,6 +1514,12 @@ static inline bool iwl_mvm_has_quota_low_latency(struct iwl_mvm *mvm)
IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY);
}
+static inline bool iwl_mvm_has_no_host_disable_tx(struct iwl_mvm *mvm)
+{
+ return fw_has_api(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX);
+}
+
static inline bool iwl_mvm_has_tlc_offload(const struct iwl_mvm *mvm)
{
return fw_has_capa(&mvm->fw->ucode_capa,
@@ -1574,12 +1581,16 @@ static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm,
extern const u8 iwl_mvm_ac_to_tx_fifo[];
extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[];
+extern const u8 iwl_mvm_ac_to_bz_tx_fifo[];
static inline u8 iwl_mvm_mac_ac_to_tx_fifo(struct iwl_mvm *mvm,
enum ieee80211_ac_numbers ac)
{
- return iwl_mvm_has_new_tx_api(mvm) ?
- iwl_mvm_ac_to_gen2_tx_fifo[ac] : iwl_mvm_ac_to_tx_fifo[ac];
+ if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
+ return iwl_mvm_ac_to_bz_tx_fifo[ac];
+ if (iwl_mvm_has_new_tx_api(mvm))
+ return iwl_mvm_ac_to_gen2_tx_fifo[ac];
+ return iwl_mvm_ac_to_tx_fifo[ac];
}
struct iwl_rate_info {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 1627b2f819db..adbbe19aeae5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1703,18 +1703,6 @@ void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode,
iwl_mvm_rx_common(mvm, rxb, pkt);
}
-static void iwl_mvm_async_cb(struct iwl_op_mode *op_mode,
- const struct iwl_device_cmd *cmd)
-{
- struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
-
- /*
- * For now, we only set the CMD_WANT_ASYNC_CALLBACK for ADD_STA
- * commands that need to block the Tx queues.
- */
- iwl_trans_block_txq_ptrs(mvm->trans, false);
-}
-
static int iwl_mvm_is_static_queue(struct iwl_mvm *mvm, int queue)
{
return queue == mvm->aux_queue || queue == mvm->probe_queue ||
@@ -2024,7 +2012,6 @@ static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode,
#define IWL_MVM_COMMON_OPS \
/* these could be differentiated */ \
- .async_cb = iwl_mvm_async_cb, \
.queue_full = iwl_mvm_stop_sw_queue, \
.queue_not_full = iwl_mvm_wake_sw_queue, \
.hw_rf_kill = iwl_mvm_set_hw_rfkill_state, \
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
index 4e1fccff3987..334d1f59f6e4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c
@@ -99,17 +99,6 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm,
active_cnt = 2;
}
- /*
- * If the firmware requested it, then we know that it supports
- * getting zero for the values to indicate "use one, but pick
- * which one yourself", which means it can dynamically pick one
- * that e.g. has better RSSI.
- */
- if (mvm->fw_static_smps_request && active_cnt == 1 && idle_cnt == 1) {
- idle_cnt = 0;
- active_cnt = 0;
- }
-
*rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) <<
PHY_RX_CHAIN_VALID_POS);
*rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index 886d00098528..af15d470c69b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -505,6 +505,10 @@ static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
return false;
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+
+ if (WARN_ON_ONCE(!mvm_sta->dup_data))
+ return false;
+
dup_data = &mvm_sta->dup_data[queue];
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 75c5c58e14a5..7b6f1cdca067 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -101,6 +101,7 @@ struct iwl_mvm_scan_params {
bool scan_6ghz;
bool enable_6ghz_passive;
bool respect_p2p_go, respect_p2p_go_hb;
+ s8 tsf_report_link_id;
u8 bssid[ETH_ALEN] __aligned(2);
};
@@ -2342,20 +2343,15 @@ iwl_mvm_scan_umac_fill_general_p_v12(struct iwl_mvm *mvm,
if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2)
gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS;
+ mvm->scan_link_id = 0;
+
if (version < 16) {
gp->scan_start_mac_or_link_id = scan_vif->id;
} else {
- struct iwl_mvm_vif_link_info *link_info;
- u8 link_id = 0;
+ struct iwl_mvm_vif_link_info *link_info =
+ scan_vif->link[params->tsf_report_link_id];
- /* Use one of the active link (if any). In the future it would
- * be possible that the link ID would be part of the scan
- * request coming from upper layers so we would need to use it.
- */
- if (vif->active_links)
- link_id = ffs(vif->active_links) - 1;
-
- link_info = scan_vif->link[link_id];
+ mvm->scan_link_id = params->tsf_report_link_id;
if (!WARN_ON(!link_info))
gp->scan_start_mac_or_link_id = link_info->fw_link_id;
}
@@ -2977,6 +2973,14 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (req->duration)
params.iter_notif = true;
+ params.tsf_report_link_id = req->tsf_report_link_id;
+ if (params.tsf_report_link_id < 0) {
+ if (vif->active_links)
+ params.tsf_report_link_id = __ffs(vif->active_links);
+ else
+ params.tsf_report_link_id = 0;
+ }
+
iwl_mvm_build_scan_probe(mvm, vif, ies, &params);
iwl_mvm_scan_6ghz_passive_scan(mvm, &params, vif);
@@ -3164,8 +3168,13 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
.aborted = aborted,
.scan_start_tsf = mvm->scan_start,
};
+ struct iwl_mvm_vif *scan_vif = mvm->scan_vif;
+ struct iwl_mvm_vif_link_info *link_info =
+ scan_vif->link[mvm->scan_link_id];
+
+ if (!WARN_ON(!link_info))
+ memcpy(info.tsf_bssid, link_info->bssid, ETH_ALEN);
- memcpy(info.tsf_bssid, mvm->scan_vif->deflink.bssid, ETH_ALEN);
ieee80211_scan_completed(mvm->hw, &info);
mvm->scan_vif = NULL;
cancel_delayed_work(&mvm->scan_timeout_dwork);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index bba96a968890..c2e0cff740e9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1502,6 +1502,34 @@ out_err:
return ret;
}
+int iwl_mvm_sta_ensure_queue(struct iwl_mvm *mvm,
+ struct ieee80211_txq *txq)
+{
+ struct iwl_mvm_txq *mvmtxq = iwl_mvm_txq_from_mac80211(txq);
+ int ret = -EINVAL;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (likely(test_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state)) ||
+ !txq->sta) {
+ return 0;
+ }
+
+ if (!iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, txq->tid)) {
+ set_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state);
+ ret = 0;
+ }
+
+ local_bh_disable();
+ spin_lock(&mvm->add_stream_lock);
+ if (!list_empty(&mvmtxq->list))
+ list_del_init(&mvmtxq->list);
+ spin_unlock(&mvm->add_stream_lock);
+ local_bh_enable();
+
+ return ret;
+}
+
void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)
{
struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm,
@@ -2550,7 +2578,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
if (WARN_ON(vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_ADHOC))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/*
* In IBSS, ieee80211_check_queues() sets the cab_queue to be
@@ -3234,7 +3262,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* should be updated as well.
*/
if (buf_size < IWL_FRAME_LIMIT)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
ret = iwl_mvm_sta_tx_agg(mvm, sta, tid, queue, true);
if (ret)
@@ -4111,10 +4139,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
}
/* block the Tx queues until the FW updated the sleep Tx count */
- iwl_trans_block_txq_ptrs(mvm->trans, true);
-
ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA,
- CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK,
+ CMD_ASYNC | CMD_BLOCK_TXQS,
iwl_mvm_add_sta_cmd_size(mvm), &cmd);
if (ret)
IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
@@ -4152,7 +4178,8 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
int ret;
if (mvm->mld_api_is_used) {
- iwl_mvm_mld_sta_modify_disable_tx(mvm, mvmsta, disable);
+ if (!iwl_mvm_has_no_host_disable_tx(mvm))
+ iwl_mvm_mld_sta_modify_disable_tx(mvm, mvmsta, disable);
return;
}
@@ -4169,7 +4196,8 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
if (mvm->mld_api_is_used) {
- iwl_mvm_mld_sta_modify_disable_tx_ap(mvm, sta, disable);
+ if (!iwl_mvm_has_no_host_disable_tx(mvm))
+ iwl_mvm_mld_sta_modify_disable_tx_ap(mvm, sta, disable);
return;
}
@@ -4224,7 +4252,9 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
int i;
if (mvm->mld_api_is_used) {
- iwl_mvm_mld_modify_all_sta_disable_tx(mvm, mvmvif, disable);
+ if (!iwl_mvm_has_no_host_disable_tx(mvm))
+ iwl_mvm_mld_modify_all_sta_disable_tx(mvm, mvmvif,
+ disable);
return;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index b33a0ce096d4..3cf8a70274ce 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2016 Intel Deutschland GmbH
*/
@@ -571,6 +571,7 @@ void iwl_mvm_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
bool disable);
void iwl_mvm_csa_client_absent(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_sta_ensure_queue(struct iwl_mvm *mvm, struct ieee80211_txq *txq);
void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk);
int iwl_mvm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_int_sta *sta, u8 *addr, u32 cipher,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
index 218fdf1ed530..2e653a417d62 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2012-2014, 2018-2023 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2024 Intel Corporation
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
* Copyright (C) 2017 Intel Deutschland GmbH
*/
@@ -972,6 +972,7 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) {
/* End TE, notify mac80211 */
mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
+ mvmvif->time_event_data.link_id = -1;
iwl_mvm_p2p_roc_finished(mvm);
ieee80211_remain_on_channel_expired(mvm->hw);
} else if (le32_to_cpu(notif->start)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index ae5cd13cd6dd..461f26d9214e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -520,13 +520,24 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
}
}
+static void iwl_mvm_copy_hdr(void *cmd, const void *hdr, int hdrlen,
+ const u8 *addr3_override)
+{
+ struct ieee80211_hdr *out_hdr = cmd;
+
+ memcpy(cmd, hdr, hdrlen);
+ if (addr3_override)
+ memcpy(out_hdr->addr3, addr3_override, ETH_ALEN);
+}
+
/*
* Allocates and sets the Tx cmd the driver data pointers in the skb
*/
static struct iwl_device_tx_cmd *
iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info, int hdrlen,
- struct ieee80211_sta *sta, u8 sta_id)
+ struct ieee80211_sta *sta, u8 sta_id,
+ const u8 *addr3_override)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_device_tx_cmd *dev_cmd;
@@ -584,7 +595,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
cmd->len = cpu_to_le16((u16)skb->len);
/* Copy MAC header from skb into command buffer */
- memcpy(cmd->hdr, hdr, hdrlen);
+ iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);
cmd->flags = cpu_to_le16(flags);
cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
@@ -599,7 +610,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
cmd->len = cpu_to_le16((u16)skb->len);
/* Copy MAC header from skb into command buffer */
- memcpy(cmd->hdr, hdr, hdrlen);
+ iwl_mvm_copy_hdr(cmd->hdr, hdr, hdrlen, addr3_override);
cmd->flags = cpu_to_le32(flags);
cmd->rate_n_flags = cpu_to_le32(rate_n_flags);
@@ -617,7 +628,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb,
iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control);
/* Copy MAC header from skb into command buffer */
- memcpy(tx_cmd->hdr, hdr, hdrlen);
+ iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override);
out:
return dev_cmd;
@@ -820,7 +831,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
IWL_DEBUG_TX(mvm, "station Id %d, queue=%d\n", sta_id, queue);
- dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id);
+ dev_cmd = iwl_mvm_set_tx_params(mvm, skb, &info, hdrlen, NULL, sta_id,
+ NULL);
if (!dev_cmd)
return -1;
@@ -1140,7 +1152,8 @@ static int iwl_mvm_tx_pkt_queued(struct iwl_mvm *mvm,
*/
static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
struct ieee80211_tx_info *info,
- struct ieee80211_sta *sta)
+ struct ieee80211_sta *sta,
+ const u8 *addr3_override)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_mvm_sta *mvmsta;
@@ -1172,7 +1185,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
iwl_mvm_probe_resp_set_noa(mvm, skb);
dev_cmd = iwl_mvm_set_tx_params(mvm, skb, info, hdrlen,
- sta, mvmsta->deflink.sta_id);
+ sta, mvmsta->deflink.sta_id,
+ addr3_override);
if (!dev_cmd)
goto drop;
@@ -1294,9 +1308,11 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_tx_info info;
struct sk_buff_head mpdus_skbs;
+ struct ieee80211_vif *vif;
unsigned int payload_len;
int ret;
struct sk_buff *orig_skb = skb;
+ const u8 *addr3;
if (WARN_ON_ONCE(!mvmsta))
return -1;
@@ -1307,26 +1323,59 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb,
memcpy(&info, skb->cb, sizeof(info));
if (!skb_is_gso(skb))
- return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
+ return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL);
payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
tcp_hdrlen(skb) + skb->data_len;
if (payload_len <= skb_shinfo(skb)->gso_size)
- return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
+ return iwl_mvm_tx_mpdu(mvm, skb, &info, sta, NULL);
__skb_queue_head_init(&mpdus_skbs);
+ vif = info.control.vif;
+ if (!vif)
+ return -1;
+
ret = iwl_mvm_tx_tso(mvm, skb, &info, sta, &mpdus_skbs);
if (ret)
return ret;
WARN_ON(skb_queue_empty(&mpdus_skbs));
+ /*
+ * As described in IEEE sta 802.11-2020, table 9-30 (Address
+ * field contents), A-MSDU address 3 should contain the BSSID
+ * address.
+ * Pass address 3 down to iwl_mvm_tx_mpdu() and further to set it
+ * in the command header. We need to preserve the original
+ * address 3 in the skb header to correctly create all the
+ * A-MSDU subframe headers from it.
+ */
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ addr3 = vif->cfg.ap_addr;
+ break;
+ case NL80211_IFTYPE_AP:
+ addr3 = vif->addr;
+ break;
+ default:
+ addr3 = NULL;
+ break;
+ }
+
while (!skb_queue_empty(&mpdus_skbs)) {
+ struct ieee80211_hdr *hdr;
+ bool amsdu;
+
skb = __skb_dequeue(&mpdus_skbs);
+ hdr = (void *)skb->data;
+ amsdu = ieee80211_is_data_qos(hdr->frame_control) &&
+ (*ieee80211_get_qos_ctl(hdr) &
+ IEEE80211_QOS_CTL_A_MSDU_PRESENT);
- ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
+ ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta,
+ amsdu ? addr3 : NULL);
if (ret) {
/* Free skbs created as part of TSO logic that have not yet been dequeued */
__skb_queue_purge(&mpdus_skbs);
@@ -2256,7 +2305,7 @@ int iwl_mvm_flush_sta_tids(struct iwl_mvm *mvm, u32 sta_id, u16 tids)
WARN_ON(!iwl_mvm_has_new_tx_api(mvm));
if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, TXPATH_FLUSH, 0) > 0)
- cmd.flags |= CMD_WANT_SKB;
+ cmd.flags |= CMD_WANT_SKB | CMD_SEND_IN_RFKILL;
IWL_DEBUG_TX_QUEUES(mvm, "flush for sta id %d tid mask 0x%x\n",
sta_id, tids);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 26a0953603ab..2c9b98c8184b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -1121,9 +1121,8 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
/*
* Read rf id and cdb info from prph register and store it
*/
-static int get_crf_id(struct iwl_trans *iwl_trans)
+static void get_crf_id(struct iwl_trans *iwl_trans)
{
- int ret = 0;
u32 sd_reg_ver_addr;
u32 val = 0;
@@ -1150,8 +1149,6 @@ static int get_crf_id(struct iwl_trans *iwl_trans)
IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n",
iwl_trans->hw_crf_id, iwl_trans->hw_cnv_id,
iwl_trans->hw_wfpm_id);
-
- return ret;
}
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
index 07931c2db494..9c2461ba13c5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c
@@ -1351,8 +1351,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
if (len < sizeof(*pkt) || offset > max_len)
break;
- trace_iwlwifi_dev_rx(trans->dev, trans, pkt, len);
- trace_iwlwifi_dev_rx_data(trans->dev, trans, pkt, len);
+ maybe_trace_iwlwifi_dev_rx(trans, pkt, len);
/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
index c9e5bda8f0b7..a4a4772330cf 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c
@@ -290,6 +290,16 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_MS):
pos = scnprintf(buf, buflen, "MS");
break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_FM):
+ pos = scnprintf(buf, buflen, "FM");
+ break;
+ case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_WP):
+ if (SILICON_Z_STEP ==
+ CSR_HW_RFID_STEP(trans->hw_rf_id))
+ pos = scnprintf(buf, buflen, "WHTC");
+ else
+ pos = scnprintf(buf, buflen, "WH");
+ break;
default:
return;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index d10208075ae5..63e13577aff8 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -2108,18 +2108,29 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk)
container_of(wk, struct iwl_trans_pcie_removal, work);
struct pci_dev *pdev = removal->pdev;
static char *prop[] = {"EVENT=INACCESSIBLE", NULL};
- struct pci_bus *bus = pdev->bus;
+ struct pci_bus *bus;
+
+ pci_lock_rescan_remove();
+
+ bus = pdev->bus;
+ /* in this case, something else already removed the device */
+ if (!bus)
+ goto out;
dev_err(&pdev->dev, "Device gone - attempting removal\n");
+
kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, prop);
- pci_lock_rescan_remove();
- pci_dev_put(pdev);
+
pci_stop_and_remove_bus_device(pdev);
- if (removal->rescan && bus) {
+ pci_dev_put(pdev);
+
+ if (removal->rescan) {
if (bus->parent)
bus = bus->parent;
pci_rescan_bus(bus);
}
+
+out:
pci_unlock_rescan_remove();
kfree(removal);
@@ -2134,6 +2145,7 @@ void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan)
return;
IWL_ERR(trans, "Device gone - scheduling removal!\n");
+ iwl_pcie_dump_csr(trans);
/*
* get a module reference to avoid doing this
@@ -2366,32 +2378,6 @@ static int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs,
ofs, val);
}
-static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block)
-{
- int i;
-
- for (i = 0; i < trans->trans_cfg->base_params->num_of_queues; i++) {
- struct iwl_txq *txq = trans->txqs.txq[i];
-
- if (i == trans->txqs.cmd.q_id)
- continue;
-
- spin_lock_bh(&txq->lock);
-
- if (!block && !(WARN_ON_ONCE(!txq->block))) {
- txq->block--;
- if (!txq->block) {
- iwl_write32(trans, HBUS_TARG_WRPTR,
- txq->write_ptr | (i << 8));
- }
- } else if (block) {
- txq->block++;
- }
-
- spin_unlock_bh(&txq->lock);
- }
-}
-
#define IWL_FLUSH_WAIT_MS 2000
static int iwl_trans_pcie_rxq_dma_data(struct iwl_trans *trans, int queue,
@@ -3573,7 +3559,6 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.wait_tx_queues_empty = iwl_trans_pcie_wait_txqs_empty,
.freeze_txq_timer = iwl_trans_txq_freeze_timer,
- .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs,
#ifdef CONFIG_IWLWIFI_DEBUGFS
.debugfs_cleanup = iwl_trans_pcie_debugfs_cleanup,
#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
index c72a84d8bb4f..aabbef114bc2 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2020 Intel Corporation
+ * Copyright (C) 2018-2020, 2023 Intel Corporation
*/
#include <net/tso.h>
#include <linux/tcp.h>
@@ -42,6 +42,9 @@ int iwl_pcie_gen2_enqueue_hcmd(struct iwl_trans *trans,
struct iwl_tfh_tfd *tfd;
unsigned long flags;
+ if (WARN_ON(cmd->flags & CMD_BLOCK_TXQS))
+ return -EINVAL;
+
copy_size = sizeof(struct iwl_cmd_header_wide);
cmd_size = sizeof(struct iwl_cmd_header_wide);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 2f39b639c43f..6c2b37e56c78 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -873,6 +873,33 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
+static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block)
+{
+ int i;
+
+ for (i = 0; i < trans->trans_cfg->base_params->num_of_queues; i++) {
+ struct iwl_txq *txq = trans->txqs.txq[i];
+
+ if (i == trans->txqs.cmd.q_id)
+ continue;
+
+ /* we skip the command queue (obviously) so it's OK to nest */
+ spin_lock_nested(&txq->lock, 1);
+
+ if (!block && !(WARN_ON_ONCE(!txq->block))) {
+ txq->block--;
+ if (!txq->block) {
+ iwl_write32(trans, HBUS_TARG_WRPTR,
+ txq->write_ptr | (i << 8));
+ }
+ } else if (block) {
+ txq->block++;
+ }
+
+ spin_unlock(&txq->lock);
+ }
+}
+
/*
* iwl_pcie_enqueue_hcmd - enqueue a uCode command
* @priv: device private data point
@@ -1137,6 +1164,9 @@ int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
goto out;
}
+ if (cmd->flags & CMD_BLOCK_TXQS)
+ iwl_trans_pcie_block_txq_ptrs(trans, true);
+
/* Increment and update queue's write index */
txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr);
iwl_pcie_txq_inc_wr_ptr(trans, txq);
@@ -1202,8 +1232,8 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
meta->source->_rx_page_order = trans_pcie->rx_page_order;
}
- if (meta->flags & CMD_WANT_ASYNC_CALLBACK)
- iwl_op_mode_async_cb(trans->op_mode, cmd);
+ if (meta->flags & CMD_BLOCK_TXQS)
+ iwl_trans_pcie_block_txq_ptrs(trans, false);
iwl_pcie_cmdq_reclaim(trans, txq_id, index);
diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig
index bd6bf70ece03..201b1534a9ca 100644
--- a/drivers/net/wireless/intersil/Kconfig
+++ b/drivers/net/wireless/intersil/Kconfig
@@ -12,8 +12,6 @@ config WLAN_VENDOR_INTERSIL
if WLAN_VENDOR_INTERSIL
-source "drivers/net/wireless/intersil/hostap/Kconfig"
-source "drivers/net/wireless/intersil/orinoco/Kconfig"
source "drivers/net/wireless/intersil/p54/Kconfig"
endif # WLAN_VENDOR_INTERSIL
diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile
index 65281d1b3d85..27e9b2869da1 100644
--- a/drivers/net/wireless/intersil/Makefile
+++ b/drivers/net/wireless/intersil/Makefile
@@ -1,4 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_HOSTAP) += hostap/
-obj-$(CONFIG_HERMES) += orinoco/
obj-$(CONFIG_P54_COMMON) += p54/
diff --git a/drivers/net/wireless/intersil/hostap/Kconfig b/drivers/net/wireless/intersil/hostap/Kconfig
deleted file mode 100644
index 2edff8efbcbb..000000000000
--- a/drivers/net/wireless/intersil/hostap/Kconfig
+++ /dev/null
@@ -1,95 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config HOSTAP
- tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- select CRC32
- select LIB80211
- select LIB80211_CRYPT_WEP
- select LIB80211_CRYPT_TKIP
- select LIB80211_CRYPT_CCMP
- help
- Shared driver code for IEEE 802.11b wireless cards based on
- Intersil Prism2/2.5/3 chipset. This driver supports so called
- Host AP mode that allows the card to act as an IEEE 802.11
- access point.
-
- See <http://hostap.epitest.fi/> for more information about the
- Host AP driver configuration and tools. This site includes
- information and tools (hostapd and wpa_supplicant) for WPA/WPA2
- support.
-
- This option includes the base Host AP driver code that is shared by
- different hardware models. You will also need to enable support for
- PLX/PCI/CS version of the driver to actually use the driver.
-
- The driver can be compiled as a module and it will be called
- hostap.
-
-config HOSTAP_FIRMWARE
- bool "Support downloading firmware images with Host AP driver"
- depends on HOSTAP
- help
- Configure Host AP driver to include support for firmware image
- download. This option by itself only enables downloading to the
- volatile memory, i.e. the card RAM. This option is required to
- support cards that don't have firmware in flash, such as D-Link
- DWL-520 rev E and D-Link DWL-650 rev P.
-
- Firmware image downloading needs a user space tool, prism2_srec.
- It is available from http://hostap.epitest.fi/.
-
-config HOSTAP_FIRMWARE_NVRAM
- bool "Support for non-volatile firmware download"
- depends on HOSTAP_FIRMWARE
- help
- Allow Host AP driver to write firmware images to the non-volatile
- card memory, i.e. flash memory that survives power cycling.
- Enable this option if you want to be able to change card firmware
- permanently.
-
- Firmware image downloading needs a user space tool, prism2_srec.
- It is available from http://hostap.epitest.fi/.
-
-config HOSTAP_PLX
- tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
- depends on PCI && HOSTAP && HAS_IOPORT
- help
- Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
- PCI adaptors.
-
- "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
- driver and its help text includes more information about the Host AP
- driver.
-
- The driver can be compiled as a module and will be named
- hostap_plx.
-
-config HOSTAP_PCI
- tristate "Host AP driver for Prism2.5 PCI adaptors"
- depends on PCI && HOSTAP
- help
- Host AP driver's version for Prism2.5 PCI adaptors.
-
- "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
- driver and its help text includes more information about the Host AP
- driver.
-
- The driver can be compiled as a module and will be named
- hostap_pci.
-
-config HOSTAP_CS
- tristate "Host AP driver for Prism2/2.5/3 PC Cards"
- depends on PCMCIA && HOSTAP
- help
- Host AP driver's version for Prism2/2.5/3 PC Cards.
-
- "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
- driver and its help text includes more information about the Host AP
- driver.
-
- The driver can be compiled as a module and will be named
- hostap_cs.
diff --git a/drivers/net/wireless/intersil/hostap/Makefile b/drivers/net/wireless/intersil/hostap/Makefile
deleted file mode 100644
index ae3bb73b2d99..000000000000
--- a/drivers/net/wireless/intersil/hostap/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \
- hostap_ioctl.o hostap_main.o hostap_proc.o
-obj-$(CONFIG_HOSTAP) += hostap.o
-
-obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
-obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
-obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
diff --git a/drivers/net/wireless/intersil/hostap/hostap.h b/drivers/net/wireless/intersil/hostap/hostap.h
deleted file mode 100644
index 552ae33d7875..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_H
-#define HOSTAP_H
-
-#include <linux/ethtool.h>
-#include <linux/kernel.h>
-
-#include "hostap_wlan.h"
-#include "hostap_ap.h"
-
-static const long __maybe_unused freq_list[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442,
- 2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-#define FREQ_COUNT ARRAY_SIZE(freq_list)
-
-/* hostap.c */
-
-extern struct proc_dir_entry *hostap_proc;
-
-u16 hostap_tx_callback_register(local_info_t *local,
- void (*func)(struct sk_buff *, int ok, void *),
- void *data);
-int hostap_tx_callback_unregister(local_info_t *local, u16 idx);
-int hostap_set_word(struct net_device *dev, int rid, u16 val);
-int hostap_set_string(struct net_device *dev, int rid, const char *val);
-u16 hostap_get_porttype(local_info_t *local);
-int hostap_set_encryption(local_info_t *local);
-int hostap_set_antsel(local_info_t *local);
-int hostap_set_roaming(local_info_t *local);
-int hostap_set_auth_algs(local_info_t *local);
-void hostap_dump_rx_header(const char *name,
- const struct hfa384x_rx_frame *rx);
-void hostap_dump_tx_header(const char *name,
- const struct hfa384x_tx_frame *tx);
-extern const struct header_ops hostap_80211_ops;
-int hostap_80211_get_hdrlen(__le16 fc);
-struct net_device_stats *hostap_get_stats(struct net_device *dev);
-void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int type);
-void hostap_set_multicast_list_queue(struct work_struct *work);
-int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
-int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
-void hostap_cleanup(local_info_t *local);
-void hostap_cleanup_handler(void *data);
-struct net_device * hostap_add_interface(struct local_info *local,
- int type, int rtnl_locked,
- const char *prefix, const char *name);
-void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
- int remove_from_list);
-int prism2_update_comms_qual(struct net_device *dev);
-int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
- u8 *body, size_t bodylen);
-int prism2_sta_deauth(local_info_t *local, u16 reason);
-int prism2_wds_add(local_info_t *local, u8 *remote_addr,
- int rtnl_locked);
-int prism2_wds_del(local_info_t *local, u8 *remote_addr,
- int rtnl_locked, int do_not_remove);
-
-
-/* hostap_ap.c */
-
-int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac);
-int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac);
-void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);
-int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac);
-void ap_control_kickall(struct ap_data *ap);
-void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
- struct lib80211_crypt_data ***crypt);
-int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
- struct iw_quality qual[], int buf_size,
- int aplist);
-int prism2_ap_translate_scan(struct net_device *dev,
- struct iw_request_info *info, char *buffer);
-int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);
-
-
-/* hostap_proc.c */
-
-void hostap_init_proc(local_info_t *local);
-void hostap_remove_proc(local_info_t *local);
-
-
-/* hostap_info.c */
-
-void hostap_info_init(local_info_t *local);
-void hostap_info_process(local_info_t *local, struct sk_buff *skb);
-
-
-/* hostap_ioctl.c */
-
-extern const struct iw_handler_def hostap_iw_handler_def;
-extern const struct ethtool_ops prism2_ethtool_ops;
-
-int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd);
-
-#endif /* HOSTAP_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211.h b/drivers/net/wireless/intersil/hostap/hostap_80211.h
deleted file mode 100644
index 1452cf6ecb07..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_80211.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_80211_H
-#define HOSTAP_80211_H
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-struct hostap_ieee80211_mgmt {
- __le16 frame_control;
- __le16 duration;
- u8 da[6];
- u8 sa[6];
- u8 bssid[6];
- __le16 seq_ctrl;
- union {
- struct {
- __le16 auth_alg;
- __le16 auth_transaction;
- __le16 status_code;
- /* possibly followed by Challenge text */
- u8 variable[0];
- } __packed auth;
- struct {
- __le16 reason_code;
- } __packed deauth;
- struct {
- __le16 capab_info;
- __le16 listen_interval;
- /* followed by SSID and Supported rates */
- u8 variable[0];
- } __packed assoc_req;
- struct {
- __le16 capab_info;
- __le16 status_code;
- __le16 aid;
- /* followed by Supported rates */
- u8 variable[0];
- } __packed assoc_resp, reassoc_resp;
- struct {
- __le16 capab_info;
- __le16 listen_interval;
- u8 current_ap[6];
- /* followed by SSID and Supported rates */
- u8 variable[0];
- } __packed reassoc_req;
- struct {
- __le16 reason_code;
- } __packed disassoc;
- struct {
- } __packed probe_req;
- struct {
- u8 timestamp[8];
- __le16 beacon_int;
- __le16 capab_info;
- /* followed by some of SSID, Supported rates,
- * FH Params, DS Params, CF Params, IBSS Params, TIM */
- u8 variable[0];
- } __packed beacon, probe_resp;
- } u;
-} __packed;
-
-
-#define IEEE80211_MGMT_HDR_LEN 24
-#define IEEE80211_DATA_HDR3_LEN 24
-#define IEEE80211_DATA_HDR4_LEN 30
-
-
-struct hostap_80211_rx_status {
- u32 mac_time;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
-};
-
-/* prism2_rx_80211 'type' argument */
-enum {
- PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
- PRISM2_RX_NULLFUNC_ACK
-};
-
-int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, int type);
-void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats);
-void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats);
-
-void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
-netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-
-#endif /* HOSTAP_80211_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
deleted file mode 100644
index 61be822f90b5..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
+++ /dev/null
@@ -1,1116 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <net/lib80211.h>
-#include <linux/if_arp.h>
-
-#include "hostap_80211.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char rfc1042_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char bridge_tunnel_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d "
- "jiffies=%ld\n",
- name, rx_stats->signal, rx_stats->noise, rx_stats->rate,
- skb->len, jiffies);
-
- if (skb->len < 2)
- return;
-
- fc = le16_to_cpu(hdr->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- if (skb->len < IEEE80211_DATA_HDR3_LEN) {
- printk("\n");
- return;
- }
-
- printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
- le16_to_cpu(hdr->seq_ctrl));
-
- printk(KERN_DEBUG " A1=%pM", hdr->addr1);
- printk(" A2=%pM", hdr->addr2);
- printk(" A3=%pM", hdr->addr3);
- if (skb->len >= 30)
- printk(" A4=%pM", hdr->addr4);
- printk("\n");
-}
-
-
-/* Send RX frame to netif with 802.11 (and possible prism) header.
- * Called from hardware or software IRQ context. */
-int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, int type)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int hdrlen, phdrlen, head_need, tail_need;
- u16 fc;
- int prism_header, ret;
- struct ieee80211_hdr *fhdr;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (dev->type == ARPHRD_IEEE80211_PRISM) {
- if (local->monitor_type == PRISM2_MONITOR_PRISM) {
- prism_header = 1;
- phdrlen = sizeof(struct linux_wlan_ng_prism_hdr);
- } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */
- prism_header = 2;
- phdrlen = sizeof(struct linux_wlan_ng_cap_hdr);
- }
- } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) {
- prism_header = 3;
- phdrlen = sizeof(struct hostap_radiotap_rx);
- } else {
- prism_header = 0;
- phdrlen = 0;
- }
-
- fhdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(fhdr->frame_control);
-
- if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
- printk(KERN_DEBUG "%s: dropped management frame with header "
- "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS);
- dev_kfree_skb_any(skb);
- return 0;
- }
-
- hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control);
-
- /* check if there is enough room for extra data; if not, expand skb
- * buffer to be large enough for the changes */
- head_need = phdrlen;
- tail_need = 0;
-#ifdef PRISM2_ADD_BOGUS_CRC
- tail_need += 4;
-#endif /* PRISM2_ADD_BOGUS_CRC */
-
- head_need -= skb_headroom(skb);
- tail_need -= skb_tailroom(skb);
-
- if (head_need > 0 || tail_need > 0) {
- if (pskb_expand_head(skb, head_need > 0 ? head_need : 0,
- tail_need > 0 ? tail_need : 0,
- GFP_ATOMIC)) {
- printk(KERN_DEBUG "%s: prism2_rx_80211 failed to "
- "reallocate skb buffer\n", dev->name);
- dev_kfree_skb_any(skb);
- return 0;
- }
- }
-
- /* We now have an skb with enough head and tail room, so just insert
- * the extra data */
-
-#ifdef PRISM2_ADD_BOGUS_CRC
- memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */
-#endif /* PRISM2_ADD_BOGUS_CRC */
-
- if (prism_header == 1) {
- struct linux_wlan_ng_prism_hdr *hdr;
- hdr = skb_push(skb, phdrlen);
- memset(hdr, 0, phdrlen);
- hdr->msgcode = LWNG_CAP_DID_BASE;
- hdr->msglen = sizeof(*hdr);
- memcpy(hdr->devname, dev->name, sizeof(hdr->devname));
-#define LWNG_SETVAL(f,i,s,l,d) \
-hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \
-hdr->f.status = s; hdr->f.len = l; hdr->f.data = d
- LWNG_SETVAL(hosttime, 1, 0, 4, jiffies);
- LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time);
- LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0);
- LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0);
- LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0);
- LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal);
- LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise);
- LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5);
- LWNG_SETVAL(istx, 9, 0, 4, 0);
- LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen);
-#undef LWNG_SETVAL
- } else if (prism_header == 2) {
- struct linux_wlan_ng_cap_hdr *hdr;
- hdr = skb_push(skb, phdrlen);
- memset(hdr, 0, phdrlen);
- hdr->version = htonl(LWNG_CAPHDR_VERSION);
- hdr->length = htonl(phdrlen);
- hdr->mactime = __cpu_to_be64(rx_stats->mac_time);
- hdr->hosttime = __cpu_to_be64(jiffies);
- hdr->phytype = htonl(4); /* dss_dot11_b */
- hdr->channel = htonl(local->channel);
- hdr->datarate = htonl(rx_stats->rate);
- hdr->antenna = htonl(0); /* unknown */
- hdr->priority = htonl(0); /* unknown */
- hdr->ssi_type = htonl(3); /* raw */
- hdr->ssi_signal = htonl(rx_stats->signal);
- hdr->ssi_noise = htonl(rx_stats->noise);
- hdr->preamble = htonl(0); /* unknown */
- hdr->encoding = htonl(1); /* cck */
- } else if (prism_header == 3) {
- struct hostap_radiotap_rx *hdr;
- hdr = skb_push(skb, phdrlen);
- memset(hdr, 0, phdrlen);
- hdr->hdr.it_len = cpu_to_le16(phdrlen);
- hdr->hdr.it_present =
- cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE));
- hdr->tsft = cpu_to_le64(rx_stats->mac_time);
- hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]);
- hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ);
- hdr->rate = rx_stats->rate / 5;
- hdr->dbm_antsignal = rx_stats->signal;
- hdr->dbm_antnoise = rx_stats->noise;
- }
-
- ret = skb->len - phdrlen;
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb_pull(skb, hdrlen);
- if (prism_header)
- skb_pull(skb, phdrlen);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void monitor_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- int len;
-
- len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += len;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static struct prism2_frag_entry *
-prism2_frag_cache_find(local_info_t *local, unsigned int seq,
- unsigned int frag, u8 *src, u8 *dst)
-{
- struct prism2_frag_entry *entry;
- int i;
-
- for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
- entry = &local->frag_cache[i];
- if (entry->skb != NULL &&
- time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- printk(KERN_DEBUG "%s: expiring fragment cache entry "
- "seq=%u last_frag=%u\n",
- local->dev->name, entry->seq, entry->last_frag);
- dev_kfree_skb(entry->skb);
- entry->skb = NULL;
- }
-
- if (entry->skb != NULL && entry->seq == seq &&
- (entry->last_frag + 1 == frag || frag == -1) &&
- memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
- memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
- return entry;
- }
-
- return NULL;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static struct sk_buff *
-prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
-{
- struct sk_buff *skb = NULL;
- u16 sc;
- unsigned int frag, seq;
- struct prism2_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- frag = sc & IEEE80211_SCTL_FRAG;
- seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-
- if (frag == 0) {
- /* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(local->dev->mtu +
- sizeof(struct ieee80211_hdr) +
- 8 /* LLC */ +
- 2 /* alignment */ +
- 8 /* WEP */ + ETH_ALEN /* WDS */);
- if (skb == NULL)
- return NULL;
-
- entry = &local->frag_cache[local->frag_next_idx];
- local->frag_next_idx++;
- if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN)
- local->frag_next_idx = 0;
-
- if (entry->skb != NULL)
- dev_kfree_skb(entry->skb);
-
- entry->first_frag_time = jiffies;
- entry->seq = seq;
- entry->last_frag = frag;
- entry->skb = skb;
- memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
- } else {
- /* received a fragment of a frame for which the head fragment
- * should have already been received */
- entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2,
- hdr->addr1);
- if (entry != NULL) {
- entry->last_frag = frag;
- skb = entry->skb;
- }
- }
-
- return skb;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int prism2_frag_cache_invalidate(local_info_t *local,
- struct ieee80211_hdr *hdr)
-{
- u16 sc;
- unsigned int seq;
- struct prism2_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-
- entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1);
-
- if (entry == NULL) {
- printk(KERN_DEBUG "%s: could not invalidate fragment cache "
- "entry (seq=%u)\n",
- local->dev->name, seq);
- return -1;
- }
-
- entry->skb = NULL;
- return 0;
-}
-
-
-static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid,
- u8 *ssid, size_t ssid_len)
-{
- struct list_head *ptr;
- struct hostap_bss_info *bss;
-
- list_for_each(ptr, &local->bss_list) {
- bss = list_entry(ptr, struct hostap_bss_info, list);
- if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
- (ssid == NULL ||
- (ssid_len == bss->ssid_len &&
- memcmp(ssid, bss->ssid, ssid_len) == 0))) {
- list_move(&bss->list, &local->bss_list);
- return bss;
- }
- }
-
- return NULL;
-}
-
-
-static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid,
- u8 *ssid, size_t ssid_len)
-{
- struct hostap_bss_info *bss;
-
- if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) {
- bss = list_entry(local->bss_list.prev,
- struct hostap_bss_info, list);
- list_del(&bss->list);
- local->num_bss_info--;
- } else {
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
- if (bss == NULL)
- return NULL;
- }
-
- memset(bss, 0, sizeof(*bss));
- memcpy(bss->bssid, bssid, ETH_ALEN);
- memcpy(bss->ssid, ssid, ssid_len);
- bss->ssid_len = ssid_len;
- local->num_bss_info++;
- list_add(&bss->list, &local->bss_list);
- return bss;
-}
-
-
-static void __hostap_expire_bss(local_info_t *local)
-{
- struct hostap_bss_info *bss;
-
- while (local->num_bss_info > 0) {
- bss = list_entry(local->bss_list.prev,
- struct hostap_bss_info, list);
- if (!time_after(jiffies, bss->last_update + 60 * HZ))
- break;
-
- list_del(&bss->list);
- local->num_bss_info--;
- kfree(bss);
- }
-}
-
-
-/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so
- * the same routine can be used to parse both of them. */
-static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
- int stype)
-{
- struct hostap_ieee80211_mgmt *mgmt;
- int left, chan = 0;
- u8 *pos;
- u8 *ssid = NULL, *wpa = NULL, *rsn = NULL;
- size_t ssid_len = 0, wpa_len = 0, rsn_len = 0;
- struct hostap_bss_info *bss;
-
- if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon))
- return;
-
- mgmt = (struct hostap_ieee80211_mgmt *) skb->data;
- pos = mgmt->u.beacon.variable;
- left = skb->len - (pos - skb->data);
-
- while (left >= 2) {
- if (2 + pos[1] > left)
- return; /* parse failed */
- switch (*pos) {
- case WLAN_EID_SSID:
- ssid = pos + 2;
- ssid_len = pos[1];
- break;
- case WLAN_EID_VENDOR_SPECIFIC:
- if (pos[1] >= 4 &&
- pos[2] == 0x00 && pos[3] == 0x50 &&
- pos[4] == 0xf2 && pos[5] == 1) {
- wpa = pos;
- wpa_len = pos[1] + 2;
- }
- break;
- case WLAN_EID_RSN:
- rsn = pos;
- rsn_len = pos[1] + 2;
- break;
- case WLAN_EID_DS_PARAMS:
- if (pos[1] >= 1)
- chan = pos[2];
- break;
- }
- left -= 2 + pos[1];
- pos += 2 + pos[1];
- }
-
- if (wpa_len > MAX_WPA_IE_LEN)
- wpa_len = MAX_WPA_IE_LEN;
- if (rsn_len > MAX_WPA_IE_LEN)
- rsn_len = MAX_WPA_IE_LEN;
- if (ssid_len > sizeof(bss->ssid))
- ssid_len = sizeof(bss->ssid);
-
- spin_lock(&local->lock);
- bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len);
- if (bss == NULL)
- bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len);
- if (bss) {
- bss->last_update = jiffies;
- bss->count++;
- bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info);
- if (wpa) {
- memcpy(bss->wpa_ie, wpa, wpa_len);
- bss->wpa_ie_len = wpa_len;
- } else
- bss->wpa_ie_len = 0;
- if (rsn) {
- memcpy(bss->rsn_ie, rsn, rsn_len);
- bss->rsn_ie_len = rsn_len;
- } else
- bss->rsn_ie_len = 0;
- bss->chan = chan;
- }
- __hostap_expire_bss(local);
- spin_unlock(&local->lock);
-}
-
-
-static int
-hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, u16 type,
- u16 stype)
-{
- if (local->iw_mode == IW_MODE_MASTER)
- hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data);
-
- if (local->hostapd && type == IEEE80211_FTYPE_MGMT) {
- if (stype == IEEE80211_STYPE_BEACON &&
- local->iw_mode == IW_MODE_MASTER) {
- struct sk_buff *skb2;
- /* Process beacon frames also in kernel driver to
- * update STA(AP) table statistics */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2)
- hostap_rx(skb2->dev, skb2, rx_stats);
- }
-
- /* send management frames to the user space daemon for
- * processing */
- local->apdevstats.rx_packets++;
- local->apdevstats.rx_bytes += skb->len;
- if (local->apdev == NULL)
- return -1;
- prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT);
- return 0;
- }
-
- if (local->iw_mode == IW_MODE_MASTER) {
- if (type != IEEE80211_FTYPE_MGMT &&
- type != IEEE80211_FTYPE_CTL) {
- printk(KERN_DEBUG "%s: unknown management frame "
- "(type=0x%02x, stype=0x%02x) dropped\n",
- skb->dev->name, type >> 2, stype >> 4);
- return -1;
- }
-
- hostap_rx(skb->dev, skb, rx_stats);
- return 0;
- } else if (type == IEEE80211_FTYPE_MGMT &&
- (stype == IEEE80211_STYPE_BEACON ||
- stype == IEEE80211_STYPE_PROBE_RESP)) {
- hostap_rx_sta_beacon(local, skb, stype);
- return -1;
- } else if (type == IEEE80211_FTYPE_MGMT &&
- (stype == IEEE80211_STYPE_ASSOC_RESP ||
- stype == IEEE80211_STYPE_REASSOC_RESP)) {
- /* Ignore (Re)AssocResp silently since these are not currently
- * needed but are still received when WPA/RSN mode is enabled.
- */
- return -1;
- } else {
- printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled"
- " management frame in non-Host AP mode (type=%d:%d)\n",
- skb->dev->name, type >> 2, stype >> 4);
- return -1;
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static struct net_device *prism2_rx_get_wds(local_info_t *local,
- u8 *addr)
-{
- struct hostap_interface *iface = NULL;
- struct list_head *ptr;
-
- read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_WDS &&
- memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0)
- break;
- iface = NULL;
- }
- read_unlock_bh(&local->iface_lock);
-
- return iface ? iface->dev : NULL;
-}
-
-
-static int
-hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc,
- struct net_device **wds)
-{
- /* FIX: is this really supposed to accept WDS frames only in Master
- * mode? What about Repeater or Managed with WDS frames? */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
- (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) &&
- (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS)))
- return 0; /* not a WDS frame */
-
- /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS)
- * or own non-standard frame with 4th address after payload */
- if (!ether_addr_equal(hdr->addr1, local->dev->dev_addr) &&
- (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff ||
- hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
- hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
- /* RA (or BSSID) is not ours - drop */
- PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
- "not own or broadcast %s=%pM\n",
- local->dev->name,
- fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
- hdr->addr1);
- return -1;
- }
-
- /* check if the frame came from a registered WDS connection */
- *wds = prism2_rx_get_wds(local, hdr->addr2);
- if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS &&
- (local->iw_mode != IW_MODE_INFRA ||
- !(local->wds_type & HOSTAP_WDS_AP_CLIENT) ||
- memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) {
- /* require that WDS link has been registered with TA or the
- * frame is from current AP when using 'AP client mode' */
- PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
- "from unknown TA=%pM\n",
- local->dev->name, hdr->addr2);
- if (local->ap && local->ap->autom_ap_wds)
- hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
- return -1;
- }
-
- if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap &&
- hostap_is_sta_assoc(local->ap, hdr->addr2)) {
- /* STA is actually associated with us even though it has a
- * registered WDS link. Assume it is in 'AP client' mode.
- * Since this is a 3-addr frame, assume it is not (bogus) WDS
- * frame and process it like any normal ToDS frame from
- * associated STA. */
- *wds = NULL;
- }
-
- return 0;
-}
-
-
-static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
-{
- struct net_device *dev = local->dev;
- u16 fc, ethertype;
- struct ieee80211_hdr *hdr;
- u8 *pos;
-
- if (skb->len < 24)
- return 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
-
- /* check that the frame is unicast frame to us */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr) &&
- ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- /* ToDS frame with own addr BSSID and DA */
- } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- /* FromDS frame with own addr as DA */
- } else
- return 0;
-
- if (skb->len < 24 + 8)
- return 0;
-
- /* check for port access entity Ethernet type */
- pos = skb->data + 24;
- ethertype = (pos[6] << 8) | pos[7];
- if (ethertype == ETH_P_PAE)
- return 1;
-
- return 0;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int
-hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct ieee80211_hdr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
- return 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- if (local->tkip_countermeasures &&
- strcmp(crypt->ops->name, "TKIP") == 0) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from %pM\n",
- local->dev->name, hdr->addr2);
- }
- return -1;
- }
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n",
- local->dev->name, hdr->addr2, res);
- local->comm_tallies.rx_discards_wep_undecryptable++;
- return -1;
- }
-
- return res;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int
-hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
- int keyidx, struct lib80211_crypt_data *crypt)
-{
- struct ieee80211_hdr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
- return 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=%pM keyidx=%d)\n",
- local->dev->name, hdr->addr2, keyidx);
- return -1;
- }
-
- return 0;
-}
-
-
-/* All received frames are sent to this function. @skb contains the frame in
- * IEEE 802.11 format, i.e., in the format it was sent over air.
- * This function is called only as a tasklet (software IRQ). */
-void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
- size_t hdrlen;
- u16 fc, type, stype, sc;
- struct net_device *wds = NULL;
- unsigned int frag;
- u8 *payload;
- struct sk_buff *skb2 = NULL;
- u16 ethertype;
- int frame_authorized = 0;
- int from_assoc_ap = 0;
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
- void *sta = NULL;
- int keyidx = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
- iface->stats.rx_packets++;
- iface->stats.rx_bytes += skb->len;
-
- /* dev is the master radio device; change this to be the default
- * virtual interface (this may be changed to WDS device below) */
- dev = local->ddev;
- iface = netdev_priv(dev);
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- if (skb->len < 10)
- goto rx_dropped;
-
- fc = le16_to_cpu(hdr->frame_control);
- type = fc & IEEE80211_FCTL_FTYPE;
- stype = fc & IEEE80211_FCTL_STYPE;
- sc = le16_to_cpu(hdr->seq_ctrl);
- frag = sc & IEEE80211_SCTL_FRAG;
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- /* Put this code here so that we avoid duplicating it in all
- * Rx paths. - Jean II */
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- /* If spy monitoring on */
- if (iface->spy_data.spy_number > 0) {
- struct iw_quality wstats;
- wstats.level = rx_stats->signal;
- wstats.noise = rx_stats->noise;
- wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED
- | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(dev, hdr->addr2, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
- hostap_update_rx_stats(local->ap, hdr, rx_stats);
-
- if (local->iw_mode == IW_MODE_MONITOR) {
- monitor_rx(dev, skb, rx_stats);
- return;
- }
-
- if (local->host_decrypt) {
- int idx = 0;
- if (skb->len >= hdrlen + 3)
- idx = skb->data[hdrlen + 3] >> 6;
- crypt = local->crypt_info.crypt[idx];
- sta = NULL;
-
- /* Use station specific key to override default keys if the
- * receiver address is a unicast address ("individual RA"). If
- * bcrx_sta_key parameter is set, station specific key is used
- * even with broad/multicast targets (this is against IEEE
- * 802.11, but makes it easier to use different keys with
- * stations that do not support WEP key mapping). */
-
- if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
- (void) hostap_handle_sta_crypto(local, hdr, &crypt,
- &sta);
-
- /* allow NULL decrypt to indicate an station specific override
- * for default encryption */
- if (crypt && (crypt->ops == NULL ||
- crypt->ops->decrypt_mpdu == NULL))
- crypt = NULL;
-
- if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
-#if 0
- /* This seems to be triggered by some (multicast?)
- * frames from other than current BSS, so just drop the
- * frames silently instead of filling system log with
- * these reports. */
- printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
- " (SA=%pM)\n",
- local->dev->name, hdr->addr2);
-#endif
- local->comm_tallies.rx_discards_wep_undecryptable++;
- goto rx_dropped;
- }
- }
-
- if (type != IEEE80211_FTYPE_DATA) {
- if (type == IEEE80211_FTYPE_MGMT &&
- stype == IEEE80211_STYPE_AUTH &&
- fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt &&
- (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
- {
- printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from %pM\n", dev->name, hdr->addr2);
- /* TODO: could inform hostapd about this so that it
- * could send auth failure report */
- goto rx_dropped;
- }
-
- if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype))
- goto rx_dropped;
- else
- goto rx_exit;
- }
-
- /* Data frame - extract src/dst addresses */
- if (skb->len < IEEE80211_DATA_HDR3_LEN)
- goto rx_dropped;
-
- switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_FROMDS:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr3, ETH_ALEN);
- break;
- case IEEE80211_FCTL_TODS:
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < IEEE80211_DATA_HDR4_LEN)
- goto rx_dropped;
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr4, ETH_ALEN);
- break;
- default:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- }
-
- if (hostap_rx_frame_wds(local, hdr, fc, &wds))
- goto rx_dropped;
- if (wds)
- skb->dev = dev = wds;
-
- if (local->iw_mode == IW_MODE_MASTER && !wds &&
- (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- local->stadev &&
- memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) {
- /* Frame from BSSID of the AP for which we are a client */
- skb->dev = dev = local->stadev;
- from_assoc_ap = 1;
- }
-
- if ((local->iw_mode == IW_MODE_MASTER ||
- local->iw_mode == IW_MODE_REPEAT) &&
- !from_assoc_ap) {
- switch (hostap_handle_sta_rx(local, dev, skb, rx_stats,
- wds != NULL)) {
- case AP_RX_CONTINUE_NOT_AUTHORIZED:
- frame_authorized = 0;
- break;
- case AP_RX_CONTINUE:
- frame_authorized = 1;
- break;
- case AP_RX_DROP:
- goto rx_dropped;
- case AP_RX_EXIT:
- goto rx_exit;
- }
- }
-
- /* Nullfunc frames may have PS-bit set, so they must be passed to
- * hostap_handle_sta_rx() before being dropped here. */
- if (stype != IEEE80211_STYPE_DATA &&
- stype != IEEE80211_STYPE_DATA_CFACK &&
- stype != IEEE80211_STYPE_DATA_CFPOLL &&
- stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
- if (stype != IEEE80211_STYPE_NULLFUNC)
- printk(KERN_DEBUG "%s: RX: dropped data frame "
- "with no data (type=0x%02x, subtype=0x%02x)\n",
- dev->name, type >> 2, stype >> 4);
- goto rx_dropped;
- }
-
- /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
-
- if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
- goto rx_dropped;
- hdr = (struct ieee80211_hdr *) skb->data;
-
- /* skb: hdr + (possibly fragmented) plaintext payload */
-
- if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
- int flen;
- struct sk_buff *frag_skb =
- prism2_frag_cache_get(local, hdr);
- if (!frag_skb) {
- printk(KERN_DEBUG "%s: Rx cannot get skb from "
- "fragment cache (morefrag=%d seq=%u frag=%u)\n",
- dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
- (sc & IEEE80211_SCTL_SEQ) >> 4, frag);
- goto rx_dropped;
- }
-
- flen = skb->len;
- if (frag != 0)
- flen -= hdrlen;
-
- if (frag_skb->tail + flen > frag_skb->end) {
- printk(KERN_WARNING "%s: host decrypted and "
- "reassembled frame did not fit skb\n",
- dev->name);
- prism2_frag_cache_invalidate(local, hdr);
- goto rx_dropped;
- }
-
- if (frag == 0) {
- /* copy first fragment (including full headers) into
- * beginning of the fragment cache skb */
- skb_copy_from_linear_data(skb, skb_put(frag_skb, flen),
- flen);
- } else {
- /* append frame payload to the end of the fragment
- * cache skb */
- skb_copy_from_linear_data_offset(skb, hdrlen,
- skb_put(frag_skb,
- flen), flen);
- }
- dev_kfree_skb(skb);
- skb = NULL;
-
- if (fc & IEEE80211_FCTL_MOREFRAGS) {
- /* more fragments expected - leave the skb in fragment
- * cache for now; it will be delivered to upper layers
- * after all fragments have been received */
- goto rx_exit;
- }
-
- /* this was the last fragment and the frame will be
- * delivered, so remove skb from fragment cache */
- skb = frag_skb;
- hdr = (struct ieee80211_hdr *) skb->data;
- prism2_frag_cache_invalidate(local, hdr);
- }
-
- /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
- * encrypted/authenticated */
-
- if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt))
- goto rx_dropped;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) {
- if (local->ieee_802_1x &&
- hostap_is_eapol_frame(local, skb)) {
- /* pass unencrypted EAPOL frames even if encryption is
- * configured */
- PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing "
- "unencrypted EAPOL frame\n", local->dev->name);
- } else {
- printk(KERN_DEBUG "%s: encryption configured, but RX "
- "frame not encrypted (SA=%pM)\n",
- local->dev->name, hdr->addr2);
- goto rx_dropped;
- }
- }
-
- if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) &&
- !hostap_is_eapol_frame(local, skb)) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: dropped unencrypted RX data "
- "frame from %pM (drop_unencrypted=1)\n",
- dev->name, hdr->addr2);
- }
- goto rx_dropped;
- }
-
- /* skb: hdr + (possible reassembled) full plaintext payload */
-
- payload = skb->data + hdrlen;
- ethertype = (payload[6] << 8) | payload[7];
-
- /* If IEEE 802.1X is used, check whether the port is authorized to send
- * the received frame. */
- if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) {
- if (ethertype == ETH_P_PAE) {
- PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n",
- dev->name);
- if (local->hostapd && local->apdev) {
- /* Send IEEE 802.1X frames to the user
- * space daemon for processing */
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_MGMT);
- local->apdevstats.rx_packets++;
- local->apdevstats.rx_bytes += skb->len;
- goto rx_exit;
- }
- } else if (!frame_authorized) {
- printk(KERN_DEBUG "%s: dropped frame from "
- "unauthorized port (IEEE 802.1X): "
- "ethertype=0x%04x\n",
- dev->name, ethertype);
- goto rx_dropped;
- }
- }
-
- /* convert hdr + possible LLC headers into Ethernet header */
- if (skb->len - hdrlen >= 8 &&
- ((memcmp(payload, rfc1042_header, 6) == 0 &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(payload, bridge_tunnel_header, 6) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation and
- * replace EtherType */
- skb_pull(skb, hdrlen + 6);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- } else {
- __be16 len;
- /* Leave Ethernet header part of hdr and full payload */
- skb_pull(skb, hdrlen);
- len = htons(skb->len);
- memcpy(skb_push(skb, 2), &len, 2);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- }
-
- if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS) &&
- skb->len >= ETH_HLEN + ETH_ALEN) {
- /* Non-standard frame: get addr4 from its bogus location after
- * the payload */
- skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN,
- skb->data + ETH_ALEN,
- ETH_ALEN);
- skb_trim(skb, skb->len - ETH_ALEN);
- }
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
- if (local->iw_mode == IW_MODE_MASTER && !wds &&
- local->ap->bridge_packets) {
- if (dst[0] & 0x01) {
- /* copy multicast frame both to the higher layers and
- * to the wireless media */
- local->ap->bridged_multicast++;
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- printk(KERN_DEBUG "%s: skb_clone failed for "
- "multicast frame\n", dev->name);
- } else if (hostap_is_sta_authorized(local->ap, dst)) {
- /* send frame directly to the associated STA using
- * wireless media and not passing to higher layers */
- local->ap->bridged_unicast++;
- skb2 = skb;
- skb = NULL;
- }
- }
-
- if (skb2 != NULL) {
- /* send to wireless media */
- skb2->dev = dev;
- skb2->protocol = cpu_to_be16(ETH_P_802_3);
- skb_reset_mac_header(skb2);
- skb_reset_network_header(skb2);
- /* skb2->network_header += ETH_HLEN; */
- dev_queue_xmit(skb2);
- }
-
- if (skb) {
- skb->protocol = eth_type_trans(skb, dev);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
- }
-
- rx_exit:
- if (sta)
- hostap_handle_sta_release(sta);
- return;
-
- rx_dropped:
- dev_kfree_skb(skb);
-
- dev->stats.rx_dropped++;
- goto rx_exit;
-}
-
-
-EXPORT_SYMBOL(hostap_80211_rx);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
deleted file mode 100644
index c47da06945c2..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
+++ /dev/null
@@ -1,554 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/etherdevice.h>
-
-#include "hostap_80211.h"
-#include "hostap_common.h"
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char rfc1042_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char bridge_tunnel_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
- name, skb->len, jiffies);
-
- if (skb->len < 2)
- return;
-
- fc = le16_to_cpu(hdr->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- if (skb->len < IEEE80211_DATA_HDR3_LEN) {
- printk("\n");
- return;
- }
-
- printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
- le16_to_cpu(hdr->seq_ctrl));
-
- printk(KERN_DEBUG " A1=%pM", hdr->addr1);
- printk(" A2=%pM", hdr->addr2);
- printk(" A3=%pM", hdr->addr3);
- if (skb->len >= 30)
- printk(" A4=%pM", hdr->addr4);
- printk("\n");
-}
-
-
-/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
- * Convert Ethernet header into a suitable IEEE 802.11 header depending on
- * device configuration. */
-netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int need_headroom, need_tailroom = 0;
- struct ieee80211_hdr hdr;
- u16 fc, ethertype = 0;
- enum {
- WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
- } use_wds = WDS_NO;
- u8 *encaps_data;
- int hdr_len, encaps_len, skip_header_bytes;
- int to_assoc_ap = 0;
- struct hostap_skb_tx_data *meta;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (skb->len < ETH_HLEN) {
- printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
- "(len=%d)\n", dev->name, skb->len);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- if (local->ddev != dev) {
- use_wds = (local->iw_mode == IW_MODE_MASTER &&
- !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?
- WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;
- if (dev == local->stadev) {
- to_assoc_ap = 1;
- use_wds = WDS_NO;
- } else if (dev == local->apdev) {
- printk(KERN_DEBUG "%s: prism2_tx: trying to use "
- "AP device with Ethernet net dev\n", dev->name);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- } else {
- if (local->iw_mode == IW_MODE_REPEAT) {
- printk(KERN_DEBUG "%s: prism2_tx: trying to use "
- "non-WDS link in Repeater mode\n", dev->name);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- } else if (local->iw_mode == IW_MODE_INFRA &&
- (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
- !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) {
- /* AP client mode: send frames with foreign src addr
- * using 4-addr WDS frames */
- use_wds = WDS_COMPLIANT_FRAME;
- }
- }
-
- /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
- * ==>
- * Prism2 TX frame with 802.11 header:
- * txdesc (address order depending on used mode; includes dst_addr and
- * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;
- * proto[2], payload {, possible addr4[6]} */
-
- ethertype = (skb->data[12] << 8) | skb->data[13];
-
- memset(&hdr, 0, sizeof(hdr));
-
- /* Length of data after IEEE 802.11 header */
- encaps_data = NULL;
- encaps_len = 0;
- skip_header_bytes = ETH_HLEN;
- if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
- encaps_data = bridge_tunnel_header;
- encaps_len = sizeof(bridge_tunnel_header);
- skip_header_bytes -= 2;
- } else if (ethertype >= 0x600) {
- encaps_data = rfc1042_header;
- encaps_len = sizeof(rfc1042_header);
- skip_header_bytes -= 2;
- }
-
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
- hdr_len = IEEE80211_DATA_HDR3_LEN;
-
- if (use_wds != WDS_NO) {
- /* Note! Prism2 station firmware has problems with sending real
- * 802.11 frames with four addresses; until these problems can
- * be fixed or worked around, 4-addr frames needed for WDS are
- * using incompatible format: FromDS flag is not set and the
- * fourth address is added after the frame payload; it is
- * assumed, that the receiving station knows how to handle this
- * frame format */
-
- if (use_wds == WDS_COMPLIANT_FRAME) {
- fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
- /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
- * Addr4 = SA */
- skb_copy_from_linear_data_offset(skb, ETH_ALEN,
- &hdr.addr4, ETH_ALEN);
- hdr_len += ETH_ALEN;
- } else {
- /* bogus 4-addr format to workaround Prism2 station
- * f/w bug */
- fc |= IEEE80211_FCTL_TODS;
- /* From DS: Addr1 = DA (used as RA),
- * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
- */
-
- /* SA from skb->data + ETH_ALEN will be added after
- * frame payload; use hdr.addr4 as a temporary buffer
- */
- skb_copy_from_linear_data_offset(skb, ETH_ALEN,
- &hdr.addr4, ETH_ALEN);
- need_tailroom += ETH_ALEN;
- }
-
- /* send broadcast and multicast frames to broadcast RA, if
- * configured; otherwise, use unicast RA of the WDS link */
- if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&
- is_multicast_ether_addr(skb->data))
- eth_broadcast_addr(hdr.addr1);
- else if (iface->type == HOSTAP_INTERFACE_WDS)
- memcpy(&hdr.addr1, iface->u.wds.remote_addr,
- ETH_ALEN);
- else
- memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
- memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
- skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
- } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
- fc |= IEEE80211_FCTL_FROMDS;
- /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
- skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
- memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3,
- ETH_ALEN);
- } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
- fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
- memcpy(&hdr.addr1, to_assoc_ap ?
- local->assoc_ap_addr : local->bssid, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
- ETH_ALEN);
- skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
- } else if (local->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
- skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
- ETH_ALEN);
- memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
- }
-
- hdr.frame_control = cpu_to_le16(fc);
-
- skb_pull(skb, skip_header_bytes);
- need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
- if (skb_tailroom(skb) < need_tailroom) {
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (skb == NULL) {
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- if (pskb_expand_head(skb, need_headroom, need_tailroom,
- GFP_ATOMIC)) {
- kfree_skb(skb);
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- } else if (skb_headroom(skb) < need_headroom) {
- struct sk_buff *tmp = skb;
- skb = skb_realloc_headroom(skb, need_headroom);
- kfree_skb(tmp);
- if (skb == NULL) {
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- } else {
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (skb == NULL) {
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- }
-
- if (encaps_data)
- memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
- memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);
- if (use_wds == WDS_OWN_FRAME) {
- skb_put_data(skb, &hdr.addr4, ETH_ALEN);
- }
-
- iface->stats.tx_packets++;
- iface->stats.tx_bytes += skb->len;
-
- skb_reset_mac_header(skb);
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- if (use_wds)
- meta->flags |= HOSTAP_TX_FLAGS_WDS;
- meta->ethertype = ethertype;
- meta->iface = iface;
-
- /* Send IEEE 802.11 encapsulated frame using the master radio device */
- skb->dev = local->dev;
- dev_queue_xmit(skb);
- return NETDEV_TX_OK;
-}
-
-
-/* hard_start_xmit function for hostapd wlan#ap interfaces */
-netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hostap_skb_tx_data *meta;
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (skb->len < 10) {
- printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
- "(len=%d)\n", dev->name, skb->len);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- iface->stats.tx_packets++;
- iface->stats.tx_bytes += skb->len;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- meta->iface = iface;
-
- if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- if (ieee80211_is_data(hdr->frame_control) &&
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) {
- u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
- sizeof(rfc1042_header)];
- meta->ethertype = (pos[0] << 8) | pos[1];
- }
- }
-
- /* Send IEEE 802.11 encapsulated frame using the master radio device */
- skb->dev = local->dev;
- dev_queue_xmit(skb);
- return NETDEV_TX_OK;
-}
-
-
-/* Called only from software IRQ */
-static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
- int prefix_len, postfix_len, hdr_len, res;
-
- iface = netdev_priv(skb->dev);
- local = iface->local;
-
- if (skb->len < IEEE80211_DATA_HDR3_LEN) {
- kfree_skb(skb);
- return NULL;
- }
-
- if (local->tkip_countermeasures &&
- strcmp(crypt->ops->name, "TKIP") == 0) {
- hdr = (struct ieee80211_hdr *) skb->data;
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to %pM\n",
- local->dev->name, hdr->addr1);
- }
- kfree_skb(skb);
- return NULL;
- }
-
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (skb == NULL)
- return NULL;
-
- prefix_len = crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_msdu_prefix_len;
- postfix_len = crypt->ops->extra_mpdu_postfix_len +
- crypt->ops->extra_msdu_postfix_len;
- if ((skb_headroom(skb) < prefix_len ||
- skb_tailroom(skb) < postfix_len) &&
- pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) {
- kfree_skb(skb);
- return NULL;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdr_len = hostap_80211_get_hdrlen(hdr->frame_control);
-
- /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
- * call both MSDU and MPDU encryption functions from here. */
- atomic_inc(&crypt->refcnt);
- res = 0;
- if (crypt->ops->encrypt_msdu)
- res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);
- if (res == 0 && crypt->ops->encrypt_mpdu)
- res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- kfree_skb(skb);
- return NULL;
- }
-
- return skb;
-}
-
-
-/* hard_start_xmit function for master radio interface wifi#.
- * AP processing (TX rate control, power save buffering, etc.).
- * Use hardware TX function to send the frame. */
-netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- netdev_tx_t ret = NETDEV_TX_BUSY;
- u16 fc;
- struct hostap_tx_data tx;
- ap_tx_ret tx_ret;
- struct hostap_skb_tx_data *meta;
- int no_encrypt = 0;
- struct ieee80211_hdr *hdr;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- tx.skb = skb;
- tx.sta_ptr = NULL;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
- printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
- "expected 0x%08x)\n",
- dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- goto fail;
- }
-
- if (local->host_encrypt) {
- /* Set crypt to default algorithm and key; will be replaced in
- * AP code if STA has own alg/key */
- tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx];
- tx.host_encrypt = 1;
- } else {
- tx.crypt = NULL;
- tx.host_encrypt = 0;
- }
-
- if (skb->len < 24) {
- printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
- "(len=%d)\n", dev->name, skb->len);
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- goto fail;
- }
-
- /* FIX (?):
- * Wi-Fi 802.11b test plan suggests that AP should ignore power save
- * bit in authentication and (re)association frames and assume tha
- * STA remains awake for the response. */
- tx_ret = hostap_handle_sta_tx(local, &tx);
- skb = tx.skb;
- meta = (struct hostap_skb_tx_data *) skb->cb;
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- switch (tx_ret) {
- case AP_TX_CONTINUE:
- break;
- case AP_TX_CONTINUE_NOT_AUTHORIZED:
- if (local->ieee_802_1x &&
- ieee80211_is_data(hdr->frame_control) &&
- meta->ethertype != ETH_P_PAE &&
- !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
- printk(KERN_DEBUG "%s: dropped frame to unauthorized "
- "port (IEEE 802.1X): ethertype=0x%04x\n",
- dev->name, meta->ethertype);
- hostap_dump_tx_80211(dev->name, skb);
-
- ret = NETDEV_TX_OK; /* drop packet */
- iface->stats.tx_dropped++;
- goto fail;
- }
- break;
- case AP_TX_DROP:
- ret = NETDEV_TX_OK; /* drop packet */
- iface->stats.tx_dropped++;
- goto fail;
- case AP_TX_RETRY:
- goto fail;
- case AP_TX_BUFFERED:
- /* do not free skb here, it will be freed when the
- * buffered frame is sent/timed out */
- ret = NETDEV_TX_OK;
- goto tx_exit;
- }
-
- /* Request TX callback if protocol version is 2 in 802.11 header;
- * this version 2 is a special case used between hostapd and kernel
- * driver */
- if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
- local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
- meta->tx_cb_idx = local->ap->tx_callback_idx;
-
- /* remove special version from the frame header */
- fc &= ~IEEE80211_FCTL_VERS;
- hdr->frame_control = cpu_to_le16(fc);
- }
-
- if (!ieee80211_is_data(hdr->frame_control)) {
- no_encrypt = 1;
- tx.crypt = NULL;
- }
-
- if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
- !(fc & IEEE80211_FCTL_PROTECTED)) {
- no_encrypt = 1;
- PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
- "unencrypted EAPOL frame\n", dev->name);
- tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */
- }
-
- if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
- tx.crypt = NULL;
- else if ((tx.crypt ||
- local->crypt_info.crypt[local->crypt_info.tx_keyidx]) &&
- !no_encrypt) {
- /* Add ISWEP flag both for firmware and host based encryption
- */
- fc |= IEEE80211_FCTL_PROTECTED;
- hdr->frame_control = cpu_to_le16(fc);
- } else if (local->drop_unencrypted &&
- ieee80211_is_data(hdr->frame_control) &&
- meta->ethertype != ETH_P_PAE) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: dropped unencrypted TX data "
- "frame (drop_unencrypted=1)\n", dev->name);
- }
- iface->stats.tx_dropped++;
- ret = NETDEV_TX_OK;
- goto fail;
- }
-
- if (tx.crypt) {
- skb = hostap_tx_encrypt(skb, tx.crypt);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: TX - encryption failed\n",
- dev->name);
- ret = NETDEV_TX_OK;
- goto fail;
- }
- meta = (struct hostap_skb_tx_data *) skb->cb;
- if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
- printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
- "expected 0x%08x) after hostap_tx_encrypt\n",
- dev->name, meta->magic,
- HOSTAP_SKB_TX_DATA_MAGIC);
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- goto fail;
- }
- }
-
- if (local->func->tx == NULL || local->func->tx(skb, dev)) {
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- } else {
- ret = NETDEV_TX_OK;
- iface->stats.tx_packets++;
- iface->stats.tx_bytes += skb->len;
- }
-
- fail:
- if (ret == NETDEV_TX_OK && skb)
- dev_kfree_skb(skb);
- tx_exit:
- if (tx.sta_ptr)
- hostap_handle_sta_release(tx.sta_ptr);
- return ret;
-}
-
-
-EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c
deleted file mode 100644
index 9b546a71e7a2..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_ap.c
+++ /dev/null
@@ -1,3277 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Intersil Prism2 driver with Host AP (software access point) support
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j@w1.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * This file is to be included into hostap.c when S/W AP functionality is
- * compiled.
- *
- * AP: FIX:
- * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from
- * unauthenticated STA, send deauth. frame (8802.11: 5.5)
- * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received
- * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5)
- * - if unicast Class 3 received from unauthenticated STA, send deauth. frame
- * (8802.11: 5.5)
- */
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/moduleparam.h>
-#include <linux/etherdevice.h>
-
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL,
- DEF_INTS };
-module_param_array(other_ap_policy, int, NULL, 0444);
-MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)");
-
-static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC,
- DEF_INTS };
-module_param_array(ap_max_inactivity, int, NULL, 0444);
-MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station "
- "inactivity");
-
-static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS };
-module_param_array(ap_bridge_packets, int, NULL, 0444);
-MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between "
- "stations");
-
-static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS };
-module_param_array(autom_ap_wds, int, NULL, 0444);
-MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs "
- "automatically");
-
-
-static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);
-static void hostap_event_expired_sta(struct net_device *dev,
- struct sta_info *sta);
-static void handle_add_proc_queue(struct work_struct *work);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-static void handle_wds_oper_queue(struct work_struct *work);
-static void prism2_send_mgmt(struct net_device *dev,
- u16 type_subtype, char *body,
- int body_len, u8 *addr, u16 tx_cb_idx);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS)
-static int ap_debug_proc_show(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
-
- seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
- seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
- seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ);
- seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets);
- seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack);
- seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds);
- seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs);
- seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
- return 0;
-}
-#endif
-
-static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
-{
- sta->hnext = ap->sta_hash[STA_HASH(sta->addr)];
- ap->sta_hash[STA_HASH(sta->addr)] = sta;
-}
-
-static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
-{
- struct sta_info *s;
-
- s = ap->sta_hash[STA_HASH(sta->addr)];
- if (s == NULL) return;
- if (ether_addr_equal(s->addr, sta->addr)) {
- ap->sta_hash[STA_HASH(sta->addr)] = s->hnext;
- return;
- }
-
- while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr))
- s = s->hnext;
- if (s->hnext != NULL)
- s->hnext = s->hnext->hnext;
- else
- printk("AP: could not remove STA %pM from hash table\n",
- sta->addr);
-}
-
-static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
-{
- if (sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
-
- if (ap->proc != NULL) {
- char name[20];
- sprintf(name, "%pM", sta->addr);
- remove_proc_entry(name, ap->proc);
- }
-
- if (sta->crypt) {
- sta->crypt->ops->deinit(sta->crypt->priv);
- kfree(sta->crypt);
- sta->crypt = NULL;
- }
-
- skb_queue_purge(&sta->tx_buf);
-
- ap->num_sta--;
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (sta->aid > 0)
- ap->sta_aid[sta->aid - 1] = NULL;
-
- if (!sta->ap)
- kfree(sta->u.sta.challenge);
- timer_shutdown_sync(&sta->timer);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- kfree(sta);
-}
-
-
-static void hostap_set_tim(local_info_t *local, int aid, int set)
-{
- if (local->func->set_tim)
- local->func->set_tim(local->dev, aid, set);
-}
-
-
-static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta)
-{
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL);
-}
-
-
-static void hostap_event_expired_sta(struct net_device *dev,
- struct sta_info *sta)
-{
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static void ap_handle_timer(struct timer_list *t)
-{
- struct sta_info *sta = from_timer(sta, t, timer);
- local_info_t *local;
- struct ap_data *ap;
- unsigned long next_time = 0;
- int was_assoc;
-
- if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
- PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
- return;
- }
-
- local = sta->local;
- ap = local->ap;
- was_assoc = sta->flags & WLAN_STA_ASSOC;
-
- if (atomic_read(&sta->users) != 0)
- next_time = jiffies + HZ;
- else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH))
- next_time = jiffies + ap->max_inactivity;
-
- if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) {
- /* station activity detected; reset timeout state */
- sta->timeout_next = STA_NULLFUNC;
- next_time = sta->last_rx + ap->max_inactivity;
- } else if (sta->timeout_next == STA_DISASSOC &&
- !(sta->flags & WLAN_STA_PENDING_POLL)) {
- /* STA ACKed data nullfunc frame poll */
- sta->timeout_next = STA_NULLFUNC;
- next_time = jiffies + ap->max_inactivity;
- }
-
- if (next_time) {
- sta->timer.expires = next_time;
- add_timer(&sta->timer);
- return;
- }
-
- if (sta->ap)
- sta->timeout_next = STA_DEAUTH;
-
- if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) {
- spin_lock(&ap->sta_table_lock);
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- spin_unlock(&ap->sta_table_lock);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- } else if (sta->timeout_next == STA_DISASSOC)
- sta->flags &= ~WLAN_STA_ASSOC;
-
- if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(local->dev, sta);
-
- if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 &&
- !skb_queue_empty(&sta->tx_buf)) {
- hostap_set_tim(local, sta->aid, 0);
- sta->flags &= ~WLAN_STA_TIM;
- }
-
- if (sta->ap) {
- if (ap->autom_ap_wds) {
- PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
- "connection to AP %pM\n",
- local->dev->name, sta->addr);
- hostap_wds_link_oper(local, sta->addr, WDS_DEL);
- }
- } else if (sta->timeout_next == STA_NULLFUNC) {
- /* send data frame to poll STA and check whether this frame
- * is ACKed */
- /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but
- * it is apparently not retried so TX Exc events are not
- * received for it */
- sta->flags |= WLAN_STA_PENDING_POLL;
- prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_DATA, NULL, 0,
- sta->addr, ap->tx_callback_poll);
- } else {
- int deauth = sta->timeout_next == STA_DEAUTH;
- __le16 resp;
- PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM"
- "(last=%lu, jiffies=%lu)\n",
- local->dev->name,
- deauth ? "deauthentication" : "disassociation",
- sta->addr, sta->last_rx, jiffies);
-
- resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
- prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT |
- (deauth ? IEEE80211_STYPE_DEAUTH :
- IEEE80211_STYPE_DISASSOC),
- (char *) &resp, 2, sta->addr, 0);
- }
-
- if (sta->timeout_next == STA_DEAUTH) {
- if (sta->flags & WLAN_STA_PERM) {
- PDEBUG(DEBUG_AP, "%s: STA %pM"
- " would have been removed, "
- "but it has 'perm' flag\n",
- local->dev->name, sta->addr);
- } else
- ap_free_sta(ap, sta);
- return;
- }
-
- if (sta->timeout_next == STA_NULLFUNC) {
- sta->timeout_next = STA_DISASSOC;
- sta->timer.expires = jiffies + AP_DISASSOC_DELAY;
- } else {
- sta->timeout_next = STA_DEAUTH;
- sta->timer.expires = jiffies + AP_DEAUTH_DELAY;
- }
-
- add_timer(&sta->timer);
-}
-
-
-void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
- int resend)
-{
- u8 addr[ETH_ALEN];
- __le16 resp;
- int i;
-
- PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);
- eth_broadcast_addr(addr);
-
- resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-
- /* deauth message sent; try to resend it few times; the message is
- * broadcast, so it may be delayed until next DTIM; there is not much
- * else we can do at this point since the driver is going to be shut
- * down */
- for (i = 0; i < 5; i++) {
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_DEAUTH,
- (char *) &resp, 2, addr, 0);
-
- if (!resend || ap->num_sta <= 0)
- return;
-
- mdelay(50);
- }
-}
-
-
-static int ap_control_proc_show(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- char *policy_txt;
- struct mac_entry *entry;
-
- if (v == SEQ_START_TOKEN) {
- switch (ap->mac_restrictions.policy) {
- case MAC_POLICY_OPEN:
- policy_txt = "open";
- break;
- case MAC_POLICY_ALLOW:
- policy_txt = "allow";
- break;
- case MAC_POLICY_DENY:
- policy_txt = "deny";
- break;
- default:
- policy_txt = "unknown";
- break;
- }
- seq_printf(m, "MAC policy: %s\n", policy_txt);
- seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries);
- seq_puts(m, "MAC list:\n");
- return 0;
- }
-
- entry = v;
- seq_printf(m, "%pM\n", entry->addr);
- return 0;
-}
-
-static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_lock_bh(&ap->mac_restrictions.lock);
- return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos);
-}
-
-static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos);
-}
-
-static void ap_control_proc_stop(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_unlock_bh(&ap->mac_restrictions.lock);
-}
-
-static const struct seq_operations ap_control_proc_seqops = {
- .start = ap_control_proc_start,
- .next = ap_control_proc_next,
- .stop = ap_control_proc_stop,
- .show = ap_control_proc_show,
-};
-
-int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
-{
- struct mac_entry *entry;
-
- entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
- if (entry == NULL)
- return -ENOMEM;
-
- memcpy(entry->addr, mac, ETH_ALEN);
-
- spin_lock_bh(&mac_restrictions->lock);
- list_add_tail(&entry->list, &mac_restrictions->mac_list);
- mac_restrictions->entries++;
- spin_unlock_bh(&mac_restrictions->lock);
-
- return 0;
-}
-
-
-int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
-{
- struct list_head *ptr;
- struct mac_entry *entry;
-
- spin_lock_bh(&mac_restrictions->lock);
- for (ptr = mac_restrictions->mac_list.next;
- ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, list);
-
- if (ether_addr_equal(entry->addr, mac)) {
- list_del(ptr);
- kfree(entry);
- mac_restrictions->entries--;
- spin_unlock_bh(&mac_restrictions->lock);
- return 0;
- }
- }
- spin_unlock_bh(&mac_restrictions->lock);
- return -1;
-}
-
-
-static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
- u8 *mac)
-{
- struct mac_entry *entry;
- int found = 0;
-
- if (mac_restrictions->policy == MAC_POLICY_OPEN)
- return 0;
-
- spin_lock_bh(&mac_restrictions->lock);
- list_for_each_entry(entry, &mac_restrictions->mac_list, list) {
- if (ether_addr_equal(entry->addr, mac)) {
- found = 1;
- break;
- }
- }
- spin_unlock_bh(&mac_restrictions->lock);
-
- if (mac_restrictions->policy == MAC_POLICY_ALLOW)
- return !found;
- else
- return found;
-}
-
-
-void ap_control_flush_macs(struct mac_restrictions *mac_restrictions)
-{
- struct list_head *ptr, *n;
- struct mac_entry *entry;
-
- if (mac_restrictions->entries == 0)
- return;
-
- spin_lock_bh(&mac_restrictions->lock);
- for (ptr = mac_restrictions->mac_list.next, n = ptr->next;
- ptr != &mac_restrictions->mac_list;
- ptr = n, n = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, list);
- list_del(ptr);
- kfree(entry);
- }
- mac_restrictions->entries = 0;
- spin_unlock_bh(&mac_restrictions->lock);
-}
-
-
-int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac)
-{
- struct sta_info *sta;
- __le16 resp;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, mac);
- if (sta) {
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -EINVAL;
-
- resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH,
- (char *) &resp, 2, sta->addr, 0);
-
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(dev, sta);
-
- ap_free_sta(ap, sta);
-
- return 0;
-}
-
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-void ap_control_kickall(struct ap_data *ap)
-{
- struct list_head *ptr, *n;
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list;
- ptr = n, n = ptr->next) {
- sta = list_entry(ptr, struct sta_info, list);
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
- ap_free_sta(ap, sta);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static int prism2_ap_proc_show(struct seq_file *m, void *v)
-{
- struct sta_info *sta = v;
- int i;
-
- if (v == SEQ_START_TOKEN) {
- seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
- return 0;
- }
-
- if (!sta->ap)
- return 0;
-
- seq_printf(m, "%pM %d %d %d %d '",
- sta->addr,
- sta->u.ap.channel, sta->last_rx_signal,
- sta->last_rx_silence, sta->last_rx_rate);
-
- for (i = 0; i < sta->u.ap.ssid_len; i++) {
- if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127)
- seq_putc(m, sta->u.ap.ssid[i]);
- else
- seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);
- }
-
- seq_putc(m, '\'');
- if (sta->capability & WLAN_CAPABILITY_ESS)
- seq_puts(m, " [ESS]");
- if (sta->capability & WLAN_CAPABILITY_IBSS)
- seq_puts(m, " [IBSS]");
- if (sta->capability & WLAN_CAPABILITY_PRIVACY)
- seq_puts(m, " [WEP]");
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_lock_bh(&ap->sta_table_lock);
- return seq_list_start_head(&ap->sta_list, *_pos);
-}
-
-static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- return seq_list_next(v, &ap->sta_list, _pos);
-}
-
-static void prism2_ap_proc_stop(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_unlock_bh(&ap->sta_table_lock);
-}
-
-static const struct seq_operations prism2_ap_proc_seqops = {
- .start = prism2_ap_proc_start,
- .next = prism2_ap_proc_next,
- .stop = prism2_ap_proc_stop,
- .show = prism2_ap_proc_show,
-};
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver)
-{
- if (!ap)
- return;
-
- if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) {
- PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - "
- "firmware upgrade recommended\n");
- ap->nullfunc_ack = 1;
- } else
- ap->nullfunc_ack = 0;
-
- if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) {
- printk(KERN_WARNING "%s: Warning: secondary station firmware "
- "version 1.4.2 does not seem to work in Host AP mode\n",
- ap->local->dev->name);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct ieee80211_hdr *hdr;
-
- if (!ap->local->hostapd || !ap->local->apdev) {
- dev_kfree_skb(skb);
- return;
- }
-
- /* Pass the TX callback frame to the hostapd; use 802.11 header version
- * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS);
- hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0));
-
- skb->dev = ap->local->apdev;
- skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control));
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-/* Called only as a tasklet (software IRQ) */
-static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct net_device *dev = ap->local->dev;
- struct ieee80211_hdr *hdr;
- u16 auth_alg, auth_transaction, status;
- __le16 *pos;
- struct sta_info *sta = NULL;
- char *txt = NULL;
-
- if (ap->local->hostapd) {
- dev_kfree_skb(skb);
- return;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if (!ieee80211_is_auth(hdr->frame_control) ||
- skb->len < IEEE80211_MGMT_HDR_LEN + 6) {
- printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid "
- "frame\n", dev->name);
- dev_kfree_skb(skb);
- return;
- }
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- auth_alg = le16_to_cpu(*pos++);
- auth_transaction = le16_to_cpu(*pos++);
- status = le16_to_cpu(*pos++);
-
- if (!ok) {
- txt = "frame was not ACKed";
- goto done;
- }
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr1);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&ap->sta_table_lock);
-
- if (!sta) {
- txt = "STA not found";
- goto done;
- }
-
- if (status == WLAN_STATUS_SUCCESS &&
- ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
- (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
- txt = "STA authenticated";
- sta->flags |= WLAN_STA_AUTH;
- sta->last_auth = jiffies;
- } else if (status != WLAN_STATUS_SUCCESS)
- txt = "authentication failed";
-
- done:
- if (sta)
- atomic_dec(&sta->users);
- if (txt) {
- PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d "
- "trans#=%d status=%d - %s\n",
- dev->name, hdr->addr1,
- auth_alg, auth_transaction, status, txt);
- }
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct net_device *dev = ap->local->dev;
- struct ieee80211_hdr *hdr;
- u16 status;
- __le16 *pos;
- struct sta_info *sta = NULL;
- char *txt = NULL;
-
- if (ap->local->hostapd) {
- dev_kfree_skb(skb);
- return;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if ((!ieee80211_is_assoc_resp(hdr->frame_control) &&
- !ieee80211_is_reassoc_resp(hdr->frame_control)) ||
- skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
- printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid "
- "frame\n", dev->name);
- dev_kfree_skb(skb);
- return;
- }
-
- if (!ok) {
- txt = "frame was not ACKed";
- goto done;
- }
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr1);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&ap->sta_table_lock);
-
- if (!sta) {
- txt = "STA not found";
- goto done;
- }
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- pos++;
- status = le16_to_cpu(*pos++);
- if (status == WLAN_STATUS_SUCCESS) {
- if (!(sta->flags & WLAN_STA_ASSOC))
- hostap_event_new_sta(dev, sta);
- txt = "STA associated";
- sta->flags |= WLAN_STA_ASSOC;
- sta->last_assoc = jiffies;
- } else
- txt = "association failed";
-
- done:
- if (sta)
- atomic_dec(&sta->users);
- if (txt) {
- PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n",
- dev->name, hdr->addr1, txt);
- }
- dev_kfree_skb(skb);
-}
-
-/* Called only as a tasklet (software IRQ); TX callback for poll frames used
- * in verifying whether the STA is still present. */
-static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct ieee80211_hdr *hdr;
- struct sta_info *sta;
-
- if (skb->len < 24)
- goto fail;
- hdr = (struct ieee80211_hdr *) skb->data;
- if (ok) {
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr1);
- if (sta)
- sta->flags &= ~WLAN_STA_PENDING_POLL;
- spin_unlock(&ap->sta_table_lock);
- } else {
- PDEBUG(DEBUG_AP,
- "%s: STA %pM did not ACK activity poll frame\n",
- ap->local->dev->name, hdr->addr1);
- }
-
- fail:
- dev_kfree_skb(skb);
-}
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-void hostap_init_data(local_info_t *local)
-{
- struct ap_data *ap = local->ap;
-
- if (ap == NULL) {
- printk(KERN_WARNING "hostap_init_data: ap == NULL\n");
- return;
- }
- memset(ap, 0, sizeof(struct ap_data));
- ap->local = local;
-
- ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx);
- ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx);
- ap->max_inactivity =
- GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ;
- ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx);
-
- spin_lock_init(&ap->sta_table_lock);
- INIT_LIST_HEAD(&ap->sta_list);
-
- /* Initialize task queue structure for AP management */
- INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue);
-
- ap->tx_callback_idx =
- hostap_tx_callback_register(local, hostap_ap_tx_cb, ap);
- if (ap->tx_callback_idx == 0)
- printk(KERN_WARNING "%s: failed to register TX callback for "
- "AP\n", local->dev->name);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue);
-
- ap->tx_callback_auth =
- hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
- ap->tx_callback_assoc =
- hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap);
- ap->tx_callback_poll =
- hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap);
- if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 ||
- ap->tx_callback_poll == 0)
- printk(KERN_WARNING "%s: failed to register TX callback for "
- "AP\n", local->dev->name);
-
- spin_lock_init(&ap->mac_restrictions.lock);
- INIT_LIST_HEAD(&ap->mac_restrictions.mac_list);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- ap->initialized = 1;
-}
-
-
-void hostap_init_ap_proc(local_info_t *local)
-{
- struct ap_data *ap = local->ap;
-
- ap->proc = local->proc;
- if (ap->proc == NULL)
- return;
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops,
- ap);
- proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-}
-
-
-void hostap_free_data(struct ap_data *ap)
-{
- struct sta_info *n, *sta;
-
- if (ap == NULL || !ap->initialized) {
- printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
- "initialized - skip resource freeing\n");
- return;
- }
-
- flush_work(&ap->add_sta_proc_queue);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- flush_work(&ap->wds_oper_queue);
- if (ap->crypt)
- ap->crypt->deinit(ap->crypt_priv);
- ap->crypt = ap->crypt_priv = NULL;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- list_for_each_entry_safe(sta, n, &ap->sta_list, list) {
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
- ap_free_sta(ap, sta);
- }
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- if (ap->proc != NULL) {
- remove_proc_entry("ap_debug", ap->proc);
- }
-#endif /* PRISM2_NO_PROCFS_DEBUG */
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (ap->proc != NULL) {
- remove_proc_entry("ap", ap->proc);
- remove_proc_entry("ap_control", ap->proc);
- }
- ap_control_flush_macs(&ap->mac_restrictions);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- ap->initialized = 0;
-}
-
-
-/* caller should have mutex for AP STA list handling */
-static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta)
-{
- struct sta_info *s;
-
- s = ap->sta_hash[STA_HASH(sta)];
- while (s != NULL && !ether_addr_equal(s->addr, sta))
- s = s->hnext;
- return s;
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-/* Called from timer handler and from scheduled AP queue handlers */
-static void prism2_send_mgmt(struct net_device *dev,
- u16 type_subtype, char *body,
- int body_len, u8 *addr, u16 tx_cb_idx)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
- u16 fc;
- struct sk_buff *skb;
- struct hostap_skb_tx_data *meta;
- int hdrlen;
-
- iface = netdev_priv(dev);
- local = iface->local;
- dev = local->dev; /* always use master radio device */
- iface = netdev_priv(dev);
-
- if (!(dev->flags & IFF_UP)) {
- PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - "
- "cannot send frame\n", dev->name);
- return;
- }
-
- skb = dev_alloc_skb(sizeof(*hdr) + body_len);
- if (skb == NULL) {
- PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate "
- "skb\n", dev->name);
- return;
- }
-
- fc = type_subtype;
- hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype));
- hdr = skb_put_zero(skb, hdrlen);
- if (body)
- skb_put_data(skb, body, body_len);
-
- /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11
- * tx_control instead of using local->tx_control */
-
-
- memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */
- if (ieee80211_is_data(hdr->frame_control)) {
- fc |= IEEE80211_FCTL_FROMDS;
- memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */
- memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */
- } else if (ieee80211_is_ctl(hdr->frame_control)) {
- /* control:ACK does not have addr2 or addr3 */
- eth_zero_addr(hdr->addr2);
- eth_zero_addr(hdr->addr3);
- } else {
- memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */
- memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */
- }
-
- hdr->frame_control = cpu_to_le16(fc);
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- meta->iface = iface;
- meta->tx_cb_idx = tx_cb_idx;
-
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb_reset_network_header(skb);
- dev_queue_xmit(skb);
-}
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-#ifdef CONFIG_PROC_FS
-static int prism2_sta_proc_show(struct seq_file *m, void *v)
-{
- struct sta_info *sta = m->private;
- int i;
-
- /* FIX: possible race condition.. the STA data could have just expired,
- * but proc entry was still here so that the read could have started;
- * some locking should be done here.. */
-
- seq_printf(m,
- "%s=%pM\nusers=%d\naid=%d\n"
- "flags=0x%04x%s%s%s%s%s%s%s\n"
- "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
- sta->ap ? "AP" : "STA",
- sta->addr, atomic_read(&sta->users), sta->aid,
- sta->flags,
- sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
- sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
- sta->flags & WLAN_STA_PS ? " PS" : "",
- sta->flags & WLAN_STA_TIM ? " TIM" : "",
- sta->flags & WLAN_STA_PERM ? " PERM" : "",
- sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
- sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
- sta->capability, sta->listen_interval);
- /* supported_rates: 500 kbit/s units with msb ignored */
- for (i = 0; i < sizeof(sta->supported_rates); i++)
- if (sta->supported_rates[i] != 0)
- seq_printf(m, "%d%sMbps ",
- (sta->supported_rates[i] & 0x7f) / 2,
- sta->supported_rates[i] & 1 ? ".5" : "");
- seq_printf(m,
- "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
- "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
- "tx_packets=%lu\n"
- "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
- "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
- "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
- "tx[11M]=%d\n"
- "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
- jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
- sta->last_tx,
- sta->rx_packets, sta->tx_packets, sta->rx_bytes,
- sta->tx_bytes, skb_queue_len(&sta->tx_buf),
- sta->last_rx_silence,
- sta->last_rx_signal, sta->last_rx_rate / 10,
- sta->last_rx_rate % 10 ? ".5" : "",
- sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
- sta->tx_count[2], sta->tx_count[3], sta->rx_count[0],
- sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
- if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats)
- sta->crypt->ops->print_stats(m, sta->crypt->priv);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (sta->ap) {
- if (sta->u.ap.channel >= 0)
- seq_printf(m, "channel=%d\n", sta->u.ap.channel);
- seq_puts(m, "ssid=");
- for (i = 0; i < sta->u.ap.ssid_len; i++) {
- if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127)
- seq_putc(m, sta->u.ap.ssid[i]);
- else
- seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);
- }
- seq_putc(m, '\n');
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- return 0;
-}
-#endif
-
-static void handle_add_proc_queue(struct work_struct *work)
-{
- struct ap_data *ap = container_of(work, struct ap_data,
- add_sta_proc_queue);
- struct sta_info *sta;
- char name[20];
- struct add_sta_proc_data *entry, *prev;
-
- entry = ap->add_sta_proc_entries;
- ap->add_sta_proc_entries = NULL;
-
- while (entry) {
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, entry->addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (sta) {
- sprintf(name, "%pM", sta->addr);
- sta->proc = proc_create_single_data(
- name, 0, ap->proc,
- prism2_sta_proc_show, sta);
-
- atomic_dec(&sta->users);
- }
-
- prev = entry;
- entry = entry->next;
- kfree(prev);
- }
-}
-
-
-static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr)
-{
- struct sta_info *sta;
-
- sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC);
- if (sta == NULL) {
- PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
- return NULL;
- }
-
- /* initialize STA info data */
- sta->local = ap->local;
- skb_queue_head_init(&sta->tx_buf);
- memcpy(sta->addr, addr, ETH_ALEN);
-
- atomic_inc(&sta->users);
- spin_lock_bh(&ap->sta_table_lock);
- list_add(&sta->list, &ap->sta_list);
- ap->num_sta++;
- ap_sta_hash_add(ap, sta);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (ap->proc) {
- struct add_sta_proc_data *entry;
- /* schedule a non-interrupt context process to add a procfs
- * entry for the STA since procfs code use GFP_KERNEL */
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry) {
- memcpy(entry->addr, sta->addr, ETH_ALEN);
- entry->next = ap->add_sta_proc_entries;
- ap->add_sta_proc_entries = entry;
- schedule_work(&ap->add_sta_proc_queue);
- } else
- printk(KERN_DEBUG "Failed to add STA proc data\n");
- }
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- timer_setup(&sta->timer, ap_handle_timer, 0);
- sta->timer.expires = jiffies + ap->max_inactivity;
- if (!ap->local->hostapd)
- add_timer(&sta->timer);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- return sta;
-}
-
-
-static int ap_tx_rate_ok(int rateidx, struct sta_info *sta,
- local_info_t *local)
-{
- if (rateidx > sta->tx_max_rate ||
- !(sta->tx_supp_rates & (1 << rateidx)))
- return 0;
-
- if (local->tx_rate_control != 0 &&
- !(local->tx_rate_control & (1 << rateidx)))
- return 0;
-
- return 1;
-}
-
-
-static void prism2_check_tx_rates(struct sta_info *sta)
-{
- int i;
-
- sta->tx_supp_rates = 0;
- for (i = 0; i < sizeof(sta->supported_rates); i++) {
- if ((sta->supported_rates[i] & 0x7f) == 2)
- sta->tx_supp_rates |= WLAN_RATE_1M;
- if ((sta->supported_rates[i] & 0x7f) == 4)
- sta->tx_supp_rates |= WLAN_RATE_2M;
- if ((sta->supported_rates[i] & 0x7f) == 11)
- sta->tx_supp_rates |= WLAN_RATE_5M5;
- if ((sta->supported_rates[i] & 0x7f) == 22)
- sta->tx_supp_rates |= WLAN_RATE_11M;
- }
- sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0;
- if (sta->tx_supp_rates & WLAN_RATE_1M) {
- sta->tx_max_rate = 0;
- if (ap_tx_rate_ok(0, sta, sta->local)) {
- sta->tx_rate = 10;
- sta->tx_rate_idx = 0;
- }
- }
- if (sta->tx_supp_rates & WLAN_RATE_2M) {
- sta->tx_max_rate = 1;
- if (ap_tx_rate_ok(1, sta, sta->local)) {
- sta->tx_rate = 20;
- sta->tx_rate_idx = 1;
- }
- }
- if (sta->tx_supp_rates & WLAN_RATE_5M5) {
- sta->tx_max_rate = 2;
- if (ap_tx_rate_ok(2, sta, sta->local)) {
- sta->tx_rate = 55;
- sta->tx_rate_idx = 2;
- }
- }
- if (sta->tx_supp_rates & WLAN_RATE_11M) {
- sta->tx_max_rate = 3;
- if (ap_tx_rate_ok(3, sta, sta->local)) {
- sta->tx_rate = 110;
- sta->tx_rate_idx = 3;
- }
- }
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static void ap_crypt_init(struct ap_data *ap)
-{
- ap->crypt = lib80211_get_crypto_ops("WEP");
-
- if (ap->crypt) {
- if (ap->crypt->init) {
- ap->crypt_priv = ap->crypt->init(0);
- if (ap->crypt_priv == NULL)
- ap->crypt = NULL;
- else {
- u8 key[WEP_KEY_LEN];
- get_random_bytes(key, WEP_KEY_LEN);
- ap->crypt->set_key(key, WEP_KEY_LEN, NULL,
- ap->crypt_priv);
- }
- }
- }
-
- if (ap->crypt == NULL) {
- printk(KERN_WARNING "AP could not initialize WEP: load module "
- "lib80211_crypt_wep.ko\n");
- }
-}
-
-
-/* Generate challenge data for shared key authentication. IEEE 802.11 specifies
- * that WEP algorithm is used for generating challenge. This should be unique,
- * but otherwise there is not really need for randomness etc. Initialize WEP
- * with pseudo random key and then use increasing IV to get unique challenge
- * streams.
- *
- * Called only as a scheduled task for pending AP frames.
- */
-static char * ap_auth_make_challenge(struct ap_data *ap)
-{
- char *tmpbuf;
- struct sk_buff *skb;
-
- if (ap->crypt == NULL) {
- ap_crypt_init(ap);
- if (ap->crypt == NULL)
- return NULL;
- }
-
- tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
- if (tmpbuf == NULL) {
- PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n");
- return NULL;
- }
-
- skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN +
- ap->crypt->extra_mpdu_prefix_len +
- ap->crypt->extra_mpdu_postfix_len);
- if (skb == NULL) {
- kfree(tmpbuf);
- return NULL;
- }
-
- skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len);
- skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN);
- if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) {
- dev_kfree_skb(skb);
- kfree(tmpbuf);
- return NULL;
- }
-
- skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len,
- tmpbuf, WLAN_AUTH_CHALLENGE_LEN);
- dev_kfree_skb(skb);
-
- return tmpbuf;
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_authen(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- size_t hdrlen;
- struct ap_data *ap = local->ap;
- char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
- int len, olen;
- u16 auth_alg, auth_transaction, status_code;
- __le16 *pos;
- u16 resp = WLAN_STATUS_SUCCESS;
- struct sta_info *sta = NULL;
- struct lib80211_crypt_data *crypt;
- char *txt = "";
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- if (len < 6) {
- PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
- "(len=%d) from %pM\n", dev->name, len, hdr->addr2);
- return;
- }
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta && sta->crypt)
- crypt = sta->crypt;
- else {
- int idx = 0;
- if (skb->len >= hdrlen + 3)
- idx = skb->data[hdrlen + 3] >> 6;
- crypt = local->crypt_info.crypt[idx];
- }
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- auth_alg = __le16_to_cpu(*pos);
- pos++;
- auth_transaction = __le16_to_cpu(*pos);
- pos++;
- status_code = __le16_to_cpu(*pos);
- pos++;
-
- if (ether_addr_equal(dev->dev_addr, hdr->addr2) ||
- ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) {
- txt = "authentication denied";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- if (((local->auth_algs & PRISM2_AUTH_OPEN) &&
- auth_alg == WLAN_AUTH_OPEN) ||
- ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) &&
- crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) {
- } else {
- txt = "unsupported algorithm";
- resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
- goto fail;
- }
-
- if (len >= 8) {
- u8 *u = (u8 *) pos;
- if (*u == WLAN_EID_CHALLENGE) {
- if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) {
- txt = "invalid challenge len";
- resp = WLAN_STATUS_CHALLENGE_FAIL;
- goto fail;
- }
- if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) {
- txt = "challenge underflow";
- resp = WLAN_STATUS_CHALLENGE_FAIL;
- goto fail;
- }
- challenge = (char *) (u + 2);
- }
- }
-
- if (sta && sta->ap) {
- if (time_after(jiffies, sta->u.ap.last_beacon +
- (10 * sta->listen_interval * HZ) / 1024)) {
- PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
- " assuming AP %pM is now STA\n",
- dev->name, sta->addr);
- sta->ap = 0;
- sta->flags = 0;
- sta->u.sta.challenge = NULL;
- } else {
- txt = "AP trying to authenticate?";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
-
- if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ||
- (auth_alg == WLAN_AUTH_SHARED_KEY &&
- (auth_transaction == 1 ||
- (auth_transaction == 3 && sta != NULL &&
- sta->u.sta.challenge != NULL)))) {
- } else {
- txt = "unknown authentication transaction number";
- resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
- goto fail;
- }
-
- if (sta == NULL) {
- txt = "new STA";
-
- if (local->ap->num_sta >= MAX_STA_COUNT) {
- /* FIX: might try to remove some old STAs first? */
- txt = "no more room for new STAs";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- sta = ap_add_sta(local->ap, hdr->addr2);
- if (sta == NULL) {
- txt = "ap_add_sta failed";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
-
- switch (auth_alg) {
- case WLAN_AUTH_OPEN:
- txt = "authOK";
- /* IEEE 802.11 standard is not completely clear about
- * whether STA is considered authenticated after
- * authentication OK frame has been send or after it
- * has been ACKed. In order to reduce interoperability
- * issues, mark the STA authenticated before ACK. */
- sta->flags |= WLAN_STA_AUTH;
- break;
-
- case WLAN_AUTH_SHARED_KEY:
- if (auth_transaction == 1) {
- if (sta->u.sta.challenge == NULL) {
- sta->u.sta.challenge =
- ap_auth_make_challenge(local->ap);
- if (sta->u.sta.challenge == NULL) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
- } else {
- if (sta->u.sta.challenge == NULL ||
- challenge == NULL ||
- memcmp(sta->u.sta.challenge, challenge,
- WLAN_AUTH_CHALLENGE_LEN) != 0 ||
- !ieee80211_has_protected(hdr->frame_control)) {
- txt = "challenge response incorrect";
- resp = WLAN_STATUS_CHALLENGE_FAIL;
- goto fail;
- }
-
- txt = "challenge OK - authOK";
- /* IEEE 802.11 standard is not completely clear about
- * whether STA is considered authenticated after
- * authentication OK frame has been send or after it
- * has been ACKed. In order to reduce interoperability
- * issues, mark the STA authenticated before ACK. */
- sta->flags |= WLAN_STA_AUTH;
- kfree(sta->u.sta.challenge);
- sta->u.sta.challenge = NULL;
- }
- break;
- }
-
- fail:
- pos = (__le16 *) body;
- *pos = cpu_to_le16(auth_alg);
- pos++;
- *pos = cpu_to_le16(auth_transaction + 1);
- pos++;
- *pos = cpu_to_le16(resp); /* status_code */
- pos++;
- olen = 6;
-
- if (resp == WLAN_STATUS_SUCCESS && sta != NULL &&
- sta->u.sta.challenge != NULL &&
- auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) {
- u8 *tmp = (u8 *) pos;
- *tmp++ = WLAN_EID_CHALLENGE;
- *tmp++ = WLAN_AUTH_CHALLENGE_LEN;
- pos++;
- memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN);
- olen += 2 + WLAN_AUTH_CHALLENGE_LEN;
- }
-
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH,
- body, olen, hdr->addr2, ap->tx_callback_auth);
-
- if (sta) {
- sta->last_rx = jiffies;
- atomic_dec(&sta->users);
- }
-
- if (resp) {
- PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d "
- "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
- dev->name, hdr->addr2,
- auth_alg, auth_transaction, status_code, len,
- le16_to_cpu(hdr->frame_control), resp, txt);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_assoc(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, int reassoc)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char body[12], *p, *lpos;
- int len, left;
- __le16 *pos;
- u16 resp = WLAN_STATUS_SUCCESS;
- struct sta_info *sta = NULL;
- int send_deauth = 0;
- char __always_unused *txt = "";
- u8 prev_ap[ETH_ALEN];
-
- left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < (reassoc ? 10 : 4)) {
- PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
- "(len=%d, reassoc=%d) from %pM\n",
- dev->name, len, reassoc, hdr->addr2);
- return;
- }
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
- spin_unlock_bh(&local->ap->sta_table_lock);
- txt = "trying to associate before authentication";
- send_deauth = 1;
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- sta = NULL; /* do not decrement sta->users */
- goto fail;
- }
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- sta->capability = __le16_to_cpu(*pos);
- pos++; left -= 2;
- sta->listen_interval = __le16_to_cpu(*pos);
- pos++; left -= 2;
-
- if (reassoc) {
- memcpy(prev_ap, pos, ETH_ALEN);
- pos++; pos++; pos++; left -= 6;
- } else
- eth_zero_addr(prev_ap);
-
- if (left >= 2) {
- unsigned int ileft;
- unsigned char *u = (unsigned char *) pos;
-
- if (*u == WLAN_EID_SSID) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft > MAX_SSID_LEN) {
- txt = "SSID overflow";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- if (ileft != strlen(local->essid) ||
- memcmp(local->essid, u, ileft) != 0) {
- txt = "not our SSID";
- resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
- goto fail;
- }
-
- u += ileft;
- left -= ileft;
- }
-
- if (left >= 2 && *u == WLAN_EID_SUPP_RATES) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft == 0 ||
- ileft > WLAN_SUPP_RATES_MAX) {
- txt = "SUPP_RATES len error";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- memset(sta->supported_rates, 0,
- sizeof(sta->supported_rates));
- memcpy(sta->supported_rates, u, ileft);
- prism2_check_tx_rates(sta);
-
- u += ileft;
- left -= ileft;
- }
-
- if (left > 0) {
- PDEBUG(DEBUG_AP, "%s: assoc from %pM"
- " with extra data (%d bytes) [",
- dev->name, hdr->addr2, left);
- while (left > 0) {
- PDEBUG2(DEBUG_AP, "<%02x>", *u);
- u++; left--;
- }
- PDEBUG2(DEBUG_AP, "]\n");
- }
- } else {
- txt = "frame underflow";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- /* get a unique AID */
- if (sta->aid > 0)
- txt = "OK, old AID";
- else {
- spin_lock_bh(&local->ap->sta_table_lock);
- for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
- if (local->ap->sta_aid[sta->aid - 1] == NULL)
- break;
- if (sta->aid > MAX_AID_TABLE_SIZE) {
- sta->aid = 0;
- spin_unlock_bh(&local->ap->sta_table_lock);
- resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
- txt = "no room for more AIDs";
- } else {
- local->ap->sta_aid[sta->aid - 1] = sta;
- spin_unlock_bh(&local->ap->sta_table_lock);
- txt = "OK, new AID";
- }
- }
-
- fail:
- pos = (__le16 *) body;
-
- if (send_deauth) {
- *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
- pos++;
- } else {
- /* FIX: CF-Pollable and CF-PollReq should be set to match the
- * values in beacons/probe responses */
- /* FIX: how about privacy and WEP? */
- /* capability */
- *pos = cpu_to_le16(WLAN_CAPABILITY_ESS);
- pos++;
-
- /* status_code */
- *pos = cpu_to_le16(resp);
- pos++;
-
- *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
- BIT(14) | BIT(15)); /* AID */
- pos++;
-
- /* Supported rates (Information element) */
- p = (char *) pos;
- *p++ = WLAN_EID_SUPP_RATES;
- lpos = p;
- *p++ = 0; /* len */
- if (local->tx_rate_control & WLAN_RATE_1M) {
- *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02;
- (*lpos)++;
- }
- if (local->tx_rate_control & WLAN_RATE_2M) {
- *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04;
- (*lpos)++;
- }
- if (local->tx_rate_control & WLAN_RATE_5M5) {
- *p++ = local->basic_rates & WLAN_RATE_5M5 ?
- 0x8b : 0x0b;
- (*lpos)++;
- }
- if (local->tx_rate_control & WLAN_RATE_11M) {
- *p++ = local->basic_rates & WLAN_RATE_11M ?
- 0x96 : 0x16;
- (*lpos)++;
- }
- pos = (__le16 *) p;
- }
-
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
- (send_deauth ? IEEE80211_STYPE_DEAUTH :
- (reassoc ? IEEE80211_STYPE_REASSOC_RESP :
- IEEE80211_STYPE_ASSOC_RESP)),
- body, (u8 *) pos - (u8 *) body,
- hdr->addr2,
- send_deauth ? 0 : local->ap->tx_callback_assoc);
-
- if (sta) {
- if (resp == WLAN_STATUS_SUCCESS) {
- sta->last_rx = jiffies;
- /* STA will be marked associated from TX callback, if
- * AssocResp is ACKed */
- }
- atomic_dec(&sta->users);
- }
-
-#if 0
- PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d "
- "prev_ap=%pM) => %d(%d) (%s)\n",
- dev->name,
- hdr->addr2,
- reassoc ? "re" : "", len,
- prev_ap,
- resp, send_deauth, txt);
-#endif
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_deauth(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- int len;
- u16 reason_code;
- __le16 *pos;
- struct sta_info *sta = NULL;
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < 2) {
- printk("handle_deauth - too short payload (len=%d)\n", len);
- return;
- }
-
- pos = (__le16 *) body;
- reason_code = le16_to_cpu(*pos);
-
- PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, "
- "reason_code=%d\n", dev->name, hdr->addr2,
- len, reason_code);
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta != NULL) {
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(local->dev, sta);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- }
- spin_unlock_bh(&local->ap->sta_table_lock);
- if (sta == NULL) {
- printk("%s: deauthentication from %pM, "
- "reason_code=%d, but STA not authenticated\n", dev->name,
- hdr->addr2, reason_code);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
- int len;
- u16 reason_code;
- __le16 *pos;
- struct sta_info *sta = NULL;
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < 2) {
- printk("handle_disassoc - too short payload (len=%d)\n", len);
- return;
- }
-
- pos = (__le16 *) body;
- reason_code = le16_to_cpu(*pos);
-
- PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, "
- "reason_code=%d\n", dev->name, hdr->addr2,
- len, reason_code);
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta != NULL) {
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(local->dev, sta);
- sta->flags &= ~WLAN_STA_ASSOC;
- }
- spin_unlock_bh(&local->ap->sta_table_lock);
- if (sta == NULL) {
- printk("%s: disassociation from %pM, "
- "reason_code=%d, but STA not authenticated\n",
- dev->name, hdr->addr2, reason_code);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void ap_handle_data_nullfunc(local_info_t *local,
- struct ieee80211_hdr *hdr)
-{
- struct net_device *dev = local->dev;
-
- /* some STA f/w's seem to require control::ACK frame for
- * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does
- * not send this..
- * send control::ACK for the data::nullfunc */
-
- printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n");
- prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK,
- NULL, 0, hdr->addr2, 0);
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void ap_handle_dropped_data(local_info_t *local,
- struct ieee80211_hdr *hdr)
-{
- struct net_device *dev = local->dev;
- struct sta_info *sta;
- __le16 reason;
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) {
- PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n");
- atomic_dec(&sta->users);
- return;
- }
-
- reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
- ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ?
- IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC),
- (char *) &reason, sizeof(reason), hdr->addr2, 0);
-
- if (sta)
- atomic_dec(&sta->users);
-}
-
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
- struct sk_buff *skb)
-{
- struct hostap_skb_tx_data *meta;
-
- if (!(sta->flags & WLAN_STA_PS)) {
- /* Station has moved to non-PS mode, so send all buffered
- * frames using normal device queue. */
- dev_queue_xmit(skb);
- return;
- }
-
- /* add a flag for hostap_handle_sta_tx() to know that this skb should
- * be passed through even though STA is using PS */
- meta = (struct hostap_skb_tx_data *) skb->cb;
- meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME;
- if (!skb_queue_empty(&sta->tx_buf)) {
- /* indicate to STA that more frames follow */
- meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA;
- }
- dev_queue_xmit(skb);
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_pspoll(local_info_t *local,
- struct ieee80211_hdr *hdr,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct sta_info *sta;
- u16 aid;
- struct sk_buff *skb;
-
- PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n",
- hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control));
-
- if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- PDEBUG(DEBUG_AP,
- "handle_pspoll - addr1(BSSID)=%pM not own MAC\n",
- hdr->addr1);
- return;
- }
-
- aid = le16_to_cpu(hdr->duration_id);
- if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) {
- PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n");
- return;
- }
- aid &= ~(BIT(15) | BIT(14));
- if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
- PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid);
- return;
- }
- PDEBUG(DEBUG_PS2, " aid=%d\n", aid);
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta == NULL) {
- PDEBUG(DEBUG_PS, " STA not found\n");
- return;
- }
- if (sta->aid != aid) {
- PDEBUG(DEBUG_PS, " received aid=%i does not match with "
- "assoc.aid=%d\n", aid, sta->aid);
- return;
- }
-
- /* FIX: todo:
- * - add timeout for buffering (clear aid in TIM vector if buffer timed
- * out (expiry time must be longer than ListenInterval for
- * the corresponding STA; "8802-11: 11.2.1.9 AP aging function"
- * - what to do, if buffered, pspolled, and sent frame is not ACKed by
- * sta; store buffer for later use and leave TIM aid bit set? use
- * TX event to check whether frame was ACKed?
- */
-
- while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) {
- /* send buffered frame .. */
- PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL"
- " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf));
-
- pspoll_send_buffered(local, sta, skb);
-
- if (sta->flags & WLAN_STA_PS) {
- /* send only one buffered packet per PS Poll */
- /* FIX: should ignore further PS Polls until the
- * buffered packet that was just sent is acknowledged
- * (Tx or TxExc event) */
- break;
- }
- }
-
- if (skb_queue_empty(&sta->tx_buf)) {
- /* try to clear aid from TIM */
- if (!(sta->flags & WLAN_STA_TIM))
- PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n",
- aid);
- hostap_set_tim(local, aid, 0);
- sta->flags &= ~WLAN_STA_TIM;
- }
-
- atomic_dec(&sta->users);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static void handle_wds_oper_queue(struct work_struct *work)
-{
- struct ap_data *ap = container_of(work, struct ap_data,
- wds_oper_queue);
- local_info_t *local = ap->local;
- struct wds_oper_data *entry, *prev;
-
- spin_lock_bh(&local->lock);
- entry = local->ap->wds_oper_entries;
- local->ap->wds_oper_entries = NULL;
- spin_unlock_bh(&local->lock);
-
- while (entry) {
- PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
- "to AP %pM\n",
- local->dev->name,
- entry->type == WDS_ADD ? "adding" : "removing",
- entry->addr);
- if (entry->type == WDS_ADD)
- prism2_wds_add(local, entry->addr, 0);
- else if (entry->type == WDS_DEL)
- prism2_wds_del(local, entry->addr, 0, 1);
-
- prev = entry;
- entry = entry->next;
- kfree(prev);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_beacon(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
- int len, left;
- u16 beacon_int, capability;
- __le16 *pos;
- char *ssid = NULL;
- unsigned char *supp_rates = NULL;
- int ssid_len = 0, supp_rates_len = 0;
- struct sta_info *sta = NULL;
- int new_sta = 0, channel = -1;
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < 8 + 2 + 2) {
- printk(KERN_DEBUG "handle_beacon - too short payload "
- "(len=%d)\n", len);
- return;
- }
-
- pos = (__le16 *) body;
- left = len;
-
- /* Timestamp (8 octets) */
- pos += 4; left -= 8;
- /* Beacon interval (2 octets) */
- beacon_int = le16_to_cpu(*pos);
- pos++; left -= 2;
- /* Capability information (2 octets) */
- capability = le16_to_cpu(*pos);
- pos++; left -= 2;
-
- if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS &&
- capability & WLAN_CAPABILITY_IBSS)
- return;
-
- if (left >= 2) {
- unsigned int ileft;
- unsigned char *u = (unsigned char *) pos;
-
- if (*u == WLAN_EID_SSID) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft > MAX_SSID_LEN) {
- PDEBUG(DEBUG_AP, "SSID: overflow\n");
- return;
- }
-
- if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID &&
- (ileft != strlen(local->essid) ||
- memcmp(local->essid, u, ileft) != 0)) {
- /* not our SSID */
- return;
- }
-
- ssid = u;
- ssid_len = ileft;
-
- u += ileft;
- left -= ileft;
- }
-
- if (*u == WLAN_EID_SUPP_RATES) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft == 0 || ileft > 8) {
- PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n");
- return;
- }
-
- supp_rates = u;
- supp_rates_len = ileft;
-
- u += ileft;
- left -= ileft;
- }
-
- if (*u == WLAN_EID_DS_PARAMS) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft != 1) {
- PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n");
- return;
- }
-
- channel = *u;
-
- u += ileft;
- left -= ileft;
- }
- }
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta != NULL)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta == NULL) {
- /* add new AP */
- new_sta = 1;
- sta = ap_add_sta(local->ap, hdr->addr2);
- if (sta == NULL) {
- printk(KERN_INFO "prism2: kmalloc failed for AP "
- "data structure\n");
- return;
- }
- hostap_event_new_sta(local->dev, sta);
-
- /* mark APs authentication and associated for pseudo ad-hoc
- * style communication */
- sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
-
- if (local->ap->autom_ap_wds) {
- hostap_wds_link_oper(local, sta->addr, WDS_ADD);
- }
- }
-
- sta->ap = 1;
- if (ssid) {
- sta->u.ap.ssid_len = ssid_len;
- memcpy(sta->u.ap.ssid, ssid, ssid_len);
- sta->u.ap.ssid[ssid_len] = '\0';
- } else {
- sta->u.ap.ssid_len = 0;
- sta->u.ap.ssid[0] = '\0';
- }
- sta->u.ap.channel = channel;
- sta->rx_packets++;
- sta->rx_bytes += len;
- sta->u.ap.last_beacon = sta->last_rx = jiffies;
- sta->capability = capability;
- sta->listen_interval = beacon_int;
-
- atomic_dec(&sta->users);
-
- if (new_sta) {
- memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- memcpy(sta->supported_rates, supp_rates, supp_rates_len);
- prism2_check_tx_rates(sta);
- }
-}
-
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-/* Called only as a tasklet. */
-static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- struct net_device *dev = local->dev;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- u16 fc, type, stype;
- struct ieee80211_hdr *hdr;
-
- /* FIX: should give skb->len to handler functions and check that the
- * buffer is long enough */
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- type = fc & IEEE80211_FCTL_FTYPE;
- stype = fc & IEEE80211_FCTL_STYPE;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (!local->hostapd && type == IEEE80211_FTYPE_DATA) {
- PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n");
-
- if (!(fc & IEEE80211_FCTL_TODS) ||
- (fc & IEEE80211_FCTL_FROMDS)) {
- if (stype == IEEE80211_STYPE_NULLFUNC) {
- /* no ToDS nullfunc seems to be used to check
- * AP association; so send reject message to
- * speed up re-association */
- ap_handle_dropped_data(local, hdr);
- goto done;
- }
- PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n",
- fc);
- goto done;
- }
-
- if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM"
- " not own MAC\n", hdr->addr1);
- goto done;
- }
-
- if (local->ap->nullfunc_ack &&
- stype == IEEE80211_STYPE_NULLFUNC)
- ap_handle_data_nullfunc(local, hdr);
- else
- ap_handle_dropped_data(local, hdr);
- goto done;
- }
-
- if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) {
- handle_beacon(local, skb, rx_stats);
- goto done;
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) {
- handle_pspoll(local, hdr, rx_stats);
- goto done;
- }
-
- if (local->hostapd) {
- PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x "
- "subtype=0x%02x\n", type, stype);
- goto done;
- }
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (type != IEEE80211_FTYPE_MGMT) {
- PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n");
- goto done;
- }
-
- if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM"
- " not own MAC\n", hdr->addr1);
- goto done;
- }
-
- if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM"
- " not own MAC\n", hdr->addr3);
- goto done;
- }
-
- switch (stype) {
- case IEEE80211_STYPE_ASSOC_REQ:
- handle_assoc(local, skb, rx_stats, 0);
- break;
- case IEEE80211_STYPE_ASSOC_RESP:
- PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n");
- break;
- case IEEE80211_STYPE_REASSOC_REQ:
- handle_assoc(local, skb, rx_stats, 1);
- break;
- case IEEE80211_STYPE_REASSOC_RESP:
- PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n");
- break;
- case IEEE80211_STYPE_ATIM:
- PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n");
- break;
- case IEEE80211_STYPE_DISASSOC:
- handle_disassoc(local, skb, rx_stats);
- break;
- case IEEE80211_STYPE_AUTH:
- handle_authen(local, skb, rx_stats);
- break;
- case IEEE80211_STYPE_DEAUTH:
- handle_deauth(local, skb, rx_stats);
- break;
- default:
- PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n",
- stype >> 4);
- break;
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- done:
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-void hostap_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (skb->len < 16)
- goto drop;
-
- dev->stats.rx_packets++;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
- ieee80211_is_beacon(hdr->frame_control))
- goto drop;
-
- skb->protocol = cpu_to_be16(ETH_P_HOSTAP);
- handle_ap_item(local, skb, rx_stats);
- return;
-
- drop:
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
-{
- struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
- struct hostap_80211_rx_status rx_stats;
-
- if (skb_queue_empty(&sta->tx_buf))
- return;
-
- skb = dev_alloc_skb(16);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc "
- "failed\n", local->dev->name);
- return;
- }
-
- hdr = skb_put(skb, 16);
-
- /* Generate a fake pspoll frame to start packet delivery */
- hdr->frame_control = cpu_to_le16(
- IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
- memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN);
- memcpy(hdr->addr2, sta->addr, ETH_ALEN);
- hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
-
- PDEBUG(DEBUG_PS2,
- "%s: Scheduling buffered packet delivery for STA %pM\n",
- local->dev->name, sta->addr);
-
- skb->dev = local->dev;
-
- memset(&rx_stats, 0, sizeof(rx_stats));
- hostap_rx(local->dev, skb, &rx_stats);
-}
-
-
-int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
- struct iw_quality qual[], int buf_size,
- int aplist)
-{
- struct ap_data *ap = local->ap;
- struct list_head *ptr;
- int count = 0;
-
- spin_lock_bh(&ap->sta_table_lock);
-
- for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
- ptr = ptr->next) {
- struct sta_info *sta = (struct sta_info *) ptr;
-
- if (aplist && !sta->ap)
- continue;
- addr[count].sa_family = ARPHRD_ETHER;
- memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
- if (sta->last_rx_silence == 0)
- qual[count].qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
- else
- qual[count].qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
- qual[count].updated = sta->last_rx_updated;
-
- sta->last_rx_updated = IW_QUAL_DBM;
-
- count++;
- if (count >= buf_size)
- break;
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- return count;
-}
-
-
-/* Translate our list of Access Points & Stations to a card independent
- * format that the Wireless Tools will understand - Jean II */
-int prism2_ap_translate_scan(struct net_device *dev,
- struct iw_request_info *info, char *buffer)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ap_data *ap;
- struct list_head *ptr;
- struct iw_event iwe;
- char *current_ev = buffer;
- char *end_buf = buffer + IW_SCAN_MAX_DATA;
-#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT)
- char buf[64];
-#endif
-
- iface = netdev_priv(dev);
- local = iface->local;
- ap = local->ap;
-
- spin_lock_bh(&ap->sta_table_lock);
-
- for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
- ptr = ptr->next) {
- struct sta_info *sta = (struct sta_info *) ptr;
-
- /* First entry *MUST* be the AP MAC address */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
- iwe.len = IW_EV_ADDR_LEN;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Use the mode to indicate if it's a station or
- * an Access Point */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWMODE;
- if (sta->ap)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_INFRA;
- iwe.len = IW_EV_UINT_LEN;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
-
- /* Some quality */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVQUAL;
- if (sta->last_rx_silence == 0)
- iwe.u.qual.qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
- else
- iwe.u.qual.qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
- iwe.u.qual.updated = sta->last_rx_updated;
- iwe.len = IW_EV_QUAL_LEN;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (sta->ap) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = sta->u.ap.ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe,
- sta->u.ap.ssid);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWENCODE;
- if (sta->capability & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags =
- IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe,
- sta->u.ap.ssid);
-
- if (sta->u.ap.channel > 0 &&
- sta->u.ap.channel <= FREQ_COUNT) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = freq_list[sta->u.ap.channel - 1]
- * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(
- info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "beacon_interval=%d",
- sta->listen_interval);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe, buf);
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- sta->last_rx_updated = IW_QUAL_DBM;
-
- /* To be continued, we should make good use of IWEVCUSTOM */
- }
-
- spin_unlock_bh(&ap->sta_table_lock);
-
- return current_ev - buffer;
-}
-
-
-static int prism2_hostapd_add_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (sta == NULL) {
- sta = ap_add_sta(ap, param->sta_addr);
- if (sta == NULL)
- return -1;
- }
-
- if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_new_sta(sta->local->dev, sta);
-
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
- sta->last_rx = jiffies;
- sta->aid = param->u.add_sta.aid;
- sta->capability = param->u.add_sta.capability;
- sta->tx_supp_rates = param->u.add_sta.tx_supp_rates;
- if (sta->tx_supp_rates & WLAN_RATE_1M)
- sta->supported_rates[0] = 2;
- if (sta->tx_supp_rates & WLAN_RATE_2M)
- sta->supported_rates[1] = 4;
- if (sta->tx_supp_rates & WLAN_RATE_5M5)
- sta->supported_rates[2] = 11;
- if (sta->tx_supp_rates & WLAN_RATE_11M)
- sta->supported_rates[3] = 22;
- prism2_check_tx_rates(sta);
- atomic_dec(&sta->users);
- return 0;
-}
-
-
-static int prism2_hostapd_remove_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta) {
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
- ap_free_sta(ap, sta);
-
- return 0;
-}
-
-
-static int prism2_hostapd_get_info_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ;
-
- atomic_dec(&sta->users);
-
- return 1;
-}
-
-
-static int prism2_hostapd_set_flags_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta) {
- sta->flags |= param->u.set_flags_sta.flags_or;
- sta->flags &= param->u.set_flags_sta.flags_and;
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- return 0;
-}
-
-
-static int prism2_hostapd_sta_clear_stats(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
- int rate;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta) {
- sta->rx_packets = sta->tx_packets = 0;
- sta->rx_bytes = sta->tx_bytes = 0;
- for (rate = 0; rate < WLAN_RATE_COUNT; rate++) {
- sta->tx_count[rate] = 0;
- sta->rx_count[rate] = 0;
- }
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- return 0;
-}
-
-
-int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param)
-{
- switch (param->cmd) {
- case PRISM2_HOSTAPD_FLUSH:
- ap_control_kickall(ap);
- return 0;
- case PRISM2_HOSTAPD_ADD_STA:
- return prism2_hostapd_add_sta(ap, param);
- case PRISM2_HOSTAPD_REMOVE_STA:
- return prism2_hostapd_remove_sta(ap, param);
- case PRISM2_HOSTAPD_GET_INFO_STA:
- return prism2_hostapd_get_info_sta(ap, param);
- case PRISM2_HOSTAPD_SET_FLAGS_STA:
- return prism2_hostapd_set_flags_sta(ap, param);
- case PRISM2_HOSTAPD_STA_CLEAR_STATS:
- return prism2_hostapd_sta_clear_stats(ap, param);
- default:
- printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n",
- param->cmd);
- return -EOPNOTSUPP;
- }
-}
-
-
-/* Update station info for host-based TX rate control and return current
- * TX rate */
-static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
-{
- int ret = sta->tx_rate;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- sta->tx_count[sta->tx_rate_idx]++;
- sta->tx_since_last_failure++;
- sta->tx_consecutive_exc = 0;
- if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT &&
- sta->tx_rate_idx < sta->tx_max_rate) {
- /* use next higher rate */
- int old_rate, new_rate;
- old_rate = new_rate = sta->tx_rate_idx;
- while (new_rate < sta->tx_max_rate) {
- new_rate++;
- if (ap_tx_rate_ok(new_rate, sta, local)) {
- sta->tx_rate_idx = new_rate;
- break;
- }
- }
- if (old_rate != sta->tx_rate_idx) {
- switch (sta->tx_rate_idx) {
- case 0: sta->tx_rate = 10; break;
- case 1: sta->tx_rate = 20; break;
- case 2: sta->tx_rate = 55; break;
- case 3: sta->tx_rate = 110; break;
- default: sta->tx_rate = 0; break;
- }
- PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n",
- dev->name, sta->addr, sta->tx_rate);
- }
- sta->tx_since_last_failure = 0;
- }
-
- return ret;
-}
-
-
-/* Called only from software IRQ. Called for each TX frame prior possible
- * encryption and transmit. */
-ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
-{
- struct sta_info *sta = NULL;
- struct sk_buff *skb = tx->skb;
- int set_tim, ret;
- struct ieee80211_hdr *hdr;
- struct hostap_skb_tx_data *meta;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- ret = AP_TX_CONTINUE;
- if (local->ap == NULL || skb->len < 10 ||
- meta->iface->type == HOSTAP_INTERFACE_STA)
- goto out;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- if (hdr->addr1[0] & 0x01) {
- /* broadcast/multicast frame - no AP related processing */
- if (local->ap->num_sta <= 0)
- ret = AP_TX_DROP;
- goto out;
- }
-
- /* unicast packet - check whether destination STA is associated */
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr1);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (local->iw_mode == IW_MODE_MASTER && sta == NULL &&
- !(meta->flags & HOSTAP_TX_FLAGS_WDS) &&
- meta->iface->type != HOSTAP_INTERFACE_MASTER &&
- meta->iface->type != HOSTAP_INTERFACE_AP) {
-#if 0
- /* This can happen, e.g., when wlan0 is added to a bridge and
- * bridging code does not know which port is the correct target
- * for a unicast frame. In this case, the packet is send to all
- * ports of the bridge. Since this is a valid scenario, do not
- * print out any errors here. */
- if (net_ratelimit()) {
- printk(KERN_DEBUG "AP: drop packet to non-associated "
- "STA %pM\n", hdr->addr1);
- }
-#endif
- local->ap->tx_drop_nonassoc++;
- ret = AP_TX_DROP;
- goto out;
- }
-
- if (sta == NULL)
- goto out;
-
- if (!(sta->flags & WLAN_STA_AUTHORIZED))
- ret = AP_TX_CONTINUE_NOT_AUTHORIZED;
-
- /* Set tx_rate if using host-based TX rate control */
- if (!local->fw_tx_rate_control)
- local->ap->last_tx_rate = meta->rate =
- ap_update_sta_tx_rate(sta, local->dev);
-
- if (local->iw_mode != IW_MODE_MASTER)
- goto out;
-
- if (!(sta->flags & WLAN_STA_PS))
- goto out;
-
- if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) {
- /* indicate to STA that more frames follow */
- hdr->frame_control |=
- cpu_to_le16(IEEE80211_FCTL_MOREDATA);
- }
-
- if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) {
- /* packet was already buffered and now send due to
- * PS poll, so do not rebuffer it */
- goto out;
- }
-
- if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
- PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s"
- "PS mode buffer\n",
- local->dev->name, sta->addr);
- /* Make sure that TIM is set for the station (it might not be
- * after AP wlan hw reset). */
- /* FIX: should fix hw reset to restore bits based on STA
- * buffer state.. */
- hostap_set_tim(local, sta->aid, 1);
- sta->flags |= WLAN_STA_TIM;
- ret = AP_TX_DROP;
- goto out;
- }
-
- /* STA in PS mode, buffer frame for later delivery */
- set_tim = skb_queue_empty(&sta->tx_buf);
- skb_queue_tail(&sta->tx_buf, skb);
- /* FIX: could save RX time to skb and expire buffered frames after
- * some time if STA does not poll for them */
-
- if (set_tim) {
- if (sta->flags & WLAN_STA_TIM)
- PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n",
- sta->aid);
- hostap_set_tim(local, sta->aid, 1);
- sta->flags |= WLAN_STA_TIM;
- }
-
- ret = AP_TX_BUFFERED;
-
- out:
- if (sta != NULL) {
- if (ret == AP_TX_CONTINUE ||
- ret == AP_TX_CONTINUE_NOT_AUTHORIZED) {
- sta->tx_packets++;
- sta->tx_bytes += skb->len;
- sta->last_tx = jiffies;
- }
-
- if ((ret == AP_TX_CONTINUE ||
- ret == AP_TX_CONTINUE_NOT_AUTHORIZED) &&
- sta->crypt && tx->host_encrypt) {
- tx->crypt = sta->crypt;
- tx->sta_ptr = sta; /* hostap_handle_sta_release() will
- * be called to release sta info
- * later */
- } else
- atomic_dec(&sta->users);
- }
-
- return ret;
-}
-
-
-void hostap_handle_sta_release(void *ptr)
-{
- struct sta_info *sta = ptr;
- atomic_dec(&sta->users);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
-{
- struct sta_info *sta;
- struct ieee80211_hdr *hdr;
- struct hostap_skb_tx_data *meta;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- meta = (struct hostap_skb_tx_data *) skb->cb;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr1);
- if (!sta) {
- spin_unlock(&local->ap->sta_table_lock);
- PDEBUG(DEBUG_AP, "%s: Could not find STA %pM"
- " for this TX error (@%lu)\n",
- local->dev->name, hdr->addr1, jiffies);
- return;
- }
-
- sta->tx_since_last_failure = 0;
- sta->tx_consecutive_exc++;
-
- if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD &&
- sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) {
- /* use next lower rate */
- int old, rate;
- old = rate = sta->tx_rate_idx;
- while (rate > 0) {
- rate--;
- if (ap_tx_rate_ok(rate, sta, local)) {
- sta->tx_rate_idx = rate;
- break;
- }
- }
- if (old != sta->tx_rate_idx) {
- switch (sta->tx_rate_idx) {
- case 0: sta->tx_rate = 10; break;
- case 1: sta->tx_rate = 20; break;
- case 2: sta->tx_rate = 55; break;
- case 3: sta->tx_rate = 110; break;
- default: sta->tx_rate = 0; break;
- }
- PDEBUG(DEBUG_AP,
- "%s: STA %pM TX rate lowered to %d\n",
- local->dev->name, sta->addr, sta->tx_rate);
- }
- sta->tx_consecutive_exc = 0;
- }
- spin_unlock(&local->ap->sta_table_lock);
-}
-
-
-static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
- int pwrmgt, int type, int stype)
-{
- if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
- sta->flags |= WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA %pM changed to use PS "
- "mode (type=0x%02X, stype=0x%02X)\n",
- sta->addr, type >> 2, stype >> 4);
- } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
- sta->flags &= ~WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA %pM changed to not use "
- "PS mode (type=0x%02X, stype=0x%02X)\n",
- sta->addr, type >> 2, stype >> 4);
- if (type != IEEE80211_FTYPE_CTL ||
- stype != IEEE80211_STYPE_PSPOLL)
- schedule_packet_send(local, sta);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ). Called for each RX frame to update
- * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr)
-{
- struct sta_info *sta;
- u16 fc;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (!sta)
- return -1;
-
- fc = le16_to_cpu(hdr->frame_control);
- hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
- fc & IEEE80211_FCTL_FTYPE,
- fc & IEEE80211_FCTL_STYPE);
-
- atomic_dec(&sta->users);
- return 0;
-}
-
-
-/* Called only as a tasklet (software IRQ). Called for each RX frame after
- * getting RX header and payload from hardware. */
-ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
- struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats,
- int wds)
-{
- int ret;
- struct sta_info *sta;
- u16 fc, type, stype;
- struct ieee80211_hdr *hdr;
-
- if (local->ap == NULL)
- return AP_RX_CONTINUE;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- fc = le16_to_cpu(hdr->frame_control);
- type = fc & IEEE80211_FCTL_FTYPE;
- stype = fc & IEEE80211_FCTL_STYPE;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (sta && !(sta->flags & WLAN_STA_AUTHORIZED))
- ret = AP_RX_CONTINUE_NOT_AUTHORIZED;
- else
- ret = AP_RX_CONTINUE;
-
-
- if (fc & IEEE80211_FCTL_TODS) {
- if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
- if (local->hostapd) {
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_NON_ASSOC);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- } else {
- printk(KERN_DEBUG "%s: dropped received packet"
- " from non-associated STA %pM"
- " (type=0x%02x, subtype=0x%02x)\n",
- dev->name, hdr->addr2,
- type >> 2, stype >> 4);
- hostap_rx(dev, skb, rx_stats);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- }
- ret = AP_RX_EXIT;
- goto out;
- }
- } else if (fc & IEEE80211_FCTL_FROMDS) {
- if (!wds) {
- /* FromDS frame - not for us; probably
- * broadcast/multicast in another BSS - drop */
- if (ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- printk(KERN_DEBUG "Odd.. FromDS packet "
- "received with own BSSID\n");
- hostap_dump_rx_80211(dev->name, skb, rx_stats);
- }
- ret = AP_RX_DROP;
- goto out;
- }
- } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
-
- if (local->hostapd) {
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_NON_ASSOC);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- } else {
- /* At least Lucent f/w seems to send data::nullfunc
- * frames with no ToDS flag when the current AP returns
- * after being unavailable for some time. Speed up
- * re-association by informing the station about it not
- * being associated. */
- printk(KERN_DEBUG "%s: rejected received nullfunc frame"
- " without ToDS from not associated STA %pM\n",
- dev->name, hdr->addr2);
- hostap_rx(dev, skb, rx_stats);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- }
- ret = AP_RX_EXIT;
- goto out;
- } else if (stype == IEEE80211_STYPE_NULLFUNC) {
- /* At least Lucent cards seem to send periodic nullfunc
- * frames with ToDS. Let these through to update SQ
- * stats and PS state. Nullfunc frames do not contain
- * any data and they will be dropped below. */
- } else {
- /* If BSSID (Addr3) is foreign, this frame is a normal
- * broadcast frame from an IBSS network. Drop it silently.
- * If BSSID is own, report the dropping of this frame. */
- if (ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- printk(KERN_DEBUG "%s: dropped received packet from %pM"
- " with no ToDS flag "
- "(type=0x%02x, subtype=0x%02x)\n", dev->name,
- hdr->addr2, type >> 2, stype >> 4);
- hostap_dump_rx_80211(dev->name, skb, rx_stats);
- }
- ret = AP_RX_DROP;
- goto out;
- }
-
- if (sta) {
- hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
- type, stype);
-
- sta->rx_packets++;
- sta->rx_bytes += skb->len;
- sta->last_rx = jiffies;
- }
-
- if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC &&
- fc & IEEE80211_FCTL_TODS) {
- if (local->hostapd) {
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_NULLFUNC_ACK);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- } else {
- /* some STA f/w's seem to require control::ACK frame
- * for data::nullfunc, but Prism2 f/w 0.8.0 (at least
- * from Compaq) does not send this.. Try to generate
- * ACK for these frames from the host driver to make
- * power saving work with, e.g., Lucent WaveLAN f/w */
- hostap_rx(dev, skb, rx_stats);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- }
- ret = AP_RX_EXIT;
- goto out;
- }
-
- out:
- if (sta)
- atomic_dec(&sta->users);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_handle_sta_crypto(local_info_t *local,
- struct ieee80211_hdr *hdr,
- struct lib80211_crypt_data **crypt,
- void **sta_ptr)
-{
- struct sta_info *sta;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (!sta)
- return -1;
-
- if (sta->crypt) {
- *crypt = sta->crypt;
- *sta_ptr = sta;
- /* hostap_handle_sta_release() will be called to release STA
- * info */
- } else
- atomic_dec(&sta->users);
-
- return 0;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr)
-{
- struct sta_info *sta;
- int ret = 0;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, sta_addr);
- if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- ret = 1;
- spin_unlock(&ap->sta_table_lock);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr)
-{
- struct sta_info *sta;
- int ret = 0;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, sta_addr);
- if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap &&
- ((sta->flags & WLAN_STA_AUTHORIZED) ||
- ap->local->ieee_802_1x == 0))
- ret = 1;
- spin_unlock(&ap->sta_table_lock);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
-{
- struct sta_info *sta;
- int ret = 1;
-
- if (!ap)
- return -1;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, sta_addr);
- if (sta)
- ret = 0;
- spin_unlock(&ap->sta_table_lock);
-
- if (ret == 1) {
- sta = ap_add_sta(ap, sta_addr);
- if (!sta)
- return -1;
- sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
- sta->ap = 1;
- memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- /* No way of knowing which rates are supported since we did not
- * get supported rates element from beacon/assoc req. Assume
- * that remote end supports all 802.11b rates. */
- sta->supported_rates[0] = 0x82;
- sta->supported_rates[1] = 0x84;
- sta->supported_rates[2] = 0x0b;
- sta->supported_rates[3] = 0x16;
- sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M |
- WLAN_RATE_5M5 | WLAN_RATE_11M;
- sta->tx_rate = 110;
- sta->tx_max_rate = sta->tx_rate_idx = 3;
- }
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_update_rx_stats(struct ap_data *ap,
- struct ieee80211_hdr *hdr,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct sta_info *sta;
-
- if (!ap)
- return -1;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr2);
- if (sta) {
- sta->last_rx_silence = rx_stats->noise;
- sta->last_rx_signal = rx_stats->signal;
- sta->last_rx_rate = rx_stats->rate;
- sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- if (rx_stats->rate == 10)
- sta->rx_count[0]++;
- else if (rx_stats->rate == 20)
- sta->rx_count[1]++;
- else if (rx_stats->rate == 55)
- sta->rx_count[2]++;
- else if (rx_stats->rate == 110)
- sta->rx_count[3]++;
- }
- spin_unlock(&ap->sta_table_lock);
-
- return sta ? 0 : -1;
-}
-
-
-void hostap_update_rates(local_info_t *local)
-{
- struct sta_info *sta;
- struct ap_data *ap = local->ap;
-
- if (!ap)
- return;
-
- spin_lock_bh(&ap->sta_table_lock);
- list_for_each_entry(sta, &ap->sta_list, list) {
- prism2_check_tx_rates(sta);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-}
-
-
-void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
- struct lib80211_crypt_data ***crypt)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta && permanent)
- sta = ap_add_sta(ap, addr);
-
- if (!sta)
- return NULL;
-
- if (permanent)
- sta->flags |= WLAN_STA_PERM;
-
- *crypt = &sta->crypt;
-
- return sta;
-}
-
-
-void hostap_add_wds_links(local_info_t *local)
-{
- struct ap_data *ap = local->ap;
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- list_for_each_entry(sta, &ap->sta_list, list) {
- if (sta->ap)
- hostap_wds_link_oper(local, sta->addr, WDS_ADD);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- schedule_work(&local->ap->wds_oper_queue);
-}
-
-
-void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type)
-{
- struct wds_oper_data *entry;
-
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry)
- return;
- memcpy(entry->addr, addr, ETH_ALEN);
- entry->type = type;
- spin_lock_bh(&local->lock);
- entry->next = local->ap->wds_oper_entries;
- local->ap->wds_oper_entries = entry;
- spin_unlock_bh(&local->lock);
-
- schedule_work(&local->ap->wds_oper_queue);
-}
-
-
-EXPORT_SYMBOL(hostap_init_data);
-EXPORT_SYMBOL(hostap_init_ap_proc);
-EXPORT_SYMBOL(hostap_free_data);
-EXPORT_SYMBOL(hostap_check_sta_fw_version);
-EXPORT_SYMBOL(hostap_handle_sta_tx_exc);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.h b/drivers/net/wireless/intersil/hostap/hostap_ap.h
deleted file mode 100644
index b7ac9e2f1a39..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_ap.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_AP_H
-#define HOSTAP_AP_H
-
-#include "hostap_80211.h"
-
-/* AP data structures for STAs */
-
-/* maximum number of frames to buffer per STA */
-#define STA_MAX_TX_BUFFER 32
-
-/* STA flags */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
-#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
-#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
- * controlling whether STA is authorized to
- * send and receive non-IEEE 802.1X frames
- */
-#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
-
-#define WLAN_RATE_1M BIT(0)
-#define WLAN_RATE_2M BIT(1)
-#define WLAN_RATE_5M5 BIT(2)
-#define WLAN_RATE_11M BIT(3)
-#define WLAN_RATE_COUNT 4
-
-/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
- * but some pre-standard IEEE 802.11g products use longer elements. */
-#define WLAN_SUPP_RATES_MAX 32
-
-/* Try to increase TX rate after # successfully sent consecutive packets */
-#define WLAN_RATE_UPDATE_COUNT 50
-
-/* Decrease TX rate after # consecutive dropped packets */
-#define WLAN_RATE_DECREASE_THRESHOLD 2
-
-struct sta_info {
- struct list_head list;
- struct sta_info *hnext; /* next entry in hash table list */
- atomic_t users; /* number of users (do not remove if > 0) */
- struct proc_dir_entry *proc;
-
- u8 addr[6];
- u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
- u32 flags;
- u16 capability;
- u16 listen_interval; /* or beacon_int for APs */
- u8 supported_rates[WLAN_SUPP_RATES_MAX];
-
- unsigned long last_auth;
- unsigned long last_assoc;
- unsigned long last_rx;
- unsigned long last_tx;
- unsigned long rx_packets, tx_packets;
- unsigned long rx_bytes, tx_bytes;
- struct sk_buff_head tx_buf;
- /* FIX: timeout buffers with an expiry time somehow derived from
- * listen_interval */
-
- s8 last_rx_silence; /* Noise in dBm */
- s8 last_rx_signal; /* Signal strength in dBm */
- u8 last_rx_rate; /* TX rate in 0.1 Mbps */
- u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */
-
- u8 tx_supp_rates; /* bit field of supported TX rates */
- u8 tx_rate; /* current TX rate (in 0.1 Mbps) */
- u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */
- u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */
- u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */
- u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
- */
- u32 tx_since_last_failure;
- u32 tx_consecutive_exc;
-
- struct lib80211_crypt_data *crypt;
-
- int ap; /* whether this station is an AP */
-
- local_info_t *local;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- union {
- struct {
- char *challenge; /* shared key authentication
- * challenge */
- } sta;
- struct {
- int ssid_len;
- unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */
- int channel;
- unsigned long last_beacon; /* last RX beacon time */
- } ap;
- } u;
-
- struct timer_list timer;
- enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-};
-
-
-#define MAX_STA_COUNT 1024
-
-/* Maximum number of AIDs to use for STAs; must be 2007 or lower
- * (8802.11 limitation) */
-#define MAX_AID_TABLE_SIZE 128
-
-#define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
-
-
-/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC
- * has passed since last received frame from the station, a nullfunc data
- * frame is sent to the station. If this frame is not acknowledged and no other
- * frames have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after
- * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
- * max inactivity timer. */
-#define AP_MAX_INACTIVITY_SEC (5 * 60)
-#define AP_DISASSOC_DELAY (HZ)
-#define AP_DEAUTH_DELAY (HZ)
-
-/* ap_policy: whether to accept frames to/from other APs/IBSS */
-typedef enum {
- AP_OTHER_AP_SKIP_ALL = 0,
- AP_OTHER_AP_SAME_SSID = 1,
- AP_OTHER_AP_ALL = 2,
- AP_OTHER_AP_EVEN_IBSS = 3
-} ap_policy_enum;
-
-#define PRISM2_AUTH_OPEN BIT(0)
-#define PRISM2_AUTH_SHARED_KEY BIT(1)
-
-
-/* MAC address-based restrictions */
-struct mac_entry {
- struct list_head list;
- u8 addr[6];
-};
-
-struct mac_restrictions {
- enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy;
- unsigned int entries;
- struct list_head mac_list;
- spinlock_t lock;
-};
-
-
-struct add_sta_proc_data {
- u8 addr[ETH_ALEN];
- struct add_sta_proc_data *next;
-};
-
-
-typedef enum { WDS_ADD, WDS_DEL } wds_oper_type;
-struct wds_oper_data {
- wds_oper_type type;
- u8 addr[ETH_ALEN];
- struct wds_oper_data *next;
-};
-
-
-struct ap_data {
- int initialized; /* whether ap_data has been initialized */
- local_info_t *local;
- int bridge_packets; /* send packet to associated STAs directly to the
- * wireless media instead of higher layers in the
- * kernel */
- unsigned int bridged_unicast; /* number of unicast frames bridged on
- * wireless media */
- unsigned int bridged_multicast; /* number of non-unicast frames
- * bridged on wireless media */
- unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped
- * because they were to an address that
- * was not associated */
- int nullfunc_ack; /* use workaround for nullfunc frame ACKs */
-
- spinlock_t sta_table_lock;
- int num_sta; /* number of entries in sta_list */
- struct list_head sta_list; /* STA info list head */
- struct sta_info *sta_hash[STA_HASH_SIZE];
-
- struct proc_dir_entry *proc;
-
- ap_policy_enum ap_policy;
- unsigned int max_inactivity;
- int autom_ap_wds;
-
- struct mac_restrictions mac_restrictions; /* MAC-based auth */
- int last_tx_rate;
-
- struct work_struct add_sta_proc_queue;
- struct add_sta_proc_data *add_sta_proc_entries;
-
- struct work_struct wds_oper_queue;
- struct wds_oper_data *wds_oper_entries;
-
- u16 tx_callback_idx;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- /* pointers to STA info; based on allocated AID or NULL if AID free
- * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
- * and so on
- */
- struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
-
- u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
-
- /* WEP operations for generating challenges to be used with shared key
- * authentication */
- struct lib80211_crypto_ops *crypt;
- void *crypt_priv;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-};
-
-
-void hostap_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats);
-void hostap_init_data(local_info_t *local);
-void hostap_init_ap_proc(local_info_t *local);
-void hostap_free_data(struct ap_data *ap);
-void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver);
-
-typedef enum {
- AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED,
- AP_TX_CONTINUE_NOT_AUTHORIZED
-} ap_tx_ret;
-struct hostap_tx_data {
- struct sk_buff *skb;
- int host_encrypt;
- struct lib80211_crypt_data *crypt;
- void *sta_ptr;
-};
-ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
-void hostap_handle_sta_release(void *ptr);
-void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
-typedef enum {
- AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
-} ap_rx_ret;
-ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
- struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats,
- int wds);
-int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
- struct lib80211_crypt_data **crypt,
- void **sta_ptr);
-int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
-int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
-int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
-int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
- struct hostap_80211_rx_status *rx_stats);
-void hostap_update_rates(local_info_t *local);
-void hostap_add_wds_links(local_info_t *local);
-void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
- int resend);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-#endif /* HOSTAP_AP_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_common.h b/drivers/net/wireless/intersil/hostap/hostap_common.h
deleted file mode 100644
index dd29a8e8d349..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_common.h
+++ /dev/null
@@ -1,420 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_COMMON_H
-#define HOSTAP_COMMON_H
-
-#include <linux/types.h>
-#include <linux/if_ether.h>
-
-/* IEEE 802.11 defines */
-
-/* HFA384X Configuration RIDs */
-#define HFA384X_RID_CNFPORTTYPE 0xFC00
-#define HFA384X_RID_CNFOWNMACADDR 0xFC01
-#define HFA384X_RID_CNFDESIREDSSID 0xFC02
-#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
-#define HFA384X_RID_CNFOWNSSID 0xFC04
-#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
-#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
-#define HFA384X_RID_CNFMAXDATALEN 0xFC07
-#define HFA384X_RID_CNFWDSADDRESS 0xFC08
-#define HFA384X_RID_CNFPMENABLED 0xFC09
-#define HFA384X_RID_CNFPMEPS 0xFC0A
-#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
-#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
-#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
-#define HFA384X_RID_CNFOWNNAME 0xFC0E
-#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
-#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
-#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
-#define HFA384X_RID_UNKNOWN1 0xFC20
-#define HFA384X_RID_UNKNOWN2 0xFC21
-#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
-#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
-#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
-#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
-#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
-#define HFA384X_RID_CNFWEPFLAGS 0xFC28
-#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
-#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
-#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
-#define HFA384X_RID_CNFTXCONTROL 0xFC2C
-#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
-#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
-#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
-#define HFA384X_RID_CNFMMLIFE 0xFC31
-#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
-#define HFA384X_RID_CNFBEACONINT 0xFC33
-#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
-#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
-#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
-#define HFA384X_RID_CNFTIMCTRL 0xFC40
-#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
-#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
-#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
-#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
- * write only */
-#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_GROUPADDRESSES 0xFC80
-#define HFA384X_RID_CREATEIBSS 0xFC81
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
-#define HFA384X_RID_RTSTHRESHOLD 0xFC83
-#define HFA384X_RID_TXRATECONTROL 0xFC84
-#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
-#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
-#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
-#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
-#define HFA384X_RID_CNFBASICRATES 0xFCB3
-#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
-#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
-#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
-#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
-#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
-#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
-#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
-#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
-#define HFA384X_RID_TICKTIME 0xFCE0
-#define HFA384X_RID_SCANREQUEST 0xFCE1
-#define HFA384X_RID_JOINREQUEST 0xFCE2
-#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
-#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
-#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
-
-/* HFA384X Information RIDs */
-#define HFA384X_RID_MAXLOADTIME 0xFD00
-#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
-#define HFA384X_RID_PRIID 0xFD02
-#define HFA384X_RID_PRISUPRANGE 0xFD03
-#define HFA384X_RID_CFIACTRANGES 0xFD04
-#define HFA384X_RID_NICSERNUM 0xFD0A
-#define HFA384X_RID_NICID 0xFD0B
-#define HFA384X_RID_MFISUPRANGE 0xFD0C
-#define HFA384X_RID_CFISUPRANGE 0xFD0D
-#define HFA384X_RID_CHANNELLIST 0xFD10
-#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
-#define HFA384X_RID_TEMPTYPE 0xFD12
-#define HFA384X_RID_CIS 0xFD13
-#define HFA384X_RID_STAID 0xFD20
-#define HFA384X_RID_STASUPRANGE 0xFD21
-#define HFA384X_RID_MFIACTRANGES 0xFD22
-#define HFA384X_RID_CFIACTRANGES2 0xFD23
-#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
- * only Prism2.5(?) */
-#define HFA384X_RID_PORTSTATUS 0xFD40
-#define HFA384X_RID_CURRENTSSID 0xFD41
-#define HFA384X_RID_CURRENTBSSID 0xFD42
-#define HFA384X_RID_COMMSQUALITY 0xFD43
-#define HFA384X_RID_CURRENTTXRATE 0xFD44
-#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
-#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
-#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
-#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
-#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
-#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
-#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
-#define HFA384X_RID_CFPOLLABLE 0xFD4C
-#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
-#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
-#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
-#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
-#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
-#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
-#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
-#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
-#define HFA384X_RID_PHYTYPE 0xFDC0
-#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
-#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
-#define HFA384X_RID_CCAMODE 0xFDC3
-#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
-#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
-#define HFA384X_RID_BUILDSEQ 0xFFFE
-#define HFA384X_RID_FWID 0xFFFF
-
-
-struct hfa384x_comp_ident
-{
- __le16 id;
- __le16 variant;
- __le16 major;
- __le16 minor;
-} __packed;
-
-#define HFA384X_COMP_ID_PRI 0x15
-#define HFA384X_COMP_ID_STA 0x1f
-#define HFA384X_COMP_ID_FW_AP 0x14b
-
-struct hfa384x_sup_range
-{
- __le16 role;
- __le16 id;
- __le16 variant;
- __le16 bottom;
- __le16 top;
-} __packed;
-
-
-struct hfa384x_build_id
-{
- __le16 pri_seq;
- __le16 sec_seq;
-} __packed;
-
-/* FD01 - Download Buffer */
-struct hfa384x_rid_download_buffer
-{
- __le16 page;
- __le16 offset;
- __le16 length;
-} __packed;
-
-/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
-struct hfa384x_comms_quality {
- __le16 comm_qual; /* 0 .. 92 */
- __le16 signal_level; /* 27 .. 154 */
- __le16 noise_level; /* 27 .. 154 */
-} __packed;
-
-
-/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
-
-/* New wireless extensions API - SET/GET convention (even ioctl numbers are
- * root only)
- */
-#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
-#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
-#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
-#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
-#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
-#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
-#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
-#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
-#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
-#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
-#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
-#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
-#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
-#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
-
-/* following are not in SIOCGIWPRIV list; check permission in the driver code
- */
-#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
-#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
-
-
-/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
-enum {
- /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
- PRISM2_PARAM_TXRATECTRL = 2,
- PRISM2_PARAM_BEACON_INT = 3,
- PRISM2_PARAM_PSEUDO_IBSS = 4,
- PRISM2_PARAM_ALC = 5,
- /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
- PRISM2_PARAM_DUMP = 7,
- PRISM2_PARAM_OTHER_AP_POLICY = 8,
- PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
- PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
- PRISM2_PARAM_DTIM_PERIOD = 11,
- PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
- PRISM2_PARAM_MAX_WDS = 13,
- PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
- PRISM2_PARAM_AP_AUTH_ALGS = 15,
- PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
- PRISM2_PARAM_HOST_ENCRYPT = 17,
- PRISM2_PARAM_HOST_DECRYPT = 18,
- /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */
- /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */
- PRISM2_PARAM_HOST_ROAMING = 21,
- PRISM2_PARAM_BCRX_STA_KEY = 22,
- PRISM2_PARAM_IEEE_802_1X = 23,
- PRISM2_PARAM_ANTSEL_TX = 24,
- PRISM2_PARAM_ANTSEL_RX = 25,
- PRISM2_PARAM_MONITOR_TYPE = 26,
- PRISM2_PARAM_WDS_TYPE = 27,
- PRISM2_PARAM_HOSTSCAN = 28,
- PRISM2_PARAM_AP_SCAN = 29,
- PRISM2_PARAM_ENH_SEC = 30,
- PRISM2_PARAM_IO_DEBUG = 31,
- PRISM2_PARAM_BASIC_RATES = 32,
- PRISM2_PARAM_OPER_RATES = 33,
- PRISM2_PARAM_HOSTAPD = 34,
- PRISM2_PARAM_HOSTAPD_STA = 35,
- PRISM2_PARAM_WPA = 36,
- PRISM2_PARAM_PRIVACY_INVOKED = 37,
- PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
- PRISM2_PARAM_DROP_UNENCRYPTED = 39,
- PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
-};
-
-enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
- HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
-
-
-/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
-enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
- AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
- AP_MAC_CMD_KICKALL = 4 };
-
-
-/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
-enum {
- PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
- /* Note! Old versions of prism2_srec have a fatal error in CRC-16
- * calculation, which will corrupt all non-volatile downloads.
- * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
- * prevent use of old versions of prism2_srec for non-volatile
- * download. */
- PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
- PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
- /* Persistent versions of volatile download commands (keep firmware
- * data in memory and automatically re-download after hw_reset */
- PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
- PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
-};
-
-struct prism2_download_param {
- u32 dl_cmd;
- u32 start_addr;
- u32 num_areas;
- struct prism2_download_area {
- u32 addr; /* wlan card address */
- u32 len;
- void __user *ptr; /* pointer to data in user space */
- } data[];
-};
-
-#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
-#define PRISM2_MAX_DOWNLOAD_LEN 262144
-
-
-/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
-enum {
- PRISM2_HOSTAPD_FLUSH = 1,
- PRISM2_HOSTAPD_ADD_STA = 2,
- PRISM2_HOSTAPD_REMOVE_STA = 3,
- PRISM2_HOSTAPD_GET_INFO_STA = 4,
- /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
- PRISM2_SET_ENCRYPTION = 6,
- PRISM2_GET_ENCRYPTION = 7,
- PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
- PRISM2_HOSTAPD_GET_RID = 9,
- PRISM2_HOSTAPD_SET_RID = 10,
- PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
- PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
- PRISM2_HOSTAPD_MLME = 13,
- PRISM2_HOSTAPD_SCAN_REQ = 14,
- PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
-};
-
-#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
-#define PRISM2_HOSTAPD_RID_HDR_LEN \
-offsetof(struct prism2_hostapd_param, u.rid.data)
-#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-offsetof(struct prism2_hostapd_param, u.generic_elem.data)
-
-/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
- */
-#define HOSTAP_CRYPT_ALG_NAME_LEN 16
-
-
-struct prism2_hostapd_param {
- u32 cmd;
- u8 sta_addr[ETH_ALEN];
- union {
- struct {
- u16 aid;
- u16 capability;
- u8 tx_supp_rates;
- } add_sta;
- struct {
- u32 inactive_sec;
- } get_info_sta;
- struct {
- u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
- u32 flags;
- u32 err;
- u8 idx;
- u8 seq[8]; /* sequence counter (set: RX, get: TX) */
- u16 key_len;
- u8 key[0];
- } crypt;
- struct {
- u32 flags_and;
- u32 flags_or;
- } set_flags_sta;
- struct {
- u16 rid;
- u16 len;
- u8 data[0];
- } rid;
- struct {
- u8 len;
- u8 data[0];
- } generic_elem;
- struct {
-#define MLME_STA_DEAUTH 0
-#define MLME_STA_DISASSOC 1
- u16 cmd;
- u16 reason_code;
- } mlme;
- struct {
- u8 ssid_len;
- u8 ssid[32];
- } scan_req;
- } u;
-};
-
-#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
-#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
-
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
-#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
-#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
-#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
-#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
-
-
-#endif /* HOSTAP_COMMON_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_config.h b/drivers/net/wireless/intersil/hostap/hostap_config.h
deleted file mode 100644
index 3ebd55847fad..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_config.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_CONFIG_H
-#define HOSTAP_CONFIG_H
-
-/* In the previous versions of Host AP driver, support for user space version
- * of IEEE 802.11 management (hostapd) used to be disabled in the default
- * configuration. From now on, support for hostapd is always included and it is
- * possible to disable kernel driver version of IEEE 802.11 management with a
- * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */
-/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-/* Maximum number of events handler per one interrupt */
-#define PRISM2_MAX_INTERRUPT_EVENTS 20
-
-/* Include code for downloading firmware images into volatile RAM. */
-#define PRISM2_DOWNLOAD_SUPPORT
-
-/* Allow kernel configuration to enable download support. */
-#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE)
-#define PRISM2_DOWNLOAD_SUPPORT
-#endif
-
-/* Allow kernel configuration to enable non-volatile download support. */
-#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM
-#define PRISM2_NON_VOLATILE_DOWNLOAD
-#endif
-
-/* Save low-level I/O for debugging. This should not be enabled in normal use.
- */
-/* #define PRISM2_IO_DEBUG */
-
-/* Following defines can be used to remove unneeded parts of the driver, e.g.,
- * to limit the size of the kernel module. Definitions can be added here in
- * hostap_config.h or they can be added to make command with ccflags-y,
- * e.g.,
- * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
- */
-
-/* Do not include debug messages into the driver */
-/* #define PRISM2_NO_DEBUG */
-
-/* Do not include /proc/net/prism2/wlan#/{registers,debug} */
-/* #define PRISM2_NO_PROCFS_DEBUG */
-
-/* Do not include station functionality (i.e., allow only Master (Host AP) mode
- */
-/* #define PRISM2_NO_STATION_MODES */
-
-#endif /* HOSTAP_CONFIG_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_cs.c b/drivers/net/wireless/intersil/hostap/hostap_cs.c
deleted file mode 100644
index ec7db2badc40..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_cs.c
+++ /dev/null
@@ -1,710 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define PRISM2_PCCARD
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/timer.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/workqueue.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <asm/io.h>
-
-#include "hostap_wlan.h"
-
-
-static char *dev_info = "hostap_cs";
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
- "cards (PC Card).");
-MODULE_LICENSE("GPL");
-
-
-static int ignore_cis_vcc;
-module_param(ignore_cis_vcc, int, 0444);
-MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
-
-
-/* struct local_info::hw_priv */
-struct hostap_cs_priv {
- struct pcmcia_device *link;
- int sandisk_connectplus;
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-
-static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
- outb(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u8 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- v = inb(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
- outw(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u16 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- v = inw(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
- outsw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline void hfa384x_insw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
- insw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
-#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
-
-#else /* PRISM2_IO_DEBUG */
-
-#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
-#define HFA384X_INB(a) inb(dev->base_addr + (a))
-#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
-#define HFA384X_INW(a) inw(dev->base_addr + (a))
-#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
-#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
- int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_INSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- *((char *) pos) = HFA384X_INB(d_off);
-
- return 0;
-}
-
-
-static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_OUTSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- HFA384X_OUTB(*((char *) pos), d_off);
-
- return 0;
-}
-
-
-/* FIX: This might change at some point.. */
-#include "hostap_hw.c"
-
-
-
-static void prism2_detach(struct pcmcia_device *p_dev);
-static void prism2_release(u_long arg);
-static int prism2_config(struct pcmcia_device *link);
-
-
-static int prism2_pccard_card_present(local_info_t *local)
-{
- struct hostap_cs_priv *hw_priv = local->hw_priv;
- if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link))
- return 1;
- return 0;
-}
-
-
-/*
- * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
- * Document No. 20-10-00058, January 2004
- * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
- */
-#define SANDISK_WLAN_ACTIVATION_OFF 0x40
-#define SANDISK_HCR_OFF 0x42
-
-
-static void sandisk_set_iobase(local_info_t *local)
-{
- int res;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- res = pcmcia_write_config_byte(hw_priv->link, 0x10,
- hw_priv->link->resource[0]->start & 0x00ff);
- if (res != 0) {
- printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
- " res=%d\n", res);
- }
- udelay(10);
-
- res = pcmcia_write_config_byte(hw_priv->link, 0x12,
- (hw_priv->link->resource[0]->start >> 8) & 0x00ff);
- if (res != 0) {
- printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
- " res=%d\n", res);
- }
-}
-
-
-static void sandisk_write_hcr(local_info_t *local, int hcr)
-{
- struct net_device *dev = local->dev;
- int i;
-
- HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
- udelay(50);
- for (i = 0; i < 10; i++) {
- HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
- }
- udelay(55);
- HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
-}
-
-
-static int sandisk_enable_wireless(struct net_device *dev)
-{
- int res, ret = 0;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- if (resource_size(hw_priv->link->resource[0]) < 0x42) {
- /* Not enough ports to be SanDisk multi-function card */
- ret = -ENODEV;
- goto done;
- }
-
- if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
- /* No SanDisk manfid found */
- ret = -ENODEV;
- goto done;
- }
-
- if (hw_priv->link->socket->functions < 2) {
- /* No multi-function links found */
- ret = -ENODEV;
- goto done;
- }
-
- printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
- " - using vendor-specific initialization\n", dev->name);
- hw_priv->sandisk_connectplus = 1;
-
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- COR_SOFT_RESET);
- if (res != 0) {
- printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
- dev->name, res);
- goto done;
- }
- mdelay(5);
-
- /*
- * Do not enable interrupts here to avoid some bogus events. Interrupts
- * will be enabled during the first cor_sreset call.
- */
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE |
- COR_FUNC_ENA));
- if (res != 0) {
- printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
- dev->name, res);
- goto done;
- }
- mdelay(5);
-
- sandisk_set_iobase(local);
-
- HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
- udelay(10);
- HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
- udelay(10);
-
-done:
- return ret;
-}
-
-
-static void prism2_pccard_cor_sreset(local_info_t *local)
-{
- int res;
- u8 val;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- if (!prism2_pccard_card_present(local))
- return;
-
- res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val);
- if (res != 0) {
- printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
- res);
- return;
- }
- printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
- val);
-
- val |= COR_SOFT_RESET;
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
- if (res != 0) {
- printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
- res);
- return;
- }
-
- mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
-
- val &= ~COR_SOFT_RESET;
- if (hw_priv->sandisk_connectplus)
- val |= COR_IREQ_ENA;
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
- if (res != 0) {
- printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
- res);
- return;
- }
-
- mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
-
- if (hw_priv->sandisk_connectplus)
- sandisk_set_iobase(local);
-}
-
-
-static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
-{
- int res;
- u8 old_cor;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- if (!prism2_pccard_card_present(local))
- return;
-
- if (hw_priv->sandisk_connectplus) {
- sandisk_write_hcr(local, hcr);
- return;
- }
-
- res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res);
- return;
- }
- printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor);
-
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- old_cor | COR_SOFT_RESET);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res);
- return;
- }
-
- mdelay(10);
-
- /* Setup Genesis mode */
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res);
- return;
- }
- mdelay(10);
-
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- old_cor & ~COR_SOFT_RESET);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res);
- return;
- }
-
- mdelay(10);
-}
-
-
-static struct prism2_helper_functions prism2_pccard_funcs =
-{
- .card_present = prism2_pccard_card_present,
- .cor_sreset = prism2_pccard_cor_sreset,
- .genesis_reset = prism2_pccard_genesis_reset,
- .hw_type = HOSTAP_HW_PCCARD,
-};
-
-
-/* allocate local data and register with CardServices
- * initialize dev_link structure, but do not configure the card yet */
-static int hostap_cs_probe(struct pcmcia_device *p_dev)
-{
- int ret;
-
- PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
-
- ret = prism2_config(p_dev);
- if (ret) {
- PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
- }
-
- return ret;
-}
-
-
-static void prism2_detach(struct pcmcia_device *link)
-{
- PDEBUG(DEBUG_FLOW, "prism2_detach\n");
-
- prism2_release((u_long)link);
-
- /* release net devices */
- if (link->priv) {
- struct hostap_cs_priv *hw_priv;
- struct net_device *dev;
- struct hostap_interface *iface;
- dev = link->priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- prism2_free_local_data(dev);
- kfree(hw_priv);
- }
-}
-
-
-static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-}
-
-static int prism2_config(struct pcmcia_device *link)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret;
- struct hostap_cs_priv *hw_priv;
- unsigned long flags;
-
- PDEBUG(DEBUG_FLOW, "prism2_config()\n");
-
- hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
- if (hw_priv == NULL) {
- ret = -ENOMEM;
- goto failed;
- }
-
- /* Look for an appropriate configuration table entry in the CIS */
- link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO |
- CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
- if (ignore_cis_vcc)
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(link, prism2_config_check, NULL);
- if (ret) {
- if (!ignore_cis_vcc)
- printk(KERN_ERR "GetNextTuple(): No matching "
- "CIS configuration. Maybe you need the "
- "ignore_cis_vcc=1 parameter.\n");
- goto failed;
- }
-
- /* Need to allocate net_device before requesting IRQ handler */
- dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
- &link->dev);
- if (!dev) {
- ret = -ENOMEM;
- goto failed;
- }
- link->priv = dev;
-
- iface = netdev_priv(dev);
- local = iface->local;
- local->hw_priv = hw_priv;
- hw_priv->link = link;
-
- /*
- * We enable IRQ here, but IRQ handler will not proceed
- * until dev->base_addr is set below. This protect us from
- * receive interrupts when driver is not initialized.
- */
- ret = pcmcia_request_irq(link, prism2_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- spin_lock_irqsave(&local->irq_init_lock, flags);
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- spin_unlock_irqrestore(&local->irq_init_lock, flags);
-
- local->shutdown = 0;
-
- sandisk_enable_wireless(dev);
-
- ret = prism2_hw_config(dev, 1);
- if (!ret)
- ret = hostap_hw_ready(dev);
-
- return ret;
-
- failed:
- kfree(hw_priv);
- prism2_release((u_long)link);
- return ret;
-}
-
-
-static void prism2_release(u_long arg)
-{
- struct pcmcia_device *link = (struct pcmcia_device *)arg;
-
- PDEBUG(DEBUG_FLOW, "prism2_release\n");
-
- if (link->priv) {
- struct net_device *dev = link->priv;
- struct hostap_interface *iface;
-
- iface = netdev_priv(dev);
- prism2_hw_shutdown(dev, 0);
- iface->local->shutdown = 1;
- }
-
- pcmcia_disable_device(link);
- PDEBUG(DEBUG_FLOW, "release - done\n");
-}
-
-static int hostap_cs_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = (struct net_device *) link->priv;
- int dev_open = 0;
- struct hostap_interface *iface = NULL;
-
- if (!dev)
- return -ENODEV;
-
- iface = netdev_priv(dev);
-
- PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
- if (iface && iface->local)
- dev_open = iface->local->num_dev_open > 0;
- if (dev_open) {
- netif_stop_queue(dev);
- netif_device_detach(dev);
- }
- prism2_suspend(dev);
-
- return 0;
-}
-
-static int hostap_cs_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = (struct net_device *) link->priv;
- int dev_open = 0;
- struct hostap_interface *iface = NULL;
-
- if (!dev)
- return -ENODEV;
-
- iface = netdev_priv(dev);
-
- PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
-
- if (iface && iface->local)
- dev_open = iface->local->num_dev_open > 0;
-
- prism2_hw_shutdown(dev, 1);
- prism2_hw_config(dev, dev_open ? 0 : 1);
- if (dev_open) {
- netif_device_attach(dev);
- netif_start_queue(dev);
- }
-
- return 0;
-}
-
-static const struct pcmcia_device_id hostap_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
- PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
- PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
-/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
- PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
- 0x2d858104),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
- 0x74c5e40d),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
- 0x4b801a17),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02",
- 0x4b74baa0),
- PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
- 0x7a954bd9, 0x74be00c6),
- PCMCIA_DEVICE_PROD_ID123(
- "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
- 0xe6ec52ce, 0x08649af2, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "Canon", "Wireless LAN CF Card K30225", "Version 01.00",
- 0x96ef6fe2, 0x263fcbab, 0xa57adb8c),
- PCMCIA_DEVICE_PROD_ID123(
- "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
- 0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "Instant Wireless ", " Network PC CARD", "Version 01.02",
- 0x11d901af, 0x6e9bd926, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "SMC", "SMC2632W", "Version 01.02",
- 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G",
- 0x2decece3, 0x82067c18),
- PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
- 0x54f7c49c, 0x15a75e5b),
- PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
- 0x74c5e40d, 0xdb472a18),
- PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
- 0x0733cc81, 0x0c52f395),
- PCMCIA_DEVICE_PROD_ID12(
- "ZoomAir 11Mbps High", "Rate wireless Networking",
- 0x273fe3db, 0x32a1eaee),
- PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
- 0xa37434e9, 0x9762e8f1),
- PCMCIA_DEVICE_PROD_ID123(
- "Pretec", "CompactWLAN Card 802.11b", "2.5",
- 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
- PCMCIA_DEVICE_PROD_ID123(
- "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
- 0xc7b8df9d, 0x1700d087, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
- "Ver. 1.00",
- 0x5cd01705, 0x4271660f, 0x9d08ee12),
- PCMCIA_DEVICE_PROD_ID123(
- "Wireless LAN" , "11Mbps PC Card", "Version 01.02",
- 0x4b8870ff, 0x70e946d1, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
- PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
- PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
- PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
-
-
-static struct pcmcia_driver hostap_driver = {
- .name = "hostap_cs",
- .probe = hostap_cs_probe,
- .remove = prism2_detach,
- .owner = THIS_MODULE,
- .id_table = hostap_cs_ids,
- .suspend = hostap_cs_suspend,
- .resume = hostap_cs_resume,
-};
-module_pcmcia_driver(hostap_driver);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_download.c b/drivers/net/wireless/intersil/hostap/hostap_download.c
deleted file mode 100644
index 5e5bada28b5b..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_download.c
+++ /dev/null
@@ -1,810 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-static int prism2_enable_aux_port(struct net_device *dev, int enable)
-{
- u16 val, reg;
- int i, tries;
- unsigned long flags;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- if (enable) {
- PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
- "port is already enabled\n", dev->name);
- }
- return 0;
- }
-
- spin_lock_irqsave(&local->cmdlock, flags);
-
- /* wait until busy bit is clear */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- spin_unlock_irqrestore(&local->cmdlock, flags);
- printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
- dev->name, reg);
- return -ETIMEDOUT;
- }
-
- val = HFA384X_INW(HFA384X_CONTROL_OFF);
-
- if (enable) {
- HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
-
- if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
- printk("prism2_enable_aux_port: was not disabled!?\n");
- val &= ~HFA384X_AUX_PORT_MASK;
- val |= HFA384X_AUX_PORT_ENABLE;
- } else {
- HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
-
- if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
- printk("prism2_enable_aux_port: was not enabled!?\n");
- val &= ~HFA384X_AUX_PORT_MASK;
- val |= HFA384X_AUX_PORT_DISABLE;
- }
- HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
-
- udelay(5);
-
- i = 10000;
- while (i > 0) {
- val = HFA384X_INW(HFA384X_CONTROL_OFF);
- val &= HFA384X_AUX_PORT_MASK;
-
- if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
- (!enable && val == HFA384X_AUX_PORT_DISABLED))
- break;
-
- udelay(10);
- i--;
- }
-
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- if (i == 0) {
- printk("prism2_enable_aux_port(%d) timed out\n",
- enable);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-
-static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
- void *buf)
-{
- u16 page, offset;
- if (addr & 1 || len & 1)
- return -1;
-
- page = addr >> 7;
- offset = addr & 0x7f;
-
- HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
- HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
-
- udelay(5);
-
-#ifdef PRISM2_PCI
- {
- __le16 *pos = (__le16 *) buf;
- while (len > 0) {
- *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
- len -= 2;
- }
- }
-#else /* PRISM2_PCI */
- HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
-#endif /* PRISM2_PCI */
-
- return 0;
-}
-
-
-static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
- void *buf)
-{
- u16 page, offset;
- if (addr & 1 || len & 1)
- return -1;
-
- page = addr >> 7;
- offset = addr & 0x7f;
-
- HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
- HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
-
- udelay(5);
-
-#ifdef PRISM2_PCI
- {
- __le16 *pos = (__le16 *) buf;
- while (len > 0) {
- HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
- len -= 2;
- }
- }
-#else /* PRISM2_PCI */
- HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
-#endif /* PRISM2_PCI */
-
- return 0;
-}
-
-
-static int prism2_pda_ok(u8 *buf)
-{
- __le16 *pda = (__le16 *) buf;
- int pos;
- u16 len, pdr;
-
- if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
- buf[3] == 0x00)
- return 0;
-
- pos = 0;
- while (pos + 1 < PRISM2_PDA_SIZE / 2) {
- len = le16_to_cpu(pda[pos]);
- pdr = le16_to_cpu(pda[pos + 1]);
- if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
- return 0;
-
- if (pdr == 0x0000 && len == 2) {
- /* PDA end found */
- return 1;
- }
-
- pos += len + 1;
- }
-
- return 0;
-}
-
-
-#define prism2_download_aux_dump_npages 65536
-
-struct prism2_download_aux_dump {
- local_info_t *local;
- u16 page[0x80];
-};
-
-static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
-{
- struct prism2_download_aux_dump *ctx = m->private;
-
- hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
- seq_write(m, ctx->page, 0x80);
- return 0;
-}
-
-static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
-{
- struct prism2_download_aux_dump *ctx = m->private;
- prism2_enable_aux_port(ctx->local->dev, 1);
- if (*_pos >= prism2_download_aux_dump_npages)
- return NULL;
- return (void *)((unsigned long)*_pos + 1);
-}
-
-static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- ++*_pos;
- if (*_pos >= prism2_download_aux_dump_npages)
- return NULL;
- return (void *)((unsigned long)*_pos + 1);
-}
-
-static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
-{
- struct prism2_download_aux_dump *ctx = m->private;
- prism2_enable_aux_port(ctx->local->dev, 0);
-}
-
-static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
- .start = prism2_download_aux_dump_proc_start,
- .next = prism2_download_aux_dump_proc_next,
- .stop = prism2_download_aux_dump_proc_stop,
- .show = prism2_download_aux_dump_proc_show,
-};
-
-static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
-{
- int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
- sizeof(struct prism2_download_aux_dump));
- if (ret == 0) {
- struct seq_file *m = file->private_data;
- m->private = pde_data(inode);
- }
- return ret;
-}
-
-static const struct proc_ops prism2_download_aux_dump_proc_ops = {
- .proc_open = prism2_download_aux_dump_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = seq_release_private,
-};
-
-
-static u8 * prism2_read_pda(struct net_device *dev)
-{
- u8 *buf;
- int res, i, found = 0;
-#define NUM_PDA_ADDRS 4
- unsigned int pda_addr[NUM_PDA_ADDRS] = {
- 0x7f0000 /* others than HFA3841 */,
- 0x3f0000 /* HFA3841 */,
- 0x390000 /* apparently used in older cards */,
- 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
- };
-
- buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return NULL;
-
- /* Note: wlan card should be in initial state (just after init cmd)
- * and no other operations should be performed concurrently. */
-
- prism2_enable_aux_port(dev, 1);
-
- for (i = 0; i < NUM_PDA_ADDRS; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
- dev->name, pda_addr[i]);
- res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
- if (res)
- continue;
- if (res == 0 && prism2_pda_ok(buf)) {
- PDEBUG2(DEBUG_EXTRA2, ": OK\n");
- found = 1;
- break;
- } else {
- PDEBUG2(DEBUG_EXTRA2, ": failed\n");
- }
- }
-
- prism2_enable_aux_port(dev, 0);
-
- if (!found) {
- printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
- kfree(buf);
- buf = NULL;
- }
-
- return buf;
-}
-
-
-static int prism2_download_volatile(local_info_t *local,
- struct prism2_download_data *param)
-{
- struct net_device *dev = local->dev;
- int ret = 0, i;
- u16 param0, param1;
-
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -1;
- }
-
- local->hw_downloading = 1;
- if (local->pri_only) {
- hfa384x_disable_interrupts(dev);
- } else {
- prism2_hw_shutdown(dev, 0);
-
- if (prism2_hw_init(dev, 0)) {
- printk(KERN_WARNING "%s: Could not initialize card for"
- " download\n", dev->name);
- ret = -1;
- goto out;
- }
- }
-
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_WARNING "%s: Could not enable AUX port\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- param0 = param->start_addr & 0xffff;
- param1 = param->start_addr >> 16;
-
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
- param0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
- dev->name, param->data[i].len, param->data[i].addr);
- if (hfa384x_to_aux(dev, param->data[i].addr,
- param->data[i].len, param->data[i].data)) {
- printk(KERN_WARNING "%s: RAM download at 0x%08x "
- "(len=%d) failed\n", dev->name,
- param->data[i].addr, param->data[i].len);
- ret = -1;
- goto out;
- }
- }
-
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_DISABLE << 8), param0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
- /* ProgMode disable causes the hardware to restart itself from the
- * given starting address. Give hw some time and ACK command just in
- * case restart did not happen. */
- mdelay(5);
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
-
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
- dev->name);
- /* continue anyway.. restart should have taken care of this */
- }
-
- mdelay(5);
- local->hw_downloading = 0;
- if (prism2_hw_config(dev, 2)) {
- printk(KERN_WARNING "%s: Card configuration after RAM "
- "download failed\n", dev->name);
- ret = -1;
- goto out;
- }
-
- out:
- local->hw_downloading = 0;
- return ret;
-}
-
-
-static int prism2_enable_genesis(local_info_t *local, int hcr)
-{
- struct net_device *dev = local->dev;
- u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
- u8 readbuf[4];
-
- printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
- dev->name, hcr);
- local->func->cor_sreset(local);
- hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
- local->func->genesis_reset(local, hcr);
-
- /* Readback test */
- hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
- hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
- hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
-
- if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
- printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
- hcr);
- return 0;
- } else {
- printk(KERN_DEBUG "Readback test failed, HCR 0x%02x write %4ph read %4ph\n",
- hcr, initseq, readbuf);
- return 1;
- }
-}
-
-
-static int prism2_get_ram_size(local_info_t *local)
-{
- int ret;
-
- /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
- if (prism2_enable_genesis(local, 0x1f) == 0)
- ret = 8;
- else if (prism2_enable_genesis(local, 0x0f) == 0)
- ret = 16;
- else
- ret = -1;
-
- /* Disable genesis mode */
- local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
-
- return ret;
-}
-
-
-static int prism2_download_genesis(local_info_t *local,
- struct prism2_download_data *param)
-{
- struct net_device *dev = local->dev;
- int ram16 = 0, i;
- int ret = 0;
-
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -EBUSY;
- }
-
- if (!local->func->genesis_reset || !local->func->cor_sreset) {
- printk(KERN_INFO "%s: Genesis mode downloading not supported "
- "with this hwmodel\n", dev->name);
- return -EOPNOTSUPP;
- }
-
- local->hw_downloading = 1;
-
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_DEBUG "%s: failed to enable AUX port\n",
- dev->name);
- ret = -EIO;
- goto out;
- }
-
- if (local->sram_type == -1) {
- /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
- if (prism2_enable_genesis(local, 0x1f) == 0) {
- ram16 = 0;
- PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
- "SRAM\n", dev->name);
- } else if (prism2_enable_genesis(local, 0x0f) == 0) {
- ram16 = 1;
- PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
- "SRAM\n", dev->name);
- } else {
- printk(KERN_DEBUG "%s: Could not initiate genesis "
- "mode\n", dev->name);
- ret = -EIO;
- goto out;
- }
- } else {
- if (prism2_enable_genesis(local, local->sram_type == 8 ?
- 0x1f : 0x0f)) {
- printk(KERN_DEBUG "%s: Failed to set Genesis "
- "mode (sram_type=%d)\n", dev->name,
- local->sram_type);
- ret = -EIO;
- goto out;
- }
- ram16 = local->sram_type != 8;
- }
-
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
- dev->name, param->data[i].len, param->data[i].addr);
- if (hfa384x_to_aux(dev, param->data[i].addr,
- param->data[i].len, param->data[i].data)) {
- printk(KERN_WARNING "%s: RAM download at 0x%08x "
- "(len=%d) failed\n", dev->name,
- param->data[i].addr, param->data[i].len);
- ret = -EIO;
- goto out;
- }
- }
-
- PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
- local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
- dev->name);
- }
-
- mdelay(5);
- local->hw_downloading = 0;
-
- PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
- /*
- * Make sure the INIT command does not generate a command completion
- * event by disabling interrupts.
- */
- hfa384x_disable_interrupts(dev);
- if (prism2_hw_init(dev, 1)) {
- printk(KERN_DEBUG "%s: Initialization after genesis mode "
- "download failed\n", dev->name);
- ret = -EIO;
- goto out;
- }
-
- PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
- if (prism2_hw_init2(dev, 1)) {
- printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
- "download failed\n", dev->name);
- ret = -EIO;
- goto out;
- }
-
- out:
- local->hw_downloading = 0;
- return ret;
-}
-
-
-#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
-/* Note! Non-volatile downloading functionality has not yet been tested
- * thoroughly and it may corrupt flash image and effectively kill the card that
- * is being updated. You have been warned. */
-
-static inline int prism2_download_block(struct net_device *dev,
- u32 addr, u8 *data,
- u32 bufaddr, int rest_len)
-{
- u16 param0, param1;
- int block_len;
-
- block_len = rest_len < 4096 ? rest_len : 4096;
-
- param0 = addr & 0xffff;
- param1 = addr >> 16;
-
- HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
-
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
- param0)) {
- printk(KERN_WARNING "%s: Flash download command execution "
- "failed\n", dev->name);
- return -1;
- }
-
- if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
- printk(KERN_WARNING "%s: flash download at 0x%08x "
- "(len=%d) failed\n", dev->name, addr, block_len);
- return -1;
- }
-
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
- 0)) {
- printk(KERN_WARNING "%s: Flash write command execution "
- "failed\n", dev->name);
- return -1;
- }
-
- return block_len;
-}
-
-
-static int prism2_download_nonvolatile(local_info_t *local,
- struct prism2_download_data *dl)
-{
- struct net_device *dev = local->dev;
- int ret = 0, i;
- struct {
- __le16 page;
- __le16 offset;
- __le16 len;
- } dlbuffer;
- u32 bufaddr;
-
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -1;
- }
-
- ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
- &dlbuffer, 6, 0);
-
- if (ret < 0) {
- printk(KERN_WARNING "%s: Could not read download buffer "
- "parameters\n", dev->name);
- goto out;
- }
-
- printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
- le16_to_cpu(dlbuffer.len),
- le16_to_cpu(dlbuffer.page),
- le16_to_cpu(dlbuffer.offset));
-
- bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
-
- local->hw_downloading = 1;
-
- if (!local->pri_only) {
- prism2_hw_shutdown(dev, 0);
-
- if (prism2_hw_init(dev, 0)) {
- printk(KERN_WARNING "%s: Could not initialize card for"
- " download\n", dev->name);
- ret = -1;
- goto out;
- }
- }
-
- hfa384x_disable_interrupts(dev);
-
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_WARNING "%s: Could not enable AUX port\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
- for (i = 0; i < dl->num_areas; i++) {
- int rest_len = dl->data[i].len;
- int data_off = 0;
-
- while (rest_len > 0) {
- int block_len;
-
- block_len = prism2_download_block(
- dev, dl->data[i].addr + data_off,
- dl->data[i].data + data_off, bufaddr,
- rest_len);
-
- if (block_len < 0) {
- ret = -1;
- goto out;
- }
-
- rest_len -= block_len;
- data_off += block_len;
- }
- }
-
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_DISABLE << 8), 0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
- dev->name);
- /* continue anyway.. restart should have taken care of this */
- }
-
- mdelay(5);
-
- local->func->hw_reset(dev);
- local->hw_downloading = 0;
- if (prism2_hw_config(dev, 2)) {
- printk(KERN_WARNING "%s: Card configuration after flash "
- "download failed\n", dev->name);
- ret = -1;
- } else {
- printk(KERN_INFO "%s: Card initialized successfully after "
- "flash download\n", dev->name);
- }
-
- out:
- local->hw_downloading = 0;
- return ret;
-}
-#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
-
-
-static void prism2_download_free_data(struct prism2_download_data *dl)
-{
- int i;
-
- if (dl == NULL)
- return;
-
- for (i = 0; i < dl->num_areas; i++)
- kfree(dl->data[i].data);
- kfree(dl);
-}
-
-
-static int prism2_download(local_info_t *local,
- struct prism2_download_param *param)
-{
- int ret = 0;
- int i;
- u32 total_len = 0;
- struct prism2_download_data *dl = NULL;
-
- printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
- "num_areas=%d\n",
- param->dl_cmd, param->start_addr, param->num_areas);
-
- if (param->num_areas > 100) {
- ret = -EINVAL;
- goto out;
- }
-
- dl = kzalloc(struct_size(dl, data, param->num_areas), GFP_KERNEL);
- if (dl == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- dl->dl_cmd = param->dl_cmd;
- dl->start_addr = param->start_addr;
- dl->num_areas = param->num_areas;
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2,
- " area %d: addr=0x%08x len=%d ptr=0x%p\n",
- i, param->data[i].addr, param->data[i].len,
- param->data[i].ptr);
-
- dl->data[i].addr = param->data[i].addr;
- dl->data[i].len = param->data[i].len;
-
- total_len += param->data[i].len;
- if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
- total_len > PRISM2_MAX_DOWNLOAD_LEN) {
- ret = -E2BIG;
- goto out;
- }
-
- dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
- if (dl->data[i].data == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (copy_from_user(dl->data[i].data, param->data[i].ptr,
- param->data[i].len)) {
- ret = -EFAULT;
- goto out;
- }
- }
-
- switch (param->dl_cmd) {
- case PRISM2_DOWNLOAD_VOLATILE:
- case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
- ret = prism2_download_volatile(local, dl);
- break;
- case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
- case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
- ret = prism2_download_genesis(local, dl);
- break;
- case PRISM2_DOWNLOAD_NON_VOLATILE:
-#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
- ret = prism2_download_nonvolatile(local, dl);
-#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
- printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
- local->dev->name);
- ret = -EOPNOTSUPP;
-#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
- break;
- default:
- printk(KERN_DEBUG "%s: unsupported download command %d\n",
- local->dev->name, param->dl_cmd);
- ret = -EINVAL;
- break;
- }
-
- out:
- if (ret == 0 && dl &&
- param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
- prism2_download_free_data(local->dl_pri);
- local->dl_pri = dl;
- } else if (ret == 0 && dl &&
- param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
- prism2_download_free_data(local->dl_sec);
- local->dl_sec = dl;
- } else
- prism2_download_free_data(dl);
-
- return ret;
-}
diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c
deleted file mode 100644
index b74f4cb5d6d3..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_hw.c
+++ /dev/null
@@ -1,3387 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Host AP (software wireless LAN access point) driver for
- * Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j@w1.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- *
- * FIX:
- * - there is currently no way of associating TX packets to correct wds device
- * when TX Exc/OK event occurs, so all tx_packets and some
- * tx_errors/tx_dropped are added to the main netdevice; using sw_support
- * field in txdesc might be used to fix this (using Alloc event to increment
- * tx_packets would need some further info in txfid table)
- *
- * Buffer Access Path (BAP) usage:
- * Prism2 cards have two separate BAPs for accessing the card memory. These
- * should allow concurrent access to two different frames and the driver
- * previously used BAP0 for sending data and BAP1 for receiving data.
- * However, there seems to be number of issues with concurrent access and at
- * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI
- * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between
- * host and card memories. BAP0 accesses are protected with local->baplock
- * (spin_lock_bh) to prevent concurrent use.
- */
-
-
-
-#include <asm/delay.h>
-#include <linux/uaccess.h>
-
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/wait.h>
-#include <linux/sched/signal.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
-#include <asm/irq.h>
-
-#include "hostap_80211.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-
-/* #define final_version */
-
-static int mtu = 1500;
-module_param(mtu, int, 0444);
-MODULE_PARM_DESC(mtu, "Maximum transfer unit");
-
-static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS };
-module_param_array(channel, int, NULL, 0444);
-MODULE_PARM_DESC(channel, "Initial channel");
-
-static char essid[33] = "test";
-module_param_string(essid, essid, sizeof(essid), 0444);
-MODULE_PARM_DESC(essid, "Host AP's ESSID");
-
-static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS };
-module_param_array(iw_mode, int, NULL, 0444);
-MODULE_PARM_DESC(iw_mode, "Initial operation mode");
-
-static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS };
-module_param_array(beacon_int, int, NULL, 0444);
-MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)");
-
-static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS };
-module_param_array(dtim_period, int, NULL, 0444);
-MODULE_PARM_DESC(dtim_period, "DTIM period");
-
-static char dev_template[16] = "wlan%d";
-module_param_string(dev_template, dev_template, sizeof(dev_template), 0444);
-MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: "
- "wlan%d)");
-
-#ifdef final_version
-#define EXTRA_EVENTS_WTERR 0
-#else
-/* check WTERR events (Wait Time-out) in development versions */
-#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR
-#endif
-
-/* Events that will be using BAP0 */
-#define HFA384X_BAP0_EVENTS \
- (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX)
-
-/* event mask, i.e., events that will result in an interrupt */
-#define HFA384X_EVENT_MASK \
- (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \
- HFA384X_EV_CMD | HFA384X_EV_TICK | \
- EXTRA_EVENTS_WTERR)
-
-/* Default TX control flags: use 802.11 headers and request interrupt for
- * failed transmits. Frames that request ACK callback, will add
- * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy.
- */
-#define HFA384X_TX_CTRL_FLAGS \
- (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX)
-
-
-/* ca. 1 usec */
-#define HFA384X_CMD_BUSY_TIMEOUT 5000
-#define HFA384X_BAP_BUSY_TIMEOUT 50000
-
-/* ca. 10 usec */
-#define HFA384X_CMD_COMPL_TIMEOUT 20000
-#define HFA384X_DL_COMPL_TIMEOUT 1000000
-
-/* Wait times for initialization; yield to other processes to avoid busy
- * waiting for long time. */
-#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */
-#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */
-
-
-static void prism2_hw_reset(struct net_device *dev);
-static void prism2_check_sta_fw_version(local_info_t *local);
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
-/* hostap_download.c */
-static const struct proc_ops prism2_download_aux_dump_proc_ops;
-static u8 * prism2_read_pda(struct net_device *dev);
-static int prism2_download(local_info_t *local,
- struct prism2_download_param *param);
-static void prism2_download_free_data(struct prism2_download_data *dl);
-static int prism2_download_volatile(local_info_t *local,
- struct prism2_download_data *param);
-static int prism2_download_genesis(local_info_t *local,
- struct prism2_download_data *param);
-static int prism2_get_ram_size(local_info_t *local);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-
-
-
-#ifndef final_version
-/* magic value written to SWSUPPORT0 reg. for detecting whether card is still
- * present */
-#define HFA384X_MAGIC 0x8A32
-#endif
-
-static void hfa384x_read_regs(struct net_device *dev,
- struct hfa384x_regs *regs)
-{
- regs->cmd = HFA384X_INW(HFA384X_CMD_OFF);
- regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
- regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF);
- regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF);
- regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF);
-}
-
-
-/**
- * __hostap_cmd_queue_free - Free Prism2 command queue entry (private)
- * @local: pointer to private Host AP driver data
- * @entry: Prism2 command queue entry to be freed
- * @del_req: request the entry to be removed
- *
- * Internal helper function for freeing Prism2 command queue entries.
- * Caller must have acquired local->cmdlock before calling this function.
- */
-static inline void __hostap_cmd_queue_free(local_info_t *local,
- struct hostap_cmd_queue *entry,
- int del_req)
-{
- if (del_req) {
- entry->del_req = 1;
- if (!list_empty(&entry->list)) {
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- }
- }
-
- if (refcount_dec_and_test(&entry->usecnt) && entry->del_req)
- kfree(entry);
-}
-
-
-/**
- * hostap_cmd_queue_free - Free Prism2 command queue entry
- * @local: pointer to private Host AP driver data
- * @entry: Prism2 command queue entry to be freed
- * @del_req: request the entry to be removed
- *
- * Free a Prism2 command queue entry.
- */
-static inline void hostap_cmd_queue_free(local_info_t *local,
- struct hostap_cmd_queue *entry,
- int del_req)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&local->cmdlock, flags);
- __hostap_cmd_queue_free(local, entry, del_req);
- spin_unlock_irqrestore(&local->cmdlock, flags);
-}
-
-
-/**
- * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries
- * @local: pointer to private Host AP driver data
- */
-static void prism2_clear_cmd_queue(local_info_t *local)
-{
- struct list_head *ptr, *n;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
-
- spin_lock_irqsave(&local->cmdlock, flags);
- list_for_each_safe(ptr, n, &local->cmd_queue) {
- entry = list_entry(ptr, struct hostap_cmd_queue, list);
- refcount_inc(&entry->usecnt);
- printk(KERN_DEBUG "%s: removed pending cmd_queue entry "
- "(type=%d, cmd=0x%04x, param0=0x%04x)\n",
- local->dev->name, entry->type, entry->cmd,
- entry->param0);
- __hostap_cmd_queue_free(local, entry, 1);
- }
- if (local->cmd_queue_len) {
- /* This should not happen; print debug message and clear
- * queue length. */
- printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after "
- "flush\n", local->dev->name, local->cmd_queue_len);
- local->cmd_queue_len = 0;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
-}
-
-
-/**
- * hfa384x_cmd_issue - Issue a Prism2 command to the hardware
- * @dev: pointer to net_device
- * @entry: Prism2 command queue entry to be issued
- */
-static int hfa384x_cmd_issue(struct net_device *dev,
- struct hostap_cmd_queue *entry)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int tries;
- u16 reg;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->card_present && !local->func->card_present(local))
- return -ENODEV;
-
- if (entry->issued) {
- printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n",
- dev->name, entry);
- }
-
- /* wait until busy bit is clear; this should always be clear since the
- * commands are serialized */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
-#ifndef final_version
- if (tries != HFA384X_CMD_BUSY_TIMEOUT) {
- prism2_io_debug_error(dev, 1);
- printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy "
- "for %d usec\n", dev->name,
- HFA384X_CMD_BUSY_TIMEOUT - tries);
- }
-#endif
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- prism2_io_debug_error(dev, 2);
- printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - "
- "reg=0x%04x\n", dev->name, reg);
- return -ETIMEDOUT;
- }
-
- /* write command */
- spin_lock_irqsave(&local->cmdlock, flags);
- HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF);
- entry->issued = 1;
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- return 0;
-}
-
-
-/**
- * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @param1: value for Param1 register (pointer; %NULL if not used)
- * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed
- *
- * Issue given command (possibly after waiting in command queue) and sleep
- * until the command is completed (or timed out or interrupted). This can be
- * called only from user process context.
- */
-static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0,
- u16 *param1, u16 *resp0)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int err, res, issue, issued = 0;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
- DECLARE_WAITQUEUE(wait, current);
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
- dev->name);
- return -1;
- }
-
- if (signal_pending(current))
- return -EINTR;
-
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry == NULL)
- return -ENOMEM;
-
- refcount_set(&entry->usecnt, 1);
- entry->type = CMD_SLEEP;
- entry->cmd = cmd;
- entry->param0 = param0;
- if (param1)
- entry->param1 = *param1;
- init_waitqueue_head(&entry->compl);
-
- /* prepare to wait for command completion event, but do not sleep yet
- */
- add_wait_queue(&entry->compl, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&local->cmdlock, flags);
- issue = list_empty(&local->cmd_queue);
- if (issue)
- entry->issuing = 1;
- list_add_tail(&entry->list, &local->cmd_queue);
- local->cmd_queue_len++;
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- err = 0;
- if (!issue)
- goto wait_completion;
-
- if (signal_pending(current))
- err = -EINTR;
-
- if (!err) {
- if (hfa384x_cmd_issue(dev, entry))
- err = -ETIMEDOUT;
- else
- issued = 1;
- }
-
- wait_completion:
- if (!err && entry->type != CMD_COMPLETED) {
- /* sleep until command is completed or timed out */
- res = schedule_timeout(2 * HZ);
- } else
- res = -1;
-
- if (!err && signal_pending(current))
- err = -EINTR;
-
- if (err && issued) {
- /* the command was issued, so a CmdCompl event should occur
- * soon; however, there's a pending signal and
- * schedule_timeout() would be interrupted; wait a short period
- * of time to avoid removing entry from the list before
- * CmdCompl event */
- udelay(300);
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&entry->compl, &wait);
-
- /* If entry->list is still in the list, it must be removed
- * first and in this case prism2_cmd_ev() does not yet have
- * local reference to it, and the data can be kfree()'d
- * here. If the command completion event is still generated,
- * it will be assigned to next (possibly) pending command, but
- * the driver will reset the card anyway due to timeout
- *
- * If the entry is not in the list prism2_cmd_ev() has a local
- * reference to it, but keeps cmdlock as long as the data is
- * needed, so the data can be kfree()'d here. */
-
- /* FIX: if the entry->list is in the list, it has not been completed
- * yet, so removing it here is somewhat wrong.. this could cause
- * references to freed memory and next list_del() causing NULL pointer
- * dereference.. it would probably be better to leave the entry in the
- * list and the list should be emptied during hw reset */
-
- spin_lock_irqsave(&local->cmdlock, flags);
- if (!list_empty(&entry->list)) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? "
- "(entry=%p, type=%d, res=%d)\n", dev->name, entry,
- entry->type, res);
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- if (err) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n",
- dev->name, err);
- res = err;
- goto done;
- }
-
- if (entry->type != CMD_COMPLETED) {
- u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
- printk(KERN_DEBUG "%s: hfa384x_cmd: command was not "
- "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, "
- "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name,
- res, entry, entry->type, entry->cmd, entry->param0, reg,
- HFA384X_INW(HFA384X_INTEN_OFF));
- if (reg & HFA384X_EV_CMD) {
- /* Command completion event is pending, but the
- * interrupt was not delivered - probably an issue
- * with pcmcia-cs configuration. */
- printk(KERN_WARNING "%s: interrupt delivery does not "
- "seem to work\n", dev->name);
- }
- prism2_io_debug_error(dev, 3);
- res = -ETIMEDOUT;
- goto done;
- }
-
- if (resp0 != NULL)
- *resp0 = entry->resp0;
-#ifndef final_version
- if (entry->res) {
- printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, "
- "resp0=0x%04x\n",
- dev->name, cmd, entry->res, entry->resp0);
- }
-#endif /* final_version */
-
- res = entry->res;
- done:
- hostap_cmd_queue_free(local, entry, 1);
- return res;
-}
-
-
-/**
- * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @callback: command completion callback function (%NULL = no callback)
- * @context: context data to be given to the callback function
- *
- * Issue given command (possibly after waiting in command queue) and use
- * callback function to indicate command completion. This can be called both
- * from user and interrupt context. The callback function will be called in
- * hardware IRQ context. It can be %NULL, when no function is called when
- * command is completed.
- */
-static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0,
- void (*callback)(struct net_device *dev,
- long context, u16 resp0,
- u16 status),
- long context)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int issue, ret;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
- dev->name);
- return -1;
- }
-
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry == NULL)
- return -ENOMEM;
-
- refcount_set(&entry->usecnt, 1);
- entry->type = CMD_CALLBACK;
- entry->cmd = cmd;
- entry->param0 = param0;
- entry->callback = callback;
- entry->context = context;
-
- spin_lock_irqsave(&local->cmdlock, flags);
- issue = list_empty(&local->cmd_queue);
- if (issue)
- entry->issuing = 1;
- list_add_tail(&entry->list, &local->cmd_queue);
- local->cmd_queue_len++;
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- if (issue && hfa384x_cmd_issue(dev, entry))
- ret = -ETIMEDOUT;
- else
- ret = 0;
-
- hostap_cmd_queue_free(local, entry, ret);
-
- return ret;
-}
-
-
-/**
- * __hfa384x_cmd_no_wait - Issue a Prism2 command (private)
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @io_debug_num: I/O debug error number
- *
- * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait().
- */
-static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0,
- int io_debug_num)
-{
- int tries;
- u16 reg;
-
- /* wait until busy bit is clear; this should always be clear since the
- * commands are serialized */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- prism2_io_debug_error(dev, io_debug_num);
- printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - "
- "reg=0x%04x\n", dev->name, io_debug_num, reg);
- return -ETIMEDOUT;
- }
-
- /* write command */
- HFA384X_OUTW(param0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(cmd, HFA384X_CMD_OFF);
-
- return 0;
-}
-
-
-/**
- * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- */
-static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0)
-{
- int res, tries;
- u16 reg;
-
- res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4);
- if (res)
- return res;
-
- /* wait for command completion */
- if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD)
- tries = HFA384X_DL_COMPL_TIMEOUT;
- else
- tries = HFA384X_CMD_COMPL_TIMEOUT;
-
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
- tries > 0) {
- tries--;
- udelay(10);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
- prism2_io_debug_error(dev, 5);
- printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - "
- "reg=0x%04x\n", dev->name, reg);
- return -ETIMEDOUT;
- }
-
- res = (HFA384X_INW(HFA384X_STATUS_OFF) &
- (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) |
- BIT(8))) >> 8;
-#ifndef final_version
- if (res) {
- printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n",
- dev->name, cmd, res);
- }
-#endif
-
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
-
- return res;
-}
-
-
-/**
- * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- */
-static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd,
- u16 param0)
-{
- return __hfa384x_cmd_no_wait(dev, cmd, param0, 6);
-}
-
-
-/**
- * prism2_cmd_ev - Prism2 command completion event handler
- * @dev: pointer to net_device
- *
- * Interrupt handler for command completion events. Called by the main
- * interrupt handler in hardware IRQ context. Read Resp0 and status registers
- * from the hardware and ACK the event. Depending on the issued command type
- * either wake up the sleeping process that is waiting for command completion
- * or call the callback function. Issue the next command, if one is pending.
- */
-static void prism2_cmd_ev(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hostap_cmd_queue *entry = NULL;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock(&local->cmdlock);
- if (!list_empty(&local->cmd_queue)) {
- entry = list_entry(local->cmd_queue.next,
- struct hostap_cmd_queue, list);
- refcount_inc(&entry->usecnt);
- list_del_init(&entry->list);
- local->cmd_queue_len--;
-
- if (!entry->issued) {
- printk(KERN_DEBUG "%s: Command completion event, but "
- "cmd not issued\n", dev->name);
- __hostap_cmd_queue_free(local, entry, 1);
- entry = NULL;
- }
- }
- spin_unlock(&local->cmdlock);
-
- if (!entry) {
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: Command completion event, but no "
- "pending commands\n", dev->name);
- return;
- }
-
- entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF);
- entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) &
- (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) |
- BIT(9) | BIT(8))) >> 8;
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
-
- /* TODO: rest of the CmdEv handling could be moved to tasklet */
- if (entry->type == CMD_SLEEP) {
- entry->type = CMD_COMPLETED;
- wake_up_interruptible(&entry->compl);
- } else if (entry->type == CMD_CALLBACK) {
- if (entry->callback)
- entry->callback(dev, entry->context, entry->resp0,
- entry->res);
- } else {
- printk(KERN_DEBUG "%s: Invalid command completion type %d\n",
- dev->name, entry->type);
- }
- hostap_cmd_queue_free(local, entry, 1);
-
- /* issue next command, if pending */
- entry = NULL;
- spin_lock(&local->cmdlock);
- if (!list_empty(&local->cmd_queue)) {
- entry = list_entry(local->cmd_queue.next,
- struct hostap_cmd_queue, list);
- if (entry->issuing) {
- /* hfa384x_cmd() has already started issuing this
- * command, so do not start here */
- entry = NULL;
- }
- if (entry)
- refcount_inc(&entry->usecnt);
- }
- spin_unlock(&local->cmdlock);
-
- if (entry) {
- /* issue next command; if command issuing fails, remove the
- * entry from cmd_queue */
- int res = hfa384x_cmd_issue(dev, entry);
- spin_lock(&local->cmdlock);
- __hostap_cmd_queue_free(local, entry, res);
- spin_unlock(&local->cmdlock);
- }
-}
-
-
-static int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
-{
- int tries = HFA384X_BAP_BUSY_TIMEOUT;
- int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
-
- while (res && tries > 0) {
- tries--;
- udelay(1);
- res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
- }
- return res;
-}
-
-
-/* Offset must be even */
-static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id,
- int offset)
-{
- u16 o_off, s_off;
- int ret = 0;
-
- if (offset % 2 || bap > 1)
- return -EINVAL;
-
- if (bap == BAP1) {
- o_off = HFA384X_OFFSET1_OFF;
- s_off = HFA384X_SELECT1_OFF;
- } else {
- o_off = HFA384X_OFFSET0_OFF;
- s_off = HFA384X_SELECT0_OFF;
- }
-
- if (hfa384x_wait_offset(dev, o_off)) {
- prism2_io_debug_error(dev, 7);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n",
- dev->name);
- ret = -ETIMEDOUT;
- goto out;
- }
-
- HFA384X_OUTW(id, s_off);
- HFA384X_OUTW(offset, o_off);
-
- if (hfa384x_wait_offset(dev, o_off)) {
- prism2_io_debug_error(dev, 8);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n",
- dev->name);
- ret = -ETIMEDOUT;
- goto out;
- }
-#ifndef final_version
- if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) {
- prism2_io_debug_error(dev, 9);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error "
- "(%d,0x04%x,%d); reg=0x%04x\n",
- dev->name, bap, id, offset, HFA384X_INW(o_off));
- ret = -EINVAL;
- }
-#endif
-
- out:
- return ret;
-}
-
-
-static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
- int exact_len)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int res, rlen = 0;
- struct hfa384x_rid_hdr rec;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI "
- "f/w\n", dev->name, rid, len);
- return -ENOTTY; /* Well.. not really correct, but return
- * something unique enough.. */
- }
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
-
- res = mutex_lock_interruptible(&local->rid_bap_mtx);
- if (res)
- return res;
-
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL);
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
- "(res=%d, rid=%04x, len=%d)\n",
- dev->name, res, rid, len);
- mutex_unlock(&local->rid_bap_mtx);
- return res;
- }
-
- spin_lock_bh(&local->baplock);
-
- res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (res)
- goto unlock;
-
- res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
- if (res)
- goto unlock;
-
- if (le16_to_cpu(rec.len) == 0) {
- /* RID not available */
- res = -ENODATA;
- goto unlock;
- }
-
- rlen = (le16_to_cpu(rec.len) - 1) * 2;
- if (exact_len && rlen != len) {
- printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
- "rid=0x%04x, len=%d (expected %d)\n",
- dev->name, rid, rlen, len);
- res = -ENODATA;
- }
-
- res = hfa384x_from_bap(dev, BAP0, buf, len);
-
-unlock:
- spin_unlock_bh(&local->baplock);
- mutex_unlock(&local->rid_bap_mtx);
-
- if (res) {
- if (res != -ENODATA)
- printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, "
- "len=%d) - failed - res=%d\n", dev->name, rid,
- len, res);
- if (res == -ETIMEDOUT)
- prism2_hw_reset(dev);
- return res;
- }
-
- return rlen;
-}
-
-
-static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_rid_hdr rec;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI "
- "f/w\n", dev->name, rid, len);
- return -ENOTTY; /* Well.. not really correct, but return
- * something unique enough.. */
- }
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
-
- rec.rid = cpu_to_le16(rid);
- /* RID len in words and +1 for rec.rid */
- rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
-
- res = mutex_lock_interruptible(&local->rid_bap_mtx);
- if (res)
- return res;
-
- spin_lock_bh(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec));
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, buf, len);
- spin_unlock_bh(&local->baplock);
-
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
- "failed - res=%d\n", dev->name, rid, len, res);
- mutex_unlock(&local->rid_bap_mtx);
- return res;
- }
-
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
- mutex_unlock(&local->rid_bap_mtx);
-
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
- "failed (res=%d, rid=%04x, len=%d)\n",
- dev->name, res, rid, len);
-
- if (res == -ETIMEDOUT)
- prism2_hw_reset(dev);
- }
-
- return res;
-}
-
-
-static void hfa384x_disable_interrupts(struct net_device *dev)
-{
- /* disable interrupts and clear event status */
- HFA384X_OUTW(0, HFA384X_INTEN_OFF);
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
-}
-
-
-static void hfa384x_enable_interrupts(struct net_device *dev)
-{
- /* ack pending events and enable interrupts from selected events */
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
-}
-
-
-static void hfa384x_events_no_bap0(struct net_device *dev)
-{
- HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS,
- HFA384X_INTEN_OFF);
-}
-
-
-static void hfa384x_events_all(struct net_device *dev)
-{
- HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
-}
-
-
-static void hfa384x_events_only_cmd(struct net_device *dev)
-{
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF);
-}
-
-
-static u16 hfa384x_allocate_fid(struct net_device *dev, int len)
-{
- u16 fid;
- unsigned long delay;
-
- /* FIX: this could be replace with hfa384x_cmd() if the Alloc event
- * below would be handled like CmdCompl event (sleep here, wake up from
- * interrupt handler */
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) {
- printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n",
- dev->name, len);
- return 0xffff;
- }
-
- delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) &&
- time_before(jiffies, delay))
- yield();
- if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) {
- printk("%s: fid allocate, len=%d - timeout\n", dev->name, len);
- return 0xffff;
- }
-
- fid = HFA384X_INW(HFA384X_ALLOCFID_OFF);
- HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
-
- return fid;
-}
-
-
-static int prism2_reset_port(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (!local->dev_enabled)
- return 0;
-
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0,
- NULL, NULL);
- if (res)
- printk(KERN_DEBUG "%s: reset port failed to disable port\n",
- dev->name);
- else {
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0,
- NULL, NULL);
- if (res)
- printk(KERN_DEBUG "%s: reset port failed to enable "
- "port\n", dev->name);
- }
-
- /* It looks like at least some STA firmware versions reset
- * fragmentation threshold back to 2346 after enable command. Restore
- * the configured value, if it differs from this default. */
- if (local->fragm_threshold != 2346 &&
- hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- local->fragm_threshold)) {
- printk(KERN_DEBUG "%s: failed to restore fragmentation "
- "threshold (%d) after Port0 enable\n",
- dev->name, local->fragm_threshold);
- }
-
- /* Some firmwares lose antenna selection settings on reset */
- (void) hostap_set_antsel(local);
-
- return res;
-}
-
-
-static int prism2_get_version_info(struct net_device *dev, u16 rid,
- const char *txt)
-{
- struct hfa384x_comp_ident comp;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- /* PRI f/w not yet available - cannot read RIDs */
- return -1;
- }
- if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) {
- printk(KERN_DEBUG "Could not get RID for component %s\n", txt);
- return -1;
- }
-
- printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt,
- __le16_to_cpu(comp.id), __le16_to_cpu(comp.major),
- __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant));
- return 0;
-}
-
-
-static int prism2_setup_rids(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 tmp;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000);
-
- if (!local->fw_ap) {
- u16 tmp1 = hostap_get_porttype(local);
- ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1);
- if (ret) {
- printk("%s: Port type setting to %d failed\n",
- dev->name, tmp1);
- goto fail;
- }
- }
-
- /* Setting SSID to empty string seems to kill the card in Host AP mode
- */
- if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') {
- ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID,
- local->essid);
- if (ret) {
- printk("%s: AP own SSID setting failed\n", dev->name);
- goto fail;
- }
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN,
- PRISM2_DATA_MAXLEN);
- if (ret) {
- printk("%s: MAC data length setting to %d failed\n",
- dev->name, PRISM2_DATA_MAXLEN);
- goto fail;
- }
-
- if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) {
- printk("%s: Channel list read failed\n", dev->name);
- ret = -EINVAL;
- goto fail;
- }
- local->channel_mask = le16_to_cpu(tmp);
-
- if (local->channel < 1 || local->channel > 14 ||
- !(local->channel_mask & (1 << (local->channel - 1)))) {
- printk(KERN_WARNING "%s: Channel setting out of range "
- "(%d)!\n", dev->name, local->channel);
- ret = -EBUSY;
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel);
- if (ret) {
- printk("%s: Channel setting to %d failed\n",
- dev->name, local->channel);
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT,
- local->beacon_int);
- if (ret) {
- printk("%s: Beacon interval setting to %d failed\n",
- dev->name, local->beacon_int);
- /* this may fail with Symbol/Lucent firmware */
- if (ret == -ETIMEDOUT)
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD,
- local->dtim_period);
- if (ret) {
- printk("%s: DTIM period setting to %d failed\n",
- dev->name, local->dtim_period);
- /* this may fail with Symbol/Lucent firmware */
- if (ret == -ETIMEDOUT)
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
- local->is_promisc);
- if (ret)
- printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n",
- dev->name, local->is_promisc);
-
- if (!local->fw_ap) {
- ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID,
- local->essid);
- if (ret) {
- printk("%s: Desired SSID setting failed\n", dev->name);
- goto fail;
- }
- }
-
- /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and
- * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic
- * rates */
- if (local->tx_rate_control == 0) {
- local->tx_rate_control =
- HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS |
- HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- }
- if (local->basic_rates == 0)
- local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS;
-
- if (!local->fw_ap) {
- ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
- local->tx_rate_control);
- if (ret) {
- printk("%s: TXRateControl setting to %d failed\n",
- dev->name, local->tx_rate_control);
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
- local->tx_rate_control);
- if (ret) {
- printk("%s: cnfSupportedRates setting to %d failed\n",
- dev->name, local->tx_rate_control);
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- local->basic_rates);
- if (ret) {
- printk("%s: cnfBasicRates setting to %d failed\n",
- dev->name, local->basic_rates);
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1);
- if (ret) {
- printk("%s: Create IBSS setting to 1 failed\n",
- dev->name);
- }
- }
-
- if (local->name_set)
- (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME,
- local->name);
-
- if (hostap_set_encryption(local)) {
- printk(KERN_INFO "%s: could not configure encryption\n",
- dev->name);
- }
-
- (void) hostap_set_antsel(local);
-
- if (hostap_set_roaming(local)) {
- printk(KERN_INFO "%s: could not set host roaming\n",
- dev->name);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) &&
- hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec))
- printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n",
- dev->name, local->enh_sec);
-
- /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently
- * not working correctly (last seven counters report bogus values).
- * This has been fixed in 0.8.2, so enable 32-bit tallies only
- * beginning with that firmware version. Another bug fix for 32-bit
- * tallies in 1.4.0; should 16-bit tallies be used for some other
- * versions, too? */
- if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) {
- if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) {
- printk(KERN_INFO "%s: cnfThirty2Tally setting "
- "failed\n", dev->name);
- local->tallies32 = 0;
- } else
- local->tallies32 = 1;
- } else
- local->tallies32 = 0;
-
- hostap_set_auth_algs(local);
-
- if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- local->fragm_threshold)) {
- printk(KERN_INFO "%s: setting FragmentationThreshold to %d "
- "failed\n", dev->name, local->fragm_threshold);
- }
-
- if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD,
- local->rts_threshold)) {
- printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n",
- dev->name, local->rts_threshold);
- }
-
- if (local->manual_retry_count >= 0 &&
- hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
- local->manual_retry_count)) {
- printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n",
- dev->name, local->manual_retry_count);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) &&
- hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) {
- local->rssi_to_dBm = le16_to_cpu(tmp);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa &&
- hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) {
- printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n",
- dev->name);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem &&
- hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT,
- local->generic_elem, local->generic_elem_len)) {
- printk(KERN_INFO "%s: setting genericElement failed\n",
- dev->name);
- }
-
- fail:
- return ret;
-}
-
-
-static int prism2_hw_init(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret, first = 1;
- unsigned long start, delay;
-
- PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n");
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits);
-
- init:
- /* initialize HFA 384x */
- ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0);
- if (ret) {
- printk(KERN_INFO "%s: first command failed - assuming card "
- "does not have primary firmware\n", dev_info);
- }
-
- if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
- /* EvStat has Cmd bit set in some cases, so retry once if no
- * wait was needed */
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: init command completed too quickly - "
- "retrying\n", dev->name);
- first = 0;
- goto init;
- }
-
- start = jiffies;
- delay = jiffies + HFA384X_INIT_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
- time_before(jiffies, delay))
- yield();
- if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
- printk(KERN_DEBUG "%s: assuming no Primary image in "
- "flash - card initialization not completed\n",
- dev_info);
- local->no_pri = 1;
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- if (local->sram_type == -1)
- local->sram_type = prism2_get_ram_size(local);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
- return 1;
- }
- local->no_pri = 0;
- printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n",
- (jiffies - start) * 1000 / HZ);
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- return 0;
-}
-
-
-static int prism2_hw_init2(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int i;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- kfree(local->pda);
- if (local->no_pri)
- local->pda = NULL;
- else
- local->pda = prism2_read_pda(dev);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- hfa384x_disable_interrupts(dev);
-
-#ifndef final_version
- HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF);
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
- printk("SWSUPPORT0 write/read failed: %04X != %04X\n",
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC);
- goto failed;
- }
-#endif
-
- if (initial || local->pri_only) {
- hfa384x_events_only_cmd(dev);
- /* get card version information */
- if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") ||
- prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) {
- hfa384x_disable_interrupts(dev);
- goto failed;
- }
-
- if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) {
- printk(KERN_DEBUG "%s: Failed to read STA f/w version "
- "- only Primary f/w present\n", dev->name);
- local->pri_only = 1;
- return 0;
- }
- local->pri_only = 0;
- hfa384x_disable_interrupts(dev);
- }
-
- /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and
- * enable interrupts before this. This would also require some sort of
- * sleeping AllocEv waiting */
-
- /* allocate TX FIDs */
- local->txfid_len = PRISM2_TXFID_LEN;
- for (i = 0; i < PRISM2_TXFID_COUNT; i++) {
- local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len);
- if (local->txfid[i] == 0xffff && local->txfid_len > 1600) {
- local->txfid[i] = hfa384x_allocate_fid(dev, 1600);
- if (local->txfid[i] != 0xffff) {
- printk(KERN_DEBUG "%s: Using shorter TX FID "
- "(1600 bytes)\n", dev->name);
- local->txfid_len = 1600;
- }
- }
- if (local->txfid[i] == 0xffff)
- goto failed;
- local->intransmitfid[i] = PRISM2_TXFID_EMPTY;
- }
-
- hfa384x_events_only_cmd(dev);
-
- if (initial) {
- u8 addr[ETH_ALEN] = {};
- struct list_head *ptr;
-
- prism2_check_sta_fw_version(local);
-
- if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR,
- addr, ETH_ALEN, 1) < 0) {
- printk("%s: could not get own MAC address\n",
- dev->name);
- }
- eth_hw_addr_set(dev, addr);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- eth_hw_addr_inherit(iface->dev, dev);
- }
- } else if (local->fw_ap)
- prism2_check_sta_fw_version(local);
-
- prism2_setup_rids(dev);
-
- /* MAC is now configured, but port 0 is not yet enabled */
- return 0;
-
- failed:
- if (!local->no_pri)
- printk(KERN_WARNING "%s: Initialization failed\n", dev_info);
- return 1;
-}
-
-
-static int prism2_hw_enable(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int was_resetting;
-
- iface = netdev_priv(dev);
- local = iface->local;
- was_resetting = local->hw_resetting;
-
- if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) {
- printk("%s: MAC port 0 enabling failed\n", dev->name);
- return 1;
- }
-
- local->hw_ready = 1;
- local->hw_reset_tries = 0;
- local->hw_resetting = 0;
- hfa384x_enable_interrupts(dev);
-
- /* at least D-Link DWL-650 seems to require additional port reset
- * before it starts acting as an AP, so reset port automatically
- * here just in case */
- if (initial && prism2_reset_port(dev)) {
- printk("%s: MAC port 0 resetting failed\n", dev->name);
- return 1;
- }
-
- if (was_resetting && netif_queue_stopped(dev)) {
- /* If hw_reset() was called during pending transmit, netif
- * queue was stopped. Wake it up now since the wlan card has
- * been resetted. */
- netif_wake_queue(dev);
- }
-
- return 0;
-}
-
-
-static int prism2_hw_config(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->hw_downloading)
- return 1;
-
- if (prism2_hw_init(dev, initial)) {
- return local->no_pri ? 0 : 1;
- }
-
- if (prism2_hw_init2(dev, initial))
- return 1;
-
- /* Enable firmware if secondary image is loaded and at least one of the
- * netdevices is up. */
- if (!local->pri_only &&
- (initial == 0 || (initial == 2 && local->num_dev_open > 0))) {
- if (!local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_ENABLE);
- local->dev_enabled = 1;
- return prism2_hw_enable(dev, initial);
- }
-
- return 0;
-}
-
-
-static void prism2_hw_shutdown(struct net_device *dev, int no_disable)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Allow only command completion events during disable */
- hfa384x_events_only_cmd(dev);
-
- local->hw_ready = 0;
- if (local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_DISABLE);
- local->dev_enabled = 0;
-
- if (local->func->card_present && !local->func->card_present(local)) {
- printk(KERN_DEBUG "%s: card already removed or not configured "
- "during shutdown\n", dev->name);
- return;
- }
-
- if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 &&
- hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL))
- printk(KERN_WARNING "%s: Shutdown failed\n", dev_info);
-
- hfa384x_disable_interrupts(dev);
-
- if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL)
- hfa384x_events_only_cmd(dev);
- else
- prism2_clear_cmd_queue(local);
-}
-
-
-static void prism2_hw_reset(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
-#if 0
- static long last_reset = 0;
-
- /* do not reset card more than once per second to avoid ending up in a
- * busy loop resetting the card */
- if (time_before_eq(jiffies, last_reset + HZ))
- return;
- last_reset = jiffies;
-#endif
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->hw_downloading)
- return;
-
- if (local->hw_resetting) {
- printk(KERN_WARNING "%s: %s: already resetting card - "
- "ignoring reset request\n", dev_info, dev->name);
- return;
- }
-
- local->hw_reset_tries++;
- if (local->hw_reset_tries > 10) {
- printk(KERN_WARNING "%s: too many reset tries, skipping\n",
- dev->name);
- return;
- }
-
- printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name);
- hfa384x_disable_interrupts(dev);
- local->hw_resetting = 1;
- if (local->func->cor_sreset) {
- /* Host system seems to hang in some cases with high traffic
- * load or shared interrupts during COR sreset. Disable shared
- * interrupts during reset to avoid these crashes. COS sreset
- * takes quite a long time, so it is unfortunate that this
- * seems to be needed. Anyway, I do not know of any better way
- * of avoiding the crash. */
- disable_irq(dev->irq);
- local->func->cor_sreset(local);
- enable_irq(dev->irq);
- }
- prism2_hw_shutdown(dev, 1);
- prism2_hw_config(dev, 0);
- local->hw_resetting = 0;
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- if (local->dl_pri) {
- printk(KERN_DEBUG "%s: persistent download of primary "
- "firmware\n", dev->name);
- if (prism2_download_genesis(local, local->dl_pri) < 0)
- printk(KERN_WARNING "%s: download (PRI) failed\n",
- dev->name);
- }
-
- if (local->dl_sec) {
- printk(KERN_DEBUG "%s: persistent download of secondary "
- "firmware\n", dev->name);
- if (prism2_download_volatile(local, local->dl_sec) < 0)
- printk(KERN_WARNING "%s: download (SEC) failed\n",
- dev->name);
- }
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- /* TODO: restore beacon TIM bits for STAs that have buffered frames */
-}
-
-
-static void prism2_schedule_reset(local_info_t *local)
-{
- schedule_work(&local->reset_queue);
-}
-
-
-/* Called only as scheduled task after noticing card timeout in interrupt
- * context */
-static void handle_reset_queue(struct work_struct *work)
-{
- local_info_t *local = container_of(work, local_info_t, reset_queue);
-
- printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);
- prism2_hw_reset(local->dev);
-
- if (netif_queue_stopped(local->dev)) {
- int i;
-
- for (i = 0; i < PRISM2_TXFID_COUNT; i++)
- if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) {
- PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: "
- "wake up queue\n");
- netif_wake_queue(local->dev);
- break;
- }
- }
-}
-
-
-static int prism2_get_txfid_idx(local_info_t *local)
-{
- int idx, end;
- unsigned long flags;
-
- spin_lock_irqsave(&local->txfidlock, flags);
- end = idx = local->next_txfid;
- do {
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
- local->intransmitfid[idx] = PRISM2_TXFID_RESERVED;
- spin_unlock_irqrestore(&local->txfidlock, flags);
- return idx;
- }
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != end);
- spin_unlock_irqrestore(&local->txfidlock, flags);
-
- PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "
- "packet dropped\n");
- local->dev->stats.tx_dropped++;
-
- return -1;
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_transmit_cb(struct net_device *dev, long context,
- u16 resp0, u16 res)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int idx = (int) context;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (res) {
- printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n",
- dev->name, res);
- return;
- }
-
- if (idx < 0 || idx >= PRISM2_TXFID_COUNT) {
- printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid "
- "idx=%d\n", dev->name, idx);
- return;
- }
-
- if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called "
- "with no pending transmit\n", dev->name);
- }
-
- if (netif_queue_stopped(dev)) {
- /* ready for next TX, so wake up queue that was stopped in
- * prism2_transmit() */
- netif_wake_queue(dev);
- }
-
- spin_lock(&local->txfidlock);
-
- /* With reclaim, Resp0 contains new txfid for transmit; the old txfid
- * will be automatically allocated for the next TX frame */
- local->intransmitfid[idx] = resp0;
-
- PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, "
- "resp0=0x%04x, transmit_txfid=0x%04x\n",
- dev->name, idx, local->txfid[idx],
- resp0, local->intransmitfid[local->next_txfid]);
-
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- local->next_txfid = idx;
-
- /* check if all TX buffers are occupied */
- do {
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
- spin_unlock(&local->txfidlock);
- return;
- }
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != local->next_txfid);
- spin_unlock(&local->txfidlock);
-
- /* no empty TX buffers, stop queue */
- netif_stop_queue(dev);
-}
-
-
-/* Called only from software IRQ if PCI bus master is not used (with bus master
- * this can be called both from software and hardware IRQ) */
-static int prism2_transmit(struct net_device *dev, int idx)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* The driver tries to stop netif queue so that there would not be
- * more than one attempt to transmit frames going on; check that this
- * is really the case */
-
- if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called "
- "when previous TX was pending\n", dev->name);
- return -1;
- }
-
- /* stop the queue for the time that transmit is pending */
- netif_stop_queue(dev);
-
- /* transmit packet */
- res = hfa384x_cmd_callback(
- dev,
- HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM,
- local->txfid[idx],
- prism2_transmit_cb, (long) idx);
-
- if (res) {
- printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "
- "failed (res=%d)\n", dev->name, res);
- dev->stats.tx_dropped++;
- netif_wake_queue(dev);
- return -1;
- }
- netif_trans_update(dev);
-
- /* Since we did not wait for command completion, the card continues
- * to process on the background and we will finish handling when
- * command completion event is handled (prism2_cmd_ev() function) */
-
- return 0;
-}
-
-
-/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and
- * send the payload with this descriptor) */
-/* Called only from software IRQ */
-static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_tx_frame txdesc;
- struct hostap_skb_tx_data *meta;
- int hdr_len, data_len, idx, res, ret = -1;
- u16 tx_control;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
-
- prism2_callback(local, PRISM2_CALLBACK_TX_START);
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- !local->hw_ready || local->hw_downloading || local->pri_only) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -"
- " skipping\n", dev->name);
- }
- goto fail;
- }
-
- memset(&txdesc, 0, sizeof(txdesc));
-
- /* skb->data starts with txdesc->frame_control */
- hdr_len = sizeof(txdesc.header);
- BUILD_BUG_ON(hdr_len != 24);
- skb_copy_from_linear_data(skb, &txdesc.header, hdr_len);
- if (ieee80211_is_data(txdesc.frame_control) &&
- ieee80211_has_a4(txdesc.frame_control) &&
- skb->len >= 30) {
- /* Addr4 */
- skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4,
- ETH_ALEN);
- hdr_len += ETH_ALEN;
- }
-
- tx_control = local->tx_control;
- if (meta->tx_cb_idx) {
- tx_control |= HFA384X_TX_CTRL_TX_OK;
- txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx);
- }
- txdesc.tx_control = cpu_to_le16(tx_control);
- txdesc.tx_rate = meta->rate;
-
- data_len = skb->len - hdr_len;
- txdesc.data_len = cpu_to_le16(data_len);
- txdesc.len = cpu_to_be16(data_len);
-
- idx = prism2_get_txfid_idx(local);
- if (idx < 0)
- goto fail;
-
- if (local->frame_dump & PRISM2_DUMP_TX_HDR)
- hostap_dump_tx_header(dev->name, &txdesc);
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0);
-
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc));
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len,
- skb->len - hdr_len);
- spin_unlock(&local->baplock);
-
- if (!res)
- res = prism2_transmit(dev, idx);
- if (res) {
- printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n",
- dev->name);
- local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
- schedule_work(&local->reset_queue);
- goto fail;
- }
-
- ret = 0;
-
-fail:
- prism2_callback(local, PRISM2_CALLBACK_TX_END);
- return ret;
-}
-
-
-/* Some SMP systems have reported number of odd errors with hostap_pci. fid
- * register has changed values between consecutive reads for an unknown reason.
- * This should really not happen, so more debugging is needed. This test
- * version is a bit slower, but it will detect most of such register changes
- * and will try to get the correct fid eventually. */
-#define EXTRA_FID_READ_TESTS
-
-static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
-{
-#ifdef EXTRA_FID_READ_TESTS
- u16 val, val2, val3;
- int i;
-
- for (i = 0; i < 10; i++) {
- val = HFA384X_INW(reg);
- val2 = HFA384X_INW(reg);
- val3 = HFA384X_INW(reg);
-
- if (val == val2 && val == val3)
- return val;
-
- printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):"
- " %04x %04x %04x\n",
- dev->name, i, reg, val, val2, val3);
- if ((val == val2 || val == val3) && val != 0)
- return val;
- if (val2 == val3 && val2 != 0)
- return val2;
- }
- printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg "
- "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3);
- return val;
-#else /* EXTRA_FID_READ_TESTS */
- return HFA384X_INW(reg);
-#endif /* EXTRA_FID_READ_TESTS */
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_rx(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- int res, rx_pending = 0;
- u16 len, hdr_len, rxfid, status, macport;
- struct hfa384x_rx_frame rxdesc;
- struct sk_buff *skb = NULL;
-
- prism2_callback(local, PRISM2_CALLBACK_RX_START);
-
- rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);
-#ifndef final_version
- if (rxfid == 0) {
- rxfid = HFA384X_INW(HFA384X_RXFID_OFF);
- printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n",
- rxfid);
- if (rxfid == 0) {
- schedule_work(&local->reset_queue);
- goto rx_dropped;
- }
- /* try to continue with the new rxfid value */
- }
-#endif
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, rxfid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc));
-
- if (res) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name,
- res);
- if (res == -ETIMEDOUT) {
- schedule_work(&local->reset_queue);
- }
- goto rx_dropped;
- }
-
- len = le16_to_cpu(rxdesc.data_len);
- hdr_len = sizeof(rxdesc);
- status = le16_to_cpu(rxdesc.status);
- macport = (status >> 8) & 0x07;
-
- /* Drop frames with too large reported payload length. Monitor mode
- * seems to sometimes pass frames (e.g., ctrl::ack) with signed and
- * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for
- * macport 7 */
- if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {
- if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {
- if (len >= (u16) -14) {
- hdr_len -= 65535 - len;
- hdr_len--;
- }
- len = 0;
- } else {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Received frame with invalid "
- "length 0x%04x\n", dev->name, len);
- hostap_dump_rx_header(dev->name, &rxdesc);
- goto rx_dropped;
- }
- }
-
- skb = dev_alloc_skb(len + hdr_len);
- if (!skb) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: RX failed to allocate skb\n",
- dev->name);
- goto rx_dropped;
- }
- skb->dev = dev;
- skb_put_data(skb, &rxdesc, hdr_len);
-
- if (len > 0)
- res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len);
- spin_unlock(&local->baplock);
- if (res) {
- printk(KERN_DEBUG "%s: RX failed to read "
- "frame data\n", dev->name);
- goto rx_dropped;
- }
-
- skb_queue_tail(&local->rx_list, skb);
- tasklet_schedule(&local->rx_tasklet);
-
- rx_exit:
- prism2_callback(local, PRISM2_CALLBACK_RX_END);
- if (!rx_pending) {
- HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF);
- }
-
- return;
-
- rx_dropped:
- dev->stats.rx_dropped++;
- if (skb)
- dev_kfree_skb(skb);
- goto rx_exit;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
-{
- struct hfa384x_rx_frame *rxdesc;
- struct net_device *dev = skb->dev;
- struct hostap_80211_rx_status stats;
- int hdrlen, rx_hdrlen;
-
- rx_hdrlen = sizeof(*rxdesc);
- if (skb->len < sizeof(*rxdesc)) {
- /* Allow monitor mode to receive shorter frames */
- if (local->iw_mode == IW_MODE_MONITOR &&
- skb->len >= sizeof(*rxdesc) - 30) {
- rx_hdrlen = skb->len;
- } else {
- dev_kfree_skb(skb);
- return;
- }
- }
-
- rxdesc = (struct hfa384x_rx_frame *) skb->data;
-
- if (local->frame_dump & PRISM2_DUMP_RX_HDR &&
- skb->len >= sizeof(*rxdesc))
- hostap_dump_rx_header(dev->name, rxdesc);
-
- if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&
- (!local->monitor_allow_fcserr ||
- local->iw_mode != IW_MODE_MONITOR))
- goto drop;
-
- if (skb->len > PRISM2_DATA_MAXLEN) {
- printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n",
- dev->name, skb->len, PRISM2_DATA_MAXLEN);
- goto drop;
- }
-
- stats.mac_time = le32_to_cpu(rxdesc->time);
- stats.signal = rxdesc->signal - local->rssi_to_dBm;
- stats.noise = rxdesc->silence - local->rssi_to_dBm;
- stats.rate = rxdesc->rate;
-
- /* Convert Prism2 RX structure into IEEE 802.11 header */
- hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control);
- if (hdrlen > rx_hdrlen)
- hdrlen = rx_hdrlen;
-
- memmove(skb_pull(skb, rx_hdrlen - hdrlen),
- &rxdesc->frame_control, hdrlen);
-
- hostap_80211_rx(dev, skb, &stats);
- return;
-
- drop:
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_rx_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, rx_tasklet);
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&local->rx_list)) != NULL)
- hostap_rx_skb(local, skb);
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_alloc_ev(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int idx;
- u16 fid;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF);
-
- PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid);
-
- spin_lock(&local->txfidlock);
- idx = local->next_alloc;
-
- do {
- if (local->txfid[idx] == fid) {
- PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n",
- idx);
-
-#ifndef final_version
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY)
- printk("Already released txfid found at idx "
- "%d\n", idx);
- if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED)
- printk("Already reserved txfid found at idx "
- "%d\n", idx);
-#endif
- local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
- idx++;
- local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 :
- idx;
-
- if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) &&
- netif_queue_stopped(dev))
- netif_wake_queue(dev);
-
- spin_unlock(&local->txfidlock);
- return;
- }
-
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != local->next_alloc);
-
- printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new "
- "read 0x%04x) for alloc event\n", dev->name, fid,
- HFA384X_INW(HFA384X_ALLOCFID_OFF));
- printk(KERN_DEBUG "TXFIDs:");
- for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++)
- printk(" %04x[%04x]", local->txfid[idx],
- local->intransmitfid[idx]);
- printk("\n");
- spin_unlock(&local->txfidlock);
-
- /* FIX: should probably schedule reset; reference to one txfid was lost
- * completely.. Bad things will happen if we run out of txfids
- * Actually, this will cause netdev watchdog to notice TX timeout and
- * then card reset after all txfids have been leaked. */
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_tx_callback(local_info_t *local,
- struct hfa384x_tx_frame *txdesc, int ok,
- char *payload)
-{
- u16 sw_support, hdrlen, len;
- struct sk_buff *skb;
- struct hostap_tx_callback_info *cb;
-
- /* Make sure that frame was from us. */
- if (!ether_addr_equal(txdesc->addr2, local->dev->dev_addr)) {
- printk(KERN_DEBUG "%s: TX callback - foreign frame\n",
- local->dev->name);
- return;
- }
-
- sw_support = le32_to_cpu(txdesc->sw_support);
-
- spin_lock(&local->lock);
- cb = local->tx_callback;
- while (cb != NULL && cb->idx != sw_support)
- cb = cb->next;
- spin_unlock(&local->lock);
-
- if (cb == NULL) {
- printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n",
- local->dev->name, sw_support);
- return;
- }
-
- hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control);
- len = le16_to_cpu(txdesc->data_len);
- skb = dev_alloc_skb(hdrlen + len);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate "
- "skb\n", local->dev->name);
- return;
- }
-
- skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen);
- if (payload)
- skb_put_data(skb, payload, len);
-
- skb->dev = local->dev;
- skb_reset_mac_header(skb);
-
- cb->func(skb, ok, cb->data);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int hostap_tx_compl_read(local_info_t *local, int error,
- struct hfa384x_tx_frame *txdesc,
- char **payload)
-{
- u16 fid, len;
- int res, ret = 0;
- struct net_device *dev = local->dev;
-
- fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF);
-
- PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error);
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, fid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc));
- if (res) {
- PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not "
- "read txdesc\n", dev->name, error, fid);
- if (res == -ETIMEDOUT) {
- schedule_work(&local->reset_queue);
- }
- ret = -1;
- goto fail;
- }
- if (txdesc->sw_support) {
- len = le16_to_cpu(txdesc->data_len);
- if (len < PRISM2_DATA_MAXLEN) {
- *payload = kmalloc(len, GFP_ATOMIC);
- if (*payload == NULL ||
- hfa384x_from_bap(dev, BAP0, *payload, len)) {
- PDEBUG(DEBUG_EXTRA, "%s: could not read TX "
- "frame payload\n", dev->name);
- kfree(*payload);
- *payload = NULL;
- ret = -1;
- goto fail;
- }
- }
- }
-
- fail:
- spin_unlock(&local->baplock);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_tx_ev(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- char *payload = NULL;
- struct hfa384x_tx_frame txdesc;
-
- if (hostap_tx_compl_read(local, 0, &txdesc, &payload))
- goto fail;
-
- if (local->frame_dump & PRISM2_DUMP_TX_HDR) {
- PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x "
- "retry_count=%d tx_rate=%d seq_ctrl=%d "
- "duration_id=%d\n",
- dev->name, le16_to_cpu(txdesc.status),
- txdesc.retry_count, txdesc.tx_rate,
- le16_to_cpu(txdesc.seq_ctrl),
- le16_to_cpu(txdesc.duration_id));
- }
-
- if (txdesc.sw_support)
- hostap_tx_callback(local, &txdesc, 1, payload);
- kfree(payload);
-
- fail:
- HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_sta_tx_exc_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, sta_tx_exc_tasklet);
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) {
- struct hfa384x_tx_frame *txdesc =
- (struct hfa384x_tx_frame *) skb->data;
-
- if (skb->len >= sizeof(*txdesc)) {
- /* Convert Prism2 RX structure into IEEE 802.11 header
- */
- int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control);
- memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen),
- &txdesc->frame_control, hdrlen);
-
- hostap_handle_sta_tx_exc(local, skb);
- }
- dev_kfree_skb(skb);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_txexc(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- u16 status, fc;
- int show_dump, res;
- char *payload = NULL;
- struct hfa384x_tx_frame txdesc;
-
- show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
- dev->stats.tx_errors++;
-
- res = hostap_tx_compl_read(local, 1, &txdesc, &payload);
- HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF);
- if (res)
- return;
-
- status = le16_to_cpu(txdesc.status);
-
- /* We produce a TXDROP event only for retry or lifetime
- * exceeded, because that's the only status that really mean
- * that this particular node went away.
- * Other errors means that *we* screwed up. - Jean II */
- if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR))
- {
- union iwreq_data wrqu;
-
- /* Copy 802.11 dest address. */
- memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
- } else
- show_dump = 1;
-
- if (local->iw_mode == IW_MODE_MASTER ||
- local->iw_mode == IW_MODE_REPEAT ||
- local->wds_type & HOSTAP_WDS_AP_CLIENT) {
- struct sk_buff *skb;
- skb = dev_alloc_skb(sizeof(txdesc));
- if (skb) {
- skb_put_data(skb, &txdesc, sizeof(txdesc));
- skb_queue_tail(&local->sta_tx_exc_list, skb);
- tasklet_schedule(&local->sta_tx_exc_tasklet);
- }
- }
-
- if (txdesc.sw_support)
- hostap_tx_callback(local, &txdesc, 0, payload);
- kfree(payload);
-
- if (!show_dump)
- return;
-
- PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)"
- " tx_control=%04x\n",
- dev->name, status,
- status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "",
- status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "",
- status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "",
- status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "",
- le16_to_cpu(txdesc.tx_control));
-
- fc = le16_to_cpu(txdesc.frame_control);
- PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x "
- "(%s%s%s::%d%s%s)\n",
- txdesc.retry_count, txdesc.tx_rate, fc,
- ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "",
- ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "",
- ieee80211_is_data(txdesc.frame_control) ? "Data" : "",
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "",
- ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : "");
- PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n",
- txdesc.addr1, txdesc.addr2,
- txdesc.addr3, txdesc.addr4);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_info_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, info_tasklet);
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&local->info_list)) != NULL) {
- hostap_info_process(local, skb);
- dev_kfree_skb(skb);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- u16 fid;
- int res, left;
- struct hfa384x_info_frame info;
- struct sk_buff *skb;
-
- fid = HFA384X_INW(HFA384X_INFOFID_OFF);
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, fid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info));
- if (res) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n",
- fid);
- if (res == -ETIMEDOUT) {
- schedule_work(&local->reset_queue);
- }
- goto out;
- }
-
- left = (le16_to_cpu(info.len) - 1) * 2;
-
- if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) {
- /* data register seems to give 0x8000 in some error cases even
- * though busy bit is not set in offset register;
- * in addition, length must be at least 1 due to type field */
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Received info frame with invalid "
- "length 0x%04x (type 0x%04x)\n", dev->name,
- le16_to_cpu(info.len), le16_to_cpu(info.type));
- goto out;
- }
-
- skb = dev_alloc_skb(sizeof(info) + left);
- if (skb == NULL) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Could not allocate skb for info "
- "frame\n", dev->name);
- goto out;
- }
-
- skb_put_data(skb, &info, sizeof(info));
- if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left))
- {
- spin_unlock(&local->baplock);
- printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, "
- "len=0x%04x, type=0x%04x\n", dev->name, fid,
- le16_to_cpu(info.len), le16_to_cpu(info.type));
- dev_kfree_skb(skb);
- goto out;
- }
- spin_unlock(&local->baplock);
-
- skb_queue_tail(&local->info_list, skb);
- tasklet_schedule(&local->info_tasklet);
-
- out:
- HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_bap_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, bap_tasklet);
- struct net_device *dev = local->dev;
- u16 ev;
- int frames = 30;
-
- if (local->func->card_present && !local->func->card_present(local))
- return;
-
- set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
-
- /* Process all pending BAP events without generating new interrupts
- * for them */
- while (frames-- > 0) {
- ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
- if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS))
- break;
- if (ev & HFA384X_EV_RX)
- prism2_rx(local);
- if (ev & HFA384X_EV_INFO)
- prism2_info(local);
- if (ev & HFA384X_EV_TX)
- prism2_tx_ev(local);
- if (ev & HFA384X_EV_TXEXC)
- prism2_txexc(local);
- }
-
- set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
- clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
-
- /* Enable interrupts for new BAP events */
- hfa384x_events_all(dev);
- clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_infdrop(struct net_device *dev)
-{
- static unsigned long last_inquire = 0;
-
- PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name);
-
- /* some firmware versions seem to get stuck with
- * full CommTallies in high traffic load cases; every
- * packet will then cause INFDROP event and CommTallies
- * info frame will not be sent automatically. Try to
- * get out of this state by inquiring CommTallies. */
- if (!last_inquire || time_after(jiffies, last_inquire + HZ)) {
- hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE,
- HFA384X_INFO_COMMTALLIES, NULL, 0);
- last_inquire = jiffies;
- }
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_ev_tick(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u16 evstat, inten;
- static int prev_stuck = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (time_after(jiffies, local->last_tick_timer + 5 * HZ) &&
- local->last_tick_timer) {
- evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
- inten = HFA384X_INW(HFA384X_INTEN_OFF);
- if (!prev_stuck) {
- printk(KERN_INFO "%s: SW TICK stuck? "
- "bits=0x%lx EvStat=%04x IntEn=%04x\n",
- dev->name, local->bits, evstat, inten);
- }
- local->sw_tick_stuck++;
- if ((evstat & HFA384X_BAP0_EVENTS) &&
- (inten & HFA384X_BAP0_EVENTS)) {
- printk(KERN_INFO "%s: trying to recover from IRQ "
- "hang\n", dev->name);
- hfa384x_events_no_bap0(dev);
- }
- prev_stuck = 1;
- } else
- prev_stuck = 0;
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_check_magic(local_info_t *local)
-{
- /* at least PCI Prism2.5 with bus mastering seems to sometimes
- * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the
- * register once or twice seems to get the correct value.. PCI cards
- * cannot anyway be removed during normal operation, so there is not
- * really any need for this verification with them. */
-
-#ifndef PRISM2_PCI
-#ifndef final_version
- static unsigned long last_magic_err = 0;
- struct net_device *dev = local->dev;
-
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
- if (!local->hw_ready)
- return;
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- if (time_after(jiffies, last_magic_err + 10 * HZ)) {
- printk("%s: Interrupt, but SWSUPPORT0 does not match: "
- "%04X != %04X - card removed?\n", dev->name,
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
- HFA384X_MAGIC);
- last_magic_err = jiffies;
- } else if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x "
- "MAGIC=%04x\n", dev->name,
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
- HFA384X_MAGIC);
- }
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff)
- schedule_work(&local->reset_queue);
- return;
- }
-#endif /* final_version */
-#endif /* !PRISM2_PCI */
-}
-
-
-/* Called only from hardware IRQ */
-static irqreturn_t prism2_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct hostap_interface *iface;
- local_info_t *local;
- int events = 0;
- u16 ev;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Detect early interrupt before driver is fully configured */
- spin_lock(&local->irq_init_lock);
- if (!dev->base_addr) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
- dev->name);
- }
- spin_unlock(&local->irq_init_lock);
- return IRQ_HANDLED;
- }
- spin_unlock(&local->irq_init_lock);
-
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
-
- if (local->func->card_present && !local->func->card_present(local)) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n",
- dev->name);
- }
- return IRQ_HANDLED;
- }
-
- prism2_check_magic(local);
-
- for (;;) {
- ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
- if (ev == 0xffff) {
- if (local->shutdown)
- return IRQ_HANDLED;
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n",
- dev->name);
- return IRQ_HANDLED;
- }
-
- ev &= HFA384X_INW(HFA384X_INTEN_OFF);
- if (ev == 0)
- break;
-
- if (ev & HFA384X_EV_CMD) {
- prism2_cmd_ev(dev);
- }
-
- /* Above events are needed even before hw is ready, but other
- * events should be skipped during initialization. This may
- * change for AllocEv if allocate_fid is implemented without
- * busy waiting. */
- if (!local->hw_ready || local->hw_resetting ||
- !local->dev_enabled) {
- ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
- if (ev & HFA384X_EV_CMD)
- goto next_event;
- if ((ev & HFA384X_EVENT_MASK) == 0)
- return IRQ_HANDLED;
- if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) &&
- net_ratelimit()) {
- printk(KERN_DEBUG "%s: prism2_interrupt: hw "
- "not ready; skipping events 0x%04x "
- "(IntEn=0x%04x)%s%s%s\n",
- dev->name, ev,
- HFA384X_INW(HFA384X_INTEN_OFF),
- !local->hw_ready ? " (!hw_ready)" : "",
- local->hw_resetting ?
- " (hw_resetting)" : "",
- !local->dev_enabled ?
- " (!dev_enabled)" : "");
- }
- HFA384X_OUTW(ev, HFA384X_EVACK_OFF);
- return IRQ_HANDLED;
- }
-
- if (ev & HFA384X_EV_TICK) {
- prism2_ev_tick(dev);
- HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF);
- }
-
- if (ev & HFA384X_EV_ALLOC) {
- prism2_alloc_ev(dev);
- HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
- }
-
- /* Reading data from the card is quite time consuming, so do it
- * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed
- * and unmasked after needed data has been read completely. */
- if (ev & HFA384X_BAP0_EVENTS) {
- hfa384x_events_no_bap0(dev);
- tasklet_schedule(&local->bap_tasklet);
- }
-
-#ifndef final_version
- if (ev & HFA384X_EV_WTERR) {
- PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name);
- HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF);
- }
-#endif /* final_version */
-
- if (ev & HFA384X_EV_INFDROP) {
- prism2_infdrop(dev);
- HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF);
- }
-
- next_event:
- events++;
- if (events >= PRISM2_MAX_INTERRUPT_EVENTS) {
- PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events "
- "(EvStat=0x%04x)\n",
- PRISM2_MAX_INTERRUPT_EVENTS,
- HFA384X_INW(HFA384X_EVSTAT_OFF));
- break;
- }
- }
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1);
- return IRQ_RETVAL(events);
-}
-
-
-static void prism2_check_sta_fw_version(local_info_t *local)
-{
- struct hfa384x_comp_ident comp;
- int id, variant, major, minor;
-
- if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID,
- &comp, sizeof(comp), 1) < 0)
- return;
-
- local->fw_ap = 0;
- id = le16_to_cpu(comp.id);
- if (id != HFA384X_COMP_ID_STA) {
- if (id == HFA384X_COMP_ID_FW_AP)
- local->fw_ap = 1;
- return;
- }
-
- major = __le16_to_cpu(comp.major);
- minor = __le16_to_cpu(comp.minor);
- variant = __le16_to_cpu(comp.variant);
- local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant);
-
- /* Station firmware versions before 1.4.x seem to have a bug in
- * firmware-based WEP encryption when using Host AP mode, so use
- * host_encrypt as a default for them. Firmware version 1.4.9 is the
- * first one that has been seen to produce correct encryption, but the
- * bug might be fixed before that (although, at least 1.4.2 is broken).
- */
- local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9);
-
- if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
- !local->fw_encrypt_ok) {
- printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
- "a workaround for firmware bug in Host AP mode WEP\n",
- local->dev->name);
- local->host_encrypt = 1;
- }
-
- /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken
- * in station firmware versions before 1.5.x. With these versions, the
- * driver uses a workaround with bogus frame format (4th address after
- * the payload). This is not compatible with other AP devices. Since
- * the firmware bug is fixed in the latest station firmware versions,
- * automatically enable standard compliant mode for cards using station
- * firmware version 1.5.0 or newer. */
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0))
- local->wds_type |= HOSTAP_WDS_STANDARD_FRAME;
- else {
- printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a "
- "workaround for firmware bug in Host AP mode WDS\n",
- local->dev->name);
- }
-
- hostap_check_sta_fw_version(local->ap, local->sta_fw_ver);
-}
-
-
-static void hostap_passive_scan(struct timer_list *t)
-{
- local_info_t *local = from_timer(local, t, passive_scan_timer);
- struct net_device *dev = local->dev;
- u16 chan;
-
- if (local->passive_scan_interval <= 0)
- return;
-
- if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) {
- int max_tries = 16;
-
- /* Even though host system does not really know when the WLAN
- * MAC is sending frames, try to avoid changing channels for
- * passive scanning when a host-generated frame is being
- * transmitted */
- if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: passive scan detected pending "
- "TX - delaying\n", dev->name);
- local->passive_scan_timer.expires = jiffies + HZ / 10;
- add_timer(&local->passive_scan_timer);
- return;
- }
-
- do {
- local->passive_scan_channel++;
- if (local->passive_scan_channel > 14)
- local->passive_scan_channel = 1;
- max_tries--;
- } while (!(local->channel_mask &
- (1 << (local->passive_scan_channel - 1))) &&
- max_tries > 0);
-
- if (max_tries == 0) {
- printk(KERN_INFO "%s: no allowed passive scan channels"
- " found\n", dev->name);
- return;
- }
-
- printk(KERN_DEBUG "%s: passive scan channel %d\n",
- dev->name, local->passive_scan_channel);
- chan = local->passive_scan_channel;
- local->passive_scan_state = PASSIVE_SCAN_WAIT;
- local->passive_scan_timer.expires = jiffies + HZ / 10;
- } else {
- chan = local->channel;
- local->passive_scan_state = PASSIVE_SCAN_LISTEN;
- local->passive_scan_timer.expires = jiffies +
- local->passive_scan_interval * HZ;
- }
-
- if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CHANGE_CHANNEL << 8),
- chan, NULL, 0))
- printk(KERN_ERR "%s: passive scan channel set %d "
- "failed\n", dev->name, chan);
-
- add_timer(&local->passive_scan_timer);
-}
-
-
-/* Called only as a scheduled task when communications quality values should
- * be updated. */
-static void handle_comms_qual_update(struct work_struct *work)
-{
- local_info_t *local =
- container_of(work, local_info_t, comms_qual_update);
- prism2_update_comms_qual(local->dev);
-}
-
-
-/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is
- * used to monitor that local->last_tick_timer is being updated. If not,
- * interrupt busy-loop is assumed and driver tries to recover by masking out
- * some events. */
-static void hostap_tick_timer(struct timer_list *t)
-{
- static unsigned long last_inquire = 0;
- local_info_t *local = from_timer(local, t, tick_timer);
- local->last_tick_timer = jiffies;
-
- /* Inquire CommTallies every 10 seconds to keep the statistics updated
- * more often during low load and when using 32-bit tallies. */
- if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) &&
- !local->hw_downloading && local->hw_ready &&
- !local->hw_resetting && local->dev_enabled) {
- hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE,
- HFA384X_INFO_COMMTALLIES, NULL, 0);
- last_inquire = jiffies;
- }
-
- if ((local->last_comms_qual_update == 0 ||
- time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) &&
- (local->iw_mode == IW_MODE_INFRA ||
- local->iw_mode == IW_MODE_ADHOC)) {
- schedule_work(&local->comms_qual_update);
- }
-
- local->tick_timer.expires = jiffies + 2 * HZ;
- add_timer(&local->tick_timer);
-}
-
-
-#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS)
-static u16 hfa384x_read_reg(struct net_device *dev, u16 reg)
-{
- return HFA384X_INW(reg);
-}
-
-static int prism2_registers_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
-
-#define SHOW_REG(n) \
- seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
-
- SHOW_REG(CMD);
- SHOW_REG(PARAM0);
- SHOW_REG(PARAM1);
- SHOW_REG(PARAM2);
- SHOW_REG(STATUS);
- SHOW_REG(RESP0);
- SHOW_REG(RESP1);
- SHOW_REG(RESP2);
- SHOW_REG(INFOFID);
- SHOW_REG(CONTROL);
- SHOW_REG(SELECT0);
- SHOW_REG(SELECT1);
- SHOW_REG(OFFSET0);
- SHOW_REG(OFFSET1);
- SHOW_REG(RXFID);
- SHOW_REG(ALLOCFID);
- SHOW_REG(TXCOMPLFID);
- SHOW_REG(SWSUPPORT0);
- SHOW_REG(SWSUPPORT1);
- SHOW_REG(SWSUPPORT2);
- SHOW_REG(EVSTAT);
- SHOW_REG(INTEN);
- SHOW_REG(EVACK);
- /* Do not read data registers, because they change the state of the
- * MAC (offset += 2) */
- /* SHOW_REG(DATA0); */
- /* SHOW_REG(DATA1); */
- SHOW_REG(AUXPAGE);
- SHOW_REG(AUXOFFSET);
- /* SHOW_REG(AUXDATA); */
-#ifdef PRISM2_PCI
- SHOW_REG(PCICOR);
- SHOW_REG(PCIHCR);
- SHOW_REG(PCI_M0_ADDRH);
- SHOW_REG(PCI_M0_ADDRL);
- SHOW_REG(PCI_M0_LEN);
- SHOW_REG(PCI_M0_CTL);
- SHOW_REG(PCI_STATUS);
- SHOW_REG(PCI_M1_ADDRH);
- SHOW_REG(PCI_M1_ADDRL);
- SHOW_REG(PCI_M1_LEN);
- SHOW_REG(PCI_M1_CTL);
-#endif /* PRISM2_PCI */
-
- return 0;
-}
-#endif
-
-struct set_tim_data {
- struct list_head list;
- int aid;
- int set;
-};
-
-static int prism2_set_tim(struct net_device *dev, int aid, int set)
-{
- struct list_head *ptr;
- struct set_tim_data *new_entry;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
- if (new_entry == NULL)
- return -ENOMEM;
-
- new_entry->aid = aid;
- new_entry->set = set;
-
- spin_lock_bh(&local->set_tim_lock);
- list_for_each(ptr, &local->set_tim_list) {
- struct set_tim_data *entry =
- list_entry(ptr, struct set_tim_data, list);
- if (entry->aid == aid) {
- PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d "
- "set=%d ==> %d\n",
- local->dev->name, aid, entry->set, set);
- entry->set = set;
- kfree(new_entry);
- new_entry = NULL;
- break;
- }
- }
- if (new_entry)
- list_add_tail(&new_entry->list, &local->set_tim_list);
- spin_unlock_bh(&local->set_tim_lock);
-
- schedule_work(&local->set_tim_queue);
-
- return 0;
-}
-
-
-static void handle_set_tim_queue(struct work_struct *work)
-{
- local_info_t *local = container_of(work, local_info_t, set_tim_queue);
- struct set_tim_data *entry;
- u16 val;
-
- for (;;) {
- entry = NULL;
- spin_lock_bh(&local->set_tim_lock);
- if (!list_empty(&local->set_tim_list)) {
- entry = list_entry(local->set_tim_list.next,
- struct set_tim_data, list);
- list_del(&entry->list);
- }
- spin_unlock_bh(&local->set_tim_lock);
- if (!entry)
- break;
-
- PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n",
- local->dev->name, entry->aid, entry->set);
-
- val = entry->aid;
- if (entry->set)
- val |= 0x8000;
- if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) {
- printk(KERN_DEBUG "%s: set_tim failed (aid=%d "
- "set=%d)\n",
- local->dev->name, entry->aid, entry->set);
- }
-
- kfree(entry);
- }
-}
-
-
-static void prism2_clear_set_tim_queue(local_info_t *local)
-{
- struct list_head *ptr, *n;
-
- list_for_each_safe(ptr, n, &local->set_tim_list) {
- struct set_tim_data *entry;
- entry = list_entry(ptr, struct set_tim_data, list);
- list_del(&entry->list);
- kfree(entry);
- }
-}
-
-
-/*
- * HostAP uses two layers of net devices, where the inner
- * layer gets called all the time from the outer layer.
- * This is a natural nesting, which needs a split lock type.
- */
-static struct lock_class_key hostap_netdev_xmit_lock_key;
-static struct lock_class_key hostap_netdev_addr_lock_key;
-
-static void prism2_set_lockdep_class_one(struct net_device *dev,
- struct netdev_queue *txq,
- void *_unused)
-{
- lockdep_set_class(&txq->_xmit_lock,
- &hostap_netdev_xmit_lock_key);
-}
-
-static void prism2_set_lockdep_class(struct net_device *dev)
-{
- lockdep_set_class(&dev->addr_list_lock,
- &hostap_netdev_addr_lock_key);
- netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL);
-}
-
-static struct net_device *
-prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
- struct device *sdev)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- struct local_info *local;
- int len, i, ret;
-
- if (funcs == NULL)
- return NULL;
-
- len = strlen(dev_template);
- if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) {
- printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n",
- dev_template);
- return NULL;
- }
-
- len = sizeof(struct hostap_interface) +
- 3 + sizeof(struct local_info) +
- 3 + sizeof(struct ap_data);
-
- dev = alloc_etherdev(len);
- if (dev == NULL)
- return NULL;
-
- iface = netdev_priv(dev);
- local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3);
- local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3);
- local->dev = iface->dev = dev;
- iface->local = local;
- iface->type = HOSTAP_INTERFACE_MASTER;
- INIT_LIST_HEAD(&local->hostap_interfaces);
-
- local->hw_module = THIS_MODULE;
-
-#ifdef PRISM2_IO_DEBUG
- local->io_debug_enabled = 1;
-#endif /* PRISM2_IO_DEBUG */
-
- local->func = funcs;
- local->func->cmd = hfa384x_cmd;
- local->func->read_regs = hfa384x_read_regs;
- local->func->get_rid = hfa384x_get_rid;
- local->func->set_rid = hfa384x_set_rid;
- local->func->hw_enable = prism2_hw_enable;
- local->func->hw_config = prism2_hw_config;
- local->func->hw_reset = prism2_hw_reset;
- local->func->hw_shutdown = prism2_hw_shutdown;
- local->func->reset_port = prism2_reset_port;
- local->func->schedule_reset = prism2_schedule_reset;
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- local->func->read_aux_proc_ops = &prism2_download_aux_dump_proc_ops;
- local->func->download = prism2_download;
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
- local->func->tx = prism2_tx_80211;
- local->func->set_tim = prism2_set_tim;
- local->func->need_tx_headroom = 0; /* no need to add txdesc in
- * skb->data (FIX: maybe for DMA bus
- * mastering? */
-
- local->mtu = mtu;
-
- rwlock_init(&local->iface_lock);
- spin_lock_init(&local->txfidlock);
- spin_lock_init(&local->cmdlock);
- spin_lock_init(&local->baplock);
- spin_lock_init(&local->lock);
- spin_lock_init(&local->irq_init_lock);
- mutex_init(&local->rid_bap_mtx);
-
- if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
- card_idx = 0;
- local->card_idx = card_idx;
-
- len = strlen(essid);
- memcpy(local->essid, essid,
- len > MAX_SSID_LEN ? MAX_SSID_LEN : len);
- local->essid[MAX_SSID_LEN] = '\0';
- i = GET_INT_PARM(iw_mode, card_idx);
- if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) ||
- i == IW_MODE_MONITOR) {
- local->iw_mode = i;
- } else {
- printk(KERN_WARNING "prism2: Unknown iw_mode %d; using "
- "IW_MODE_MASTER\n", i);
- local->iw_mode = IW_MODE_MASTER;
- }
- local->channel = GET_INT_PARM(channel, card_idx);
- local->beacon_int = GET_INT_PARM(beacon_int, card_idx);
- local->dtim_period = GET_INT_PARM(dtim_period, card_idx);
- local->wds_max_connections = 16;
- local->tx_control = HFA384X_TX_CTRL_FLAGS;
- local->manual_retry_count = -1;
- local->rts_threshold = 2347;
- local->fragm_threshold = 2346;
- local->rssi_to_dBm = 100; /* default; to be overriden by
- * cnfDbmAdjust, if available */
- local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY;
- local->sram_type = -1;
- local->scan_channel_mask = 0xffff;
- local->monitor_type = PRISM2_MONITOR_RADIOTAP;
-
- /* Initialize task queue structures */
- INIT_WORK(&local->reset_queue, handle_reset_queue);
- INIT_WORK(&local->set_multicast_list_queue,
- hostap_set_multicast_list_queue);
-
- INIT_WORK(&local->set_tim_queue, handle_set_tim_queue);
- INIT_LIST_HEAD(&local->set_tim_list);
- spin_lock_init(&local->set_tim_lock);
-
- INIT_WORK(&local->comms_qual_update, handle_comms_qual_update);
-
- /* Initialize tasklets for handling hardware IRQ related operations
- * outside hw IRQ handler */
- tasklet_setup(&local->bap_tasklet, hostap_bap_tasklet);
- tasklet_setup(&local->info_tasklet, hostap_info_tasklet);
- hostap_info_init(local);
-
- tasklet_setup(&local->rx_tasklet, hostap_rx_tasklet);
- skb_queue_head_init(&local->rx_list);
-
- tasklet_setup(&local->sta_tx_exc_tasklet,
- hostap_sta_tx_exc_tasklet);
- skb_queue_head_init(&local->sta_tx_exc_list);
-
- INIT_LIST_HEAD(&local->cmd_queue);
- init_waitqueue_head(&local->hostscan_wq);
-
- lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock);
-
- timer_setup(&local->passive_scan_timer, hostap_passive_scan, 0);
- timer_setup(&local->tick_timer, hostap_tick_timer, 0);
- local->tick_timer.expires = jiffies + 2 * HZ;
- add_timer(&local->tick_timer);
-
- INIT_LIST_HEAD(&local->bss_list);
-
- hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER);
-
- dev->type = ARPHRD_IEEE80211;
- dev->header_ops = &hostap_80211_ops;
-
- rtnl_lock();
- ret = dev_alloc_name(dev, "wifi%d");
- SET_NETDEV_DEV(dev, sdev);
- if (ret >= 0)
- ret = register_netdevice(dev);
-
- prism2_set_lockdep_class(dev);
- rtnl_unlock();
- if (ret < 0) {
- printk(KERN_WARNING "%s: register netdevice failed!\n",
- dev_info);
- goto fail;
- }
- printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name);
-
- hostap_init_data(local);
- return dev;
-
- fail:
- free_netdev(dev);
- return NULL;
-}
-
-
-static int hostap_hw_ready(struct net_device *dev)
-{
- struct hostap_interface *iface;
- struct local_info *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
- local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0,
- "", dev_template);
-
- if (local->ddev) {
- if (local->iw_mode == IW_MODE_INFRA ||
- local->iw_mode == IW_MODE_ADHOC) {
- netif_carrier_off(local->dev);
- netif_carrier_off(local->ddev);
- }
- hostap_init_proc(local);
-#ifndef PRISM2_NO_PROCFS_DEBUG
- proc_create_single_data("registers", 0, local->proc,
- prism2_registers_proc_show, local);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
- hostap_init_ap_proc(local);
- return 0;
- }
-
- return -1;
-}
-
-
-static void prism2_free_local_data(struct net_device *dev)
-{
- struct hostap_tx_callback_info *tx_cb, *tx_cb_prev;
- int i;
- struct hostap_interface *iface;
- struct local_info *local;
- struct list_head *ptr, *n;
-
- if (dev == NULL)
- return;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Unregister all netdevs before freeing local data. */
- list_for_each_safe(ptr, n, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_MASTER) {
- /* special handling for this interface below */
- continue;
- }
- hostap_remove_interface(iface->dev, 0, 1);
- }
-
- unregister_netdev(local->dev);
-
- flush_work(&local->reset_queue);
- flush_work(&local->set_multicast_list_queue);
- flush_work(&local->set_tim_queue);
-#ifndef PRISM2_NO_STATION_MODES
- flush_work(&local->info_queue);
-#endif
- flush_work(&local->comms_qual_update);
-
- lib80211_crypt_info_free(&local->crypt_info);
-
- if (timer_pending(&local->passive_scan_timer))
- del_timer(&local->passive_scan_timer);
-
- if (timer_pending(&local->tick_timer))
- del_timer(&local->tick_timer);
-
- prism2_clear_cmd_queue(local);
-
- skb_queue_purge(&local->info_list);
- skb_queue_purge(&local->rx_list);
- skb_queue_purge(&local->sta_tx_exc_list);
-
- if (local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_DISABLE);
-
- if (local->ap != NULL)
- hostap_free_data(local->ap);
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- if (local->proc != NULL)
- remove_proc_entry("registers", local->proc);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
- hostap_remove_proc(local);
-
- tx_cb = local->tx_callback;
- while (tx_cb != NULL) {
- tx_cb_prev = tx_cb;
- tx_cb = tx_cb->next;
- kfree(tx_cb_prev);
- }
-
- hostap_set_hostapd(local, 0, 0);
- hostap_set_hostapd_sta(local, 0, 0);
-
- for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
- if (local->frag_cache[i].skb != NULL)
- dev_kfree_skb(local->frag_cache[i].skb);
- }
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- prism2_download_free_data(local->dl_pri);
- prism2_download_free_data(local->dl_sec);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- prism2_clear_set_tim_queue(local);
-
- list_for_each_safe(ptr, n, &local->bss_list) {
- struct hostap_bss_info *bss =
- list_entry(ptr, struct hostap_bss_info, list);
- kfree(bss);
- }
-
- kfree(local->pda);
- kfree(local->last_scan_results);
- kfree(local->generic_elem);
-
- free_netdev(local->dev);
-}
-
-
-#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD)
-static void __maybe_unused prism2_suspend(struct net_device *dev)
-{
- struct hostap_interface *iface;
- struct local_info *local;
- union iwreq_data wrqu;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Send disconnect event, e.g., to trigger reassociation after resume
- * if wpa_supplicant is used. */
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
-
- /* Disable hardware and firmware */
- prism2_hw_shutdown(dev, 0);
-}
-#endif /* PRISM2_PCI || PRISM2_PCCARD */
-
-
-/* These might at some point be compiled separately and used as separate
- * kernel modules or linked into one */
-#ifdef PRISM2_DOWNLOAD_SUPPORT
-#include "hostap_download.c"
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-#ifdef PRISM2_CALLBACK
-/* External hostap_callback.c file can be used to, e.g., blink activity led.
- * This can use platform specific code and must define prism2_callback()
- * function (if PRISM2_CALLBACK is not defined, these function calls are not
- * used. */
-#include "hostap_callback.c"
-#endif /* PRISM2_CALLBACK */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_info.c b/drivers/net/wireless/intersil/hostap/hostap_info.c
deleted file mode 100644
index da8c30f10d92..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_info.c
+++ /dev/null
@@ -1,509 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Host AP driver Info Frame processing (part of hostap.o module) */
-
-#include <linux/if_arp.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/etherdevice.h>
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
- int left)
-{
- struct hfa384x_comm_tallies *tallies;
-
- if (left < sizeof(struct hfa384x_comm_tallies)) {
- printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
- "info frame\n", local->dev->name, left);
- return;
- }
-
- tallies = (struct hfa384x_comm_tallies *) buf;
-#define ADD_COMM_TALLIES(name) \
-local->comm_tallies.name += le16_to_cpu(tallies->name)
- ADD_COMM_TALLIES(tx_unicast_frames);
- ADD_COMM_TALLIES(tx_multicast_frames);
- ADD_COMM_TALLIES(tx_fragments);
- ADD_COMM_TALLIES(tx_unicast_octets);
- ADD_COMM_TALLIES(tx_multicast_octets);
- ADD_COMM_TALLIES(tx_deferred_transmissions);
- ADD_COMM_TALLIES(tx_single_retry_frames);
- ADD_COMM_TALLIES(tx_multiple_retry_frames);
- ADD_COMM_TALLIES(tx_retry_limit_exceeded);
- ADD_COMM_TALLIES(tx_discards);
- ADD_COMM_TALLIES(rx_unicast_frames);
- ADD_COMM_TALLIES(rx_multicast_frames);
- ADD_COMM_TALLIES(rx_fragments);
- ADD_COMM_TALLIES(rx_unicast_octets);
- ADD_COMM_TALLIES(rx_multicast_octets);
- ADD_COMM_TALLIES(rx_fcs_errors);
- ADD_COMM_TALLIES(rx_discards_no_buffer);
- ADD_COMM_TALLIES(tx_discards_wrong_sa);
- ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
- ADD_COMM_TALLIES(rx_message_in_msg_fragments);
- ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
-#undef ADD_COMM_TALLIES
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
- int left)
-{
- struct hfa384x_comm_tallies32 *tallies;
-
- if (left < sizeof(struct hfa384x_comm_tallies32)) {
- printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
- "info frame\n", local->dev->name, left);
- return;
- }
-
- tallies = (struct hfa384x_comm_tallies32 *) buf;
-#define ADD_COMM_TALLIES(name) \
-local->comm_tallies.name += le32_to_cpu(tallies->name)
- ADD_COMM_TALLIES(tx_unicast_frames);
- ADD_COMM_TALLIES(tx_multicast_frames);
- ADD_COMM_TALLIES(tx_fragments);
- ADD_COMM_TALLIES(tx_unicast_octets);
- ADD_COMM_TALLIES(tx_multicast_octets);
- ADD_COMM_TALLIES(tx_deferred_transmissions);
- ADD_COMM_TALLIES(tx_single_retry_frames);
- ADD_COMM_TALLIES(tx_multiple_retry_frames);
- ADD_COMM_TALLIES(tx_retry_limit_exceeded);
- ADD_COMM_TALLIES(tx_discards);
- ADD_COMM_TALLIES(rx_unicast_frames);
- ADD_COMM_TALLIES(rx_multicast_frames);
- ADD_COMM_TALLIES(rx_fragments);
- ADD_COMM_TALLIES(rx_unicast_octets);
- ADD_COMM_TALLIES(rx_multicast_octets);
- ADD_COMM_TALLIES(rx_fcs_errors);
- ADD_COMM_TALLIES(rx_discards_no_buffer);
- ADD_COMM_TALLIES(tx_discards_wrong_sa);
- ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
- ADD_COMM_TALLIES(rx_message_in_msg_fragments);
- ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
-#undef ADD_COMM_TALLIES
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
- int left)
-{
- if (local->tallies32)
- prism2_info_commtallies32(local, buf, left);
- else
- prism2_info_commtallies16(local, buf, left);
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-#ifndef PRISM2_NO_DEBUG
-static const char* hfa384x_linkstatus_str(u16 linkstatus)
-{
- switch (linkstatus) {
- case HFA384X_LINKSTATUS_CONNECTED:
- return "Connected";
- case HFA384X_LINKSTATUS_DISCONNECTED:
- return "Disconnected";
- case HFA384X_LINKSTATUS_AP_CHANGE:
- return "Access point change";
- case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
- return "Access point out of range";
- case HFA384X_LINKSTATUS_AP_IN_RANGE:
- return "Access point in range";
- case HFA384X_LINKSTATUS_ASSOC_FAILED:
- return "Association failed";
- default:
- return "Unknown";
- }
-}
-#endif /* PRISM2_NO_DEBUG */
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
- int left)
-{
- u16 val;
- int non_sta_mode;
-
- /* Alloc new JoinRequests to occur since LinkStatus for the previous
- * has been received */
- local->last_join_time = 0;
-
- if (left != 2) {
- printk(KERN_DEBUG "%s: invalid linkstatus info frame "
- "length %d\n", local->dev->name, left);
- return;
- }
-
- non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
- local->iw_mode == IW_MODE_REPEAT ||
- local->iw_mode == IW_MODE_MONITOR;
-
- val = buf[0] | (buf[1] << 8);
- if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
- local->dev->name, val, hfa384x_linkstatus_str(val));
- }
-
- if (non_sta_mode) {
- netif_carrier_on(local->dev);
- netif_carrier_on(local->ddev);
- return;
- }
-
- /* Get current BSSID later in scheduled task */
- set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
- local->prev_link_status = val;
- schedule_work(&local->info_queue);
-}
-
-
-static void prism2_host_roaming(local_info_t *local)
-{
- struct hfa384x_join_request req;
- struct net_device *dev = local->dev;
- struct hfa384x_hostscan_result *selected, *entry;
- int i;
- unsigned long flags;
-
- if (local->last_join_time &&
- time_before(jiffies, local->last_join_time + 10 * HZ)) {
- PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
- "completed - waiting for it before issuing new one\n",
- dev->name);
- return;
- }
-
- /* ScanResults are sorted: first ESS results in decreasing signal
- * quality then IBSS results in similar order.
- * Trivial roaming policy: just select the first entry.
- * This could probably be improved by adding hysteresis to limit
- * number of handoffs, etc.
- *
- * Could do periodic RID_SCANREQUEST or Inquire F101 to get new
- * ScanResults */
- spin_lock_irqsave(&local->lock, flags);
- if (local->last_scan_results == NULL ||
- local->last_scan_results_count == 0) {
- spin_unlock_irqrestore(&local->lock, flags);
- PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
- dev->name);
- return;
- }
-
- selected = &local->last_scan_results[0];
-
- if (local->preferred_ap[0] || local->preferred_ap[1] ||
- local->preferred_ap[2] || local->preferred_ap[3] ||
- local->preferred_ap[4] || local->preferred_ap[5]) {
- /* Try to find preferred AP */
- PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n",
- dev->name, local->preferred_ap);
- for (i = 0; i < local->last_scan_results_count; i++) {
- entry = &local->last_scan_results[i];
- if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
- {
- PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
- "selection\n", dev->name);
- selected = entry;
- break;
- }
- }
- }
-
- memcpy(req.bssid, selected->bssid, ETH_ALEN);
- req.channel = selected->chid;
- spin_unlock_irqrestore(&local->lock, flags);
-
- PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM"
- " channel=%d\n",
- dev->name, req.bssid, le16_to_cpu(req.channel));
- if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
- sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
- }
- local->last_join_time = jiffies;
-}
-
-
-static void hostap_report_scan_complete(local_info_t *local)
-{
- union iwreq_data wrqu;
-
- /* Inform user space about new scan results (just empty event,
- * SIOCGIWSCAN can be used to fetch data */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
-
- /* Allow SIOCGIWSCAN handling to occur since we have received
- * scanning result */
- local->scan_timestamp = 0;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
- int left)
-{
- u16 *pos;
- int new_count, i;
- unsigned long flags;
- struct hfa384x_scan_result *res;
- struct hfa384x_hostscan_result *results, *prev;
-
- if (left < 4) {
- printk(KERN_DEBUG "%s: invalid scanresult info frame "
- "length %d\n", local->dev->name, left);
- return;
- }
-
- pos = (u16 *) buf;
- pos++;
- pos++;
- left -= 4;
-
- new_count = left / sizeof(struct hfa384x_scan_result);
- results = kmalloc_array(new_count,
- sizeof(struct hfa384x_hostscan_result),
- GFP_ATOMIC);
- if (results == NULL)
- return;
-
- /* Convert to hostscan result format. */
- res = (struct hfa384x_scan_result *) pos;
- for (i = 0; i < new_count; i++) {
- memcpy(&results[i], &res[i],
- sizeof(struct hfa384x_scan_result));
- results[i].atim = 0;
- }
-
- spin_lock_irqsave(&local->lock, flags);
- local->last_scan_type = PRISM2_SCAN;
- prev = local->last_scan_results;
- local->last_scan_results = results;
- local->last_scan_results_count = new_count;
- spin_unlock_irqrestore(&local->lock, flags);
- kfree(prev);
-
- hostap_report_scan_complete(local);
-
- /* Perform rest of ScanResults handling later in scheduled task */
- set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
- schedule_work(&local->info_queue);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_hostscanresults(local_info_t *local,
- unsigned char *buf, int left)
-{
- int i, result_size, copy_len, new_count;
- struct hfa384x_hostscan_result *results, *prev;
- unsigned long flags;
- __le16 *pos;
- u8 *ptr;
-
- wake_up_interruptible(&local->hostscan_wq);
-
- if (left < 4) {
- printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
- "length %d\n", local->dev->name, left);
- return;
- }
-
- pos = (__le16 *) buf;
- copy_len = result_size = le16_to_cpu(*pos);
- if (result_size == 0) {
- printk(KERN_DEBUG "%s: invalid result_size (0) in "
- "hostscanresults\n", local->dev->name);
- return;
- }
- if (copy_len > sizeof(struct hfa384x_hostscan_result))
- copy_len = sizeof(struct hfa384x_hostscan_result);
-
- pos++;
- pos++;
- left -= 4;
- ptr = (u8 *) pos;
-
- new_count = left / result_size;
- results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result),
- GFP_ATOMIC);
- if (results == NULL)
- return;
-
- for (i = 0; i < new_count; i++) {
- memcpy(&results[i], ptr, copy_len);
- ptr += result_size;
- left -= result_size;
- }
-
- if (left) {
- printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
- local->dev->name, left, result_size);
- }
-
- spin_lock_irqsave(&local->lock, flags);
- local->last_scan_type = PRISM2_HOSTSCAN;
- prev = local->last_scan_results;
- local->last_scan_results = results;
- local->last_scan_results_count = new_count;
- spin_unlock_irqrestore(&local->lock, flags);
- kfree(prev);
-
- hostap_report_scan_complete(local);
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-/* Called only as a tasklet (software IRQ) */
-void hostap_info_process(local_info_t *local, struct sk_buff *skb)
-{
- struct hfa384x_info_frame *info;
- unsigned char *buf;
- int left;
-#ifndef PRISM2_NO_DEBUG
- int i;
-#endif /* PRISM2_NO_DEBUG */
-
- info = (struct hfa384x_info_frame *) skb->data;
- buf = skb->data + sizeof(*info);
- left = skb->len - sizeof(*info);
-
- switch (le16_to_cpu(info->type)) {
- case HFA384X_INFO_COMMTALLIES:
- prism2_info_commtallies(local, buf, left);
- break;
-
-#ifndef PRISM2_NO_STATION_MODES
- case HFA384X_INFO_LINKSTATUS:
- prism2_info_linkstatus(local, buf, left);
- break;
-
- case HFA384X_INFO_SCANRESULTS:
- prism2_info_scanresults(local, buf, left);
- break;
-
- case HFA384X_INFO_HOSTSCANRESULTS:
- prism2_info_hostscanresults(local, buf, left);
- break;
-#endif /* PRISM2_NO_STATION_MODES */
-
-#ifndef PRISM2_NO_DEBUG
- default:
- PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
- local->dev->name, le16_to_cpu(info->len),
- le16_to_cpu(info->type));
- PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
- for (i = 0; i < (left < 100 ? left : 100); i++)
- PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
- PDEBUG2(DEBUG_EXTRA, "\n");
- break;
-#endif /* PRISM2_NO_DEBUG */
- }
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static void handle_info_queue_linkstatus(local_info_t *local)
-{
- int val = local->prev_link_status;
- int connected;
- union iwreq_data wrqu;
-
- connected =
- val == HFA384X_LINKSTATUS_CONNECTED ||
- val == HFA384X_LINKSTATUS_AP_CHANGE ||
- val == HFA384X_LINKSTATUS_AP_IN_RANGE;
-
- if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
- local->bssid, ETH_ALEN, 1) < 0) {
- printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
- "LinkStatus event\n", local->dev->name);
- } else {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n",
- local->dev->name,
- (unsigned char *) local->bssid);
- if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
- hostap_add_sta(local->ap, local->bssid);
- }
-
- /* Get BSSID if we have a valid AP address */
- if (connected) {
- netif_carrier_on(local->dev);
- netif_carrier_on(local->ddev);
- memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
- } else {
- netif_carrier_off(local->dev);
- netif_carrier_off(local->ddev);
- eth_zero_addr(wrqu.ap_addr.sa_data);
- }
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /*
- * Filter out sequential disconnect events in order not to cause a
- * flood of SIOCGIWAP events that have a race condition with EAPOL
- * frames and can confuse wpa_supplicant about the current association
- * status.
- */
- if (connected || local->prev_linkstatus_connected)
- wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
- local->prev_linkstatus_connected = connected;
-}
-
-
-static void handle_info_queue_scanresults(local_info_t *local)
-{
- if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
- prism2_host_roaming(local);
-
- if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
- !is_zero_ether_addr(local->preferred_ap)) {
- /*
- * Firmware seems to be getting into odd state in host_roaming
- * mode 2 when hostscan is used without join command, so try
- * to fix this by re-joining the current AP. This does not
- * actually trigger a new association if the current AP is
- * still in the scan results.
- */
- prism2_host_roaming(local);
- }
-}
-
-
-/* Called only as scheduled task after receiving info frames (used to avoid
- * pending too much time in HW IRQ handler). */
-static void handle_info_queue(struct work_struct *work)
-{
- local_info_t *local = container_of(work, local_info_t, info_queue);
-
- if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
- &local->pending_info))
- handle_info_queue_linkstatus(local);
-
- if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
- &local->pending_info))
- handle_info_queue_scanresults(local);
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-void hostap_info_init(local_info_t *local)
-{
- skb_queue_head_init(&local->info_list);
-#ifndef PRISM2_NO_STATION_MODES
- INIT_WORK(&local->info_queue, handle_info_queue);
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-EXPORT_SYMBOL(hostap_info_init);
-EXPORT_SYMBOL(hostap_info_process);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c
deleted file mode 100644
index 26162f92e3c3..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c
+++ /dev/null
@@ -1,3847 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/sched/signal.h>
-#include <linux/ethtool.h>
-#include <linux/if_arp.h>
-#include <linux/module.h>
-#include <linux/etherdevice.h>
-#include <net/lib80211.h>
-
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct iw_statistics *wstats;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Why are we doing that ? Jean II */
- if (iface->type != HOSTAP_INTERFACE_MAIN)
- return NULL;
-
- wstats = &local->wstats;
-
- wstats->status = 0;
- wstats->discard.code =
- local->comm_tallies.rx_discards_wep_undecryptable;
- wstats->discard.misc =
- local->comm_tallies.rx_fcs_errors +
- local->comm_tallies.rx_discards_no_buffer +
- local->comm_tallies.tx_discards_wrong_sa;
-
- wstats->discard.retries =
- local->comm_tallies.tx_retry_limit_exceeded;
- wstats->discard.fragment =
- local->comm_tallies.rx_message_in_bad_msg_fragments;
-
- if (local->iw_mode != IW_MODE_MASTER &&
- local->iw_mode != IW_MODE_REPEAT) {
-
- if (prism2_update_comms_qual(dev) == 0)
- wstats->qual.updated = IW_QUAL_ALL_UPDATED |
- IW_QUAL_DBM;
-
- wstats->qual.qual = local->comms_qual;
- wstats->qual.level = local->avg_signal;
- wstats->qual.noise = local->avg_noise;
- } else {
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
-
-
-static int prism2_get_datarates(struct net_device *dev, u8 *rates)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u8 buf[12];
- int len;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf,
- sizeof(buf), 0);
- if (len < 2)
- return 0;
-
- val = le16_to_cpu(*(__le16 *) buf); /* string length */
-
- if (len - 2 < val || val > 10)
- return 0;
-
- memcpy(rates, buf + 2, val);
- return val;
-}
-
-
-static int prism2_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 rates[10];
- int len, i, over2 = 0;
-
- len = prism2_get_datarates(dev, rates);
-
- for (i = 0; i < len; i++) {
- if (rates[i] == 0x0b || rates[i] == 0x16) {
- over2 = 1;
- break;
- }
- }
-
- strcpy(wrqu->name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS");
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface;
- local_info_t *local;
- int i;
- struct lib80211_crypt_data **crypt;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i < 1 || i > 4)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
- if (i < 0 || i >= WEP_KEYS)
- return -EINVAL;
-
- crypt = &local->crypt_info.crypt[i];
-
- if (erq->flags & IW_ENCODE_DISABLED) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- goto done;
- }
-
- if (*crypt != NULL && (*crypt)->ops != NULL &&
- strcmp((*crypt)->ops->name, "WEP") != 0) {
- /* changing to use WEP; deinit previously used algorithm */
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- }
-
- if (*crypt == NULL) {
- struct lib80211_crypt_data *new_crypt;
-
- /* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL)
- return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- if (!new_crypt->ops) {
- request_module("lib80211_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- }
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(i);
- if (!new_crypt->ops || !new_crypt->priv) {
- kfree(new_crypt);
- new_crypt = NULL;
-
- printk(KERN_WARNING "%s: could not initialize WEP: "
- "load module hostap_crypt_wep.o\n",
- dev->name);
- return -EOPNOTSUPP;
- }
- *crypt = new_crypt;
- }
-
- if (erq->length > 0) {
- int len = erq->length <= 5 ? 5 : 13;
- int first = 1, j;
- if (len > erq->length)
- memset(keybuf + erq->length, 0, len - erq->length);
- (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv);
- for (j = 0; j < WEP_KEYS; j++) {
- if (j != i && local->crypt_info.crypt[j]) {
- first = 0;
- break;
- }
- }
- if (first)
- local->crypt_info.tx_keyidx = i;
- } else {
- /* No key data - just set the default TX key index */
- local->crypt_info.tx_keyidx = i;
- }
-
- done:
- local->open_wep = erq->flags & IW_ENCODE_OPEN;
-
- if (hostap_set_encryption(local)) {
- printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name);
- return -EINVAL;
- }
-
- /* Do not reset port0 if card is in Managed mode since resetting will
- * generate new IEEE 802.11 authentication which may end up in looping
- * with IEEE 802.1X. Prism2 documentation seem to require port reset
- * after WEP configuration. However, keys are apparently changed at
- * least in Managed mode. */
- if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) {
- printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface;
- local_info_t *local;
- int i, len;
- u16 val;
- struct lib80211_crypt_data *crypt;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i < 1 || i > 4)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
- if (i < 0 || i >= WEP_KEYS)
- return -EINVAL;
-
- crypt = local->crypt_info.crypt[i];
- erq->flags = i + 1;
-
- if (crypt == NULL || crypt->ops == NULL) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- if (strcmp(crypt->ops->name, "WEP") != 0) {
- /* only WEP is supported with wireless extensions, so just
- * report that encryption is used */
- erq->length = 0;
- erq->flags |= IW_ENCODE_ENABLED;
- return 0;
- }
-
- /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show
- * the keys from driver buffer */
- len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv);
- erq->length = (len >= 0 ? len : 0);
-
- if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0)
- {
- printk("CNFWEPFLAGS reading failed\n");
- return -EOPNOTSUPP;
- }
- le16_to_cpus(&val);
- if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED)
- erq->flags |= IW_ENCODE_ENABLED;
- else
- erq->flags |= IW_ENCODE_DISABLED;
- if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- return 0;
-}
-
-
-static int hostap_set_rate(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret, basic_rates;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- basic_rates = local->basic_rates & local->tx_rate_control;
- if (!basic_rates || basic_rates != local->basic_rates) {
- printk(KERN_INFO "%s: updating basic rate set automatically "
- "to match with the new supported rate set\n",
- dev->name);
- if (!basic_rates)
- basic_rates = local->tx_rate_control;
-
- local->basic_rates = basic_rates;
- if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- basic_rates))
- printk(KERN_WARNING "%s: failed to set "
- "cnfBasicRates\n", dev->name);
- }
-
- ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
- local->tx_rate_control) ||
- hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
- local->tx_rate_control) ||
- local->func->reset_port(dev));
-
- if (ret) {
- printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates "
- "setting to 0x%x failed\n",
- dev->name, local->tx_rate_control);
- }
-
- /* Update TX rate configuration for all STAs based on new operational
- * rate set. */
- hostap_update_rates(local);
-
- return ret;
-}
-
-
-static int prism2_ioctl_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rrq->fixed) {
- switch (rrq->value) {
- case 11000000:
- local->tx_rate_control = HFA384X_RATES_11MBPS;
- break;
- case 5500000:
- local->tx_rate_control = HFA384X_RATES_5MBPS;
- break;
- case 2000000:
- local->tx_rate_control = HFA384X_RATES_2MBPS;
- break;
- case 1000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS;
- break;
- default:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- break;
- }
- } else {
- switch (rrq->value) {
- case 11000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- break;
- case 5500000:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS;
- break;
- case 2000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS;
- break;
- case 1000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS;
- break;
- default:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- break;
- }
- }
-
- return hostap_set_rate(dev);
-}
-
-
-static int prism2_ioctl_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- u16 val;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- if ((val & 0x1) && (val > 1))
- rrq->fixed = 0;
- else
- rrq->fixed = 1;
-
- if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL &&
- !local->fw_tx_rate_control) {
- /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in
- * Host AP mode, so use the recorded TX rate of the last sent
- * frame */
- rrq->value = local->ap->last_tx_rate > 0 ?
- local->ap->last_tx_rate * 100000 : 11000000;
- return 0;
- }
-
- if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- switch (val) {
- case HFA384X_RATES_1MBPS:
- rrq->value = 1000000;
- break;
- case HFA384X_RATES_2MBPS:
- rrq->value = 2000000;
- break;
- case HFA384X_RATES_5MBPS:
- rrq->value = 5500000;
- break;
- case HFA384X_RATES_11MBPS:
- rrq->value = 11000000;
- break;
- default:
- /* should not happen */
- rrq->value = 11000000;
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_siwsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *sens = &wrqu->sens;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Set the desired AP density */
- if (sens->value < 1 || sens->value > 3)
- return -EINVAL;
-
- if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *sens = &wrqu->sens;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Get the current AP density */
- if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- sens->value = le16_to_cpu(val);
- sens->fixed = 1;
-
- return 0;
-}
-
-
-/* Deprecated in new wireless extension API */
-static int prism2_ioctl_giwaplist(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- struct sockaddr *addr;
- struct iw_quality *qual;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->iw_mode != IW_MODE_MASTER) {
- printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported "
- "in Host AP mode\n");
- data->length = 0;
- return -EOPNOTSUPP;
- }
-
- addr = kmalloc_array(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL);
- qual = kmalloc_array(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL);
- if (addr == NULL || qual == NULL) {
- kfree(addr);
- kfree(qual);
- data->length = 0;
- return -ENOMEM;
- }
-
- data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
-
- memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
- data->flags = 1; /* has quality information */
- memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
- sizeof(struct iw_quality) * data->length);
-
- kfree(addr);
- kfree(qual);
- return 0;
-}
-
-
-static int prism2_ioctl_siwrts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rts->disabled)
- val = cpu_to_le16(2347);
- else if (rts->value < 0 || rts->value > 2347)
- return -EINVAL;
- else
- val = cpu_to_le16(rts->value);
-
- if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- local->rts_threshold = rts->value;
-
- return 0;
-}
-
-static int prism2_ioctl_giwrts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- rts->value = le16_to_cpu(val);
- rts->disabled = (rts->value == 2347);
- rts->fixed = 1;
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwfrag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rts->disabled)
- val = cpu_to_le16(2346);
- else if (rts->value < 256 || rts->value > 2346)
- return -EINVAL;
- else
- val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */
-
- local->fragm_threshold = rts->value & ~0x1;
- if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val,
- 2)
- || local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwfrag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- &val, 2, 1) < 0)
- return -EINVAL;
-
- rts->value = le16_to_cpu(val);
- rts->disabled = (rts->value == 2346);
- rts->fixed = 1;
-
- return 0;
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static int hostap_join_ap(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_join_request req;
- unsigned long flags;
- int i;
- struct hfa384x_hostscan_result *entry;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memcpy(req.bssid, local->preferred_ap, ETH_ALEN);
- req.channel = 0;
-
- spin_lock_irqsave(&local->lock, flags);
- for (i = 0; i < local->last_scan_results_count; i++) {
- if (!local->last_scan_results)
- break;
- entry = &local->last_scan_results[i];
- if (ether_addr_equal(local->preferred_ap, entry->bssid)) {
- req.channel = entry->chid;
- break;
- }
- }
- spin_unlock_irqrestore(&local->lock, flags);
-
- if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
- sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest %pM failed\n",
- dev->name, local->preferred_ap);
- return -1;
- }
-
- printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n",
- dev->name, local->preferred_ap);
-
- return 0;
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-static int prism2_ioctl_siwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN);
-
- if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) {
- struct hfa384x_scan_request scan_req;
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(0x3fff);
- scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
- if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST,
- &scan_req, sizeof(scan_req))) {
- printk(KERN_DEBUG "%s: ScanResults request failed - "
- "preferred AP delayed to next unsolicited "
- "scan\n", dev->name);
- }
- } else if (local->host_roaming == 2 &&
- local->iw_mode == IW_MODE_INFRA) {
- if (hostap_join_ap(dev))
- return -EINVAL;
- } else {
- printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only "
- "in Managed mode when host_roaming is enabled\n",
- dev->name);
- }
-
- return 0;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-static int prism2_ioctl_giwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- ap_addr->sa_family = ARPHRD_ETHER;
- switch (iface->type) {
- case HOSTAP_INTERFACE_AP:
- memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN);
- break;
- case HOSTAP_INTERFACE_STA:
- memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN);
- break;
- case HOSTAP_INTERFACE_WDS:
- memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN);
- break;
- default:
- if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID,
- &ap_addr->sa_data, ETH_ALEN, 1) < 0)
- return -EOPNOTSUPP;
-
- /* local->bssid is also updated in LinkStatus handler when in
- * station mode */
- memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN);
- break;
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwnickn(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *nickname)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memset(local->name, 0, sizeof(local->name));
- memcpy(local->name, nickname, data->length);
- local->name_set = 1;
-
- if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwnickn(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *nickname)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- int len;
- char name[MAX_NAME_LEN + 3];
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME,
- &name, MAX_NAME_LEN + 2, 0);
- val = le16_to_cpu(*(__le16 *) name);
- if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN)
- return -EOPNOTSUPP;
-
- name[val + 2] = '\0';
- data->length = val + 1;
- memcpy(nickname, name + 2, val + 1);
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* freq => chan. */
- if (freq->e == 1 &&
- freq->m / 100000 >= freq_list[0] &&
- freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) {
- int ch;
- int fr = freq->m / 100000;
- for (ch = 0; ch < FREQ_COUNT; ch++) {
- if (fr == freq_list[ch]) {
- freq->e = 0;
- freq->m = ch + 1;
- break;
- }
- }
- }
-
- if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT ||
- !(local->channel_mask & (1 << (freq->m - 1))))
- return -EINVAL;
-
- local->channel = freq->m; /* channel is used in prism2_setup_rids() */
- if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct hostap_interface *iface;
- local_info_t *local;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- le16_to_cpus(&val);
- if (val < 1 || val > FREQ_COUNT)
- return -EINVAL;
-
- freq->m = freq_list[val - 1] * 100000;
- freq->e = 1;
-
- return 0;
-}
-
-
-static void hostap_monitor_set_type(local_info_t *local)
-{
- struct net_device *dev = local->ddev;
-
- if (dev == NULL)
- return;
-
- if (local->monitor_type == PRISM2_MONITOR_PRISM ||
- local->monitor_type == PRISM2_MONITOR_CAPHDR) {
- dev->type = ARPHRD_IEEE80211_PRISM;
- } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) {
- dev->type = ARPHRD_IEEE80211_RADIOTAP;
- } else {
- dev->type = ARPHRD_IEEE80211;
- }
-}
-
-
-static int prism2_ioctl_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *ssid)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (iface->type == HOSTAP_INTERFACE_WDS)
- return -EOPNOTSUPP;
-
- if (data->flags == 0)
- ssid[0] = '\0'; /* ANY */
-
- if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') {
- /* Setting SSID to empty string seems to kill the card in
- * Host AP mode */
- printk(KERN_DEBUG "%s: Host AP mode does not support "
- "'Any' essid\n", dev->name);
- return -EINVAL;
- }
-
- memcpy(local->essid, ssid, data->length);
- local->essid[data->length] = '\0';
-
- if ((!local->fw_ap &&
- hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid))
- || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *essid)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (iface->type == HOSTAP_INTERFACE_WDS)
- return -EOPNOTSUPP;
-
- data->flags = 1; /* active */
- if (local->iw_mode == IW_MODE_MASTER) {
- data->length = strlen(local->essid);
- memcpy(essid, local->essid, IW_ESSID_MAX_SIZE);
- } else {
- int len;
- char ssid[MAX_SSID_LEN + 2];
- memset(ssid, 0, sizeof(ssid));
- len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID,
- &ssid, MAX_SSID_LEN + 2, 0);
- val = le16_to_cpu(*(__le16 *) ssid);
- if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) {
- return -EOPNOTSUPP;
- }
- data->length = val;
- memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE);
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_giwrange(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- struct iw_range *range = (struct iw_range *) extra;
- u8 rates[10];
- u16 val;
- int i, len, over2;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- data->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- /* TODO: could fill num_txpower and txpower array with
- * something; however, there are 128 different values.. */
-
- range->txpower_capa = IW_TXPOW_DBM;
-
- if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC)
- {
- range->min_pmp = 1 * 1024;
- range->max_pmp = 65535 * 1024;
- range->min_pmt = 1 * 1024;
- range->max_pmt = 1000 * 1024;
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT |
- IW_POWER_UNICAST_R | IW_POWER_ALL_R;
- }
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
- range->retry_capa = IW_RETRY_LIMIT;
- range->retry_flags = IW_RETRY_LIMIT;
- range->min_retry = 0;
- range->max_retry = 255;
-
- range->num_channels = FREQ_COUNT;
-
- val = 0;
- for (i = 0; i < FREQ_COUNT; i++) {
- if (local->channel_mask & (1 << i)) {
- range->freq[val].i = i + 1;
- range->freq[val].m = freq_list[i] * 100000;
- range->freq[val].e = 1;
- val++;
- }
- if (val == IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = val;
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
- range->max_qual.qual = 70; /* what is correct max? This was not
- * documented exactly. At least
- * 69 has been observed. */
- range->max_qual.level = 0; /* dB */
- range->max_qual.noise = 0; /* dB */
-
- /* What would be suitable values for "average/typical" qual? */
- range->avg_qual.qual = 20;
- range->avg_qual.level = -60;
- range->avg_qual.noise = -95;
- } else {
- range->max_qual.qual = 92; /* 0 .. 92 */
- range->max_qual.level = 154; /* 27 .. 154 */
- range->max_qual.noise = 154; /* 27 .. 154 */
- }
- range->sensitivity = 3;
-
- range->max_encoding_tokens = WEP_KEYS;
- range->num_encoding_sizes = 2;
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
-
- over2 = 0;
- len = prism2_get_datarates(dev, rates);
- range->num_bitrates = 0;
- for (i = 0; i < len; i++) {
- if (range->num_bitrates < IW_MAX_BITRATES) {
- range->bitrate[range->num_bitrates] =
- rates[i] * 500000;
- range->num_bitrates++;
- }
- if (rates[i] == 0x0b || rates[i] == 0x16)
- over2 = 1;
- }
- /* estimated maximum TCP throughput values (bps) */
- range->throughput = over2 ? 5500000 : 1500000;
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
- range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) |
- IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
- IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
- IW_EVENT_CAPA_MASK(IWEVEXPIRED));
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
- range->scan_capa = IW_SCAN_CAPA_ESSID;
-
- return 0;
-}
-
-
-static int hostap_monitor_mode_enable(local_info_t *local)
-{
- struct net_device *dev = local->dev;
-
- printk(KERN_DEBUG "Enabling monitor mode\n");
- hostap_monitor_set_type(local);
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- HFA384X_PORTTYPE_PSEUDO_IBSS)) {
- printk(KERN_DEBUG "Port type setting for monitor mode "
- "failed\n");
- return -EOPNOTSUPP;
- }
-
- /* Host decrypt is needed to get the IV and ICV fields;
- * however, monitor mode seems to remove WEP flag from frame
- * control field */
- if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS,
- HFA384X_WEPFLAGS_HOSTENCRYPT |
- HFA384X_WEPFLAGS_HOSTDECRYPT)) {
- printk(KERN_DEBUG "WEP flags setting failed\n");
- return -EOPNOTSUPP;
- }
-
- if (local->func->reset_port(dev) ||
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_MONITOR << 8),
- 0, NULL, NULL)) {
- printk(KERN_DEBUG "Setting monitor mode failed\n");
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-
-static int hostap_monitor_mode_disable(local_info_t *local)
-{
- struct net_device *dev = local->ddev;
-
- if (dev == NULL)
- return -1;
-
- printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
- dev->type = ARPHRD_ETHER;
-
- if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_STOP << 8),
- 0, NULL, NULL))
- return -1;
- return hostap_set_encryption(local);
-}
-
-
-static int prism2_ioctl_siwmode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct hostap_interface *iface;
- local_info_t *local;
- int double_reset = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
- *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT &&
- *mode != IW_MODE_MONITOR)
- return -EOPNOTSUPP;
-
-#ifdef PRISM2_NO_STATION_MODES
- if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA)
- return -EOPNOTSUPP;
-#endif /* PRISM2_NO_STATION_MODES */
-
- if (*mode == local->iw_mode)
- return 0;
-
- if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') {
- printk(KERN_WARNING "%s: empty SSID not allowed in Master "
- "mode\n", dev->name);
- return -EINVAL;
- }
-
- if (local->iw_mode == IW_MODE_MONITOR)
- hostap_monitor_mode_disable(local);
-
- if ((local->iw_mode == IW_MODE_ADHOC ||
- local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) {
- /* There seems to be a firmware bug in at least STA f/w v1.5.6
- * that leaves beacon frames to use IBSS type when moving from
- * IBSS to Host AP mode. Doing double Port0 reset seems to be
- * enough to workaround this. */
- double_reset = 1;
- }
-
- printk(KERN_DEBUG "prism2: %s: operating mode changed "
- "%d -> %d\n", dev->name, local->iw_mode, *mode);
- local->iw_mode = *mode;
-
- if (local->iw_mode == IW_MODE_MONITOR)
- hostap_monitor_mode_enable(local);
- else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
- !local->fw_encrypt_ok) {
- printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
- "a workaround for firmware bug in Host AP mode WEP\n",
- dev->name);
- local->host_encrypt = 1;
- }
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- hostap_get_porttype(local)))
- return -EOPNOTSUPP;
-
- if (local->func->reset_port(dev))
- return -EINVAL;
- if (double_reset && local->func->reset_port(dev))
- return -EINVAL;
-
- if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC)
- {
- /* netif_carrier is used only in client modes for now, so make
- * sure carrier is on when moving to non-client modes. */
- netif_carrier_on(local->dev);
- netif_carrier_on(local->ddev);
- }
- return 0;
-}
-
-
-static int prism2_ioctl_giwmode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (iface->type) {
- case HOSTAP_INTERFACE_STA:
- *mode = IW_MODE_INFRA;
- break;
- case HOSTAP_INTERFACE_WDS:
- *mode = IW_MODE_REPEAT;
- break;
- default:
- *mode = local->iw_mode;
- break;
- }
- return 0;
-}
-
-
-static int prism2_ioctl_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *wrq = &wrqu->power;
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- int ret = 0;
-
- if (wrq->disabled)
- return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0);
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- break;
- case IW_POWER_ALL_R:
- ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- break;
- case IW_POWER_ON:
- break;
- default:
- return -EINVAL;
- }
-
- if (wrq->flags & IW_POWER_TIMEOUT) {
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION,
- wrq->value / 1024);
- if (ret)
- return ret;
- }
- if (wrq->flags & IW_POWER_PERIOD) {
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
- wrq->value / 1024);
- if (ret)
- return ret;
- }
-
- return ret;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->power;
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 enable, mcast;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1)
- < 0)
- return -EINVAL;
-
- if (!le16_to_cpu(enable)) {
- rrq->disabled = 1;
- return 0;
- }
-
- rrq->disabled = 0;
-
- if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- __le16 timeout;
- if (local->func->get_rid(dev,
- HFA384X_RID_CNFPMHOLDOVERDURATION,
- &timeout, 2, 1) < 0)
- return -EINVAL;
-
- rrq->flags = IW_POWER_TIMEOUT;
- rrq->value = le16_to_cpu(timeout) * 1024;
- } else {
- __le16 period;
- if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
- &period, 2, 1) < 0)
- return -EINVAL;
-
- rrq->flags = IW_POWER_PERIOD;
- rrq->value = le16_to_cpu(period) * 1024;
- }
-
- if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast,
- 2, 1) < 0)
- return -EINVAL;
-
- if (le16_to_cpu(mcast))
- rrq->flags |= IW_POWER_ALL_R;
- else
- rrq->flags |= IW_POWER_UNICAST_R;
-
- return 0;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->retry;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rrq->disabled)
- return -EINVAL;
-
- /* setting retry limits is not supported with the current station
- * firmware code; simulate this with alternative retry count for now */
- if (rrq->flags == IW_RETRY_LIMIT) {
- if (rrq->value < 0) {
- /* disable manual retry count setting and use firmware
- * defaults */
- local->manual_retry_count = -1;
- local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY;
- } else {
- if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
- rrq->value)) {
- printk(KERN_DEBUG "%s: Alternate retry count "
- "setting to %d failed\n",
- dev->name, rrq->value);
- return -EOPNOTSUPP;
- }
-
- local->manual_retry_count = rrq->value;
- local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY;
- }
- return 0;
- }
-
- return -EOPNOTSUPP;
-
-#if 0
- /* what could be done, if firmware would support this.. */
-
- if (rrq->flags & IW_RETRY_LIMIT) {
- if (rrq->flags & IW_RETRY_LONG)
- HFA384X_RID_LONGRETRYLIMIT = rrq->value;
- else if (rrq->flags & IW_RETRY_SHORT)
- HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
- else {
- HFA384X_RID_LONGRETRYLIMIT = rrq->value;
- HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
- }
-
- }
-
- if (rrq->flags & IW_RETRY_LIFETIME) {
- HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024;
- }
-
- return 0;
-#endif /* 0 */
-}
-
-static int prism2_ioctl_giwretry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->retry;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 shortretry, longretry, lifetime, altretry;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry,
- 2, 1) < 0 ||
- local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry,
- 2, 1) < 0 ||
- local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME,
- &lifetime, 2, 1) < 0)
- return -EINVAL;
-
- rrq->disabled = 0;
-
- if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- rrq->flags = IW_RETRY_LIFETIME;
- rrq->value = le16_to_cpu(lifetime) * 1024;
- } else {
- if (local->manual_retry_count >= 0) {
- rrq->flags = IW_RETRY_LIMIT;
- if (local->func->get_rid(dev,
- HFA384X_RID_CNFALTRETRYCOUNT,
- &altretry, 2, 1) >= 0)
- rrq->value = le16_to_cpu(altretry);
- else
- rrq->value = local->manual_retry_count;
- } else if ((rrq->flags & IW_RETRY_LONG)) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- rrq->value = le16_to_cpu(longretry);
- } else {
- rrq->flags = IW_RETRY_LIMIT;
- rrq->value = le16_to_cpu(shortretry);
- if (shortretry != longretry)
- rrq->flags |= IW_RETRY_SHORT;
- }
- }
- return 0;
-}
-
-
-/* Note! This TX power controlling is experimental and should not be used in
- * production use. It just sets raw power register and does not use any kind of
- * feedback information from the measured TX power (CR58). This is now
- * commented out to make sure that it is not used by accident. TX power
- * configuration will be enabled again after proper algorithm using feedback
- * has been implemented. */
-
-#ifdef RAW_TXPOWER_SETTING
-/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping..
- * This version assumes following mapping:
- * CR31 is 7-bit value with -64 to +63 range.
- * -64 is mapped into +20dBm and +63 into -43dBm.
- * This is certainly not an exact mapping for every card, but at least
- * increasing dBm value should correspond to increasing TX power.
- */
-
-static int prism2_txpower_hfa386x_to_dBm(u16 val)
-{
- signed char tmp;
-
- if (val > 255)
- val = 255;
-
- tmp = val;
- tmp >>= 2;
-
- return -12 - tmp;
-}
-
-static u16 prism2_txpower_dBm_to_hfa386x(int val)
-{
- signed char tmp;
-
- if (val > 20)
- return 128;
- else if (val < -43)
- return 127;
-
- tmp = val;
- tmp = -12 - tmp;
- tmp <<= 2;
-
- return (unsigned char) tmp;
-}
-#endif /* RAW_TXPOWER_SETTING */
-
-
-static int prism2_ioctl_siwtxpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->txpower;
- struct hostap_interface *iface;
- local_info_t *local;
-#ifdef RAW_TXPOWER_SETTING
- char *tmp;
-#endif
- u16 val;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rrq->disabled) {
- if (local->txpower_type != PRISM2_TXPOWER_OFF) {
- val = 0xff; /* use all standby and sleep modes */
- ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_A_D_TEST_MODES2,
- &val, NULL);
- printk(KERN_DEBUG "%s: Turning radio off: %s\n",
- dev->name, ret ? "failed" : "OK");
- local->txpower_type = PRISM2_TXPOWER_OFF;
- }
- return (ret ? -EOPNOTSUPP : 0);
- }
-
- if (local->txpower_type == PRISM2_TXPOWER_OFF) {
- val = 0; /* disable all standby and sleep modes */
- ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_A_D_TEST_MODES2, &val, NULL);
- printk(KERN_DEBUG "%s: Turning radio on: %s\n",
- dev->name, ret ? "failed" : "OK");
- local->txpower_type = PRISM2_TXPOWER_UNKNOWN;
- }
-
-#ifdef RAW_TXPOWER_SETTING
- if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) {
- printk(KERN_DEBUG "Setting ALC on\n");
- val = HFA384X_TEST_CFG_BIT_ALC;
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL);
- local->txpower_type = PRISM2_TXPOWER_AUTO;
- return 0;
- }
-
- if (local->txpower_type != PRISM2_TXPOWER_FIXED) {
- printk(KERN_DEBUG "Setting ALC off\n");
- val = HFA384X_TEST_CFG_BIT_ALC;
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
- local->txpower_type = PRISM2_TXPOWER_FIXED;
- }
-
- if (rrq->flags == IW_TXPOW_DBM)
- tmp = "dBm";
- else if (rrq->flags == IW_TXPOW_MWATT)
- tmp = "mW";
- else
- tmp = "UNKNOWN";
- printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp);
-
- if (rrq->flags != IW_TXPOW_DBM) {
- printk("SIOCSIWTXPOW with mW is not supported; use dBm\n");
- return -EOPNOTSUPP;
- }
-
- local->txpower = rrq->value;
- val = prism2_txpower_dBm_to_hfa386x(local->txpower);
- if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_MANUAL_TX_POWER, &val, NULL))
- ret = -EOPNOTSUPP;
-#else /* RAW_TXPOWER_SETTING */
- if (rrq->fixed)
- ret = -EOPNOTSUPP;
-#endif /* RAW_TXPOWER_SETTING */
-
- return ret;
-}
-
-static int prism2_ioctl_giwtxpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
-#ifdef RAW_TXPOWER_SETTING
- struct iw_param *rrq = &wrqu->txpower;
- struct hostap_interface *iface;
- local_info_t *local;
- u16 resp0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- rrq->flags = IW_TXPOW_DBM;
- rrq->disabled = 0;
- rrq->fixed = 0;
-
- if (local->txpower_type == PRISM2_TXPOWER_AUTO) {
- if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF,
- HFA386X_CR_MANUAL_TX_POWER,
- NULL, &resp0) == 0) {
- rrq->value = prism2_txpower_hfa386x_to_dBm(resp0);
- } else {
- /* Could not get real txpower; guess 15 dBm */
- rrq->value = 15;
- }
- } else if (local->txpower_type == PRISM2_TXPOWER_OFF) {
- rrq->value = 0;
- rrq->disabled = 1;
- } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
- rrq->value = local->txpower;
- rrq->fixed = 1;
- } else {
- printk("SIOCGIWTXPOW - unknown txpower_type=%d\n",
- local->txpower_type);
- }
- return 0;
-#else /* RAW_TXPOWER_SETTING */
- return -EOPNOTSUPP;
-#endif /* RAW_TXPOWER_SETTING */
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-
-/* HostScan request works with and without host_roaming mode. In addition, it
- * does not break current association. However, it requires newer station
- * firmware version (>= 1.3.1) than scan request. */
-static int prism2_request_hostscan(struct net_device *dev,
- u8 *ssid, u8 ssid_len)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_hostscan_request scan_req;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(local->channel_mask &
- local->scan_channel_mask);
- scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
- if (ssid) {
- if (ssid_len > 32)
- return -EINVAL;
- scan_req.target_ssid_len = cpu_to_le16(ssid_len);
- memcpy(scan_req.target_ssid, ssid, ssid_len);
- }
-
- if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
- sizeof(scan_req))) {
- printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name);
- return -EINVAL;
- }
- return 0;
-}
-
-
-static int prism2_request_scan(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_scan_request scan_req;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(local->channel_mask &
- local->scan_channel_mask);
- scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
-
- /* FIX:
- * It seems to be enough to set roaming mode for a short moment to
- * host-based and then setup scanrequest data and return the mode to
- * firmware-based.
- *
- * Master mode would need to drop to Managed mode for a short while
- * to make scanning work.. Or sweep through the different channels and
- * use passive scan based on beacons. */
-
- if (!local->host_roaming)
- hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
- HFA384X_ROAMING_HOST);
-
- if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req,
- sizeof(scan_req))) {
- printk(KERN_DEBUG "SCANREQUEST failed\n");
- ret = -EINVAL;
- }
-
- if (!local->host_roaming)
- hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
- HFA384X_ROAMING_FIRMWARE);
-
- return ret;
-}
-
-#else /* !PRISM2_NO_STATION_MODES */
-
-static inline int prism2_request_hostscan(struct net_device *dev,
- u8 *ssid, u8 ssid_len)
-{
- return -EOPNOTSUPP;
-}
-
-
-static inline int prism2_request_scan(struct net_device *dev)
-{
- return -EOPNOTSUPP;
-}
-
-#endif /* !PRISM2_NO_STATION_MODES */
-
-
-static int prism2_ioctl_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret;
- u8 *ssid = NULL, ssid_len = 0;
- struct iw_scan_req *req = (struct iw_scan_req *) extra;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (data->length < sizeof(struct iw_scan_req))
- req = NULL;
-
- if (local->iw_mode == IW_MODE_MASTER) {
- /* In master mode, we just return the results of our local
- * tables, so we don't need to start anything...
- * Jean II */
- data->length = 0;
- return 0;
- }
-
- if (!local->dev_enabled)
- return -ENETDOWN;
-
- if (req && data->flags & IW_SCAN_THIS_ESSID) {
- ssid = req->essid;
- ssid_len = req->essid_len;
-
- if (ssid_len &&
- ((local->iw_mode != IW_MODE_INFRA &&
- local->iw_mode != IW_MODE_ADHOC) ||
- (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))))
- return -EOPNOTSUPP;
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
- ret = prism2_request_hostscan(dev, ssid, ssid_len);
- else
- ret = prism2_request_scan(dev);
-
- if (ret == 0)
- local->scan_timestamp = jiffies;
-
- /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */
-
- return ret;
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static char * __prism2_translate_scan(local_info_t *local,
- struct iw_request_info *info,
- struct hfa384x_hostscan_result *scan,
- struct hostap_bss_info *bss,
- char *current_ev, char *end_buf)
-{
- int i, chan;
- struct iw_event iwe;
- char *current_val;
- u16 capabilities;
- u8 *pos;
- u8 *ssid, *bssid;
- size_t ssid_len;
- char *buf;
-
- if (bss) {
- ssid = bss->ssid;
- ssid_len = bss->ssid_len;
- bssid = bss->bssid;
- } else {
- ssid = scan->ssid;
- ssid_len = le16_to_cpu(scan->ssid_len);
- bssid = scan->bssid;
- }
- if (ssid_len > 32)
- ssid_len = 32;
-
- /* First entry *MUST* be the AP MAC address */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ssid);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWMODE;
- if (bss) {
- capabilities = bss->capab_info;
- } else {
- capabilities = le16_to_cpu(scan->capability);
- }
- if (capabilities & (WLAN_CAPABILITY_ESS |
- WLAN_CAPABILITY_IBSS)) {
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- if (scan) {
- chan = le16_to_cpu(scan->chid);
- } else if (bss) {
- chan = bss->chan;
- } else {
- chan = 0;
- }
-
- if (chan > 0) {
- iwe.u.freq.m = freq_list[chan - 1] * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- if (scan) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVQUAL;
- if (local->last_scan_type == PRISM2_HOSTSCAN) {
- iwe.u.qual.level = le16_to_cpu(scan->sl);
- iwe.u.qual.noise = le16_to_cpu(scan->anl);
- } else {
- iwe.u.qual.level =
- HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl));
- iwe.u.qual.noise =
- HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl));
- }
- iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_UPDATED
- | IW_QUAL_QUAL_INVALID
- | IW_QUAL_DBM;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, "");
-
- /* TODO: add SuppRates into BSS table */
- if (scan) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWRATE;
- current_val = current_ev + iwe_stream_lcp_len(info);
- pos = scan->sup_rates;
- for (i = 0; i < sizeof(scan->sup_rates); i++) {
- if (pos[i] == 0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(
- info, current_ev, current_val, end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
- }
-
- /* TODO: add BeaconInt,resp_rate,atim into BSS table */
- buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC);
- if (buf && scan) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
-
- if (local->last_scan_type == PRISM2_HOSTSCAN &&
- (capabilities & WLAN_CAPABILITY_IBSS)) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe, buf);
- }
- }
- kfree(buf);
-
- if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = bss->wpa_ie_len;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->wpa_ie);
- }
-
- if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = bss->rsn_ie_len;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->rsn_ie);
- }
-
- return current_ev;
-}
-
-
-/* Translate scan data returned from the card to a card independent
- * format that the Wireless Tools will understand - Jean II */
-static inline int prism2_translate_scan(local_info_t *local,
- struct iw_request_info *info,
- char *buffer, int buflen)
-{
- struct hfa384x_hostscan_result *scan;
- int entry;
- char *current_ev = buffer;
- char *end_buf = buffer + buflen;
- struct list_head *ptr;
-
- spin_lock_bh(&local->lock);
-
- list_for_each(ptr, &local->bss_list) {
- struct hostap_bss_info *bss;
- bss = list_entry(ptr, struct hostap_bss_info, list);
- bss->included = 0;
- }
-
- for (entry = 0; entry < local->last_scan_results_count; entry++) {
- int found = 0;
- scan = &local->last_scan_results[entry];
-
- /* Report every SSID if the AP is using multiple SSIDs. If no
- * BSS record is found (e.g., when WPA mode is disabled),
- * report the AP once. */
- list_for_each(ptr, &local->bss_list) {
- struct hostap_bss_info *bss;
- bss = list_entry(ptr, struct hostap_bss_info, list);
- if (ether_addr_equal(bss->bssid, scan->bssid)) {
- bss->included = 1;
- current_ev = __prism2_translate_scan(
- local, info, scan, bss, current_ev,
- end_buf);
- found++;
- }
- }
- if (!found) {
- current_ev = __prism2_translate_scan(
- local, info, scan, NULL, current_ev, end_buf);
- }
- /* Check if there is space for one more entry */
- if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a bigger buffer */
- spin_unlock_bh(&local->lock);
- return -E2BIG;
- }
- }
-
- /* Prism2 firmware has limits (32 at least in some versions) for number
- * of BSSes in scan results. Extend this limit by using local BSS list.
- */
- list_for_each(ptr, &local->bss_list) {
- struct hostap_bss_info *bss;
- bss = list_entry(ptr, struct hostap_bss_info, list);
- if (bss->included)
- continue;
- current_ev = __prism2_translate_scan(local, info, NULL, bss,
- current_ev, end_buf);
- /* Check if there is space for one more entry */
- if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a bigger buffer */
- spin_unlock_bh(&local->lock);
- return -E2BIG;
- }
- }
-
- spin_unlock_bh(&local->lock);
-
- return current_ev - buffer;
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Wait until the scan is finished. We can probably do better
- * than that - Jean II */
- if (local->scan_timestamp &&
- time_before(jiffies, local->scan_timestamp + 3 * HZ)) {
- /* Important note : we don't want to block the caller
- * until results are ready for various reasons.
- * First, managing wait queues is complex and racy
- * (there may be multiple simultaneous callers).
- * Second, we grab some rtnetlink lock before coming
- * here (in dev_ioctl()).
- * Third, the caller can wait on the Wireless Event
- * - Jean II */
- return -EAGAIN;
- }
- local->scan_timestamp = 0;
-
- res = prism2_translate_scan(local, info, extra, data->length);
-
- if (res >= 0) {
- data->length = res;
- return 0;
- } else {
- data->length = 0;
- return res;
- }
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->iw_mode == IW_MODE_MASTER) {
- /* In MASTER mode, it doesn't make sense to go around
- * scanning the frequencies and make the stations we serve
- * wait when what the user is really interested about is the
- * list of stations and access points we are talking to.
- * So, just extract results from our cache...
- * Jean II */
-
- /* Translate to WE format */
- res = prism2_ap_translate_scan(dev, info, extra);
- if (res >= 0) {
- printk(KERN_DEBUG "Scan result translation succeeded "
- "(length=%d)\n", res);
- data->length = res;
- return 0;
- } else {
- printk(KERN_DEBUG
- "Scan result translation failed (res=%d)\n",
- res);
- data->length = 0;
- return res;
- }
- } else {
- /* Station mode */
- return prism2_ioctl_giwscan_sta(dev, info, data, extra);
- }
-}
-
-
-static const struct iw_priv_args prism2_priv[] = {
- { PRISM2_IOCTL_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" },
- { PRISM2_IOCTL_READMIF,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" },
- { PRISM2_IOCTL_WRITEMIF,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" },
- { PRISM2_IOCTL_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" },
- { PRISM2_IOCTL_INQUIRE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" },
- { PRISM2_IOCTL_SET_RID_WORD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" },
- { PRISM2_IOCTL_MACCMD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" },
- { PRISM2_IOCTL_WDS_ADD,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" },
- { PRISM2_IOCTL_WDS_DEL,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" },
- { PRISM2_IOCTL_ADDMAC,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" },
- { PRISM2_IOCTL_DELMAC,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" },
- { PRISM2_IOCTL_KICKMAC,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" },
- /* --- raw access to sub-ioctls --- */
- { PRISM2_IOCTL_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" },
- { PRISM2_IOCTL_GET_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" },
- /* --- sub-ioctls handlers --- */
- { PRISM2_IOCTL_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
- { PRISM2_IOCTL_GET_PRISM2_PARAM,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
- /* --- sub-ioctls definitions --- */
- { PRISM2_PARAM_TXRATECTRL,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" },
- { PRISM2_PARAM_TXRATECTRL,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" },
- { PRISM2_PARAM_BEACON_INT,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" },
- { PRISM2_PARAM_BEACON_INT,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" },
-#ifndef PRISM2_NO_STATION_MODES
- { PRISM2_PARAM_PSEUDO_IBSS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" },
- { PRISM2_PARAM_PSEUDO_IBSS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" },
-#endif /* PRISM2_NO_STATION_MODES */
- { PRISM2_PARAM_ALC,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" },
- { PRISM2_PARAM_ALC,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" },
- { PRISM2_PARAM_DUMP,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" },
- { PRISM2_PARAM_DUMP,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" },
- { PRISM2_PARAM_OTHER_AP_POLICY,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" },
- { PRISM2_PARAM_OTHER_AP_POLICY,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" },
- { PRISM2_PARAM_AP_MAX_INACTIVITY,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" },
- { PRISM2_PARAM_AP_MAX_INACTIVITY,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" },
- { PRISM2_PARAM_AP_BRIDGE_PACKETS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" },
- { PRISM2_PARAM_AP_BRIDGE_PACKETS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" },
- { PRISM2_PARAM_DTIM_PERIOD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" },
- { PRISM2_PARAM_DTIM_PERIOD,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" },
- { PRISM2_PARAM_AP_NULLFUNC_ACK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" },
- { PRISM2_PARAM_AP_NULLFUNC_ACK,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" },
- { PRISM2_PARAM_MAX_WDS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" },
- { PRISM2_PARAM_MAX_WDS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" },
- { PRISM2_PARAM_AP_AUTOM_AP_WDS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" },
- { PRISM2_PARAM_AP_AUTOM_AP_WDS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" },
- { PRISM2_PARAM_AP_AUTH_ALGS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" },
- { PRISM2_PARAM_AP_AUTH_ALGS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" },
- { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" },
- { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" },
- { PRISM2_PARAM_HOST_ENCRYPT,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" },
- { PRISM2_PARAM_HOST_ENCRYPT,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" },
- { PRISM2_PARAM_HOST_DECRYPT,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" },
- { PRISM2_PARAM_HOST_DECRYPT,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" },
-#ifndef PRISM2_NO_STATION_MODES
- { PRISM2_PARAM_HOST_ROAMING,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" },
- { PRISM2_PARAM_HOST_ROAMING,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" },
-#endif /* PRISM2_NO_STATION_MODES */
- { PRISM2_PARAM_BCRX_STA_KEY,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" },
- { PRISM2_PARAM_BCRX_STA_KEY,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" },
- { PRISM2_PARAM_IEEE_802_1X,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" },
- { PRISM2_PARAM_IEEE_802_1X,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" },
- { PRISM2_PARAM_ANTSEL_TX,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" },
- { PRISM2_PARAM_ANTSEL_TX,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" },
- { PRISM2_PARAM_ANTSEL_RX,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" },
- { PRISM2_PARAM_ANTSEL_RX,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" },
- { PRISM2_PARAM_MONITOR_TYPE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" },
- { PRISM2_PARAM_MONITOR_TYPE,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" },
- { PRISM2_PARAM_WDS_TYPE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" },
- { PRISM2_PARAM_WDS_TYPE,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" },
- { PRISM2_PARAM_HOSTSCAN,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" },
- { PRISM2_PARAM_HOSTSCAN,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" },
- { PRISM2_PARAM_AP_SCAN,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" },
- { PRISM2_PARAM_AP_SCAN,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" },
- { PRISM2_PARAM_ENH_SEC,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" },
- { PRISM2_PARAM_ENH_SEC,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" },
-#ifdef PRISM2_IO_DEBUG
- { PRISM2_PARAM_IO_DEBUG,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" },
- { PRISM2_PARAM_IO_DEBUG,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" },
-#endif /* PRISM2_IO_DEBUG */
- { PRISM2_PARAM_BASIC_RATES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" },
- { PRISM2_PARAM_BASIC_RATES,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" },
- { PRISM2_PARAM_OPER_RATES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" },
- { PRISM2_PARAM_OPER_RATES,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" },
- { PRISM2_PARAM_HOSTAPD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" },
- { PRISM2_PARAM_HOSTAPD,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" },
- { PRISM2_PARAM_HOSTAPD_STA,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" },
- { PRISM2_PARAM_HOSTAPD_STA,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" },
- { PRISM2_PARAM_WPA,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" },
- { PRISM2_PARAM_WPA,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" },
- { PRISM2_PARAM_PRIVACY_INVOKED,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" },
- { PRISM2_PARAM_PRIVACY_INVOKED,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" },
- { PRISM2_PARAM_TKIP_COUNTERMEASURES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" },
- { PRISM2_PARAM_TKIP_COUNTERMEASURES,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" },
- { PRISM2_PARAM_DROP_UNENCRYPTED,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" },
- { PRISM2_PARAM_DROP_UNENCRYPTED,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" },
- { PRISM2_PARAM_SCAN_CHANNEL_MASK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" },
- { PRISM2_PARAM_SCAN_CHANNEL_MASK,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" },
-};
-
-
-static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *uwrq, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int *i = (int *) extra;
- int param = *i;
- int value = *(i + 1);
- int ret = 0;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (param) {
- case PRISM2_PARAM_TXRATECTRL:
- local->fw_tx_rate_control = value;
- break;
-
- case PRISM2_PARAM_BEACON_INT:
- if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- else
- local->beacon_int = value;
- break;
-
-#ifndef PRISM2_NO_STATION_MODES
- case PRISM2_PARAM_PSEUDO_IBSS:
- if (value == local->pseudo_adhoc)
- break;
-
- if (value != 0 && value != 1) {
- ret = -EINVAL;
- break;
- }
-
- printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n",
- dev->name, local->pseudo_adhoc, value);
- local->pseudo_adhoc = value;
- if (local->iw_mode != IW_MODE_ADHOC)
- break;
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- hostap_get_porttype(local))) {
- ret = -EOPNOTSUPP;
- break;
- }
-
- if (local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-#endif /* PRISM2_NO_STATION_MODES */
-
- case PRISM2_PARAM_ALC:
- printk(KERN_DEBUG "%s: %s ALC\n", dev->name,
- value == 0 ? "Disabling" : "Enabling");
- val = HFA384X_TEST_CFG_BIT_ALC;
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CFG_BITS << 8),
- value == 0 ? 0 : 1, &val, NULL);
- break;
-
- case PRISM2_PARAM_DUMP:
- local->frame_dump = value;
- break;
-
- case PRISM2_PARAM_OTHER_AP_POLICY:
- if (value < 0 || value > 3) {
- ret = -EINVAL;
- break;
- }
- if (local->ap != NULL)
- local->ap->ap_policy = value;
- break;
-
- case PRISM2_PARAM_AP_MAX_INACTIVITY:
- if (value < 0 || value > 7 * 24 * 60 * 60) {
- ret = -EINVAL;
- break;
- }
- if (local->ap != NULL)
- local->ap->max_inactivity = value * HZ;
- break;
-
- case PRISM2_PARAM_AP_BRIDGE_PACKETS:
- if (local->ap != NULL)
- local->ap->bridge_packets = value;
- break;
-
- case PRISM2_PARAM_DTIM_PERIOD:
- if (value < 0 || value > 65535) {
- ret = -EINVAL;
- break;
- }
- if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value)
- || local->func->reset_port(dev))
- ret = -EINVAL;
- else
- local->dtim_period = value;
- break;
-
- case PRISM2_PARAM_AP_NULLFUNC_ACK:
- if (local->ap != NULL)
- local->ap->nullfunc_ack = value;
- break;
-
- case PRISM2_PARAM_MAX_WDS:
- local->wds_max_connections = value;
- break;
-
- case PRISM2_PARAM_AP_AUTOM_AP_WDS:
- if (local->ap != NULL) {
- if (!local->ap->autom_ap_wds && value) {
- /* add WDS link to all APs in STA table */
- hostap_add_wds_links(local);
- }
- local->ap->autom_ap_wds = value;
- }
- break;
-
- case PRISM2_PARAM_AP_AUTH_ALGS:
- local->auth_algs = value;
- if (hostap_set_auth_algs(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
- local->monitor_allow_fcserr = value;
- break;
-
- case PRISM2_PARAM_HOST_ENCRYPT:
- local->host_encrypt = value;
- if (hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_HOST_DECRYPT:
- local->host_decrypt = value;
- if (hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
-#ifndef PRISM2_NO_STATION_MODES
- case PRISM2_PARAM_HOST_ROAMING:
- if (value < 0 || value > 2) {
- ret = -EINVAL;
- break;
- }
- local->host_roaming = value;
- if (hostap_set_roaming(local) || local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-#endif /* PRISM2_NO_STATION_MODES */
-
- case PRISM2_PARAM_BCRX_STA_KEY:
- local->bcrx_sta_key = value;
- break;
-
- case PRISM2_PARAM_IEEE_802_1X:
- local->ieee_802_1x = value;
- break;
-
- case PRISM2_PARAM_ANTSEL_TX:
- if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
- ret = -EINVAL;
- break;
- }
- local->antsel_tx = value;
- hostap_set_antsel(local);
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
- ret = -EINVAL;
- break;
- }
- local->antsel_rx = value;
- hostap_set_antsel(local);
- break;
-
- case PRISM2_PARAM_MONITOR_TYPE:
- if (value != PRISM2_MONITOR_80211 &&
- value != PRISM2_MONITOR_CAPHDR &&
- value != PRISM2_MONITOR_PRISM &&
- value != PRISM2_MONITOR_RADIOTAP) {
- ret = -EINVAL;
- break;
- }
- local->monitor_type = value;
- if (local->iw_mode == IW_MODE_MONITOR)
- hostap_monitor_set_type(local);
- break;
-
- case PRISM2_PARAM_WDS_TYPE:
- local->wds_type = value;
- break;
-
- case PRISM2_PARAM_HOSTSCAN:
- {
- struct hfa384x_hostscan_request scan_req;
- u16 rate;
-
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(0x3fff);
- switch (value) {
- case 1: rate = HFA384X_RATES_1MBPS; break;
- case 2: rate = HFA384X_RATES_2MBPS; break;
- case 3: rate = HFA384X_RATES_5MBPS; break;
- case 4: rate = HFA384X_RATES_11MBPS; break;
- default: rate = HFA384X_RATES_1MBPS; break;
- }
- scan_req.txrate = cpu_to_le16(rate);
- /* leave SSID empty to accept all SSIDs */
-
- if (local->iw_mode == IW_MODE_MASTER) {
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- HFA384X_PORTTYPE_BSS) ||
- local->func->reset_port(dev))
- printk(KERN_DEBUG "Leaving Host AP mode "
- "for HostScan failed\n");
- }
-
- if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
- sizeof(scan_req))) {
- printk(KERN_DEBUG "HOSTSCAN failed\n");
- ret = -EINVAL;
- }
- if (local->iw_mode == IW_MODE_MASTER) {
- wait_queue_entry_t __wait;
- init_waitqueue_entry(&__wait, current);
- add_wait_queue(&local->hostscan_wq, &__wait);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- if (signal_pending(current))
- ret = -EINTR;
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&local->hostscan_wq, &__wait);
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- HFA384X_PORTTYPE_HOSTAP) ||
- local->func->reset_port(dev))
- printk(KERN_DEBUG "Returning to Host AP mode "
- "after HostScan failed\n");
- }
- break;
- }
-
- case PRISM2_PARAM_AP_SCAN:
- local->passive_scan_interval = value;
- if (timer_pending(&local->passive_scan_timer))
- del_timer(&local->passive_scan_timer);
- if (value > 0 && value < INT_MAX / HZ) {
- local->passive_scan_timer.expires = jiffies +
- local->passive_scan_interval * HZ;
- add_timer(&local->passive_scan_timer);
- }
- break;
-
- case PRISM2_PARAM_ENH_SEC:
- if (value < 0 || value > 3) {
- ret = -EINVAL;
- break;
- }
- local->enh_sec = value;
- if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY,
- local->enh_sec) ||
- local->func->reset_port(dev)) {
- printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w "
- "1.6.3 or newer\n", dev->name);
- ret = -EOPNOTSUPP;
- }
- break;
-
-#ifdef PRISM2_IO_DEBUG
- case PRISM2_PARAM_IO_DEBUG:
- local->io_debug_enabled = value;
- break;
-#endif /* PRISM2_IO_DEBUG */
-
- case PRISM2_PARAM_BASIC_RATES:
- if ((value & local->tx_rate_control) != value || value == 0) {
- printk(KERN_INFO "%s: invalid basic rate set - basic "
- "rates must be in supported rate set\n",
- dev->name);
- ret = -EINVAL;
- break;
- }
- local->basic_rates = value;
- if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- local->basic_rates) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_OPER_RATES:
- local->tx_rate_control = value;
- if (hostap_set_rate(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_HOSTAPD:
- ret = hostap_set_hostapd(local, value, 1);
- break;
-
- case PRISM2_PARAM_HOSTAPD_STA:
- ret = hostap_set_hostapd_sta(local, value, 1);
- break;
-
- case PRISM2_PARAM_WPA:
- local->wpa = value;
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- ret = -EOPNOTSUPP;
- else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
- value ? 1 : 0))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_PRIVACY_INVOKED:
- local->privacy_invoked = value;
- if (hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_TKIP_COUNTERMEASURES:
- local->tkip_countermeasures = value;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- local->drop_unencrypted = value;
- break;
-
- case PRISM2_PARAM_SCAN_CHANNEL_MASK:
- local->scan_channel_mask = value;
- break;
-
- default:
- printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n",
- dev->name, param);
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int *param = (int *) extra;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (*param) {
- case PRISM2_PARAM_TXRATECTRL:
- *param = local->fw_tx_rate_control;
- break;
-
- case PRISM2_PARAM_BEACON_INT:
- *param = local->beacon_int;
- break;
-
- case PRISM2_PARAM_PSEUDO_IBSS:
- *param = local->pseudo_adhoc;
- break;
-
- case PRISM2_PARAM_ALC:
- ret = -EOPNOTSUPP; /* FIX */
- break;
-
- case PRISM2_PARAM_DUMP:
- *param = local->frame_dump;
- break;
-
- case PRISM2_PARAM_OTHER_AP_POLICY:
- if (local->ap != NULL)
- *param = local->ap->ap_policy;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_MAX_INACTIVITY:
- if (local->ap != NULL)
- *param = local->ap->max_inactivity / HZ;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_BRIDGE_PACKETS:
- if (local->ap != NULL)
- *param = local->ap->bridge_packets;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_DTIM_PERIOD:
- *param = local->dtim_period;
- break;
-
- case PRISM2_PARAM_AP_NULLFUNC_ACK:
- if (local->ap != NULL)
- *param = local->ap->nullfunc_ack;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_MAX_WDS:
- *param = local->wds_max_connections;
- break;
-
- case PRISM2_PARAM_AP_AUTOM_AP_WDS:
- if (local->ap != NULL)
- *param = local->ap->autom_ap_wds;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_AUTH_ALGS:
- *param = local->auth_algs;
- break;
-
- case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
- *param = local->monitor_allow_fcserr;
- break;
-
- case PRISM2_PARAM_HOST_ENCRYPT:
- *param = local->host_encrypt;
- break;
-
- case PRISM2_PARAM_HOST_DECRYPT:
- *param = local->host_decrypt;
- break;
-
- case PRISM2_PARAM_HOST_ROAMING:
- *param = local->host_roaming;
- break;
-
- case PRISM2_PARAM_BCRX_STA_KEY:
- *param = local->bcrx_sta_key;
- break;
-
- case PRISM2_PARAM_IEEE_802_1X:
- *param = local->ieee_802_1x;
- break;
-
- case PRISM2_PARAM_ANTSEL_TX:
- *param = local->antsel_tx;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- *param = local->antsel_rx;
- break;
-
- case PRISM2_PARAM_MONITOR_TYPE:
- *param = local->monitor_type;
- break;
-
- case PRISM2_PARAM_WDS_TYPE:
- *param = local->wds_type;
- break;
-
- case PRISM2_PARAM_HOSTSCAN:
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_SCAN:
- *param = local->passive_scan_interval;
- break;
-
- case PRISM2_PARAM_ENH_SEC:
- *param = local->enh_sec;
- break;
-
-#ifdef PRISM2_IO_DEBUG
- case PRISM2_PARAM_IO_DEBUG:
- *param = local->io_debug_enabled;
- break;
-#endif /* PRISM2_IO_DEBUG */
-
- case PRISM2_PARAM_BASIC_RATES:
- *param = local->basic_rates;
- break;
-
- case PRISM2_PARAM_OPER_RATES:
- *param = local->tx_rate_control;
- break;
-
- case PRISM2_PARAM_HOSTAPD:
- *param = local->hostapd;
- break;
-
- case PRISM2_PARAM_HOSTAPD_STA:
- *param = local->hostapd_sta;
- break;
-
- case PRISM2_PARAM_WPA:
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- ret = -EOPNOTSUPP;
- *param = local->wpa;
- break;
-
- case PRISM2_PARAM_PRIVACY_INVOKED:
- *param = local->privacy_invoked;
- break;
-
- case PRISM2_PARAM_TKIP_COUNTERMEASURES:
- *param = local->tkip_countermeasures;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- *param = local->drop_unencrypted;
- break;
-
- case PRISM2_PARAM_SCAN_CHANNEL_MASK:
- *param = local->scan_channel_mask;
- break;
-
- default:
- printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n",
- dev->name, *param);
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_priv_readmif(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u16 resp0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL,
- &resp0))
- return -EOPNOTSUPP;
- else
- *extra = resp0;
-
- return 0;
-}
-
-
-static int prism2_ioctl_priv_writemif(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u16 cr, val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- cr = *extra;
- val = *(extra + 1);
- if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL))
- return -EOPNOTSUPP;
-
- return 0;
-}
-
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
-static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
-{
- struct prism2_download_param *param;
- int ret = 0;
-
- if (p->length < sizeof(struct prism2_download_param) ||
- p->length > 1024 || !p->pointer)
- return -EINVAL;
-
- param = memdup_user(p->pointer, p->length);
- if (IS_ERR(param)) {
- return PTR_ERR(param);
- }
-
- if (p->length < sizeof(struct prism2_download_param) +
- param->num_areas * sizeof(struct prism2_download_area)) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = local->func->download(local, param);
-
- out:
- kfree(param);
- return ret;
-}
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-
-static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
- size_t len)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- u8 *buf;
-
- /*
- * Add 16-bit length in the beginning of the buffer because Prism2 RID
- * includes it.
- */
- buf = kmalloc(len + 2, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- *((__le16 *) buf) = cpu_to_le16(len);
- memcpy(buf + 2, elem, len);
-
- kfree(local->generic_elem);
- local->generic_elem = buf;
- local->generic_elem_len = len + 2;
-
- return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT,
- buf, len + 2);
-}
-
-
-static int prism2_ioctl_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *data = &wrqu->param;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * Host AP driver does not use these parameters and allows
- * wpa_supplicant to control them internally.
- */
- break;
- case IW_AUTH_TKIP_COUNTERMEASURES:
- local->tkip_countermeasures = data->value;
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- local->drop_unencrypted = data->value;
- break;
- case IW_AUTH_80211_AUTH_ALG:
- local->auth_algs = data->value;
- break;
- case IW_AUTH_WPA_ENABLED:
- if (data->value == 0) {
- local->wpa = 0;
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- break;
- prism2_set_genericelement(dev, "", 0);
- local->host_roaming = 0;
- local->privacy_invoked = 0;
- if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
- 0) ||
- hostap_set_roaming(local) ||
- hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- return -EINVAL;
- break;
- }
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- return -EOPNOTSUPP;
- local->host_roaming = 2;
- local->privacy_invoked = 1;
- local->wpa = 1;
- if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) ||
- hostap_set_roaming(local) ||
- hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- return -EINVAL;
- break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- local->ieee_802_1x = data->value;
- break;
- case IW_AUTH_PRIVACY_INVOKED:
- local->privacy_invoked = data->value;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-static int prism2_ioctl_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *data = &wrqu->param;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * Host AP driver does not use these parameters and allows
- * wpa_supplicant to control them internally.
- */
- return -EOPNOTSUPP;
- case IW_AUTH_TKIP_COUNTERMEASURES:
- data->value = local->tkip_countermeasures;
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- data->value = local->drop_unencrypted;
- break;
- case IW_AUTH_80211_AUTH_ALG:
- data->value = local->auth_algs;
- break;
- case IW_AUTH_WPA_ENABLED:
- data->value = local->wpa;
- break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- data->value = local->ieee_802_1x;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-static int prism2_ioctl_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int i, ret = 0;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
- u8 *addr;
- const char *alg, *module;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i > WEP_KEYS)
- return -EINVAL;
- if (i < 1 || i > WEP_KEYS)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
- if (i < 0 || i >= WEP_KEYS)
- return -EINVAL;
-
- addr = ext->addr.sa_data;
- if (is_broadcast_ether_addr(addr)) {
- sta_ptr = NULL;
- crypt = &local->crypt_info.crypt[i];
- } else {
- if (i != 0)
- return -EINVAL;
- sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
- if (sta_ptr == NULL) {
- if (local->iw_mode == IW_MODE_INFRA) {
- /*
- * TODO: add STA entry for the current AP so
- * that unicast key can be used. For now, this
- * is emulated by using default key idx 0.
- */
- i = 0;
- crypt = &local->crypt_info.crypt[i];
- } else
- return -EINVAL;
- }
- }
-
- if ((erq->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- goto done;
- }
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_WEP:
- alg = "WEP";
- module = "lib80211_crypt_wep";
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = "TKIP";
- module = "lib80211_crypt_tkip";
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = "CCMP";
- module = "lib80211_crypt_ccmp";
- break;
- default:
- printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
- local->dev->name, ext->alg);
- ret = -EOPNOTSUPP;
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(alg);
- if (ops == NULL) {
- request_module(module);
- ops = lib80211_get_crypto_ops(alg);
- }
- if (ops == NULL) {
- printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
- local->dev->name, alg);
- ret = -EOPNOTSUPP;
- goto done;
- }
-
- if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) {
- /*
- * Per station encryption and other than WEP algorithms
- * require host-based encryption, so force them on
- * automatically.
- */
- local->host_decrypt = local->host_encrypt = 1;
- }
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(i);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- ret = -EINVAL;
- goto done;
- }
-
- *crypt = new_crypt;
- }
-
- /*
- * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the
- * existing seq# should not be changed.
- * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq#
- * should be changed to something else than zero.
- */
- if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0)
- && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
- (*crypt)->priv) < 0) {
- printk(KERN_DEBUG "%s: key setting failed\n",
- local->dev->name);
- ret = -EINVAL;
- goto done;
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- if (!sta_ptr)
- local->crypt_info.tx_keyidx = i;
- }
-
-
- if (sta_ptr == NULL && ext->key_len > 0) {
- int first = 1, j;
- for (j = 0; j < WEP_KEYS; j++) {
- if (j != i && local->crypt_info.crypt[j]) {
- first = 0;
- break;
- }
- }
- if (first)
- local->crypt_info.tx_keyidx = i;
- }
-
- done:
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- local->open_wep = erq->flags & IW_ENCODE_OPEN;
-
- /*
- * Do not reset port0 if card is in Managed mode since resetting will
- * generate new IEEE 802.11 authentication which may end up in looping
- * with IEEE 802.1X. Prism2 documentation seem to require port reset
- * after WEP configuration. However, keys are apparently changed at
- * least in Managed mode.
- */
- if (ret == 0 &&
- (hostap_set_encryption(local) ||
- (local->iw_mode != IW_MODE_INFRA &&
- local->func->reset_port(local->dev))))
- ret = -EINVAL;
-
- return ret;
-}
-
-
-static int prism2_ioctl_giwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
- int max_key_len, i;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- u8 *addr;
-
- max_key_len = erq->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i < 1 || i > WEP_KEYS)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
-
- addr = ext->addr.sa_data;
- if (is_broadcast_ether_addr(addr)) {
- sta_ptr = NULL;
- crypt = &local->crypt_info.crypt[i];
- } else {
- i = 0;
- sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
- if (sta_ptr == NULL)
- return -EINVAL;
- }
- erq->flags = i + 1;
- memset(ext, 0, sizeof(*ext));
-
- if (*crypt == NULL || (*crypt)->ops == NULL) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- } else {
- if (strcmp((*crypt)->ops->name, "WEP") == 0)
- ext->alg = IW_ENCODE_ALG_WEP;
- else if (strcmp((*crypt)->ops->name, "TKIP") == 0)
- ext->alg = IW_ENCODE_ALG_TKIP;
- else if (strcmp((*crypt)->ops->name, "CCMP") == 0)
- ext->alg = IW_ENCODE_ALG_CCMP;
- else
- return -EINVAL;
-
- if ((*crypt)->ops->get_key) {
- ext->key_len =
- (*crypt)->ops->get_key(ext->key,
- max_key_len,
- ext->tx_seq,
- (*crypt)->priv);
- if (ext->key_len &&
- (ext->alg == IW_ENCODE_ALG_TKIP ||
- ext->alg == IW_ENCODE_ALG_CCMP))
- ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
- }
- }
-
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- return 0;
-}
-
-
-static int prism2_ioctl_set_encryption(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int ret = 0;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
-
- param->u.crypt.err = 0;
- param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
-
- if (param_len !=
- (int) ((char *) param->u.crypt.key - (char *) param) +
- param->u.crypt.key_len)
- return -EINVAL;
-
- if (is_broadcast_ether_addr(param->sta_addr)) {
- if (param->u.crypt.idx >= WEP_KEYS)
- return -EINVAL;
- sta_ptr = NULL;
- crypt = &local->crypt_info.crypt[param->u.crypt.idx];
- } else {
- if (param->u.crypt.idx)
- return -EINVAL;
- sta_ptr = ap_crypt_get_ptrs(
- local->ap, param->sta_addr,
- (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT),
- &crypt);
-
- if (sta_ptr == NULL) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
- return -EINVAL;
- }
- }
-
- if (strcmp(param->u.crypt.alg, "none") == 0) {
- if (crypt)
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
- request_module("lib80211_crypt_wep");
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
- request_module("lib80211_crypt_tkip");
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
- request_module("lib80211_crypt_ccmp");
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- }
- if (ops == NULL) {
- printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
- local->dev->name, param->u.crypt.alg);
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
- ret = -EINVAL;
- goto done;
- }
-
- /* station based encryption and other than WEP algorithms require
- * host-based encryption, so force them on automatically */
- local->host_decrypt = local->host_encrypt = 1;
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- param->u.crypt.err =
- HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED;
- ret = -EINVAL;
- goto done;
- }
-
- *crypt = new_crypt;
- }
-
- if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) ||
- param->u.crypt.key_len > 0) && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(param->u.crypt.key,
- param->u.crypt.key_len, param->u.crypt.seq,
- (*crypt)->priv) < 0) {
- printk(KERN_DEBUG "%s: key setting failed\n",
- local->dev->name);
- param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
- ret = -EINVAL;
- goto done;
- }
-
- if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
- if (!sta_ptr)
- local->crypt_info.tx_keyidx = param->u.crypt.idx;
- else if (param->u.crypt.idx) {
- printk(KERN_DEBUG "%s: TX key idx setting failed\n",
- local->dev->name);
- param->u.crypt.err =
- HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED;
- ret = -EINVAL;
- goto done;
- }
- }
-
- done:
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- /* Do not reset port0 if card is in Managed mode since resetting will
- * generate new IEEE 802.11 authentication which may end up in looping
- * with IEEE 802.1X. Prism2 documentation seem to require port reset
- * after WEP configuration. However, keys are apparently changed at
- * least in Managed mode. */
- if (ret == 0 &&
- (hostap_set_encryption(local) ||
- (local->iw_mode != IW_MODE_INFRA &&
- local->func->reset_port(local->dev)))) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED;
- return -EINVAL;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_get_encryption(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
- int max_key_len;
-
- param->u.crypt.err = 0;
-
- max_key_len = param_len -
- (int) ((char *) param->u.crypt.key - (char *) param);
- if (max_key_len < 0)
- return -EINVAL;
-
- if (is_broadcast_ether_addr(param->sta_addr)) {
- sta_ptr = NULL;
- if (param->u.crypt.idx >= WEP_KEYS)
- param->u.crypt.idx = local->crypt_info.tx_keyidx;
- crypt = &local->crypt_info.crypt[param->u.crypt.idx];
- } else {
- param->u.crypt.idx = 0;
- sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
- &crypt);
-
- if (sta_ptr == NULL) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
- return -EINVAL;
- }
- }
-
- if (*crypt == NULL || (*crypt)->ops == NULL) {
- memcpy(param->u.crypt.alg, "none", 5);
- param->u.crypt.key_len = 0;
- param->u.crypt.idx = 0xff;
- } else {
- strscpy(param->u.crypt.alg, (*crypt)->ops->name,
- HOSTAP_CRYPT_ALG_NAME_LEN);
- param->u.crypt.key_len = 0;
-
- memset(param->u.crypt.seq, 0, 8);
- if ((*crypt)->ops->get_key) {
- param->u.crypt.key_len =
- (*crypt)->ops->get_key(param->u.crypt.key,
- max_key_len,
- param->u.crypt.seq,
- (*crypt)->priv);
- }
- }
-
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- return 0;
-}
-
-
-static int prism2_ioctl_get_rid(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int max_len, res;
-
- max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
- if (max_len < 0)
- return -EINVAL;
-
- res = local->func->get_rid(local->dev, param->u.rid.rid,
- param->u.rid.data, param->u.rid.len, 0);
- if (res >= 0) {
- param->u.rid.len = res;
- return 0;
- }
-
- return res;
-}
-
-
-static int prism2_ioctl_set_rid(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int max_len;
-
- max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
- if (max_len < 0 || max_len < param->u.rid.len)
- return -EINVAL;
-
- return local->func->set_rid(local->dev, param->u.rid.rid,
- param->u.rid.data, param->u.rid.len);
-}
-
-
-static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n",
- local->dev->name, param->sta_addr);
- memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int prism2_ioctl_siwgenie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- return prism2_set_genericelement(dev, extra, data->length);
-}
-
-
-static int prism2_ioctl_giwgenie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- int len = local->generic_elem_len - 2;
-
- if (len <= 0 || local->generic_elem == NULL) {
- data->length = 0;
- return 0;
- }
-
- if (data->length < len)
- return -E2BIG;
-
- data->length = len;
- memcpy(extra, local->generic_elem + 2, len);
-
- return 0;
-}
-
-
-static int prism2_ioctl_set_generic_element(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int max_len, len;
-
- len = param->u.generic_elem.len;
- max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
- if (max_len < 0 || max_len < len)
- return -EINVAL;
-
- return prism2_set_genericelement(local->dev,
- param->u.generic_elem.data, len);
-}
-
-
-static int prism2_ioctl_siwmlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct iw_mlme *mlme = (struct iw_mlme *) extra;
- __le16 reason;
-
- reason = cpu_to_le16(mlme->reason_code);
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
- IEEE80211_STYPE_DEAUTH,
- (u8 *) &reason, 2);
- case IW_MLME_DISASSOC:
- return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
- IEEE80211_STYPE_DISASSOC,
- (u8 *) &reason, 2);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
-static int prism2_ioctl_mlme(local_info_t *local,
- struct prism2_hostapd_param *param)
-{
- __le16 reason;
-
- reason = cpu_to_le16(param->u.mlme.reason_code);
- switch (param->u.mlme.cmd) {
- case MLME_STA_DEAUTH:
- return prism2_sta_send_mgmt(local, param->sta_addr,
- IEEE80211_STYPE_DEAUTH,
- (u8 *) &reason, 2);
- case MLME_STA_DISASSOC:
- return prism2_sta_send_mgmt(local, param->sta_addr,
- IEEE80211_STYPE_DISASSOC,
- (u8 *) &reason, 2);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
-static int prism2_ioctl_scan_req(local_info_t *local,
- struct prism2_hostapd_param *param)
-{
-#ifndef PRISM2_NO_STATION_MODES
- if ((local->iw_mode != IW_MODE_INFRA &&
- local->iw_mode != IW_MODE_ADHOC) ||
- (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))
- return -EOPNOTSUPP;
-
- if (!local->dev_enabled)
- return -ENETDOWN;
-
- return prism2_request_hostscan(local->dev, param->u.scan_req.ssid,
- param->u.scan_req.ssid_len);
-#else /* PRISM2_NO_STATION_MODES */
- return -EOPNOTSUPP;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
-{
- struct prism2_hostapd_param *param;
- int ret = 0;
- int ap_ioctl = 0;
-
- if (p->length < sizeof(struct prism2_hostapd_param) ||
- p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
- return -EINVAL;
-
- param = memdup_user(p->pointer, p->length);
- if (IS_ERR(param)) {
- return PTR_ERR(param);
- }
-
- switch (param->cmd) {
- case PRISM2_SET_ENCRYPTION:
- ret = prism2_ioctl_set_encryption(local, param, p->length);
- break;
- case PRISM2_GET_ENCRYPTION:
- ret = prism2_ioctl_get_encryption(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_GET_RID:
- ret = prism2_ioctl_get_rid(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_SET_RID:
- ret = prism2_ioctl_set_rid(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR:
- ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
- ret = prism2_ioctl_set_generic_element(local, param,
- p->length);
- break;
- case PRISM2_HOSTAPD_MLME:
- ret = prism2_ioctl_mlme(local, param);
- break;
- case PRISM2_HOSTAPD_SCAN_REQ:
- ret = prism2_ioctl_scan_req(local, param);
- break;
- default:
- ret = prism2_hostapd(local->ap, param);
- ap_ioctl = 1;
- break;
- }
-
- if (ret == 1 || !ap_ioctl) {
- if (copy_to_user(p->pointer, param, p->length)) {
- ret = -EFAULT;
- goto out;
- } else if (ap_ioctl)
- ret = 0;
- }
-
- out:
- kfree(param);
- return ret;
-}
-
-
-static void prism2_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- strscpy(info->driver, "hostap", sizeof(info->driver));
- snprintf(info->fw_version, sizeof(info->fw_version),
- "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
- (local->sta_fw_ver >> 8) & 0xff,
- local->sta_fw_ver & 0xff);
-}
-
-const struct ethtool_ops prism2_ethtool_ops = {
- .get_drvinfo = prism2_get_drvinfo
-};
-
-
-/* Structures to export the Wireless Handlers */
-
-static const iw_handler prism2_handler[] =
-{
- IW_HANDLER(SIOCGIWNAME, prism2_get_name),
- IW_HANDLER(SIOCSIWFREQ, prism2_ioctl_siwfreq),
- IW_HANDLER(SIOCGIWFREQ, prism2_ioctl_giwfreq),
- IW_HANDLER(SIOCSIWMODE, prism2_ioctl_siwmode),
- IW_HANDLER(SIOCGIWMODE, prism2_ioctl_giwmode),
- IW_HANDLER(SIOCSIWSENS, prism2_ioctl_siwsens),
- IW_HANDLER(SIOCGIWSENS, prism2_ioctl_giwsens),
- IW_HANDLER(SIOCGIWRANGE, prism2_ioctl_giwrange),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, prism2_ioctl_siwap),
- IW_HANDLER(SIOCGIWAP, prism2_ioctl_giwap),
- IW_HANDLER(SIOCSIWMLME, prism2_ioctl_siwmlme),
- IW_HANDLER(SIOCGIWAPLIST, prism2_ioctl_giwaplist),
- IW_HANDLER(SIOCSIWSCAN, prism2_ioctl_siwscan),
- IW_HANDLER(SIOCGIWSCAN, prism2_ioctl_giwscan),
- IW_HANDLER(SIOCSIWESSID, prism2_ioctl_siwessid),
- IW_HANDLER(SIOCGIWESSID, prism2_ioctl_giwessid),
- IW_HANDLER(SIOCSIWNICKN, prism2_ioctl_siwnickn),
- IW_HANDLER(SIOCGIWNICKN, prism2_ioctl_giwnickn),
- IW_HANDLER(SIOCSIWRATE, prism2_ioctl_siwrate),
- IW_HANDLER(SIOCGIWRATE, prism2_ioctl_giwrate),
- IW_HANDLER(SIOCSIWRTS, prism2_ioctl_siwrts),
- IW_HANDLER(SIOCGIWRTS, prism2_ioctl_giwrts),
- IW_HANDLER(SIOCSIWFRAG, prism2_ioctl_siwfrag),
- IW_HANDLER(SIOCGIWFRAG, prism2_ioctl_giwfrag),
- IW_HANDLER(SIOCSIWTXPOW, prism2_ioctl_siwtxpow),
- IW_HANDLER(SIOCGIWTXPOW, prism2_ioctl_giwtxpow),
- IW_HANDLER(SIOCSIWRETRY, prism2_ioctl_siwretry),
- IW_HANDLER(SIOCGIWRETRY, prism2_ioctl_giwretry),
- IW_HANDLER(SIOCSIWENCODE, prism2_ioctl_siwencode),
- IW_HANDLER(SIOCGIWENCODE, prism2_ioctl_giwencode),
- IW_HANDLER(SIOCSIWPOWER, prism2_ioctl_siwpower),
- IW_HANDLER(SIOCGIWPOWER, prism2_ioctl_giwpower),
- IW_HANDLER(SIOCSIWGENIE, prism2_ioctl_siwgenie),
- IW_HANDLER(SIOCGIWGENIE, prism2_ioctl_giwgenie),
- IW_HANDLER(SIOCSIWAUTH, prism2_ioctl_siwauth),
- IW_HANDLER(SIOCGIWAUTH, prism2_ioctl_giwauth),
- IW_HANDLER(SIOCSIWENCODEEXT, prism2_ioctl_siwencodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, prism2_ioctl_giwencodeext),
-};
-
-static const iw_handler prism2_private_handler[] =
-{ /* SIOCIWFIRSTPRIV + */
- prism2_ioctl_priv_prism2_param, /* 0 */
- prism2_ioctl_priv_get_prism2_param, /* 1 */
- prism2_ioctl_priv_writemif, /* 2 */
- prism2_ioctl_priv_readmif, /* 3 */
-};
-
-const struct iw_handler_def hostap_iw_handler_def =
-{
- .num_standard = ARRAY_SIZE(prism2_handler),
- .num_private = ARRAY_SIZE(prism2_private_handler),
- .num_private_args = ARRAY_SIZE(prism2_priv),
- .standard = prism2_handler,
- .private = prism2_private_handler,
- .private_args = (struct iw_priv_args *) prism2_priv,
- .get_wireless_stats = hostap_get_wireless_stats,
-};
-
-
-/* Private ioctls that are not used with iwpriv;
- * in SIOCDEVPRIVATE range */
-int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd)
-{
- struct iwreq *wrq = (struct iwreq *)ifr;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (in_compat_syscall()) /* not implemented yet */
- return -EOPNOTSUPP;
-
- switch (cmd) {
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- case PRISM2_IOCTL_DOWNLOAD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_download(local, &wrq->u.data);
- break;
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- case PRISM2_IOCTL_HOSTAPD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c
deleted file mode 100644
index bf86ac26c2ac..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_main.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Host AP (software wireless LAN access point) driver for
- * Intersil Prism2/2.5/3 - hostap.o module, common routines
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j@w1.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/workqueue.h>
-#include <linux/kmod.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <net/net_namespace.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
-#include <linux/uaccess.h>
-
-#include "hostap_wlan.h"
-#include "hostap_80211.h"
-#include "hostap_ap.h"
-#include "hostap.h"
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Host AP common routines");
-MODULE_LICENSE("GPL");
-
-#define TX_TIMEOUT (2 * HZ)
-
-#define PRISM2_MAX_FRAME_SIZE 2304
-#define PRISM2_MIN_MTU 256
-/* FIX: */
-#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */))
-
-
-struct net_device * hostap_add_interface(struct local_info *local,
- int type, int rtnl_locked,
- const char *prefix,
- const char *name)
-{
- struct net_device *dev, *mdev;
- struct hostap_interface *iface;
- int ret;
-
- dev = alloc_etherdev(sizeof(struct hostap_interface));
- if (dev == NULL)
- return NULL;
-
- iface = netdev_priv(dev);
- iface->dev = dev;
- iface->local = local;
- iface->type = type;
- list_add(&iface->list, &local->hostap_interfaces);
-
- mdev = local->dev;
- eth_hw_addr_inherit(dev, mdev);
- dev->base_addr = mdev->base_addr;
- dev->irq = mdev->irq;
- dev->mem_start = mdev->mem_start;
- dev->mem_end = mdev->mem_end;
-
- hostap_setup_dev(dev, local, type);
- dev->needs_free_netdev = true;
-
- sprintf(dev->name, "%s%s", prefix, name);
- if (!rtnl_locked)
- rtnl_lock();
-
- SET_NETDEV_DEV(dev, mdev->dev.parent);
- ret = register_netdevice(dev);
-
- if (!rtnl_locked)
- rtnl_unlock();
-
- if (ret < 0) {
- printk(KERN_WARNING "%s: failed to add new netdevice!\n",
- dev->name);
- free_netdev(dev);
- return NULL;
- }
-
- printk(KERN_DEBUG "%s: registered netdevice %s\n",
- mdev->name, dev->name);
-
- return dev;
-}
-
-
-void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
- int remove_from_list)
-{
- struct hostap_interface *iface;
-
- if (!dev)
- return;
-
- iface = netdev_priv(dev);
-
- if (remove_from_list) {
- list_del(&iface->list);
- }
-
- if (dev == iface->local->ddev)
- iface->local->ddev = NULL;
- else if (dev == iface->local->apdev)
- iface->local->apdev = NULL;
- else if (dev == iface->local->stadev)
- iface->local->stadev = NULL;
-
- if (rtnl_locked)
- unregister_netdevice(dev);
- else
- unregister_netdev(dev);
-
- /* 'dev->needs_free_netdev = true' implies device data, including
- * private data, will be freed when the device is removed */
-}
-
-
-static inline int prism2_wds_special_addr(u8 *addr)
-{
- if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5])
- return 0;
-
- return 1;
-}
-
-
-int prism2_wds_add(local_info_t *local, u8 *remote_addr,
- int rtnl_locked)
-{
- struct net_device *dev;
- struct list_head *ptr;
- struct hostap_interface *iface, *empty, *match;
-
- empty = match = NULL;
- read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type != HOSTAP_INTERFACE_WDS)
- continue;
-
- if (prism2_wds_special_addr(iface->u.wds.remote_addr))
- empty = iface;
- else if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) {
- match = iface;
- break;
- }
- }
- if (!match && empty && !prism2_wds_special_addr(remote_addr)) {
- /* take pre-allocated entry into use */
- memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN);
- read_unlock_bh(&local->iface_lock);
- printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n",
- local->dev->name, empty->dev->name);
- return 0;
- }
- read_unlock_bh(&local->iface_lock);
-
- if (!prism2_wds_special_addr(remote_addr)) {
- if (match)
- return -EEXIST;
- hostap_add_sta(local->ap, remote_addr);
- }
-
- if (local->wds_connections >= local->wds_max_connections)
- return -ENOBUFS;
-
- /* verify that there is room for wds# postfix in the interface name */
- if (strlen(local->dev->name) >= IFNAMSIZ - 5) {
- printk(KERN_DEBUG "'%s' too long base device name\n",
- local->dev->name);
- return -EINVAL;
- }
-
- dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked,
- local->ddev->name, "wds%d");
- if (dev == NULL)
- return -ENOMEM;
-
- iface = netdev_priv(dev);
- memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN);
-
- local->wds_connections++;
-
- return 0;
-}
-
-
-int prism2_wds_del(local_info_t *local, u8 *remote_addr,
- int rtnl_locked, int do_not_remove)
-{
- unsigned long flags;
- struct list_head *ptr;
- struct hostap_interface *iface, *selected = NULL;
-
- write_lock_irqsave(&local->iface_lock, flags);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type != HOSTAP_INTERFACE_WDS)
- continue;
-
- if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) {
- selected = iface;
- break;
- }
- }
- if (selected && !do_not_remove)
- list_del(&selected->list);
- write_unlock_irqrestore(&local->iface_lock, flags);
-
- if (selected) {
- if (do_not_remove)
- eth_zero_addr(selected->u.wds.remote_addr);
- else {
- hostap_remove_interface(selected->dev, rtnl_locked, 0);
- local->wds_connections--;
- }
- }
-
- return selected ? 0 : -ENODEV;
-}
-
-
-u16 hostap_tx_callback_register(local_info_t *local,
- void (*func)(struct sk_buff *, int ok, void *),
- void *data)
-{
- unsigned long flags;
- struct hostap_tx_callback_info *entry;
-
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
- if (entry == NULL)
- return 0;
-
- entry->func = func;
- entry->data = data;
-
- spin_lock_irqsave(&local->lock, flags);
- entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1;
- entry->next = local->tx_callback;
- local->tx_callback = entry;
- spin_unlock_irqrestore(&local->lock, flags);
-
- return entry->idx;
-}
-
-
-int hostap_tx_callback_unregister(local_info_t *local, u16 idx)
-{
- unsigned long flags;
- struct hostap_tx_callback_info *cb, *prev = NULL;
-
- spin_lock_irqsave(&local->lock, flags);
- cb = local->tx_callback;
- while (cb != NULL && cb->idx != idx) {
- prev = cb;
- cb = cb->next;
- }
- if (cb) {
- if (prev == NULL)
- local->tx_callback = cb->next;
- else
- prev->next = cb->next;
- kfree(cb);
- }
- spin_unlock_irqrestore(&local->lock, flags);
-
- return cb ? 0 : -1;
-}
-
-
-/* val is in host byte order */
-int hostap_set_word(struct net_device *dev, int rid, u16 val)
-{
- struct hostap_interface *iface;
- __le16 tmp = cpu_to_le16(val);
- iface = netdev_priv(dev);
- return iface->local->func->set_rid(dev, rid, &tmp, 2);
-}
-
-
-int hostap_set_string(struct net_device *dev, int rid, const char *val)
-{
- struct hostap_interface *iface;
- char buf[MAX_SSID_LEN + 2];
- int len;
-
- iface = netdev_priv(dev);
- len = strlen(val);
- if (len > MAX_SSID_LEN)
- return -1;
- memset(buf, 0, sizeof(buf));
- buf[0] = len; /* little endian 16 bit word */
- memcpy(buf + 2, val, len);
-
- return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2);
-}
-
-
-u16 hostap_get_porttype(local_info_t *local)
-{
- if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc)
- return HFA384X_PORTTYPE_PSEUDO_IBSS;
- if (local->iw_mode == IW_MODE_ADHOC)
- return HFA384X_PORTTYPE_IBSS;
- if (local->iw_mode == IW_MODE_INFRA)
- return HFA384X_PORTTYPE_BSS;
- if (local->iw_mode == IW_MODE_REPEAT)
- return HFA384X_PORTTYPE_WDS;
- if (local->iw_mode == IW_MODE_MONITOR)
- return HFA384X_PORTTYPE_PSEUDO_IBSS;
- return HFA384X_PORTTYPE_HOSTAP;
-}
-
-
-int hostap_set_encryption(local_info_t *local)
-{
- u16 val, old_val;
- int i, keylen, len, idx;
- char keybuf[WEP_KEY_LEN + 1];
- enum { NONE, WEP, OTHER } encrypt_type;
-
- idx = local->crypt_info.tx_keyidx;
- if (local->crypt_info.crypt[idx] == NULL ||
- local->crypt_info.crypt[idx]->ops == NULL)
- encrypt_type = NONE;
- else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0)
- encrypt_type = WEP;
- else
- encrypt_type = OTHER;
-
- if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2,
- 1) < 0) {
- printk(KERN_DEBUG "Could not read current WEP flags.\n");
- goto fail;
- }
- le16_to_cpus(&val);
- old_val = val;
-
- if (encrypt_type != NONE || local->privacy_invoked)
- val |= HFA384X_WEPFLAGS_PRIVACYINVOKED;
- else
- val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED;
-
- if (local->open_wep || encrypt_type == NONE ||
- ((local->ieee_802_1x || local->wpa) && local->host_decrypt))
- val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
- else
- val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
-
- if ((encrypt_type != NONE || local->privacy_invoked) &&
- (encrypt_type == OTHER || local->host_encrypt))
- val |= HFA384X_WEPFLAGS_HOSTENCRYPT;
- else
- val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT;
- if ((encrypt_type != NONE || local->privacy_invoked) &&
- (encrypt_type == OTHER || local->host_decrypt))
- val |= HFA384X_WEPFLAGS_HOSTDECRYPT;
- else
- val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT;
-
- if (val != old_val &&
- hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) {
- printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n",
- val);
- goto fail;
- }
-
- if (encrypt_type != WEP)
- return 0;
-
- /* 104-bit support seems to require that all the keys are set to the
- * same keylen */
- keylen = 6; /* first 5 octets */
- len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL,
- local->crypt_info.crypt[idx]->priv);
- if (idx >= 0 && idx < WEP_KEYS && len > 5)
- keylen = WEP_KEY_LEN + 1; /* first 13 octets */
-
- for (i = 0; i < WEP_KEYS; i++) {
- memset(keybuf, 0, sizeof(keybuf));
- if (local->crypt_info.crypt[i]) {
- (void) local->crypt_info.crypt[i]->ops->get_key(
- keybuf, sizeof(keybuf),
- NULL, local->crypt_info.crypt[i]->priv);
- }
- if (local->func->set_rid(local->dev,
- HFA384X_RID_CNFDEFAULTKEY0 + i,
- keybuf, keylen)) {
- printk(KERN_DEBUG "Could not set key %d (len=%d)\n",
- i, keylen);
- goto fail;
- }
- }
- if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) {
- printk(KERN_DEBUG "Could not set default keyid %d\n", idx);
- goto fail;
- }
-
- return 0;
-
- fail:
- printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name);
- return -1;
-}
-
-
-int hostap_set_antsel(local_info_t *local)
-{
- u16 val;
- int ret = 0;
-
- if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
- local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
- HFA386X_CR_TX_CONFIGURE,
- NULL, &val) == 0) {
- val &= ~(BIT(2) | BIT(1));
- switch (local->antsel_tx) {
- case HOSTAP_ANTSEL_DIVERSITY:
- val |= BIT(1);
- break;
- case HOSTAP_ANTSEL_LOW:
- break;
- case HOSTAP_ANTSEL_HIGH:
- val |= BIT(2);
- break;
- }
-
- if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_TX_CONFIGURE, &val, NULL)) {
- printk(KERN_INFO "%s: setting TX AntSel failed\n",
- local->dev->name);
- ret = -1;
- }
- }
-
- if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
- local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
- HFA386X_CR_RX_CONFIGURE,
- NULL, &val) == 0) {
- val &= ~(BIT(1) | BIT(0));
- switch (local->antsel_rx) {
- case HOSTAP_ANTSEL_DIVERSITY:
- break;
- case HOSTAP_ANTSEL_LOW:
- val |= BIT(0);
- break;
- case HOSTAP_ANTSEL_HIGH:
- val |= BIT(0) | BIT(1);
- break;
- }
-
- if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_RX_CONFIGURE, &val, NULL)) {
- printk(KERN_INFO "%s: setting RX AntSel failed\n",
- local->dev->name);
- ret = -1;
- }
- }
-
- return ret;
-}
-
-
-int hostap_set_roaming(local_info_t *local)
-{
- u16 val;
-
- switch (local->host_roaming) {
- case 1:
- val = HFA384X_ROAMING_HOST;
- break;
- case 2:
- val = HFA384X_ROAMING_DISABLED;
- break;
- case 0:
- default:
- val = HFA384X_ROAMING_FIRMWARE;
- break;
- }
-
- return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val);
-}
-
-
-int hostap_set_auth_algs(local_info_t *local)
-{
- int val = local->auth_algs;
- /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication
- * set to include both Open and Shared Key flags. It tries to use
- * Shared Key authentication in that case even if WEP keys are not
- * configured.. STA f/w v0.7.6 is able to handle such configuration,
- * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */
- if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) &&
- val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY)
- val = PRISM2_AUTH_OPEN;
-
- if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) {
- printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x "
- "failed\n", local->dev->name, local->auth_algs);
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
-{
- u16 status, fc;
-
- status = __le16_to_cpu(rx->status);
-
- printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, "
- "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; "
- "jiffies=%ld\n",
- name, status, (status >> 8) & 0x07, status >> 13, status & 1,
- rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies);
-
- fc = __le16_to_cpu(rx->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
- "data_len=%d%s%s\n",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl),
- __le16_to_cpu(rx->data_len),
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n",
- rx->addr1, rx->addr2, rx->addr3, rx->addr4);
-
- printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n",
- rx->dst_addr, rx->src_addr,
- __be16_to_cpu(rx->len));
-}
-
-
-void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
-{
- u16 fc;
-
- printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
- "tx_control=0x%04x; jiffies=%ld\n",
- name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate,
- __le16_to_cpu(tx->tx_control), jiffies);
-
- fc = __le16_to_cpu(tx->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
- "data_len=%d%s%s\n",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl),
- __le16_to_cpu(tx->data_len),
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n",
- tx->addr1, tx->addr2, tx->addr3, tx->addr4);
-
- printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n",
- tx->dst_addr, tx->src_addr,
- __be16_to_cpu(tx->len));
-}
-
-
-static int hostap_80211_header_parse(const struct sk_buff *skb,
- unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
-
-
-int hostap_80211_get_hdrlen(__le16 fc)
-{
- if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc))
- return 30; /* Addr4 */
- else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc))
- return 10;
- else if (ieee80211_is_ctl(fc))
- return 16;
-
- return 24;
-}
-
-
-static int prism2_close(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name);
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (dev == local->ddev) {
- prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
- }
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (!local->hostapd && dev == local->dev &&
- (!local->func->card_present || local->func->card_present(local)) &&
- local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER)
- hostap_deauth_all_stas(dev, local->ap, 1);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- if (dev == local->dev) {
- local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL);
- }
-
- if (netif_running(dev)) {
- netif_stop_queue(dev);
- netif_device_detach(dev);
- }
-
- cancel_work_sync(&local->reset_queue);
- cancel_work_sync(&local->set_multicast_list_queue);
- cancel_work_sync(&local->set_tim_queue);
-#ifndef PRISM2_NO_STATION_MODES
- cancel_work_sync(&local->info_queue);
-#endif
- cancel_work_sync(&local->comms_qual_update);
-
- module_put(local->hw_module);
-
- local->num_dev_open--;
-
- if (dev != local->dev && local->dev->flags & IFF_UP &&
- local->master_dev_auto_open && local->num_dev_open == 1) {
- /* Close master radio interface automatically if it was also
- * opened automatically and we are now closing the last
- * remaining non-master device. */
- dev_close(local->dev);
- }
-
- return 0;
-}
-
-
-static int prism2_open(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name);
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: could not set interface UP - no PRI "
- "f/w\n", dev->name);
- return -ENODEV;
- }
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
-
- if (!try_module_get(local->hw_module))
- return -ENODEV;
- local->num_dev_open++;
-
- if (!local->dev_enabled && local->func->hw_enable(dev, 1)) {
- printk(KERN_WARNING "%s: could not enable MAC port\n",
- dev->name);
- prism2_close(dev);
- return -ENODEV;
- }
- if (!local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_ENABLE);
- local->dev_enabled = 1;
-
- if (dev != local->dev && !(local->dev->flags & IFF_UP)) {
- /* Master radio interface is needed for all operation, so open
- * it automatically when any virtual net_device is opened. */
- local->master_dev_auto_open = 1;
- dev_open(local->dev, NULL);
- }
-
- netif_device_attach(dev);
- netif_start_queue(dev);
-
- return 0;
-}
-
-
-static int prism2_set_mac_address(struct net_device *dev, void *p)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct list_head *ptr;
- struct sockaddr *addr = p;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data,
- ETH_ALEN) < 0 || local->func->reset_port(dev))
- return -EINVAL;
-
- read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- eth_hw_addr_set(iface->dev, addr->sa_data);
- }
- eth_hw_addr_set(local->dev, addr->sa_data);
- read_unlock_bh(&local->iface_lock);
-
- return 0;
-}
-
-
-/* TODO: to be further implemented as soon as Prism2 fully supports
- * GroupAddresses and correct documentation is available */
-void hostap_set_multicast_list_queue(struct work_struct *work)
-{
- local_info_t *local =
- container_of(work, local_info_t, set_multicast_list_queue);
- struct net_device *dev = local->dev;
-
- if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
- local->is_promisc)) {
- printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
- dev->name, local->is_promisc ? "en" : "dis");
- }
-}
-
-
-static void hostap_set_multicast_list(struct net_device *dev)
-{
-#if 0
- /* FIX: promiscuous mode seems to be causing a lot of problems with
- * some station firmware versions (FCSErr frames, invalid MACPort, etc.
- * corrupted incoming frames). This code is now commented out while the
- * problems are investigated. */
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
- if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) {
- local->is_promisc = 1;
- } else {
- local->is_promisc = 0;
- }
-
- schedule_work(&local->set_multicast_list_queue);
-#endif
-}
-
-
-static void prism2_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_regs regs;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name);
- netif_stop_queue(local->dev);
-
- local->func->read_regs(dev, &regs);
- printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x "
- "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n",
- dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1,
- regs.swsupport0);
-
- local->func->schedule_reset(local);
-}
-
-const struct header_ops hostap_80211_ops = {
- .create = eth_header,
- .cache = eth_header_cache,
- .cache_update = eth_header_cache_update,
- .parse = hostap_80211_header_parse,
-};
-EXPORT_SYMBOL(hostap_80211_ops);
-
-
-static const struct net_device_ops hostap_netdev_ops = {
- .ndo_start_xmit = hostap_data_start_xmit,
-
- .ndo_open = prism2_open,
- .ndo_stop = prism2_close,
- .ndo_siocdevprivate = hostap_siocdevprivate,
- .ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_rx_mode = hostap_set_multicast_list,
- .ndo_tx_timeout = prism2_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static const struct net_device_ops hostap_mgmt_netdev_ops = {
- .ndo_start_xmit = hostap_mgmt_start_xmit,
-
- .ndo_open = prism2_open,
- .ndo_stop = prism2_close,
- .ndo_siocdevprivate = hostap_siocdevprivate,
- .ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_rx_mode = hostap_set_multicast_list,
- .ndo_tx_timeout = prism2_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static const struct net_device_ops hostap_master_ops = {
- .ndo_start_xmit = hostap_master_start_xmit,
-
- .ndo_open = prism2_open,
- .ndo_stop = prism2_close,
- .ndo_siocdevprivate = hostap_siocdevprivate,
- .ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_rx_mode = hostap_set_multicast_list,
- .ndo_tx_timeout = prism2_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int type)
-{
- struct hostap_interface *iface;
-
- iface = netdev_priv(dev);
- ether_setup(dev);
- dev->min_mtu = PRISM2_MIN_MTU;
- dev->max_mtu = PRISM2_MAX_MTU;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
-
- /* kernel callbacks */
- if (iface) {
- /* Currently, we point to the proper spy_data only on
- * the main_dev. This could be fixed. Jean II */
- iface->wireless_data.spy_data = &iface->spy_data;
- dev->wireless_data = &iface->wireless_data;
- }
- dev->wireless_handlers = &hostap_iw_handler_def;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- switch(type) {
- case HOSTAP_INTERFACE_AP:
- dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */
- dev->netdev_ops = &hostap_mgmt_netdev_ops;
- dev->type = ARPHRD_IEEE80211;
- dev->header_ops = &hostap_80211_ops;
- break;
- case HOSTAP_INTERFACE_MASTER:
- dev->netdev_ops = &hostap_master_ops;
- break;
- default:
- dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */
- dev->netdev_ops = &hostap_netdev_ops;
- }
-
- dev->mtu = local->mtu;
-
-
- dev->ethtool_ops = &prism2_ethtool_ops;
-
-}
-
-static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- if (local->apdev)
- return -EEXIST;
-
- printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name);
-
- local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP,
- rtnl_locked, local->ddev->name,
- "ap");
- if (local->apdev == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-
-static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
-
- hostap_remove_interface(local->apdev, rtnl_locked, 1);
- local->apdev = NULL;
-
- return 0;
-}
-
-
-static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- if (local->stadev)
- return -EEXIST;
-
- printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name);
-
- local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA,
- rtnl_locked, local->ddev->name,
- "sta");
- if (local->stadev == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-
-static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
-
- hostap_remove_interface(local->stadev, rtnl_locked, 1);
- local->stadev = NULL;
-
- return 0;
-}
-
-
-int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked)
-{
- int ret;
-
- if (val < 0 || val > 1)
- return -EINVAL;
-
- if (local->hostapd == val)
- return 0;
-
- if (val) {
- ret = hostap_enable_hostapd(local, rtnl_locked);
- if (ret == 0)
- local->hostapd = 1;
- } else {
- local->hostapd = 0;
- ret = hostap_disable_hostapd(local, rtnl_locked);
- if (ret != 0)
- local->hostapd = 1;
- }
-
- return ret;
-}
-
-
-int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked)
-{
- int ret;
-
- if (val < 0 || val > 1)
- return -EINVAL;
-
- if (local->hostapd_sta == val)
- return 0;
-
- if (val) {
- ret = hostap_enable_hostapd_sta(local, rtnl_locked);
- if (ret == 0)
- local->hostapd_sta = 1;
- } else {
- local->hostapd_sta = 0;
- ret = hostap_disable_hostapd_sta(local, rtnl_locked);
- if (ret != 0)
- local->hostapd_sta = 1;
- }
-
-
- return ret;
-}
-
-
-int prism2_update_comms_qual(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
- struct hfa384x_comms_quality sq;
-
- iface = netdev_priv(dev);
- local = iface->local;
- if (!local->sta_fw_ver)
- ret = -1;
- else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
- if (local->func->get_rid(local->dev,
- HFA384X_RID_DBMCOMMSQUALITY,
- &sq, sizeof(sq), 1) >= 0) {
- local->comms_qual = (s16) le16_to_cpu(sq.comm_qual);
- local->avg_signal = (s16) le16_to_cpu(sq.signal_level);
- local->avg_noise = (s16) le16_to_cpu(sq.noise_level);
- local->last_comms_qual_update = jiffies;
- } else
- ret = -1;
- } else {
- if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY,
- &sq, sizeof(sq), 1) >= 0) {
- local->comms_qual = le16_to_cpu(sq.comm_qual);
- local->avg_signal = HFA384X_LEVEL_TO_dBm(
- le16_to_cpu(sq.signal_level));
- local->avg_noise = HFA384X_LEVEL_TO_dBm(
- le16_to_cpu(sq.noise_level));
- local->last_comms_qual_update = jiffies;
- } else
- ret = -1;
- }
-
- return ret;
-}
-
-
-int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
- u8 *body, size_t bodylen)
-{
- struct sk_buff *skb;
- struct hostap_ieee80211_mgmt *mgmt;
- struct hostap_skb_tx_data *meta;
- struct net_device *dev = local->dev;
-
- skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen);
- if (skb == NULL)
- return -ENOMEM;
-
- mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
- memcpy(mgmt->da, dst, ETH_ALEN);
- memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, dst, ETH_ALEN);
- if (body)
- skb_put_data(skb, body, bodylen);
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- meta->iface = netdev_priv(dev);
-
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb_reset_network_header(skb);
- dev_queue_xmit(skb);
-
- return 0;
-}
-
-
-int prism2_sta_deauth(local_info_t *local, u16 reason)
-{
- union iwreq_data wrqu;
- int ret;
- __le16 val = cpu_to_le16(reason);
-
- if (local->iw_mode != IW_MODE_INFRA ||
- is_zero_ether_addr(local->bssid) ||
- ether_addr_equal(local->bssid, "\x44\x44\x44\x44\x44\x44"))
- return 0;
-
- ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH,
- (u8 *) &val, 2);
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
- return ret;
-}
-
-
-struct proc_dir_entry *hostap_proc;
-
-static int __init hostap_init(void)
-{
- if (init_net.proc_net != NULL) {
- hostap_proc = proc_mkdir("hostap", init_net.proc_net);
- if (!hostap_proc)
- printk(KERN_WARNING "Failed to mkdir "
- "/proc/net/hostap\n");
- } else
- hostap_proc = NULL;
-
- return 0;
-}
-
-
-static void __exit hostap_exit(void)
-{
- if (hostap_proc != NULL) {
- hostap_proc = NULL;
- remove_proc_entry("hostap", init_net.proc_net);
- }
-}
-
-
-EXPORT_SYMBOL(hostap_set_word);
-EXPORT_SYMBOL(hostap_set_string);
-EXPORT_SYMBOL(hostap_get_porttype);
-EXPORT_SYMBOL(hostap_set_encryption);
-EXPORT_SYMBOL(hostap_set_antsel);
-EXPORT_SYMBOL(hostap_set_roaming);
-EXPORT_SYMBOL(hostap_set_auth_algs);
-EXPORT_SYMBOL(hostap_dump_rx_header);
-EXPORT_SYMBOL(hostap_dump_tx_header);
-EXPORT_SYMBOL(hostap_80211_get_hdrlen);
-EXPORT_SYMBOL(hostap_setup_dev);
-EXPORT_SYMBOL(hostap_set_multicast_list_queue);
-EXPORT_SYMBOL(hostap_set_hostapd);
-EXPORT_SYMBOL(hostap_set_hostapd_sta);
-EXPORT_SYMBOL(hostap_add_interface);
-EXPORT_SYMBOL(hostap_remove_interface);
-EXPORT_SYMBOL(prism2_update_comms_qual);
-
-module_init(hostap_init);
-module_exit(hostap_exit);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c
deleted file mode 100644
index 52d77506effd..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_pci.c
+++ /dev/null
@@ -1,445 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define PRISM2_PCI
-
-/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
- * driver patches from Reyk Floeter <reyk@vantronix.net> and
- * Andy Warner <andyw@pobox.com> */
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "hostap_wlan.h"
-
-
-static char *dev_info = "hostap_pci";
-
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
- "PCI cards.");
-MODULE_LICENSE("GPL");
-
-
-/* struct local_info::hw_priv */
-struct hostap_pci_priv {
- void __iomem *mem_start;
-};
-
-
-/* FIX: do we need mb/wmb/rmb with memory operations? */
-
-
-static const struct pci_device_id prism2_pci_id_table[] = {
- /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
- { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
- /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
- { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
- /* Samsung MagicLAN SWL-2210P */
- { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
- { 0 }
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-
-static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
- writeb(v, hw_priv->mem_start + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
- u8 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- v = readb(hw_priv->mem_start + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
- writew(v, hw_priv->mem_start + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
- u16 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- v = readw(hw_priv->mem_start + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v)))
-#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a)))
-
-#else /* PRISM2_IO_DEBUG */
-
-static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- writeb(v, hw_priv->mem_start + a);
-}
-
-static inline u8 hfa384x_inb(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- return readb(hw_priv->mem_start + a);
-}
-
-static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- writew(v, hw_priv->mem_start + a);
-}
-
-static inline u16 hfa384x_inw(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- return readw(hw_priv->mem_start + a);
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw(dev, (a))
-#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v)))
-#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a)))
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
- int len)
-{
- u16 d_off;
- __le16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (__le16 *) buf;
-
- for ( ; len > 1; len -= 2)
- *pos++ = HFA384X_INW_DATA(d_off);
-
- if (len & 1)
- *((char *) pos) = HFA384X_INB(d_off);
-
- return 0;
-}
-
-
-static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
-{
- u16 d_off;
- __le16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (__le16 *) buf;
-
- for ( ; len > 1; len -= 2)
- HFA384X_OUTW_DATA(*pos++, d_off);
-
- if (len & 1)
- HFA384X_OUTB(*((char *) pos), d_off);
-
- return 0;
-}
-
-
-/* FIX: This might change at some point.. */
-#include "hostap_hw.c"
-
-static void prism2_pci_cor_sreset(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- u16 reg;
-
- reg = HFA384X_INB(HFA384X_PCICOR_OFF);
- printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
-
- /* linux-wlan-ng uses extremely long hold and settle times for
- * COR sreset. A comment in the driver code mentions that the long
- * delays appear to be necessary. However, at least IBM 22P6901 seems
- * to work fine with shorter delays.
- *
- * Longer delays can be configured by uncommenting following line: */
-/* #define PRISM2_PCI_USE_LONG_DELAYS */
-
-#ifdef PRISM2_PCI_USE_LONG_DELAYS
- int i;
-
- HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
- mdelay(250);
-
- HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
- mdelay(500);
-
- /* Wait for f/w to complete initialization (CMD:BUSY == 0) */
- i = 2000000 / 10;
- while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
- udelay(10);
-
-#else /* PRISM2_PCI_USE_LONG_DELAYS */
-
- HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
- mdelay(2);
- HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
- mdelay(2);
-
-#endif /* PRISM2_PCI_USE_LONG_DELAYS */
-
- if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
- printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
- }
-}
-
-
-static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
-{
- struct net_device *dev = local->dev;
-
- HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
- mdelay(10);
- HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
- mdelay(10);
- HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
- mdelay(10);
-}
-
-
-static struct prism2_helper_functions prism2_pci_funcs =
-{
- .card_present = NULL,
- .cor_sreset = prism2_pci_cor_sreset,
- .genesis_reset = prism2_pci_genesis_reset,
- .hw_type = HOSTAP_HW_PCI,
-};
-
-
-static int prism2_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- unsigned long phymem;
- void __iomem *mem = NULL;
- local_info_t *local = NULL;
- struct net_device *dev = NULL;
- static int cards_found /* = 0 */;
- int irq_registered = 0;
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
-
- hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
- if (hw_priv == NULL)
- return -ENOMEM;
-
- if (pci_enable_device(pdev))
- goto err_out_free;
-
- phymem = pci_resource_start(pdev, 0);
-
- if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
- printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
- goto err_out_disable;
- }
-
- mem = pci_ioremap_bar(pdev, 0);
- if (mem == NULL) {
- printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
- goto fail;
- }
-
- dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
- &pdev->dev);
- if (dev == NULL)
- goto fail;
- iface = netdev_priv(dev);
- local = iface->local;
- local->hw_priv = hw_priv;
- cards_found++;
-
- dev->irq = pdev->irq;
- hw_priv->mem_start = mem;
- dev->base_addr = (unsigned long) mem;
-
- prism2_pci_cor_sreset(local);
-
- pci_set_drvdata(pdev, dev);
-
- if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
- dev)) {
- printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
- goto fail;
- } else
- irq_registered = 1;
-
- if (!local->pri_only && prism2_hw_config(dev, 1)) {
- printk(KERN_DEBUG "%s: hardware initialization failed\n",
- dev_info);
- goto fail;
- }
-
- printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
- "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
-
- return hostap_hw_ready(dev);
-
- fail:
- if (irq_registered && dev)
- free_irq(dev->irq, dev);
-
- if (mem)
- iounmap(mem);
-
- release_mem_region(phymem, pci_resource_len(pdev, 0));
-
- err_out_disable:
- pci_disable_device(pdev);
- prism2_free_local_data(dev);
-
- err_out_free:
- kfree(hw_priv);
-
- return -ENODEV;
-}
-
-
-static void prism2_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- void __iomem *mem_start;
- struct hostap_pci_priv *hw_priv;
-
- dev = pci_get_drvdata(pdev);
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
-
- /* Reset the hardware, and ensure interrupts are disabled. */
- prism2_pci_cor_sreset(iface->local);
- hfa384x_disable_interrupts(dev);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- mem_start = hw_priv->mem_start;
- prism2_free_local_data(dev);
- kfree(hw_priv);
-
- iounmap(mem_start);
-
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- pci_disable_device(pdev);
-}
-
-static int __maybe_unused prism2_pci_suspend(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
-
- if (netif_running(dev)) {
- netif_stop_queue(dev);
- netif_device_detach(dev);
- }
- prism2_suspend(dev);
-
- return 0;
-}
-
-static int __maybe_unused prism2_pci_resume(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
-
- prism2_hw_config(dev, 0);
- if (netif_running(dev)) {
- netif_device_attach(dev);
- netif_start_queue(dev);
- }
-
- return 0;
-}
-
-MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
-
-static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops,
- prism2_pci_suspend,
- prism2_pci_resume);
-
-static struct pci_driver prism2_pci_driver = {
- .name = "hostap_pci",
- .id_table = prism2_pci_id_table,
- .probe = prism2_pci_probe,
- .remove = prism2_pci_remove,
- .driver.pm = &prism2_pci_pm_ops,
-};
-
-module_pci_driver(prism2_pci_driver);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_plx.c b/drivers/net/wireless/intersil/hostap/hostap_plx.c
deleted file mode 100644
index 58247290fcbc..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_plx.c
+++ /dev/null
@@ -1,617 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define PRISM2_PLX
-
-/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
- * based on:
- * - Host AP driver patch from james@madingley.org
- * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
- */
-
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "hostap_wlan.h"
-
-
-static char *dev_info = "hostap_plx";
-
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
- "cards (PLX).");
-MODULE_LICENSE("GPL");
-
-
-static int ignore_cis;
-module_param(ignore_cis, int, 0444);
-MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
-
-
-/* struct local_info::hw_priv */
-struct hostap_plx_priv {
- void __iomem *attr_mem;
- unsigned int cor_offset;
-};
-
-
-#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
-#define COR_SRESET 0x80
-#define COR_LEVLREQ 0x40
-#define COR_ENABLE_FUNC 0x01
-/* PCI Configuration Registers */
-#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
-/* Local Configuration Registers */
-#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
-#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
-#define PLX_CNTRL 0x50
-#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
-
-
-#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
-
-static const struct pci_device_id prism2_plx_id_table[] = {
- PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
- PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
- PLXDEV(0x126c, 0x8030, "Nortel emobility"),
- PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
- PLXDEV(0x1385, 0x4100, "Netgear MA301"),
- PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
- PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
- PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
- PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
- PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
- PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
- PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
- PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
- PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
- { 0 }
-};
-
-
-/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
- * is not listed here, you will need to add it here to get the driver
- * initialized. */
-static struct prism2_plx_manfid {
- u16 manfid1, manfid2;
-} prism2_plx_known_manfids[] = {
- { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
- { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
- { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
- { 0x0126, 0x8000 } /* Proxim RangeLAN */,
- { 0x0138, 0x0002 } /* Compaq WL100 */,
- { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
- { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
- { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
- { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
- { 0x028a, 0x0002 } /* D-Link DRC-650 */,
- { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
- { 0xc250, 0x0002 } /* EMTAC A2424i */,
- { 0xd601, 0x0002 } /* Z-Com XI300 */,
- { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
- { 0, 0}
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-
-static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
- outb(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u8 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- v = inb(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
- outw(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u16 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- v = inw(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
- outsw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline void hfa384x_insw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
- insw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
-#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
-
-#else /* PRISM2_IO_DEBUG */
-
-#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
-#define HFA384X_INB(a) inb(dev->base_addr + (a))
-#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
-#define HFA384X_INW(a) inw(dev->base_addr + (a))
-#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
-#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
- int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_INSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- *((char *) pos) = HFA384X_INB(d_off);
-
- return 0;
-}
-
-
-static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_OUTSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- HFA384X_OUTB(*((char *) pos), d_off);
-
- return 0;
-}
-
-
-/* FIX: This might change at some point.. */
-#include "hostap_hw.c"
-
-
-static void prism2_plx_cor_sreset(local_info_t *local)
-{
- unsigned char corsave;
- struct hostap_plx_priv *hw_priv = local->hw_priv;
-
- printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
- dev_info);
-
- /* Set sreset bit of COR and clear it after hold time */
-
- if (hw_priv->attr_mem == NULL) {
- /* TMD7160 - COR at card's first I/O addr */
- corsave = inb(hw_priv->cor_offset);
- outb(corsave | COR_SRESET, hw_priv->cor_offset);
- mdelay(2);
- outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
- mdelay(2);
- } else {
- /* PLX9052 */
- corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
- writeb(corsave | COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(2);
- writeb(corsave & ~COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(2);
- }
-}
-
-
-static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
-{
- unsigned char corsave;
- struct hostap_plx_priv *hw_priv = local->hw_priv;
-
- if (hw_priv->attr_mem == NULL) {
- /* TMD7160 - COR at card's first I/O addr */
- corsave = inb(hw_priv->cor_offset);
- outb(corsave | COR_SRESET, hw_priv->cor_offset);
- mdelay(10);
- outb(hcr, hw_priv->cor_offset + 2);
- mdelay(10);
- outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
- mdelay(10);
- } else {
- /* PLX9052 */
- corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
- writeb(corsave | COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(10);
- writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
- mdelay(10);
- writeb(corsave & ~COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(10);
- }
-}
-
-
-static struct prism2_helper_functions prism2_plx_funcs =
-{
- .card_present = NULL,
- .cor_sreset = prism2_plx_cor_sreset,
- .genesis_reset = prism2_plx_genesis_reset,
- .hw_type = HOSTAP_HW_PLX,
-};
-
-
-static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
- unsigned int *cor_offset,
- unsigned int *cor_index)
-{
-#define CISTPL_CONFIG 0x1A
-#define CISTPL_MANFID 0x20
-#define CISTPL_END 0xFF
-#define CIS_MAX_LEN 256
- u8 *cis;
- int i, pos;
- unsigned int rmsz, rasz, manfid1, manfid2;
- struct prism2_plx_manfid *manfid;
-
- cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
- if (cis == NULL)
- return -ENOMEM;
-
- /* read CIS; it is in even offsets in the beginning of attr_mem */
- for (i = 0; i < CIS_MAX_LEN; i++)
- cis[i] = readb(attr_mem + 2 * i);
- printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis);
-
- /* set reasonable defaults for Prism2 cards just in case CIS parsing
- * fails */
- *cor_offset = 0x3e0;
- *cor_index = 0x01;
- manfid1 = manfid2 = 0;
-
- pos = 0;
- while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
- if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
- goto cis_error;
-
- switch (cis[pos]) {
- case CISTPL_CONFIG:
- if (cis[pos + 1] < 2)
- goto cis_error;
- rmsz = (cis[pos + 2] & 0x3c) >> 2;
- rasz = cis[pos + 2] & 0x03;
- if (4 + rasz + rmsz > cis[pos + 1])
- goto cis_error;
- *cor_index = cis[pos + 3] & 0x3F;
- *cor_offset = 0;
- for (i = 0; i <= rasz; i++)
- *cor_offset += cis[pos + 4 + i] << (8 * i);
- printk(KERN_DEBUG "%s: cor_index=0x%x "
- "cor_offset=0x%x\n", dev_info,
- *cor_index, *cor_offset);
- if (*cor_offset > attr_len) {
- printk(KERN_ERR "%s: COR offset not within "
- "attr_mem\n", dev_info);
- kfree(cis);
- return -1;
- }
- break;
-
- case CISTPL_MANFID:
- if (cis[pos + 1] < 4)
- goto cis_error;
- manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
- manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
- printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
- dev_info, manfid1, manfid2);
- break;
- }
-
- pos += cis[pos + 1] + 2;
- }
-
- if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
- goto cis_error;
-
- for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
- if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
- kfree(cis);
- return 0;
- }
-
- printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
- " not supported card\n", dev_info, manfid1, manfid2);
- goto fail;
-
- cis_error:
- printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
-
- fail:
- kfree(cis);
- if (ignore_cis) {
- printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
- "errors during CIS verification\n", dev_info);
- return 0;
- }
- return -1;
-}
-
-
-static int prism2_plx_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- unsigned int pccard_ioaddr, plx_ioaddr;
- unsigned long pccard_attr_mem;
- unsigned int pccard_attr_len;
- void __iomem *attr_mem = NULL;
- unsigned int cor_offset = 0, cor_index = 0;
- u32 reg;
- local_info_t *local = NULL;
- struct net_device *dev = NULL;
- struct hostap_interface *iface;
- static int cards_found /* = 0 */;
- int irq_registered = 0;
- int tmd7160;
- struct hostap_plx_priv *hw_priv;
-
- hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
- if (hw_priv == NULL)
- return -ENOMEM;
-
- if (pci_enable_device(pdev))
- goto err_out_free;
-
- /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
- tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
-
- plx_ioaddr = pci_resource_start(pdev, 1);
- pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
-
- if (tmd7160) {
- /* TMD7160 */
- attr_mem = NULL; /* no access to PC Card attribute memory */
-
- printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
- "irq=%d, pccard_io=0x%x\n",
- plx_ioaddr, pdev->irq, pccard_ioaddr);
-
- cor_offset = plx_ioaddr;
- cor_index = 0x04;
-
- outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
- mdelay(1);
- reg = inb(plx_ioaddr);
- if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
- printk(KERN_ERR "%s: Error setting COR (expected="
- "0x%02x, was=0x%02x)\n", dev_info,
- cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
- goto fail;
- }
- } else {
- /* PLX9052 */
- pccard_attr_mem = pci_resource_start(pdev, 2);
- pccard_attr_len = pci_resource_len(pdev, 2);
- if (pccard_attr_len < PLX_MIN_ATTR_LEN)
- goto fail;
-
-
- attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
- if (attr_mem == NULL) {
- printk(KERN_ERR "%s: cannot remap attr_mem\n",
- dev_info);
- goto fail;
- }
-
- printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
- "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
- pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
-
- if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
- &cor_offset, &cor_index)) {
- printk(KERN_INFO "Unknown PC Card CIS - not a "
- "Prism2/2.5 card?\n");
- goto fail;
- }
-
- printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
- "adapter\n");
-
- /* Write COR to enable PC Card */
- writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
- attr_mem + cor_offset);
-
- /* Enable PCI interrupts if they are not already enabled */
- reg = inl(plx_ioaddr + PLX_INTCSR);
- printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
- if (!(reg & PLX_INTCSR_PCI_INTEN)) {
- outl(reg | PLX_INTCSR_PCI_INTEN,
- plx_ioaddr + PLX_INTCSR);
- if (!(inl(plx_ioaddr + PLX_INTCSR) &
- PLX_INTCSR_PCI_INTEN)) {
- printk(KERN_WARNING "%s: Could not enable "
- "Local Interrupts\n", dev_info);
- goto fail;
- }
- }
-
- reg = inl(plx_ioaddr + PLX_CNTRL);
- printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
- "present=%d)\n",
- reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
- /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
- * not present; but are there really such cards in use(?) */
- }
-
- dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
- &pdev->dev);
- if (dev == NULL)
- goto fail;
- iface = netdev_priv(dev);
- local = iface->local;
- local->hw_priv = hw_priv;
- cards_found++;
-
- dev->irq = pdev->irq;
- dev->base_addr = pccard_ioaddr;
- hw_priv->attr_mem = attr_mem;
- hw_priv->cor_offset = cor_offset;
-
- pci_set_drvdata(pdev, dev);
-
- if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
- dev)) {
- printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
- goto fail;
- } else
- irq_registered = 1;
-
- if (prism2_hw_config(dev, 1)) {
- printk(KERN_DEBUG "%s: hardware initialization failed\n",
- dev_info);
- goto fail;
- }
-
- return hostap_hw_ready(dev);
-
- fail:
- if (irq_registered && dev)
- free_irq(dev->irq, dev);
-
- if (attr_mem)
- iounmap(attr_mem);
-
- pci_disable_device(pdev);
- prism2_free_local_data(dev);
-
- err_out_free:
- kfree(hw_priv);
-
- return -ENODEV;
-}
-
-
-static void prism2_plx_remove(struct pci_dev *pdev)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- struct hostap_plx_priv *hw_priv;
-
- dev = pci_get_drvdata(pdev);
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
-
- /* Reset the hardware, and ensure interrupts are disabled. */
- prism2_plx_cor_sreset(iface->local);
- hfa384x_disable_interrupts(dev);
-
- if (hw_priv->attr_mem)
- iounmap(hw_priv->attr_mem);
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- prism2_free_local_data(dev);
- kfree(hw_priv);
- pci_disable_device(pdev);
-}
-
-
-MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
-
-static struct pci_driver prism2_plx_driver = {
- .name = "hostap_plx",
- .id_table = prism2_plx_id_table,
- .probe = prism2_plx_probe,
- .remove = prism2_plx_remove,
-};
-
-module_pci_driver(prism2_plx_driver);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_proc.c b/drivers/net/wireless/intersil/hostap/hostap_proc.c
deleted file mode 100644
index 61f68786056f..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_proc.c
+++ /dev/null
@@ -1,411 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* /proc routines for Host AP driver */
-
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-#include <net/lib80211.h>
-
-#include "hostap_wlan.h"
-#include "hostap.h"
-
-#define PROC_LIMIT (PAGE_SIZE - 80)
-
-#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS)
-static int prism2_debug_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
- int i;
-
- seq_printf(m, "next_txfid=%d next_alloc=%d\n",
- local->next_txfid, local->next_alloc);
- for (i = 0; i < PRISM2_TXFID_COUNT; i++)
- seq_printf(m, "FID: tx=%04X intransmit=%04X\n",
- local->txfid[i], local->intransmitfid[i]);
- seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control);
- seq_printf(m, "beacon_int=%d\n", local->beacon_int);
- seq_printf(m, "dtim_period=%d\n", local->dtim_period);
- seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections);
- seq_printf(m, "dev_enabled=%d\n", local->dev_enabled);
- seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
- for (i = 0; i < WEP_KEYS; i++) {
- if (local->crypt_info.crypt[i] &&
- local->crypt_info.crypt[i]->ops) {
- seq_printf(m, "crypt[%d]=%s\n", i,
- local->crypt_info.crypt[i]->ops->name);
- }
- }
- seq_printf(m, "pri_only=%d\n", local->pri_only);
- seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
- seq_printf(m, "sram_type=%d\n", local->sram_type);
- seq_printf(m, "no_pri=%d\n", local->no_pri);
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_PROC_FS
-static int prism2_stats_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
- struct comm_tallies_sums *sums = &local->comm_tallies;
-
- seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
- seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
- seq_printf(m, "TxFragments=%u\n", sums->tx_fragments);
- seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
- seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
- seq_printf(m, "TxDeferredTransmissions=%u\n",
- sums->tx_deferred_transmissions);
- seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames);
- seq_printf(m, "TxMultipleRetryFrames=%u\n",
- sums->tx_multiple_retry_frames);
- seq_printf(m, "TxRetryLimitExceeded=%u\n",
- sums->tx_retry_limit_exceeded);
- seq_printf(m, "TxDiscards=%u\n", sums->tx_discards);
- seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
- seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
- seq_printf(m, "RxFragments=%u\n", sums->rx_fragments);
- seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
- seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
- seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
- seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer);
- seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
- seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n",
- sums->rx_discards_wep_undecryptable);
- seq_printf(m, "RxMessageInMsgFragments=%u\n",
- sums->rx_message_in_msg_fragments);
- seq_printf(m, "RxMessageInBadMsgFragments=%u\n",
- sums->rx_message_in_bad_msg_fragments);
- /* FIX: this may grow too long for one page(?) */
-
- return 0;
-}
-#endif
-
-static int prism2_wds_proc_show(struct seq_file *m, void *v)
-{
- struct list_head *ptr = v;
- struct hostap_interface *iface;
-
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_WDS)
- seq_printf(m, "%s\t%pM\n",
- iface->dev->name, iface->u.wds.remote_addr);
- return 0;
-}
-
-static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- read_lock_bh(&local->iface_lock);
- return seq_list_start(&local->hostap_interfaces, *_pos);
-}
-
-static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- return seq_list_next(v, &local->hostap_interfaces, _pos);
-}
-
-static void prism2_wds_proc_stop(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- read_unlock_bh(&local->iface_lock);
-}
-
-static const struct seq_operations prism2_wds_proc_seqops = {
- .start = prism2_wds_proc_start,
- .next = prism2_wds_proc_next,
- .stop = prism2_wds_proc_stop,
- .show = prism2_wds_proc_show,
-};
-
-static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- struct list_head *ptr = v;
- struct hostap_bss_info *bss;
-
- if (ptr == &local->bss_list) {
- seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
- "SSID(hex)\tWPA IE\n");
- return 0;
- }
-
- bss = list_entry(ptr, struct hostap_bss_info, list);
- seq_printf(m, "%pM\t%lu\t%u\t0x%x\t",
- bss->bssid, bss->last_update,
- bss->count, bss->capab_info);
-
- seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid);
-
- seq_putc(m, '\t');
- seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
- seq_putc(m, '\t');
- seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie);
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos)
- __acquires(&local->lock)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_lock_bh(&local->lock);
- return seq_list_start_head(&local->bss_list, *_pos);
-}
-
-static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- return seq_list_next(v, &local->bss_list, _pos);
-}
-
-static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)
- __releases(&local->lock)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_unlock_bh(&local->lock);
-}
-
-static const struct seq_operations prism2_bss_list_proc_seqops = {
- .start = prism2_bss_list_proc_start,
- .next = prism2_bss_list_proc_next,
- .stop = prism2_bss_list_proc_stop,
- .show = prism2_bss_list_proc_show,
-};
-
-#ifdef CONFIG_PROC_FS
-static int prism2_crypt_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
- int i;
-
- seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
- for (i = 0; i < WEP_KEYS; i++) {
- if (local->crypt_info.crypt[i] &&
- local->crypt_info.crypt[i]->ops &&
- local->crypt_info.crypt[i]->ops->print_stats) {
- local->crypt_info.crypt[i]->ops->print_stats(
- m, local->crypt_info.crypt[i]->priv);
- }
- }
- return 0;
-}
-#endif
-
-static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf,
- size_t count, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(file));
- size_t off;
-
- if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)
- return 0;
-
- off = *_pos;
- if (count > PRISM2_PDA_SIZE - off)
- count = PRISM2_PDA_SIZE - off;
- if (copy_to_user(buf, local->pda + off, count) != 0)
- return -EFAULT;
- *_pos += count;
- return count;
-}
-
-static const struct proc_ops prism2_pda_proc_ops = {
- .proc_read = prism2_pda_proc_read,
- .proc_lseek = generic_file_llseek,
-};
-
-
-static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf,
- size_t bufsize, loff_t *_pos)
-{
- return 0;
-}
-
-static const struct proc_ops prism2_aux_dump_proc_ops = {
- .proc_read = prism2_aux_dump_proc_no_read,
- .proc_lseek = default_llseek,
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- local_info_t *local = (local_info_t *) data;
- int head = local->io_debug_head;
- int start_bytes, left, copy;
-
- if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
- *eof = 1;
- if (off >= PRISM2_IO_DEBUG_SIZE * 4)
- return 0;
- count = PRISM2_IO_DEBUG_SIZE * 4 - off;
- }
-
- start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
- left = count;
-
- if (off < start_bytes) {
- copy = start_bytes - off;
- if (copy > count)
- copy = count;
- memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
- left -= copy;
- if (left > 0)
- memcpy(&page[copy], local->io_debug, left);
- } else {
- memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
- left);
- }
-
- *start = page;
-
- return count;
-}
-#endif /* PRISM2_IO_DEBUG */
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static int prism2_scan_results_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- unsigned long entry;
- int i, len;
- struct hfa384x_hostscan_result *scanres;
- u8 *p;
-
- if (v == SEQ_START_TOKEN) {
- seq_printf(m,
- "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n");
- return 0;
- }
-
- entry = (unsigned long)v - 2;
- scanres = &local->last_scan_results[entry];
-
- seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ",
- le16_to_cpu(scanres->chid),
- (s16) le16_to_cpu(scanres->anl),
- (s16) le16_to_cpu(scanres->sl),
- le16_to_cpu(scanres->beacon_interval),
- le16_to_cpu(scanres->capability),
- le16_to_cpu(scanres->rate),
- scanres->bssid,
- le16_to_cpu(scanres->atim));
-
- p = scanres->sup_rates;
- for (i = 0; i < sizeof(scanres->sup_rates); i++) {
- if (p[i] == 0)
- break;
- seq_printf(m, "<%02x>", p[i]);
- }
- seq_putc(m, ' ');
-
- p = scanres->ssid;
- len = le16_to_cpu(scanres->ssid_len);
- if (len > 32)
- len = 32;
- for (i = 0; i < len; i++) {
- unsigned char c = p[i];
- if (c >= 32 && c < 127)
- seq_putc(m, c);
- else
- seq_printf(m, "<%02x>", c);
- }
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_lock_bh(&local->lock);
-
- /* We have a header (pos 0) + N results to show (pos 1...N) */
- if (*_pos > local->last_scan_results_count)
- return NULL;
- return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
-}
-
-static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
-
- ++*_pos;
- if (*_pos > local->last_scan_results_count)
- return NULL;
- return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
-}
-
-static void prism2_scan_results_proc_stop(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_unlock_bh(&local->lock);
-}
-
-static const struct seq_operations prism2_scan_results_proc_seqops = {
- .start = prism2_scan_results_proc_start,
- .next = prism2_scan_results_proc_next,
- .stop = prism2_scan_results_proc_stop,
- .show = prism2_scan_results_proc_show,
-};
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-void hostap_init_proc(local_info_t *local)
-{
- local->proc = NULL;
-
- if (hostap_proc == NULL) {
- printk(KERN_WARNING "%s: hostap proc directory not created\n",
- local->dev->name);
- return;
- }
-
- local->proc = proc_mkdir(local->ddev->name, hostap_proc);
- if (local->proc == NULL) {
- printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
- local->ddev->name);
- return;
- }
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- proc_create_single_data("debug", 0, local->proc,
- prism2_debug_proc_show, local);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
- proc_create_single_data("stats", 0, local->proc, prism2_stats_proc_show,
- local);
- proc_create_seq_data("wds", 0, local->proc,
- &prism2_wds_proc_seqops, local);
- proc_create_data("pda", 0, local->proc,
- &prism2_pda_proc_ops, local);
- proc_create_data("aux_dump", 0, local->proc,
- local->func->read_aux_proc_ops ?: &prism2_aux_dump_proc_ops,
- local);
- proc_create_seq_data("bss_list", 0, local->proc,
- &prism2_bss_list_proc_seqops, local);
- proc_create_single_data("crypt", 0, local->proc, prism2_crypt_proc_show,
- local);
-#ifdef PRISM2_IO_DEBUG
- proc_create_single_data("io_debug", 0, local->proc,
- prism2_debug_proc_show, local);
-#endif /* PRISM2_IO_DEBUG */
-#ifndef PRISM2_NO_STATION_MODES
- proc_create_seq_data("scan_results", 0, local->proc,
- &prism2_scan_results_proc_seqops, local);
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-void hostap_remove_proc(local_info_t *local)
-{
- proc_remove(local->proc);
-}
-
-
-EXPORT_SYMBOL(hostap_init_proc);
-EXPORT_SYMBOL(hostap_remove_proc);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h
deleted file mode 100644
index f71c0545c0be..000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h
+++ /dev/null
@@ -1,1051 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_WLAN_H
-#define HOSTAP_WLAN_H
-
-#include <linux/interrupt.h>
-#include <linux/wireless.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/mutex.h>
-#include <linux/refcount.h>
-#include <net/iw_handler.h>
-#include <net/ieee80211_radiotap.h>
-#include <net/lib80211.h>
-
-#include "hostap_config.h"
-#include "hostap_common.h"
-
-#define MAX_PARM_DEVICES 8
-#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES)
-#define DEF_INTS -1, -1, -1, -1, -1, -1, -1
-#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx]
-
-
-/* Specific skb->protocol value that indicates that the packet already contains
- * txdesc header.
- * FIX: This might need own value that would be allocated especially for Prism2
- * txdesc; ETH_P_CONTROL is commented as "Card specific control frames".
- * However, these skb's should have only minimal path in the kernel side since
- * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */
-#define ETH_P_HOSTAP ETH_P_CONTROL
-
-/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header
- * (from linux-wlan-ng) */
-struct linux_wlan_ng_val {
- u32 did;
- u16 status, len;
- u32 data;
-} __packed;
-
-struct linux_wlan_ng_prism_hdr {
- u32 msgcode, msglen;
- char devname[16];
- struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
- noise, rate, istx, frmlen;
-} __packed;
-
-struct linux_wlan_ng_cap_hdr {
- __be32 version;
- __be32 length;
- __be64 mactime;
- __be64 hosttime;
- __be32 phytype;
- __be32 channel;
- __be32 datarate;
- __be32 antenna;
- __be32 priority;
- __be32 ssi_type;
- __be32 ssi_signal;
- __be32 ssi_noise;
- __be32 preamble;
- __be32 encoding;
-} __packed;
-
-struct hostap_radiotap_rx {
- struct ieee80211_radiotap_header hdr;
- __le64 tsft;
- u8 rate;
- u8 padding;
- __le16 chan_freq;
- __le16 chan_flags;
- s8 dbm_antsignal;
- s8 dbm_antnoise;
-} __packed;
-
-#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */
-#define LWNG_CAPHDR_VERSION 0x80211001
-
-struct hfa384x_rx_frame {
- /* HFA384X RX frame descriptor */
- __le16 status; /* HFA384X_RX_STATUS_ flags */
- __le32 time; /* timestamp, 1 microsecond resolution */
- u8 silence; /* 27 .. 154; seems to be 0 */
- u8 signal; /* 27 .. 154 */
- u8 rate; /* 10, 20, 55, or 110 */
- u8 rxflow;
- __le32 reserved;
-
- /* 802.11 */
- __le16 frame_control;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctrl;
- u8 addr4[ETH_ALEN];
- __le16 data_len;
-
- /* 802.3 */
- u8 dst_addr[ETH_ALEN];
- u8 src_addr[ETH_ALEN];
- __be16 len;
-
- /* followed by frame data; max 2304 bytes */
-} __packed;
-
-
-struct hfa384x_tx_frame {
- /* HFA384X TX frame descriptor */
- __le16 status; /* HFA384X_TX_STATUS_ flags */
- __le16 reserved1;
- __le16 reserved2;
- __le32 sw_support;
- u8 retry_count; /* not yet implemented */
- u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */
- __le16 tx_control; /* HFA384X_TX_CTRL_ flags */
-
- /* 802.11 */
- struct_group(header,
- __le16 frame_control; /* parts not used */
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN]; /* filled by firmware */
- u8 addr3[ETH_ALEN];
- __le16 seq_ctrl; /* filled by firmware */
- );
- u8 addr4[ETH_ALEN];
- __le16 data_len;
-
- /* 802.3 */
- u8 dst_addr[ETH_ALEN];
- u8 src_addr[ETH_ALEN];
- __be16 len;
-
- /* followed by frame data; max 2304 bytes */
-} __packed;
-
-
-struct hfa384x_rid_hdr
-{
- __le16 len;
- __le16 rid;
-} __packed;
-
-
-/* Macro for converting signal levels (range 27 .. 154) to wireless ext
- * dBm value with some accuracy */
-#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100
-
-#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100
-
-struct hfa384x_scan_request {
- __le16 channel_list;
- __le16 txrate; /* HFA384X_RATES_* */
-} __packed;
-
-struct hfa384x_hostscan_request {
- __le16 channel_list;
- __le16 txrate;
- __le16 target_ssid_len;
- u8 target_ssid[32];
-} __packed;
-
-struct hfa384x_join_request {
- u8 bssid[ETH_ALEN];
- __le16 channel;
-} __packed;
-
-struct hfa384x_info_frame {
- __le16 len;
- __le16 type;
-} __packed;
-
-struct hfa384x_comm_tallies {
- __le16 tx_unicast_frames;
- __le16 tx_multicast_frames;
- __le16 tx_fragments;
- __le16 tx_unicast_octets;
- __le16 tx_multicast_octets;
- __le16 tx_deferred_transmissions;
- __le16 tx_single_retry_frames;
- __le16 tx_multiple_retry_frames;
- __le16 tx_retry_limit_exceeded;
- __le16 tx_discards;
- __le16 rx_unicast_frames;
- __le16 rx_multicast_frames;
- __le16 rx_fragments;
- __le16 rx_unicast_octets;
- __le16 rx_multicast_octets;
- __le16 rx_fcs_errors;
- __le16 rx_discards_no_buffer;
- __le16 tx_discards_wrong_sa;
- __le16 rx_discards_wep_undecryptable;
- __le16 rx_message_in_msg_fragments;
- __le16 rx_message_in_bad_msg_fragments;
-} __packed;
-
-struct hfa384x_comm_tallies32 {
- __le32 tx_unicast_frames;
- __le32 tx_multicast_frames;
- __le32 tx_fragments;
- __le32 tx_unicast_octets;
- __le32 tx_multicast_octets;
- __le32 tx_deferred_transmissions;
- __le32 tx_single_retry_frames;
- __le32 tx_multiple_retry_frames;
- __le32 tx_retry_limit_exceeded;
- __le32 tx_discards;
- __le32 rx_unicast_frames;
- __le32 rx_multicast_frames;
- __le32 rx_fragments;
- __le32 rx_unicast_octets;
- __le32 rx_multicast_octets;
- __le32 rx_fcs_errors;
- __le32 rx_discards_no_buffer;
- __le32 tx_discards_wrong_sa;
- __le32 rx_discards_wep_undecryptable;
- __le32 rx_message_in_msg_fragments;
- __le32 rx_message_in_bad_msg_fragments;
-} __packed;
-
-struct hfa384x_scan_result_hdr {
- __le16 reserved;
- __le16 scan_reason;
-#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */
-#define HFA384X_SCAN_HOST_INITIATED 1
-#define HFA384X_SCAN_FIRMWARE_INITIATED 2
-#define HFA384X_SCAN_INQUIRY_FROM_HOST 3
-} __packed;
-
-#define HFA384X_SCAN_MAX_RESULTS 32
-
-struct hfa384x_scan_result {
- __le16 chid;
- __le16 anl;
- __le16 sl;
- u8 bssid[ETH_ALEN];
- __le16 beacon_interval;
- __le16 capability;
- __le16 ssid_len;
- u8 ssid[32];
- u8 sup_rates[10];
- __le16 rate;
-} __packed;
-
-struct hfa384x_hostscan_result {
- __le16 chid;
- __le16 anl;
- __le16 sl;
- u8 bssid[ETH_ALEN];
- __le16 beacon_interval;
- __le16 capability;
- __le16 ssid_len;
- u8 ssid[32];
- u8 sup_rates[10];
- __le16 rate;
- __le16 atim;
-} __packed;
-
-struct comm_tallies_sums {
- unsigned int tx_unicast_frames;
- unsigned int tx_multicast_frames;
- unsigned int tx_fragments;
- unsigned int tx_unicast_octets;
- unsigned int tx_multicast_octets;
- unsigned int tx_deferred_transmissions;
- unsigned int tx_single_retry_frames;
- unsigned int tx_multiple_retry_frames;
- unsigned int tx_retry_limit_exceeded;
- unsigned int tx_discards;
- unsigned int rx_unicast_frames;
- unsigned int rx_multicast_frames;
- unsigned int rx_fragments;
- unsigned int rx_unicast_octets;
- unsigned int rx_multicast_octets;
- unsigned int rx_fcs_errors;
- unsigned int rx_discards_no_buffer;
- unsigned int tx_discards_wrong_sa;
- unsigned int rx_discards_wep_undecryptable;
- unsigned int rx_message_in_msg_fragments;
- unsigned int rx_message_in_bad_msg_fragments;
-};
-
-
-struct hfa384x_regs {
- u16 cmd;
- u16 evstat;
- u16 offset0;
- u16 offset1;
- u16 swsupport0;
-};
-
-
-#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX)
-/* I/O ports for HFA384X Controller access */
-#define HFA384X_CMD_OFF 0x00
-#define HFA384X_PARAM0_OFF 0x02
-#define HFA384X_PARAM1_OFF 0x04
-#define HFA384X_PARAM2_OFF 0x06
-#define HFA384X_STATUS_OFF 0x08
-#define HFA384X_RESP0_OFF 0x0A
-#define HFA384X_RESP1_OFF 0x0C
-#define HFA384X_RESP2_OFF 0x0E
-#define HFA384X_INFOFID_OFF 0x10
-#define HFA384X_CONTROL_OFF 0x14
-#define HFA384X_SELECT0_OFF 0x18
-#define HFA384X_SELECT1_OFF 0x1A
-#define HFA384X_OFFSET0_OFF 0x1C
-#define HFA384X_OFFSET1_OFF 0x1E
-#define HFA384X_RXFID_OFF 0x20
-#define HFA384X_ALLOCFID_OFF 0x22
-#define HFA384X_TXCOMPLFID_OFF 0x24
-#define HFA384X_SWSUPPORT0_OFF 0x28
-#define HFA384X_SWSUPPORT1_OFF 0x2A
-#define HFA384X_SWSUPPORT2_OFF 0x2C
-#define HFA384X_EVSTAT_OFF 0x30
-#define HFA384X_INTEN_OFF 0x32
-#define HFA384X_EVACK_OFF 0x34
-#define HFA384X_DATA0_OFF 0x36
-#define HFA384X_DATA1_OFF 0x38
-#define HFA384X_AUXPAGE_OFF 0x3A
-#define HFA384X_AUXOFFSET_OFF 0x3C
-#define HFA384X_AUXDATA_OFF 0x3E
-#endif /* PRISM2_PCCARD || PRISM2_PLX */
-
-#ifdef PRISM2_PCI
-/* Memory addresses for ISL3874 controller access */
-#define HFA384X_CMD_OFF 0x00
-#define HFA384X_PARAM0_OFF 0x04
-#define HFA384X_PARAM1_OFF 0x08
-#define HFA384X_PARAM2_OFF 0x0C
-#define HFA384X_STATUS_OFF 0x10
-#define HFA384X_RESP0_OFF 0x14
-#define HFA384X_RESP1_OFF 0x18
-#define HFA384X_RESP2_OFF 0x1C
-#define HFA384X_INFOFID_OFF 0x20
-#define HFA384X_CONTROL_OFF 0x28
-#define HFA384X_SELECT0_OFF 0x30
-#define HFA384X_SELECT1_OFF 0x34
-#define HFA384X_OFFSET0_OFF 0x38
-#define HFA384X_OFFSET1_OFF 0x3C
-#define HFA384X_RXFID_OFF 0x40
-#define HFA384X_ALLOCFID_OFF 0x44
-#define HFA384X_TXCOMPLFID_OFF 0x48
-#define HFA384X_PCICOR_OFF 0x4C
-#define HFA384X_SWSUPPORT0_OFF 0x50
-#define HFA384X_SWSUPPORT1_OFF 0x54
-#define HFA384X_SWSUPPORT2_OFF 0x58
-#define HFA384X_PCIHCR_OFF 0x5C
-#define HFA384X_EVSTAT_OFF 0x60
-#define HFA384X_INTEN_OFF 0x64
-#define HFA384X_EVACK_OFF 0x68
-#define HFA384X_DATA0_OFF 0x6C
-#define HFA384X_DATA1_OFF 0x70
-#define HFA384X_AUXPAGE_OFF 0x74
-#define HFA384X_AUXOFFSET_OFF 0x78
-#define HFA384X_AUXDATA_OFF 0x7C
-#define HFA384X_PCI_M0_ADDRH_OFF 0x80
-#define HFA384X_PCI_M0_ADDRL_OFF 0x84
-#define HFA384X_PCI_M0_LEN_OFF 0x88
-#define HFA384X_PCI_M0_CTL_OFF 0x8C
-#define HFA384X_PCI_STATUS_OFF 0x98
-#define HFA384X_PCI_M1_ADDRH_OFF 0xA0
-#define HFA384X_PCI_M1_ADDRL_OFF 0xA4
-#define HFA384X_PCI_M1_LEN_OFF 0xA8
-#define HFA384X_PCI_M1_CTL_OFF 0xAC
-
-/* PCI bus master control bits (these are undocumented; based on guessing and
- * experimenting..) */
-#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0))
-#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0))
-
-#endif /* PRISM2_PCI */
-
-
-/* Command codes for CMD reg. */
-#define HFA384X_CMDCODE_INIT 0x00
-#define HFA384X_CMDCODE_ENABLE 0x01
-#define HFA384X_CMDCODE_DISABLE 0x02
-#define HFA384X_CMDCODE_ALLOC 0x0A
-#define HFA384X_CMDCODE_TRANSMIT 0x0B
-#define HFA384X_CMDCODE_INQUIRE 0x11
-#define HFA384X_CMDCODE_ACCESS 0x21
-#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8))
-#define HFA384X_CMDCODE_DOWNLOAD 0x22
-#define HFA384X_CMDCODE_READMIF 0x30
-#define HFA384X_CMDCODE_WRITEMIF 0x31
-#define HFA384X_CMDCODE_TEST 0x38
-
-#define HFA384X_CMDCODE_MASK 0x3F
-
-/* Test mode operations */
-#define HFA384X_TEST_CHANGE_CHANNEL 0x08
-#define HFA384X_TEST_MONITOR 0x0B
-#define HFA384X_TEST_STOP 0x0F
-#define HFA384X_TEST_CFG_BITS 0x15
-#define HFA384X_TEST_CFG_BIT_ALC BIT(3)
-
-#define HFA384X_CMD_BUSY BIT(15)
-
-#define HFA384X_CMD_TX_RECLAIM BIT(8)
-
-#define HFA384X_OFFSET_ERR BIT(14)
-#define HFA384X_OFFSET_BUSY BIT(15)
-
-
-/* ProgMode for download command */
-#define HFA384X_PROGMODE_DISABLE 0
-#define HFA384X_PROGMODE_ENABLE_VOLATILE 1
-#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2
-#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3
-
-#define HFA384X_AUX_MAGIC0 0xfe01
-#define HFA384X_AUX_MAGIC1 0xdc23
-#define HFA384X_AUX_MAGIC2 0xba45
-
-#define HFA384X_AUX_PORT_DISABLED 0
-#define HFA384X_AUX_PORT_DISABLE BIT(14)
-#define HFA384X_AUX_PORT_ENABLE BIT(15)
-#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15))
-#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15))
-
-#define PRISM2_PDA_SIZE 1024
-
-
-/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */
-#define HFA384X_EV_TICK BIT(15)
-#define HFA384X_EV_WTERR BIT(14)
-#define HFA384X_EV_INFDROP BIT(13)
-#ifdef PRISM2_PCI
-#define HFA384X_EV_PCI_M1 BIT(9)
-#define HFA384X_EV_PCI_M0 BIT(8)
-#endif /* PRISM2_PCI */
-#define HFA384X_EV_INFO BIT(7)
-#define HFA384X_EV_DTIM BIT(5)
-#define HFA384X_EV_CMD BIT(4)
-#define HFA384X_EV_ALLOC BIT(3)
-#define HFA384X_EV_TXEXC BIT(2)
-#define HFA384X_EV_TX BIT(1)
-#define HFA384X_EV_RX BIT(0)
-
-
-/* HFA384X Information frames */
-#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */
-#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */
-#define HFA384X_INFO_COMMTALLIES 0xF100
-#define HFA384X_INFO_SCANRESULTS 0xF101
-#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */
-#define HFA384X_INFO_HOSTSCANRESULTS 0xF103
-#define HFA384X_INFO_LINKSTATUS 0xF200
-#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */
-#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */
-#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */
-#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */
-
-enum { HFA384X_LINKSTATUS_CONNECTED = 1,
- HFA384X_LINKSTATUS_DISCONNECTED = 2,
- HFA384X_LINKSTATUS_AP_CHANGE = 3,
- HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4,
- HFA384X_LINKSTATUS_AP_IN_RANGE = 5,
- HFA384X_LINKSTATUS_ASSOC_FAILED = 6 };
-
-enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2,
- HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0,
- HFA384X_PORTTYPE_HOSTAP = 6 };
-
-#define HFA384X_RATES_1MBPS BIT(0)
-#define HFA384X_RATES_2MBPS BIT(1)
-#define HFA384X_RATES_5MBPS BIT(2)
-#define HFA384X_RATES_11MBPS BIT(3)
-
-#define HFA384X_ROAMING_FIRMWARE 1
-#define HFA384X_ROAMING_HOST 2
-#define HFA384X_ROAMING_DISABLED 3
-
-#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0)
-#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1)
-#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4)
-#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7)
-
-#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13))
-#define HFA384X_RX_STATUS_PCF BIT(12)
-#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8))
-#define HFA384X_RX_STATUS_UNDECR BIT(1)
-#define HFA384X_RX_STATUS_FCSERR BIT(0)
-
-#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \
-(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13)
-#define HFA384X_RX_STATUS_GET_MACPORT(s) \
-(((s) & HFA384X_RX_STATUS_MACPORT) >> 8)
-
-enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1,
- HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 };
-
-
-#define HFA384X_TX_CTRL_ALT_RTRY BIT(5)
-#define HFA384X_TX_CTRL_802_11 BIT(3)
-#define HFA384X_TX_CTRL_802_3 0
-#define HFA384X_TX_CTRL_TX_EX BIT(2)
-#define HFA384X_TX_CTRL_TX_OK BIT(1)
-
-#define HFA384X_TX_STATUS_RETRYERR BIT(0)
-#define HFA384X_TX_STATUS_AGEDERR BIT(1)
-#define HFA384X_TX_STATUS_DISCON BIT(2)
-#define HFA384X_TX_STATUS_FORMERR BIT(3)
-
-/* HFA3861/3863 (BBP) Control Registers */
-#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */
-#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */
-#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */
-#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */
-#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */
-
-
-#ifdef __KERNEL__
-
-#define PRISM2_TXFID_COUNT 8
-#define PRISM2_DATA_MAXLEN 2304
-#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame))
-#define PRISM2_TXFID_EMPTY 0xffff
-#define PRISM2_TXFID_RESERVED 0xfffe
-#define PRISM2_DUMMY_FID 0xffff
-#define MAX_SSID_LEN 32
-#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */
-
-#define PRISM2_DUMP_RX_HDR BIT(0)
-#define PRISM2_DUMP_TX_HDR BIT(1)
-#define PRISM2_DUMP_TXEXC_HDR BIT(2)
-
-struct hostap_tx_callback_info {
- u16 idx;
- void (*func)(struct sk_buff *, int ok, void *);
- void *data;
- struct hostap_tx_callback_info *next;
-};
-
-
-/* IEEE 802.11 requires that STA supports concurrent reception of at least
- * three fragmented frames. This define can be increased to support more
- * concurrent frames, but it should be noted that each entry can consume about
- * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define PRISM2_FRAG_CACHE_LEN 4
-
-struct prism2_frag_entry {
- unsigned long first_frag_time;
- unsigned int seq;
- unsigned int last_frag;
- struct sk_buff *skb;
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
-};
-
-
-struct hostap_cmd_queue {
- struct list_head list;
- wait_queue_head_t compl;
- volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type;
- void (*callback)(struct net_device *dev, long context, u16 resp0,
- u16 res);
- long context;
- u16 cmd, param0, param1;
- u16 resp0, res;
- volatile int issued, issuing;
-
- refcount_t usecnt;
- int del_req;
-};
-
-/* options for hw_shutdown */
-#define HOSTAP_HW_NO_DISABLE BIT(0)
-#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1)
-
-typedef struct local_info local_info_t;
-
-struct prism2_helper_functions {
- /* these functions are defined in hardware model specific files
- * (hostap_{cs,plx,pci}.c */
- int (*card_present)(local_info_t *local);
- void (*cor_sreset)(local_info_t *local);
- void (*genesis_reset)(local_info_t *local, int hcr);
-
- /* the following functions are from hostap_hw.c, but they may have some
- * hardware model specific code */
-
- /* FIX: low-level commands like cmd might disappear at some point to
- * make it easier to change them if needed (e.g., cmd would be replaced
- * with write_mif/read_mif/testcmd/inquire); at least get_rid and
- * set_rid might move to hostap_{cs,plx,pci}.c */
- int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1,
- u16 *resp0);
- void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs);
- int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len,
- int exact_len);
- int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len);
- int (*hw_enable)(struct net_device *dev, int initial);
- int (*hw_config)(struct net_device *dev, int initial);
- void (*hw_reset)(struct net_device *dev);
- void (*hw_shutdown)(struct net_device *dev, int no_disable);
- int (*reset_port)(struct net_device *dev);
- void (*schedule_reset)(local_info_t *local);
- int (*download)(local_info_t *local,
- struct prism2_download_param *param);
- int (*tx)(struct sk_buff *skb, struct net_device *dev);
- int (*set_tim)(struct net_device *dev, int aid, int set);
- const struct proc_ops *read_aux_proc_ops;
-
- int need_tx_headroom; /* number of bytes of headroom needed before
- * IEEE 802.11 header */
- enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type;
-};
-
-
-struct prism2_download_data {
- u32 dl_cmd;
- u32 start_addr;
- u32 num_areas;
- struct prism2_download_data_area {
- u32 addr; /* wlan card address */
- u32 len;
- u8 *data; /* allocated data */
- } data[] __counted_by(num_areas);
-};
-
-
-#define HOSTAP_MAX_BSS_COUNT 64
-#define MAX_WPA_IE_LEN 64
-
-struct hostap_bss_info {
- struct list_head list;
- unsigned long last_update;
- unsigned int count;
- u8 bssid[ETH_ALEN];
- u16 capab_info;
- u8 ssid[32];
- size_t ssid_len;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- int chan;
- int included;
-};
-
-
-/* Per radio private Host AP data - shared by all net devices interfaces used
- * by each radio (wlan#, wlan#ap, wlan#sta, WDS).
- * ((struct hostap_interface *) netdev_priv(dev))->local points to this
- * structure. */
-struct local_info {
- struct module *hw_module;
- int card_idx;
- int dev_enabled;
- int master_dev_auto_open; /* was master device opened automatically */
- int num_dev_open; /* number of open devices */
- struct net_device *dev; /* master radio device */
- struct net_device *ddev; /* main data device */
- struct list_head hostap_interfaces; /* Host AP interface list (contains
- * struct hostap_interface entries)
- */
- rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock
- * when removing entries from the list.
- * TX and RX paths can use read lock. */
- spinlock_t cmdlock, baplock, lock, irq_init_lock;
- struct mutex rid_bap_mtx;
- u16 infofid; /* MAC buffer id for info frame */
- /* txfid, intransmitfid, next_txtid, and next_alloc are protected by
- * txfidlock */
- spinlock_t txfidlock;
- int txfid_len; /* length of allocated TX buffers */
- u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */
- /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if
- * corresponding txfid is free for next TX frame */
- u16 intransmitfid[PRISM2_TXFID_COUNT];
- int next_txfid; /* index to the next txfid to be checked for
- * availability */
- int next_alloc; /* index to the next intransmitfid to be checked for
- * allocation events */
-
- /* bitfield for atomic bitops */
-#define HOSTAP_BITS_TRANSMIT 0
-#define HOSTAP_BITS_BAP_TASKLET 1
-#define HOSTAP_BITS_BAP_TASKLET2 2
- unsigned long bits;
-
- struct ap_data *ap;
-
- char essid[MAX_SSID_LEN + 1];
- char name[MAX_NAME_LEN + 1];
- int name_set;
- u16 channel_mask; /* mask of allowed channels */
- u16 scan_channel_mask; /* mask of channels to be scanned */
- struct comm_tallies_sums comm_tallies;
- struct proc_dir_entry *proc;
- int iw_mode; /* operating mode (IW_MODE_*) */
- int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS
- * 1: IW_MODE_ADHOC is "pseudo IBSS" */
- char bssid[ETH_ALEN];
- int channel;
- int beacon_int;
- int dtim_period;
- int mtu;
- int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */
- int fw_tx_rate_control;
- u16 tx_rate_control;
- u16 basic_rates;
- int hw_resetting;
- int hw_ready;
- int hw_reset_tries; /* how many times reset has been tried */
- int hw_downloading;
- int shutdown;
- int pri_only;
- int no_pri; /* no PRI f/w present */
- int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */
-
- enum {
- PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF,
- PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN
- } txpower_type;
- int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */
-
- /* command queue for hfa384x_cmd(); protected with cmdlock */
- struct list_head cmd_queue;
- /* max_len for cmd_queue; in addition, cmd_callback can use two
- * additional entries to prevent sleeping commands from stopping
- * transmits */
-#define HOSTAP_CMD_QUEUE_MAX_LEN 16
- int cmd_queue_len; /* number of entries in cmd_queue */
-
- /* if card timeout is detected in interrupt context, reset_queue is
- * used to schedule card reseting to be done in user context */
- struct work_struct reset_queue;
-
- /* For scheduling a change of the promiscuous mode RID */
- int is_promisc;
- struct work_struct set_multicast_list_queue;
-
- struct work_struct set_tim_queue;
- struct list_head set_tim_list;
- spinlock_t set_tim_lock;
-
- int wds_max_connections;
- int wds_connections;
-#define HOSTAP_WDS_BROADCAST_RA BIT(0)
-#define HOSTAP_WDS_AP_CLIENT BIT(1)
-#define HOSTAP_WDS_STANDARD_FRAME BIT(2)
- u32 wds_type;
- u16 tx_control; /* flags to be used in TX description */
- int manual_retry_count; /* -1 = use f/w default; otherwise retry count
- * to be used with all frames */
-
- struct iw_statistics wstats;
- unsigned long scan_timestamp; /* Time started to scan */
- enum {
- PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
- PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3
- } monitor_type;
- int monitor_allow_fcserr;
-
- int hostapd; /* whether user space daemon, hostapd, is used for AP
- * management */
- int hostapd_sta; /* whether hostapd is used with an extra STA interface
- */
- struct net_device *apdev;
- struct net_device_stats apdevstats;
-
- char assoc_ap_addr[ETH_ALEN];
- struct net_device *stadev;
- struct net_device_stats stadevstats;
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
- struct lib80211_crypt_info crypt_info;
-
- int open_wep; /* allow unencrypted frames */
- int host_encrypt;
- int host_decrypt;
- int privacy_invoked; /* force privacy invoked flag even if no keys are
- * configured */
- int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working
- * in Host AP mode (STA f/w 1.4.9 or newer) */
- int bcrx_sta_key; /* use individual keys to override default keys even
- * with RX of broad/multicast frames */
-
- struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN];
- unsigned int frag_next_idx;
-
- int ieee_802_1x; /* is IEEE 802.1X used */
-
- int antsel_tx, antsel_rx;
- int rts_threshold; /* dot11RTSThreshold */
- int fragm_threshold; /* dot11FragmentationThreshold */
- int auth_algs; /* PRISM2_AUTH_ flags */
-
- int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */
- int tallies32; /* 32-bit tallies in use */
-
- struct prism2_helper_functions *func;
-
- u8 *pda;
- int fw_ap;
-#define PRISM2_FW_VER(major, minor, variant) \
-(((major) << 16) | ((minor) << 8) | variant)
- u32 sta_fw_ver;
-
- /* Tasklets for handling hardware IRQ related operations outside hw IRQ
- * handler */
- struct tasklet_struct bap_tasklet;
-
- struct tasklet_struct info_tasklet;
- struct sk_buff_head info_list; /* info frames as skb's for
- * info_tasklet */
-
- struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks
- */
-
- struct tasklet_struct rx_tasklet;
- struct sk_buff_head rx_list;
-
- struct tasklet_struct sta_tx_exc_tasklet;
- struct sk_buff_head sta_tx_exc_list;
-
- int host_roaming;
- unsigned long last_join_time; /* time of last JoinRequest */
- struct hfa384x_hostscan_result *last_scan_results;
- int last_scan_results_count;
- enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type;
- struct work_struct info_queue;
- unsigned long pending_info; /* bit field of pending info_queue items */
-#define PRISM2_INFO_PENDING_LINKSTATUS 0
-#define PRISM2_INFO_PENDING_SCANRESULTS 1
- int prev_link_status; /* previous received LinkStatus info */
- int prev_linkstatus_connected;
- u8 preferred_ap[ETH_ALEN]; /* use this AP if possible */
-
-#ifdef PRISM2_CALLBACK
- void *callback_data; /* Can be used in callbacks; e.g., allocate
- * on enable event and free on disable event.
- * Host AP driver code does not touch this. */
-#endif /* PRISM2_CALLBACK */
-
- wait_queue_head_t hostscan_wq;
-
- /* Passive scan in Host AP mode */
- struct timer_list passive_scan_timer;
- int passive_scan_interval; /* in seconds, 0 = disabled */
- int passive_scan_channel;
- enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state;
-
- struct timer_list tick_timer;
- unsigned long last_tick_timer;
- unsigned int sw_tick_stuck;
-
- /* commsQuality / dBmCommsQuality data from periodic polling; only
- * valid for Managed and Ad-hoc modes */
- unsigned long last_comms_qual_update;
- int comms_qual; /* in some odd unit.. */
- int avg_signal; /* in dB (note: negative) */
- int avg_noise; /* in dB (note: negative) */
- struct work_struct comms_qual_update;
-
- /* RSSI to dBm adjustment (for RX descriptor fields) */
- int rssi_to_dBm; /* subtract from RSSI to get approximate dBm value */
-
- /* BSS list / protected by local->lock */
- struct list_head bss_list;
- int num_bss_info;
- int wpa; /* WPA support enabled */
- int tkip_countermeasures;
- int drop_unencrypted;
- /* Generic IEEE 802.11 info element to be added to
- * ProbeResp/Beacon/(Re)AssocReq */
- u8 *generic_elem;
- size_t generic_elem_len;
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- /* Persistent volatile download data */
- struct prism2_download_data *dl_pri;
- struct prism2_download_data *dl_sec;
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-#ifdef PRISM2_IO_DEBUG
-#define PRISM2_IO_DEBUG_SIZE 10000
- u32 io_debug[PRISM2_IO_DEBUG_SIZE];
- int io_debug_head;
- int io_debug_enabled;
-#endif /* PRISM2_IO_DEBUG */
-
- /* Pointer to hardware model specific (cs,pci,plx) private data. */
- void *hw_priv;
-};
-
-
-/* Per interface private Host AP data
- * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta,
- * WDS) and netdev_priv(dev) points to this structure. */
-struct hostap_interface {
- struct list_head list; /* list entry in Host AP interface list */
- struct net_device *dev; /* pointer to this device */
- struct local_info *local; /* pointer to shared private data */
- struct net_device_stats stats;
- struct iw_spy_data spy_data; /* iwspy support */
- struct iw_public_data wireless_data;
-
- enum {
- HOSTAP_INTERFACE_MASTER,
- HOSTAP_INTERFACE_MAIN,
- HOSTAP_INTERFACE_AP,
- HOSTAP_INTERFACE_STA,
- HOSTAP_INTERFACE_WDS,
- } type;
-
- union {
- struct hostap_interface_wds {
- u8 remote_addr[ETH_ALEN];
- } wds;
- } u;
-};
-
-
-#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2
-
-/*
- * TX meta data - stored in skb->cb buffer, so this must not be increased over
- * the 48-byte limit.
- * THE PADDING THIS STARTS WITH IS A HORRIBLE HACK THAT SHOULD NOT LIVE
- * TO SEE THE DAY.
- */
-struct hostap_skb_tx_data {
- unsigned int __padding_for_default_qdiscs;
- u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */
- u8 rate; /* transmit rate */
-#define HOSTAP_TX_FLAGS_WDS BIT(0)
-#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1)
-#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2)
- u8 flags; /* HOSTAP_TX_FLAGS_* */
- u16 tx_cb_idx;
- struct hostap_interface *iface;
- unsigned long jiffies; /* queueing timestamp */
- unsigned short ethertype;
-};
-
-
-#ifndef PRISM2_NO_DEBUG
-
-#define DEBUG_FID BIT(0)
-#define DEBUG_PS BIT(1)
-#define DEBUG_FLOW BIT(2)
-#define DEBUG_AP BIT(3)
-#define DEBUG_HW BIT(4)
-#define DEBUG_EXTRA BIT(5)
-#define DEBUG_EXTRA2 BIT(6)
-#define DEBUG_PS2 BIT(7)
-#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA)
-#define PDEBUG(n, args...) \
-do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0)
-#define PDEBUG2(n, args...) \
-do { if ((n) & DEBUG_MASK) printk(args); } while (0)
-
-#else /* PRISM2_NO_DEBUG */
-
-#define PDEBUG(n, args...)
-#define PDEBUG2(n, args...)
-
-#endif /* PRISM2_NO_DEBUG */
-
-enum { BAP0 = 0, BAP1 = 1 };
-
-#define PRISM2_IO_DEBUG_CMD_INB 0
-#define PRISM2_IO_DEBUG_CMD_INW 1
-#define PRISM2_IO_DEBUG_CMD_INSW 2
-#define PRISM2_IO_DEBUG_CMD_OUTB 3
-#define PRISM2_IO_DEBUG_CMD_OUTW 4
-#define PRISM2_IO_DEBUG_CMD_OUTSW 5
-#define PRISM2_IO_DEBUG_CMD_ERROR 6
-#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7
-
-#ifdef PRISM2_IO_DEBUG
-
-#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \
-(((cmd) << 24) | ((reg) << 16) | value)
-
-static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
- int reg, int value)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
-
- if (!local->io_debug_enabled)
- return;
-
- local->io_debug[local->io_debug_head] = jiffies & 0xffffffff;
- if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
- local->io_debug_head = 0;
- local->io_debug[local->io_debug_head] =
- PRISM2_IO_DEBUG_ENTRY(cmd, reg, value);
- if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
- local->io_debug_head = 0;
-}
-
-
-static inline void prism2_io_debug_error(struct net_device *dev, int err)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- unsigned long flags;
-
- if (!local->io_debug_enabled)
- return;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err);
- if (local->io_debug_enabled == 1) {
- local->io_debug_enabled = 0;
- printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name);
- }
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-#else /* PRISM2_IO_DEBUG */
-
-static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
- int reg, int value)
-{
-}
-
-static inline void prism2_io_debug_error(struct net_device *dev, int err)
-{
-}
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-#ifdef PRISM2_CALLBACK
-enum {
- /* Called when card is enabled */
- PRISM2_CALLBACK_ENABLE,
-
- /* Called when card is disabled */
- PRISM2_CALLBACK_DISABLE,
-
- /* Called when RX/TX starts/ends */
- PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END,
- PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END
-};
-void prism2_callback(local_info_t *local, int event);
-#else /* PRISM2_CALLBACK */
-#define prism2_callback(d, e) do { } while (0)
-#endif /* PRISM2_CALLBACK */
-
-#endif /* __KERNEL__ */
-
-#endif /* HOSTAP_WLAN_H */
diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig
deleted file mode 100644
index f62730aa7be3..000000000000
--- a/drivers/net/wireless/intersil/orinoco/Kconfig
+++ /dev/null
@@ -1,143 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config HERMES
- tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
- depends on (PPC_PMAC || PCI || PCMCIA)
- depends on CFG80211
- select CFG80211_WEXT_EXPORT
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- help
- A driver for 802.11b wireless cards based on the "Hermes" or
- Intersil HFA384x (Prism 2) MAC controller. This includes the vast
- majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
- - except for the Cisco/Aironet cards. Cards supported include the
- Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco,
- Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
- IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
- MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
- IPW2011, and Symbol Spectrum24 High Rate amongst others.
-
- This option includes the guts of the driver, but in order to
- actually use a card you will also need to enable support for PCMCIA
- Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below.
-
- You will also very likely also need the Wireless Tools in order to
- configure your card and that /etc/pcmcia/wireless.opts works :
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
-
-config HERMES_PRISM
- bool "Support Prism 2/2.5 chipset"
- depends on HERMES
- help
-
- Say Y to enable support for Prism 2 and 2.5 chipsets. These
- chipsets are better handled by the hostap driver. This driver
- would not support WPA or firmware download for Prism chipset.
-
- If you are not sure, say N.
-
-config HERMES_CACHE_FW_ON_INIT
- bool "Cache Hermes firmware on driver initialisation"
- depends on HERMES
- default y
- help
- Say Y to cache any firmware required by the Hermes drivers
- on startup. The firmware will remain cached until the
- driver is unloaded. The cache uses 64K of RAM.
-
- Otherwise load the firmware from userspace as required. In
- this case the driver should be unloaded and restarted
- whenever the firmware is changed.
-
- If you are not sure, say Y.
-
-config APPLE_AIRPORT
- tristate "Apple Airport support (built-in)"
- depends on PPC_PMAC && HERMES
- help
- Say Y here to support the Airport 802.11b wireless Ethernet hardware
- built into the Macintosh iBook and other recent PowerPC-based
- Macintosh machines. This is essentially a Lucent Orinoco card with
- a non-standard interface.
-
- This driver does not support the Airport Extreme (802.11b/g). Use
- the BCM43xx driver for Airport Extreme cards.
-
-config PLX_HERMES
- tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
- depends on PCI && HERMES
- help
- Enable support for PCMCIA cards supported by the "Hermes" (aka
- orinoco) driver when used in PLX9052 based PCI adaptors. These
- adaptors are not a full PCMCIA controller but act as a more limited
- PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
- 802.11b PCMCIA cards can be used in desktop machines. The Netgear
- MA301 is such an adaptor.
-
-config TMD_HERMES
- tristate "Hermes in TMD7160 based PCI adaptor support"
- depends on PCI && HERMES
- help
- Enable support for PCMCIA cards supported by the "Hermes" (aka
- orinoco) driver when used in TMD7160 based PCI adaptors. These
- adaptors are not a full PCMCIA controller but act as a more limited
- PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
- 802.11b PCMCIA cards can be used in desktop machines.
-
-config NORTEL_HERMES
- tristate "Nortel emobility PCI adaptor support"
- depends on PCI && HERMES
- help
- Enable support for PCMCIA cards supported by the "Hermes" (aka
- orinoco) driver when used in Nortel emobility PCI adaptors. These
- adaptors are not full PCMCIA controllers, but act as a more limited
- PCI <-> PCMCIA bridge.
-
-config PCI_HERMES
- tristate "Prism 2.5 PCI 802.11b adaptor support"
- depends on PCI && HERMES && HERMES_PRISM
- help
- Enable support for PCI and mini-PCI 802.11b wireless NICs based on
- the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
- PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also
- common. Some of the built-in wireless adaptors in laptops are of
- this variety.
-
-config PCMCIA_HERMES
- tristate "Hermes PCMCIA card support"
- depends on PCMCIA && HERMES && HAS_IOPORT_MAP
- help
- A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and
- others). It should also be usable on various Prism II based cards
- such as the Linksys, D-Link and Farallon Skyline. It should also
- work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
-
- You will very likely need the Wireless Tools in order to
- configure your card and that /etc/pcmcia/wireless.opts works:
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
-config PCMCIA_SPECTRUM
- tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
- depends on PCMCIA && HERMES && HAS_IOPORT_MAP
- help
-
- This is a driver for 802.11b cards using RAM-loadable Symbol
- firmware, such as Symbol Wireless Networker LA4100, CompactFlash
- cards by Socket Communications and Intel PRO/Wireless 2011B.
-
- This driver requires firmware download on startup. Utilities
- for downloading Symbol firmware are available at
- <http://sourceforge.net/projects/orinoco/>
-
-config ORINOCO_USB
- tristate "Agere Orinoco USB support"
- depends on USB && HERMES
- select FW_LOADER
- help
- This driver is for USB versions of the Agere Orinoco card.
diff --git a/drivers/net/wireless/intersil/orinoco/Makefile b/drivers/net/wireless/intersil/orinoco/Makefile
deleted file mode 100644
index 0c29c56c88d6..000000000000
--- a/drivers/net/wireless/intersil/orinoco/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the orinoco wireless device drivers.
-#
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
-
-obj-$(CONFIG_HERMES) += orinoco.o
-obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
-obj-$(CONFIG_APPLE_AIRPORT) += airport.o
-obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
-obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
-obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
-obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
-obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
-obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o
diff --git a/drivers/net/wireless/intersil/orinoco/airport.c b/drivers/net/wireless/intersil/orinoco/airport.c
deleted file mode 100644
index 45ac00fdafa5..000000000000
--- a/drivers/net/wireless/intersil/orinoco/airport.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* airport.c
- *
- * A driver for "Hermes" chipset based Apple Airport wireless
- * card.
- *
- * Copyright notice & release notes in file main.c
- *
- * Note specific to airport stub:
- *
- * 0.05 : first version of the new split driver
- * 0.06 : fix possible hang on powerup, add sleep support
- */
-
-#define DRIVER_NAME "airport"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
-#include <asm/pmac_feature.h>
-
-#include "orinoco.h"
-
-#define AIRPORT_IO_LEN (0x1000) /* one page */
-
-struct airport {
- struct macio_dev *mdev;
- void __iomem *vaddr;
- unsigned int irq;
- int irq_requested;
- int ndev_registered;
-};
-
-static int
-airport_suspend(struct macio_dev *mdev, pm_message_t state)
-{
- struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
- struct net_device *dev = priv->ndev;
- struct airport *card = priv->card;
- unsigned long flags;
- int err;
-
- printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
- dev->name);
- return 0;
- }
-
- orinoco_down(priv);
- orinoco_unlock(priv, &flags);
-
- disable_irq(card->irq);
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 0);
-
- return 0;
-}
-
-static int
-airport_resume(struct macio_dev *mdev)
-{
- struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
- struct net_device *dev = priv->ndev;
- struct airport *card = priv->card;
- unsigned long flags;
- int err;
-
- printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
-
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 1);
- msleep(200);
-
- enable_irq(card->irq);
-
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- err = orinoco_up(priv);
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- return err;
-}
-
-static int
-airport_detach(struct macio_dev *mdev)
-{
- struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
- struct airport *card = priv->card;
-
- if (card->ndev_registered)
- orinoco_if_del(priv);
- card->ndev_registered = 0;
-
- if (card->irq_requested)
- free_irq(card->irq, priv);
- card->irq_requested = 0;
-
- if (card->vaddr)
- iounmap(card->vaddr);
- card->vaddr = NULL;
-
- macio_release_resource(mdev, 0);
-
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 0);
- ssleep(1);
-
- macio_set_drvdata(mdev, NULL);
- free_orinocodev(priv);
-
- return 0;
-}
-
-static int airport_hard_reset(struct orinoco_private *priv)
-{
- /* It would be nice to power cycle the Airport for a real hard
- * reset, but for some reason although it appears to
- * re-initialize properly, it falls in a screaming heap
- * shortly afterwards. */
-#if 0
- struct airport *card = priv->card;
-
- /* Vitally important. If we don't do this it seems we get an
- * interrupt somewhere during the power cycle, since
- * hw_unavailable is already set it doesn't get ACKed, we get
- * into an interrupt loop and the PMU decides to turn us
- * off. */
- disable_irq(card->irq);
-
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(card->mdev), 0, 0);
- ssleep(1);
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(card->mdev), 0, 1);
- ssleep(1);
-
- enable_irq(card->irq);
- ssleep(1);
-#endif
-
- return 0;
-}
-
-static int
-airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
-{
- struct orinoco_private *priv;
- struct airport *card;
- unsigned long phys_addr;
- struct hermes *hw;
-
- if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
- printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
- return -ENODEV;
- }
-
- /* Allocate space for private device-specific data */
- priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
- airport_hard_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- return -ENODEV;
- }
- card = priv->card;
-
- hw = &priv->hw;
- card->mdev = mdev;
-
- if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
- printk(KERN_ERR PFX "can't request IO resource !\n");
- free_orinocodev(priv);
- return -EBUSY;
- }
-
- macio_set_drvdata(mdev, priv);
-
- /* Setup interrupts & base address */
- card->irq = macio_irq(mdev, 0);
- phys_addr = macio_resource_start(mdev, 0); /* Physical address */
- printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
- card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
- if (!card->vaddr) {
- printk(KERN_ERR PFX "ioremap() failed\n");
- goto failed;
- }
-
- hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
-
- /* Power up card */
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 1);
- ssleep(1);
-
- /* Reset it before we get the interrupt */
- hw->ops->init(hw);
-
- if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
- printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
- goto failed;
- }
- card->irq_requested = 1;
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto failed;
- }
-
- /* Register an interface with the stack */
- if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto failed;
- }
- card->ndev_registered = 1;
- return 0;
- failed:
- airport_detach(mdev);
- return -ENODEV;
-} /* airport_attach */
-
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
-MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
-MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static const struct of_device_id airport_match[] = {
- {
- .name = "radio",
- },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, airport_match);
-
-static struct macio_driver airport_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = airport_match,
- },
- .probe = airport_attach,
- .remove = airport_detach,
- .suspend = airport_suspend,
- .resume = airport_resume,
-};
-
-static int __init
-init_airport(void)
-{
- printk(KERN_DEBUG "%s\n", version);
-
- return macio_register_driver(&airport_driver);
-}
-
-static void __exit
-exit_airport(void)
-{
- macio_unregister_driver(&airport_driver);
-}
-
-module_init(init_airport);
-module_exit(exit_airport);
diff --git a/drivers/net/wireless/intersil/orinoco/cfg.c b/drivers/net/wireless/intersil/orinoco/cfg.c
deleted file mode 100644
index b2d5ec8634b5..000000000000
--- a/drivers/net/wireless/intersil/orinoco/cfg.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/* cfg80211 support
- *
- * See copyright notice in main.c
- */
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-#include "hw.h"
-#include "main.h"
-#include "orinoco.h"
-
-#include "cfg.h"
-
-/* Supported bitrates. Must agree with hw.c */
-static struct ieee80211_rate orinoco_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20 },
- { .bitrate = 55 },
- { .bitrate = 110 },
-};
-
-static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
-
-/* Called after orinoco_private is allocated. */
-void orinoco_wiphy_init(struct wiphy *wiphy)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
-
- wiphy->privid = orinoco_wiphy_privid;
-
- set_wiphy_dev(wiphy, priv->dev);
-}
-
-/* Called after firmware is initialised */
-int orinoco_wiphy_register(struct wiphy *wiphy)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int i, channels = 0;
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- wiphy->max_scan_ssids = 1;
- else
- wiphy->max_scan_ssids = 0;
-
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
-
- /* TODO: should we set if we only have demo ad-hoc?
- * (priv->has_port3)
- */
- if (priv->has_ibss)
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
-
- if (!priv->broken_monitor || force_monitor)
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
-
- priv->band.bitrates = orinoco_rates;
- priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
-
- /* Only support channels allowed by the card EEPROM */
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (priv->channel_mask & (1 << i)) {
- priv->channels[i].center_freq =
- ieee80211_channel_to_frequency(i + 1,
- NL80211_BAND_2GHZ);
- channels++;
- }
- }
- priv->band.channels = priv->channels;
- priv->band.n_channels = channels;
-
- wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
- i = 0;
- if (priv->has_wep) {
- priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
- i++;
-
- if (priv->has_big_wep) {
- priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
- i++;
- }
- }
- if (priv->has_wpa) {
- priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
- i++;
- }
- wiphy->cipher_suites = priv->cipher_suites;
- wiphy->n_cipher_suites = i;
-
- wiphy->rts_threshold = priv->rts_thresh;
- if (!priv->has_mwo)
- wiphy->frag_threshold = priv->frag_thresh + 1;
- wiphy->retry_short = priv->short_retry_limit;
- wiphy->retry_long = priv->long_retry_limit;
-
- return wiphy_register(wiphy);
-}
-
-static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
- enum nl80211_iftype type,
- struct vif_params *params)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int err = 0;
- unsigned long lock;
-
- if (orinoco_lock(priv, &lock) != 0)
- return -EBUSY;
-
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
- if (!priv->has_ibss && !priv->has_port3)
- err = -EINVAL;
- break;
-
- case NL80211_IFTYPE_STATION:
- break;
-
- case NL80211_IFTYPE_MONITOR:
- if (priv->broken_monitor && !force_monitor) {
- wiphy_warn(wiphy,
- "Monitor mode support is buggy in this firmware, not enabling\n");
- err = -EINVAL;
- }
- break;
-
- default:
- err = -EINVAL;
- }
-
- if (!err) {
- priv->iw_mode = type;
- set_port_type(priv);
- err = orinoco_commit(priv);
- }
-
- orinoco_unlock(priv, &lock);
-
- return err;
-}
-
-static int orinoco_scan(struct wiphy *wiphy,
- struct cfg80211_scan_request *request)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int err;
-
- if (!request)
- return -EINVAL;
-
- if (priv->scan_request && priv->scan_request != request)
- return -EBUSY;
-
- priv->scan_request = request;
-
- err = orinoco_hw_trigger_scan(priv, request->ssids);
- /* On error the we aren't processing the request */
- if (err)
- priv->scan_request = NULL;
-
- return err;
-}
-
-static int orinoco_set_monitor_channel(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int err = 0;
- unsigned long flags;
- int channel;
-
- if (!chandef->chan)
- return -EINVAL;
-
- if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
- return -EINVAL;
-
- if (chandef->chan->band != NL80211_BAND_2GHZ)
- return -EINVAL;
-
- channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
-
- if ((channel < 1) || (channel > NUM_CHANNELS) ||
- !(priv->channel_mask & (1 << (channel - 1))))
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- priv->channel = channel;
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- /* Fast channel change - no commit if successful */
- struct hermes *hw = &priv->hw;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_SET_CHANNEL,
- channel, NULL);
- }
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int frag_value = -1;
- int rts_value = -1;
- int err = 0;
-
- if (changed & WIPHY_PARAM_RETRY_SHORT) {
- /* Setting short retry not supported */
- err = -EINVAL;
- }
-
- if (changed & WIPHY_PARAM_RETRY_LONG) {
- /* Setting long retry not supported */
- err = -EINVAL;
- }
-
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
- /* Set fragmentation */
- if (priv->has_mwo) {
- if (wiphy->frag_threshold == -1)
- frag_value = 0;
- else {
- printk(KERN_WARNING "%s: Fixed fragmentation "
- "is not supported on this firmware. "
- "Using MWO robust instead.\n",
- priv->ndev->name);
- frag_value = 1;
- }
- } else {
- if (wiphy->frag_threshold == -1)
- frag_value = 2346;
- else if ((wiphy->frag_threshold < 257) ||
- (wiphy->frag_threshold > 2347))
- err = -EINVAL;
- else
- /* cfg80211 value is 257-2347 (odd only)
- * orinoco rid has range 256-2346 (even only) */
- frag_value = wiphy->frag_threshold & ~0x1;
- }
- }
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- /* Set RTS.
- *
- * Prism documentation suggests default of 2432,
- * and a range of 0-3000.
- *
- * Current implementation uses 2347 as the default and
- * the upper limit.
- */
-
- if (wiphy->rts_threshold == -1)
- rts_value = 2347;
- else if (wiphy->rts_threshold > 2347)
- err = -EINVAL;
- else
- rts_value = wiphy->rts_threshold;
- }
-
- if (!err) {
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (frag_value >= 0) {
- if (priv->has_mwo)
- priv->mwo_robust = frag_value;
- else
- priv->frag_thresh = frag_value;
- }
- if (rts_value >= 0)
- priv->rts_thresh = rts_value;
-
- err = orinoco_commit(priv);
-
- orinoco_unlock(priv, &flags);
- }
-
- return err;
-}
-
-const struct cfg80211_ops orinoco_cfg_ops = {
- .change_virtual_intf = orinoco_change_vif,
- .set_monitor_channel = orinoco_set_monitor_channel,
- .scan = orinoco_scan,
- .set_wiphy_params = orinoco_set_wiphy_params,
-};
diff --git a/drivers/net/wireless/intersil/orinoco/cfg.h b/drivers/net/wireless/intersil/orinoco/cfg.h
deleted file mode 100644
index 3ddc96a06cd7..000000000000
--- a/drivers/net/wireless/intersil/orinoco/cfg.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* cfg80211 support.
- *
- * See copyright notice in main.c
- */
-#ifndef ORINOCO_CFG_H
-#define ORINOCO_CFG_H
-
-#include <net/cfg80211.h>
-
-extern const struct cfg80211_ops orinoco_cfg_ops;
-
-void orinoco_wiphy_init(struct wiphy *wiphy);
-int orinoco_wiphy_register(struct wiphy *wiphy);
-
-#endif /* ORINOCO_CFG_H */
diff --git a/drivers/net/wireless/intersil/orinoco/fw.c b/drivers/net/wireless/intersil/orinoco/fw.c
deleted file mode 100644
index 015af782881b..000000000000
--- a/drivers/net/wireless/intersil/orinoco/fw.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* Firmware file reading and download helpers
- *
- * See copyright notice in main.c
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/device.h>
-#include <linux/module.h>
-
-#include "hermes.h"
-#include "hermes_dld.h"
-#include "orinoco.h"
-
-#include "fw.h"
-
-/* End markers (for Symbol firmware only) */
-#define TEXT_END 0x1A /* End of text header */
-
-struct fw_info {
- char *pri_fw;
- char *sta_fw;
- char *ap_fw;
- u32 pda_addr;
- u16 pda_size;
-};
-
-static const struct fw_info orinoco_fw[] = {
- { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
- { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
- { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
-};
-MODULE_FIRMWARE("agere_sta_fw.bin");
-MODULE_FIRMWARE("agere_ap_fw.bin");
-MODULE_FIRMWARE("prism_sta_fw.bin");
-MODULE_FIRMWARE("prism_ap_fw.bin");
-MODULE_FIRMWARE("symbol_sp24t_prim_fw");
-MODULE_FIRMWARE("symbol_sp24t_sec_fw");
-
-/* Structure used to access fields in FW
- * Make sure LE decoding macros are used
- */
-struct orinoco_fw_header {
- char hdr_vers[6]; /* ASCII string for header version */
- __le16 headersize; /* Total length of header */
- __le32 entry_point; /* NIC entry point */
- __le32 blocks; /* Number of blocks to program */
- __le32 block_offset; /* Offset of block data from eof header */
- __le32 pdr_offset; /* Offset to PDR data from eof header */
- __le32 pri_offset; /* Offset to primary plug data */
- __le32 compat_offset; /* Offset to compatibility data*/
- char signature[]; /* FW signature length headersize-20 */
-} __packed;
-
-/* Check the range of various header entries. Return a pointer to a
- * description of the problem, or NULL if everything checks out. */
-static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len)
-{
- u16 hdrsize;
-
- if (len < sizeof(*hdr))
- return "image too small";
- if (memcmp(hdr->hdr_vers, "HFW", 3) != 0)
- return "format not recognised";
-
- hdrsize = le16_to_cpu(hdr->headersize);
- if (hdrsize > len)
- return "bad headersize";
- if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len)
- return "bad block offset";
- if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len)
- return "bad PDR offset";
- if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len)
- return "bad PRI offset";
- if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len)
- return "bad compat offset";
-
- /* TODO: consider adding a checksum or CRC to the firmware format */
- return NULL;
-}
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-static inline const struct firmware *
-orinoco_cached_fw_get(struct orinoco_private *priv, bool primary)
-{
- if (primary)
- return priv->cached_pri_fw;
- else
- return priv->cached_fw;
-}
-#else
-#define orinoco_cached_fw_get(priv, primary) (NULL)
-#endif
-
-/* Download either STA or AP firmware into the card. */
-static int
-orinoco_dl_firmware(struct orinoco_private *priv,
- const struct fw_info *fw,
- int ap)
-{
- /* Plug Data Area (PDA) */
- __le16 *pda;
-
- struct hermes *hw = &priv->hw;
- const struct firmware *fw_entry;
- const struct orinoco_fw_header *hdr;
- const unsigned char *first_block;
- const void *end;
- const char *firmware;
- const char *fw_err;
- struct device *dev = priv->dev;
- int err = 0;
-
- pda = kzalloc(fw->pda_size, GFP_KERNEL);
- if (!pda)
- return -ENOMEM;
-
- if (ap)
- firmware = fw->ap_fw;
- else
- firmware = fw->sta_fw;
-
- dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
-
- /* Read current plug data */
- err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
- dev_dbg(dev, "Read PDA returned %d\n", err);
- if (err)
- goto free;
-
- if (!orinoco_cached_fw_get(priv, false)) {
- err = request_firmware(&fw_entry, firmware, priv->dev);
-
- if (err) {
- dev_err(dev, "Cannot find firmware %s\n", firmware);
- err = -ENOENT;
- goto free;
- }
- } else
- fw_entry = orinoco_cached_fw_get(priv, false);
-
- hdr = (const struct orinoco_fw_header *) fw_entry->data;
-
- fw_err = validate_fw(hdr, fw_entry->size);
- if (fw_err) {
- dev_warn(dev, "Invalid firmware image detected (%s). "
- "Aborting download\n", fw_err);
- err = -EINVAL;
- goto abort;
- }
-
- /* Enable aux port to allow programming */
- err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
- dev_dbg(dev, "Program init returned %d\n", err);
- if (err != 0)
- goto abort;
-
- /* Program data */
- first_block = (fw_entry->data +
- le16_to_cpu(hdr->headersize) +
- le32_to_cpu(hdr->block_offset));
- end = fw_entry->data + fw_entry->size;
-
- err = hermes_program(hw, first_block, end);
- dev_dbg(dev, "Program returned %d\n", err);
- if (err != 0)
- goto abort;
-
- /* Update production data */
- first_block = (fw_entry->data +
- le16_to_cpu(hdr->headersize) +
- le32_to_cpu(hdr->pdr_offset));
-
- err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
- &pda[fw->pda_size / sizeof(*pda)]);
- dev_dbg(dev, "Apply PDA returned %d\n", err);
- if (err)
- goto abort;
-
- /* Tell card we've finished */
- err = hw->ops->program_end(hw);
- dev_dbg(dev, "Program end returned %d\n", err);
- if (err != 0)
- goto abort;
-
- /* Check if we're running */
- dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
-
-abort:
- /* If we requested the firmware, release it. */
- if (!orinoco_cached_fw_get(priv, false))
- release_firmware(fw_entry);
-
-free:
- kfree(pda);
- return err;
-}
-
-/*
- * Process a firmware image - stop the card, load the firmware, reset
- * the card and make sure it responds. For the secondary firmware take
- * care of the PDA - read it and then write it on top of the firmware.
- */
-static int
-symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
- const unsigned char *image, const void *end,
- int secondary)
-{
- struct hermes *hw = &priv->hw;
- int ret = 0;
- const unsigned char *ptr;
- const unsigned char *first_block;
-
- /* Plug Data Area (PDA) */
- __le16 *pda = NULL;
-
- /* Binary block begins after the 0x1A marker */
- ptr = image;
- while (*ptr++ != TEXT_END);
- first_block = ptr;
-
- /* Read the PDA from EEPROM */
- if (secondary) {
- pda = kzalloc(fw->pda_size, GFP_KERNEL);
- if (!pda)
- return -ENOMEM;
-
- ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
- if (ret)
- goto free;
- }
-
- /* Stop the firmware, so that it can be safely rewritten */
- if (priv->stop_fw) {
- ret = priv->stop_fw(priv, 1);
- if (ret)
- goto free;
- }
-
- /* Program the adapter with new firmware */
- ret = hermes_program(hw, first_block, end);
- if (ret)
- goto free;
-
- /* Write the PDA to the adapter */
- if (secondary) {
- size_t len = hermes_blocks_length(first_block, end);
- ptr = first_block + len;
- ret = hermes_apply_pda(hw, ptr, end, pda,
- &pda[fw->pda_size / sizeof(*pda)]);
- kfree(pda);
- if (ret)
- return ret;
- }
-
- /* Run the firmware */
- if (priv->stop_fw) {
- ret = priv->stop_fw(priv, 0);
- if (ret)
- return ret;
- }
-
- /* Reset hermes chip and make sure it responds */
- ret = hw->ops->init(hw);
-
- /* hermes_reset() should return 0 with the secondary firmware */
- if (secondary && ret != 0)
- return -ENODEV;
-
- /* And this should work with any firmware */
- if (!hermes_present(hw))
- return -ENODEV;
-
- return 0;
-
-free:
- kfree(pda);
- return ret;
-}
-
-
-/*
- * Download the firmware into the card, this also does a PCMCIA soft
- * reset on the card, to make sure it's in a sane state.
- */
-static int
-symbol_dl_firmware(struct orinoco_private *priv,
- const struct fw_info *fw)
-{
- struct device *dev = priv->dev;
- int ret;
- const struct firmware *fw_entry;
-
- if (!orinoco_cached_fw_get(priv, true)) {
- if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
- dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
- return -ENOENT;
- }
- } else
- fw_entry = orinoco_cached_fw_get(priv, true);
-
- /* Load primary firmware */
- ret = symbol_dl_image(priv, fw, fw_entry->data,
- fw_entry->data + fw_entry->size, 0);
-
- if (!orinoco_cached_fw_get(priv, true))
- release_firmware(fw_entry);
- if (ret) {
- dev_err(dev, "Primary firmware download failed\n");
- return ret;
- }
-
- if (!orinoco_cached_fw_get(priv, false)) {
- if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
- dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
- return -ENOENT;
- }
- } else
- fw_entry = orinoco_cached_fw_get(priv, false);
-
- /* Load secondary firmware */
- ret = symbol_dl_image(priv, fw, fw_entry->data,
- fw_entry->data + fw_entry->size, 1);
- if (!orinoco_cached_fw_get(priv, false))
- release_firmware(fw_entry);
- if (ret)
- dev_err(dev, "Secondary firmware download failed\n");
-
- return ret;
-}
-
-int orinoco_download(struct orinoco_private *priv)
-{
- int err = 0;
- /* Reload firmware */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* case FIRMWARE_TYPE_INTERSIL: */
- err = orinoco_dl_firmware(priv,
- &orinoco_fw[priv->firmware_type], 0);
- break;
-
- case FIRMWARE_TYPE_SYMBOL:
- err = symbol_dl_firmware(priv,
- &orinoco_fw[priv->firmware_type]);
- break;
- case FIRMWARE_TYPE_INTERSIL:
- break;
- }
- /* TODO: if we fail we probably need to reinitialise
- * the driver */
-
- return err;
-}
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-void orinoco_cache_fw(struct orinoco_private *priv, int ap)
-{
- const struct firmware *fw_entry = NULL;
- const char *pri_fw;
- const char *fw;
-
- pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
- if (ap)
- fw = orinoco_fw[priv->firmware_type].ap_fw;
- else
- fw = orinoco_fw[priv->firmware_type].sta_fw;
-
- if (pri_fw) {
- if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
- priv->cached_pri_fw = fw_entry;
- }
-
- if (fw) {
- if (request_firmware(&fw_entry, fw, priv->dev) == 0)
- priv->cached_fw = fw_entry;
- }
-}
-
-void orinoco_uncache_fw(struct orinoco_private *priv)
-{
- release_firmware(priv->cached_pri_fw);
- release_firmware(priv->cached_fw);
- priv->cached_pri_fw = NULL;
- priv->cached_fw = NULL;
-}
-#endif
diff --git a/drivers/net/wireless/intersil/orinoco/fw.h b/drivers/net/wireless/intersil/orinoco/fw.h
deleted file mode 100644
index aca63e3c4b5b..000000000000
--- a/drivers/net/wireless/intersil/orinoco/fw.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Firmware file reading and download helpers
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_FW_H_
-#define _ORINOCO_FW_H_
-
-/* Forward declations */
-struct orinoco_private;
-
-int orinoco_download(struct orinoco_private *priv);
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-void orinoco_cache_fw(struct orinoco_private *priv, int ap);
-void orinoco_uncache_fw(struct orinoco_private *priv);
-#else
-#define orinoco_cache_fw(priv, ap) do { } while (0)
-#define orinoco_uncache_fw(priv) do { } while (0)
-#endif
-
-#endif /* _ORINOCO_FW_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/hermes.c b/drivers/net/wireless/intersil/orinoco/hermes.c
deleted file mode 100644
index 4888286727ff..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/* hermes.c
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
- * particular order).
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia.
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#include <linux/net.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-
-#include "hermes.h"
-
-/* These are maximum timeouts. Most often, card wil react much faster */
-#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
-#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
-#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
-#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
-
-/*
- * AUX port access. To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register. Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
-#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
-
-/*
- * Debugging helpers
- */
-
-#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
- printk(stuff); } while (0)
-
-#undef HERMES_DEBUG
-#ifdef HERMES_DEBUG
-
-#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
-
-#else /* ! HERMES_DEBUG */
-
-#define DEBUG(lvl, stuff...) do { } while (0)
-
-#endif /* ! HERMES_DEBUG */
-
-static const struct hermes_ops hermes_ops_local;
-
-/*
- * Internal functions
- */
-
-/* Issue a command to the chip. Waiting for it to complete is the caller's
- problem.
-
- Returns -EBUSY if the command register is busy, 0 on success.
-
- Callable from any context.
-*/
-static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
- u16 param1, u16 param2)
-{
- int k = CMD_BUSY_TIMEOUT;
- u16 reg;
-
- /* First wait for the command register to unbusy */
- reg = hermes_read_regn(hw, CMD);
- while ((reg & HERMES_CMD_BUSY) && k) {
- k--;
- udelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
- if (reg & HERMES_CMD_BUSY)
- return -EBUSY;
-
- hermes_write_regn(hw, PARAM2, param2);
- hermes_write_regn(hw, PARAM1, param1);
- hermes_write_regn(hw, PARAM0, param0);
- hermes_write_regn(hw, CMD, cmd);
-
- return 0;
-}
-
-/*
- * Function definitions
- */
-
-/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
-static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
- u16 parm0, u16 parm1, u16 parm2,
- struct hermes_response *resp)
-{
- int err = 0;
- int k;
- u16 status, reg;
-
- err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
- if (err)
- return err;
-
- reg = hermes_read_regn(hw, EVSTAT);
- k = CMD_INIT_TIMEOUT;
- while ((!(reg & HERMES_EV_CMD)) && k) {
- k--;
- udelay(10);
- reg = hermes_read_regn(hw, EVSTAT);
- }
-
- hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
-
- if (!hermes_present(hw)) {
- DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
- hw->iobase);
- err = -ENODEV;
- goto out;
- }
-
- if (!(reg & HERMES_EV_CMD)) {
- printk(KERN_ERR "hermes @ %p: "
- "Timeout waiting for card to reset (reg=0x%04x)!\n",
- hw->iobase, reg);
- err = -ETIMEDOUT;
- goto out;
- }
-
- status = hermes_read_regn(hw, STATUS);
- if (resp) {
- resp->status = status;
- resp->resp0 = hermes_read_regn(hw, RESP0);
- resp->resp1 = hermes_read_regn(hw, RESP1);
- resp->resp2 = hermes_read_regn(hw, RESP2);
- }
-
- hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
- if (status & HERMES_STATUS_RESULT)
- err = -EIO;
-out:
- return err;
-}
-
-void hermes_struct_init(struct hermes *hw, void __iomem *address,
- int reg_spacing)
-{
- hw->iobase = address;
- hw->reg_spacing = reg_spacing;
- hw->inten = 0x0;
- hw->eeprom_pda = false;
- hw->ops = &hermes_ops_local;
-}
-EXPORT_SYMBOL(hermes_struct_init);
-
-static int hermes_init(struct hermes *hw)
-{
- u16 reg;
- int err = 0;
- int k;
-
- /* We don't want to be interrupted while resetting the chipset */
- hw->inten = 0x0;
- hermes_write_regn(hw, INTEN, 0);
- hermes_write_regn(hw, EVACK, 0xffff);
-
- /* Normally it's a "can't happen" for the command register to
- be busy when we go to issue a command because we are
- serializing all commands. However we want to have some
- chance of resetting the card even if it gets into a stupid
- state, so we actually wait to see if the command register
- will unbusy itself here. */
- k = CMD_BUSY_TIMEOUT;
- reg = hermes_read_regn(hw, CMD);
- while (k && (reg & HERMES_CMD_BUSY)) {
- if (reg == 0xffff) /* Special case - the card has probably been
- removed, so don't wait for the timeout */
- return -ENODEV;
-
- k--;
- udelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* No need to explicitly handle the timeout - if we've timed
- out hermes_issue_cmd() will probably return -EBUSY below */
-
- /* According to the documentation, EVSTAT may contain
- obsolete event occurrence information. We have to acknowledge
- it by writing EVACK. */
- reg = hermes_read_regn(hw, EVSTAT);
- hermes_write_regn(hw, EVACK, reg);
-
- /* We don't use hermes_docmd_wait here, because the reset wipes
- the magic constant in SWSUPPORT0 away, and it gets confused */
- err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
-
- return err;
-}
-
-/* Issue a command to the chip, and (busy!) wait for it to
- * complete.
- *
- * Returns:
- * < 0 on internal error
- * 0 on success
- * > 0 on error returned by the firmware
- *
- * Callable from any context, but locking is your problem. */
-static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp)
-{
- int err;
- int k;
- u16 reg;
- u16 status;
-
- err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
- if (err) {
- if (!hermes_present(hw)) {
- if (net_ratelimit())
- printk(KERN_WARNING "hermes @ %p: "
- "Card removed while issuing command "
- "0x%04x.\n", hw->iobase, cmd);
- err = -ENODEV;
- } else
- if (net_ratelimit())
- printk(KERN_ERR "hermes @ %p: "
- "Error %d issuing command 0x%04x.\n",
- hw->iobase, err, cmd);
- goto out;
- }
-
- reg = hermes_read_regn(hw, EVSTAT);
- k = CMD_COMPL_TIMEOUT;
- while ((!(reg & HERMES_EV_CMD)) && k) {
- k--;
- udelay(10);
- reg = hermes_read_regn(hw, EVSTAT);
- }
-
- if (!hermes_present(hw)) {
- printk(KERN_WARNING "hermes @ %p: Card removed "
- "while waiting for command 0x%04x completion.\n",
- hw->iobase, cmd);
- err = -ENODEV;
- goto out;
- }
-
- if (!(reg & HERMES_EV_CMD)) {
- printk(KERN_ERR "hermes @ %p: Timeout waiting for "
- "command 0x%04x completion.\n", hw->iobase, cmd);
- err = -ETIMEDOUT;
- goto out;
- }
-
- status = hermes_read_regn(hw, STATUS);
- if (resp) {
- resp->status = status;
- resp->resp0 = hermes_read_regn(hw, RESP0);
- resp->resp1 = hermes_read_regn(hw, RESP1);
- resp->resp2 = hermes_read_regn(hw, RESP2);
- }
-
- hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
- if (status & HERMES_STATUS_RESULT)
- err = -EIO;
-
- out:
- return err;
-}
-
-static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
-{
- int err = 0;
- int k;
- u16 reg;
-
- if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
- return -EINVAL;
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
- if (err)
- return err;
-
- reg = hermes_read_regn(hw, EVSTAT);
- k = ALLOC_COMPL_TIMEOUT;
- while ((!(reg & HERMES_EV_ALLOC)) && k) {
- k--;
- udelay(10);
- reg = hermes_read_regn(hw, EVSTAT);
- }
-
- if (!hermes_present(hw)) {
- printk(KERN_WARNING "hermes @ %p: "
- "Card removed waiting for frame allocation.\n",
- hw->iobase);
- return -ENODEV;
- }
-
- if (!(reg & HERMES_EV_ALLOC)) {
- printk(KERN_ERR "hermes @ %p: "
- "Timeout waiting for frame allocation\n",
- hw->iobase);
- return -ETIMEDOUT;
- }
-
- *fid = hermes_read_regn(hw, ALLOCFID);
- hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
-
- return 0;
-}
-
-/* Set up a BAP to read a particular chunk of data from card's internal buffer.
- *
- * Returns:
- * < 0 on internal failure (errno)
- * 0 on success
- * > 0 on error
- * from firmware
- *
- * Callable from any context */
-static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
-{
- int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
- int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
- int k;
- u16 reg;
-
- /* Paranoia.. */
- if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
- return -EINVAL;
-
- k = HERMES_BAP_BUSY_TIMEOUT;
- reg = hermes_read_reg(hw, oreg);
- while ((reg & HERMES_OFFSET_BUSY) && k) {
- k--;
- udelay(1);
- reg = hermes_read_reg(hw, oreg);
- }
-
- if (reg & HERMES_OFFSET_BUSY)
- return -ETIMEDOUT;
-
- /* Now we actually set up the transfer */
- hermes_write_reg(hw, sreg, id);
- hermes_write_reg(hw, oreg, offset);
-
- /* Wait for the BAP to be ready */
- k = HERMES_BAP_BUSY_TIMEOUT;
- reg = hermes_read_reg(hw, oreg);
- while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
- k--;
- udelay(1);
- reg = hermes_read_reg(hw, oreg);
- }
-
- if (reg != offset) {
- printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
- "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
- (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
- reg, id, offset);
-
- if (reg & HERMES_OFFSET_BUSY)
- return -ETIMEDOUT;
-
- return -EIO; /* error or wrong offset */
- }
-
- return 0;
-}
-
-/* Read a block of data from the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem. len
- * must be even.
- *
- * Returns:
- * < 0 on internal failure (errno)
- * 0 on success
- * > 0 on error from firmware
- */
-static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
- u16 id, u16 offset)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
-
- if ((len < 0) || (len % 2))
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, id, offset);
- if (err)
- goto out;
-
- /* Actually do the transfer */
- hermes_read_words(hw, dreg, buf, len / 2);
-
- out:
- return err;
-}
-
-/* Write a block of data to the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem.
- *
- * Returns:
- * < 0 on internal failure (errno)
- * 0 on success
- * > 0 on error from firmware
- */
-static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
- int len, u16 id, u16 offset)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
-
- if (len < 0)
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, id, offset);
- if (err)
- goto out;
-
- /* Actually do the transfer */
- hermes_write_bytes(hw, dreg, buf, len);
-
- out:
- return err;
-}
-
-/* Read a Length-Type-Value record from the card.
- *
- * If length is NULL, we ignore the length read from the card, and
- * read the entire buffer regardless. This is useful because some of
- * the configuration records appear to have incorrect lengths in
- * practice.
- *
- * Callable from user or bh context. */
-static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf)
-{
- int err = 0;
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- u16 rlength, rtype;
- unsigned nwords;
-
- if (bufsize % 2)
- return -EINVAL;
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
- if (err)
- return err;
-
- err = hermes_bap_seek(hw, bap, rid, 0);
- if (err)
- return err;
-
- rlength = hermes_read_reg(hw, dreg);
-
- if (!rlength)
- return -ENODATA;
-
- rtype = hermes_read_reg(hw, dreg);
-
- if (length)
- *length = rlength;
-
- if (rtype != rid)
- printk(KERN_WARNING "hermes @ %p: %s(): "
- "rid (0x%04x) does not match type (0x%04x)\n",
- hw->iobase, __func__, rid, rtype);
- if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
- printk(KERN_WARNING "hermes @ %p: "
- "Truncating LTV record from %d to %d bytes. "
- "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
- HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
-
- nwords = min((unsigned)rlength - 1, bufsize / 2);
- hermes_read_words(hw, dreg, buf, nwords);
-
- return 0;
-}
-
-static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *value)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
- unsigned count;
-
- if (length == 0)
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, rid, 0);
- if (err)
- return err;
-
- hermes_write_reg(hw, dreg, length);
- hermes_write_reg(hw, dreg, rid);
-
- count = length - 1;
-
- hermes_write_bytes(hw, dreg, value, count << 1);
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
- rid, NULL);
-
- return err;
-}
-
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(struct hermes *hw, u32 addr)
-{
- hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
- hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(struct hermes *hw, int enabled)
-{
- int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
- int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
- int i;
-
- /* Already open? */
- if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
- return 0;
-
- hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
- hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
- hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
- hermes_write_reg(hw, HERMES_CONTROL, action);
-
- for (i = 0; i < 20; i++) {
- udelay(10);
- if (hermes_read_reg(hw, HERMES_CONTROL) ==
- desired_state)
- return 0;
- }
-
- return -EBUSY;
-}
-
-/*** Hermes programming ***/
-
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-static int hermesi_program_init(struct hermes *hw, u32 offset)
-{
- int err;
-
- /* Disable interrupts?*/
- /*hw->inten = 0x0;*/
- /*hermes_write_regn(hw, INTEN, 0);*/
- /*hermes_set_irqmask(hw, 0);*/
-
- /* Acknowledge any outstanding command */
- hermes_write_regn(hw, EVACK, 0xFFFF);
-
- /* Using init_cmd_wait rather than cmd_wait */
- err = hw->ops->init_cmd_wait(hw,
- 0x0100 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
- if (err)
- return err;
-
- err = hw->ops->init_cmd_wait(hw,
- 0x0000 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
- if (err)
- return err;
-
- err = hermes_aux_control(hw, 1);
- pr_debug("AUX enable returned %d\n", err);
-
- if (err)
- return err;
-
- pr_debug("Enabling volatile, EP 0x%08x\n", offset);
- err = hw->ops->init_cmd_wait(hw,
- HERMES_PROGRAM_ENABLE_VOLATILE,
- offset & 0xFFFFu,
- offset >> 16,
- 0,
- NULL);
- pr_debug("PROGRAM_ENABLE returned %d\n", err);
-
- return err;
-}
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-static int hermesi_program_end(struct hermes *hw)
-{
- struct hermes_response resp;
- int rc = 0;
- int err;
-
- rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
- pr_debug("PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
-
- if ((rc == 0) &&
- ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
- rc = -EIO;
-
- err = hermes_aux_control(hw, 0);
- pr_debug("AUX disable returned %d\n", err);
-
- /* Acknowledge any outstanding command */
- hermes_write_regn(hw, EVACK, 0xFFFF);
-
- /* Reinitialise, ignoring return */
- (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
-
- return rc ? rc : err;
-}
-
-static int hermes_program_bytes(struct hermes *hw, const char *data,
- u32 addr, u32 len)
-{
- /* wl lkm splits the programming into chunks of 2000 bytes.
- * This restriction appears to come from USB. The PCMCIA
- * adapters can program the whole lot in one go */
- hermes_aux_setaddr(hw, addr);
- hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
- return 0;
-}
-
-/* Read PDA from the adapter */
-static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
- u16 pda_len)
-{
- int ret;
- u16 pda_size;
- u16 data_len = pda_len;
- __le16 *data = pda;
-
- if (hw->eeprom_pda) {
- /* PDA of spectrum symbol is in eeprom */
-
- /* Issue command to read EEPROM */
- ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
- if (ret)
- return ret;
- } else {
- /* wl_lkm does not include PDA size in the PDA area.
- * We will pad the information into pda, so other routines
- * don't have to be modified */
- pda[0] = cpu_to_le16(pda_len - 2);
- /* Includes CFG_PROD_DATA but not itself */
- pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
- data_len = pda_len - 4;
- data = pda + 2;
- }
-
- /* Open auxiliary port */
- ret = hermes_aux_control(hw, 1);
- pr_debug("AUX enable returned %d\n", ret);
- if (ret)
- return ret;
-
- /* Read PDA */
- hermes_aux_setaddr(hw, pda_addr);
- hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
- /* Close aux port */
- ret = hermes_aux_control(hw, 0);
- pr_debug("AUX disable returned %d\n", ret);
-
- /* Check PDA length */
- pda_size = le16_to_cpu(pda[0]);
- pr_debug("Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
- if (pda_size > pda_len)
- return -EINVAL;
-
- return 0;
-}
-
-static void hermes_lock_irqsave(spinlock_t *lock,
- unsigned long *flags) __acquires(lock)
-{
- spin_lock_irqsave(lock, *flags);
-}
-
-static void hermes_unlock_irqrestore(spinlock_t *lock,
- unsigned long *flags) __releases(lock)
-{
- spin_unlock_irqrestore(lock, *flags);
-}
-
-static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
-{
- spin_lock_irq(lock);
-}
-
-static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
-{
- spin_unlock_irq(lock);
-}
-
-/* Hermes operations for local buses */
-static const struct hermes_ops hermes_ops_local = {
- .init = hermes_init,
- .cmd_wait = hermes_docmd_wait,
- .init_cmd_wait = hermes_doicmd_wait,
- .allocate = hermes_allocate,
- .read_ltv = hermes_read_ltv,
- .read_ltv_pr = hermes_read_ltv,
- .write_ltv = hermes_write_ltv,
- .bap_pread = hermes_bap_pread,
- .bap_pwrite = hermes_bap_pwrite,
- .read_pda = hermes_read_pda,
- .program_init = hermesi_program_init,
- .program_end = hermesi_program_end,
- .program = hermes_program_bytes,
- .lock_irqsave = hermes_lock_irqsave,
- .unlock_irqrestore = hermes_unlock_irqrestore,
- .lock_irq = hermes_lock_irq,
- .unlock_irq = hermes_unlock_irq,
-};
diff --git a/drivers/net/wireless/intersil/orinoco/hermes.h b/drivers/net/wireless/intersil/orinoco/hermes.h
deleted file mode 100644
index 3dc561a5cb7a..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes.h
+++ /dev/null
@@ -1,534 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* hermes.h
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism I & II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver.
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia.
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- *
- * Portions taken from hfa384x.h.
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- */
-
-#ifndef _HERMES_H
-#define _HERMES_H
-
-/* Notes on locking:
- *
- * As a module of low level hardware access routines, there is no
- * locking. Users of this module should ensure that they serialize
- * access to the hermes structure, and to the hardware
-*/
-
-#include <linux/if_ether.h>
-#include <linux/io.h>
-
-/*
- * Limits and constants
- */
-#define HERMES_ALLOC_LEN_MIN (4)
-#define HERMES_ALLOC_LEN_MAX (2400)
-#define HERMES_LTV_LEN_MAX (34)
-#define HERMES_BAP_DATALEN_MAX (4096)
-#define HERMES_BAP_OFFSET_MAX (4096)
-#define HERMES_PORTID_MAX (7)
-#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX + 1)
-#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */
-#define HERMES_PDA_RECS_MAX (200) /* a guess */
-#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */
-#define HERMES_SCANRESULT_MAX (35)
-#define HERMES_CHINFORESULT_MAX (8)
-#define HERMES_MAX_MULTICAST (16)
-#define HERMES_MAGIC (0x7d1f)
-
-/*
- * Hermes register offsets
- */
-#define HERMES_CMD (0x00)
-#define HERMES_PARAM0 (0x02)
-#define HERMES_PARAM1 (0x04)
-#define HERMES_PARAM2 (0x06)
-#define HERMES_STATUS (0x08)
-#define HERMES_RESP0 (0x0A)
-#define HERMES_RESP1 (0x0C)
-#define HERMES_RESP2 (0x0E)
-#define HERMES_INFOFID (0x10)
-#define HERMES_RXFID (0x20)
-#define HERMES_ALLOCFID (0x22)
-#define HERMES_TXCOMPLFID (0x24)
-#define HERMES_SELECT0 (0x18)
-#define HERMES_OFFSET0 (0x1C)
-#define HERMES_DATA0 (0x36)
-#define HERMES_SELECT1 (0x1A)
-#define HERMES_OFFSET1 (0x1E)
-#define HERMES_DATA1 (0x38)
-#define HERMES_EVSTAT (0x30)
-#define HERMES_INTEN (0x32)
-#define HERMES_EVACK (0x34)
-#define HERMES_CONTROL (0x14)
-#define HERMES_SWSUPPORT0 (0x28)
-#define HERMES_SWSUPPORT1 (0x2A)
-#define HERMES_SWSUPPORT2 (0x2C)
-#define HERMES_AUXPAGE (0x3A)
-#define HERMES_AUXOFFSET (0x3C)
-#define HERMES_AUXDATA (0x3E)
-
-/*
- * CMD register bitmasks
- */
-#define HERMES_CMD_BUSY (0x8000)
-#define HERMES_CMD_AINFO (0x7f00)
-#define HERMES_CMD_MACPORT (0x0700)
-#define HERMES_CMD_RECL (0x0100)
-#define HERMES_CMD_WRITE (0x0100)
-#define HERMES_CMD_PROGMODE (0x0300)
-#define HERMES_CMD_CMDCODE (0x003f)
-
-/*
- * STATUS register bitmasks
- */
-#define HERMES_STATUS_RESULT (0x7f00)
-#define HERMES_STATUS_CMDCODE (0x003f)
-
-/*
- * OFFSET register bitmasks
- */
-#define HERMES_OFFSET_BUSY (0x8000)
-#define HERMES_OFFSET_ERR (0x4000)
-#define HERMES_OFFSET_DATAOFF (0x0ffe)
-
-/*
- * Event register bitmasks (INTEN, EVSTAT, EVACK)
- */
-#define HERMES_EV_TICK (0x8000)
-#define HERMES_EV_WTERR (0x4000)
-#define HERMES_EV_INFDROP (0x2000)
-#define HERMES_EV_INFO (0x0080)
-#define HERMES_EV_DTIM (0x0020)
-#define HERMES_EV_CMD (0x0010)
-#define HERMES_EV_ALLOC (0x0008)
-#define HERMES_EV_TXEXC (0x0004)
-#define HERMES_EV_TX (0x0002)
-#define HERMES_EV_RX (0x0001)
-
-/*
- * Command codes
- */
-/*--- Controller Commands ----------------------------*/
-#define HERMES_CMD_INIT (0x0000)
-#define HERMES_CMD_ENABLE (0x0001)
-#define HERMES_CMD_DISABLE (0x0002)
-#define HERMES_CMD_DIAG (0x0003)
-
-/*--- Buffer Mgmt Commands ---------------------------*/
-#define HERMES_CMD_ALLOC (0x000A)
-#define HERMES_CMD_TX (0x000B)
-
-/*--- Regulate Commands ------------------------------*/
-#define HERMES_CMD_NOTIFY (0x0010)
-#define HERMES_CMD_INQUIRE (0x0011)
-
-/*--- Configure Commands -----------------------------*/
-#define HERMES_CMD_ACCESS (0x0021)
-#define HERMES_CMD_DOWNLD (0x0022)
-
-/*--- Serial I/O Commands ----------------------------*/
-#define HERMES_CMD_READMIF (0x0030)
-#define HERMES_CMD_WRITEMIF (0x0031)
-
-/*--- Debugging Commands -----------------------------*/
-#define HERMES_CMD_TEST (0x0038)
-
-
-/* Test command arguments */
-#define HERMES_TEST_SET_CHANNEL 0x0800
-#define HERMES_TEST_MONITOR 0x0b00
-#define HERMES_TEST_STOP 0x0f00
-
-/* Authentication algorithms */
-#define HERMES_AUTH_OPEN 1
-#define HERMES_AUTH_SHARED_KEY 2
-
-/* WEP settings */
-#define HERMES_WEP_PRIVACY_INVOKED 0x0001
-#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002
-#define HERMES_WEP_HOST_ENCRYPT 0x0010
-#define HERMES_WEP_HOST_DECRYPT 0x0080
-
-/* Symbol hostscan options */
-#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001
-#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002
-#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040
-#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080
-
-/*
- * Frame structures and constants
- */
-
-#define HERMES_DESCRIPTOR_OFFSET 0
-#define HERMES_802_11_OFFSET (14)
-#define HERMES_802_3_OFFSET (14 + 32)
-#define HERMES_802_2_OFFSET (14 + 32 + 14)
-#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2)
-
-#define HERMES_RXSTAT_ERR (0x0003)
-#define HERMES_RXSTAT_BADCRC (0x0001)
-#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002)
-#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */
-#define HERMES_RXSTAT_MACPORT (0x0700)
-#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */
-#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */
-#define HERMES_RXSTAT_MSGTYPE (0xE000)
-#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */
-#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */
-#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */
-
-/* Shift amount for key ID in RXSTAT and TXCTRL */
-#define HERMES_MIC_KEY_ID_SHIFT 11
-
-struct hermes_tx_descriptor {
- __le16 status;
- __le16 reserved1;
- __le16 reserved2;
- __le32 sw_support;
- u8 retry_count;
- u8 tx_rate;
- __le16 tx_control;
-} __packed;
-
-#define HERMES_TXSTAT_RETRYERR (0x0001)
-#define HERMES_TXSTAT_AGEDERR (0x0002)
-#define HERMES_TXSTAT_DISCON (0x0004)
-#define HERMES_TXSTAT_FORMERR (0x0008)
-
-#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */
-#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */
-#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */
-#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */
-#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */
-#define HERMES_TXCTRL_ALT_RTRY (0x0020)
-
-/* Inquiry constants and data types */
-
-#define HERMES_INQ_TALLIES (0xF100)
-#define HERMES_INQ_SCAN (0xF101)
-#define HERMES_INQ_CHANNELINFO (0xF102)
-#define HERMES_INQ_HOSTSCAN (0xF103)
-#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104)
-#define HERMES_INQ_LINKSTATUS (0xF200)
-#define HERMES_INQ_SEC_STAT_AGERE (0xF202)
-
-struct hermes_tallies_frame {
- __le16 TxUnicastFrames;
- __le16 TxMulticastFrames;
- __le16 TxFragments;
- __le16 TxUnicastOctets;
- __le16 TxMulticastOctets;
- __le16 TxDeferredTransmissions;
- __le16 TxSingleRetryFrames;
- __le16 TxMultipleRetryFrames;
- __le16 TxRetryLimitExceeded;
- __le16 TxDiscards;
- __le16 RxUnicastFrames;
- __le16 RxMulticastFrames;
- __le16 RxFragments;
- __le16 RxUnicastOctets;
- __le16 RxMulticastOctets;
- __le16 RxFCSErrors;
- __le16 RxDiscards_NoBuffer;
- __le16 TxDiscardsWrongSA;
- __le16 RxWEPUndecryptable;
- __le16 RxMsgInMsgFragments;
- __le16 RxMsgInBadMsgFragments;
- /* Those last are probably not available in very old firmwares */
- __le16 RxDiscards_WEPICVError;
- __le16 RxDiscards_WEPExcluded;
-} __packed;
-
-/* Grabbed from wlan-ng - Thanks Mark... - Jean II
- * This is the result of a scan inquiry command */
-/* Structure describing info about an Access Point */
-struct prism2_scan_apinfo {
- __le16 channel; /* Channel where the AP sits */
- __le16 noise; /* Noise level */
- __le16 level; /* Signal level */
- u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- __le16 beacon_interv; /* Beacon interval */
- __le16 capabilities; /* Capabilities */
- __le16 essid_len; /* ESSID length */
- u8 essid[32]; /* ESSID of the network */
- u8 rates[10]; /* Bit rate supported */
- __le16 proberesp_rate; /* Data rate of the response frame */
- __le16 atim; /* ATIM window time, Kus (hostscan only) */
-} __packed;
-
-/* Same stuff for the Lucent/Agere card.
- * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
-struct agere_scan_apinfo {
- __le16 channel; /* Channel where the AP sits */
- __le16 noise; /* Noise level */
- __le16 level; /* Signal level */
- u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- __le16 beacon_interv; /* Beacon interval */
- __le16 capabilities; /* Capabilities */
- /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
- __le16 essid_len; /* ESSID length */
- u8 essid[32]; /* ESSID of the network */
-} __packed;
-
-/* Moustafa: Scan structure for Symbol cards */
-struct symbol_scan_apinfo {
- u8 channel; /* Channel where the AP sits */
- u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */
- __le16 noise; /* Noise level */
- __le16 level; /* Signal level */
- u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- __le16 beacon_interv; /* Beacon interval */
- __le16 capabilities; /* Capabilities */
- /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
- __le16 essid_len; /* ESSID length */
- u8 essid[32]; /* ESSID of the network */
- __le16 rates[5]; /* Bit rate supported */
- __le16 basic_rates; /* Basic rates bitmask */
- u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */
- u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */
-} __packed;
-
-union hermes_scan_info {
- struct agere_scan_apinfo a;
- struct prism2_scan_apinfo p;
- struct symbol_scan_apinfo s;
-};
-
-/* Extended scan struct for HERMES_INQ_CHANNELINFO.
- * wl_lkm calls this an ACS scan (Automatic Channel Select).
- * Keep out of union hermes_scan_info because it is much bigger than
- * the older scan structures. */
-struct agere_ext_scan_info {
- __le16 reserved0;
-
- u8 noise;
- u8 level;
- u8 rx_flow;
- u8 rate;
- __le16 reserved1[2];
-
- __le16 frame_control;
- __le16 dur_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- __le16 sequence;
- u8 addr4[ETH_ALEN];
-
- __le16 data_length;
-
- /* Next 3 fields do not get filled in. */
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
- __le16 len_type;
-
- __le64 timestamp;
- __le16 beacon_interval;
- __le16 capabilities;
- u8 data[];
-} __packed;
-
-#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
-#define HERMES_LINKSTATUS_CONNECTED (0x0001)
-#define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
-#define HERMES_LINKSTATUS_AP_CHANGE (0x0003)
-#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
-#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005)
-#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006)
-
-struct hermes_linkstatus {
- __le16 linkstatus; /* Link status */
-} __packed;
-
-struct hermes_response {
- u16 status, resp0, resp1, resp2;
-};
-
-/* "ID" structure - used for ESSID and station nickname */
-struct hermes_idstring {
- __le16 len;
- __le16 val[16];
-} __packed;
-
-struct hermes_multicast {
- u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __packed;
-
-/* Timeouts */
-#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
-
-struct hermes;
-
-/* Functions to access hardware */
-struct hermes_ops {
- int (*init)(struct hermes *hw);
- int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp);
- int (*init_cmd_wait)(struct hermes *hw, u16 cmd,
- u16 parm0, u16 parm1, u16 parm2,
- struct hermes_response *resp);
- int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
- int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
- u16 *length, void *buf);
- int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid,
- unsigned buflen, u16 *length, void *buf);
- int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *value);
- int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
- u16 id, u16 offset);
- int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
- int len, u16 id, u16 offset);
- int (*read_pda)(struct hermes *hw, __le16 *pda,
- u32 pda_addr, u16 pda_len);
- int (*program_init)(struct hermes *hw, u32 entry_point);
- int (*program_end)(struct hermes *hw);
- int (*program)(struct hermes *hw, const char *buf,
- u32 addr, u32 len);
- void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
- void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
- void (*lock_irq)(spinlock_t *lock);
- void (*unlock_irq)(spinlock_t *lock);
-};
-
-/* Basic control structure */
-struct hermes {
- void __iomem *iobase;
- int reg_spacing;
-#define HERMES_16BIT_REGSPACING 0
-#define HERMES_32BIT_REGSPACING 1
- u16 inten; /* Which interrupts should be enabled? */
- bool eeprom_pda;
- const struct hermes_ops *ops;
- void *priv;
-};
-
-/* Register access convenience macros */
-#define hermes_read_reg(hw, off) \
- (ioread16((hw)->iobase + ((off) << (hw)->reg_spacing)))
-#define hermes_write_reg(hw, off, val) \
- (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing)))
-#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
-#define hermes_write_regn(hw, name, val) \
- hermes_write_reg((hw), HERMES_##name, (val))
-
-/* Function prototypes */
-void hermes_struct_init(struct hermes *hw, void __iomem *address,
- int reg_spacing);
-
-/* Inline functions */
-
-static inline int hermes_present(struct hermes *hw)
-{
- return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
-}
-
-static inline void hermes_set_irqmask(struct hermes *hw, u16 events)
-{
- hw->inten = events;
- hermes_write_regn(hw, INTEN, events);
-}
-
-static inline int hermes_enable_port(struct hermes *hw, int port)
-{
- return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
- 0, NULL);
-}
-
-static inline int hermes_disable_port(struct hermes *hw, int port)
-{
- return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
- 0, NULL);
-}
-
-/* Initiate an INQUIRE command (tallies or scan). The result will come as an
- * information frame in __orinoco_ev_info() */
-static inline int hermes_inquire(struct hermes *hw, u16 rid)
-{
- return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
-}
-
-#define HERMES_BYTES_TO_RECLEN(n) ((((n) + 1) / 2) + 1)
-#define HERMES_RECLEN_TO_BYTES(n) (((n) - 1) * 2)
-
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-static inline void hermes_read_words(struct hermes *hw, int off,
- void *buf, unsigned count)
-{
- off = off << hw->reg_spacing;
- ioread16_rep(hw->iobase + off, buf, count);
-}
-
-static inline void hermes_write_bytes(struct hermes *hw, int off,
- const char *buf, unsigned count)
-{
- off = off << hw->reg_spacing;
- iowrite16_rep(hw->iobase + off, buf, count >> 1);
- if (unlikely(count & 1))
- iowrite8(buf[count - 1], hw->iobase + off);
-}
-
-static inline void hermes_clear_words(struct hermes *hw, int off,
- unsigned count)
-{
- unsigned i;
-
- off = off << hw->reg_spacing;
-
- for (i = 0; i < count; i++)
- iowrite16(0, hw->iobase + off);
-}
-
-#define HERMES_READ_RECORD(hw, bap, rid, buf) \
- (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
-#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \
- (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
-#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
- (hw->ops->write_ltv((hw), (bap), (rid), \
- HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
-
-static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid,
- u16 *word)
-{
- __le16 rec;
- int err;
-
- err = HERMES_READ_RECORD(hw, bap, rid, &rec);
- *word = le16_to_cpu(rec);
- return err;
-}
-
-static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid,
- u16 *word)
-{
- __le16 rec;
- int err;
-
- err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec);
- *word = le16_to_cpu(rec);
- return err;
-}
-
-static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid,
- u16 word)
-{
- __le16 rec = cpu_to_le16(word);
- return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
-}
-
-#endif /* _HERMES_H */
diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.c b/drivers/net/wireless/intersil/orinoco/hermes_dld.c
deleted file mode 100644
index dbeadfcfefe2..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes_dld.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Hermes download helper.
- *
- * This helper:
- * - is capable of writing to the volatile area of the hermes device
- * - is currently not capable of writing to non-volatile areas
- * - provide helpers to identify and update plugin data
- * - is not capable of interpreting a fw image directly. That is up to
- * the main card driver.
- * - deals with Hermes I devices. It can probably be modified to deal
- * with Hermes II devices
- *
- * Copyright (C) 2007, David Kilroy
- *
- * Plug data code slightly modified from spectrum_cs driver
- * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
- * Portions based on information in wl_lkm_718 Agere driver
- * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include "hermes.h"
-#include "hermes_dld.h"
-
-#define PFX "hermes_dld: "
-
-/* End markers used in dblocks */
-#define PDI_END 0x00000000 /* End of PDA */
-#define BLOCK_END 0xFFFFFFFF /* Last image block */
-#define TEXT_END 0x1A /* End of text header */
-
-/*
- * The following structures have little-endian fields denoted by
- * the leading underscore. Don't access them directly - use inline
- * functions defined below.
- */
-
-/*
- * The binary image to be downloaded consists of series of data blocks.
- * Each block has the following structure.
- */
-struct dblock {
- __le32 addr; /* adapter address where to write the block */
- __le16 len; /* length of the data only, in bytes */
- char data[]; /* data to be written */
-} __packed;
-
-/*
- * Plug Data References are located in the image after the last data
- * block. They refer to areas in the adapter memory where the plug data
- * items with matching ID should be written.
- */
-struct pdr {
- __le32 id; /* record ID */
- __le32 addr; /* adapter address where to write the data */
- __le32 len; /* expected length of the data, in bytes */
- char next[]; /* next PDR starts here */
-} __packed;
-
-/*
- * Plug Data Items are located in the EEPROM read from the adapter by
- * primary firmware. They refer to the device-specific data that should
- * be plugged into the secondary firmware.
- */
-struct pdi {
- __le16 len; /* length of ID and data, in words */
- __le16 id; /* record ID */
- char data[]; /* plug data */
-} __packed;
-
-/*** FW data block access functions ***/
-
-static inline u32
-dblock_addr(const struct dblock *blk)
-{
- return le32_to_cpu(blk->addr);
-}
-
-static inline u32
-dblock_len(const struct dblock *blk)
-{
- return le16_to_cpu(blk->len);
-}
-
-/*** PDR Access functions ***/
-
-static inline u32
-pdr_id(const struct pdr *pdr)
-{
- return le32_to_cpu(pdr->id);
-}
-
-static inline u32
-pdr_addr(const struct pdr *pdr)
-{
- return le32_to_cpu(pdr->addr);
-}
-
-static inline u32
-pdr_len(const struct pdr *pdr)
-{
- return le32_to_cpu(pdr->len);
-}
-
-/*** PDI Access functions ***/
-
-static inline u32
-pdi_id(const struct pdi *pdi)
-{
- return le16_to_cpu(pdi->id);
-}
-
-/* Return length of the data only, in bytes */
-static inline u32
-pdi_len(const struct pdi *pdi)
-{
- return 2 * (le16_to_cpu(pdi->len) - 1);
-}
-
-/*** Plug Data Functions ***/
-
-/*
- * Scan PDR for the record with the specified RECORD_ID.
- * If it's not found, return NULL.
- */
-static const struct pdr *
-hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
-{
- const struct pdr *pdr = first_pdr;
-
- end -= sizeof(struct pdr);
-
- while (((void *) pdr <= end) &&
- (pdr_id(pdr) != PDI_END)) {
- /*
- * PDR area is currently not terminated by PDI_END.
- * It's followed by CRC records, which have the type
- * field where PDR has length. The type can be 0 or 1.
- */
- if (pdr_len(pdr) < 2)
- return NULL;
-
- /* If the record ID matches, we are done */
- if (pdr_id(pdr) == record_id)
- return pdr;
-
- pdr = (struct pdr *) pdr->next;
- }
- return NULL;
-}
-
-/* Scan production data items for a particular entry */
-static const struct pdi *
-hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
-{
- const struct pdi *pdi = first_pdi;
-
- end -= sizeof(struct pdi);
-
- while (((void *) pdi <= end) &&
- (pdi_id(pdi) != PDI_END)) {
-
- /* If the record ID matches, we are done */
- if (pdi_id(pdi) == record_id)
- return pdi;
-
- pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
- }
- return NULL;
-}
-
-/* Process one Plug Data Item - find corresponding PDR and plug it */
-static int
-hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr,
- const struct pdi *pdi, const void *pdr_end)
-{
- const struct pdr *pdr;
-
- /* Find the PDR corresponding to this PDI */
- pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
-
- /* No match is found, safe to ignore */
- if (!pdr)
- return 0;
-
- /* Lengths of the data in PDI and PDR must match */
- if (pdi_len(pdi) != pdr_len(pdr))
- return -EINVAL;
-
- /* do the actual plugging */
- hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
-
- return 0;
-}
-
-/* Parse PDA and write the records into the adapter
- *
- * Attempt to write every records that is in the specified pda
- * which also has a valid production data record for the firmware.
- */
-int hermes_apply_pda(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end)
-{
- int ret;
- const struct pdi *pdi;
- const struct pdr *pdr;
-
- pdr = (const struct pdr *) first_pdr;
- pda_end -= sizeof(struct pdi);
-
- /* Go through every PDI and plug them into the adapter */
- pdi = (const struct pdi *) (pda + 2);
- while (((void *) pdi <= pda_end) &&
- (pdi_id(pdi) != PDI_END)) {
- ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
- if (ret)
- return ret;
-
- /* Increment to the next PDI */
- pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
- }
- return 0;
-}
-
-/* Identify the total number of bytes in all blocks
- * including the header data.
- */
-size_t
-hermes_blocks_length(const char *first_block, const void *end)
-{
- const struct dblock *blk = (const struct dblock *) first_block;
- int total_len = 0;
- int len;
-
- end -= sizeof(*blk);
-
- /* Skip all blocks to locate Plug Data References
- * (Spectrum CS) */
- while (((void *) blk <= end) &&
- (dblock_addr(blk) != BLOCK_END)) {
- len = dblock_len(blk);
- total_len += sizeof(*blk) + len;
- blk = (struct dblock *) &blk->data[len];
- }
-
- return total_len;
-}
-
-/*** Hermes programming ***/
-
-/* Program the data blocks */
-int hermes_program(struct hermes *hw, const char *first_block, const void *end)
-{
- const struct dblock *blk;
- u32 blkaddr;
- u32 blklen;
- int err = 0;
-
- blk = (const struct dblock *) first_block;
-
- if ((void *) blk > (end - sizeof(*blk)))
- return -EIO;
-
- blkaddr = dblock_addr(blk);
- blklen = dblock_len(blk);
-
- while ((blkaddr != BLOCK_END) &&
- (((void *) blk + blklen) <= end)) {
- pr_debug(PFX "Programming block of length %d "
- "to address 0x%08x\n", blklen, blkaddr);
-
- err = hw->ops->program(hw, blk->data, blkaddr, blklen);
- if (err)
- break;
-
- blk = (const struct dblock *) &blk->data[blklen];
-
- if ((void *) blk > (end - sizeof(*blk)))
- return -EIO;
-
- blkaddr = dblock_addr(blk);
- blklen = dblock_len(blk);
- }
- return err;
-}
-
-/*** Default plugging data for Hermes I ***/
-/* Values from wl_lkm_718/hcf/dhf.c */
-
-#define DEFINE_DEFAULT_PDR(pid, length, data) \
-static const struct { \
- __le16 len; \
- __le16 id; \
- u8 val[length]; \
-} __packed default_pdr_data_##pid = { \
- cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
- sizeof(__le16)) - 1), \
- cpu_to_le16(pid), \
- data \
-}
-
-#define DEFAULT_PDR(pid) default_pdr_data_##pid
-
-/* HWIF Compatibility */
-DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
-
-/* PPPPSign */
-DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
-
-/* PPPPProf */
-DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
-
-/* Antenna diversity */
-DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
-
-/* Modem VCO band Set-up */
-DEFINE_DEFAULT_PDR(0x0160, 28,
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00");
-
-/* Modem Rx Gain Table Values */
-DEFINE_DEFAULT_PDR(0x0161, 256,
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
- "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
- "\x3B\x01\x3A\01\x3A\x01\x39\x01"
- "\x39\x01\x38\01\x38\x01\x37\x01"
- "\x37\x01\x36\01\x36\x01\x35\x01"
- "\x35\x01\x34\01\x34\x01\x33\x01"
- "\x33\x01\x32\x01\x32\x01\x31\x01"
- "\x31\x01\x30\x01\x30\x01\x7B\x01"
- "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
- "\x79\x01\x78\x01\x78\x01\x77\x01"
- "\x77\x01\x76\x01\x76\x01\x75\x01"
- "\x75\x01\x74\x01\x74\x01\x73\x01"
- "\x73\x01\x72\x01\x72\x01\x71\x01"
- "\x71\x01\x70\x01\x70\x01\x68\x01"
- "\x68\x01\x67\x01\x67\x01\x66\x01"
- "\x66\x01\x65\x01\x65\x01\x57\x01"
- "\x57\x01\x56\x01\x56\x01\x55\x01"
- "\x55\x01\x54\x01\x54\x01\x53\x01"
- "\x53\x01\x52\x01\x52\x01\x51\x01"
- "\x51\x01\x50\x01\x50\x01\x48\x01"
- "\x48\x01\x47\x01\x47\x01\x46\x01"
- "\x46\x01\x45\x01\x45\x01\x44\x01"
- "\x44\x01\x43\x01\x43\x01\x42\x01"
- "\x42\x01\x41\x01\x41\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01");
-
-/* Write PDA according to certain rules.
- *
- * For every production data record, look for a previous setting in
- * the pda, and use that.
- *
- * For certain records, use defaults if they are not found in pda.
- */
-int hermes_apply_pda_with_defaults(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end)
-{
- const struct pdr *pdr = (const struct pdr *) first_pdr;
- const struct pdi *first_pdi = (const struct pdi *) &pda[2];
- const struct pdi *pdi;
- const struct pdi *default_pdi = NULL;
- const struct pdi *outdoor_pdi;
- int record_id;
-
- pdr_end -= sizeof(struct pdr);
-
- while (((void *) pdr <= pdr_end) &&
- (pdr_id(pdr) != PDI_END)) {
- /*
- * For spectrum_cs firmwares,
- * PDR area is currently not terminated by PDI_END.
- * It's followed by CRC records, which have the type
- * field where PDR has length. The type can be 0 or 1.
- */
- if (pdr_len(pdr) < 2)
- break;
- record_id = pdr_id(pdr);
-
- pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
- if (pdi)
- pr_debug(PFX "Found record 0x%04x at %p\n",
- record_id, pdi);
-
- switch (record_id) {
- case 0x110: /* Modem REFDAC values */
- case 0x120: /* Modem VGDAC values */
- outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
- pda_end);
- default_pdi = NULL;
- if (outdoor_pdi) {
- pdi = outdoor_pdi;
- pr_debug(PFX
- "Using outdoor record 0x%04x at %p\n",
- record_id + 1, pdi);
- }
- break;
- case 0x5: /* HWIF Compatibility */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
- break;
- case 0x108: /* PPPPSign */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
- break;
- case 0x109: /* PPPPProf */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
- break;
- case 0x150: /* Antenna diversity */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
- break;
- case 0x160: /* Modem VCO band Set-up */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
- break;
- case 0x161: /* Modem Rx Gain Table Values */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
- break;
- default:
- default_pdi = NULL;
- break;
- }
- if (!pdi && default_pdi) {
- /* Use default */
- pdi = default_pdi;
- pr_debug(PFX "Using default record 0x%04x at %p\n",
- record_id, pdi);
- }
-
- if (pdi) {
- /* Lengths of the data in PDI and PDR must match */
- if ((pdi_len(pdi) == pdr_len(pdr)) &&
- ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
- /* do the actual plugging */
- hw->ops->program(hw, pdi->data, pdr_addr(pdr),
- pdi_len(pdi));
- }
- }
-
- pdr++;
- }
- return 0;
-}
diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.h b/drivers/net/wireless/intersil/orinoco/hermes_dld.h
deleted file mode 100644
index b5377e232c63..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes_dld.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007, David Kilroy
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-#ifndef _HERMES_DLD_H
-#define _HERMES_DLD_H
-
-#include "hermes.h"
-
-int hermesi_program_init(struct hermes *hw, u32 offset);
-int hermesi_program_end(struct hermes *hw);
-int hermes_program(struct hermes *hw, const char *first_block, const void *end);
-
-int hermes_read_pda(struct hermes *hw,
- __le16 *pda,
- u32 pda_addr,
- u16 pda_len,
- int use_eeprom);
-int hermes_apply_pda(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end);
-int hermes_apply_pda_with_defaults(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end);
-
-size_t hermes_blocks_length(const char *first_block, const void *end);
-
-#endif /* _HERMES_DLD_H */
diff --git a/drivers/net/wireless/intersil/orinoco/hermes_rid.h b/drivers/net/wireless/intersil/orinoco/hermes_rid.h
deleted file mode 100644
index 42eb67dea1df..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes_rid.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef _HERMES_RID_H
-#define _HERMES_RID_H
-
-/*
- * Configuration RIDs
- */
-#define HERMES_RID_CNFPORTTYPE 0xFC00
-#define HERMES_RID_CNFOWNMACADDR 0xFC01
-#define HERMES_RID_CNFDESIREDSSID 0xFC02
-#define HERMES_RID_CNFOWNCHANNEL 0xFC03
-#define HERMES_RID_CNFOWNSSID 0xFC04
-#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05
-#define HERMES_RID_CNFSYSTEMSCALE 0xFC06
-#define HERMES_RID_CNFMAXDATALEN 0xFC07
-#define HERMES_RID_CNFWDSADDRESS 0xFC08
-#define HERMES_RID_CNFPMENABLED 0xFC09
-#define HERMES_RID_CNFPMEPS 0xFC0A
-#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B
-#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C
-#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D
-#define HERMES_RID_CNFOWNNAME 0xFC0E
-#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10
-#define HERMES_RID_CNFWDSADDRESS1 0xFC11
-#define HERMES_RID_CNFWDSADDRESS2 0xFC12
-#define HERMES_RID_CNFWDSADDRESS3 0xFC13
-#define HERMES_RID_CNFWDSADDRESS4 0xFC14
-#define HERMES_RID_CNFWDSADDRESS5 0xFC15
-#define HERMES_RID_CNFWDSADDRESS6 0xFC16
-#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17
-#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20
-#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21
-#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21
-#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22
-#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23
-#define HERMES_RID_CNFDEFAULTKEY0 0xFC24
-#define HERMES_RID_CNFDEFAULTKEY1 0xFC25
-#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25
-#define HERMES_RID_CNFDEFAULTKEY2 0xFC26
-#define HERMES_RID_CNFDEFAULTKEY3 0xFC27
-#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28
-#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
-#define HERMES_RID_CNFAUTHENTICATION 0xFC2A
-#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B
-#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B
-#define HERMES_RID_CNFTXCONTROL 0xFC2C
-#define HERMES_RID_CNFROAMINGMODE 0xFC2D
-#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E
-#define HERMES_RID_CNFRCVCRCERROR 0xFC30
-#define HERMES_RID_CNFMMLIFE 0xFC31
-#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32
-#define HERMES_RID_CNFBEACONINT 0xFC33
-#define HERMES_RID_CNFAPPCFINFO 0xFC34
-#define HERMES_RID_CNFSTAPCFINFO 0xFC35
-#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37
-#define HERMES_RID_CNFTIMCTRL 0xFC40
-#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42
-#define HERMES_RID_CNFENHSECURITY 0xFC43
-#define HERMES_RID_CNFGROUPADDRESSES 0xFC80
-#define HERMES_RID_CNFCREATEIBSS 0xFC81
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82
-#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83
-#define HERMES_RID_CNFTXRATECONTROL 0xFC84
-#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85
-#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A
-#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96
-#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97
-#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98
-#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99
-#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A
-#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B
-#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C
-#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D
-#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB
-#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0
-#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0
-#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
-#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1
-#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
-#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2
-#define HERMES_RID_CNFBASICRATES 0xFCB3
-#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4
-#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4
-#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5
-#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6
-#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7
-#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8
-#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9
-#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA
-#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB
-#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2
-#define HERMES_RID_CNFDISASSOCIATE 0xFCC8
-#define HERMES_RID_CNFTICKTIME 0xFCE0
-#define HERMES_RID_CNFSCANREQUEST 0xFCE1
-#define HERMES_RID_CNFJOINREQUEST 0xFCE2
-#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3
-#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4
-#define HERMES_RID_CNFHOSTSCAN 0xFCE5
-
-/*
- * Information RIDs
- */
-#define HERMES_RID_MAXLOADTIME 0xFD00
-#define HERMES_RID_DOWNLOADBUFFER 0xFD01
-#define HERMES_RID_PRIID 0xFD02
-#define HERMES_RID_PRISUPRANGE 0xFD03
-#define HERMES_RID_CFIACTRANGES 0xFD04
-#define HERMES_RID_NICSERNUM 0xFD0A
-#define HERMES_RID_NICID 0xFD0B
-#define HERMES_RID_MFISUPRANGE 0xFD0C
-#define HERMES_RID_CFISUPRANGE 0xFD0D
-#define HERMES_RID_CHANNELLIST 0xFD10
-#define HERMES_RID_REGULATORYDOMAINS 0xFD11
-#define HERMES_RID_TEMPTYPE 0xFD12
-#define HERMES_RID_CIS 0xFD13
-#define HERMES_RID_STAID 0xFD20
-#define HERMES_RID_STASUPRANGE 0xFD21
-#define HERMES_RID_MFIACTRANGES 0xFD22
-#define HERMES_RID_CFIACTRANGES2 0xFD23
-#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24
-#define HERMES_RID_PORTSTATUS 0xFD40
-#define HERMES_RID_CURRENTSSID 0xFD41
-#define HERMES_RID_CURRENTBSSID 0xFD42
-#define HERMES_RID_COMMSQUALITY 0xFD43
-#define HERMES_RID_CURRENTTXRATE 0xFD44
-#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45
-#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46
-#define HERMES_RID_PROTOCOLRSPTIME 0xFD47
-#define HERMES_RID_SHORTRETRYLIMIT 0xFD48
-#define HERMES_RID_LONGRETRYLIMIT 0xFD49
-#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A
-#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B
-#define HERMES_RID_CFPOLLABLE 0xFD4C
-#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D
-#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
-#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51
-#define HERMES_RID_CURRENTTXRATE1 0xFD80
-#define HERMES_RID_CURRENTTXRATE2 0xFD81
-#define HERMES_RID_CURRENTTXRATE3 0xFD82
-#define HERMES_RID_CURRENTTXRATE4 0xFD83
-#define HERMES_RID_CURRENTTXRATE5 0xFD84
-#define HERMES_RID_CURRENTTXRATE6 0xFD85
-#define HERMES_RID_OWNMACADDR 0xFD86
-#define HERMES_RID_SCANRESULTSTABLE 0xFD88
-#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89
-#define HERMES_RID_CURRENT_WPA_IE 0xFD8A
-#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B
-#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C
-#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D
-#define HERMES_RID_TXQUEUEEMPTY 0xFD91
-#define HERMES_RID_PHYTYPE 0xFDC0
-#define HERMES_RID_CURRENTCHANNEL 0xFDC1
-#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2
-#define HERMES_RID_CCAMODE 0xFDC3
-#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6
-#define HERMES_RID_BUILDSEQ 0xFFFE
-#define HERMES_RID_FWID 0xFFFF
-
-#endif
diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c
deleted file mode 100644
index 4fcca08e50de..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hw.c
+++ /dev/null
@@ -1,1362 +0,0 @@
-/* Encapsulate basic setting changes and retrieval on Hermes hardware
- *
- * See copyright notice in main.c
- */
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/if_arp.h>
-#include <linux/ieee80211.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-#include "hermes.h"
-#include "hermes_rid.h"
-#include "orinoco.h"
-
-#include "hw.h"
-
-#define SYMBOL_MAX_VER_LEN (14)
-
-/* Symbol firmware has a bug allocating buffers larger than this */
-#define TX_NICBUF_SIZE_BUG 1585
-
-/********************************************************************/
-/* Data tables */
-/********************************************************************/
-
-/* This tables gives the actual meanings of the bitrate IDs returned
- * by the firmware. */
-static const struct {
- int bitrate; /* in 100s of kilobits */
- int automatic;
- u16 agere_txratectrl;
- u16 intersil_txratectrl;
-} bitrate_table[] = {
- {110, 1, 3, 15}, /* Entry 0 is the default */
- {10, 0, 1, 1},
- {10, 1, 1, 1},
- {20, 0, 2, 2},
- {20, 1, 6, 3},
- {55, 0, 4, 4},
- {55, 1, 7, 7},
- {110, 0, 5, 8},
-};
-#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
-
-/* Firmware version encoding */
-struct comp_id {
- u16 id, variant, major, minor;
-} __packed;
-
-static inline enum fwtype determine_firmware_type(struct comp_id *nic_id)
-{
- if (nic_id->id < 0x8000)
- return FIRMWARE_TYPE_AGERE;
- else if (nic_id->id == 0x8000 && nic_id->major == 0)
- return FIRMWARE_TYPE_SYMBOL;
- else
- return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties
- * This function can be called before we have registerred with netdev,
- * so all errors go out with dev_* rather than printk
- *
- * If non-NULL stores a firmware description in fw_name.
- * If non-NULL stores a HW version in hw_ver
- *
- * These are output via generic cfg80211 ethtool support.
- */
-int determine_fw_capabilities(struct orinoco_private *priv,
- char *fw_name, size_t fw_name_len,
- u32 *hw_ver)
-{
- struct device *dev = priv->dev;
- struct hermes *hw = &priv->hw;
- int err;
- struct comp_id nic_id, sta_id;
- unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2)));
-
- /* Get the hardware version */
- err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
- if (err) {
- dev_err(dev, "Cannot read hardware identity: error %d\n",
- err);
- return err;
- }
-
- le16_to_cpus(&nic_id.id);
- le16_to_cpus(&nic_id.variant);
- le16_to_cpus(&nic_id.major);
- le16_to_cpus(&nic_id.minor);
- dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
- nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
-
- if (hw_ver)
- *hw_ver = (((nic_id.id & 0xff) << 24) |
- ((nic_id.variant & 0xff) << 16) |
- ((nic_id.major & 0xff) << 8) |
- (nic_id.minor & 0xff));
-
- priv->firmware_type = determine_firmware_type(&nic_id);
-
- /* Get the firmware version */
- err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
- if (err) {
- dev_err(dev, "Cannot read station identity: error %d\n",
- err);
- return err;
- }
-
- le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.variant);
- le16_to_cpus(&sta_id.major);
- le16_to_cpus(&sta_id.minor);
- dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
- sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
-
- switch (sta_id.id) {
- case 0x15:
- dev_err(dev, "Primary firmware is active\n");
- return -ENODEV;
- case 0x14b:
- dev_err(dev, "Tertiary firmware is active\n");
- return -ENODEV;
- case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
- case 0x21: /* Symbol Spectrum24 Trilogy */
- break;
- default:
- dev_notice(dev, "Unknown station ID, please report\n");
- break;
- }
-
- /* Default capabilities */
- priv->has_sensitivity = 1;
- priv->has_mwo = 0;
- priv->has_preamble = 0;
- priv->has_port3 = 1;
- priv->has_ibss = 1;
- priv->has_wep = 0;
- priv->has_big_wep = 0;
- priv->has_alt_txcntl = 0;
- priv->has_ext_scan = 0;
- priv->has_wpa = 0;
- priv->do_fw_download = 0;
-
- /* Determine capabilities from the firmware version */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
- ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- if (fw_name)
- snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
- sta_id.major, sta_id.minor);
-
- firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
- priv->has_ibss = (firmver >= 0x60006);
- priv->has_wep = (firmver >= 0x40020);
- priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
- Gold cards from the others? */
- priv->has_mwo = (firmver >= 0x60000);
- priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
- priv->ibss_port = 1;
- priv->has_hostscan = (firmver >= 0x8000a);
- priv->do_fw_download = 1;
- priv->broken_monitor = (firmver >= 0x80000);
- priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_wpa = (firmver >= 0x9002a);
- /* Tested with Agere firmware :
- * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
- * Tested CableTron firmware : 4.32 => Anton */
- break;
- case FIRMWARE_TYPE_SYMBOL:
- /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
- /* Intel MAC : 00:02:B3:* */
- /* 3Com MAC : 00:50:DA:* */
- memset(tmp, 0, sizeof(tmp));
- /* Get the Symbol firmware version */
- err = hw->ops->read_ltv_pr(hw, USER_BAP,
- HERMES_RID_SECONDARYVERSION_SYMBOL,
- SYMBOL_MAX_VER_LEN, NULL, &tmp);
- if (err) {
- dev_warn(dev, "Error %d reading Symbol firmware info. "
- "Wildly guessing capabilities...\n", err);
- firmver = 0;
- tmp[0] = '\0';
- } else {
- /* The firmware revision is a string, the format is
- * something like : "V2.20-01".
- * Quick and dirty parsing... - Jean II
- */
- firmver = ((tmp[1] - '0') << 16)
- | ((tmp[3] - '0') << 12)
- | ((tmp[4] - '0') << 8)
- | ((tmp[6] - '0') << 4)
- | (tmp[7] - '0');
-
- tmp[SYMBOL_MAX_VER_LEN] = '\0';
- }
-
- if (fw_name)
- snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
-
- priv->has_ibss = (firmver >= 0x20000);
- priv->has_wep = (firmver >= 0x15012);
- priv->has_big_wep = (firmver >= 0x20000);
- priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
- (firmver >= 0x29000 && firmver < 0x30000) ||
- firmver >= 0x31000;
- priv->has_preamble = (firmver >= 0x20000);
- priv->ibss_port = 4;
-
- /* Symbol firmware is found on various cards, but
- * there has been no attempt to check firmware
- * download on non-spectrum_cs based cards.
- *
- * Given that the Agere firmware download works
- * differently, we should avoid doing a firmware
- * download with the Symbol algorithm on non-spectrum
- * cards.
- *
- * For now we can identify a spectrum_cs based card
- * because it has a firmware reset function.
- */
- priv->do_fw_download = (priv->stop_fw != NULL);
-
- priv->broken_disableport = (firmver == 0x25013) ||
- (firmver >= 0x30000 && firmver <= 0x31000);
- priv->has_hostscan = (firmver >= 0x31001) ||
- (firmver >= 0x29057 && firmver < 0x30000);
- /* Tested with Intel firmware : 0x20015 => Jean II */
- /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- /* D-Link, Linksys, Adtron, ZoomAir, and many others...
- * Samsung, Compaq 100/200 and Proxim are slightly
- * different and less well tested */
- /* D-Link MAC : 00:40:05:* */
- /* Addtron MAC : 00:90:D1:* */
- if (fw_name)
- snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
- sta_id.major, sta_id.minor, sta_id.variant);
-
- firmver = ((unsigned long)sta_id.major << 16) |
- ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
- priv->has_ibss = (firmver >= 0x000700); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
- priv->has_pm = (firmver >= 0x000700);
- priv->has_hostscan = (firmver >= 0x010301);
-
- if (firmver >= 0x000800)
- priv->ibss_port = 0;
- else {
- dev_notice(dev, "Intersil firmware earlier than v0.8.x"
- " - several features not supported\n");
- priv->ibss_port = 1;
- }
- break;
- }
- if (fw_name)
- dev_info(dev, "Firmware determined as %s\n", fw_name);
-
-#ifndef CONFIG_HERMES_PRISM
- if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
- dev_err(dev, "Support for Prism chipset is not enabled\n");
- return -ENODEV;
- }
-#endif
-
- return 0;
-}
-
-/* Read settings from EEPROM into our private structure.
- * MAC address gets dropped into callers buffer
- * Can be called before netdev registration.
- */
-int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
-{
- struct device *dev = priv->dev;
- struct hermes_idstring nickbuf;
- struct hermes *hw = &priv->hw;
- int len;
- int err;
- u16 reclen;
-
- /* Get the MAC address */
- err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- ETH_ALEN, NULL, dev_addr);
- if (err) {
- dev_warn(dev, "Failed to read MAC address!\n");
- goto out;
- }
-
- dev_dbg(dev, "MAC address %pM\n", dev_addr);
-
- /* Get the station name */
- err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- sizeof(nickbuf), &reclen, &nickbuf);
- if (err) {
- dev_err(dev, "failed to read station name\n");
- goto out;
- }
- if (nickbuf.len)
- len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
- else
- len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
- memcpy(priv->nick, &nickbuf.val, len);
- priv->nick[len] = '\0';
-
- dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
-
- /* Get allowed channels */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST,
- &priv->channel_mask);
- if (err) {
- dev_err(dev, "Failed to read channel list!\n");
- goto out;
- }
-
- /* Get initial AP density */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
- &priv->ap_density);
- if (err || priv->ap_density < 1 || priv->ap_density > 3)
- priv->has_sensitivity = 0;
-
- /* Get initial RTS threshold */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- &priv->rts_thresh);
- if (err) {
- dev_err(dev, "Failed to read RTS threshold!\n");
- goto out;
- }
-
- /* Get initial fragmentation settings */
- if (priv->has_mwo)
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- &priv->mwo_robust);
- else
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- &priv->frag_thresh);
- if (err) {
- dev_err(dev, "Failed to read fragmentation settings!\n");
- goto out;
- }
-
- /* Power management setup */
- if (priv->has_pm) {
- priv->pm_on = 0;
- priv->pm_mcast = 1;
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- &priv->pm_period);
- if (err) {
- dev_err(dev, "Failed to read power management "
- "period!\n");
- goto out;
- }
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- &priv->pm_timeout);
- if (err) {
- dev_err(dev, "Failed to read power management "
- "timeout!\n");
- goto out;
- }
- }
-
- /* Preamble setup */
- if (priv->has_preamble) {
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- &priv->preamble);
- if (err) {
- dev_err(dev, "Failed to read preamble setup\n");
- goto out;
- }
- }
-
- /* Retry settings */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
- &priv->short_retry_limit);
- if (err) {
- dev_err(dev, "Failed to read short retry limit\n");
- goto out;
- }
-
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
- &priv->long_retry_limit);
- if (err) {
- dev_err(dev, "Failed to read long retry limit\n");
- goto out;
- }
-
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
- &priv->retry_lifetime);
- if (err) {
- dev_err(dev, "Failed to read max retry lifetime\n");
- goto out;
- }
-
-out:
- return err;
-}
-
-/* Can be called before netdev registration */
-int orinoco_hw_allocate_fid(struct orinoco_private *priv)
-{
- struct device *dev = priv->dev;
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
- /* Try workaround for old Symbol firmware bug */
- priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
- err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
-
- dev_warn(dev, "Firmware ALLOC bug detected "
- "(old Symbol firmware?). Work around %s\n",
- err ? "failed!" : "ok.");
- }
-
- return err;
-}
-
-int orinoco_get_bitratemode(int bitrate, int automatic)
-{
- int ratemode = -1;
- int i;
-
- if ((bitrate != 10) && (bitrate != 20) &&
- (bitrate != 55) && (bitrate != 110))
- return ratemode;
-
- for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
- if ((bitrate_table[i].bitrate == bitrate) &&
- (bitrate_table[i].automatic == automatic)) {
- ratemode = i;
- break;
- }
- }
- return ratemode;
-}
-
-void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
-{
- BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
-
- *bitrate = bitrate_table[ratemode].bitrate * 100000;
- *automatic = bitrate_table[ratemode].automatic;
-}
-
-int orinoco_hw_program_rids(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct wireless_dev *wdev = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err;
- struct hermes_idstring idbuf;
-
- /* Set the MAC address */
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- HERMES_BYTES_TO_RECLEN(ETH_ALEN),
- dev->dev_addr);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting MAC address\n",
- dev->name, err);
- return err;
- }
-
- /* Set up the link mode */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
- priv->port_type);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting port type\n",
- dev->name, err);
- return err;
- }
- /* Set the channel/frequency */
- if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFOWNCHANNEL,
- priv->channel);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting channel %d\n",
- dev->name, err, priv->channel);
- return err;
- }
- }
-
- if (priv->has_ibss) {
- u16 createibss;
-
- if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
- printk(KERN_WARNING "%s: This firmware requires an "
- "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
- /* With wvlan_cs, in this case, we would crash.
- * hopefully, this driver will behave better...
- * Jean II */
- createibss = 0;
- } else {
- createibss = priv->createibss;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFCREATEIBSS,
- createibss);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set the desired BSSID */
- err = __orinoco_hw_set_wap(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting AP address\n",
- dev->name, err);
- return err;
- }
-
- /* Set the desired ESSID */
- idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
- memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
- /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
- dev->name, err);
- return err;
- }
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
- dev->name, err);
- return err;
- }
-
- /* Set the station name */
- idbuf.len = cpu_to_le16(strlen(priv->nick));
- memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting nickname\n",
- dev->name, err);
- return err;
- }
-
- /* Set AP density */
- if (priv->has_sensitivity) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE,
- priv->ap_density);
- if (err) {
- printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
- "Disabling sensitivity control\n",
- dev->name, err);
-
- priv->has_sensitivity = 0;
- }
- }
-
- /* Set RTS threshold */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
- dev->name, err);
- return err;
- }
-
- /* Set fragmentation threshold or MWO robustness */
- if (priv->has_mwo)
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- priv->mwo_robust);
- else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- priv->frag_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting fragmentation\n",
- dev->name, err);
- return err;
- }
-
- /* Set bitrate */
- err = __orinoco_hw_set_bitrate(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting bitrate\n",
- dev->name, err);
- return err;
- }
-
- /* Set power management */
- if (priv->has_pm) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED,
- priv->pm_on);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE,
- priv->pm_mcast);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set preamble - only for Symbol so far... */
- if (priv->has_preamble) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- priv->preamble);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting preamble\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set up encryption */
- if (priv->has_wep || priv->has_wpa) {
- err = __orinoco_hw_setup_enc(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d activating encryption\n",
- dev->name, err);
- return err;
- }
- }
-
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- /* Enable monitor mode */
- dev->type = ARPHRD_IEEE80211;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_MONITOR, 0, NULL);
- } else {
- /* Disable monitor mode */
- dev->type = ARPHRD_ETHER;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_STOP, 0, NULL);
- }
- if (err)
- return err;
-
- /* Reset promiscuity / multicast*/
- priv->promiscuous = 0;
- priv->mc_count = 0;
-
- /* Record mode change */
- wdev->iftype = priv->iw_mode;
-
- return 0;
-}
-
-/* Get tsc from the firmware */
-int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- u8 tsc_arr[4][ORINOCO_SEQ_LEN];
-
- if ((key < 0) || (key >= 4))
- return -EINVAL;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
- sizeof(tsc_arr), NULL, &tsc_arr);
- if (!err)
- memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
-
- return err;
-}
-
-int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int ratemode = priv->bitratemode;
- int err = 0;
-
- if (ratemode >= BITRATE_TABLE_SIZE) {
- printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
- priv->ndev->name, ratemode);
- return -EINVAL;
- }
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFTXRATECONTROL,
- bitrate_table[ratemode].agere_txratectrl);
- break;
- case FIRMWARE_TYPE_INTERSIL:
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFTXRATECONTROL,
- bitrate_table[ratemode].intersil_txratectrl);
- break;
- default:
- BUG();
- }
-
- return err;
-}
-
-int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
-{
- struct hermes *hw = &priv->hw;
- int i;
- int err = 0;
- u16 val;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CURRENTTXRATE, &val);
- if (err)
- return err;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
- /* Note : in Lucent firmware, the return value of
- * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
- * and therefore is totally different from the
- * encoding of HERMES_RID_CNFTXRATECONTROL.
- * Don't forget that 6Mb/s is really 5.5Mb/s */
- if (val == 6)
- *bitrate = 5500000;
- else
- *bitrate = val * 1000000;
- break;
- case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
- case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
- for (i = 0; i < BITRATE_TABLE_SIZE; i++)
- if (bitrate_table[i].intersil_txratectrl == val) {
- *bitrate = bitrate_table[i].bitrate * 100000;
- break;
- }
-
- if (i >= BITRATE_TABLE_SIZE) {
- printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
- priv->ndev->name, val);
- err = -EIO;
- }
-
- break;
- default:
- BUG();
- }
-
- return err;
-}
-
-/* Set fixed AP address */
-int __orinoco_hw_set_wap(struct orinoco_private *priv)
-{
- int roaming_flag;
- int err = 0;
- struct hermes *hw = &priv->hw;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* not supported */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- if (priv->bssid_fixed)
- roaming_flag = 2;
- else
- roaming_flag = 1;
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFROAMINGMODE,
- roaming_flag);
- break;
- case FIRMWARE_TYPE_SYMBOL:
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
- &priv->desired_bssid);
- break;
- }
- return err;
-}
-
-/* Change the WEP keys and/or the current keys. Can be called
- * either from __orinoco_hw_setup_enc() or directly from
- * orinoco_ioctl_setiwencode(). In the later case the association
- * with the AP is not broken (if the firmware can handle it),
- * which is needed for 802.1x implementations. */
-int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- int i;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- {
- struct orinoco_key keys[ORINOCO_MAX_KEYS];
-
- memset(&keys, 0, sizeof(keys));
- for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
- int len = min(priv->keys[i].key_len,
- ORINOCO_MAX_KEY_SIZE);
- memcpy(&keys[i].data, priv->keys[i].key, len);
- if (len > SMALL_KEY_SIZE)
- keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
- else if (len > 0)
- keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
- else
- keys[i].len = cpu_to_le16(0);
- }
-
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFWEPKEYS_AGERE,
- &keys);
- if (err)
- return err;
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFTXKEY_AGERE,
- priv->tx_key);
- if (err)
- return err;
- break;
- }
- case FIRMWARE_TYPE_INTERSIL:
- case FIRMWARE_TYPE_SYMBOL:
- {
- int keylen;
-
- /* Force uniform key length to work around
- * firmware bugs */
- keylen = priv->keys[priv->tx_key].key_len;
-
- if (keylen > LARGE_KEY_SIZE) {
- printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
- priv->ndev->name, priv->tx_key, keylen);
- return -E2BIG;
- } else if (keylen > SMALL_KEY_SIZE)
- keylen = LARGE_KEY_SIZE;
- else if (keylen > 0)
- keylen = SMALL_KEY_SIZE;
- else
- keylen = 0;
-
- /* Write all 4 keys */
- for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
- u8 key[LARGE_KEY_SIZE] = { 0 };
-
- memcpy(key, priv->keys[i].key,
- priv->keys[i].key_len);
-
- err = hw->ops->write_ltv(hw, USER_BAP,
- HERMES_RID_CNFDEFAULTKEY0 + i,
- HERMES_BYTES_TO_RECLEN(keylen),
- key);
- if (err)
- return err;
- }
-
- /* Write the index of the key used in transmission */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFWEPDEFAULTKEYID,
- priv->tx_key);
- if (err)
- return err;
- }
- break;
- }
-
- return 0;
-}
-
-int __orinoco_hw_setup_enc(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- int master_wep_flag;
- int auth_flag;
- int enc_flag;
-
- /* Setup WEP keys */
- if (priv->encode_alg == ORINOCO_ALG_WEP)
- __orinoco_hw_setup_wepkeys(priv);
-
- if (priv->wep_restrict)
- auth_flag = HERMES_AUTH_SHARED_KEY;
- else
- auth_flag = HERMES_AUTH_OPEN;
-
- if (priv->wpa_enabled)
- enc_flag = 2;
- else if (priv->encode_alg == ORINOCO_ALG_WEP)
- enc_flag = 1;
- else
- enc_flag = 0;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
- if (priv->encode_alg == ORINOCO_ALG_WEP) {
- /* Enable the shared-key authentication. */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFAUTHENTICATION_AGERE,
- auth_flag);
- if (err)
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFWEPENABLED_AGERE,
- enc_flag);
- if (err)
- return err;
-
- if (priv->has_wpa) {
- /* Set WPA key management */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
- priv->key_mgmt);
- if (err)
- return err;
- }
-
- break;
-
- case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
- case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
- if (priv->encode_alg == ORINOCO_ALG_WEP) {
- if (priv->wep_restrict ||
- (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
- master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
- HERMES_WEP_EXCL_UNENCRYPTED;
- else
- master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFAUTHENTICATION,
- auth_flag);
- if (err)
- return err;
- } else
- master_wep_flag = 0;
-
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
- master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
-
- /* Master WEP setting : on/off */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFWEPFLAGS_INTERSIL,
- master_wep_flag);
- if (err)
- return err;
-
- break;
- }
-
- return 0;
-}
-
-/* key must be 32 bytes, including the tx and rx MIC keys.
- * rsc must be NULL or up to 8 bytes
- * tsc must be NULL or up to 8 bytes
- */
-int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
- int set_tx, const u8 *key, size_t key_len,
- const u8 *rsc, size_t rsc_len,
- const u8 *tsc, size_t tsc_len)
-{
- struct {
- __le16 idx;
- u8 rsc[ORINOCO_SEQ_LEN];
- struct {
- u8 key[TKIP_KEYLEN];
- u8 tx_mic[MIC_KEYLEN];
- u8 rx_mic[MIC_KEYLEN];
- } tkip;
- u8 tsc[ORINOCO_SEQ_LEN];
- } __packed buf;
- struct hermes *hw = &priv->hw;
- int ret;
- int err;
- int k;
- u16 xmitting;
-
- key_idx &= 0x3;
-
- if (set_tx)
- key_idx |= 0x8000;
-
- buf.idx = cpu_to_le16(key_idx);
- if (key_len != sizeof(buf.tkip))
- return -EINVAL;
- memcpy(&buf.tkip, key, sizeof(buf.tkip));
-
- if (rsc_len > sizeof(buf.rsc))
- rsc_len = sizeof(buf.rsc);
-
- if (tsc_len > sizeof(buf.tsc))
- tsc_len = sizeof(buf.tsc);
-
- memset(buf.rsc, 0, sizeof(buf.rsc));
- memset(buf.tsc, 0, sizeof(buf.tsc));
-
- if (rsc != NULL)
- memcpy(buf.rsc, rsc, rsc_len);
-
- if (tsc != NULL)
- memcpy(buf.tsc, tsc, tsc_len);
- else
- buf.tsc[4] = 0x10;
-
- /* Wait up to 100ms for tx queue to empty */
- for (k = 100; k > 0; k--) {
- udelay(1000);
- ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
- &xmitting);
- if (ret || !xmitting)
- break;
- }
-
- if (k == 0)
- ret = -ETIMEDOUT;
-
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
- &buf);
-
- return ret ? ret : err;
-}
-
-int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
- key_idx);
- if (err)
- printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
- priv->ndev->name, err, key_idx);
- return err;
-}
-
-int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
- struct net_device *dev,
- int mc_count, int promisc)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
-
- if (promisc != priv->promiscuous) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPROMISCUOUSMODE,
- promisc);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
- priv->ndev->name, err);
- } else
- priv->promiscuous = promisc;
- }
-
- /* If we're not in promiscuous mode, then we need to set the
- * group address if either we want to multicast, or if we were
- * multicasting and want to stop */
- if (!promisc && (mc_count || priv->mc_count)) {
- struct netdev_hw_addr *ha;
- struct hermes_multicast mclist;
- int i = 0;
-
- netdev_for_each_mc_addr(ha, dev) {
- if (i == mc_count)
- break;
- memcpy(mclist.addr[i++], ha->addr, ETH_ALEN);
- }
-
- err = hw->ops->write_ltv(hw, USER_BAP,
- HERMES_RID_CNFGROUPADDRESSES,
- HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
- &mclist);
- if (err)
- printk(KERN_ERR "%s: Error %d setting multicast list.\n",
- priv->ndev->name, err);
- else
- priv->mc_count = mc_count;
- }
- return err;
-}
-
-/* Return : < 0 -> error code ; >= 0 -> length */
-int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
- char buf[IW_ESSID_MAX_SIZE + 1])
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- struct hermes_idstring essidbuf;
- char *p = (char *)(&essidbuf.val);
- int len;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (strlen(priv->desired_essid) > 0) {
- /* We read the desired SSID from the hardware rather
- than from priv->desired_essid, just in case the
- firmware is allowed to change it on us. I'm not
- sure about this */
- /* My guess is that the OWNSSID should always be whatever
- * we set to the card, whereas CURRENT_SSID is the one that
- * may change... - Jean II */
- u16 rid;
-
- *active = 1;
-
- rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
- HERMES_RID_CNFDESIREDSSID;
-
- err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
- NULL, &essidbuf);
- if (err)
- goto fail_unlock;
- } else {
- *active = 0;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
- sizeof(essidbuf), NULL, &essidbuf);
- if (err)
- goto fail_unlock;
- }
-
- len = le16_to_cpu(essidbuf.len);
- BUG_ON(len > IW_ESSID_MAX_SIZE);
-
- memset(buf, 0, IW_ESSID_MAX_SIZE);
- memcpy(buf, p, len);
- err = len;
-
- fail_unlock:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-int orinoco_hw_get_freq(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- u16 channel;
- int freq = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
- &channel);
- if (err)
- goto out;
-
- /* Intersil firmware 1.3.5 returns 0 when the interface is down */
- if (channel == 0) {
- err = -EBUSY;
- goto out;
- }
-
- if ((channel < 1) || (channel > NUM_CHANNELS)) {
- printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
- priv->ndev->name, channel);
- err = -EBUSY;
- goto out;
-
- }
- freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
-
- out:
- orinoco_unlock(priv, &flags);
-
- if (err > 0)
- err = -EBUSY;
- return err ? err : freq;
-}
-
-int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
- int *numrates, s32 *rates, int max)
-{
- struct hermes *hw = &priv->hw;
- struct hermes_idstring list;
- unsigned char *p = (unsigned char *)&list.val;
- int err = 0;
- int num;
- int i;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
- sizeof(list), NULL, &list);
- orinoco_unlock(priv, &flags);
-
- if (err)
- return err;
-
- num = le16_to_cpu(list.len);
- *numrates = num;
- num = min(num, max);
-
- for (i = 0; i < num; i++)
- rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
-
- return 0;
-}
-
-int orinoco_hw_trigger_scan(struct orinoco_private *priv,
- const struct cfg80211_ssid *ssid)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- unsigned long flags;
- int err = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Scanning with port 0 disabled would fail */
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- /* In monitor mode, the scan results are always empty.
- * Probe responses are passed to the driver as received
- * frames and could be processed in software. */
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (priv->has_hostscan) {
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN_SYMBOL,
- HERMES_HOSTSCAN_SYMBOL_ONCE |
- HERMES_HOSTSCAN_SYMBOL_BCAST);
- break;
- case FIRMWARE_TYPE_INTERSIL: {
- __le16 req[3];
-
- req[0] = cpu_to_le16(0x3fff); /* All channels */
- req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
- req[2] = 0; /* Any ESSID */
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN, &req);
- break;
- }
- case FIRMWARE_TYPE_AGERE:
- if (ssid->ssid_len > 0) {
- struct hermes_idstring idbuf;
- size_t len = ssid->ssid_len;
-
- idbuf.len = cpu_to_le16(len);
- memcpy(idbuf.val, ssid->ssid, len);
-
- err = hw->ops->write_ltv(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- HERMES_BYTES_TO_RECLEN(len + 2),
- &idbuf);
- } else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- 0); /* Any ESSID */
- if (err)
- break;
-
- if (priv->has_ext_scan) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANCHANNELS2GHZ,
- 0x7FFF);
- if (err)
- goto out;
-
- err = hermes_inquire(hw,
- HERMES_INQ_CHANNELINFO);
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- break;
- }
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-/* Disassociate from node with BSSID addr */
-int orinoco_hw_disassociate(struct orinoco_private *priv,
- u8 *addr, u16 reason_code)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- struct {
- u8 addr[ETH_ALEN];
- __le16 reason_code;
- } __packed buf;
-
- /* Currently only supported by WPA enabled Agere fw */
- if (!priv->has_wpa)
- return -EOPNOTSUPP;
-
- memcpy(buf.addr, addr, ETH_ALEN);
- buf.reason_code = cpu_to_le16(reason_code);
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFDISASSOCIATE,
- &buf);
- return err;
-}
-
-int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
- u8 *addr)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, addr);
-
- return err;
-}
diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h
deleted file mode 100644
index da5804dbdf34..000000000000
--- a/drivers/net/wireless/intersil/orinoco/hw.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Encapsulate basic setting changes on Hermes hardware
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_HW_H_
-#define _ORINOCO_HW_H_
-
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-
-/* Hardware BAPs */
-#define USER_BAP 0
-#define IRQ_BAP 1
-
-/* WEP key sizes */
-#define SMALL_KEY_SIZE 5
-#define LARGE_KEY_SIZE 13
-
-/* Number of supported channels */
-#define NUM_CHANNELS 14
-
-/* Forward declarations */
-struct orinoco_private;
-
-int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
- size_t fw_name_len, u32 *hw_ver);
-int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
-int orinoco_hw_allocate_fid(struct orinoco_private *priv);
-int orinoco_get_bitratemode(int bitrate, int automatic);
-void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
-
-int orinoco_hw_program_rids(struct orinoco_private *priv);
-int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
-int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
-int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
-int __orinoco_hw_set_wap(struct orinoco_private *priv);
-int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
-int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
- int set_tx, const u8 *key, size_t key_len,
- const u8 *rsc, size_t rsc_len,
- const u8 *tsc, size_t tsc_len);
-int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
-int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
- struct net_device *dev,
- int mc_count, int promisc);
-int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
- char buf[IW_ESSID_MAX_SIZE + 1]);
-int orinoco_hw_get_freq(struct orinoco_private *priv);
-int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
- int *numrates, s32 *rates, int max);
-int orinoco_hw_trigger_scan(struct orinoco_private *priv,
- const struct cfg80211_ssid *ssid);
-int orinoco_hw_disassociate(struct orinoco_private *priv,
- u8 *addr, u16 reason_code);
-int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
- u8 *addr);
-
-#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c
deleted file mode 100644
index 7df88d20ff3d..000000000000
--- a/drivers/net/wireless/intersil/orinoco/main.c
+++ /dev/null
@@ -1,2414 +0,0 @@
-/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c)
- *
- * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
- * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
- *
- * Current maintainers (as of 29 September 2003) are:
- * Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corporation 2001-2003.
- * Copyright (C) 2000 David Gibson, Linuxcare Australia.
- * With some help from :
- * Copyright (C) 2001 Jean Tourrilhes, HP Labs
- * Copyright (C) 2001 Benjamin Herrenschmidt
- *
- * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
- *
- * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
- * AT fasta.fh-dortmund.de>
- * http://www.stud.fh-dortmund.de/~andy/wvlan/
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds AT users.sourceforge.net>. Portions created by David
- * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights
- * Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL. */
-
-/*
- * TODO
- * o Handle de-encapsulation within network layer, provide 802.11
- * headers (patch from Thomas 'Dent' Mirlacher)
- * o Fix possible races in SPY handling.
- * o Disconnect wireless extensions from fundamental configuration.
- * o (maybe) Software WEP support (patch from Stano Meduna).
- * o (maybe) Use multiple Tx buffers - driver handling queue
- * rather than firmware.
- */
-
-/* Locking and synchronization:
- *
- * The basic principle is that everything is serialized through a
- * single spinlock, priv->lock. The lock is used in user, bh and irq
- * context, so when taken outside hardirq context it should always be
- * taken with interrupts disabled. The lock protects both the
- * hardware and the struct orinoco_private.
- *
- * Another flag, priv->hw_unavailable indicates that the hardware is
- * unavailable for an extended period of time (e.g. suspended, or in
- * the middle of a hard reset). This flag is protected by the
- * spinlock. All code which touches the hardware should check the
- * flag after taking the lock, and if it is set, give up on whatever
- * they are doing and drop the lock again. The orinoco_lock()
- * function handles this (it unlocks and returns -EBUSY if
- * hw_unavailable is non-zero).
- */
-
-#define DRIVER_NAME "orinoco"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/suspend.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <net/iw_handler.h>
-#include <net/cfg80211.h>
-
-#include "hermes_rid.h"
-#include "hermes_dld.h"
-#include "hw.h"
-#include "scan.h"
-#include "mic.h"
-#include "fw.h"
-#include "wext.h"
-#include "cfg.h"
-#include "main.h"
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module information */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & "
- "David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based "
- "and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Level of debugging. Used in the macros in orinoco.h */
-#ifdef ORINOCO_DEBUG
-int orinoco_debug = ORINOCO_DEBUG;
-EXPORT_SYMBOL(orinoco_debug);
-module_param(orinoco_debug, int, 0644);
-MODULE_PARM_DESC(orinoco_debug, "Debug level");
-#endif
-
-static bool suppress_linkstatus; /* = 0 */
-module_param(suppress_linkstatus, bool, 0644);
-MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
-
-static int ignore_disconnect; /* = 0 */
-module_param(ignore_disconnect, int, 0644);
-MODULE_PARM_DESC(ignore_disconnect,
- "Don't report lost link to the network layer");
-
-int force_monitor; /* = 0 */
-module_param(force_monitor, int, 0644);
-MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
-
-/********************************************************************/
-/* Internal constants */
-/********************************************************************/
-
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
-
-#define ORINOCO_MIN_MTU 256
-#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-
-#define MAX_IRQLOOPS_PER_IRQ 10
-#define MAX_IRQLOOPS_PER_JIFFY (20000 / HZ) /* Based on a guestimate of
- * how many events the
- * device could
- * legitimately generate */
-
-#define DUMMY_FID 0xFFFF
-
-/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
- HERMES_MAX_MULTICAST : 0)*/
-#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST)
-
-#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \
- | HERMES_EV_TX | HERMES_EV_TXEXC \
- | HERMES_EV_WTERR | HERMES_EV_INFO \
- | HERMES_EV_INFDROP)
-
-/********************************************************************/
-/* Data types */
-/********************************************************************/
-
-/* Beginning of the Tx descriptor, used in TxExc handling */
-struct hermes_txexc_data {
- struct hermes_tx_descriptor desc;
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
-} __packed;
-
-/* Rx frame header except compatibility 802.3 header */
-struct hermes_rx_descriptor {
- /* Control */
- __le16 status;
- __le32 time;
- u8 silence;
- u8 signal;
- u8 rate;
- u8 rxflow;
- __le32 reserved;
-
- /* 802.11 header */
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
-
- /* Data length */
- __le16 data_len;
-} __packed;
-
-struct orinoco_rx_data {
- struct hermes_rx_descriptor *desc;
- struct sk_buff *skb;
- struct list_head list;
-};
-
-struct orinoco_scan_data {
- void *buf;
- size_t len;
- int type;
- struct list_head list;
-};
-
-/********************************************************************/
-/* Function prototypes */
-/********************************************************************/
-
-static int __orinoco_set_multicast_list(struct net_device *dev);
-static int __orinoco_up(struct orinoco_private *priv);
-static int __orinoco_down(struct orinoco_private *priv);
-static int __orinoco_commit(struct orinoco_private *priv);
-
-/********************************************************************/
-/* Internal helper functions */
-/********************************************************************/
-
-void set_port_type(struct orinoco_private *priv)
-{
- switch (priv->iw_mode) {
- case NL80211_IFTYPE_STATION:
- priv->port_type = 1;
- priv->createibss = 0;
- break;
- case NL80211_IFTYPE_ADHOC:
- if (priv->prefer_port3) {
- priv->port_type = 3;
- priv->createibss = 0;
- } else {
- priv->port_type = priv->ibss_port;
- priv->createibss = 1;
- }
- break;
- case NL80211_IFTYPE_MONITOR:
- priv->port_type = 3;
- priv->createibss = 0;
- break;
- default:
- printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
- priv->ndev->name);
- }
-}
-
-/********************************************************************/
-/* Device methods */
-/********************************************************************/
-
-int orinoco_open(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = __orinoco_up(priv);
-
- if (!err)
- priv->open = 1;
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-EXPORT_SYMBOL(orinoco_open);
-
-int orinoco_stop(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int err = 0;
-
- /* We mustn't use orinoco_lock() here, because we need to be
- able to close the interface even if hw_unavailable is set
- (e.g. as we're released after a PC Card removal) */
- orinoco_lock_irq(priv);
-
- priv->open = 0;
-
- err = __orinoco_down(priv);
-
- orinoco_unlock_irq(priv);
-
- return err;
-}
-EXPORT_SYMBOL(orinoco_stop);
-
-void orinoco_set_multicast_list(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0) {
- printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
- "called when hw_unavailable\n", dev->name);
- return;
- }
-
- __orinoco_set_multicast_list(dev);
- orinoco_unlock(priv, &flags);
-}
-EXPORT_SYMBOL(orinoco_set_multicast_list);
-
-int orinoco_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- /* MTU + encapsulation + header length */
- if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
- (priv->nicbuf_size - ETH_HLEN))
- return -EINVAL;
-
- dev->mtu = new_mtu;
-
- return 0;
-}
-EXPORT_SYMBOL(orinoco_change_mtu);
-
-/********************************************************************/
-/* Tx path */
-/********************************************************************/
-
-/* Add encapsulation and MIC to the existing SKB.
- * The main xmit routine will then send the whole lot to the card.
- * Need 8 bytes headroom
- * Need 8 bytes tailroom
- *
- * With encapsulated ethernet II frame
- * --------
- * 803.3 header (14 bytes)
- * dst[6]
- * -------- src[6]
- * 803.3 header (14 bytes) len[2]
- * dst[6] 803.2 header (8 bytes)
- * src[6] encaps[6]
- * len[2] <- leave alone -> len[2]
- * -------- -------- <-- 0
- * Payload Payload
- * ... ...
- *
- * -------- --------
- * MIC (8 bytes)
- * --------
- *
- * returns 0 on success, -ENOMEM on error.
- */
-int orinoco_process_xmit_skb(struct sk_buff *skb,
- struct net_device *dev,
- struct orinoco_private *priv,
- int *tx_control,
- u8 *mic_buf)
-{
- struct orinoco_tkip_key *key;
- struct ethhdr *eh;
- int do_mic;
-
- key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
-
- do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
- (key != NULL));
-
- if (do_mic)
- *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
- HERMES_TXCTRL_MIC;
-
- eh = (struct ethhdr *)skb->data;
-
- /* Encapsulate Ethernet-II frames */
- if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
- struct header_struct {
- struct ethhdr eth; /* 802.3 header */
- u8 encap[6]; /* 802.2 header */
- } __packed hdr;
- int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
-
- if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
- if (net_ratelimit())
- printk(KERN_ERR
- "%s: Not enough headroom for 802.2 headers %d\n",
- dev->name, skb_headroom(skb));
- return -ENOMEM;
- }
-
- /* Fill in new header */
- memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
- hdr.eth.h_proto = htons(len);
- memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
- /* Make room for the new header, and copy it in */
- eh = skb_push(skb, ENCAPS_OVERHEAD);
- memcpy(eh, &hdr, sizeof(hdr));
- }
-
- /* Calculate Michael MIC */
- if (do_mic) {
- size_t len = skb->len - ETH_HLEN;
- u8 *mic = &mic_buf[0];
-
- /* Have to write to an even address, so copy the spare
- * byte across */
- if (skb->len % 2) {
- *mic = skb->data[skb->len - 1];
- mic++;
- }
-
- orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
- eh->h_dest, eh->h_source, 0 /* priority */,
- skb->data + ETH_HLEN,
- len, mic);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(orinoco_process_xmit_skb);
-
-static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct hermes *hw = &priv->hw;
- int err = 0;
- u16 txfid = priv->txfid;
- int tx_control;
- unsigned long flags;
- u8 mic_buf[MICHAEL_MIC_LEN + 1];
-
- if (!netif_running(dev)) {
- printk(KERN_ERR "%s: Tx on stopped device!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (netif_queue_stopped(dev)) {
- printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (orinoco_lock(priv, &flags) != 0) {
- printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (!netif_carrier_ok(dev) ||
- (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
- /* Oops, the firmware hasn't established a connection,
- silently drop the packet (this seems to be the
- safest approach). */
- goto drop;
- }
-
- /* Check packet length */
- if (skb->len < ETH_HLEN)
- goto drop;
-
- tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
-
- err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
- &mic_buf[0]);
- if (err)
- goto drop;
-
- if (priv->has_alt_txcntl) {
- /* WPA enabled firmwares have tx_cntl at the end of
- * the 802.11 header. So write zeroed descriptor and
- * 802.11 header at the same time
- */
- char desc[HERMES_802_3_OFFSET];
- __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
-
- memset(&desc, 0, sizeof(desc));
-
- *txcntl = cpu_to_le16(tx_control);
- err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
- txfid, 0);
- if (err) {
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d writing Tx "
- "descriptor to BAP\n", dev->name, err);
- goto busy;
- }
- } else {
- struct hermes_tx_descriptor desc;
-
- memset(&desc, 0, sizeof(desc));
-
- desc.tx_control = cpu_to_le16(tx_control);
- err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
- txfid, 0);
- if (err) {
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d writing Tx "
- "descriptor to BAP\n", dev->name, err);
- goto busy;
- }
-
- /* Clear the 802.11 header and data length fields - some
- * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
- * if this isn't done. */
- hermes_clear_words(hw, HERMES_DATA0,
- HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
- }
-
- err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
- txfid, HERMES_802_3_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
- dev->name, err);
- goto busy;
- }
-
- if (tx_control & HERMES_TXCTRL_MIC) {
- size_t offset = HERMES_802_3_OFFSET + skb->len;
- size_t len = MICHAEL_MIC_LEN;
-
- if (offset % 2) {
- offset--;
- len++;
- }
- err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
- txfid, offset);
- if (err) {
- printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
- dev->name, err);
- goto busy;
- }
- }
-
- /* Finally, we actually initiate the send */
- netif_stop_queue(dev);
-
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
- txfid, NULL);
- if (err) {
- netif_start_queue(dev);
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d transmitting packet\n",
- dev->name, err);
- goto busy;
- }
-
- stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
- goto ok;
-
- drop:
- stats->tx_errors++;
- stats->tx_dropped++;
-
- ok:
- orinoco_unlock(priv, &flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-
- busy:
- if (err == -EIO)
- schedule_work(&priv->reset_work);
- orinoco_unlock(priv, &flags);
- return NETDEV_TX_BUSY;
-}
-
-static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u16 fid = hermes_read_regn(hw, ALLOCFID);
-
- if (fid != priv->txfid) {
- if (fid != DUMMY_FID)
- printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
- dev->name, fid);
- return;
- }
-
- hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw)
-{
- dev->stats.tx_packets++;
-
- netif_wake_queue(dev);
-
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw)
-{
- struct net_device_stats *stats = &dev->stats;
- u16 fid = hermes_read_regn(hw, TXCOMPLFID);
- u16 status;
- struct hermes_txexc_data hdr;
- int err = 0;
-
- if (fid == DUMMY_FID)
- return; /* Nothing's really happened */
-
- /* Read part of the frame header - we need status and addr1 */
- err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
- sizeof(struct hermes_txexc_data),
- fid, 0);
-
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
- stats->tx_errors++;
-
- if (err) {
- printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
- "(FID=%04X error %d)\n",
- dev->name, fid, err);
- return;
- }
-
- DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
- err, fid);
-
- /* We produce a TXDROP event only for retry or lifetime
- * exceeded, because that's the only status that really mean
- * that this particular node went away.
- * Other errors means that *we* screwed up. - Jean II */
- status = le16_to_cpu(hdr.desc.status);
- if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
- union iwreq_data wrqu;
-
- /* Copy 802.11 dest address.
- * We use the 802.11 header because the frame may
- * not be 802.3 or may be mangled...
- * In Ad-Hoc mode, it will be the node address.
- * In managed mode, it will be most likely the AP addr
- * User space will figure out how to convert it to
- * whatever it needs (IP address or else).
- * - Jean II */
- memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
- }
-
- netif_wake_queue(dev);
-}
-
-void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct hermes *hw = &priv->hw;
-
- printk(KERN_WARNING "%s: Tx timeout! "
- "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
- dev->name, hermes_read_regn(hw, ALLOCFID),
- hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
-
- stats->tx_errors++;
-
- schedule_work(&priv->reset_work);
-}
-EXPORT_SYMBOL(orinoco_tx_timeout);
-
-/********************************************************************/
-/* Rx path (data frames) */
-/********************************************************************/
-
-/* Does the frame have a SNAP header indicating it should be
- * de-encapsulated to Ethernet-II? */
-static inline int is_ethersnap(void *_hdr)
-{
- u8 *hdr = _hdr;
-
- /* We de-encapsulate all packets which, a) have SNAP headers
- * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
- * and where b) the OUI of the SNAP header is 00:00:00 or
- * 00:00:f8 - we need both because different APs appear to use
- * different OUIs for some reason */
- return (memcmp(hdr, &encaps_hdr, 5) == 0)
- && ((hdr[5] == 0x00) || (hdr[5] == 0xf8));
-}
-
-static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
- int level, int noise)
-{
- struct iw_quality wstats;
- wstats.level = level - 0x95;
- wstats.noise = noise - 0x95;
- wstats.qual = (level > noise) ? (level - noise) : 0;
- wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(dev, mac, &wstats);
-}
-
-static void orinoco_stat_gather(struct net_device *dev,
- struct sk_buff *skb,
- struct hermes_rx_descriptor *desc)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- /* Using spy support with lots of Rx packets, like in an
- * infrastructure (AP), will really slow down everything, because
- * the MAC address must be compared to each entry of the spy list.
- * If the user really asks for it (set some address in the
- * spy list), we do it, but he will pay the price.
- * Note that to get here, you need both WIRELESS_SPY
- * compiled in AND some addresses in the list !!!
- */
- /* Note : gcc will optimise the whole section away if
- * WIRELESS_SPY is not defined... - Jean II */
- if (SPY_NUMBER(priv)) {
- orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
- desc->signal, desc->silence);
- }
-}
-
-/*
- * orinoco_rx_monitor - handle received monitor frames.
- *
- * Arguments:
- * dev network device
- * rxfid received FID
- * desc rx descriptor of the frame
- *
- * Call context: interrupt
- */
-static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
- struct hermes_rx_descriptor *desc)
-{
- u32 hdrlen = 30; /* return full header by default */
- u32 datalen = 0;
- u16 fc;
- int err;
- int len;
- struct sk_buff *skb;
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct hermes *hw = &priv->hw;
-
- len = le16_to_cpu(desc->data_len);
-
- /* Determine the size of the header and the data */
- fc = le16_to_cpu(desc->frame_ctl);
- switch (fc & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_TODS)
- && (fc & IEEE80211_FCTL_FROMDS))
- hdrlen = 30;
- else
- hdrlen = 24;
- datalen = len;
- break;
- case IEEE80211_FTYPE_MGMT:
- hdrlen = 24;
- datalen = len;
- break;
- case IEEE80211_FTYPE_CTL:
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_PSPOLL:
- case IEEE80211_STYPE_RTS:
- case IEEE80211_STYPE_CFEND:
- case IEEE80211_STYPE_CFENDACK:
- hdrlen = 16;
- break;
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = 10;
- break;
- }
- break;
- default:
- /* Unknown frame type */
- break;
- }
-
- /* sanity check the length */
- if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
- printk(KERN_DEBUG "%s: oversized monitor frame, "
- "data length = %d\n", dev->name, datalen);
- stats->rx_length_errors++;
- goto update_stats;
- }
-
- skb = dev_alloc_skb(hdrlen + datalen);
- if (!skb) {
- printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
- dev->name);
- goto update_stats;
- }
-
- /* Copy the 802.11 header to the skb */
- skb_put_data(skb, &(desc->frame_ctl), hdrlen);
- skb_reset_mac_header(skb);
-
- /* If any, copy the data from the card to the skb */
- if (datalen > 0) {
- err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
- ALIGN(datalen, 2), rxfid,
- HERMES_802_2_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: error %d reading monitor frame\n",
- dev->name, err);
- goto drop;
- }
- }
-
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_NONE;
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_802_2);
-
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
-
- netif_rx(skb);
- return;
-
- drop:
- dev_kfree_skb_irq(skb);
- update_stats:
- stats->rx_errors++;
- stats->rx_dropped++;
-}
-
-void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct iw_statistics *wstats = &priv->wstats;
- struct sk_buff *skb = NULL;
- u16 rxfid, status;
- int length;
- struct hermes_rx_descriptor *desc;
- struct orinoco_rx_data *rx_data;
- int err;
-
- desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if (!desc)
- goto update_stats;
-
- rxfid = hermes_read_regn(hw, RXFID);
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
- rxfid, 0);
- if (err) {
- printk(KERN_ERR "%s: error %d reading Rx descriptor. "
- "Frame dropped.\n", dev->name, err);
- goto update_stats;
- }
-
- status = le16_to_cpu(desc->status);
-
- if (status & HERMES_RXSTAT_BADCRC) {
- DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
- dev->name);
- stats->rx_crc_errors++;
- goto update_stats;
- }
-
- /* Handle frames in monitor mode */
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- orinoco_rx_monitor(dev, rxfid, desc);
- goto out;
- }
-
- if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
- DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
- dev->name);
- wstats->discard.code++;
- goto update_stats;
- }
-
- length = le16_to_cpu(desc->data_len);
-
- /* Sanity checks */
- if (length < 3) { /* No for even an 802.2 LLC header */
- /* At least on Symbol firmware with PCF we get quite a
- lot of these legitimately - Poll frames with no
- data. */
- goto out;
- }
- if (length > IEEE80211_MAX_DATA_LEN) {
- printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
- dev->name, length);
- stats->rx_length_errors++;
- goto update_stats;
- }
-
- /* Payload size does not include Michael MIC. Increase payload
- * size to read it together with the data. */
- if (status & HERMES_RXSTAT_MIC)
- length += MICHAEL_MIC_LEN;
-
- /* We need space for the packet data itself, plus an ethernet
- header, plus 2 bytes so we can align the IP header on a
- 32bit boundary, plus 1 byte so we can read in odd length
- packets from the card, which has an IO granularity of 16
- bits */
- skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1);
- if (!skb) {
- printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
- dev->name);
- goto update_stats;
- }
-
- /* We'll prepend the header, so reserve space for it. The worst
- case is no decapsulation, when 802.3 header is prepended and
- nothing is removed. 2 is for aligning the IP header. */
- skb_reserve(skb, ETH_HLEN + 2);
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
- ALIGN(length, 2), rxfid,
- HERMES_802_2_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: error %d reading frame. "
- "Frame dropped.\n", dev->name, err);
- goto drop;
- }
-
- /* Add desc and skb to rx queue */
- rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
- if (!rx_data)
- goto drop;
-
- rx_data->desc = desc;
- rx_data->skb = skb;
- list_add_tail(&rx_data->list, &priv->rx_list);
- tasklet_schedule(&priv->rx_tasklet);
-
- return;
-
-drop:
- dev_kfree_skb_irq(skb);
-update_stats:
- stats->rx_errors++;
- stats->rx_dropped++;
-out:
- kfree(desc);
-}
-EXPORT_SYMBOL(__orinoco_ev_rx);
-
-static void orinoco_rx(struct net_device *dev,
- struct hermes_rx_descriptor *desc,
- struct sk_buff *skb)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- u16 status, fc;
- int length;
- struct ethhdr *hdr;
-
- status = le16_to_cpu(desc->status);
- length = le16_to_cpu(desc->data_len);
- fc = le16_to_cpu(desc->frame_ctl);
-
- /* Calculate and check MIC */
- if (status & HERMES_RXSTAT_MIC) {
- struct orinoco_tkip_key *key;
- int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
- HERMES_MIC_KEY_ID_SHIFT);
- u8 mic[MICHAEL_MIC_LEN];
- u8 *rxmic;
- u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
- desc->addr3 : desc->addr2;
-
- /* Extract Michael MIC from payload */
- rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
-
- skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
- length -= MICHAEL_MIC_LEN;
-
- key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
-
- if (!key) {
- printk(KERN_WARNING "%s: Received encrypted frame from "
- "%pM using key %i, but key is not installed\n",
- dev->name, src, key_id);
- goto drop;
- }
-
- orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
- 0, /* priority or QoS? */
- skb->data, skb->len, &mic[0]);
-
- if (memcmp(mic, rxmic,
- MICHAEL_MIC_LEN)) {
- union iwreq_data wrqu;
- struct iw_michaelmicfailure wxmic;
-
- printk(KERN_WARNING "%s: "
- "Invalid Michael MIC in data frame from %pM, "
- "using key %i\n",
- dev->name, src, key_id);
-
- /* TODO: update stats */
-
- /* Notify userspace */
- memset(&wxmic, 0, sizeof(wxmic));
- wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
- wxmic.flags |= (desc->addr1[0] & 1) ?
- IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
- wxmic.src_addr.sa_family = ARPHRD_ETHER;
- memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
-
- (void) orinoco_hw_get_tkip_iv(priv, key_id,
- &wxmic.tsc[0]);
-
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = sizeof(wxmic);
- wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
- (char *) &wxmic);
-
- goto drop;
- }
- }
-
- /* Handle decapsulation
- * In most cases, the firmware tell us about SNAP frames.
- * For some reason, the SNAP frames sent by LinkSys APs
- * are not properly recognised by most firmwares.
- * So, check ourselves */
- if (length >= ENCAPS_OVERHEAD &&
- (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
- ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
- is_ethersnap(skb->data))) {
- /* These indicate a SNAP within 802.2 LLC within
- 802.11 frame which we'll need to de-encapsulate to
- the original EthernetII frame. */
- hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
- } else {
- /* 802.3 frame - prepend 802.3 header as is */
- hdr = skb_push(skb, ETH_HLEN);
- hdr->h_proto = htons(length);
- }
- memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
- if (fc & IEEE80211_FCTL_FROMDS)
- memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
- else
- memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
-
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- if (fc & IEEE80211_FCTL_TODS)
- skb->pkt_type = PACKET_OTHERHOST;
-
- /* Process the wireless stats if needed */
- orinoco_stat_gather(dev, skb, desc);
-
- /* Pass the packet to the networking stack */
- netif_rx(skb);
- stats->rx_packets++;
- stats->rx_bytes += length;
-
- return;
-
- drop:
- dev_kfree_skb(skb);
- stats->rx_errors++;
- stats->rx_dropped++;
-}
-
-static void orinoco_rx_isr_tasklet(struct tasklet_struct *t)
-{
- struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet);
- struct net_device *dev = priv->ndev;
- struct orinoco_rx_data *rx_data, *temp;
- struct hermes_rx_descriptor *desc;
- struct sk_buff *skb;
- unsigned long flags;
-
- /* orinoco_rx requires the driver lock, and we also need to
- * protect priv->rx_list, so just hold the lock over the
- * lot.
- *
- * If orinoco_lock fails, we've unplugged the card. In this
- * case just abort. */
- if (orinoco_lock(priv, &flags) != 0)
- return;
-
- /* extract desc and skb from queue */
- list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
- desc = rx_data->desc;
- skb = rx_data->skb;
- list_del(&rx_data->list);
- kfree(rx_data);
-
- orinoco_rx(dev, desc, skb);
-
- kfree(desc);
- }
-
- orinoco_unlock(priv, &flags);
-}
-
-/********************************************************************/
-/* Rx path (info frames) */
-/********************************************************************/
-
-static void print_linkstatus(struct net_device *dev, u16 status)
-{
- char *s;
-
- if (suppress_linkstatus)
- return;
-
- switch (status) {
- case HERMES_LINKSTATUS_NOT_CONNECTED:
- s = "Not Connected";
- break;
- case HERMES_LINKSTATUS_CONNECTED:
- s = "Connected";
- break;
- case HERMES_LINKSTATUS_DISCONNECTED:
- s = "Disconnected";
- break;
- case HERMES_LINKSTATUS_AP_CHANGE:
- s = "AP Changed";
- break;
- case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
- s = "AP Out of Range";
- break;
- case HERMES_LINKSTATUS_AP_IN_RANGE:
- s = "AP In Range";
- break;
- case HERMES_LINKSTATUS_ASSOC_FAILED:
- s = "Association Failed";
- break;
- default:
- s = "UNKNOWN";
- }
-
- printk(KERN_DEBUG "%s: New link status: %s (%04x)\n",
- dev->name, s, status);
-}
-
-/* Search scan results for requested BSSID, join it if found */
-static void orinoco_join_ap(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, join_work);
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
- unsigned long flags;
- struct join_req {
- u8 bssid[ETH_ALEN];
- __le16 channel;
- } __packed req;
- const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
- struct prism2_scan_apinfo *atom = NULL;
- int offset = 4;
- int found = 0;
- u8 *buf;
- u16 len;
-
- /* Allocate buffer for scan results */
- buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
- if (!buf)
- return;
-
- if (orinoco_lock(priv, &flags) != 0)
- goto fail_lock;
-
- /* Sanity checks in case user changed something in the meantime */
- if (!priv->bssid_fixed)
- goto out;
-
- if (strlen(priv->desired_essid) == 0)
- goto out;
-
- /* Read scan results from the firmware */
- err = hw->ops->read_ltv(hw, USER_BAP,
- HERMES_RID_SCANRESULTSTABLE,
- MAX_SCAN_LEN, &len, buf);
- if (err) {
- printk(KERN_ERR "%s: Cannot read scan results\n",
- dev->name);
- goto out;
- }
-
- len = HERMES_RECLEN_TO_BYTES(len);
-
- /* Go through the scan results looking for the channel of the AP
- * we were requested to join */
- for (; offset + atom_len <= len; offset += atom_len) {
- atom = (struct prism2_scan_apinfo *) (buf + offset);
- if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- DEBUG(1, "%s: Requested AP not found in scan results\n",
- dev->name);
- goto out;
- }
-
- memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
- req.channel = atom->channel; /* both are little-endian */
- err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
- &req);
- if (err)
- printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
-
- out:
- orinoco_unlock(priv, &flags);
-
- fail_lock:
- kfree(buf);
-}
-
-/* Send new BSSID to userspace */
-static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- union iwreq_data wrqu;
- int err;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
- if (err != 0)
- return;
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- union iwreq_data wrqu;
- int err;
- u8 buf[88];
- u8 *ie;
-
- if (!priv->has_wpa)
- return;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
- sizeof(buf), NULL, &buf);
- if (err != 0)
- return;
-
- ie = orinoco_get_wpa_ie(buf, sizeof(buf));
- if (ie) {
- int rem = sizeof(buf) - (ie - &buf[0]);
- wrqu.data.length = ie[1] + 2;
- if (wrqu.data.length > rem)
- wrqu.data.length = rem;
-
- if (wrqu.data.length)
- /* Send event to user space */
- wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
- }
-}
-
-static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- union iwreq_data wrqu;
- int err;
- u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
- u8 *ie;
-
- if (!priv->has_wpa)
- return;
-
- err = hw->ops->read_ltv(hw, USER_BAP,
- HERMES_RID_CURRENT_ASSOC_RESP_INFO,
- sizeof(buf), NULL, &buf);
- if (err != 0)
- return;
-
- ie = orinoco_get_wpa_ie(buf, sizeof(buf));
- if (ie) {
- int rem = sizeof(buf) - (ie - &buf[0]);
- wrqu.data.length = ie[1] + 2;
- if (wrqu.data.length > rem)
- wrqu.data.length = rem;
-
- if (wrqu.data.length)
- /* Send event to user space */
- wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
- }
-}
-
-static void orinoco_send_wevents(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, wevent_work);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return;
-
- orinoco_send_assocreqie_wevent(priv);
- orinoco_send_assocrespie_wevent(priv);
- orinoco_send_bssid_wevent(priv);
-
- orinoco_unlock(priv, &flags);
-}
-
-static void qbuf_scan(struct orinoco_private *priv, void *buf,
- int len, int type)
-{
- struct orinoco_scan_data *sd;
- unsigned long flags;
-
- sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
- if (!sd)
- return;
-
- sd->buf = buf;
- sd->len = len;
- sd->type = type;
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- list_add_tail(&sd->list, &priv->scan_list);
- spin_unlock_irqrestore(&priv->scan_lock, flags);
-
- schedule_work(&priv->process_scan);
-}
-
-static void qabort_scan(struct orinoco_private *priv)
-{
- struct orinoco_scan_data *sd;
- unsigned long flags;
-
- sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
- if (!sd)
- return;
-
- sd->len = -1; /* Abort */
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- list_add_tail(&sd->list, &priv->scan_list);
- spin_unlock_irqrestore(&priv->scan_lock, flags);
-
- schedule_work(&priv->process_scan);
-}
-
-static void orinoco_process_scan_results(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, process_scan);
- struct orinoco_scan_data *sd, *temp;
- unsigned long flags;
- void *buf;
- int len;
- int type;
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
-
- buf = sd->buf;
- len = sd->len;
- type = sd->type;
-
- list_del(&sd->list);
- spin_unlock_irqrestore(&priv->scan_lock, flags);
- kfree(sd);
-
- if (len > 0) {
- if (type == HERMES_INQ_CHANNELINFO)
- orinoco_add_extscan_result(priv, buf, len);
- else
- orinoco_add_hostscan_results(priv, buf, len);
-
- kfree(buf);
- } else {
- /* Either abort or complete the scan */
- orinoco_scan_done(priv, (len < 0));
- }
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- }
- spin_unlock_irqrestore(&priv->scan_lock, flags);
-}
-
-void __orinoco_ev_info(struct net_device *dev, struct hermes *hw)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u16 infofid;
- struct {
- __le16 len;
- __le16 type;
- } __packed info;
- int len, type;
- int err;
-
- /* This is an answer to an INQUIRE command that we did earlier,
- * or an information "event" generated by the card
- * The controller return to us a pseudo frame containing
- * the information in question - Jean II */
- infofid = hermes_read_regn(hw, INFOFID);
-
- /* Read the info frame header - don't try too hard */
- err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
- infofid, 0);
- if (err) {
- printk(KERN_ERR "%s: error %d reading info frame. "
- "Frame dropped.\n", dev->name, err);
- return;
- }
-
- len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
- type = le16_to_cpu(info.type);
-
- switch (type) {
- case HERMES_INQ_TALLIES: {
- struct hermes_tallies_frame tallies;
- struct iw_statistics *wstats = &priv->wstats;
-
- if (len > sizeof(tallies)) {
- printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
- dev->name, len);
- len = sizeof(tallies);
- }
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
- infofid, sizeof(info));
- if (err)
- break;
-
- /* Increment our various counters */
- /* wstats->discard.nwid - no wrong BSSID stuff */
- wstats->discard.code +=
- le16_to_cpu(tallies.RxWEPUndecryptable);
- if (len == sizeof(tallies))
- wstats->discard.code +=
- le16_to_cpu(tallies.RxDiscards_WEPICVError) +
- le16_to_cpu(tallies.RxDiscards_WEPExcluded);
- wstats->discard.misc +=
- le16_to_cpu(tallies.TxDiscardsWrongSA);
- wstats->discard.fragment +=
- le16_to_cpu(tallies.RxMsgInBadMsgFragments);
- wstats->discard.retries +=
- le16_to_cpu(tallies.TxRetryLimitExceeded);
- /* wstats->miss.beacon - no match */
- }
- break;
- case HERMES_INQ_LINKSTATUS: {
- struct hermes_linkstatus linkstatus;
- u16 newstatus;
- int connected;
-
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
- break;
-
- if (len != sizeof(linkstatus)) {
- printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
- dev->name, len);
- break;
- }
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
- infofid, sizeof(info));
- if (err)
- break;
- newstatus = le16_to_cpu(linkstatus.linkstatus);
-
- /* Symbol firmware uses "out of range" to signal that
- * the hostscan frame can be requested. */
- if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
- priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
- priv->has_hostscan && priv->scan_request) {
- hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
- break;
- }
-
- connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
- || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
- || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
-
- if (connected)
- netif_carrier_on(dev);
- else if (!ignore_disconnect)
- netif_carrier_off(dev);
-
- if (newstatus != priv->last_linkstatus) {
- priv->last_linkstatus = newstatus;
- print_linkstatus(dev, newstatus);
- /* The info frame contains only one word which is the
- * status (see hermes.h). The status is pretty boring
- * in itself, that's why we export the new BSSID...
- * Jean II */
- schedule_work(&priv->wevent_work);
- }
- }
- break;
- case HERMES_INQ_SCAN:
- if (!priv->scan_request && priv->bssid_fixed &&
- priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
- schedule_work(&priv->join_work);
- break;
- }
- fallthrough;
- case HERMES_INQ_HOSTSCAN:
- case HERMES_INQ_HOSTSCAN_SYMBOL: {
- /* Result of a scanning. Contains information about
- * cells in the vicinity - Jean II */
- unsigned char *buf;
-
- /* Sanity check */
- if (len > 4096) {
- printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
- dev->name, len);
- qabort_scan(priv);
- break;
- }
-
- /* Allocate buffer for results */
- buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL) {
- /* No memory, so can't printk()... */
- qabort_scan(priv);
- break;
- }
-
- /* Read scan data */
- err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
- infofid, sizeof(info));
- if (err) {
- kfree(buf);
- qabort_scan(priv);
- break;
- }
-
-#ifdef ORINOCO_DEBUG
- {
- int i;
- printk(KERN_DEBUG "Scan result [%02X", buf[0]);
- for (i = 1; i < (len * 2); i++)
- printk(":%02X", buf[i]);
- printk("]\n");
- }
-#endif /* ORINOCO_DEBUG */
-
- qbuf_scan(priv, buf, len, type);
- }
- break;
- case HERMES_INQ_CHANNELINFO:
- {
- struct agere_ext_scan_info *bss;
-
- if (!priv->scan_request) {
- printk(KERN_DEBUG "%s: Got chaninfo without scan, "
- "len=%d\n", dev->name, len);
- break;
- }
-
- /* An empty result indicates that the scan is complete */
- if (len == 0) {
- qbuf_scan(priv, NULL, len, type);
- break;
- }
-
- /* Sanity check */
- else if (len < (offsetof(struct agere_ext_scan_info,
- data) + 2)) {
- /* Drop this result now so we don't have to
- * keep checking later */
- printk(KERN_WARNING
- "%s: Ext scan results too short (%d bytes)\n",
- dev->name, len);
- break;
- }
-
- bss = kmalloc(len, GFP_ATOMIC);
- if (bss == NULL)
- break;
-
- /* Read scan data */
- err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
- infofid, sizeof(info));
- if (err)
- kfree(bss);
- else
- qbuf_scan(priv, bss, len, type);
-
- break;
- }
- case HERMES_INQ_SEC_STAT_AGERE:
- /* Security status (Agere specific) */
- /* Ignore this frame for now */
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- break;
- fallthrough;
- default:
- printk(KERN_DEBUG "%s: Unknown information frame received: "
- "type 0x%04x, length %d\n", dev->name, type, len);
- /* We don't actually do anything about it */
- break;
- }
-}
-EXPORT_SYMBOL(__orinoco_ev_info);
-
-static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw)
-{
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
-}
-
-/********************************************************************/
-/* Internal hardware control routines */
-/********************************************************************/
-
-static int __orinoco_up(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
-
- netif_carrier_off(dev); /* just to make sure */
-
- err = __orinoco_commit(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d configuring card\n",
- dev->name, err);
- return err;
- }
-
- /* Fire things up again */
- hermes_set_irqmask(hw, ORINOCO_INTEN);
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_ERR "%s: Error %d enabling MAC port\n",
- dev->name, err);
- return err;
- }
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int __orinoco_down(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
-
- netif_stop_queue(dev);
-
- if (!priv->hw_unavailable) {
- if (!priv->broken_disableport) {
- err = hermes_disable_port(hw, 0);
- if (err) {
- /* Some firmwares (e.g. Intersil 1.3.x) seem
- * to have problems disabling the port, oh
- * well, too bad. */
- printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
- dev->name, err);
- priv->broken_disableport = 1;
- }
- }
- hermes_set_irqmask(hw, 0);
- hermes_write_regn(hw, EVACK, 0xffff);
- }
-
- orinoco_scan_done(priv, true);
-
- /* firmware will have to reassociate */
- netif_carrier_off(dev);
- priv->last_linkstatus = 0xffff;
-
- return 0;
-}
-
-static int orinoco_reinit_firmware(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hw->ops->init(hw);
- if (priv->do_fw_download && !err) {
- err = orinoco_download(priv);
- if (err)
- priv->do_fw_download = 0;
- }
- if (!err)
- err = orinoco_hw_allocate_fid(priv);
-
- return err;
-}
-
-static int
-__orinoco_set_multicast_list(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int err = 0;
- int promisc, mc_count;
-
- /* The Hermes doesn't seem to have an allmulti mode, so we go
- * into promiscuous mode and let the upper levels deal. */
- if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
- (netdev_mc_count(dev) > MAX_MULTICAST(priv))) {
- promisc = 1;
- mc_count = 0;
- } else {
- promisc = 0;
- mc_count = netdev_mc_count(dev);
- }
-
- err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc);
-
- return err;
-}
-
-/* This must be called from user context, without locks held - use
- * schedule_work() */
-void orinoco_reset(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, reset_work);
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- /* When the hardware becomes available again, whatever
- * detects that is responsible for re-initializing
- * it. So no need for anything further */
- return;
-
- netif_stop_queue(dev);
-
- /* Shut off interrupts. Depending on what state the hardware
- * is in, this might not work, but we'll try anyway */
- hermes_set_irqmask(hw, 0);
- hermes_write_regn(hw, EVACK, 0xffff);
-
- priv->hw_unavailable++;
- priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
- netif_carrier_off(dev);
-
- orinoco_unlock(priv, &flags);
-
- /* Scanning support: Notify scan cancellation */
- orinoco_scan_done(priv, true);
-
- if (priv->hard_reset) {
- err = (*priv->hard_reset)(priv);
- if (err) {
- printk(KERN_ERR "%s: orinoco_reset: Error %d "
- "performing hard reset\n", dev->name, err);
- goto disable;
- }
- }
-
- err = orinoco_reinit_firmware(priv);
- if (err) {
- printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
- dev->name, err);
- goto disable;
- }
-
- /* This has to be called from user context */
- orinoco_lock_irq(priv);
-
- priv->hw_unavailable--;
-
- /* priv->open or priv->hw_unavailable might have changed while
- * we dropped the lock */
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(priv);
- if (err) {
- printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
- dev->name, err);
- } else
- netif_trans_update(dev);
- }
-
- orinoco_unlock_irq(priv);
-
- return;
- disable:
- hermes_set_irqmask(hw, 0);
- netif_device_detach(dev);
- printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
-}
-
-static int __orinoco_commit(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- int err = 0;
-
- /* If we've called commit, we are reconfiguring or bringing the
- * interface up. Maintaining countermeasures across this would
- * be confusing, so note that we've disabled them. The port will
- * be enabled later in orinoco_commit or __orinoco_up. */
- priv->tkip_cm_active = 0;
-
- err = orinoco_hw_program_rids(priv);
-
- /* FIXME: what about netif_tx_lock */
- (void) __orinoco_set_multicast_list(dev);
-
- return err;
-}
-
-/* Ensures configuration changes are applied. May result in a reset.
- * The caller should hold priv->lock
- */
-int orinoco_commit(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
-
- if (priv->broken_disableport) {
- schedule_work(&priv->reset_work);
- return 0;
- }
-
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port "
- "while reconfiguring card\n", dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_commit(priv);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
- return err;
-}
-
-/********************************************************************/
-/* Interrupt handler */
-/********************************************************************/
-
-static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw)
-{
- printk(KERN_DEBUG "%s: TICK\n", dev->name);
-}
-
-static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw)
-{
- /* This seems to happen a fair bit under load, but ignoring it
- seems to work fine...*/
- printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
- dev->name);
-}
-
-irqreturn_t orinoco_interrupt(int irq, void *dev_id)
-{
- struct orinoco_private *priv = dev_id;
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int count = MAX_IRQLOOPS_PER_IRQ;
- u16 evstat, events;
- /* These are used to detect a runaway interrupt situation.
- *
- * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
- * we panic and shut down the hardware
- */
- /* jiffies value the last time we were called */
- static int last_irq_jiffy; /* = 0 */
- static int loops_this_jiffy; /* = 0 */
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0) {
- /* If hw is unavailable - we don't know if the irq was
- * for us or not */
- return IRQ_HANDLED;
- }
-
- evstat = hermes_read_regn(hw, EVSTAT);
- events = evstat & hw->inten;
- if (!events) {
- orinoco_unlock(priv, &flags);
- return IRQ_NONE;
- }
-
- if (jiffies != last_irq_jiffy)
- loops_this_jiffy = 0;
- last_irq_jiffy = jiffies;
-
- while (events && count--) {
- if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
- printk(KERN_WARNING "%s: IRQ handler is looping too "
- "much! Resetting.\n", dev->name);
- /* Disable interrupts for now */
- hermes_set_irqmask(hw, 0);
- schedule_work(&priv->reset_work);
- break;
- }
-
- /* Check the card hasn't been removed */
- if (!hermes_present(hw)) {
- DEBUG(0, "orinoco_interrupt(): card removed\n");
- break;
- }
-
- if (events & HERMES_EV_TICK)
- __orinoco_ev_tick(dev, hw);
- if (events & HERMES_EV_WTERR)
- __orinoco_ev_wterr(dev, hw);
- if (events & HERMES_EV_INFDROP)
- __orinoco_ev_infdrop(dev, hw);
- if (events & HERMES_EV_INFO)
- __orinoco_ev_info(dev, hw);
- if (events & HERMES_EV_RX)
- __orinoco_ev_rx(dev, hw);
- if (events & HERMES_EV_TXEXC)
- __orinoco_ev_txexc(dev, hw);
- if (events & HERMES_EV_TX)
- __orinoco_ev_tx(dev, hw);
- if (events & HERMES_EV_ALLOC)
- __orinoco_ev_alloc(dev, hw);
-
- hermes_write_regn(hw, EVACK, evstat);
-
- evstat = hermes_read_regn(hw, EVSTAT);
- events = evstat & hw->inten;
- }
-
- orinoco_unlock(priv, &flags);
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(orinoco_interrupt);
-
-/********************************************************************/
-/* Power management */
-/********************************************************************/
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
-static int orinoco_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event,
- void *unused)
-{
- struct orinoco_private *priv = container_of(notifier,
- struct orinoco_private,
- pm_notifier);
-
- /* All we need to do is cache the firmware before suspend, and
- * release it when we come out.
- *
- * Only need to do this if we're downloading firmware. */
- if (!priv->do_fw_download)
- return NOTIFY_DONE;
-
- switch (pm_event) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- orinoco_cache_fw(priv, 0);
- break;
-
- case PM_POST_RESTORE:
- /* Restore from hibernation failed. We need to clean
- * up in exactly the same way, so fall through. */
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- orinoco_uncache_fw(priv);
- break;
-
- case PM_RESTORE_PREPARE:
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static void orinoco_register_pm_notifier(struct orinoco_private *priv)
-{
- priv->pm_notifier.notifier_call = orinoco_pm_notifier;
- register_pm_notifier(&priv->pm_notifier);
-}
-
-static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
-{
- unregister_pm_notifier(&priv->pm_notifier);
-}
-#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
-#define orinoco_register_pm_notifier(priv) do { } while (0)
-#define orinoco_unregister_pm_notifier(priv) do { } while (0)
-#endif
-
-/********************************************************************/
-/* Initialization */
-/********************************************************************/
-
-int orinoco_init(struct orinoco_private *priv)
-{
- struct device *dev = priv->dev;
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct hermes *hw = &priv->hw;
- int err = 0;
-
- /* No need to lock, the hw_unavailable flag is already set in
- * alloc_orinocodev() */
- priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
-
- /* Initialize the firmware */
- err = hw->ops->init(hw);
- if (err != 0) {
- dev_err(dev, "Failed to initialize firmware (err = %d)\n",
- err);
- goto out;
- }
-
- err = determine_fw_capabilities(priv, wiphy->fw_version,
- sizeof(wiphy->fw_version),
- &wiphy->hw_version);
- if (err != 0) {
- dev_err(dev, "Incompatible firmware, aborting\n");
- goto out;
- }
-
- if (priv->do_fw_download) {
-#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
- orinoco_cache_fw(priv, 0);
-#endif
-
- err = orinoco_download(priv);
- if (err)
- priv->do_fw_download = 0;
-
- /* Check firmware version again */
- err = determine_fw_capabilities(priv, wiphy->fw_version,
- sizeof(wiphy->fw_version),
- &wiphy->hw_version);
- if (err != 0) {
- dev_err(dev, "Incompatible firmware, aborting\n");
- goto out;
- }
- }
-
- if (priv->has_port3)
- dev_info(dev, "Ad-hoc demo mode supported\n");
- if (priv->has_ibss)
- dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
- if (priv->has_wep)
- dev_info(dev, "WEP supported, %s-bit key\n",
- priv->has_big_wep ? "104" : "40");
- if (priv->has_wpa) {
- dev_info(dev, "WPA-PSK supported\n");
- if (orinoco_mic_init(priv)) {
- dev_err(dev, "Failed to setup MIC crypto algorithm. "
- "Disabling WPA support\n");
- priv->has_wpa = 0;
- }
- }
-
- err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
- if (err)
- goto out;
-
- err = orinoco_hw_allocate_fid(priv);
- if (err) {
- dev_err(dev, "Failed to allocate NIC buffer!\n");
- goto out;
- }
-
- /* Set up the default configuration */
- priv->iw_mode = NL80211_IFTYPE_STATION;
- /* By default use IEEE/IBSS ad-hoc mode if we have it */
- priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
- set_port_type(priv);
- priv->channel = 0; /* use firmware default */
-
- priv->promiscuous = 0;
- priv->encode_alg = ORINOCO_ALG_NONE;
- priv->tx_key = 0;
- priv->wpa_enabled = 0;
- priv->tkip_cm_active = 0;
- priv->key_mgmt = 0;
- priv->wpa_ie_len = 0;
- priv->wpa_ie = NULL;
-
- if (orinoco_wiphy_register(wiphy)) {
- err = -ENODEV;
- goto out;
- }
-
- /* Make the hardware available, as long as it hasn't been
- * removed elsewhere (e.g. by PCMCIA hot unplug) */
- orinoco_lock_irq(priv);
- priv->hw_unavailable--;
- orinoco_unlock_irq(priv);
-
- dev_dbg(dev, "Ready\n");
-
- out:
- return err;
-}
-EXPORT_SYMBOL(orinoco_init);
-
-static const struct net_device_ops orinoco_netdev_ops = {
- .ndo_open = orinoco_open,
- .ndo_stop = orinoco_stop,
- .ndo_start_xmit = orinoco_xmit,
- .ndo_set_rx_mode = orinoco_set_multicast_list,
- .ndo_change_mtu = orinoco_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_tx_timeout = orinoco_tx_timeout,
-};
-
-/* Allocate private data.
- *
- * This driver has a number of structures associated with it
- * netdev - Net device structure for each network interface
- * wiphy - structure associated with wireless phy
- * wireless_dev (wdev) - structure for each wireless interface
- * hw - structure for hermes chip info
- * card - card specific structure for use by the card driver
- * (airport, orinoco_cs)
- * priv - orinoco private data
- * device - generic linux device structure
- *
- * +---------+ +---------+
- * | wiphy | | netdev |
- * | +-------+ | +-------+
- * | | priv | | | wdev |
- * | | +-----+ +-+-------+
- * | | | hw |
- * | +-+-----+
- * | | card |
- * +-+-------+
- *
- * priv has a link to netdev and device
- * wdev has a link to wiphy
- */
-struct orinoco_private
-*alloc_orinocodev(int sizeof_card,
- struct device *device,
- int (*hard_reset)(struct orinoco_private *),
- int (*stop_fw)(struct orinoco_private *, int))
-{
- struct orinoco_private *priv;
- struct wiphy *wiphy;
-
- /* allocate wiphy
- * NOTE: We only support a single virtual interface
- * but this may change when monitor mode is added
- */
- wiphy = wiphy_new(&orinoco_cfg_ops,
- sizeof(struct orinoco_private) + sizeof_card);
- if (!wiphy)
- return NULL;
-
- priv = wiphy_priv(wiphy);
- priv->dev = device;
-
- if (sizeof_card)
- priv->card = (void *)((unsigned long)priv
- + sizeof(struct orinoco_private));
- else
- priv->card = NULL;
-
- orinoco_wiphy_init(wiphy);
-
-#ifdef WIRELESS_SPY
- priv->wireless_data.spy_data = &priv->spy_data;
-#endif
-
- /* Set up default callbacks */
- priv->hard_reset = hard_reset;
- priv->stop_fw = stop_fw;
-
- spin_lock_init(&priv->lock);
- priv->open = 0;
- priv->hw_unavailable = 1; /* orinoco_init() must clear this
- * before anything else touches the
- * hardware */
- INIT_WORK(&priv->reset_work, orinoco_reset);
- INIT_WORK(&priv->join_work, orinoco_join_ap);
- INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
-
- INIT_LIST_HEAD(&priv->rx_list);
- tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet);
-
- spin_lock_init(&priv->scan_lock);
- INIT_LIST_HEAD(&priv->scan_list);
- INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
-
- priv->last_linkstatus = 0xffff;
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
- priv->cached_pri_fw = NULL;
- priv->cached_fw = NULL;
-#endif
-
- /* Register PM notifiers */
- orinoco_register_pm_notifier(priv);
-
- return priv;
-}
-EXPORT_SYMBOL(alloc_orinocodev);
-
-/* We can only support a single interface. We provide a separate
- * function to set it up to distinguish between hardware
- * initialisation and interface setup.
- *
- * The base_addr and irq parameters are passed on to netdev for use
- * with SIOCGIFMAP.
- */
-int orinoco_if_add(struct orinoco_private *priv,
- unsigned long base_addr,
- unsigned int irq,
- const struct net_device_ops *ops)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct wireless_dev *wdev;
- struct net_device *dev;
- int ret;
-
- dev = alloc_etherdev(sizeof(struct wireless_dev));
-
- if (!dev)
- return -ENOMEM;
-
- /* Initialise wireless_dev */
- wdev = netdev_priv(dev);
- wdev->wiphy = wiphy;
- wdev->iftype = NL80211_IFTYPE_STATION;
-
- /* Setup / override net_device fields */
- dev->ieee80211_ptr = wdev;
- dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->wireless_handlers = &orinoco_handler_def;
-#ifdef WIRELESS_SPY
- dev->wireless_data = &priv->wireless_data;
-#endif
- /* Default to standard ops if not set */
- if (ops)
- dev->netdev_ops = ops;
- else
- dev->netdev_ops = &orinoco_netdev_ops;
-
- /* we use the default eth_mac_addr for setting the MAC addr */
-
- /* Reserve space in skb for the SNAP header */
- dev->needed_headroom = ENCAPS_OVERHEAD;
-
- netif_carrier_off(dev);
-
- eth_hw_addr_set(dev, wiphy->perm_addr);
-
- dev->base_addr = base_addr;
- dev->irq = irq;
-
- dev->min_mtu = ORINOCO_MIN_MTU;
- dev->max_mtu = ORINOCO_MAX_MTU;
-
- SET_NETDEV_DEV(dev, priv->dev);
- ret = register_netdev(dev);
- if (ret)
- goto fail;
-
- priv->ndev = dev;
-
- /* Report what we've done */
- dev_dbg(priv->dev, "Registered interface %s.\n", dev->name);
-
- return 0;
-
- fail:
- free_netdev(dev);
- return ret;
-}
-EXPORT_SYMBOL(orinoco_if_add);
-
-void orinoco_if_del(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
-
- unregister_netdev(dev);
- free_netdev(dev);
-}
-EXPORT_SYMBOL(orinoco_if_del);
-
-void free_orinocodev(struct orinoco_private *priv)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct orinoco_rx_data *rx_data, *temp;
- struct orinoco_scan_data *sd, *sdtemp;
-
- /* If the tasklet is scheduled when we call tasklet_kill it
- * will run one final time. However the tasklet will only
- * drain priv->rx_list if the hw is still available. */
- tasklet_kill(&priv->rx_tasklet);
-
- /* Explicitly drain priv->rx_list */
- list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
- list_del(&rx_data->list);
-
- dev_kfree_skb(rx_data->skb);
- kfree(rx_data->desc);
- kfree(rx_data);
- }
-
- cancel_work_sync(&priv->process_scan);
- /* Explicitly drain priv->scan_list */
- list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
- list_del(&sd->list);
-
- if (sd->len > 0)
- kfree(sd->buf);
- kfree(sd);
- }
-
- orinoco_unregister_pm_notifier(priv);
- orinoco_uncache_fw(priv);
-
- priv->wpa_ie_len = 0;
- kfree(priv->wpa_ie);
- orinoco_mic_free(priv);
- wiphy_free(wiphy);
-}
-EXPORT_SYMBOL(free_orinocodev);
-
-int orinoco_up(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- unsigned long flags;
- int err;
-
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
-
- err = orinoco_reinit_firmware(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- goto exit;
- }
-
- netif_device_attach(dev);
- priv->hw_unavailable--;
-
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(priv);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
-exit:
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- return 0;
-}
-EXPORT_SYMBOL(orinoco_up);
-
-void orinoco_down(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- unsigned long flags;
- int err;
-
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- err = __orinoco_down(priv);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-}
-EXPORT_SYMBOL(orinoco_down);
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (David Gibson <hermes@gibson.dropbear.id.au>, "
- "Pavel Roskin <proski@gnu.org>, et al)";
-
-static int __init init_orinoco(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return 0;
-}
-
-static void __exit exit_orinoco(void)
-{
-}
-
-module_init(init_orinoco);
-module_exit(exit_orinoco);
diff --git a/drivers/net/wireless/intersil/orinoco/main.h b/drivers/net/wireless/intersil/orinoco/main.h
deleted file mode 100644
index 5a8fec26136e..000000000000
--- a/drivers/net/wireless/intersil/orinoco/main.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Exports from main to helper modules
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_MAIN_H_
-#define _ORINOCO_MAIN_H_
-
-#include <linux/ieee80211.h>
-#include "orinoco.h"
-
-/********************************************************************/
-/* Compile time configuration and compatibility stuff */
-/********************************************************************/
-
-/* We do this this way to avoid ifdefs in the actual code */
-#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv) (priv->spy_data.spy_number)
-#else
-#define SPY_NUMBER(priv) 0
-#endif /* WIRELESS_SPY */
-
-/********************************************************************/
-
-/* Export module parameter */
-extern int force_monitor;
-
-/* Forward declarations */
-struct net_device;
-struct work_struct;
-
-void set_port_type(struct orinoco_private *priv);
-int orinoco_commit(struct orinoco_private *priv);
-void orinoco_reset(struct work_struct *work);
-
-/* Information element helpers - find a home for these... */
-#define WPA_OUI_TYPE "\x00\x50\xF2\x01"
-#define WPA_SELECTOR_LEN 4
-static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
-{
- u8 *p = data;
- while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) &&
- (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
- return p;
- p += p[1] + 2;
- }
- return NULL;
-}
-
-#endif /* _ORINOCO_MAIN_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c
deleted file mode 100644
index a324bc4b7938..000000000000
--- a/drivers/net/wireless/intersil/orinoco/mic.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Orinoco MIC helpers
- *
- * See copyright notice in main.c
- */
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/if_ether.h>
-#include <linux/scatterlist.h>
-#include <crypto/hash.h>
-
-#include "orinoco.h"
-#include "mic.h"
-
-/********************************************************************/
-/* Michael MIC crypto setup */
-/********************************************************************/
-int orinoco_mic_init(struct orinoco_private *priv)
-{
- priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->tx_tfm_mic)) {
- printk(KERN_DEBUG "%s: could not allocate "
- "crypto API michael_mic\n", __func__);
- priv->tx_tfm_mic = NULL;
- return -ENOMEM;
- }
-
- priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->rx_tfm_mic)) {
- printk(KERN_DEBUG "%s: could not allocate "
- "crypto API michael_mic\n", __func__);
- priv->rx_tfm_mic = NULL;
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void orinoco_mic_free(struct orinoco_private *priv)
-{
- if (priv->tx_tfm_mic)
- crypto_free_shash(priv->tx_tfm_mic);
- if (priv->rx_tfm_mic)
- crypto_free_shash(priv->rx_tfm_mic);
-}
-
-int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
- u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic)
-{
- SHASH_DESC_ON_STACK(desc, tfm_michael);
- u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
- int err;
-
- if (tfm_michael == NULL) {
- printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__);
- return -1;
- }
-
- /* Copy header into buffer. We need the padding on the end zeroed */
- memcpy(&hdr[0], da, ETH_ALEN);
- memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
- hdr[ETH_ALEN * 2] = priority;
- hdr[ETH_ALEN * 2 + 1] = 0;
- hdr[ETH_ALEN * 2 + 2] = 0;
- hdr[ETH_ALEN * 2 + 3] = 0;
-
- desc->tfm = tfm_michael;
-
- err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
- if (err)
- return err;
-
- err = crypto_shash_init(desc);
- if (err)
- return err;
-
- err = crypto_shash_update(desc, hdr, sizeof(hdr));
- if (err)
- return err;
-
- err = crypto_shash_update(desc, data, data_len);
- if (err)
- return err;
-
- err = crypto_shash_final(desc, mic);
- shash_desc_zero(desc);
-
- return err;
-}
diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h
deleted file mode 100644
index e8724e889219..000000000000
--- a/drivers/net/wireless/intersil/orinoco/mic.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Orinoco MIC helpers
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_MIC_H_
-#define _ORINOCO_MIC_H_
-
-#include <linux/types.h>
-#include <crypto/hash.h>
-
-#define MICHAEL_MIC_LEN 8
-
-/* Forward declarations */
-struct orinoco_private;
-struct crypto_ahash;
-
-int orinoco_mic_init(struct orinoco_private *priv);
-void orinoco_mic_free(struct orinoco_private *priv);
-int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
- u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic);
-
-#endif /* ORINOCO_MIC_H */
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h
deleted file mode 100644
index cdd026af100b..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/* orinoco.h
- *
- * Common definitions to all pieces of the various orinoco
- * drivers
- */
-
-#ifndef _ORINOCO_H
-#define _ORINOCO_H
-
-#define DRIVER_VERSION "0.15"
-
-#include <linux/interrupt.h>
-#include <linux/suspend.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/cfg80211.h>
-
-#include "hermes.h"
-
-/* To enable debug messages */
-/*#define ORINOCO_DEBUG 3*/
-
-#define WIRELESS_SPY /* enable iwspy support */
-
-#define MAX_SCAN_LEN 4096
-
-#define ORINOCO_SEQ_LEN 8
-#define ORINOCO_MAX_KEY_SIZE 14
-#define ORINOCO_MAX_KEYS 4
-
-struct orinoco_key {
- __le16 len; /* always stored as little-endian */
- char data[ORINOCO_MAX_KEY_SIZE];
-} __packed;
-
-#define TKIP_KEYLEN 16
-#define MIC_KEYLEN 8
-
-struct orinoco_tkip_key {
- u8 tkip[TKIP_KEYLEN];
- u8 tx_mic[MIC_KEYLEN];
- u8 rx_mic[MIC_KEYLEN];
-};
-
-enum orinoco_alg {
- ORINOCO_ALG_NONE,
- ORINOCO_ALG_WEP,
- ORINOCO_ALG_TKIP
-};
-
-enum fwtype {
- FIRMWARE_TYPE_AGERE,
- FIRMWARE_TYPE_INTERSIL,
- FIRMWARE_TYPE_SYMBOL
-};
-
-struct firmware;
-
-struct orinoco_private {
- void *card; /* Pointer to card dependent structure */
- struct device *dev;
- int (*hard_reset)(struct orinoco_private *);
- int (*stop_fw)(struct orinoco_private *, int);
-
- struct ieee80211_supported_band band;
- struct ieee80211_channel channels[14];
- u32 cipher_suites[3];
-
- /* Synchronisation stuff */
- spinlock_t lock;
- int hw_unavailable;
- struct work_struct reset_work;
-
- /* Interrupt tasklets */
- struct tasklet_struct rx_tasklet;
- struct list_head rx_list;
-
- /* driver state */
- int open;
- u16 last_linkstatus;
- struct work_struct join_work;
- struct work_struct wevent_work;
-
- /* Net device stuff */
- struct net_device *ndev;
- struct iw_statistics wstats;
-
- /* Hardware control variables */
- struct hermes hw;
- u16 txfid;
-
- /* Capabilities of the hardware/firmware */
- enum fwtype firmware_type;
- int ibss_port;
- int nicbuf_size;
- u16 channel_mask;
-
- /* Boolean capabilities */
- unsigned int has_ibss:1;
- unsigned int has_port3:1;
- unsigned int has_wep:1;
- unsigned int has_big_wep:1;
- unsigned int has_mwo:1;
- unsigned int has_pm:1;
- unsigned int has_preamble:1;
- unsigned int has_sensitivity:1;
- unsigned int has_hostscan:1;
- unsigned int has_alt_txcntl:1;
- unsigned int has_ext_scan:1;
- unsigned int has_wpa:1;
- unsigned int do_fw_download:1;
- unsigned int broken_disableport:1;
- unsigned int broken_monitor:1;
- unsigned int prefer_port3:1;
-
- /* Configuration paramaters */
- enum nl80211_iftype iw_mode;
- enum orinoco_alg encode_alg;
- u16 wep_restrict, tx_key;
- struct key_params keys[ORINOCO_MAX_KEYS];
-
- int bitratemode;
- char nick[IW_ESSID_MAX_SIZE + 1];
- char desired_essid[IW_ESSID_MAX_SIZE + 1];
- char desired_bssid[ETH_ALEN];
- int bssid_fixed;
- u16 frag_thresh, mwo_robust;
- u16 channel;
- u16 ap_density, rts_thresh;
- u16 pm_on, pm_mcast, pm_period, pm_timeout;
- u16 preamble;
- u16 short_retry_limit, long_retry_limit;
- u16 retry_lifetime;
-#ifdef WIRELESS_SPY
- struct iw_spy_data spy_data; /* iwspy support */
- struct iw_public_data wireless_data;
-#endif
-
- /* Configuration dependent variables */
- int port_type, createibss;
- int promiscuous, mc_count;
-
- /* Scanning support */
- struct cfg80211_scan_request *scan_request;
- struct work_struct process_scan;
- struct list_head scan_list;
- spinlock_t scan_lock; /* protects the scan list */
-
- /* WPA support */
- u8 *wpa_ie;
- int wpa_ie_len;
-
- struct crypto_shash *rx_tfm_mic;
- struct crypto_shash *tx_tfm_mic;
-
- unsigned int wpa_enabled:1;
- unsigned int tkip_cm_active:1;
- unsigned int key_mgmt:3;
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
- /* Cached in memory firmware to use during ->resume. */
- const struct firmware *cached_pri_fw;
- const struct firmware *cached_fw;
-#endif
-
- struct notifier_block pm_notifier;
-};
-
-#ifdef ORINOCO_DEBUG
-extern int orinoco_debug;
-#define DEBUG(n, args...) do { \
- if (orinoco_debug > (n)) \
- printk(KERN_DEBUG args); \
-} while (0)
-#else
-#define DEBUG(n, args...) do { } while (0)
-#endif /* ORINOCO_DEBUG */
-
-/********************************************************************/
-/* Exported prototypes */
-/********************************************************************/
-
-struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device,
- int (*hard_reset)(struct orinoco_private *),
- int (*stop_fw)(struct orinoco_private *, int));
-void free_orinocodev(struct orinoco_private *priv);
-int orinoco_init(struct orinoco_private *priv);
-int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr,
- unsigned int irq, const struct net_device_ops *ops);
-void orinoco_if_del(struct orinoco_private *priv);
-int orinoco_up(struct orinoco_private *priv);
-void orinoco_down(struct orinoco_private *priv);
-irqreturn_t orinoco_interrupt(int irq, void *dev_id);
-
-void __orinoco_ev_info(struct net_device *dev, struct hermes *hw);
-void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw);
-
-int orinoco_process_xmit_skb(struct sk_buff *skb,
- struct net_device *dev,
- struct orinoco_private *priv,
- int *tx_control,
- u8 *mic);
-
-/* Common ndo functions exported for reuse by orinoco_usb */
-int orinoco_open(struct net_device *dev);
-int orinoco_stop(struct net_device *dev);
-void orinoco_set_multicast_list(struct net_device *dev);
-int orinoco_change_mtu(struct net_device *dev, int new_mtu);
-void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue);
-
-/********************************************************************/
-/* Locking and synchronization functions */
-/********************************************************************/
-
-static inline int orinoco_lock(struct orinoco_private *priv,
- unsigned long *flags)
-{
- priv->hw.ops->lock_irqsave(&priv->lock, flags);
- if (priv->hw_unavailable) {
- DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
- priv->ndev);
- priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
- return -EBUSY;
- }
- return 0;
-}
-
-static inline void orinoco_unlock(struct orinoco_private *priv,
- unsigned long *flags)
-{
- priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
-}
-
-static inline void orinoco_lock_irq(struct orinoco_private *priv)
-{
- priv->hw.ops->lock_irq(&priv->lock);
-}
-
-static inline void orinoco_unlock_irq(struct orinoco_private *priv)
-{
- priv->hw.ops->unlock_irq(&priv->lock);
-}
-
-/*** Navigate from net_device to orinoco_private ***/
-static inline struct orinoco_private *ndev_priv(struct net_device *dev)
-{
- struct wireless_dev *wdev = netdev_priv(dev);
- return wdev_priv(wdev);
-}
-#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c
deleted file mode 100644
index 03bfd2482656..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/* orinoco_cs.c (formerly known as dldwd_cs.c)
- *
- * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
- * It should also be usable on various Prism II based cards such as the
- * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
- * cards such as the 3Com AirConnect and Ericsson WLAN.
- *
- * Copyright notice & release notes in file main.c
- */
-
-#define DRIVER_NAME "orinoco_cs"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module stuff */
-/********************************************************************/
-
-MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco,"
- " Prism II based and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Module parameters */
-
-/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
-static int ignore_cis_vcc; /* = 0 */
-module_param(ignore_cis_vcc, int, 0);
-MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
-
-/********************************************************************/
-/* Data structures */
-/********************************************************************/
-
-/* PCMCIA specific device information (goes in the card field of
- * struct orinoco_private */
-struct orinoco_pccard {
- struct pcmcia_device *p_dev;
-
- /* Used to handle hard reset */
- /* yuck, we need this hack to work around the insanity of the
- * PCMCIA layer */
- unsigned long hard_reset_in_progress;
-};
-
-
-/********************************************************************/
-/* Function prototypes */
-/********************************************************************/
-
-static int orinoco_cs_config(struct pcmcia_device *link);
-static void orinoco_cs_release(struct pcmcia_device *link);
-static void orinoco_cs_detach(struct pcmcia_device *p_dev);
-
-/********************************************************************/
-/* Device methods */
-/********************************************************************/
-
-static int
-orinoco_cs_hard_reset(struct orinoco_private *priv)
-{
- struct orinoco_pccard *card = priv->card;
- struct pcmcia_device *link = card->p_dev;
- int err;
-
- /* We need atomic ops here, because we're not holding the lock */
- set_bit(0, &card->hard_reset_in_progress);
-
- err = pcmcia_reset_card(link->socket);
- if (err)
- return err;
-
- msleep(100);
- clear_bit(0, &card->hard_reset_in_progress);
-
- return 0;
-}
-
-/********************************************************************/
-/* PCMCIA stuff */
-/********************************************************************/
-
-static int
-orinoco_cs_probe(struct pcmcia_device *link)
-{
- struct orinoco_private *priv;
- struct orinoco_pccard *card;
- int ret;
-
- priv = alloc_orinocodev(sizeof(*card), &link->dev,
- orinoco_cs_hard_reset, NULL);
- if (!priv)
- return -ENOMEM;
- card = priv->card;
-
- /* Link both structures together */
- card->p_dev = link;
- link->priv = priv;
-
- ret = orinoco_cs_config(link);
- if (ret)
- goto err_free_orinocodev;
-
- return 0;
-
-err_free_orinocodev:
- free_orinocodev(priv);
- return ret;
-}
-
-static void orinoco_cs_detach(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
-
- orinoco_if_del(priv);
-
- orinoco_cs_release(link);
-
- wiphy_unregister(priv_to_wiphy(priv));
- free_orinocodev(priv);
-} /* orinoco_cs_detach */
-
-static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-};
-
-static int
-orinoco_cs_config(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct hermes *hw = &priv->hw;
- int ret;
- void __iomem *mem;
-
- link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
- CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
- if (ignore_cis_vcc)
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
- if (ret) {
- if (!ignore_cis_vcc)
- printk(KERN_ERR PFX "GetNextTuple(): No matching "
- "CIS configuration. Maybe you need the "
- "ignore_cis_vcc=1 parameter.\n");
- goto failed;
- }
-
- mem = ioport_map(link->resource[0]->start,
- resource_size(link->resource[0]));
- if (!mem)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
- hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
-
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto failed;
- }
-
- /* Register an interface with the stack */
- if (orinoco_if_add(priv, link->resource[0]->start,
- link->irq, NULL) != 0) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto failed;
- }
-
- return 0;
-
- failed:
- orinoco_cs_release(link);
- return -ENODEV;
-} /* orinoco_cs_config */
-
-static void
-orinoco_cs_release(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- unsigned long flags;
-
- /* We're committed to taking the device away now, so mark the
- * hardware as unavailable */
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- priv->hw_unavailable++;
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- pcmcia_disable_device(link);
- if (priv->hw.iobase)
- ioport_unmap(priv->hw.iobase);
-} /* orinoco_cs_release */
-
-static int orinoco_cs_suspend(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct orinoco_pccard *card = priv->card;
-
- /* This is probably racy, but I can't think of
- a better way, short of rewriting the PCMCIA
- layer to not suck :-( */
- if (!test_bit(0, &card->hard_reset_in_progress))
- orinoco_down(priv);
-
- return 0;
-}
-
-static int orinoco_cs_resume(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct orinoco_pccard *card = priv->card;
- int err = 0;
-
- if (!test_bit(0, &card->hard_reset_in_progress))
- err = orinoco_up(priv);
-
- return err;
-}
-
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-static const struct pcmcia_device_id orinoco_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
- PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
- PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
- PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
- PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */
- PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
- PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
- PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
- PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
- PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
- PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
- PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
- PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
- PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
- PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
- PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
- PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
- PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
- PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
- PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
- PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
- PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
- PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
- PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
- PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
- PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
- PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
- PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
- PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
- PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */
-#ifdef CONFIG_HERMES_PRISM
- /* Only entries that certainly identify Prism chipset */
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
- PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
- PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
- PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
- PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
- PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
- PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
- PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
- PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
- PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
- PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
- PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
- PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
- PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
- PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
- PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
- PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
- PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
- PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
- PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
- PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
- PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
- PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
- PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
- PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
- PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
- PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
- PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
- PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
- PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
- PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
- PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
- PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
- PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
- PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
- PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
-
- /* This may be Agere or Intersil Firmware */
- PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
-#endif
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
-
-static struct pcmcia_driver orinoco_driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .probe = orinoco_cs_probe,
- .remove = orinoco_cs_detach,
- .id_table = orinoco_cs_ids,
- .suspend = orinoco_cs_suspend,
- .resume = orinoco_cs_resume,
-};
-module_pcmcia_driver(orinoco_driver);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
deleted file mode 100644
index 18bd0d9876c2..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* orinoco_nortel.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
- * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
- *
- * Copyright (C) 2002 Tobias Hoffmann
- * (C) 2003 Christoph Jungegger <disdos@traum404.de>
- *
- * Some of this code is borrowed from orinoco_plx.c
- * Copyright (C) 2001 Daniel Barlow
- * Some of this code is borrowed from orinoco_pci.c
- * Copyright (C) 2001 Jean Tourrilhes
- * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
- * has been copied from it. linux-wlan-ng-0.1.10 is originally :
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#define DRIVER_NAME "orinoco_nortel"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
-#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- * We need this to get going...
- * This is the part of the code that is strongly inspired from wlan-ng
- *
- * Note bis : Don't try to access HERMES_CMD during the reset phase.
- * It just won't work !
- */
-static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
-{
- struct orinoco_pci_card *card = priv->card;
-
- /* Assert the reset until the card notices */
- iowrite16(8, card->bridge_io + 2);
- ioread16(card->attr_io + COR_OFFSET);
- iowrite16(0x80, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- /* Give time for the card to recover from this hard effort */
- iowrite16(0, card->attr_io + COR_OFFSET);
- iowrite16(0, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- /* Set COR as usual */
- iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
- iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- iowrite16(0x228, card->bridge_io + 2);
-
- return 0;
-}
-
-static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
-{
- int i;
- u32 reg;
-
- /* Setup bridge */
- if (ioread16(card->bridge_io) & 1) {
- printk(KERN_ERR PFX "brg1 answer1 wrong\n");
- return -EBUSY;
- }
- iowrite16(0x118, card->bridge_io + 2);
- iowrite16(0x108, card->bridge_io + 2);
- mdelay(30);
- iowrite16(0x8, card->bridge_io + 2);
- for (i = 0; i < 30; i++) {
- mdelay(30);
- if (ioread16(card->bridge_io) & 0x10)
- break;
- }
- if (i == 30) {
- printk(KERN_ERR PFX "brg1 timed out\n");
- return -EBUSY;
- }
- if (ioread16(card->attr_io + COR_OFFSET) & 1) {
- printk(KERN_ERR PFX "brg2 answer1 wrong\n");
- return -EBUSY;
- }
- if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
- printk(KERN_ERR PFX "brg2 answer2 wrong\n");
- return -EBUSY;
- }
- if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
- printk(KERN_ERR PFX "brg2 answer3 wrong\n");
- return -EBUSY;
- }
-
- /* Set the PCMCIA COR register */
- iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
- mdelay(1);
- reg = ioread16(card->attr_io + COR_OFFSET);
- if (reg != COR_VALUE) {
- printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
- reg);
- return -EBUSY;
- }
-
- /* Set LEDs */
- iowrite16(1, card->bridge_io + 10);
- return 0;
-}
-
-static int orinoco_nortel_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io, *bridge_io, *attr_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- bridge_io = pci_iomap(pdev, 0, 0);
- if (!bridge_io) {
- printk(KERN_ERR PFX "Cannot map bridge registers\n");
- err = -EIO;
- goto fail_map_bridge;
- }
-
- attr_io = pci_iomap(pdev, 1, 0);
- if (!attr_io) {
- printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
- err = -EIO;
- goto fail_map_attr;
- }
-
- hermes_io = pci_iomap(pdev, 2, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot map chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_nortel_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
- card->bridge_io = bridge_io;
- card->attr_io = attr_io;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_nortel_hw_init(card);
- if (err) {
- printk(KERN_ERR PFX "Hardware initialization failed\n");
- goto fail;
- }
-
- err = orinoco_nortel_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail_wiphy;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail_wiphy:
- wiphy_unregister(priv_to_wiphy(priv));
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_iounmap(pdev, attr_io);
-
- fail_map_attr:
- pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_nortel_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct orinoco_pci_card *card = priv->card;
-
- /* Clear LEDs */
- iowrite16(0, card->bridge_io + 10);
-
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(priv));
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_iounmap(pdev, card->attr_io);
- pci_iounmap(pdev, card->bridge_io);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_nortel_id_table[] = {
- /* Nortel emobility PCI */
- {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
- /* Symbol LA-4123 PCI */
- {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
-
-static struct pci_driver orinoco_nortel_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_nortel_id_table,
- .probe = orinoco_nortel_init_one,
- .remove = orinoco_nortel_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
-MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_nortel_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_nortel_driver);
-}
-
-static void __exit orinoco_nortel_exit(void)
-{
- pci_unregister_driver(&orinoco_nortel_driver);
-}
-
-module_init(orinoco_nortel_init);
-module_exit(orinoco_nortel_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c
deleted file mode 100644
index 7e3a6dd60c15..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* orinoco_pci.c
- *
- * Driver for Prism 2.5/3 devices that have a direct PCI interface
- * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
- * The card contains only one PCI region, which contains all the usual
- * hermes registers, as well as the COR register.
- *
- * Current maintainers are:
- * Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * Some of this code is borrowed from orinoco_plx.c
- * Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
- * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
- * has been copied from it. linux-wlan-ng-0.1.10 is originally :
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- * This file originally written by:
- * Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
- * And is now maintained by:
- * (C) Copyright David Gibson, IBM Corp. 2002-2003.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#define DRIVER_NAME "orinoco_pci"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-/* Offset of the COR register of the PCI card */
-#define HERMES_PCI_COR (0x26)
-
-/* Bitmask to reset the card */
-#define HERMES_PCI_COR_MASK (0x0080)
-
-/* Magic timeouts for doing the reset.
- * Those times are straight from wlan-ng, and it is claimed that they
- * are necessary. Alan will kill me. Take your time and grab a coffee. */
-#define HERMES_PCI_COR_ONT (250) /* ms */
-#define HERMES_PCI_COR_OFFT (500) /* ms */
-#define HERMES_PCI_COR_BUSYT (500) /* ms */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- * We need this to get going...
- * This is the part of the code that is strongly inspired from wlan-ng
- *
- * Note : This code is done with irq enabled. This mean that many
- * interrupts will occur while we are there. This is why we use the
- * jiffies to regulate time instead of a straight mdelay(). Usually we
- * need only around 245 iteration of the loop to do 250 ms delay.
- *
- * Note bis : Don't try to access HERMES_CMD during the reset phase.
- * It just won't work !
- */
-static int orinoco_pci_cor_reset(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- unsigned long timeout;
- u16 reg;
-
- /* Assert the reset until the card notices */
- hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
- mdelay(HERMES_PCI_COR_ONT);
-
- /* Give time for the card to recover from this hard effort */
- hermes_write_regn(hw, PCI_COR, 0x0000);
- mdelay(HERMES_PCI_COR_OFFT);
-
- /* The card is ready when it's no longer busy */
- timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
- reg = hermes_read_regn(hw, CMD);
- while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
- mdelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* Still busy? */
- if (reg & HERMES_CMD_BUSY) {
- printk(KERN_ERR PFX "Busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int orinoco_pci_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- hermes_io = pci_iomap(pdev, 0, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot remap chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_pci_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_pci_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail_wiphy;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail_wiphy:
- wiphy_unregister(priv_to_wiphy(priv));
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_pci_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
-
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(priv));
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_pci_id_table[] = {
- /* Intersil Prism 3 */
- {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
- /* Intersil Prism 2.5 */
- {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
- /* Samsung MagicLAN SWL-2210P */
- {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
-
-static struct pci_driver orinoco_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_pci_id_table,
- .probe = orinoco_pci_init_one,
- .remove = orinoco_pci_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Pavel Roskin <proski@gnu.org>,"
- " David Gibson <hermes@gibson.dropbear.id.au> &"
- " Jean Tourrilhes <jt@hpl.hp.com>)";
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> &"
- " David Gibson <hermes@gibson.dropbear.id.au>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_pci_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_pci_driver);
-}
-
-static void __exit orinoco_pci_exit(void)
-{
- pci_unregister_driver(&orinoco_pci_driver);
-}
-
-module_init(orinoco_pci_init);
-module_exit(orinoco_pci_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h
deleted file mode 100644
index d49d940864b4..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* orinoco_pci.h
- *
- * Common code for all Orinoco drivers for PCI devices, including
- * both native PCI and PCMCIA-to-PCI bridges.
- *
- * Copyright (C) 2005, Pavel Roskin.
- * See main.c for license.
- */
-
-#ifndef _ORINOCO_PCI_H
-#define _ORINOCO_PCI_H
-
-#include <linux/netdevice.h>
-
-/* Driver specific data */
-struct orinoco_pci_card {
- void __iomem *bridge_io;
- void __iomem *attr_io;
-};
-
-static int __maybe_unused orinoco_pci_suspend(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct orinoco_private *priv = pci_get_drvdata(pdev);
-
- orinoco_down(priv);
- free_irq(pdev->irq, priv);
-
- return 0;
-}
-
-static int __maybe_unused orinoco_pci_resume(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct net_device *dev = priv->ndev;
- int err;
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, priv);
- if (err) {
- printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
- dev->name);
- return -EBUSY;
- }
-
- return orinoco_up(priv);
-}
-
-static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops,
- orinoco_pci_suspend,
- orinoco_pci_resume);
-
-#endif /* _ORINOCO_PCI_H */
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c
deleted file mode 100644
index 73e6ae124013..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/* orinoco_plx.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a PLX9052.
- *
- * Current maintainers are:
- * Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- * Copyright (C) 2001 Daniel Barlow
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * Here's the general details on how the PLX9052 adapter works:
- *
- * - Two PCI I/O address spaces, one 0x80 long which contains the
- * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
- * slot I/O address space.
- *
- * - One PCI memory address space, mapped to the PCMCIA attribute space
- * (containing the CIS).
- *
- * Using the later, you can read through the CIS data to make sure the
- * card is compatible with the driver. Keep in mind that the PCMCIA
- * spec specifies the CIS as the lower 8 bits of each word read from
- * the CIS, so to read the bytes of the CIS, read every other byte
- * (0,2,4,...). Passing that test, you need to enable the I/O address
- * space on the PCMCIA card via the PCMCIA COR register. This is the
- * first byte following the CIS. In my case (which may not have any
- * relation to what's on the PRISM2 cards), COR was at offset 0x800
- * within the PCI memory space. Write 0x41 to the COR register to
- * enable I/O mode and to select level triggered interrupts. To
- * confirm you actually succeeded, read the COR register back and make
- * sure it actually got set to 0x41, in case you have an unexpected
- * card inserted.
- *
- * Following that, you can treat the second PCI I/O address space (the
- * one that's not 0x80 in length) as the PCMCIA I/O space.
- *
- * Note that in the Eumitcom's source for their drivers, they register
- * the interrupt as edge triggered when registering it with the
- * Windows kernel. I don't recall how to register edge triggered on
- * Linux (if it can be done at all). But in some experimentation, I
- * don't see much operational difference between using either
- * interrupt mode. Don't mess with the interrupt mode in the COR
- * register though, as the PLX9052 wants level triggers with the way
- * the serial EEPROM configures it on the WL11000.
- *
- * There's some other little quirks related to timing that I bumped
- * into, but I don't recall right now. Also, there's two variants of
- * the WL11000 I've seen, revision A1 and T2. These seem to differ
- * slightly in the timings configured in the wait-state generator in
- * the PLX9052. There have also been some comments from Eumitcom that
- * cards shouldn't be hot swapped, apparently due to risk of cooking
- * the PLX9052. I'm unsure why they believe this, as I can't see
- * anything in the design that would really cause a problem, except
- * for crashing drivers not written to expect it. And having developed
- * drivers for the WL11000, I'd say it's quite tricky to write code
- * that will successfully deal with a hot unplug. Very odd things
- * happen on the I/O side of things. But anyway, be warned. Despite
- * that, I've hot-swapped a number of times during debugging and
- * driver development for various reasons (stuck WAIT# line after the
- * radio card's firmware locks up).
- */
-
-#define DRIVER_NAME "orinoco_plx"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */
-#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-#define COR_RESET (0x80) /* reset bit in the COR register */
-#define PLX_RESET_TIME (500) /* milliseconds */
-
-#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */
-#define PLX_INTCSR_INTEN (1 << 6) /* Interrupt Enable bit */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- */
-static int orinoco_plx_cor_reset(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- struct orinoco_pci_card *card = priv->card;
- unsigned long timeout;
- u16 reg;
-
- iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- /* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME);
- reg = hermes_read_regn(hw, CMD);
- while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
- mdelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* Still busy? */
- if (reg & HERMES_CMD_BUSY) {
- printk(KERN_ERR PFX "Busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
-{
- int i;
- u32 csr_reg;
- static const u8 cis_magic[] = {
- 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
- };
-
- printk(KERN_DEBUG PFX "CIS: ");
- for (i = 0; i < 16; i++)
- printk("%02X:", ioread8(card->attr_io + (i << 1)));
- printk("\n");
-
- /* Verify whether a supported PC card is present */
- /* FIXME: we probably need to be smarted about this */
- for (i = 0; i < sizeof(cis_magic); i++) {
- if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
- printk(KERN_ERR PFX "The CIS value of Prism2 PC "
- "card is unexpected\n");
- return -ENODEV;
- }
- }
-
- /* bjoern: We need to tell the card to enable interrupts, in
- case the serial eprom didn't do this already. See the
- PLX9052 data book, p8-1 and 8-24 for reference. */
- csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
- if (!(csr_reg & PLX_INTCSR_INTEN)) {
- csr_reg |= PLX_INTCSR_INTEN;
- iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
- csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
- if (!(csr_reg & PLX_INTCSR_INTEN)) {
- printk(KERN_ERR PFX "Cannot enable interrupts\n");
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int orinoco_plx_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io, *attr_io, *bridge_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- bridge_io = pci_iomap(pdev, 1, 0);
- if (!bridge_io) {
- printk(KERN_ERR PFX "Cannot map bridge registers\n");
- err = -EIO;
- goto fail_map_bridge;
- }
-
- attr_io = pci_iomap(pdev, 2, 0);
- if (!attr_io) {
- printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
- err = -EIO;
- goto fail_map_attr;
- }
-
- hermes_io = pci_iomap(pdev, 3, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot map chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_plx_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
- card->bridge_io = bridge_io;
- card->attr_io = attr_io;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_plx_hw_init(card);
- if (err) {
- printk(KERN_ERR PFX "Hardware initialization failed\n");
- goto fail;
- }
-
- err = orinoco_plx_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail_wiphy;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail_wiphy:
- wiphy_unregister(priv_to_wiphy(priv));
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_iounmap(pdev, attr_io);
-
- fail_map_attr:
- pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_plx_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct orinoco_pci_card *card = priv->card;
-
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(priv));
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_iounmap(pdev, card->attr_io);
- pci_iounmap(pdev, card->bridge_io);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_plx_id_table[] = {
- {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */
- {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
- {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */
- {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W,
- Eumitcom PCI WL11000,
- Addtron AWA-100 */
- {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */
- {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */
- {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */
- {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */
- {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by
- Brendan W. McAdams <rit AT jacked-in.org> */
- {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by
- Damien Persohn <damien AT persohn.net> */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
-
-static struct pci_driver orinoco_plx_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_plx_id_table,
- .probe = orinoco_plx_init_one,
- .remove = orinoco_plx_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Pavel Roskin <proski@gnu.org>,"
- " David Gibson <hermes@gibson.dropbear.id.au>,"
- " Daniel Barlow <dan@telent.net>)";
-MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_plx_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_plx_driver);
-}
-
-static void __exit orinoco_plx_exit(void)
-{
- pci_unregister_driver(&orinoco_plx_driver);
-}
-
-module_init(orinoco_plx_init);
-module_exit(orinoco_plx_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
deleted file mode 100644
index 939d5a1dce97..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/* orinoco_tmd.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a TMD7160.
- *
- * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net>
- * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * The actual driving is done by main.c, this is just resource
- * allocation stuff.
- *
- * This driver is modeled after the orinoco_plx driver. The main
- * difference is that the TMD chip has only IO port ranges and doesn't
- * provide access to the PCMCIA attribute space.
- *
- * Pheecom sells cards with the TMD chip as "ASIC version"
- */
-
-#define DRIVER_NAME "orinoco_tmd"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-#define COR_RESET (0x80) /* reset bit in the COR register */
-#define TMD_RESET_TIME (500) /* milliseconds */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- */
-static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- struct orinoco_pci_card *card = priv->card;
- unsigned long timeout;
- u16 reg;
-
- iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
- mdelay(1);
-
- iowrite8(COR_VALUE, card->bridge_io);
- mdelay(1);
-
- /* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME);
- reg = hermes_read_regn(hw, CMD);
- while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
- mdelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* Still busy? */
- if (reg & HERMES_CMD_BUSY) {
- printk(KERN_ERR PFX "Busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-
-static int orinoco_tmd_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io, *bridge_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- bridge_io = pci_iomap(pdev, 1, 0);
- if (!bridge_io) {
- printk(KERN_ERR PFX "Cannot map bridge registers\n");
- err = -EIO;
- goto fail_map_bridge;
- }
-
- hermes_io = pci_iomap(pdev, 2, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot map chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_tmd_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
- card->bridge_io = bridge_io;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_tmd_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_tmd_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct orinoco_pci_card *card = priv->card;
-
- orinoco_if_del(priv);
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_iounmap(pdev, card->bridge_io);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_tmd_id_table[] = {
- {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
-
-static struct pci_driver orinoco_tmd_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_tmd_id_table,
- .probe = orinoco_tmd_init_one,
- .remove = orinoco_tmd_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Joerg Dorchain <joerg@dorchain.net>)";
-MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_tmd_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_tmd_driver);
-}
-
-static void __exit orinoco_tmd_exit(void)
-{
- pci_unregister_driver(&orinoco_tmd_driver);
-}
-
-module_init(orinoco_tmd_init);
-module_exit(orinoco_tmd_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
deleted file mode 100644
index 866e0230df25..000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+++ /dev/null
@@ -1,1787 +0,0 @@
-/*
- * USB Orinoco driver
- *
- * Copyright (c) 2003 Manuel Estrada Sainz
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * Queueing code based on linux-wlan-ng 0.2.1-pre5
- *
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- *
- * The license is the same as above.
- *
- * Initialy based on USB Skeleton driver - 0.7
- *
- * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
- *
- * 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 Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * NOTE: The original USB Skeleton driver is GPL, but all that code is
- * gone so MPL/GPL applies.
- */
-
-#define DRIVER_NAME "orinoco_usb"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/usb.h>
-#include <linux/timer.h>
-
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <linux/firmware.h>
-#include <linux/refcount.h>
-
-#include "mic.h"
-#include "orinoco.h"
-
-#ifndef URB_ASYNC_UNLINK
-#define URB_ASYNC_UNLINK 0
-#endif
-
-struct header_struct {
- /* 802.3 */
- u8 dest[ETH_ALEN];
- u8 src[ETH_ALEN];
- __be16 len;
- /* 802.2 */
- u8 dsap;
- u8 ssap;
- u8 ctrl;
- /* SNAP */
- u8 oui[3];
- __be16 ethertype;
-} __packed;
-
-struct ez_usb_fw {
- u16 size;
- const u8 *code;
-};
-
-static struct ez_usb_fw firmware = {
- .size = 0,
- .code = NULL,
-};
-
-/* Debugging macros */
-#undef err
-#define err(format, arg...) \
- do { printk(KERN_ERR PFX format "\n", ## arg); } while (0)
-
-MODULE_FIRMWARE("orinoco_ezusb_fw");
-
-/*
- * Under some conditions, the card gets stuck and stops paying attention
- * to the world (i.e. data communication stalls) until we do something to
- * it. Sending an INQ_TALLIES command seems to be enough and should be
- * harmless otherwise. This behaviour has been observed when using the
- * driver on a systemimager client during installation. In the past a
- * timer was used to send INQ_TALLIES commands when there was no other
- * activity, but it was troublesome and was removed.
- */
-
-#define USB_COMPAQ_VENDOR_ID 0x049f /* Compaq Computer Corp. */
-#define USB_COMPAQ_WL215_ID 0x001f /* Compaq WL215 USB Adapter */
-#define USB_COMPAQ_W200_ID 0x0076 /* Compaq W200 USB Adapter */
-#define USB_HP_WL215_ID 0x0082 /* Compaq WL215 USB Adapter */
-
-#define USB_MELCO_VENDOR_ID 0x0411
-#define USB_BUFFALO_L11_ID 0x0006 /* BUFFALO WLI-USB-L11 */
-#define USB_BUFFALO_L11G_WR_ID 0x000B /* BUFFALO WLI-USB-L11G-WR */
-#define USB_BUFFALO_L11G_ID 0x000D /* BUFFALO WLI-USB-L11G */
-
-#define USB_LUCENT_VENDOR_ID 0x047E /* Lucent Technologies */
-#define USB_LUCENT_ORINOCO_ID 0x0300 /* Lucent/Agere Orinoco USB Client */
-
-#define USB_AVAYA8_VENDOR_ID 0x0D98
-#define USB_AVAYAE_VENDOR_ID 0x0D9E
-#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */
-
-#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */
-#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */
-#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */
-#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */
-
-#define USB_ELSA_VENDOR_ID 0x05CC
-#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */
-
-#define USB_LEGEND_VENDOR_ID 0x0E7C
-#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */
-
-#define USB_SAMSUNG_VENDOR_ID 0x04E8
-#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
-#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */
-#define USB_SAMSUNG_SEW2003U_ID 0x7011 /* Samsung SEW-2003U Card */
-
-#define USB_IGATE_VENDOR_ID 0x0681
-#define USB_IGATE_IGATE_11M_ID 0x0012 /* I-GATE 11M USB Card */
-
-#define USB_FUJITSU_VENDOR_ID 0x0BF8
-#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */
-
-#define USB_2WIRE_VENDOR_ID 0x1630
-#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */
-
-
-#define EZUSB_REQUEST_FW_TRANS 0xA0
-#define EZUSB_REQUEST_TRIGGER 0xAA
-#define EZUSB_REQUEST_TRIG_AC 0xAC
-#define EZUSB_CPUCS_REG 0x7F92
-
-#define EZUSB_RID_TX 0x0700
-#define EZUSB_RID_RX 0x0701
-#define EZUSB_RID_INIT1 0x0702
-#define EZUSB_RID_ACK 0x0710
-#define EZUSB_RID_READ_PDA 0x0800
-#define EZUSB_RID_PROG_INIT 0x0852
-#define EZUSB_RID_PROG_SET_ADDR 0x0853
-#define EZUSB_RID_PROG_BYTES 0x0854
-#define EZUSB_RID_PROG_END 0x0855
-#define EZUSB_RID_DOCMD 0x0860
-
-/* Recognize info frames */
-#define EZUSB_IS_INFO(id) ((id >= 0xF000) && (id <= 0xF2FF))
-
-#define EZUSB_MAGIC 0x0210
-
-#define EZUSB_FRAME_DATA 1
-#define EZUSB_FRAME_CONTROL 2
-
-#define DEF_TIMEOUT (3 * HZ)
-
-#define BULK_BUF_SIZE 2048
-
-#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
-
-#define FW_BUF_SIZE 64
-#define FW_VAR_OFFSET_PTR 0x359
-#define FW_VAR_VALUE 0
-#define FW_HOLE_START 0x100
-#define FW_HOLE_END 0x300
-
-struct ezusb_packet {
- __le16 magic; /* 0x0210 */
- u8 req_reply_count;
- u8 ans_reply_count;
- __le16 frame_type; /* 0x01 for data frames, 0x02 otherwise */
- __le16 size; /* transport size */
- __le16 crc; /* CRC up to here */
- __le16 hermes_len;
- __le16 hermes_rid;
- u8 data[];
-} __packed;
-
-/* Table of devices that work or may work with this driver */
-static const struct usb_device_id ezusb_table[] = {
- {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)},
- {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)},
- {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)},
- {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)},
- {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)},
- {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)},
- {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)},
- {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
- {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
- {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)},
- {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)},
- {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)},
- {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)},
- {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID,
- 0, 0)},
- {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)},
- {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)},
- {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)},
- {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)},
- {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)},
- {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)},
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ezusb_table);
-
-/* Structure to hold all of our device specific stuff */
-struct ezusb_priv {
- struct usb_device *udev;
- struct net_device *dev;
- struct mutex mtx;
- spinlock_t req_lock;
- struct list_head req_pending;
- struct list_head req_active;
- spinlock_t reply_count_lock;
- u16 hermes_reg_fake[0x40];
- u8 *bap_buf;
- struct urb *read_urb;
- int read_pipe;
- int write_pipe;
- u8 reply_count;
-};
-
-enum ezusb_state {
- EZUSB_CTX_START,
- EZUSB_CTX_QUEUED,
- EZUSB_CTX_REQ_SUBMITTED,
- EZUSB_CTX_REQ_COMPLETE,
- EZUSB_CTX_RESP_RECEIVED,
- EZUSB_CTX_REQ_TIMEOUT,
- EZUSB_CTX_REQ_FAILED,
- EZUSB_CTX_RESP_TIMEOUT,
- EZUSB_CTX_REQSUBMIT_FAIL,
- EZUSB_CTX_COMPLETE,
-};
-
-struct request_context {
- struct list_head list;
- refcount_t refcount;
- struct completion done; /* Signals that CTX is dead */
- int killed;
- struct urb *outurb; /* OUT for req pkt */
- struct ezusb_priv *upriv;
- struct ezusb_packet *buf;
- int buf_length;
- struct timer_list timer; /* Timeout handling */
- enum ezusb_state state; /* Current state */
- /* the RID that we will wait for */
- u16 out_rid;
- u16 in_rid;
-};
-
-
-/* Forward declarations */
-static void ezusb_ctx_complete(struct request_context *ctx);
-static void ezusb_req_queue_run(struct ezusb_priv *upriv);
-static void ezusb_bulk_in_callback(struct urb *urb);
-
-static inline u8 ezusb_reply_inc(u8 count)
-{
- if (count < 0x7F)
- return count + 1;
- else
- return 1;
-}
-
-static void ezusb_request_context_put(struct request_context *ctx)
-{
- if (!refcount_dec_and_test(&ctx->refcount))
- return;
-
- WARN_ON(!ctx->done.done);
- BUG_ON(ctx->outurb->status == -EINPROGRESS);
- BUG_ON(timer_pending(&ctx->timer));
- usb_free_urb(ctx->outurb);
- kfree(ctx->buf);
- kfree(ctx);
-}
-
-static inline void ezusb_mod_timer(struct ezusb_priv *upriv,
- struct timer_list *timer,
- unsigned long expire)
-{
- if (!upriv->udev)
- return;
- mod_timer(timer, expire);
-}
-
-static void ezusb_request_timerfn(struct timer_list *t)
-{
- struct request_context *ctx = from_timer(ctx, t, timer);
-
- ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
- if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) {
- ctx->state = EZUSB_CTX_REQ_TIMEOUT;
- } else {
- ctx->state = EZUSB_CTX_RESP_TIMEOUT;
- dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n");
- refcount_inc(&ctx->refcount);
- ctx->killed = 1;
- ezusb_ctx_complete(ctx);
- ezusb_request_context_put(ctx);
- }
-};
-
-static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
- u16 out_rid, u16 in_rid)
-{
- struct request_context *ctx;
-
- ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
- if (!ctx)
- return NULL;
-
- ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
- if (!ctx->buf) {
- kfree(ctx);
- return NULL;
- }
- ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!ctx->outurb) {
- kfree(ctx->buf);
- kfree(ctx);
- return NULL;
- }
-
- ctx->upriv = upriv;
- ctx->state = EZUSB_CTX_START;
- ctx->out_rid = out_rid;
- ctx->in_rid = in_rid;
-
- refcount_set(&ctx->refcount, 1);
- init_completion(&ctx->done);
-
- timer_setup(&ctx->timer, ezusb_request_timerfn, 0);
- return ctx;
-}
-
-static void ezusb_ctx_complete(struct request_context *ctx)
-{
- struct ezusb_priv *upriv = ctx->upriv;
- unsigned long flags;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- list_del_init(&ctx->list);
- if (upriv->udev) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- ezusb_req_queue_run(upriv);
- spin_lock_irqsave(&upriv->req_lock, flags);
- }
-
- switch (ctx->state) {
- case EZUSB_CTX_COMPLETE:
- case EZUSB_CTX_REQSUBMIT_FAIL:
- case EZUSB_CTX_REQ_FAILED:
- case EZUSB_CTX_REQ_TIMEOUT:
- case EZUSB_CTX_RESP_TIMEOUT:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) {
- struct net_device *dev = upriv->dev;
- struct net_device_stats *stats = &dev->stats;
-
- if (ctx->state != EZUSB_CTX_COMPLETE)
- stats->tx_errors++;
- else
- stats->tx_packets++;
-
- netif_wake_queue(dev);
- }
- complete_all(&ctx->done);
- ezusb_request_context_put(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- if (!upriv->udev) {
- /* This is normal, as all request contexts get flushed
- * when the device is disconnected */
- err("Called, CTX not terminating, but device gone");
- complete_all(&ctx->done);
- ezusb_request_context_put(ctx);
- break;
- }
-
- err("Called, CTX not in terminating state.");
- /* Things are really bad if this happens. Just leak
- * the CTX because it may still be linked to the
- * queue or the OUT urb may still be active.
- * Just leaking at least prevents an Oops or Panic.
- */
- break;
- }
-}
-
-/*
- * ezusb_req_queue_run:
- * Description:
- * Note: Only one active CTX at any one time, because there's no
- * other (reliable) way to match the response URB to the correct
- * CTX.
- */
-static void ezusb_req_queue_run(struct ezusb_priv *upriv)
-{
- unsigned long flags;
- struct request_context *ctx;
- int result;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- if (!list_empty(&upriv->req_active))
- goto unlock;
-
- if (list_empty(&upriv->req_pending))
- goto unlock;
-
- ctx =
- list_entry(upriv->req_pending.next, struct request_context,
- list);
-
- if (!ctx->upriv->udev)
- goto unlock;
-
- /* We need to split this off to avoid a race condition */
- list_move_tail(&ctx->list, &upriv->req_active);
-
- if (ctx->state == EZUSB_CTX_QUEUED) {
- refcount_inc(&ctx->refcount);
- result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
- if (result) {
- ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
-
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- err("Fatal, failed to submit command urb."
- " error=%d\n", result);
-
- ezusb_ctx_complete(ctx);
- ezusb_request_context_put(ctx);
- goto done;
- }
-
- ctx->state = EZUSB_CTX_REQ_SUBMITTED;
- ezusb_mod_timer(ctx->upriv, &ctx->timer,
- jiffies + DEF_TIMEOUT);
- }
-
- unlock:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- done:
- return;
-}
-
-static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- if (!ctx->upriv->udev) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- goto done;
- }
- refcount_inc(&ctx->refcount);
- list_add_tail(&ctx->list, &upriv->req_pending);
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- ctx->state = EZUSB_CTX_QUEUED;
- ezusb_req_queue_run(upriv);
-
- done:
- return;
-}
-
-static void ezusb_request_out_callback(struct urb *urb)
-{
- unsigned long flags;
- enum ezusb_state state;
- struct request_context *ctx = urb->context;
- struct ezusb_priv *upriv = ctx->upriv;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- del_timer(&ctx->timer);
-
- if (ctx->killed) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- pr_warn("interrupt called with dead ctx\n");
- goto out;
- }
-
- state = ctx->state;
-
- if (urb->status == 0) {
- switch (state) {
- case EZUSB_CTX_REQ_SUBMITTED:
- if (ctx->in_rid) {
- ctx->state = EZUSB_CTX_REQ_COMPLETE;
- /* reply URB still pending */
- ezusb_mod_timer(upriv, &ctx->timer,
- jiffies + DEF_TIMEOUT);
- spin_unlock_irqrestore(&upriv->req_lock,
- flags);
- break;
- }
- fallthrough;
- case EZUSB_CTX_RESP_RECEIVED:
- /* IN already received before this OUT-ACK */
- ctx->state = EZUSB_CTX_COMPLETE;
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- ezusb_ctx_complete(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- err("Unexpected state(0x%x, %d) in OUT URB",
- state, urb->status);
- break;
- }
- } else {
- /* If someone cancels the OUT URB then its status
- * should be either -ECONNRESET or -ENOENT.
- */
- switch (state) {
- case EZUSB_CTX_REQ_SUBMITTED:
- case EZUSB_CTX_RESP_RECEIVED:
- ctx->state = EZUSB_CTX_REQ_FAILED;
- fallthrough;
-
- case EZUSB_CTX_REQ_FAILED:
- case EZUSB_CTX_REQ_TIMEOUT:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- ezusb_ctx_complete(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- err("Unexpected state(0x%x, %d) in OUT URB",
- state, urb->status);
- break;
- }
- }
- out:
- ezusb_request_context_put(ctx);
-}
-
-static void ezusb_request_in_callback(struct ezusb_priv *upriv,
- struct urb *urb)
-{
- struct ezusb_packet *ans = urb->transfer_buffer;
- struct request_context *ctx = NULL;
- enum ezusb_state state;
- unsigned long flags;
-
- /* Find the CTX on the active queue that requested this URB */
- spin_lock_irqsave(&upriv->req_lock, flags);
- if (upriv->udev) {
- struct list_head *item;
-
- list_for_each(item, &upriv->req_active) {
- struct request_context *c;
- int reply_count;
-
- c = list_entry(item, struct request_context, list);
- reply_count =
- ezusb_reply_inc(c->buf->req_reply_count);
- if ((ans->ans_reply_count == reply_count)
- && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) {
- ctx = c;
- break;
- }
- netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n",
- le16_to_cpu(ans->hermes_rid), c->in_rid,
- ans->ans_reply_count, reply_count);
- }
- }
-
- if (ctx == NULL) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- err("%s: got unexpected RID: 0x%04X", __func__,
- le16_to_cpu(ans->hermes_rid));
- ezusb_req_queue_run(upriv);
- return;
- }
-
- /* The data we want is in the in buffer, exchange */
- urb->transfer_buffer = ctx->buf;
- ctx->buf = (void *) ans;
- ctx->buf_length = urb->actual_length;
-
- state = ctx->state;
- switch (state) {
- case EZUSB_CTX_REQ_SUBMITTED:
- /* We have received our response URB before
- * our request has been acknowledged. Do NOT
- * destroy our CTX yet, because our OUT URB
- * is still alive ...
- */
- ctx->state = EZUSB_CTX_RESP_RECEIVED;
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- /* Let the machine continue running. */
- break;
-
- case EZUSB_CTX_REQ_COMPLETE:
- /* This is the usual path: our request
- * has already been acknowledged, and
- * we have now received the reply.
- */
- ctx->state = EZUSB_CTX_COMPLETE;
-
- /* Stop the intimer */
- del_timer(&ctx->timer);
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- /* Call the completion handler */
- ezusb_ctx_complete(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- pr_warn("Matched IN URB, unexpected context state(0x%x)\n",
- state);
- /* Throw this CTX away and try submitting another */
- del_timer(&ctx->timer);
- ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
- usb_unlink_urb(ctx->outurb);
- ezusb_req_queue_run(upriv);
- break;
- } /* switch */
-}
-
-typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *);
-
-static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- switch (ctx->state) {
- case EZUSB_CTX_QUEUED:
- case EZUSB_CTX_REQ_SUBMITTED:
- case EZUSB_CTX_REQ_COMPLETE:
- case EZUSB_CTX_RESP_RECEIVED:
- wait_for_completion(&ctx->done);
- break;
- default:
- /* Done or failed - nothing to wait for */
- break;
- }
-}
-
-static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- int msecs;
-
- switch (ctx->state) {
- case EZUSB_CTX_QUEUED:
- case EZUSB_CTX_REQ_SUBMITTED:
- case EZUSB_CTX_REQ_COMPLETE:
- case EZUSB_CTX_RESP_RECEIVED:
- /* If we get called from a timer or with our lock acquired, then
- * we can't wait for the completion and have to poll. This won't
- * happen if the USB controller completes the URB requests in
- * BH.
- */
- msecs = DEF_TIMEOUT * (1000 / HZ);
-
- while (!try_wait_for_completion(&ctx->done) && msecs--)
- udelay(1000);
- break;
- default:
- /* Done or failed - nothing to wait for */
- break;
- }
-}
-
-static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- WARN(1, "Shouldn't be invoked for in_rid\n");
-}
-
-static inline u16 build_crc(struct ezusb_packet *data)
-{
- u16 crc = 0;
- u8 *bytes = (u8 *)data;
- int i;
-
- for (i = 0; i < 8; i++)
- crc = (crc << 1) + bytes[i];
-
- return crc;
-}
-
-/*
- * ezusb_fill_req:
- *
- * if data == NULL and length > 0 the data is assumed to be already in
- * the target buffer and only the header is filled.
- *
- */
-static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid,
- const void *data, u16 frame_type, u8 reply_count)
-{
- int total_size = sizeof(*req) + length;
-
- BUG_ON(total_size > BULK_BUF_SIZE);
-
- req->magic = cpu_to_le16(EZUSB_MAGIC);
- req->req_reply_count = reply_count;
- req->ans_reply_count = 0;
- req->frame_type = cpu_to_le16(frame_type);
- req->size = cpu_to_le16(length + 4);
- req->crc = cpu_to_le16(build_crc(req));
- req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length));
- req->hermes_rid = cpu_to_le16(rid);
- if (data)
- memcpy(req->data, data, length);
- return total_size;
-}
-
-static int ezusb_submit_in_urb(struct ezusb_priv *upriv)
-{
- int retval = 0;
- void *cur_buf = upriv->read_urb->transfer_buffer;
-
- if (upriv->read_urb->status == -EINPROGRESS) {
- netdev_dbg(upriv->dev, "urb busy, not resubmiting\n");
- retval = -EBUSY;
- goto exit;
- }
- usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe,
- cur_buf, BULK_BUF_SIZE,
- ezusb_bulk_in_callback, upriv);
- upriv->read_urb->transfer_flags = 0;
- retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC);
- if (retval)
- err("%s submit failed %d", __func__, retval);
-
- exit:
- return retval;
-}
-
-static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
-{
- int ret;
- u8 *res_val = NULL;
-
- if (!upriv->udev) {
- err("%s: !upriv->udev", __func__);
- return -EFAULT;
- }
-
- res_val = kmalloc(sizeof(*res_val), GFP_KERNEL);
-
- if (!res_val)
- return -ENOMEM;
-
- *res_val = reset; /* avoid argument promotion */
-
- ret = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_FW_TRANS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_OUT, EZUSB_CPUCS_REG, 0, res_val,
- sizeof(*res_val), DEF_TIMEOUT);
-
- kfree(res_val);
-
- return ret;
-}
-
-static int ezusb_firmware_download(struct ezusb_priv *upriv,
- struct ez_usb_fw *fw)
-{
- u8 *fw_buffer;
- int retval, addr;
- int variant_offset;
-
- fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL);
- if (!fw_buffer) {
- printk(KERN_ERR PFX "Out of memory for firmware buffer.\n");
- return -ENOMEM;
- }
- /*
- * This byte is 1 and should be replaced with 0. The offset is
- * 0x10AD in version 0.0.6. The byte in question should follow
- * the end of the code pointed to by the jump in the beginning
- * of the firmware. Also, it is read by code located at 0x358.
- */
- variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]);
- if (variant_offset >= fw->size) {
- printk(KERN_ERR PFX "Invalid firmware variant offset: "
- "0x%04x\n", variant_offset);
- retval = -EINVAL;
- goto fail;
- }
-
- retval = ezusb_8051_cpucs(upriv, 1);
- if (retval < 0)
- goto fail;
- for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) {
- /* 0x100-0x300 should be left alone, it contains card
- * specific data, like USB enumeration information */
- if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END))
- continue;
-
- memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE);
- if (variant_offset >= addr &&
- variant_offset < addr + FW_BUF_SIZE) {
- netdev_dbg(upriv->dev,
- "Patching card_variant byte at 0x%04X\n",
- variant_offset);
- fw_buffer[variant_offset - addr] = FW_VAR_VALUE;
- }
- retval = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_FW_TRANS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE
- | USB_DIR_OUT,
- addr, 0x0,
- fw_buffer, FW_BUF_SIZE,
- DEF_TIMEOUT);
-
- if (retval < 0)
- goto fail;
- }
- retval = ezusb_8051_cpucs(upriv, 0);
- if (retval < 0)
- goto fail;
-
- goto exit;
- fail:
- printk(KERN_ERR PFX "Firmware download failed, error %d\n",
- retval);
- exit:
- kfree(fw_buffer);
- return retval;
-}
-
-static int ezusb_access_ltv(struct ezusb_priv *upriv,
- struct request_context *ctx,
- u16 length, const void *data, u16 frame_type,
- void *ans_buff, unsigned ans_size, u16 *ans_length,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-{
- int req_size;
- int retval = 0;
- enum ezusb_state state;
-
- if (!upriv->udev) {
- retval = -ENODEV;
- goto exit;
- }
-
- if (upriv->read_urb->status != -EINPROGRESS)
- err("%s: in urb not pending", __func__);
-
- /* protect upriv->reply_count, guarantee sequential numbers */
- spin_lock_bh(&upriv->reply_count_lock);
- req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data,
- frame_type, upriv->reply_count);
- usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe,
- ctx->buf, req_size,
- ezusb_request_out_callback, ctx);
-
- if (ctx->in_rid)
- upriv->reply_count = ezusb_reply_inc(upriv->reply_count);
-
- ezusb_req_enqueue_run(upriv, ctx);
-
- spin_unlock_bh(&upriv->reply_count_lock);
-
- if (ctx->in_rid)
- ezusb_ctx_wait_func(upriv, ctx);
-
- state = ctx->state;
- switch (state) {
- case EZUSB_CTX_COMPLETE:
- retval = ctx->outurb->status;
- break;
-
- case EZUSB_CTX_QUEUED:
- case EZUSB_CTX_REQ_SUBMITTED:
- if (!ctx->in_rid)
- break;
- fallthrough;
- default:
- err("%s: Unexpected context state %d", __func__,
- state);
- fallthrough;
- case EZUSB_CTX_REQ_TIMEOUT:
- case EZUSB_CTX_REQ_FAILED:
- case EZUSB_CTX_RESP_TIMEOUT:
- case EZUSB_CTX_REQSUBMIT_FAIL:
- printk(KERN_ERR PFX "Access failed, resetting (state %d,"
- " reply_count %d)\n", state, upriv->reply_count);
- upriv->reply_count = 0;
- if (state == EZUSB_CTX_REQ_TIMEOUT
- || state == EZUSB_CTX_RESP_TIMEOUT) {
- printk(KERN_ERR PFX "ctx timed out\n");
- retval = -ETIMEDOUT;
- } else {
- printk(KERN_ERR PFX "ctx failed\n");
- retval = -EFAULT;
- }
- goto exit;
- }
- if (ctx->in_rid) {
- struct ezusb_packet *ans = ctx->buf;
- unsigned exp_len;
-
- if (ans->hermes_len != 0)
- exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
- else
- exp_len = 14;
-
- if (exp_len != ctx->buf_length) {
- err("%s: length mismatch for RID 0x%04x: "
- "expected %d, got %d", __func__,
- ctx->in_rid, exp_len, ctx->buf_length);
- retval = -EIO;
- goto exit;
- }
-
- if (ans_buff)
- memcpy(ans_buff, ans->data, min(exp_len, ans_size));
- if (ans_length)
- *ans_length = le16_to_cpu(ans->hermes_len);
- }
- exit:
- ezusb_request_context_put(ctx);
- return retval;
-}
-
-static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *data,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-{
- struct ezusb_priv *upriv = hw->priv;
- u16 frame_type;
- struct request_context *ctx;
-
- if (length == 0)
- return -EINVAL;
-
- length = HERMES_RECLEN_TO_BYTES(length);
-
- /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be
- * set to be empty, but the USB bridge doesn't like it */
- if (length == 0)
- return 0;
-
- ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- if (rid == EZUSB_RID_TX)
- frame_type = EZUSB_FRAME_DATA;
- else
- frame_type = EZUSB_FRAME_CONTROL;
-
- return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
- NULL, 0, NULL, ezusb_ctx_wait_func);
-}
-
-static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *data)
-{
- return __ezusb_write_ltv(hw, bap, rid, length, data,
- ezusb_req_ctx_wait_poll);
-}
-
-static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
-
- if (bufsize % 2)
- return -EINVAL;
-
- ctx = ezusb_alloc_ctx(upriv, rid, rid);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
- buf, bufsize, length, ezusb_req_ctx_wait_poll);
-}
-
-static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf)
-{
- return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
- ezusb_req_ctx_wait_poll);
-}
-
-static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf)
-{
- return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1,
- u16 parm2, struct hermes_response *resp)
-{
- WARN_ON_ONCE(1);
- return -EINVAL;
-}
-
-static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
-
- __le16 data[4] = {
- cpu_to_le16(cmd),
- cpu_to_le16(parm0),
- 0,
- 0,
- };
- netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0);
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_ctx_wait_func);
-}
-
-static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp)
-{
- return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll);
-}
-
-static int ezusb_bap_pread(struct hermes *hw, int bap,
- void *buf, int len, u16 id, u16 offset)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer;
- int actual_length = upriv->read_urb->actual_length;
-
- if (id == EZUSB_RID_RX) {
- if ((sizeof(*ans) + offset + len) > actual_length) {
- printk(KERN_ERR PFX "BAP read beyond buffer end "
- "in rx frame\n");
- return -EINVAL;
- }
- memcpy(buf, ans->data + offset, len);
- return 0;
- }
-
- if (EZUSB_IS_INFO(id)) {
- /* Include 4 bytes for length/type */
- if ((sizeof(*ans) + offset + len - 4) > actual_length) {
- printk(KERN_ERR PFX "BAP read beyond buffer end "
- "in info frame\n");
- return -EFAULT;
- }
- memcpy(buf, ans->data + offset - 4, len);
- } else {
- printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
- u32 pda_addr, u16 pda_len)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
- __le16 data[] = {
- cpu_to_le16(pda_addr & 0xffff),
- cpu_to_le16(pda_len - 4)
- };
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
- if (!ctx)
- return -ENOMEM;
-
- /* wl_lkm does not include PDA size in the PDA area.
- * We will pad the information into pda, so other routines
- * don't have to be modified */
- pda[0] = cpu_to_le16(pda_len - 2);
- /* Includes CFG_PROD_DATA but not itself */
- pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
-
- return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
- NULL, ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program_init(struct hermes *hw, u32 entry_point)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
- __le32 data = cpu_to_le32(entry_point);
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program_end(struct hermes *hw)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, 0, NULL,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program_bytes(struct hermes *hw, const char *buf,
- u32 addr, u32 len)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
- __le32 data = cpu_to_le32(addr);
- int err;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
- if (err)
- return err;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, len, buf,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program(struct hermes *hw, const char *buf,
- u32 addr, u32 len)
-{
- u32 ch_addr;
- u32 ch_len;
- int err = 0;
-
- /* We can only send 2048 bytes out of the bulk xmit at a time,
- * so we have to split any programming into chunks of <2048
- * bytes. */
-
- ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
- ch_addr = addr;
-
- while (ch_addr < (addr + len)) {
- pr_debug("Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- ch_len, ch_addr, &buf[ch_addr - addr]);
-
- err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
- ch_addr, ch_len);
- if (err)
- break;
-
- ch_addr += ch_len;
- ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
- (addr + len - ch_addr) : MAX_DL_SIZE;
- }
-
- return err;
-}
-
-static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct ezusb_priv *upriv = priv->card;
- u8 mic[MICHAEL_MIC_LEN + 1];
- int err = 0;
- int tx_control;
- unsigned long flags;
- struct request_context *ctx;
- u8 *buf;
- int tx_size;
-
- if (!netif_running(dev)) {
- printk(KERN_ERR "%s: Tx on stopped device!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (netif_queue_stopped(dev)) {
- printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (orinoco_lock(priv, &flags) != 0) {
- printk(KERN_ERR
- "%s: ezusb_xmit() called while hw_unavailable\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (!netif_carrier_ok(dev) ||
- (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
- /* Oops, the firmware hasn't established a connection,
- silently drop the packet (this seems to be the
- safest approach). */
- goto drop;
- }
-
- /* Check packet length */
- if (skb->len < ETH_HLEN)
- goto drop;
-
- tx_control = 0;
-
- err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
- &mic[0]);
- if (err)
- goto drop;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
- if (!ctx)
- goto drop;
-
- memset(ctx->buf, 0, BULK_BUF_SIZE);
- buf = ctx->buf->data;
-
- {
- __le16 *tx_cntl = (__le16 *)buf;
- *tx_cntl = cpu_to_le16(tx_control);
- buf += sizeof(*tx_cntl);
- }
-
- memcpy(buf, skb->data, skb->len);
- buf += skb->len;
-
- if (tx_control & HERMES_TXCTRL_MIC) {
- u8 *m = mic;
- /* Mic has been offset so it can be copied to an even
- * address. We're copying eveything anyway, so we
- * don't need to copy that first byte. */
- if (skb->len % 2)
- m++;
- memcpy(buf, m, MICHAEL_MIC_LEN);
- buf += MICHAEL_MIC_LEN;
- }
-
- /* Finally, we actually initiate the send */
- netif_stop_queue(dev);
-
- /* The card may behave better if we send evenly sized usb transfers */
- tx_size = ALIGN(buf - ctx->buf->data, 2);
-
- err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
- EZUSB_FRAME_DATA, NULL, 0, NULL,
- ezusb_req_ctx_wait_skip);
-
- if (err) {
- netif_start_queue(dev);
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d transmitting packet\n",
- dev->name, err);
- goto busy;
- }
-
- netif_trans_update(dev);
- stats->tx_bytes += skb->len;
- goto ok;
-
- drop:
- stats->tx_errors++;
- stats->tx_dropped++;
-
- ok:
- orinoco_unlock(priv, &flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-
- busy:
- orinoco_unlock(priv, &flags);
- return NETDEV_TX_BUSY;
-}
-
-static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid)
-{
- *fid = EZUSB_RID_TX;
- return 0;
-}
-
-
-static int ezusb_hard_reset(struct orinoco_private *priv)
-{
- struct ezusb_priv *upriv = priv->card;
- int retval = ezusb_8051_cpucs(upriv, 1);
-
- if (retval < 0) {
- err("Failed to reset");
- return retval;
- }
-
- retval = ezusb_8051_cpucs(upriv, 0);
- if (retval < 0) {
- err("Failed to unreset");
- return retval;
- }
-
- netdev_dbg(upriv->dev, "sending control message\n");
- retval = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_TRIGGER,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_OUT, 0x0, 0x0, NULL, 0,
- DEF_TIMEOUT);
- if (retval < 0) {
- err("EZUSB_REQUEST_TRIGGER failed retval %d", retval);
- return retval;
- }
-#if 0
- dbg("Sending EZUSB_REQUEST_TRIG_AC");
- retval = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_TRIG_AC,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_OUT, 0x00FA, 0x0, NULL, 0,
- DEF_TIMEOUT);
- if (retval < 0) {
- err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval);
- return retval;
- }
-#endif
-
- return 0;
-}
-
-
-static int ezusb_init(struct hermes *hw)
-{
- struct ezusb_priv *upriv = hw->priv;
- int retval;
-
- if (!upriv)
- return -EINVAL;
-
- upriv->reply_count = 0;
- /* Write the MAGIC number on the simulated registers to keep
- * orinoco.c happy */
- hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
- hermes_write_regn(hw, RXFID, EZUSB_RID_RX);
-
- usb_kill_urb(upriv->read_urb);
- ezusb_submit_in_urb(upriv);
-
- retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
- HERMES_BYTES_TO_RECLEN(2), "\x10\x00",
- ezusb_req_ctx_wait_compl);
- if (retval < 0) {
- printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
- return retval;
- }
-
- retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL,
- ezusb_req_ctx_wait_compl);
- if (retval < 0) {
- printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
- return retval;
- }
-
- return 0;
-}
-
-static void ezusb_bulk_in_callback(struct urb *urb)
-{
- struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context;
- struct ezusb_packet *ans = urb->transfer_buffer;
- u16 crc;
- u16 hermes_rid;
-
- if (upriv->udev == NULL)
- return;
-
- if (urb->status == -ETIMEDOUT) {
- /* When a device gets unplugged we get this every time
- * we resubmit, flooding the logs. Since we don't use
- * USB timeouts, it shouldn't happen any other time*/
- pr_warn("%s: urb timed out, not resubmitting\n", __func__);
- return;
- }
- if (urb->status == -ECONNABORTED) {
- pr_warn("%s: connection abort, resubmitting urb\n",
- __func__);
- goto resubmit;
- }
- if ((urb->status == -EILSEQ)
- || (urb->status == -ENOENT)
- || (urb->status == -ECONNRESET)) {
- netdev_dbg(upriv->dev, "status %d, not resubmiting\n",
- urb->status);
- return;
- }
- if (urb->status)
- netdev_dbg(upriv->dev, "status: %d length: %d\n",
- urb->status, urb->actual_length);
- if (urb->actual_length < sizeof(*ans)) {
- err("%s: short read, ignoring", __func__);
- goto resubmit;
- }
- crc = build_crc(ans);
- if (le16_to_cpu(ans->crc) != crc) {
- err("CRC error, ignoring packet");
- goto resubmit;
- }
-
- hermes_rid = le16_to_cpu(ans->hermes_rid);
- if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) {
- ezusb_request_in_callback(upriv, urb);
- } else if (upriv->dev) {
- struct net_device *dev = upriv->dev;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
-
- if (hermes_rid == EZUSB_RID_RX) {
- __orinoco_ev_rx(dev, hw);
- } else {
- hermes_write_regn(hw, INFOFID,
- le16_to_cpu(ans->hermes_rid));
- __orinoco_ev_info(dev, hw);
- }
- }
-
- resubmit:
- if (upriv->udev)
- ezusb_submit_in_urb(upriv);
-}
-
-static inline void ezusb_delete(struct ezusb_priv *upriv)
-{
- struct list_head *item;
- struct list_head *tmp_item;
- unsigned long flags;
-
- BUG_ON(!upriv);
-
- mutex_lock(&upriv->mtx);
-
- upriv->udev = NULL; /* No timer will be rearmed from here */
-
- usb_kill_urb(upriv->read_urb);
-
- spin_lock_irqsave(&upriv->req_lock, flags);
- list_for_each_safe(item, tmp_item, &upriv->req_active) {
- struct request_context *ctx;
- int err;
-
- ctx = list_entry(item, struct request_context, list);
- refcount_inc(&ctx->refcount);
-
- ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
- err = usb_unlink_urb(ctx->outurb);
-
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- if (err == -EINPROGRESS)
- wait_for_completion(&ctx->done);
-
- del_timer_sync(&ctx->timer);
- /* FIXME: there is an slight chance for the irq handler to
- * be running */
- if (!list_empty(&ctx->list))
- ezusb_ctx_complete(ctx);
-
- ezusb_request_context_put(ctx);
- spin_lock_irqsave(&upriv->req_lock, flags);
- }
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- list_for_each_safe(item, tmp_item, &upriv->req_pending)
- ezusb_ctx_complete(list_entry(item,
- struct request_context, list));
-
- if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS)
- printk(KERN_ERR PFX "Some URB in progress\n");
-
- mutex_unlock(&upriv->mtx);
-
- if (upriv->read_urb) {
- kfree(upriv->read_urb->transfer_buffer);
- usb_free_urb(upriv->read_urb);
- }
- kfree(upriv->bap_buf);
- if (upriv->dev) {
- struct orinoco_private *priv = ndev_priv(upriv->dev);
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(upriv));
- free_orinocodev(priv);
- }
-}
-
-static void ezusb_lock_irqsave(spinlock_t *lock,
- unsigned long *flags) __acquires(lock)
-{
- spin_lock_bh(lock);
-}
-
-static void ezusb_unlock_irqrestore(spinlock_t *lock,
- unsigned long *flags) __releases(lock)
-{
- spin_unlock_bh(lock);
-}
-
-static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock)
-{
- spin_lock_bh(lock);
-}
-
-static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock)
-{
- spin_unlock_bh(lock);
-}
-
-static const struct hermes_ops ezusb_ops = {
- .init = ezusb_init,
- .cmd_wait = ezusb_docmd_wait,
- .init_cmd_wait = ezusb_doicmd_wait,
- .allocate = ezusb_allocate,
- .read_ltv = ezusb_read_ltv,
- .read_ltv_pr = ezusb_read_ltv_preempt,
- .write_ltv = ezusb_write_ltv,
- .bap_pread = ezusb_bap_pread,
- .read_pda = ezusb_read_pda,
- .program_init = ezusb_program_init,
- .program_end = ezusb_program_end,
- .program = ezusb_program,
- .lock_irqsave = ezusb_lock_irqsave,
- .unlock_irqrestore = ezusb_unlock_irqrestore,
- .lock_irq = ezusb_lock_irq,
- .unlock_irq = ezusb_unlock_irq,
-};
-
-static const struct net_device_ops ezusb_netdev_ops = {
- .ndo_open = orinoco_open,
- .ndo_stop = orinoco_stop,
- .ndo_start_xmit = ezusb_xmit,
- .ndo_set_rx_mode = orinoco_set_multicast_list,
- .ndo_change_mtu = orinoco_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_tx_timeout = orinoco_tx_timeout,
-};
-
-static int ezusb_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(interface);
- struct orinoco_private *priv;
- struct hermes *hw;
- struct ezusb_priv *upriv = NULL;
- struct usb_interface_descriptor *iface_desc;
- struct usb_endpoint_descriptor *ep;
- const struct firmware *fw_entry = NULL;
- int retval = 0;
- int i;
-
- priv = alloc_orinocodev(sizeof(*upriv), &udev->dev,
- ezusb_hard_reset, NULL);
- if (!priv) {
- err("Couldn't allocate orinocodev");
- retval = -ENOMEM;
- goto exit;
- }
-
- hw = &priv->hw;
-
- upriv = priv->card;
-
- mutex_init(&upriv->mtx);
- spin_lock_init(&upriv->reply_count_lock);
-
- spin_lock_init(&upriv->req_lock);
- INIT_LIST_HEAD(&upriv->req_pending);
- INIT_LIST_HEAD(&upriv->req_active);
-
- upriv->udev = udev;
-
- hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake;
- hw->reg_spacing = HERMES_16BIT_REGSPACING;
- hw->priv = upriv;
- hw->ops = &ezusb_ops;
-
- /* set up the endpoint information */
- /* check out the endpoints */
-
- iface_desc = &interface->cur_altsetting->desc;
- for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
- ep = &interface->cur_altsetting->endpoint[i].desc;
-
- if (usb_endpoint_is_bulk_in(ep)) {
- /* we found a bulk in endpoint */
- if (upriv->read_urb != NULL) {
- pr_warn("Found a second bulk in ep, ignored\n");
- continue;
- }
-
- upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!upriv->read_urb)
- goto error;
- if (le16_to_cpu(ep->wMaxPacketSize) != 64)
- pr_warn("bulk in: wMaxPacketSize!= 64\n");
- if (ep->bEndpointAddress != (2 | USB_DIR_IN))
- pr_warn("bulk in: bEndpointAddress: %d\n",
- ep->bEndpointAddress);
- upriv->read_pipe = usb_rcvbulkpipe(udev,
- ep->
- bEndpointAddress);
- upriv->read_urb->transfer_buffer =
- kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
- if (!upriv->read_urb->transfer_buffer) {
- err("Couldn't allocate IN buffer");
- goto error;
- }
- }
-
- if (usb_endpoint_is_bulk_out(ep)) {
- /* we found a bulk out endpoint */
- if (upriv->bap_buf != NULL) {
- pr_warn("Found a second bulk out ep, ignored\n");
- continue;
- }
-
- if (le16_to_cpu(ep->wMaxPacketSize) != 64)
- pr_warn("bulk out: wMaxPacketSize != 64\n");
- if (ep->bEndpointAddress != 2)
- pr_warn("bulk out: bEndpointAddress: %d\n",
- ep->bEndpointAddress);
- upriv->write_pipe = usb_sndbulkpipe(udev,
- ep->
- bEndpointAddress);
- upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
- if (!upriv->bap_buf) {
- err("Couldn't allocate bulk_out_buffer");
- goto error;
- }
- }
- }
- if (!upriv->bap_buf || !upriv->read_urb) {
- err("Didn't find the required bulk endpoints");
- goto error;
- }
-
- if (request_firmware(&fw_entry, "orinoco_ezusb_fw",
- &interface->dev) == 0) {
- firmware.size = fw_entry->size;
- firmware.code = fw_entry->data;
- }
- if (firmware.size && firmware.code) {
- if (ezusb_firmware_download(upriv, &firmware) < 0)
- goto error;
- } else {
- err("No firmware to download");
- goto error;
- }
-
- if (ezusb_hard_reset(priv) < 0) {
- err("Cannot reset the device");
- goto error;
- }
-
- /* If the firmware is already downloaded orinoco.c will call
- * ezusb_init but if the firmware is not already there, that will make
- * the kernel very unstable, so we try initializing here and quit in
- * case of error */
- if (ezusb_init(hw) < 0) {
- err("Couldn't initialize the device");
- err("Firmware may not be downloaded or may be wrong.");
- goto error;
- }
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- err("orinoco_init() failed\n");
- goto error;
- }
-
- if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {
- upriv->dev = NULL;
- err("%s: orinoco_if_add() failed", __func__);
- wiphy_unregister(priv_to_wiphy(priv));
- goto error;
- }
- upriv->dev = priv->ndev;
-
- goto exit;
-
- error:
- ezusb_delete(upriv);
- if (upriv->dev) {
- /* upriv->dev was 0, so ezusb_delete() didn't free it */
- free_orinocodev(priv);
- }
- upriv = NULL;
- retval = -EFAULT;
- exit:
- if (fw_entry) {
- firmware.code = NULL;
- firmware.size = 0;
- release_firmware(fw_entry);
- }
- usb_set_intfdata(interface, upriv);
- return retval;
-}
-
-
-static void ezusb_disconnect(struct usb_interface *intf)
-{
- struct ezusb_priv *upriv = usb_get_intfdata(intf);
- usb_set_intfdata(intf, NULL);
- ezusb_delete(upriv);
- printk(KERN_INFO PFX "Disconnected\n");
-}
-
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver orinoco_driver = {
- .name = DRIVER_NAME,
- .probe = ezusb_probe,
- .disconnect = ezusb_disconnect,
- .id_table = ezusb_table,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(orinoco_driver);
-
-MODULE_AUTHOR("Manuel Estrada Sainz");
-MODULE_DESCRIPTION("Driver for Orinoco wireless LAN cards using EZUSB bridge");
-MODULE_LICENSE("Dual MPL/GPL");
diff --git a/drivers/net/wireless/intersil/orinoco/scan.c b/drivers/net/wireless/intersil/orinoco/scan.c
deleted file mode 100644
index 6d1d084854fb..000000000000
--- a/drivers/net/wireless/intersil/orinoco/scan.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Helpers for managing scan queues
- *
- * See copyright notice in main.c
- */
-
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-
-#include "hermes.h"
-#include "orinoco.h"
-#include "main.h"
-
-#include "scan.h"
-
-#define ZERO_DBM_OFFSET 0x95
-#define MAX_SIGNAL_LEVEL 0x8A
-#define MIN_SIGNAL_LEVEL 0x2F
-
-#define SIGNAL_TO_DBM(x) \
- (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
- - ZERO_DBM_OFFSET)
-#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
-
-static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
-{
- int i;
- u8 rate;
-
- buf[0] = WLAN_EID_SUPP_RATES;
- for (i = 0; i < 5; i++) {
- rate = le16_to_cpu(rates[i]);
- /* NULL terminated */
- if (rate == 0x0)
- break;
- buf[i + 2] = rate;
- }
- buf[1] = i;
-
- return i + 2;
-}
-
-static int prism_build_supp_rates(u8 *buf, const u8 *rates)
-{
- int i;
-
- buf[0] = WLAN_EID_SUPP_RATES;
- for (i = 0; i < 8; i++) {
- /* NULL terminated */
- if (rates[i] == 0x0)
- break;
- buf[i + 2] = rates[i];
- }
- buf[1] = i;
-
- /* We might still have another 2 rates, which need to go in
- * extended supported rates */
- if (i == 8 && rates[i] > 0) {
- buf[10] = WLAN_EID_EXT_SUPP_RATES;
- for (; i < 10; i++) {
- /* NULL terminated */
- if (rates[i] == 0x0)
- break;
- buf[i + 2] = rates[i];
- }
- buf[11] = i - 8;
- }
-
- return (i < 8) ? i + 2 : i + 4;
-}
-
-static void orinoco_add_hostscan_result(struct orinoco_private *priv,
- const union hermes_scan_info *bss)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct ieee80211_channel *channel;
- struct cfg80211_bss *cbss;
- u8 *ie;
- u8 ie_buf[46];
- u64 timestamp;
- s32 signal;
- u16 capability;
- u16 beacon_interval;
- int ie_len;
- int freq;
- int len;
-
- len = le16_to_cpu(bss->a.essid_len);
-
- /* Reconstruct SSID and bitrate IEs to pass up */
- ie_buf[0] = WLAN_EID_SSID;
- ie_buf[1] = len;
- memcpy(&ie_buf[2], bss->a.essid, len);
-
- ie = ie_buf + len + 2;
- ie_len = ie_buf[1] + 2;
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- ie_len += symbol_build_supp_rates(ie, bss->s.rates);
- break;
-
- case FIRMWARE_TYPE_INTERSIL:
- ie_len += prism_build_supp_rates(ie, bss->p.rates);
- break;
-
- case FIRMWARE_TYPE_AGERE:
- default:
- break;
- }
-
- freq = ieee80211_channel_to_frequency(
- le16_to_cpu(bss->a.channel), NL80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, freq);
- if (!channel) {
- printk(KERN_DEBUG "Invalid channel designation %04X(%04X)",
- bss->a.channel, freq);
- return; /* Then ignore it for now */
- }
- timestamp = 0;
- capability = le16_to_cpu(bss->a.capabilities);
- beacon_interval = le16_to_cpu(bss->a.beacon_interv);
- signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
-
- cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
- bss->a.bssid, timestamp, capability,
- beacon_interval, ie_buf, ie_len, signal,
- GFP_KERNEL);
- cfg80211_put_bss(wiphy, cbss);
-}
-
-void orinoco_add_extscan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *bss,
- size_t len)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct ieee80211_channel *channel;
- struct cfg80211_bss *cbss;
- const u8 *ie;
- u64 timestamp;
- s32 signal;
- u16 capability;
- u16 beacon_interval;
- size_t ie_len;
- int chan, freq;
-
- ie_len = len - sizeof(*bss);
- ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
- chan = ie ? ie[2] : 0;
- freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, freq);
-
- timestamp = le64_to_cpu(bss->timestamp);
- capability = le16_to_cpu(bss->capabilities);
- beacon_interval = le16_to_cpu(bss->beacon_interval);
- ie = bss->data;
- signal = SIGNAL_TO_MBM(bss->level);
-
- cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
- bss->bssid, timestamp, capability,
- beacon_interval, ie, ie_len, signal,
- GFP_KERNEL);
- cfg80211_put_bss(wiphy, cbss);
-}
-
-void orinoco_add_hostscan_results(struct orinoco_private *priv,
- unsigned char *buf,
- size_t len)
-{
- int offset; /* In the scan data */
- size_t atom_len;
- bool abort = false;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- atom_len = sizeof(struct agere_scan_apinfo);
- offset = 0;
- break;
-
- case FIRMWARE_TYPE_SYMBOL:
- /* Lack of documentation necessitates this hack.
- * Different firmwares have 68 or 76 byte long atoms.
- * We try modulo first. If the length divides by both,
- * we check what would be the channel in the second
- * frame for a 68-byte atom. 76-byte atoms have 0 there.
- * Valid channel cannot be 0. */
- if (len % 76)
- atom_len = 68;
- else if (len % 68)
- atom_len = 76;
- else if (len >= 1292 && buf[68] == 0)
- atom_len = 76;
- else
- atom_len = 68;
- offset = 0;
- break;
-
- case FIRMWARE_TYPE_INTERSIL:
- offset = 4;
- if (priv->has_hostscan) {
- atom_len = le16_to_cpup((__le16 *)buf);
- /* Sanity check for atom_len */
- if (atom_len < sizeof(struct prism2_scan_apinfo)) {
- printk(KERN_ERR "%s: Invalid atom_len in scan "
- "data: %zu\n", priv->ndev->name,
- atom_len);
- abort = true;
- goto scan_abort;
- }
- } else
- atom_len = offsetof(struct prism2_scan_apinfo, atim);
- break;
-
- default:
- abort = true;
- goto scan_abort;
- }
-
- /* Check that we got an whole number of atoms */
- if ((len - offset) % atom_len) {
- printk(KERN_ERR "%s: Unexpected scan data length %zu, "
- "atom_len %zu, offset %d\n", priv->ndev->name, len,
- atom_len, offset);
- abort = true;
- goto scan_abort;
- }
-
- /* Process the entries one by one */
- for (; offset + atom_len <= len; offset += atom_len) {
- union hermes_scan_info *atom;
-
- atom = (union hermes_scan_info *) (buf + offset);
-
- orinoco_add_hostscan_result(priv, atom);
- }
-
- scan_abort:
- if (priv->scan_request) {
- struct cfg80211_scan_info info = {
- .aborted = abort,
- };
-
- cfg80211_scan_done(priv->scan_request, &info);
- priv->scan_request = NULL;
- }
-}
-
-void orinoco_scan_done(struct orinoco_private *priv, bool abort)
-{
- if (priv->scan_request) {
- struct cfg80211_scan_info info = {
- .aborted = abort,
- };
-
- cfg80211_scan_done(priv->scan_request, &info);
- priv->scan_request = NULL;
- }
-}
diff --git a/drivers/net/wireless/intersil/orinoco/scan.h b/drivers/net/wireless/intersil/orinoco/scan.h
deleted file mode 100644
index 27281fb0a6dc..000000000000
--- a/drivers/net/wireless/intersil/orinoco/scan.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Helpers for managing scan queues
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_SCAN_H_
-#define _ORINOCO_SCAN_H_
-
-/* Forward declarations */
-struct orinoco_private;
-struct agere_ext_scan_info;
-
-/* Add scan results */
-void orinoco_add_extscan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom,
- size_t len);
-void orinoco_add_hostscan_results(struct orinoco_private *dev,
- unsigned char *buf,
- size_t len);
-void orinoco_scan_done(struct orinoco_private *priv, bool abort);
-
-#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c
deleted file mode 100644
index 841d623c621a..000000000000
--- a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
- * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
- * Communications and Intel PRO/Wireless 2011B.
- *
- * The driver implements Symbol firmware download. The rest is handled
- * in hermes.c and main.c.
- *
- * Utilities for downloading the Symbol firmware are available at
- * http://sourceforge.net/projects/orinoco/
- *
- * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
- * Portions based on orinoco_cs.c:
- * Copyright (C) David Gibson, Linuxcare Australia
- * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
- * Copyright (C) Symbol Technologies.
- *
- * See copyright notice in file main.c.
- */
-
-#define DRIVER_NAME "spectrum_cs"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module stuff */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
-MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Module parameters */
-
-/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
-static int ignore_cis_vcc; /* = 0 */
-module_param(ignore_cis_vcc, int, 0);
-MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
-
-/********************************************************************/
-/* Data structures */
-/********************************************************************/
-
-/* PCMCIA specific device information (goes in the card field of
- * struct orinoco_private */
-struct orinoco_pccard {
- struct pcmcia_device *p_dev;
-};
-
-/********************************************************************/
-/* Function prototypes */
-/********************************************************************/
-
-static int spectrum_cs_config(struct pcmcia_device *link);
-static void spectrum_cs_release(struct pcmcia_device *link);
-
-/* Constants for the CISREG_CCSR register */
-#define HCR_RUN 0x07 /* run firmware after reset */
-#define HCR_IDLE 0x0E /* don't run firmware after reset */
-#define HCR_MEM16 0x10 /* memory width bit, should be preserved */
-
-
-/*
- * Reset the card using configuration registers COR and CCSR.
- * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
- */
-static int
-spectrum_reset(struct pcmcia_device *link, int idle)
-{
- int ret;
- u8 save_cor;
- u8 ccsr;
-
- /* Doing it if hardware is gone is guaranteed crash */
- if (!pcmcia_dev_present(link))
- return -ENODEV;
-
- /* Save original COR value */
- ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor);
- if (ret)
- goto failed;
-
- /* Soft-Reset card */
- ret = pcmcia_write_config_byte(link, CISREG_COR,
- (save_cor | COR_SOFT_RESET));
- if (ret)
- goto failed;
- udelay(1000);
-
- /* Read CCSR */
- ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr);
- if (ret)
- goto failed;
-
- /*
- * Start or stop the firmware. Memory width bit should be
- * preserved from the value we've just read.
- */
- ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16);
- ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr);
- if (ret)
- goto failed;
- udelay(1000);
-
- /* Restore original COR configuration index */
- ret = pcmcia_write_config_byte(link, CISREG_COR,
- (save_cor & ~COR_SOFT_RESET));
- if (ret)
- goto failed;
- udelay(1000);
- return 0;
-
-failed:
- return -ENODEV;
-}
-
-/********************************************************************/
-/* Device methods */
-/********************************************************************/
-
-static int
-spectrum_cs_hard_reset(struct orinoco_private *priv)
-{
- struct orinoco_pccard *card = priv->card;
- struct pcmcia_device *link = card->p_dev;
-
- /* Soft reset using COR and HCR */
- spectrum_reset(link, 0);
-
- return 0;
-}
-
-static int
-spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
-{
- struct orinoco_pccard *card = priv->card;
- struct pcmcia_device *link = card->p_dev;
-
- return spectrum_reset(link, idle);
-}
-
-/********************************************************************/
-/* PCMCIA stuff */
-/********************************************************************/
-
-static int
-spectrum_cs_probe(struct pcmcia_device *link)
-{
- struct orinoco_private *priv;
- struct orinoco_pccard *card;
- int ret;
-
- priv = alloc_orinocodev(sizeof(*card), &link->dev,
- spectrum_cs_hard_reset,
- spectrum_cs_stop_firmware);
- if (!priv)
- return -ENOMEM;
- card = priv->card;
-
- /* Link both structures together */
- card->p_dev = link;
- link->priv = priv;
-
- ret = spectrum_cs_config(link);
- if (ret)
- goto err_free_orinocodev;
-
- return 0;
-
-err_free_orinocodev:
- free_orinocodev(priv);
- return ret;
-}
-
-static void spectrum_cs_detach(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
-
- orinoco_if_del(priv);
-
- spectrum_cs_release(link);
-
- free_orinocodev(priv);
-} /* spectrum_cs_detach */
-
-static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
- void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-};
-
-static int
-spectrum_cs_config(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct hermes *hw = &priv->hw;
- int ret;
- void __iomem *mem;
-
- link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
- CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
- if (ignore_cis_vcc)
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
- if (ret) {
- if (!ignore_cis_vcc)
- printk(KERN_ERR PFX "GetNextTuple(): No matching "
- "CIS configuration. Maybe you need the "
- "ignore_cis_vcc=1 parameter.\n");
- goto failed;
- }
-
- mem = ioport_map(link->resource[0]->start,
- resource_size(link->resource[0]));
- if (!mem)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
- hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
- hw->eeprom_pda = true;
-
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- /* Reset card */
- if (spectrum_cs_hard_reset(priv) != 0)
- goto failed;
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto failed;
- }
-
- /* Register an interface with the stack */
- if (orinoco_if_add(priv, link->resource[0]->start,
- link->irq, NULL) != 0) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto failed;
- }
-
- return 0;
-
- failed:
- spectrum_cs_release(link);
- return -ENODEV;
-} /* spectrum_cs_config */
-
-static void
-spectrum_cs_release(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- unsigned long flags;
-
- /* We're committed to taking the device away now, so mark the
- * hardware as unavailable */
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- priv->hw_unavailable++;
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- pcmcia_disable_device(link);
- if (priv->hw.iobase)
- ioport_unmap(priv->hw.iobase);
-} /* spectrum_cs_release */
-
-
-static int
-spectrum_cs_suspend(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
-
- /* Mark the device as stopped, to block IO until later */
- orinoco_down(priv);
-
- return 0;
-}
-
-static int
-spectrum_cs_resume(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- int err = orinoco_up(priv);
-
- return err;
-}
-
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-static const struct pcmcia_device_id spectrum_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
- PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
- PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
-
-static struct pcmcia_driver orinoco_driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .probe = spectrum_cs_probe,
- .remove = spectrum_cs_detach,
- .suspend = spectrum_cs_suspend,
- .resume = spectrum_cs_resume,
- .id_table = spectrum_cs_ids,
-};
-module_pcmcia_driver(orinoco_driver);
diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c
deleted file mode 100644
index dea1ff044342..000000000000
--- a/drivers/net/wireless/intersil/orinoco/wext.c
+++ /dev/null
@@ -1,1428 +0,0 @@
-/* Wireless extensions support.
- *
- * See copyright notice in main.c
- */
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/etherdevice.h>
-#include <net/iw_handler.h>
-#include <net/cfg80211.h>
-#include <net/cfg80211-wext.h>
-
-#include "hermes.h"
-#include "hermes_rid.h"
-#include "orinoco.h"
-
-#include "hw.h"
-#include "mic.h"
-#include "scan.h"
-#include "main.h"
-
-#include "wext.h"
-
-#define MAX_RID_LEN 1024
-
-/* Helper routine to record keys
- * It is called under orinoco_lock so it may not sleep */
-static int orinoco_set_key(struct orinoco_private *priv, int index,
- enum orinoco_alg alg, const u8 *key, int key_len,
- const u8 *seq, int seq_len)
-{
- kfree_sensitive(priv->keys[index].key);
- kfree_sensitive(priv->keys[index].seq);
-
- if (key_len) {
- priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
- if (!priv->keys[index].key)
- goto nomem;
- } else
- priv->keys[index].key = NULL;
-
- if (seq_len) {
- priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
- if (!priv->keys[index].seq)
- goto free_key;
- } else
- priv->keys[index].seq = NULL;
-
- priv->keys[index].key_len = key_len;
- priv->keys[index].seq_len = seq_len;
-
- if (key_len)
- memcpy((void *)priv->keys[index].key, key, key_len);
- if (seq_len)
- memcpy((void *)priv->keys[index].seq, seq, seq_len);
-
- switch (alg) {
- case ORINOCO_ALG_TKIP:
- priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
- break;
-
- case ORINOCO_ALG_WEP:
- priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
- WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
- break;
-
- case ORINOCO_ALG_NONE:
- default:
- priv->keys[index].cipher = 0;
- break;
- }
-
- return 0;
-
-free_key:
- kfree(priv->keys[index].key);
- priv->keys[index].key = NULL;
-
-nomem:
- priv->keys[index].key_len = 0;
- priv->keys[index].seq_len = 0;
- priv->keys[index].cipher = 0;
-
- return -ENOMEM;
-}
-
-static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- struct iw_statistics *wstats = &priv->wstats;
- int err;
- unsigned long flags;
-
- if (!netif_device_present(dev)) {
- printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
- dev->name);
- return NULL; /* FIXME: Can we do better than this? */
- }
-
- /* If busy, return the old stats. Returning NULL may cause
- * the interface to disappear from /proc/net/wireless */
- if (orinoco_lock(priv, &flags) != 0)
- return wstats;
-
- /* We can't really wait for the tallies inquiry command to
- * complete, so we just use the previous results and trigger
- * a new tallies inquiry command for next time - Jean II */
- /* FIXME: Really we should wait for the inquiry to come back -
- * as it is the stats we give don't make a whole lot of sense.
- * Unfortunately, it's not clear how to do that within the
- * wireless extensions framework: I think we're in user
- * context, but a lock seems to be held by the time we get in
- * here so we're not safe to sleep here. */
- hermes_inquire(hw, HERMES_INQ_TALLIES);
-
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
- memset(&wstats->qual, 0, sizeof(wstats->qual));
- /* If a spy address is defined, we report stats of the
- * first spy address - Jean II */
- if (SPY_NUMBER(priv)) {
- wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
- wstats->qual.level = priv->spy_data.spy_stat[0].level;
- wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
- wstats->qual.updated =
- priv->spy_data.spy_stat[0].updated;
- }
- } else {
- struct {
- __le16 qual, signal, noise, unused;
- } __packed cq;
-
- err = HERMES_READ_RECORD(hw, USER_BAP,
- HERMES_RID_COMMSQUALITY, &cq);
-
- if (!err) {
- wstats->qual.qual = (int)le16_to_cpu(cq.qual);
- wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
- wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
- wstats->qual.updated =
- IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- }
- }
-
- orinoco_unlock(priv, &flags);
- return wstats;
-}
-
-/********************************************************************/
-/* Wireless extensions */
-/********************************************************************/
-
-static int orinoco_ioctl_setwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct orinoco_private *priv = ndev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Enable automatic roaming - no sanity checks are needed */
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- priv->bssid_fixed = 0;
- eth_zero_addr(priv->desired_bssid);
-
- /* "off" means keep existing connection */
- if (ap_addr->sa_data[0] == 0) {
- __orinoco_hw_set_wap(priv);
- err = 0;
- }
- goto out;
- }
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
- printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
- "support manual roaming\n",
- dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (priv->iw_mode != NL80211_IFTYPE_STATION) {
- printk(KERN_WARNING "%s: Manual roaming supported only in "
- "managed mode\n", dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Intersil firmware hangs without Desired ESSID */
- if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
- strlen(priv->desired_essid) == 0) {
- printk(KERN_WARNING "%s: Desired ESSID must be set for "
- "manual roaming\n", dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Finally, enable manual roaming */
- priv->bssid_fixed = 1;
- memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static int orinoco_ioctl_getwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct orinoco_private *priv = ndev_priv(dev);
-
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- ap_addr->sa_family = ARPHRD_ETHER;
- err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_setiwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct orinoco_private *priv = ndev_priv(dev);
- int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- int setindex = priv->tx_key;
- enum orinoco_alg encode_alg = priv->encode_alg;
- int restricted = priv->wep_restrict;
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (!priv->has_wep)
- return -EOPNOTSUPP;
-
- if (erq->pointer) {
- /* We actually have a key to set - check its length */
- if (erq->length > LARGE_KEY_SIZE)
- return -E2BIG;
-
- if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
- return -E2BIG;
- }
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Clear any TKIP key we have */
- if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
- (void) orinoco_clear_tkip_key(priv, setindex);
-
- if (erq->length > 0) {
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
- index = priv->tx_key;
-
- /* Switch on WEP if off */
- if (encode_alg != ORINOCO_ALG_WEP) {
- setindex = index;
- encode_alg = ORINOCO_ALG_WEP;
- }
- } else {
- /* Important note : if the user do "iwconfig eth0 enc off",
- * we will arrive there with an index of -1. This is valid
- * but need to be taken care off... Jean II */
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
- if ((index != -1) || (erq->flags == 0)) {
- err = -EINVAL;
- goto out;
- }
- } else {
- /* Set the index : Check that the key is valid */
- if (priv->keys[index].key_len == 0) {
- err = -EINVAL;
- goto out;
- }
- setindex = index;
- }
- }
-
- if (erq->flags & IW_ENCODE_DISABLED)
- encode_alg = ORINOCO_ALG_NONE;
- if (erq->flags & IW_ENCODE_OPEN)
- restricted = 0;
- if (erq->flags & IW_ENCODE_RESTRICTED)
- restricted = 1;
-
- if (erq->pointer && erq->length > 0) {
- err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
- erq->length, NULL, 0);
- }
- priv->tx_key = setindex;
-
- /* Try fast key change if connected and only keys are changed */
- if ((priv->encode_alg == encode_alg) &&
- (priv->wep_restrict == restricted) &&
- netif_carrier_ok(dev)) {
- err = __orinoco_hw_setup_wepkeys(priv);
- /* No need to commit if successful */
- goto out;
- }
-
- priv->encode_alg = encode_alg;
- priv->wep_restrict = restricted;
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getiwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct orinoco_private *priv = ndev_priv(dev);
- int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- unsigned long flags;
-
- if (!priv->has_wep)
- return -EOPNOTSUPP;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
- index = priv->tx_key;
-
- erq->flags = 0;
- if (!priv->encode_alg)
- erq->flags |= IW_ENCODE_DISABLED;
- erq->flags |= index + 1;
-
- if (priv->wep_restrict)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- erq->length = priv->keys[index].key_len;
-
- memcpy(keybuf, priv->keys[index].key, erq->length);
-
- orinoco_unlock(priv, &flags);
- return 0;
-}
-
-static int orinoco_ioctl_setessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *essidbuf)
-{
- struct iw_point *erq = &wrqu->essid;
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
-
- /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
- * anyway... - Jean II */
-
- /* Hum... Should not use Wireless Extension constant (may change),
- * should use our own... - Jean II */
- if (erq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
- memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
-
- /* If not ANY, get the new ESSID */
- if (erq->flags)
- memcpy(priv->desired_essid, essidbuf, erq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *essidbuf)
-{
- struct iw_point *erq = &wrqu->essid;
- struct orinoco_private *priv = ndev_priv(dev);
- int active;
- int err = 0;
- unsigned long flags;
-
- if (netif_running(dev)) {
- err = orinoco_hw_get_essid(priv, &active, essidbuf);
- if (err < 0)
- return err;
- erq->length = err;
- } else {
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
- erq->length = strlen(priv->desired_essid);
- orinoco_unlock(priv, &flags);
- }
-
- erq->flags = 1;
-
- return 0;
-}
-
-static int orinoco_ioctl_setfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *frq = &wrqu->freq;
- struct orinoco_private *priv = ndev_priv(dev);
- int chan = -1;
- unsigned long flags;
- int err = -EINPROGRESS; /* Call commit handler */
-
- /* In infrastructure mode the AP sets the channel */
- if (priv->iw_mode == NL80211_IFTYPE_STATION)
- return -EBUSY;
-
- if ((frq->e == 0) && (frq->m <= 1000)) {
- /* Setting by channel number */
- chan = frq->m;
- } else {
- /* Setting by frequency */
- int denom = 1;
- int i;
-
- /* Calculate denominator to rescale to MHz */
- for (i = 0; i < (6 - frq->e); i++)
- denom *= 10;
-
- chan = ieee80211_frequency_to_channel(frq->m / denom);
- }
-
- if ((chan < 1) || (chan > NUM_CHANNELS) ||
- !(priv->channel_mask & (1 << (chan - 1))))
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- priv->channel = chan;
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- /* Fast channel change - no commit if successful */
- struct hermes *hw = &priv->hw;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_SET_CHANNEL,
- chan, NULL);
- }
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *frq = &wrqu->freq;
- struct orinoco_private *priv = ndev_priv(dev);
- int tmp;
-
- /* Locking done in there */
- tmp = orinoco_hw_get_freq(priv);
- if (tmp < 0)
- return tmp;
-
- frq->m = tmp * 100000;
- frq->e = 1;
-
- return 0;
-}
-
-static int orinoco_ioctl_getsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *srq = &wrqu->sens;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- u16 val;
- int err;
- unsigned long flags;
-
- if (!priv->has_sensitivity)
- return -EOPNOTSUPP;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE, &val);
- orinoco_unlock(priv, &flags);
-
- if (err)
- return err;
-
- srq->value = val;
- srq->fixed = 0; /* auto */
-
- return 0;
-}
-
-static int orinoco_ioctl_setsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *srq = &wrqu->sens;
- struct orinoco_private *priv = ndev_priv(dev);
- int val = srq->value;
- unsigned long flags;
-
- if (!priv->has_sensitivity)
- return -EOPNOTSUPP;
-
- if ((val < 1) || (val > 3))
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- priv->ap_density = val;
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_setrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct orinoco_private *priv = ndev_priv(dev);
- int ratemode;
- int bitrate; /* 100s of kilobits */
- unsigned long flags;
-
- /* As the user space doesn't know our highest rate, it uses -1
- * to ask us to set the highest rate. Test it using "iwconfig
- * ethX rate auto" - Jean II */
- if (rrq->value == -1)
- bitrate = 110;
- else {
- if (rrq->value % 100000)
- return -EINVAL;
- bitrate = rrq->value / 100000;
- }
-
- ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
-
- if (ratemode == -1)
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- priv->bitratemode = ratemode;
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS;
-}
-
-static int orinoco_ioctl_getrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct orinoco_private *priv = ndev_priv(dev);
- int err = 0;
- int bitrate, automatic;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
-
- /* If the interface is running we try to find more about the
- current mode */
- if (netif_running(dev)) {
- int act_bitrate;
- int lerr;
-
- /* Ignore errors if we can't get the actual bitrate */
- lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
- if (!lerr)
- bitrate = act_bitrate;
- }
-
- orinoco_unlock(priv, &flags);
-
- rrq->value = bitrate;
- rrq->fixed = !automatic;
- rrq->disabled = 0;
-
- return err;
-}
-
-static int orinoco_ioctl_setpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *prq = &wrqu->power;
- struct orinoco_private *priv = ndev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (prq->disabled) {
- priv->pm_on = 0;
- } else {
- switch (prq->flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- priv->pm_mcast = 0;
- priv->pm_on = 1;
- break;
- case IW_POWER_ALL_R:
- priv->pm_mcast = 1;
- priv->pm_on = 1;
- break;
- case IW_POWER_ON:
- /* No flags : but we may have a value - Jean II */
- break;
- default:
- err = -EINVAL;
- goto out;
- }
-
- if (prq->flags & IW_POWER_TIMEOUT) {
- priv->pm_on = 1;
- priv->pm_timeout = prq->value / 1000;
- }
- if (prq->flags & IW_POWER_PERIOD) {
- priv->pm_on = 1;
- priv->pm_period = prq->value / 1000;
- }
- /* It's valid to not have a value if we are just toggling
- * the flags... Jean II */
- if (!priv->pm_on) {
- err = -EINVAL;
- goto out;
- }
- }
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *prq = &wrqu->power;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err = 0;
- u16 enable, period, timeout, mcast;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED, &enable);
- if (err)
- goto out;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION, &period);
- if (err)
- goto out;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
- if (err)
- goto out;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
- if (err)
- goto out;
-
- prq->disabled = !enable;
- /* Note : by default, display the period */
- if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- prq->flags = IW_POWER_TIMEOUT;
- prq->value = timeout * 1000;
- } else {
- prq->flags = IW_POWER_PERIOD;
- prq->value = period * 1000;
- }
- if (mcast)
- prq->flags |= IW_POWER_ALL_R;
- else
- prq->flags |= IW_POWER_UNICAST_R;
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, alg = ext->alg, set_key = 1;
- unsigned long flags;
- int err = -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Determine and validate the key index */
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if ((idx < 1) || (idx > 4))
- goto out;
- idx--;
- } else
- idx = priv->tx_key;
-
- if (encoding->flags & IW_ENCODE_DISABLED)
- alg = IW_ENCODE_ALG_NONE;
-
- if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
- /* Clear any TKIP TX key we had */
- (void) orinoco_clear_tkip_key(priv, priv->tx_key);
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- priv->tx_key = idx;
- set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
- (ext->key_len > 0)) ? 1 : 0;
- }
-
- if (set_key) {
- /* Set the requested key first */
- switch (alg) {
- case IW_ENCODE_ALG_NONE:
- priv->encode_alg = ORINOCO_ALG_NONE;
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
- NULL, 0, NULL, 0);
- break;
-
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len <= 0)
- goto out;
-
- priv->encode_alg = ORINOCO_ALG_WEP;
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
- ext->key, ext->key_len, NULL, 0);
- break;
-
- case IW_ENCODE_ALG_TKIP:
- {
- u8 *tkip_iv = NULL;
-
- if (!priv->has_wpa ||
- (ext->key_len > sizeof(struct orinoco_tkip_key)))
- goto out;
-
- priv->encode_alg = ORINOCO_ALG_TKIP;
-
- if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- tkip_iv = &ext->rx_seq[0];
-
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
- ext->key, ext->key_len, tkip_iv,
- ORINOCO_SEQ_LEN);
-
- err = __orinoco_hw_set_tkip_key(priv, idx,
- ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
- priv->keys[idx].key, priv->keys[idx].key_len,
- tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
- if (err)
- printk(KERN_ERR "%s: Error %d setting TKIP key"
- "\n", dev->name, err);
-
- goto out;
- }
- default:
- goto out;
- }
- }
- err = -EINPROGRESS;
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, max_key_len;
- unsigned long flags;
- int err;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = -EINVAL;
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- goto out;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if ((idx < 1) || (idx > 4))
- goto out;
- idx--;
- } else
- idx = priv->tx_key;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- switch (priv->encode_alg) {
- case ORINOCO_ALG_NONE:
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- break;
- case ORINOCO_ALG_WEP:
- ext->alg = IW_ENCODE_ALG_WEP;
- ext->key_len = min(priv->keys[idx].key_len, max_key_len);
- memcpy(ext->key, priv->keys[idx].key, ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- break;
- case ORINOCO_ALG_TKIP:
- ext->alg = IW_ENCODE_ALG_TKIP;
- ext->key_len = min(priv->keys[idx].key_len, max_key_len);
- memcpy(ext->key, priv->keys[idx].key, ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- break;
- }
-
- err = 0;
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- struct iw_param *param = &wrqu->param;
- unsigned long flags;
- int ret = -EINPROGRESS;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_PRIVACY_INVOKED:
- case IW_AUTH_DROP_UNENCRYPTED:
- /*
- * orinoco does not use these parameters
- */
- break;
-
- case IW_AUTH_MFP:
- /* Management Frame Protection not supported.
- * Only fail if set to required.
- */
- if (param->value == IW_AUTH_MFP_REQUIRED)
- ret = -EINVAL;
- break;
-
- case IW_AUTH_KEY_MGMT:
- /* wl_lkm implies value 2 == PSK for Hermes I
- * which ties in with WEXT
- * no other hints tho :(
- */
- priv->key_mgmt = param->value;
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- /* When countermeasures are enabled, shut down the
- * card; when disabled, re-enable the card. This must
- * take effect immediately.
- *
- * TODO: Make sure that the EAPOL message is getting
- * out before card disabled
- */
- if (param->value) {
- priv->tkip_cm_active = 1;
- ret = hermes_disable_port(hw, 0);
- } else {
- priv->tkip_cm_active = 0;
- ret = hermes_enable_port(hw, 0);
- }
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (param->value & IW_AUTH_ALG_SHARED_KEY)
- priv->wep_restrict = 1;
- else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
- priv->wep_restrict = 0;
- else
- ret = -EINVAL;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- if (priv->has_wpa) {
- priv->wpa_enabled = param->value ? 1 : 0;
- } else {
- if (param->value)
- ret = -EOPNOTSUPP;
- /* else silently accept disable of WPA */
- priv->wpa_enabled = 0;
- }
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_param *param = &wrqu->param;
- unsigned long flags;
- int ret = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_KEY_MGMT:
- param->value = priv->key_mgmt;
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- param->value = priv->tkip_cm_active;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (priv->wep_restrict)
- param->value = IW_AUTH_ALG_SHARED_KEY;
- else
- param->value = IW_AUTH_ALG_OPEN_SYSTEM;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = priv->wpa_enabled;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u8 *buf;
- unsigned long flags;
-
- /* cut off at IEEE80211_MAX_DATA_LEN */
- if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
- (wrqu->data.length && (extra == NULL)))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
- } else
- buf = NULL;
-
- if (orinoco_lock(priv, &flags) != 0) {
- kfree(buf);
- return -EBUSY;
- }
-
- kfree(priv->wpa_ie);
- priv->wpa_ie = buf;
- priv->wpa_ie_len = wrqu->data.length;
-
- if (priv->wpa_ie) {
- /* Looks like wl_lkm wants to check the auth alg, and
- * somehow pass it to the firmware.
- * Instead it just calls the key mgmt rid
- * - we do this in set auth.
- */
- }
-
- orinoco_unlock(priv, &flags);
- return 0;
-}
-
-static int orinoco_ioctl_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
- wrqu->data.length = 0;
- goto out;
- }
-
- if (wrqu->data.length < priv->wpa_ie_len) {
- err = -E2BIG;
- goto out;
- }
-
- wrqu->data.length = priv->wpa_ie_len;
- memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static int orinoco_ioctl_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
- unsigned long flags;
- int ret = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* silently ignore */
- break;
-
- case IW_MLME_DISASSOC:
-
- ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
- mlme->reason_code);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
- printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-
- /* Firmware reset */
- orinoco_reset(&priv->reset_work);
- } else {
- printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
- schedule_work(&priv->reset_work);
- }
-
- return 0;
-}
-
-static int orinoco_ioctl_setibssport(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int val = *((int *) extra);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- priv->ibss_port = val;
-
- /* Actually update the mode we are using */
- set_port_type(priv);
-
- orinoco_unlock(priv, &flags);
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getibssport(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int *val = (int *) extra;
-
- *val = priv->ibss_port;
- return 0;
-}
-
-static int orinoco_ioctl_setport3(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int val = *((int *) extra);
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (val) {
- case 0: /* Try to do IEEE ad-hoc mode */
- if (!priv->has_ibss) {
- err = -EINVAL;
- break;
- }
- priv->prefer_port3 = 0;
-
- break;
-
- case 1: /* Try to do Lucent proprietary ad-hoc mode */
- if (!priv->has_port3) {
- err = -EINVAL;
- break;
- }
- priv->prefer_port3 = 1;
- break;
-
- default:
- err = -EINVAL;
- }
-
- if (!err) {
- /* Actually update the mode we are using */
- set_port_type(priv);
- err = -EINPROGRESS;
- }
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getport3(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int *val = (int *) extra;
-
- *val = priv->prefer_port3;
- return 0;
-}
-
-static int orinoco_ioctl_setpreamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int val;
-
- if (!priv->has_preamble)
- return -EOPNOTSUPP;
-
- /* 802.11b has recently defined some short preamble.
- * Basically, the Phy header has been reduced in size.
- * This increase performance, especially at high rates
- * (the preamble is transmitted at 1Mb/s), unfortunately
- * this give compatibility troubles... - Jean II */
- val = *((int *) extra);
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (val)
- priv->preamble = 1;
- else
- priv->preamble = 0;
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getpreamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int *val = (int *) extra;
-
- if (!priv->has_preamble)
- return -EOPNOTSUPP;
-
- *val = priv->preamble;
- return 0;
-}
-
-/* ioctl interface to hermes_read_ltv()
- * To use with iwpriv, pass the RID as the token argument, e.g.
- * iwpriv get_rid [0xfc00]
- * At least Wireless Tools 25 is required to use iwpriv.
- * For Wireless Tools 25 and 26 append "dummy" are the end. */
-static int orinoco_ioctl_getrid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- int rid = data->flags;
- u16 length;
- int err;
- unsigned long flags;
-
- /* It's a "get" function, but we don't want users to access the
- * WEP key and other raw firmware data */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (rid < 0xfc00 || rid > 0xffff)
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
- extra);
- if (err)
- goto out;
-
- data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
- MAX_RID_LEN);
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-
-/* Commit handler, called after set operations */
-static int orinoco_ioctl_commit(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- if (!priv->open)
- return 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return err;
-
- err = orinoco_commit(priv);
-
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static const struct iw_priv_args orinoco_privtab[] = {
- { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
- { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
- { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_port3" },
- { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_port3" },
- { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_preamble" },
- { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_preamble" },
- { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_ibssport" },
- { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_ibssport" },
- { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
- "get_rid" },
-};
-
-
-/*
- * Structures to export the Wireless Handlers
- */
-
-static const iw_handler orinoco_handler[] = {
- IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
- IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
- IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq),
- IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq),
- IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode),
- IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode),
- IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens),
- IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens),
- IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
- IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
- IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
- IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
- IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
- IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
- IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
- IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
- IW_HANDLER(SIOCSIWRTS, cfg80211_wext_siwrts),
- IW_HANDLER(SIOCGIWRTS, cfg80211_wext_giwrts),
- IW_HANDLER(SIOCSIWFRAG, cfg80211_wext_siwfrag),
- IW_HANDLER(SIOCGIWFRAG, cfg80211_wext_giwfrag),
- IW_HANDLER(SIOCGIWRETRY, cfg80211_wext_giwretry),
- IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode),
- IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode),
- IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower),
- IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower),
- IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie),
- IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie),
- IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme),
- IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth),
- IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
-};
-
-
-/*
- Added typecasting since we no longer use iwreq_data -- Moustafa
- */
-static const iw_handler orinoco_private_handler[] = {
- [0] = orinoco_ioctl_reset,
- [1] = orinoco_ioctl_reset,
- [2] = orinoco_ioctl_setport3,
- [3] = orinoco_ioctl_getport3,
- [4] = orinoco_ioctl_setpreamble,
- [5] = orinoco_ioctl_getpreamble,
- [6] = orinoco_ioctl_setibssport,
- [7] = orinoco_ioctl_getibssport,
- [9] = orinoco_ioctl_getrid,
-};
-
-const struct iw_handler_def orinoco_handler_def = {
- .num_standard = ARRAY_SIZE(orinoco_handler),
- .num_private = ARRAY_SIZE(orinoco_private_handler),
- .num_private_args = ARRAY_SIZE(orinoco_privtab),
- .standard = orinoco_handler,
- .private = orinoco_private_handler,
- .private_args = orinoco_privtab,
- .get_wireless_stats = orinoco_get_wireless_stats,
-};
diff --git a/drivers/net/wireless/intersil/orinoco/wext.h b/drivers/net/wireless/intersil/orinoco/wext.h
deleted file mode 100644
index 1479f4e26dde..000000000000
--- a/drivers/net/wireless/intersil/orinoco/wext.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Wireless extensions support.
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_WEXT_H_
-#define _ORINOCO_WEXT_H_
-
-#include <net/iw_handler.h>
-
-/* Structure defining all our WEXT handlers */
-extern const struct iw_handler_def orinoco_handler_def;
-
-#endif /* _ORINOCO_WEXT_H_ */
diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c
index b52cce38115d..c4fe70e05b9b 100644
--- a/drivers/net/wireless/intersil/p54/fwio.c
+++ b/drivers/net/wireless/intersil/p54/fwio.c
@@ -125,7 +125,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
"FW rev %s - Softmac protocol %x.%x\n",
fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
- "%s - %x.%x", fw_version,
+ "%.19s - %x.%x", fw_version,
priv->fw_var >> 8, priv->fw_var & 0xff);
}
diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c
index ce0179b8ab36..0073b5e0f9c9 100644
--- a/drivers/net/wireless/intersil/p54/p54spi.c
+++ b/drivers/net/wireless/intersil/p54/p54spi.c
@@ -700,6 +700,7 @@ static struct spi_driver p54spi_driver = {
module_spi_driver(p54spi_driver);
+MODULE_DESCRIPTION("Prism54 SPI wireless driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
MODULE_ALIAS("spi:cx3110x");
diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig
deleted file mode 100644
index 3a5275941212..000000000000
--- a/drivers/net/wireless/legacy/Kconfig
+++ /dev/null
@@ -1,55 +0,0 @@
-config PCMCIA_RAYCS
- tristate "Aviator/Raytheon 2.4GHz wireless support"
- depends on PCMCIA
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- help
- Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
- (PC-card) wireless Ethernet networking card to your computer.
- Please read the file
- <file:Documentation/networking/device_drivers/wifi/ray_cs.rst> for
- details.
-
- To compile this driver as a module, choose M here: the module will be
- called ray_cs. If unsure, say N.
-
-config PCMCIA_WL3501
- tristate "Planet WL3501 PCMCIA cards"
- depends on CFG80211 && PCMCIA
- select WIRELESS_EXT
- select WEXT_SPY
- help
- A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
- It has basic support for Linux wireless extensions and initial
- micro support for ethtool.
-
-config USB_NET_RNDIS_WLAN
- tristate "Wireless RNDIS USB support"
- depends on USB
- depends on CFG80211
- select USB_NET_DRIVERS
- select USB_USBNET
- select USB_NET_CDCETHER
- select USB_NET_RNDIS_HOST
- help
- This is a driver for wireless RNDIS devices.
- These are USB based adapters found in devices such as:
-
- Buffalo WLI-U2-KG125S
- U.S. Robotics USR5421
- Belkin F5D7051
- Linksys WUSB54GSv2
- Linksys WUSB54GSC
- Asus WL169gE
- Eminent EM4045
- BT Voyager 1055
- Linksys WUSB54GSv1
- U.S. Robotics USR5420
- BUFFALO WLI-USB-G54
-
- All of these devices are based on Broadcom 4320 chip which is the
- only wireless RNDIS chip known to date.
-
- If you choose to build a module, it'll be called rndis_wlan.
-
diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile
deleted file mode 100644
index 36878f080bfc..000000000000
--- a/drivers/net/wireless/legacy/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# 16-bit wireless PCMCIA client drivers
-obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
-obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
-
-obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o
-
diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c
deleted file mode 100644
index c95a79e01cd0..000000000000
--- a/drivers/net/wireless/legacy/ray_cs.c
+++ /dev/null
@@ -1,2824 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*=============================================================================
- *
- * A PCMCIA client driver for the Raylink wireless LAN card.
- * The starting point for this module was the skeleton.c in the
- * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net
- *
- * Copyright (c) 1998 Corey Thomas (corey@world.std.com)
- *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
- * - reorganize kmallocs in ray_attach, checking all for failure
- * and releasing the previous allocations if one fails
- *
- * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003
- * - Audit copy_to_user in ioctl(SIOCGIWESSID)
- *
-=============================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/ptrace.h>
-#include <linux/seq_file.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-#include <linux/ieee80211.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY /* Enable spying addresses */
-/* Definitions we need for spy */
-typedef struct iw_statistics iw_stats;
-typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */
-
-#include "rayctl.h"
-#include "ray_cs.h"
-
-
-/** Prototypes based on PCMCIA skeleton driver *******************************/
-static int ray_config(struct pcmcia_device *link);
-static void ray_release(struct pcmcia_device *link);
-static void ray_detach(struct pcmcia_device *p_dev);
-
-/***** Prototypes indicated by device structure ******************************/
-static int ray_dev_close(struct net_device *dev);
-static int ray_dev_config(struct net_device *dev, struct ifmap *map);
-static struct net_device_stats *ray_get_stats(struct net_device *dev);
-static int ray_dev_init(struct net_device *dev);
-
-static int ray_open(struct net_device *dev);
-static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void ray_update_multi_list(struct net_device *dev, int all);
-static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
- unsigned char *data, int len);
-static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
- UCHAR msg_type, unsigned char *data);
-static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
-static iw_stats *ray_get_wireless_stats(struct net_device *dev);
-static const struct iw_handler_def ray_handler_def;
-
-/***** Prototypes for raylink functions **************************************/
-static void authenticate(ray_dev_t *local);
-static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
-static void authenticate_timeout(struct timer_list *t);
-static int get_free_ccs(ray_dev_t *local);
-static int get_free_tx_ccs(ray_dev_t *local);
-static void init_startup_params(ray_dev_t *local);
-static int parse_addr(char *in_str, UCHAR *out);
-static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type);
-static int ray_init(struct net_device *dev);
-static int interrupt_ecf(ray_dev_t *local, int ccs);
-static void ray_reset(struct net_device *dev);
-static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
-static void verify_dl_startup(struct timer_list *t);
-
-/* Prototypes for interrpt time functions **********************************/
-static irqreturn_t ray_interrupt(int reg, void *dev_id);
-static void clear_interrupt(ray_dev_t *local);
-static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len);
-static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
-static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs);
-static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs);
-static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len);
-static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len);
-static void associate(ray_dev_t *local);
-
-/* Card command functions */
-static int dl_startup_params(struct net_device *dev);
-static void join_net(struct timer_list *t);
-static void start_net(struct timer_list *t);
-
-/*===========================================================================*/
-/* Parameters that can be set with 'insmod' */
-
-/* ADHOC=0, Infrastructure=1 */
-static int net_type = ADHOC;
-
-/* Hop dwell time in Kus (1024 us units defined by 802.11) */
-static int hop_dwell = 128;
-
-/* Beacon period in Kus */
-static int beacon_period = 256;
-
-/* power save mode (0 = off, 1 = save power) */
-static int psm;
-
-/* String for network's Extended Service Set ID. 32 Characters max */
-static char *essid;
-
-/* Default to encapsulation unless translation requested */
-static bool translate = true;
-
-static int country = USA;
-
-static int sniffer;
-
-static int bc;
-
-/* 48 bit physical card address if overriding card's real physical
- * address is required. Since IEEE 802.11 addresses are 48 bits
- * like ethernet, an int can't be used, so a string is used. To
- * allow use of addresses starting with a decimal digit, the first
- * character must be a letter and will be ignored. This letter is
- * followed by up to 12 hex digits which are the address. If less
- * than 12 digits are used, the address will be left filled with 0's.
- * Note that bit 0 of the first byte is the broadcast bit, and evil
- * things will happen if it is not 0 in a card address.
- */
-static char *phy_addr = NULL;
-
-static unsigned int ray_mem_speed = 500;
-
-/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */
-static struct pcmcia_device *this_device = NULL;
-
-MODULE_AUTHOR("Corey Thomas <corey@world.std.com>");
-MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
-MODULE_LICENSE("GPL");
-
-module_param(net_type, int, 0);
-module_param(hop_dwell, int, 0);
-module_param(beacon_period, int, 0);
-module_param(psm, int, 0);
-module_param(essid, charp, 0);
-module_param(translate, bool, 0);
-module_param(country, int, 0);
-module_param(sniffer, int, 0);
-module_param(bc, int, 0);
-module_param(phy_addr, charp, 0);
-module_param(ray_mem_speed, int, 0);
-
-static const UCHAR b5_default_startup_parms[] = {
- 0, 0, /* Adhoc station */
- 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, /* Active scan, CA Mode */
- 0, 0, 0, 0, 0, 0, /* No default MAC addr */
- 0x7f, 0xff, /* Frag threshold */
- 0x00, 0x80, /* Hop time 128 Kus */
- 0x01, 0x00, /* Beacon period 256 Kus */
- 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */
- 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */
- 0x7f, 0xff, /* RTS threshold */
- 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */
- 0x05, /* assoc resp timeout thresh */
- 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max */
- 0, /* Promiscuous mode */
- 0x0c, 0x0bd, /* Unique word */
- 0x32, /* Slot time */
- 0xff, 0xff, /* roam-low snr, low snr count */
- 0x05, 0xff, /* Infra, adhoc missed bcn thresh */
- 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */
-/* b4 - b5 differences start here */
- 0x00, 0x3f, /* CW max */
- 0x00, 0x0f, /* CW min */
- 0x04, 0x08, /* Noise gain, limit offset */
- 0x28, 0x28, /* det rssi, med busy offsets */
- 7, /* det sync thresh */
- 0, 2, 2, /* test mode, min, max */
- 0, /* allow broadcast SSID probe resp */
- 0, 0, /* privacy must start, can join */
- 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */
-};
-
-static const UCHAR b4_default_startup_parms[] = {
- 0, 0, /* Adhoc station */
- 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, /* Active scan, CA Mode */
- 0, 0, 0, 0, 0, 0, /* No default MAC addr */
- 0x7f, 0xff, /* Frag threshold */
- 0x02, 0x00, /* Hop time */
- 0x00, 0x01, /* Beacon period */
- 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */
- 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */
- 0x7f, 0xff, /* RTS threshold */
- 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */
- 0x05, /* assoc resp timeout thresh */
- 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max */
- 0, /* Promiscuous mode */
- 0x0c, 0x0bd, /* Unique word */
- 0x4e, /* Slot time (TBD seems wrong) */
- 0xff, 0xff, /* roam-low snr, low snr count */
- 0x05, 0xff, /* Infra, adhoc missed bcn thresh */
- 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */
-/* b4 - b5 differences start here */
- 0x3f, 0x0f, /* CW max, min */
- 0x04, 0x08, /* Noise gain, limit offset */
- 0x28, 0x28, /* det rssi, med busy offsets */
- 7, /* det sync thresh */
- 0, 2, 2, /* test mode, min, max */
- 0, /* rx/tx delay */
- 0, 0, 0, 0, 0, 0, /* current BSS id */
- 0 /* hop set */
-};
-
-/*===========================================================================*/
-static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
-
-static const char hop_pattern_length[] = { 1,
- USA_HOP_MOD, EUROPE_HOP_MOD,
- JAPAN_HOP_MOD, KOREA_HOP_MOD,
- SPAIN_HOP_MOD, FRANCE_HOP_MOD,
- ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD,
- JAPAN_TEST_HOP_MOD
-};
-
-static const char rcsid[] =
- "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
-
-static const struct net_device_ops ray_netdev_ops = {
- .ndo_init = ray_dev_init,
- .ndo_open = ray_open,
- .ndo_stop = ray_dev_close,
- .ndo_start_xmit = ray_dev_start_xmit,
- .ndo_set_config = ray_dev_config,
- .ndo_get_stats = ray_get_stats,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ray_probe(struct pcmcia_device *p_dev)
-{
- ray_dev_t *local;
- struct net_device *dev;
- int ret;
-
- dev_dbg(&p_dev->dev, "ray_attach()\n");
-
- /* Allocate space for private device-specific data */
- dev = alloc_etherdev(sizeof(ray_dev_t));
- if (!dev)
- return -ENOMEM;
-
- local = netdev_priv(dev);
- local->finder = p_dev;
-
- /* The io structure describes IO port mapping. None used here */
- p_dev->resource[0]->end = 0;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
- /* General socket configuration */
- p_dev->config_flags |= CONF_ENABLE_IRQ;
- p_dev->config_index = 1;
-
- p_dev->priv = dev;
-
- local->finder = p_dev;
- local->card_status = CARD_INSERTED;
- local->authentication_state = UNAUTHENTICATED;
- local->num_multi = 0;
- dev_dbg(&p_dev->dev, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n",
- p_dev, dev, local, &ray_interrupt);
-
- /* Raylink entries in the device structure */
- dev->netdev_ops = &ray_netdev_ops;
- dev->wireless_handlers = &ray_handler_def;
-#ifdef WIRELESS_SPY
- local->wireless_data.spy_data = &local->spy_data;
- dev->wireless_data = &local->wireless_data;
-#endif /* WIRELESS_SPY */
-
-
- dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n");
- netif_stop_queue(dev);
-
- timer_setup(&local->timer, NULL, 0);
-
- this_device = p_dev;
- ret = ray_config(p_dev);
- if (ret)
- goto err_free_dev;
-
- return 0;
-
-err_free_dev:
- free_netdev(dev);
- return ret;
-}
-
-static void ray_detach(struct pcmcia_device *link)
-{
- struct net_device *dev;
-
- dev_dbg(&link->dev, "ray_detach\n");
-
- this_device = NULL;
- dev = link->priv;
-
- ray_release(link);
-
- if (link->priv) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- dev_dbg(&link->dev, "ray_cs ray_detach ending\n");
-} /* ray_detach */
-
-#define MAX_TUPLE_SIZE 128
-static int ray_config(struct pcmcia_device *link)
-{
- int ret = 0;
- int i;
- struct net_device *dev = link->priv;
- ray_dev_t *local = netdev_priv(dev);
-
- dev_dbg(&link->dev, "ray_config\n");
-
- /* Determine card type and firmware version */
- printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n",
- link->prod_id[0] ? link->prod_id[0] : " ",
- link->prod_id[1] ? link->prod_id[1] : " ",
- link->prod_id[2] ? link->prod_id[2] : " ",
- link->prod_id[3] ? link->prod_id[3] : " ");
-
- /* Now allocate an interrupt line. Note that this does not
- actually assign a handler to the interrupt.
- */
- ret = pcmcia_request_irq(link, ray_interrupt);
- if (ret)
- goto failed;
- dev->irq = link->irq;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
-/*** Set up 32k window for shared memory (transmit and control) ************/
- link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
- link->resource[2]->start = 0;
- link->resource[2]->end = 0x8000;
- ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed);
- if (ret)
- goto failed;
- ret = pcmcia_map_mem_page(link, link->resource[2], 0);
- if (ret)
- goto failed;
- local->sram = ioremap(link->resource[2]->start,
- resource_size(link->resource[2]));
- if (!local->sram)
- goto failed;
-
-/*** Set up 16k window for shared memory (receive buffer) ***************/
- link->resource[3]->flags |=
- WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
- link->resource[3]->start = 0;
- link->resource[3]->end = 0x4000;
- ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed);
- if (ret)
- goto failed;
- ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000);
- if (ret)
- goto failed;
- local->rmem = ioremap(link->resource[3]->start,
- resource_size(link->resource[3]));
- if (!local->rmem)
- goto failed;
-
-/*** Set up window for attribute memory ***********************************/
- link->resource[4]->flags |=
- WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
- link->resource[4]->start = 0;
- link->resource[4]->end = 0x1000;
- ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed);
- if (ret)
- goto failed;
- ret = pcmcia_map_mem_page(link, link->resource[4], 0);
- if (ret)
- goto failed;
- local->amem = ioremap(link->resource[4]->start,
- resource_size(link->resource[4]));
- if (!local->amem)
- goto failed;
-
- dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram);
- dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem);
- dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem);
- if (ray_init(dev) < 0) {
- ray_release(link);
- return -ENODEV;
- }
-
- SET_NETDEV_DEV(dev, &link->dev);
- i = register_netdev(dev);
- if (i != 0) {
- printk("ray_config register_netdev() failed\n");
- ray_release(link);
- return i;
- }
-
- printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
- dev->name, dev->irq, dev->dev_addr);
-
- return 0;
-
-failed:
- ray_release(link);
- return -ENODEV;
-} /* ray_config */
-
-static inline struct ccs __iomem *ccs_base(ray_dev_t *dev)
-{
- return dev->sram + CCS_BASE;
-}
-
-static inline struct rcs __iomem *rcs_base(ray_dev_t *dev)
-{
- /*
- * This looks nonsensical, since there is a separate
- * RCS_BASE. But the difference between a "struct rcs"
- * and a "struct ccs" ends up being in the _index_ off
- * the base, so the base pointer is the same for both
- * ccs/rcs.
- */
- return dev->sram + CCS_BASE;
-}
-
-/*===========================================================================*/
-static int ray_init(struct net_device *dev)
-{
- int i;
- struct ccs __iomem *pccs;
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- dev_dbg(&link->dev, "ray_init(0x%p)\n", dev);
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_init - device not present\n");
- return -1;
- }
-
- local->net_type = net_type;
- local->sta_type = TYPE_STA;
-
- /* Copy the startup results to local memory */
- memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,
- sizeof(struct startup_res_6));
-
- /* Check Power up test status and get mac address from card */
- if (local->startup_res.startup_word != 0x80) {
- printk(KERN_INFO "ray_init ERROR card status = %2x\n",
- local->startup_res.startup_word);
- local->card_status = CARD_INIT_ERROR;
- return -1;
- }
-
- local->fw_ver = local->startup_res.firmware_version[0];
- local->fw_bld = local->startup_res.firmware_version[1];
- local->fw_var = local->startup_res.firmware_version[2];
- dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver,
- local->fw_bld);
-
- local->tib_length = 0x20;
- if ((local->fw_ver == 5) && (local->fw_bld >= 30))
- local->tib_length = local->startup_res.tib_length;
- dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length);
- /* Initialize CCS's to buffer free state */
- pccs = ccs_base(local);
- for (i = 0; i < NUMBER_OF_CCS; i++) {
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- }
- init_startup_params(local);
-
- /* copy mac address to startup parameters */
- if (!parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) {
- memcpy(&local->sparm.b4.a_mac_addr,
- &local->startup_res.station_addr, ADDRLEN);
- }
-
- clear_interrupt(local); /* Clear any interrupt from the card */
- local->card_status = CARD_AWAITING_PARAM;
- dev_dbg(&link->dev, "ray_init ending\n");
- return 0;
-} /* ray_init */
-
-/*===========================================================================*/
-/* Download startup parameters to the card and command it to read them */
-static int dl_startup_params(struct net_device *dev)
-{
- int ccsindex;
- ray_dev_t *local = netdev_priv(dev);
- struct ccs __iomem *pccs;
- struct pcmcia_device *link = local->finder;
-
- dev_dbg(&link->dev, "dl_startup_params entered\n");
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n");
- return -1;
- }
-
- /* Copy parameters to host to ECF area */
- if (local->fw_ver == 0x55)
- memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
- sizeof(struct b4_startup_params));
- else
- memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
- sizeof(struct b5_startup_params));
-
- /* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) < 0)
- return -1;
- local->dl_param_ccs = ccsindex;
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
- dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n",
- local->dl_param_ccs);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- printk(KERN_INFO "ray dl_startup_params failed - "
- "ECF not ready for intr\n");
- local->card_status = CARD_DL_PARAM_ERROR;
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return -2;
- }
- local->card_status = CARD_DL_PARAM;
- /* Start kernel timer to wait for dl startup to complete. */
- local->timer.expires = jiffies + HZ / 2;
- local->timer.function = verify_dl_startup;
- add_timer(&local->timer);
- dev_dbg(&link->dev,
- "ray_cs dl_startup_params started timer for verify_dl_startup\n");
- return 0;
-} /* dl_startup_params */
-
-/*===========================================================================*/
-static void init_startup_params(ray_dev_t *local)
-{
- int i;
-
- if (country > JAPAN_TEST)
- country = USA;
- else if (country < USA)
- country = USA;
- /* structure for hop time and beacon period is defined here using
- * New 802.11D6.1 format. Card firmware is still using old format
- * until version 6.
- * Before After
- * a_hop_time ms byte a_hop_time ms byte
- * a_hop_time 2s byte a_hop_time ls byte
- * a_hop_time ls byte a_beacon_period ms byte
- * a_beacon_period a_beacon_period ls byte
- *
- * a_hop_time = uS a_hop_time = KuS
- * a_beacon_period = hops a_beacon_period = KuS
- *//* 64ms = 010000 */
- if (local->fw_ver == 0x55) {
- memcpy(&local->sparm.b4, b4_default_startup_parms,
- sizeof(struct b4_startup_params));
- /* Translate sane kus input values to old build 4/5 format */
- /* i = hop time in uS truncated to 3 bytes */
- i = (hop_dwell * 1024) & 0xffffff;
- local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
- local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
- local->sparm.b4.a_beacon_period[0] = 0;
- local->sparm.b4.a_beacon_period[1] =
- ((beacon_period / hop_dwell) - 1) & 0xff;
- local->sparm.b4.a_curr_country_code = country;
- local->sparm.b4.a_hop_pattern_length =
- hop_pattern_length[(int)country] - 1;
- if (bc) {
- local->sparm.b4.a_ack_timeout = 0x50;
- local->sparm.b4.a_sifs = 0x3f;
- }
- } else { /* Version 5 uses real kus values */
- memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms,
- sizeof(struct b5_startup_params));
-
- local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
- local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
- local->sparm.b5.a_beacon_period[0] =
- (beacon_period >> 8) & 0xff;
- local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
- if (psm)
- local->sparm.b5.a_power_mgt_state = 1;
- local->sparm.b5.a_curr_country_code = country;
- local->sparm.b5.a_hop_pattern_length =
- hop_pattern_length[(int)country];
- }
-
- local->sparm.b4.a_network_type = net_type & 0x01;
- local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
-
- if (essid != NULL)
- strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
-} /* init_startup_params */
-
-/*===========================================================================*/
-static void verify_dl_startup(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
- struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs;
- UCHAR status;
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n");
- return;
- }
-#if 0
- {
- int i;
- printk(KERN_DEBUG
- "verify_dl_startup parameters sent via ccs %d:\n",
- local->dl_param_ccs);
- for (i = 0; i < sizeof(struct b5_startup_params); i++) {
- printk(" %2x",
- (unsigned int)readb(local->sram +
- HOST_TO_ECF_BASE + i));
- }
- printk("\n");
- }
-#endif
-
- status = readb(&pccs->buffer_status);
- if (status != CCS_BUFFER_FREE) {
- printk(KERN_INFO
- "Download startup params failed. Status = %d\n",
- status);
- local->card_status = CARD_DL_PARAM_ERROR;
- return;
- }
- if (local->sparm.b4.a_network_type == ADHOC)
- start_net(&local->timer);
- else
- join_net(&local->timer);
-} /* end verify_dl_startup */
-
-/*===========================================================================*/
-/* Command card to start a network */
-static void start_net(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
- struct ccs __iomem *pccs;
- int ccsindex;
- struct pcmcia_device *link = local->finder;
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs start_net - device not present\n");
- return;
- }
- /* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) < 0)
- return;
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_START_NETWORK, &pccs->cmd);
- writeb(0, &pccs->var.start_network.update_param);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return;
- }
- local->card_status = CARD_DOING_ACQ;
-} /* end start_net */
-
-/*===========================================================================*/
-/* Command card to join a network */
-static void join_net(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
-
- struct ccs __iomem *pccs;
- int ccsindex;
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs join_net - device not present\n");
- return;
- }
- /* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) < 0)
- return;
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_JOIN_NETWORK, &pccs->cmd);
- writeb(0, &pccs->var.join_network.update_param);
- writeb(0, &pccs->var.join_network.net_initiated);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return;
- }
- local->card_status = CARD_DOING_ACQ;
-}
-
-
-static void ray_release(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
- ray_dev_t *local = netdev_priv(dev);
-
- dev_dbg(&link->dev, "ray_release\n");
-
- del_timer_sync(&local->timer);
-
- if (local->sram)
- iounmap(local->sram);
- if (local->rmem)
- iounmap(local->rmem);
- if (local->amem)
- iounmap(local->amem);
- pcmcia_disable_device(link);
-
- dev_dbg(&link->dev, "ray_release ending\n");
-}
-
-static int ray_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open)
- netif_device_detach(dev);
-
- return 0;
-}
-
-static int ray_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open) {
- ray_reset(dev);
- netif_device_attach(dev);
- }
-
- return 0;
-}
-
-/*===========================================================================*/
-static int ray_dev_init(struct net_device *dev)
-{
-#ifdef RAY_IMMEDIATE_INIT
- int i;
-#endif /* RAY_IMMEDIATE_INIT */
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
-
- dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev);
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_dev_init - device not present\n");
- return -1;
- }
-#ifdef RAY_IMMEDIATE_INIT
- /* Download startup parameters */
- if ((i = dl_startup_params(dev)) < 0) {
- printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
- "returns 0x%x\n", i);
- return -1;
- }
-#else /* RAY_IMMEDIATE_INIT */
- /* Postpone the card init so that we can still configure the card,
- * for example using the Wireless Extensions. The init will happen
- * in ray_open() - Jean II */
- dev_dbg(&link->dev,
- "ray_dev_init: postponing card init to ray_open() ; Status = %d\n",
- local->card_status);
-#endif /* RAY_IMMEDIATE_INIT */
-
- /* copy mac and broadcast addresses to linux device */
- eth_hw_addr_set(dev, local->sparm.b4.a_mac_addr);
- eth_broadcast_addr(dev->broadcast);
-
- dev_dbg(&link->dev, "ray_dev_init ending\n");
- return 0;
-}
-
-/*===========================================================================*/
-static int ray_dev_config(struct net_device *dev, struct ifmap *map)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- /* Dummy routine to satisfy device structure */
- dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map);
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_dev_config - device not present\n");
- return -1;
- }
-
- return 0;
-}
-
-/*===========================================================================*/
-static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- short length = skb->len;
-
- if (!pcmcia_dev_present(link)) {
- dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev);
- if (local->authentication_state == NEED_TO_AUTH) {
- dev_dbg(&link->dev, "ray_cs Sending authentication request.\n");
- if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) {
- local->authentication_state = AUTHENTICATED;
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- }
- }
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
- case XMIT_NO_CCS:
- case XMIT_NEED_AUTH:
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- case XMIT_NO_INTR:
- case XMIT_MSG_BAD:
- case XMIT_OK:
- default:
- dev_kfree_skb(skb);
- }
-
- return NETDEV_TX_OK;
-} /* ray_dev_start_xmit */
-
-/*===========================================================================*/
-static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev,
- UCHAR msg_type)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct ccs __iomem *pccs;
- int ccsindex;
- int offset;
- struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */
- short int addr; /* Address of xmit buffer in card space */
-
- pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev);
- if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) {
- printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",
- len);
- return XMIT_MSG_BAD;
- }
- switch (ccsindex = get_free_tx_ccs(local)) {
- case ECCSBUSY:
- pr_debug("ray_hw_xmit tx_ccs table busy\n");
- fallthrough;
- case ECCSFULL:
- pr_debug("ray_hw_xmit No free tx ccs\n");
- fallthrough;
- case ECARDGONE:
- netif_stop_queue(dev);
- return XMIT_NO_CCS;
- default:
- break;
- }
- addr = TX_BUF_BASE + (ccsindex << 11);
-
- if (msg_type == DATA_TYPE) {
- local->stats.tx_bytes += len;
- local->stats.tx_packets++;
- }
-
- ptx = local->sram + addr;
-
- ray_build_header(local, ptx, msg_type, data);
- if (translate) {
- offset = translate_frame(local, ptx, data, len);
- } else { /* Encapsulate frame */
- /* TBD TIB length will move address of ptx->var */
- memcpy_toio(&ptx->var, data, len);
- offset = 0;
- }
-
- /* fill in the CCS */
- pccs = ccs_base(local) + ccsindex;
- len += TX_HEADER_LENGTH + offset;
- writeb(CCS_TX_REQUEST, &pccs->cmd);
- writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
- writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
- writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
- writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
-/* TBD still need psm_cam? */
- writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
- writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
- writeb(0, &pccs->var.tx_request.antenna);
- pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n",
- local->net_default_tx_rate);
-
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- pr_debug("ray_hw_xmit failed - ECF not ready for intr\n");
-/* TBD very inefficient to copy packet to buffer, and then not
- send it, but the alternative is to queue the messages and that
- won't be done for a while. Maybe set tbusy until a CCS is free?
-*/
- writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
- return XMIT_NO_INTR;
- }
- return XMIT_OK;
-} /* end ray_hw_xmit */
-
-/*===========================================================================*/
-static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
- unsigned char *data, int len)
-{
- __be16 proto = ((struct ethhdr *)data)->h_proto;
- if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */
- pr_debug("ray_cs translate_frame DIX II\n");
- /* Copy LLC header to card buffer */
- memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
- memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc),
- (UCHAR *) &proto, 2);
- if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
- /* This is the selective translation table, only 2 entries */
- writeb(0xf8,
- &((struct snaphdr_t __iomem *)ptx->var)->org[2]);
- }
- /* Copy body of ethernet packet without ethernet header */
- memcpy_toio((void __iomem *)&ptx->var +
- sizeof(struct snaphdr_t), data + ETH_HLEN,
- len - ETH_HLEN);
- return (int)sizeof(struct snaphdr_t) - ETH_HLEN;
- } else { /* already 802 type, and proto is length */
- pr_debug("ray_cs translate_frame 802\n");
- if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
- pr_debug("ray_cs translate_frame evil IPX\n");
- memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
- return 0 - ETH_HLEN;
- }
- memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
- return 0 - ETH_HLEN;
- }
- /* TBD do other frame types */
-} /* end translate_frame */
-
-/*===========================================================================*/
-static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
- UCHAR msg_type, unsigned char *data)
-{
- writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
-/*** IEEE 802.11 Address field assignments *************
- TODS FROMDS addr_1 addr_2 addr_3 addr_4
-Adhoc 0 0 dest src (terminal) BSSID N/A
-AP to Terminal 0 1 dest AP(BSSID) source N/A
-Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A
-AP to AP 1 1 dest AP src AP dest source
-*******************************************************/
- if (local->net_type == ADHOC) {
- writeb(0, &ptx->mac.frame_ctl_2);
- memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest,
- ADDRLEN);
- memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source,
- ADDRLEN);
- memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
- } else { /* infrastructure */
-
- if (local->sparm.b4.a_acting_as_ap_status) {
- writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);
- memcpy_toio(ptx->mac.addr_1,
- ((struct ethhdr *)data)->h_dest, ADDRLEN);
- memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
- memcpy_toio(ptx->mac.addr_3,
- ((struct ethhdr *)data)->h_source, ADDRLEN);
- } else { /* Terminal */
-
- writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
- memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
- memcpy_toio(ptx->mac.addr_2,
- ((struct ethhdr *)data)->h_source, ADDRLEN);
- memcpy_toio(ptx->mac.addr_3,
- ((struct ethhdr *)data)->h_dest, ADDRLEN);
- }
- }
-} /* end encapsulate_frame */
-
-/*====================================================================*/
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get protocol name
- */
-static int ray_get_name(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- strcpy(wrqu->name, "IEEE 802.11-FH");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set frequency
- */
-static int ray_set_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* Setting by channel number */
- if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0))
- err = -EOPNOTSUPP;
- else
- local->sparm.b5.a_hop_pattern = wrqu->freq.m;
-
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get frequency
- */
-static int ray_get_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- wrqu->freq.m = local->sparm.b5.a_hop_pattern;
- wrqu->freq.e = 0;
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set ESSID
- */
-static int ray_set_essid(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* Check if we asked for `any' */
- if (wrqu->essid.flags == 0)
- /* Corey : can you do that ? */
- return -EOPNOTSUPP;
-
- /* Check the size of the string */
- if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- /* Set the ESSID in the card */
- memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
- memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get ESSID
- */
-static int ray_get_essid(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- UCHAR tmp[IW_ESSID_MAX_SIZE + 1];
-
- /* Get the essid that was set */
- memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
- memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
- tmp[IW_ESSID_MAX_SIZE] = '\0';
-
- /* Push it out ! */
- wrqu->essid.length = strlen(tmp);
- wrqu->essid.flags = 1; /* active */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get AP address
- */
-static int ray_get_wap(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN);
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Bit-Rate
- */
-static int ray_set_rate(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* Check if rate is in range */
- if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000))
- return -EINVAL;
-
- /* Hack for 1.5 Mb/s instead of 2 Mb/s */
- if ((local->fw_ver == 0x55) && /* Please check */
- (wrqu->bitrate.value == 2000000))
- local->net_default_tx_rate = 3;
- else
- local->net_default_tx_rate = wrqu->bitrate.value / 500000;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Bit-Rate
- */
-static int ray_get_rate(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- if (local->net_default_tx_rate == 3)
- wrqu->bitrate.value = 2000000; /* Hum... */
- else
- wrqu->bitrate.value = local->net_default_tx_rate * 500000;
- wrqu->bitrate.fixed = 0; /* We are in auto mode */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set RTS threshold
- */
-static int ray_set_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int rthr = wrqu->rts.value;
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* if(wrq->u.rts.fixed == 0) we should complain */
- if (wrqu->rts.disabled)
- rthr = 32767;
- else {
- if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
- return -EINVAL;
- }
- local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
- local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get RTS threshold
- */
-static int ray_get_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
- + local->sparm.b5.a_rts_threshold[1];
- wrqu->rts.disabled = (wrqu->rts.value == 32767);
- wrqu->rts.fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Fragmentation threshold
- */
-static int ray_set_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int fthr = wrqu->frag.value;
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* if(wrq->u.frag.fixed == 0) should complain */
- if (wrqu->frag.disabled)
- fthr = 32767;
- else {
- if ((fthr < 256) || (fthr > 2347)) /* To check out ! */
- return -EINVAL;
- }
- local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
- local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Fragmentation threshold
- */
-static int ray_get_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
- + local->sparm.b5.a_frag_threshold[1];
- wrqu->frag.disabled = (wrqu->frag.value == 32767);
- wrqu->frag.fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Mode of Operation
- */
-static int ray_set_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- char card_mode = 1;
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- switch (wrqu->mode) {
- case IW_MODE_ADHOC:
- card_mode = 0;
- fallthrough;
- case IW_MODE_INFRA:
- local->sparm.b5.a_network_type = card_mode;
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Mode of Operation
- */
-static int ray_get_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- if (local->sparm.b5.a_network_type)
- wrqu->mode = IW_MODE_INFRA;
- else
- wrqu->mode = IW_MODE_ADHOC;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get range info
- */
-static int ray_get_range(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_range *range = (struct iw_range *)extra;
-
- memset(range, 0, sizeof(struct iw_range));
-
- /* Set the length (very important for backward compatibility) */
- wrqu->data.length = sizeof(struct iw_range);
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 9;
-
- /* Set information in the range struct */
- range->throughput = 1.1 * 1000 * 1000; /* Put the right number here */
- range->num_channels = hop_pattern_length[(int)country];
- range->num_frequency = 0;
- range->max_qual.qual = 0;
- range->max_qual.level = 255; /* What's the correct value ? */
- range->max_qual.noise = 255; /* Idem */
- range->num_bitrates = 2;
- range->bitrate[0] = 1000000; /* 1 Mb/s */
- range->bitrate[1] = 2000000; /* 2 Mb/s */
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Private Handler : set framing mode
- */
-static int ray_set_framing(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- translate = !!*(extra); /* Set framing mode */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Private Handler : get framing mode
- */
-static int ray_get_framing(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- *(extra) = translate;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Private Handler : get country
- */
-static int ray_get_country(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- *(extra) = country;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Commit handler : called after a bunch of SET operations
- */
-static int ray_commit(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Stats handler : return Wireless Stats
- */
-static iw_stats *ray_get_wireless_stats(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- struct status __iomem *p = local->sram + STATUS_BASE;
-
- local->wstats.status = local->card_status;
-#ifdef WIRELESS_SPY
- if ((local->spy_data.spy_number > 0)
- && (local->sparm.b5.a_network_type == 0)) {
- /* Get it from the first node in spy list */
- local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
- local->wstats.qual.level = local->spy_data.spy_stat[0].level;
- local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
- local->wstats.qual.updated =
- local->spy_data.spy_stat[0].updated;
- }
-#endif /* WIRELESS_SPY */
-
- if (pcmcia_dev_present(link)) {
- local->wstats.qual.noise = readb(&p->rxnoise);
- local->wstats.qual.updated |= 4;
- }
-
- return &local->wstats;
-} /* end ray_get_wireless_stats */
-
-/*------------------------------------------------------------------*/
-/*
- * Structures to export the Wireless Handlers
- */
-
-static const iw_handler ray_handler[] = {
- IW_HANDLER(SIOCSIWCOMMIT, ray_commit),
- IW_HANDLER(SIOCGIWNAME, ray_get_name),
- IW_HANDLER(SIOCSIWFREQ, ray_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ray_get_freq),
- IW_HANDLER(SIOCSIWMODE, ray_set_mode),
- IW_HANDLER(SIOCGIWMODE, ray_get_mode),
- IW_HANDLER(SIOCGIWRANGE, ray_get_range),
-#ifdef WIRELESS_SPY
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
-#endif /* WIRELESS_SPY */
- IW_HANDLER(SIOCGIWAP, ray_get_wap),
- IW_HANDLER(SIOCSIWESSID, ray_set_essid),
- IW_HANDLER(SIOCGIWESSID, ray_get_essid),
- IW_HANDLER(SIOCSIWRATE, ray_set_rate),
- IW_HANDLER(SIOCGIWRATE, ray_get_rate),
- IW_HANDLER(SIOCSIWRTS, ray_set_rts),
- IW_HANDLER(SIOCGIWRTS, ray_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ray_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ray_get_frag),
-};
-
-#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
-#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */
-#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */
-
-static const iw_handler ray_private_handler[] = {
- [0] = ray_set_framing,
- [1] = ray_get_framing,
- [3] = ray_get_country,
-};
-
-static const struct iw_priv_args ray_private_args[] = {
-/* cmd, set_args, get_args, name */
- {SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0,
- "set_framing"},
- {SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
- "get_framing"},
- {SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
- "get_country"},
-};
-
-static const struct iw_handler_def ray_handler_def = {
- .num_standard = ARRAY_SIZE(ray_handler),
- .num_private = ARRAY_SIZE(ray_private_handler),
- .num_private_args = ARRAY_SIZE(ray_private_args),
- .standard = ray_handler,
- .private = ray_private_handler,
- .private_args = ray_private_args,
- .get_wireless_stats = ray_get_wireless_stats,
-};
-
-/*===========================================================================*/
-static int ray_open(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link;
- link = local->finder;
-
- dev_dbg(&link->dev, "ray_open('%s')\n", dev->name);
-
- if (link->open == 0)
- local->num_multi = 0;
- link->open++;
-
- /* If the card is not started, time to start it ! - Jean II */
- if (local->card_status == CARD_AWAITING_PARAM) {
- int i;
-
- dev_dbg(&link->dev, "ray_open: doing init now !\n");
-
- /* Download startup parameters */
- if ((i = dl_startup_params(dev)) < 0) {
- printk(KERN_INFO
- "ray_dev_init dl_startup_params failed - "
- "returns 0x%x\n", i);
- return -1;
- }
- }
-
- if (sniffer)
- netif_stop_queue(dev);
- else
- netif_start_queue(dev);
-
- dev_dbg(&link->dev, "ray_open ending\n");
- return 0;
-} /* end ray_open */
-
-/*===========================================================================*/
-static int ray_dev_close(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link;
- link = local->finder;
-
- dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name);
-
- link->open--;
- netif_stop_queue(dev);
-
- /* In here, we should stop the hardware (stop card from beeing active)
- * and set local->card_status to CARD_AWAITING_PARAM, so that while the
- * card is closed we can chage its configuration.
- * Probably also need a COR reset to get sane state - Jean II */
-
- return 0;
-} /* end ray_dev_close */
-
-/*===========================================================================*/
-static void ray_reset(struct net_device *dev)
-{
- pr_debug("ray_reset entered\n");
-}
-
-/*===========================================================================*/
-/* Cause a firmware interrupt if it is ready for one */
-/* Return nonzero if not ready */
-static int interrupt_ecf(ray_dev_t *local, int ccs)
-{
- int i = 50;
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n");
- return -1;
- }
- dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs);
-
- while (i &&
- (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) &
- ECF_INTR_SET))
- i--;
- if (i == 0) {
- dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n");
- return -1;
- }
- /* Fill the mailbox, then kick the card */
- writeb(ccs, local->sram + SCB_BASE);
- writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
- return 0;
-} /* interrupt_ecf */
-
-/*===========================================================================*/
-/* Get next free transmit CCS */
-/* Return - index of current tx ccs */
-static int get_free_tx_ccs(ray_dev_t *local)
-{
- int i;
- struct ccs __iomem *pccs = ccs_base(local);
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n");
- return ECARDGONE;
- }
-
- if (test_and_set_bit(0, &local->tx_ccs_lock)) {
- dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n");
- return ECCSBUSY;
- }
-
- for (i = 0; i < NUMBER_OF_TX_CCS; i++) {
- if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
- writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
- writeb(CCS_END_LIST, &(pccs + i)->link);
- local->tx_ccs_lock = 0;
- return i;
- }
- }
- local->tx_ccs_lock = 0;
- dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n");
- return ECCSFULL;
-} /* get_free_tx_ccs */
-
-/*===========================================================================*/
-/* Get next free CCS */
-/* Return - index of current ccs */
-static int get_free_ccs(ray_dev_t *local)
-{
- int i;
- struct ccs __iomem *pccs = ccs_base(local);
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n");
- return ECARDGONE;
- }
- if (test_and_set_bit(0, &local->ccs_lock)) {
- dev_dbg(&link->dev, "ray_cs ccs_lock busy\n");
- return ECCSBUSY;
- }
-
- for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
- if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
- writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
- writeb(CCS_END_LIST, &(pccs + i)->link);
- local->ccs_lock = 0;
- return i;
- }
- }
- local->ccs_lock = 0;
- dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n");
- return ECCSFULL;
-} /* get_free_ccs */
-
-/*===========================================================================*/
-static void authenticate_timeout(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
- del_timer(&local->timer);
- printk(KERN_INFO "ray_cs Authentication with access point failed"
- " - timeout\n");
- join_net(&local->timer);
-}
-
-/*===========================================================================*/
-static int parse_addr(char *in_str, UCHAR *out)
-{
- int i, k;
- int len;
-
- if (in_str == NULL)
- return 0;
- len = strnlen(in_str, ADDRLEN * 2 + 1) - 1;
- if (len < 1)
- return 0;
- memset(out, 0, ADDRLEN);
-
- i = 5;
-
- while (len > 0) {
- if ((k = hex_to_bin(in_str[len--])) != -1)
- out[i] = k;
- else
- return 0;
-
- if (len == 0)
- break;
- if ((k = hex_to_bin(in_str[len--])) != -1)
- out[i] += k << 4;
- else
- return 0;
- if (!i--)
- break;
- }
- return 1;
-}
-
-/*===========================================================================*/
-static struct net_device_stats *ray_get_stats(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- struct status __iomem *p = local->sram + STATUS_BASE;
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n");
- return &local->stats;
- }
- if (readb(&p->mrx_overflow_for_host)) {
- local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
- writeb(0, &p->mrx_overflow);
- writeb(0, &p->mrx_overflow_for_host);
- }
- if (readb(&p->mrx_checksum_error_for_host)) {
- local->stats.rx_crc_errors +=
- swab16(readw(&p->mrx_checksum_error));
- writeb(0, &p->mrx_checksum_error);
- writeb(0, &p->mrx_checksum_error_for_host);
- }
- if (readb(&p->rx_hec_error_for_host)) {
- local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
- writeb(0, &p->rx_hec_error);
- writeb(0, &p->rx_hec_error_for_host);
- }
- return &local->stats;
-}
-
-/*===========================================================================*/
-static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value,
- int len)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- int ccsindex;
- int i;
- struct ccs __iomem *pccs;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_update_parm - device not present\n");
- return;
- }
-
- if ((ccsindex = get_free_ccs(local)) < 0) {
- dev_dbg(&link->dev, "ray_update_parm - No free ccs\n");
- return;
- }
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
- writeb(objid, &pccs->var.update_param.object_id);
- writeb(1, &pccs->var.update_param.number_objects);
- writeb(0, &pccs->var.update_param.failure_cause);
- for (i = 0; i < len; i++) {
- writeb(value[i], local->sram + HOST_TO_ECF_BASE);
- }
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- }
-}
-
-/*===========================================================================*/
-static void ray_update_multi_list(struct net_device *dev, int all)
-{
- int ccsindex;
- struct ccs __iomem *pccs;
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- void __iomem *p = local->sram + HOST_TO_ECF_BASE;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_update_multi_list - device not present\n");
- return;
- } else
- dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev);
- if ((ccsindex = get_free_ccs(local)) < 0) {
- dev_dbg(&link->dev, "ray_update_multi - No free ccs\n");
- return;
- }
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
-
- if (all) {
- writeb(0xff, &pccs->var);
- local->num_multi = 0xff;
- } else {
- struct netdev_hw_addr *ha;
- int i = 0;
-
- /* Copy the kernel's list of MC addresses to card */
- netdev_for_each_mc_addr(ha, dev) {
- memcpy_toio(p, ha->addr, ETH_ALEN);
- dev_dbg(&link->dev, "ray_update_multi add addr %pm\n",
- ha->addr);
- p += ETH_ALEN;
- i++;
- }
- if (i > 256 / ADDRLEN)
- i = 256 / ADDRLEN;
- writeb((UCHAR) i, &pccs->var);
- dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i);
- /* Interrupt the firmware to process the command */
- local->num_multi = i;
- }
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev,
- "ray_cs update_multi failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- }
-} /* end ray_update_multi_list */
-
-/*===========================================================================*/
-static void set_multicast_list(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- UCHAR promisc;
-
- pr_debug("ray_cs set_multicast_list(%p)\n", dev);
-
- if (dev->flags & IFF_PROMISC) {
- if (local->sparm.b5.a_promiscuous_mode == 0) {
- pr_debug("ray_cs set_multicast_list promisc on\n");
- local->sparm.b5.a_promiscuous_mode = 1;
- promisc = 1;
- ray_update_parm(dev, OBJID_promiscuous_mode,
- &promisc, sizeof(promisc));
- }
- } else {
- if (local->sparm.b5.a_promiscuous_mode == 1) {
- pr_debug("ray_cs set_multicast_list promisc off\n");
- local->sparm.b5.a_promiscuous_mode = 0;
- promisc = 0;
- ray_update_parm(dev, OBJID_promiscuous_mode,
- &promisc, sizeof(promisc));
- }
- }
-
- if (dev->flags & IFF_ALLMULTI)
- ray_update_multi_list(dev, 1);
- else {
- if (local->num_multi != netdev_mc_count(dev))
- ray_update_multi_list(dev, 0);
- }
-} /* end set_multicast_list */
-
-/*=============================================================================
- * All routines below here are run at interrupt time.
-=============================================================================*/
-static irqreturn_t ray_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct pcmcia_device *link;
- ray_dev_t *local;
- struct ccs __iomem *pccs;
- struct rcs __iomem *prcs;
- UCHAR rcsindex;
- UCHAR tmp;
- UCHAR cmd;
- UCHAR status;
- UCHAR memtmp[ESSID_SIZE + 1];
-
-
- if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */
- return IRQ_NONE;
-
- pr_debug("ray_cs: interrupt for *dev=%p\n", dev);
-
- local = netdev_priv(dev);
- link = local->finder;
- if (!pcmcia_dev_present(link)) {
- pr_debug(
- "ray_cs interrupt from device not present or suspended.\n");
- return IRQ_NONE;
- }
- rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index);
-
- if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
- dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex);
- clear_interrupt(local);
- return IRQ_HANDLED;
- }
- if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */
- pccs = ccs_base(local) + rcsindex;
- cmd = readb(&pccs->cmd);
- status = readb(&pccs->buffer_status);
- switch (cmd) {
- case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */
- del_timer(&local->timer);
- if (status == CCS_COMMAND_COMPLETE) {
- dev_dbg(&link->dev,
- "ray_cs interrupt download_startup_parameters OK\n");
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt download_startup_parameters fail\n");
- }
- break;
- case CCS_UPDATE_PARAMS:
- dev_dbg(&link->dev, "ray_cs interrupt update params done\n");
- if (status != CCS_COMMAND_COMPLETE) {
- tmp =
- readb(&pccs->var.update_param.
- failure_cause);
- dev_dbg(&link->dev,
- "ray_cs interrupt update params failed - reason %d\n",
- tmp);
- }
- break;
- case CCS_REPORT_PARAMS:
- dev_dbg(&link->dev, "ray_cs interrupt report params done\n");
- break;
- case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */
- dev_dbg(&link->dev,
- "ray_cs interrupt CCS Update Multicast List done\n");
- break;
- case CCS_UPDATE_POWER_SAVINGS_MODE:
- dev_dbg(&link->dev,
- "ray_cs interrupt update power save mode done\n");
- break;
- case CCS_START_NETWORK:
- case CCS_JOIN_NETWORK:
- memcpy(memtmp, local->sparm.b4.a_current_ess_id,
- ESSID_SIZE);
- memtmp[ESSID_SIZE] = '\0';
-
- if (status == CCS_COMMAND_COMPLETE) {
- if (readb
- (&pccs->var.start_network.net_initiated) ==
- 1) {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" started\n",
- memtmp);
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" joined\n",
- memtmp);
- }
- memcpy_fromio(&local->bss_id,
- pccs->var.start_network.bssid,
- ADDRLEN);
-
- if (local->fw_ver == 0x55)
- local->net_default_tx_rate = 3;
- else
- local->net_default_tx_rate =
- readb(&pccs->var.start_network.
- net_default_tx_rate);
- local->encryption =
- readb(&pccs->var.start_network.encryption);
- if (!sniffer && (local->net_type == INFRA)
- && !(local->sparm.b4.a_acting_as_ap_status)) {
- authenticate(local);
- }
- local->card_status = CARD_ACQ_COMPLETE;
- } else {
- local->card_status = CARD_ACQ_FAILED;
-
- del_timer(&local->timer);
- local->timer.expires = jiffies + HZ * 5;
- if (status == CCS_START_NETWORK) {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" start failed\n",
- memtmp);
- local->timer.function = start_net;
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" join failed\n",
- memtmp);
- local->timer.function = join_net;
- }
- add_timer(&local->timer);
- }
- break;
- case CCS_START_ASSOCIATION:
- if (status == CCS_COMMAND_COMPLETE) {
- local->card_status = CARD_ASSOC_COMPLETE;
- dev_dbg(&link->dev, "ray_cs association successful\n");
- } else {
- dev_dbg(&link->dev, "ray_cs association failed,\n");
- local->card_status = CARD_ASSOC_FAILED;
- join_net(&local->timer);
- }
- break;
- case CCS_TX_REQUEST:
- if (status == CCS_COMMAND_COMPLETE) {
- dev_dbg(&link->dev,
- "ray_cs interrupt tx request complete\n");
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt tx request failed\n");
- }
- if (!sniffer)
- netif_start_queue(dev);
- netif_wake_queue(dev);
- break;
- case CCS_TEST_MEMORY:
- dev_dbg(&link->dev, "ray_cs interrupt mem test done\n");
- break;
- case CCS_SHUTDOWN:
- dev_dbg(&link->dev,
- "ray_cs interrupt Unexpected CCS returned - Shutdown\n");
- break;
- case CCS_DUMP_MEMORY:
- dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n");
- break;
- case CCS_START_TIMER:
- dev_dbg(&link->dev,
- "ray_cs interrupt DING - raylink timer expired\n");
- break;
- default:
- dev_dbg(&link->dev,
- "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",
- rcsindex, cmd);
- }
- writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
- } else { /* It's an RCS */
-
- prcs = rcs_base(local) + rcsindex;
-
- switch (readb(&prcs->interrupt_id)) {
- case PROCESS_RX_PACKET:
- ray_rx(dev, local, prcs);
- break;
- case REJOIN_NET_COMPLETE:
- dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n");
- local->card_status = CARD_ACQ_COMPLETE;
- /* do we need to clear tx buffers CCS's? */
- if (local->sparm.b4.a_network_type == ADHOC) {
- if (!sniffer)
- netif_start_queue(dev);
- } else {
- memcpy_fromio(&local->bss_id,
- prcs->var.rejoin_net_complete.
- bssid, ADDRLEN);
- dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n",
- local->bss_id);
- if (!sniffer)
- authenticate(local);
- }
- break;
- case ROAMING_INITIATED:
- dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n");
- netif_stop_queue(dev);
- local->card_status = CARD_DOING_ACQ;
- break;
- case JAPAN_CALL_SIGN_RXD:
- dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n");
- break;
- default:
- dev_dbg(&link->dev,
- "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",
- rcsindex,
- (unsigned int)readb(&prcs->interrupt_id));
- break;
- }
- writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
- }
- clear_interrupt(local);
- return IRQ_HANDLED;
-} /* ray_interrupt */
-
-/*===========================================================================*/
-static void ray_rx(struct net_device *dev, ray_dev_t *local,
- struct rcs __iomem *prcs)
-{
- int rx_len;
- unsigned int pkt_addr;
- void __iomem *pmsg;
- pr_debug("ray_rx process rx packet\n");
-
- /* Calculate address of packet within Rx buffer */
- pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
- + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
- /* Length of first packet fragment */
- rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
- + readb(&prcs->var.rx_packet.rx_data_length[1]);
-
- local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
- pmsg = local->rmem + pkt_addr;
- switch (readb(pmsg)) {
- case DATA_TYPE:
- pr_debug("ray_rx data type\n");
- rx_data(dev, prcs, pkt_addr, rx_len);
- break;
- case AUTHENTIC_TYPE:
- pr_debug("ray_rx authentic type\n");
- if (sniffer)
- rx_data(dev, prcs, pkt_addr, rx_len);
- else
- rx_authenticate(local, prcs, pkt_addr, rx_len);
- break;
- case DEAUTHENTIC_TYPE:
- pr_debug("ray_rx deauth type\n");
- if (sniffer)
- rx_data(dev, prcs, pkt_addr, rx_len);
- else
- rx_deauthenticate(local, prcs, pkt_addr, rx_len);
- break;
- case NULL_MSG_TYPE:
- pr_debug("ray_cs rx NULL msg\n");
- break;
- case BEACON_TYPE:
- pr_debug("ray_rx beacon type\n");
- if (sniffer)
- rx_data(dev, prcs, pkt_addr, rx_len);
-
- copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr,
- rx_len < sizeof(struct beacon_rx) ?
- rx_len : sizeof(struct beacon_rx));
-
- local->beacon_rxed = 1;
- /* Get the statistics so the card counters never overflow */
- ray_get_stats(dev);
- break;
- default:
- pr_debug("ray_cs unknown pkt type %2x\n",
- (unsigned int)readb(pmsg));
- break;
- }
-
-} /* end ray_rx */
-
-/*===========================================================================*/
-static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len)
-{
- struct sk_buff *skb = NULL;
- struct rcs __iomem *prcslink = prcs;
- ray_dev_t *local = netdev_priv(dev);
- UCHAR *rx_ptr;
- int total_len;
- int tmp;
-#ifdef WIRELESS_SPY
- int siglev = local->last_rsl;
- u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */
-#endif
-
- if (!sniffer) {
- if (translate) {
-/* TBD length needs fixing for translated header */
- if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
- rx_len >
- (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
- FCS_LEN)) {
- pr_debug(
- "ray_cs invalid packet length %d received\n",
- rx_len);
- return;
- }
- } else { /* encapsulated ethernet */
-
- if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
- rx_len >
- (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
- FCS_LEN)) {
- pr_debug(
- "ray_cs invalid packet length %d received\n",
- rx_len);
- return;
- }
- }
- }
- pr_debug("ray_cs rx_data packet\n");
- /* If fragmented packet, verify sizes of fragments add up */
- if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
- pr_debug("ray_cs rx'ed fragment\n");
- tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
- + readb(&prcs->var.rx_packet.totalpacketlength[1]);
- total_len = tmp;
- prcslink = prcs;
- do {
- tmp -=
- (readb(&prcslink->var.rx_packet.rx_data_length[0])
- << 8)
- + readb(&prcslink->var.rx_packet.rx_data_length[1]);
- if (readb(&prcslink->var.rx_packet.next_frag_rcs_index)
- == 0xFF || tmp < 0)
- break;
- prcslink = rcs_base(local)
- + readb(&prcslink->link_field);
- } while (1);
-
- if (tmp < 0) {
- pr_debug(
- "ray_cs rx_data fragment lengths don't add up\n");
- local->stats.rx_dropped++;
- release_frag_chain(local, prcs);
- return;
- }
- } else { /* Single unfragmented packet */
- total_len = rx_len;
- }
-
- skb = dev_alloc_skb(total_len + 5);
- if (skb == NULL) {
- pr_debug("ray_cs rx_data could not allocate skb\n");
- local->stats.rx_dropped++;
- if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
- release_frag_chain(local, prcs);
- return;
- }
- skb_reserve(skb, 2); /* Align IP on 16 byte (TBD check this) */
-
- pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len,
- rx_len);
-
-/************************/
- /* Reserve enough room for the whole damn packet. */
- rx_ptr = skb_put(skb, total_len);
- /* Copy the whole packet to sk_buff */
- rx_ptr +=
- copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
- /* Get source address */
-#ifdef WIRELESS_SPY
- skb_copy_from_linear_data_offset(skb,
- offsetof(struct mac_header, addr_2),
- linksrcaddr, ETH_ALEN);
-#endif
- /* Now, deal with encapsulation/translation/sniffer */
- if (!sniffer) {
- if (!translate) {
- /* Encapsulated ethernet, so just lop off 802.11 MAC header */
-/* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */
- skb_pull(skb, RX_MAC_HEADER_LENGTH);
- } else {
- /* Do translation */
- untranslate(local, skb, total_len);
- }
- } else { /* sniffer mode, so just pass whole packet */
- }
-
-/************************/
- /* Now pick up the rest of the fragments if any */
- tmp = 17;
- if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
- prcslink = prcs;
- pr_debug("ray_cs rx_data in fragment loop\n");
- do {
- prcslink = rcs_base(local)
- +
- readb(&prcslink->var.rx_packet.next_frag_rcs_index);
- rx_len =
- ((readb(&prcslink->var.rx_packet.rx_data_length[0])
- << 8)
- +
- readb(&prcslink->var.rx_packet.rx_data_length[1]))
- & RX_BUFF_END;
- pkt_addr =
- ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) <<
- 8)
- + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
- & RX_BUFF_END;
-
- rx_ptr +=
- copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
-
- } while (tmp-- &&
- readb(&prcslink->var.rx_packet.next_frag_rcs_index) !=
- 0xFF);
- release_frag_chain(local, prcs);
- }
-
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- local->stats.rx_packets++;
- local->stats.rx_bytes += total_len;
-
- /* Gather signal strength per address */
-#ifdef WIRELESS_SPY
- /* For the Access Point or the node having started the ad-hoc net
- * note : ad-hoc work only in some specific configurations, but we
- * kludge in ray_get_wireless_stats... */
- if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) {
- /* Update statistics */
- /*local->wstats.qual.qual = none ? */
- local->wstats.qual.level = siglev;
- /*local->wstats.qual.noise = none ? */
- local->wstats.qual.updated = 0x2;
- }
- /* Now, update the spy stuff */
- {
- struct iw_quality wstats;
- wstats.level = siglev;
- /* wstats.noise = none ? */
- /* wstats.qual = none ? */
- wstats.updated = 0x2;
- /* Update spy records */
- wireless_spy_update(dev, linksrcaddr, &wstats);
- }
-#endif /* WIRELESS_SPY */
-} /* end rx_data */
-
-/*===========================================================================*/
-static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
-{
- snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH);
- struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
- __be16 type = *(__be16 *) psnap->ethertype;
- int delta;
- struct ethhdr *peth;
- UCHAR srcaddr[ADDRLEN];
- UCHAR destaddr[ADDRLEN];
- static const UCHAR org_bridge[3] = { 0, 0, 0xf8 };
- static const UCHAR org_1042[3] = { 0, 0, 0 };
-
- memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
- memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
-
-#if 0
- if {
- print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ",
- DUMP_PREFIX_NONE, 16, 1,
- skb->data, 64, true);
- printk(KERN_DEBUG
- "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
- ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl,
- psnap->org[0], psnap->org[1], psnap->org[2]);
- printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data);
- }
-#endif
-
- if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
- /* not a snap type so leave it alone */
- pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n",
- psnap->dsap, psnap->ssap, psnap->ctrl);
-
- delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
- } else { /* Its a SNAP */
- if (memcmp(psnap->org, org_bridge, 3) == 0) {
- /* EtherII and nuke the LLC */
- pr_debug("ray_cs untranslate Bridge encap\n");
- delta = RX_MAC_HEADER_LENGTH
- + sizeof(struct snaphdr_t) - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = type;
- } else if (memcmp(psnap->org, org_1042, 3) == 0) {
- switch (ntohs(type)) {
- case ETH_P_IPX:
- case ETH_P_AARP:
- pr_debug("ray_cs untranslate RFC IPX/AARP\n");
- delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto =
- htons(len - RX_MAC_HEADER_LENGTH);
- break;
- default:
- pr_debug("ray_cs untranslate RFC default\n");
- delta = RX_MAC_HEADER_LENGTH +
- sizeof(struct snaphdr_t) - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = type;
- break;
- }
- } else {
- printk("ray_cs untranslate very confused by packet\n");
- delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = type;
- }
- }
-/* TBD reserve skb_reserve(skb, delta); */
- skb_pull(skb, delta);
- pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta,
- skb->data);
- memcpy(peth->h_dest, destaddr, ADDRLEN);
- memcpy(peth->h_source, srcaddr, ADDRLEN);
-#if 0
- {
- int i;
- printk(KERN_DEBUG "skb->data after untranslate:");
- for (i = 0; i < 64; i++)
- printk("%02x ", skb->data[i]);
- printk("\n");
- }
-#endif
-} /* end untranslate */
-
-/*===========================================================================*/
-/* Copy data from circular receive buffer to PC memory.
- * dest = destination address in PC memory
- * pkt_addr = source address in receive buffer
- * len = length of packet to copy
- */
-static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr,
- int length)
-{
- int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
- if (wrap_bytes <= 0) {
- memcpy_fromio(dest, local->rmem + pkt_addr, length);
- } else { /* Packet wrapped in circular buffer */
-
- memcpy_fromio(dest, local->rmem + pkt_addr,
- length - wrap_bytes);
- memcpy_fromio(dest + length - wrap_bytes, local->rmem,
- wrap_bytes);
- }
- return length;
-}
-
-/*===========================================================================*/
-static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs)
-{
- struct rcs __iomem *prcslink = prcs;
- int tmp = 17;
- unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
-
- while (tmp--) {
- writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
- if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
- pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n",
- rcsindex);
- break;
- }
- prcslink = rcs_base(local) + rcsindex;
- rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
- }
- writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
-}
-
-/*===========================================================================*/
-static void authenticate(ray_dev_t *local)
-{
- struct pcmcia_device *link = local->finder;
- dev_dbg(&link->dev, "ray_cs Starting authentication.\n");
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs authenticate - device not present\n");
- return;
- }
-
- del_timer(&local->timer);
- if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
- local->timer.function = join_net;
- } else {
- local->timer.function = authenticate_timeout;
- }
- local->timer.expires = jiffies + HZ * 2;
- add_timer(&local->timer);
- local->authentication_state = AWAITING_RESPONSE;
-} /* end authenticate */
-
-/*===========================================================================*/
-static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len)
-{
- UCHAR buff[256];
- struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
-
- del_timer(&local->timer);
-
- copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
- /* if we are trying to get authenticated */
- if (local->sparm.b4.a_network_type == ADHOC) {
- pr_debug("ray_cs rx_auth var= %6ph\n", msg->var);
- if (msg->var[2] == 1) {
- pr_debug("ray_cs Sending authentication response.\n");
- if (!build_auth_frame
- (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
- local->authentication_state = NEED_TO_AUTH;
- memcpy(local->auth_id, msg->mac.addr_2,
- ADDRLEN);
- }
- }
- } else { /* Infrastructure network */
-
- if (local->authentication_state == AWAITING_RESPONSE) {
- /* Verify authentication sequence #2 and success */
- if (msg->var[2] == 2) {
- if ((msg->var[3] | msg->var[4]) == 0) {
- pr_debug("Authentication successful\n");
- local->card_status = CARD_AUTH_COMPLETE;
- associate(local);
- local->authentication_state =
- AUTHENTICATED;
- } else {
- pr_debug("Authentication refused\n");
- local->card_status = CARD_AUTH_REFUSED;
- join_net(&local->timer);
- local->authentication_state =
- UNAUTHENTICATED;
- }
- }
- }
- }
-
-} /* end rx_authenticate */
-
-/*===========================================================================*/
-static void associate(ray_dev_t *local)
-{
- struct ccs __iomem *pccs;
- struct pcmcia_device *link = local->finder;
- struct net_device *dev = link->priv;
- int ccsindex;
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs associate - device not present\n");
- return;
- }
- /* If no tx buffers available, return */
- if ((ccsindex = get_free_ccs(local)) < 0) {
-/* TBD should never be here but... what if we are? */
- dev_dbg(&link->dev, "ray_cs associate - No free ccs\n");
- return;
- }
- dev_dbg(&link->dev, "ray_cs Starting association with access point\n");
- pccs = ccs_base(local) + ccsindex;
- /* fill in the CCS */
- writeb(CCS_START_ASSOCIATION, &pccs->cmd);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-
- del_timer(&local->timer);
- local->timer.expires = jiffies + HZ * 2;
- local->timer.function = join_net;
- add_timer(&local->timer);
- local->card_status = CARD_ASSOC_FAILED;
- return;
- }
- if (!sniffer)
- netif_start_queue(dev);
-
-} /* end associate */
-
-/*===========================================================================*/
-static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len)
-{
-/* UCHAR buff[256];
- struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
-*/
- pr_debug("Deauthentication frame received\n");
- local->authentication_state = UNAUTHENTICATED;
- /* Need to reauthenticate or rejoin depending on reason code */
-/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
- */
-}
-
-/*===========================================================================*/
-static void clear_interrupt(ray_dev_t *local)
-{
- writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
-}
-
-/*===========================================================================*/
-#ifdef CONFIG_PROC_FS
-#define MAXDATA (PAGE_SIZE - 80)
-
-static const char *card_status[] = {
- "Card inserted - uninitialized", /* 0 */
- "Card not downloaded", /* 1 */
- "Waiting for download parameters", /* 2 */
- "Card doing acquisition", /* 3 */
- "Acquisition complete", /* 4 */
- "Authentication complete", /* 5 */
- "Association complete", /* 6 */
- "???", "???", "???", "???", /* 7 8 9 10 undefined */
- "Card init error", /* 11 */
- "Download parameters error", /* 12 */
- "???", /* 13 */
- "Acquisition failed", /* 14 */
- "Authentication refused", /* 15 */
- "Association failed" /* 16 */
-};
-
-static const char *nettype[] = { "Adhoc", "Infra " };
-static const char *framing[] = { "Encapsulation", "Translation" }
-
-;
-/*===========================================================================*/
-static int ray_cs_proc_show(struct seq_file *m, void *v)
-{
-/* Print current values which are not available via other means
- * eg ifconfig
- */
- int i;
- struct pcmcia_device *link;
- struct net_device *dev;
- ray_dev_t *local;
- UCHAR *p;
- struct freq_hop_element *pfh;
- UCHAR c[33];
-
- link = this_device;
- if (!link)
- return 0;
- dev = link->priv;
- if (!dev)
- return 0;
- local = netdev_priv(dev);
- if (!local)
- return 0;
-
- seq_puts(m, "Raylink Wireless LAN driver status\n");
- seq_printf(m, "%s\n", rcsid);
- /* build 4 does not report version, and field is 0x55 after memtest */
- seq_puts(m, "Firmware version = ");
- if (local->fw_ver == 0x55)
- seq_puts(m, "4 - Use dump_cis for more details\n");
- else
- seq_printf(m, "%2d.%02d.%02d\n",
- local->fw_ver, local->fw_bld, local->fw_var);
-
- for (i = 0; i < 32; i++)
- c[i] = local->sparm.b5.a_current_ess_id[i];
- c[32] = 0;
- seq_printf(m, "%s network ESSID = \"%s\"\n",
- nettype[local->sparm.b5.a_network_type], c);
-
- p = local->bss_id;
- seq_printf(m, "BSSID = %pM\n", p);
-
- seq_printf(m, "Country code = %d\n",
- local->sparm.b5.a_curr_country_code);
-
- i = local->card_status;
- if (i < 0)
- i = 10;
- if (i > 16)
- i = 10;
- seq_printf(m, "Card status = %s\n", card_status[i]);
-
- seq_printf(m, "Framing mode = %s\n", framing[translate]);
-
- seq_printf(m, "Last pkt signal lvl = %d\n", local->last_rsl);
-
- if (local->beacon_rxed) {
- /* Pull some fields out of last beacon received */
- seq_printf(m, "Beacon Interval = %d Kus\n",
- local->last_bcn.beacon_intvl[0]
- + 256 * local->last_bcn.beacon_intvl[1]);
-
- p = local->last_bcn.elements;
- if (p[0] == C_ESSID_ELEMENT_ID)
- p += p[1] + 2;
- else {
- seq_printf(m,
- "Parse beacon failed at essid element id = %d\n",
- p[0]);
- return 0;
- }
-
- if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
- seq_puts(m, "Supported rate codes = ");
- for (i = 2; i < p[1] + 2; i++)
- seq_printf(m, "0x%02x ", p[i]);
- seq_putc(m, '\n');
- p += p[1] + 2;
- } else {
- seq_puts(m, "Parse beacon failed at rates element\n");
- return 0;
- }
-
- if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
- pfh = (struct freq_hop_element *)p;
- seq_printf(m, "Hop dwell = %d Kus\n",
- pfh->dwell_time[0] +
- 256 * pfh->dwell_time[1]);
- seq_printf(m, "Hop set = %d\n",
- pfh->hop_set);
- seq_printf(m, "Hop pattern = %d\n",
- pfh->hop_pattern);
- seq_printf(m, "Hop index = %d\n",
- pfh->hop_index);
- p += p[1] + 2;
- } else {
- seq_puts(m,
- "Parse beacon failed at FH param element\n");
- return 0;
- }
- } else {
- seq_puts(m, "No beacons received\n");
- }
- return 0;
-}
-#endif
-/*===========================================================================*/
-static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
-{
- int addr;
- struct ccs __iomem *pccs;
- struct tx_msg __iomem *ptx;
- int ccsindex;
-
- /* If no tx buffers available, return */
- if ((ccsindex = get_free_tx_ccs(local)) < 0) {
- pr_debug("ray_cs send authenticate - No free tx ccs\n");
- return -1;
- }
-
- pccs = ccs_base(local) + ccsindex;
-
- /* Address in card space */
- addr = TX_BUF_BASE + (ccsindex << 11);
- /* fill in the CCS */
- writeb(CCS_TX_REQUEST, &pccs->cmd);
- writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
- writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
- writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
- writeb(TX_AUTHENTICATE_LENGTH_LSB,
- pccs->var.tx_request.tx_data_length + 1);
- writeb(0, &pccs->var.tx_request.pow_sav_mode);
-
- ptx = local->sram + addr;
- /* fill in the mac header */
- writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
- writeb(0, &ptx->mac.frame_ctl_2);
-
- memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
- memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
- memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
-
- /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
- memset_io(ptx->var, 0, 6);
- writeb(auth_type & 0xff, ptx->var + 2);
-
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- pr_debug(
- "ray_cs send authentication request failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return -1;
- }
- return 0;
-} /* End build_auth_frame */
-
-/*===========================================================================*/
-#ifdef CONFIG_PROC_FS
-static ssize_t ray_cs_essid_proc_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *pos)
-{
- static char proc_essid[33];
- unsigned int len = count;
-
- if (len > 32)
- len = 32;
- memset(proc_essid, 0, 33);
- if (copy_from_user(proc_essid, buffer, len))
- return -EFAULT;
- essid = proc_essid;
- return count;
-}
-
-static const struct proc_ops ray_cs_essid_proc_ops = {
- .proc_write = ray_cs_essid_proc_write,
- .proc_lseek = noop_llseek,
-};
-
-static ssize_t int_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- static char proc_number[10];
- char *p;
- int nr, len;
-
- if (!count)
- return 0;
-
- if (count > 9)
- return -EINVAL;
- if (copy_from_user(proc_number, buffer, count))
- return -EFAULT;
- p = proc_number;
- nr = 0;
- len = count;
- do {
- unsigned int c = *p - '0';
- if (c > 9)
- return -EINVAL;
- nr = nr * 10 + c;
- p++;
- } while (--len);
- *(int *)pde_data(file_inode(file)) = nr;
- return count;
-}
-
-static const struct proc_ops int_proc_ops = {
- .proc_write = int_proc_write,
- .proc_lseek = noop_llseek,
-};
-#endif
-
-static const struct pcmcia_device_id ray_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
- PCMCIA_DEVICE_NULL,
-};
-
-MODULE_DEVICE_TABLE(pcmcia, ray_ids);
-
-static struct pcmcia_driver ray_driver = {
- .owner = THIS_MODULE,
- .name = "ray_cs",
- .probe = ray_probe,
- .remove = ray_detach,
- .id_table = ray_ids,
- .suspend = ray_suspend,
- .resume = ray_resume,
-};
-
-static int __init init_ray_cs(void)
-{
- int rc;
-
- pr_debug("%s\n", rcsid);
- rc = pcmcia_register_driver(&ray_driver);
- pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n",
- rc);
- if (rc)
- return rc;
-
-#ifdef CONFIG_PROC_FS
- proc_mkdir("driver/ray_cs", NULL);
-
- proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show);
- proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_ops);
- proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_ops,
- &net_type);
- proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_ops,
- &translate);
-#endif
- translate = !!translate;
- return 0;
-} /* init_ray_cs */
-
-/*===========================================================================*/
-
-static void __exit exit_ray_cs(void)
-{
- pr_debug("ray_cs: cleanup_module\n");
-
-#ifdef CONFIG_PROC_FS
- remove_proc_subtree("driver/ray_cs", NULL);
-#endif
-
- pcmcia_unregister_driver(&ray_driver);
-} /* exit_ray_cs */
-
-module_init(init_ray_cs);
-module_exit(exit_ray_cs);
-
-/*===========================================================================*/
diff --git a/drivers/net/wireless/legacy/ray_cs.h b/drivers/net/wireless/legacy/ray_cs.h
deleted file mode 100644
index 0609d8625019..000000000000
--- a/drivers/net/wireless/legacy/ray_cs.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Raytheon wireless LAN PCMCIA card driver for Linux
- A PCMCIA client driver for the Raylink wireless network card
- Written by Corey Thomas
-*/
-
-#ifndef _RAY_CS_H_
-#define _RAY_CS_H_
-
-struct beacon_rx {
- struct mac_header mac;
- UCHAR timestamp[8];
- UCHAR beacon_intvl[2];
- UCHAR capability[2];
- UCHAR elements[sizeof(struct essid_element)
- + sizeof(struct rates_element)
- + sizeof(struct freq_hop_element)
- + sizeof(struct japan_call_sign_element)
- + sizeof(struct tim_element)];
-};
-
-/* Return values for get_free{,_tx}_ccs */
-#define ECCSFULL (-1)
-#define ECCSBUSY (-2)
-#define ECARDGONE (-3)
-
-typedef struct ray_dev_t {
- int card_status;
- int authentication_state;
- void __iomem *sram; /* pointer to beginning of shared RAM */
- void __iomem *amem; /* pointer to attribute mem window */
- void __iomem *rmem; /* pointer to receive buffer window */
- struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */
- struct timer_list timer;
- unsigned long tx_ccs_lock;
- unsigned long ccs_lock;
- int dl_param_ccs;
- union {
- struct b4_startup_params b4;
- struct b5_startup_params b5;
- } sparm;
- int timeout_flag;
- UCHAR supported_rates[8];
- UCHAR japan_call_sign[12];
- struct startup_res_6 startup_res;
- int num_multi;
- /* Network parameters from start/join */
- UCHAR bss_id[6];
- UCHAR auth_id[6];
- UCHAR net_default_tx_rate;
- UCHAR encryption;
- struct net_device_stats stats;
-
- UCHAR net_type;
- UCHAR sta_type;
- UCHAR fw_ver;
- UCHAR fw_bld;
- UCHAR fw_var;
- UCHAR ASIC_version;
- UCHAR assoc_id[2];
- UCHAR tib_length;
- UCHAR last_rsl;
- int beacon_rxed;
- struct beacon_rx last_bcn;
- iw_stats wstats; /* Wireless specific stats */
-#ifdef WIRELESS_SPY
- struct iw_spy_data spy_data;
- struct iw_public_data wireless_data;
-#endif /* WIRELESS_SPY */
-
-} ray_dev_t;
-/*****************************************************************************/
-
-#endif /* _RAY_CS_H_ */
diff --git a/drivers/net/wireless/legacy/rayctl.h b/drivers/net/wireless/legacy/rayctl.h
deleted file mode 100644
index 1f3bde8ac73d..000000000000
--- a/drivers/net/wireless/legacy/rayctl.h
+++ /dev/null
@@ -1,734 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _RAYCTL_H_
-#define _RAYCTL_H_
-
-typedef unsigned char UCHAR;
-
-/****** IEEE 802.11 constants ************************************************/
-#define ADDRLEN 6
-/* Frame control 1 bit fields */
-#define PROTOCOL_VER 0x00
-#define DATA_TYPE 0x08
-#define ASSOC_REQ_TYPE 0x00
-#define ASSOC_RESP_TYPE 0x10
-#define REASSOC_REQ_TYPE 0x20
-#define REASSOC_RESP_TYPE 0x30
-#define NULL_MSG_TYPE 0x48
-#define BEACON_TYPE 0x80
-#define DISASSOC_TYPE 0xA0
-#define PSPOLL_TYPE 0xA4
-#define AUTHENTIC_TYPE 0xB0
-#define DEAUTHENTIC_TYPE 0xC0
-/* Frame control 2 bit fields */
-#define FC2_TO_DS 0x01
-#define FC2_FROM_DS 0x02
-#define FC2_MORE_FRAG 0x04
-#define FC2_RETRY 0x08
-#define FC2_PSM 0x10
-#define FC2_MORE_DATA 0x20
-#define FC2_WEP 0x40
-#define FC2_ORDER 0x80
-/*****************************************************************************/
-/* 802.11 element ID's and lengths */
-#define C_BP_CAPABILITY_ESS 0x01
-#define C_BP_CAPABILITY_IBSS 0x02
-#define C_BP_CAPABILITY_CF_POLLABLE 0x04
-#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08
-#define C_BP_CAPABILITY_PRIVACY 0x10
-
-#define C_ESSID_ELEMENT_ID 0
-#define C_ESSID_ELEMENT_MAX_LENGTH 32
-
-#define C_SUPPORTED_RATES_ELEMENT_ID 1
-#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2
-
-#define C_FH_PARAM_SET_ELEMENT_ID 2
-#define C_FH_PARAM_SET_ELEMENT_LNGTH 5
-
-#define C_CF_PARAM_SET_ELEMENT_ID 4
-#define C_CF_PARAM_SET_ELEMENT_LNGTH 6
-
-#define C_TIM_ELEMENT_ID 5
-#define C_TIM_BITMAP_LENGTH 251
-#define C_TIM_BMCAST_BIT 0x01
-
-#define C_IBSS_ELEMENT_ID 6
-#define C_IBSS_ELEMENT_LENGTH 2
-
-#define C_JAPAN_CALL_SIGN_ELEMENT_ID 51
-#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12
-
-#define C_DISASSOC_REASON_CODE_LEN 2
-#define C_DISASSOC_REASON_CODE_DEFAULT 8
-
-#define C_CRC_LEN 4
-#define C_NUM_SUPPORTED_RATES 8
-/****** IEEE 802.11 mac header for type data packets *************************/
-struct mac_header {
- UCHAR frame_ctl_1;
- UCHAR frame_ctl_2;
- UCHAR duration_lsb;
- UCHAR duration_msb;
- UCHAR addr_1[ADDRLEN];
- UCHAR addr_2[ADDRLEN];
- UCHAR addr_3[ADDRLEN];
- UCHAR seq_frag_num[2];
-/* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */
-};
-/****** IEEE 802.11 frame element structures *********************************/
-struct essid_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH];
-};
-struct rates_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR value[8];
-};
-struct freq_hop_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR dwell_time[2];
- UCHAR hop_set;
- UCHAR hop_pattern;
- UCHAR hop_index;
-};
-struct tim_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR dtim_count;
- UCHAR dtim_period;
- UCHAR bitmap_control;
- UCHAR tim[C_TIM_BITMAP_LENGTH];
-};
-struct ibss_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR atim_window[2];
-};
-struct japan_call_sign_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR call_sign[12];
-};
-/****** Beacon message structures ********************************************/
-/* .elements is a large lump of max size because elements are variable size */
-struct infra_beacon
-{
- UCHAR timestamp[8];
- UCHAR beacon_intvl[2];
- UCHAR capability[2];
- UCHAR elements[sizeof(struct essid_element)
- + sizeof(struct rates_element)
- + sizeof(struct freq_hop_element)
- + sizeof(struct japan_call_sign_element)
- + sizeof(struct tim_element)];
-};
-struct adhoc_beacon
-{
- UCHAR timestamp[8];
- UCHAR beacon_intvl[2];
- UCHAR capability[2];
- UCHAR elements[sizeof(struct essid_element)
- + sizeof(struct rates_element)
- + sizeof(struct freq_hop_element)
- + sizeof(struct japan_call_sign_element)
- + sizeof(struct ibss_element)];
-};
-/*****************************************************************************/
-/*****************************************************************************/
-/* #define C_MAC_HDR_2_WEP 0x40 */
-/* TX/RX CCS constants */
-#define TX_HEADER_LENGTH 0x1C
-#define RX_MAC_HEADER_LENGTH 0x18
-#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6)
-#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
-#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
-#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2)
-#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
-#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
-#define FCS_LEN 4
-
-#define ADHOC 0
-#define INFRA 1
-
-#define TYPE_STA 0
-#define TYPE_AP 1
-
-#define PASSIVE_SCAN 1
-#define ACTIVE_SCAN 1
-
-#define PSM_CAM 0
-
-/* Country codes */
-#define USA 1
-#define EUROPE 2
-#define JAPAN 3
-#define KOREA 4
-#define SPAIN 5
-#define FRANCE 6
-#define ISRAEL 7
-#define AUSTRALIA 8
-#define JAPAN_TEST 9
-
-/* Hop pattern lengths */
-#define USA_HOP_MOD 79
-#define EUROPE_HOP_MOD 79
-#define JAPAN_HOP_MOD 23
-#define KOREA_HOP_MOD 23
-#define SPAIN_HOP_MOD 27
-#define FRANCE_HOP_MOD 35
-#define ISRAEL_HOP_MOD 35
-#define AUSTRALIA_HOP_MOD 47
-#define JAPAN_TEST_HOP_MOD 23
-
-#define ESSID_SIZE 32
-/**********************************************************************/
-/* CIS Register Constants */
-#define CIS_OFFSET 0x0f00
-/* Configuration Option Register (0x0F00) */
-#define COR_OFFSET 0x00
-#define COR_SOFT_RESET 0x80
-#define COR_LEVEL_IRQ 0x40
-#define COR_CONFIG_NUM 0x01
-#define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM)
-
-/* Card Configuration and Status Register (0x0F01) */
-#define CCSR_OFFSET 0x01
-#define CCSR_HOST_INTR_PENDING 0x01
-#define CCSR_POWER_DOWN 0x04
-
-/* HCS Interrupt Register (0x0F05) */
-#define HCS_INTR_OFFSET 0x05
-/* #define HCS_INTR_OFFSET 0x0A */
-#define HCS_INTR_CLEAR 0x00
-
-/* ECF Interrupt Register (0x0F06) */
-#define ECF_INTR_OFFSET 0x06
-/* #define ECF_INTR_OFFSET 0x0C */
-#define ECF_INTR_SET 0x01
-
-/* Authorization Register 0 (0x0F08) */
-#define AUTH_0_ON 0x57
-
-/* Authorization Register 1 (0x0F09) */
-#define AUTH_1_ON 0x82
-
-/* Program Mode Register (0x0F0A) */
-#define PC2PM 0x02
-#define PC2CAL 0x10
-#define PC2MLSE 0x20
-
-/* PC Test Mode Register (0x0F0B) */
-#define PC_TEST_MODE 0x08
-
-/* Frequency Control Word (0x0F10) */
-/* Range 0x02 - 0xA6 */
-
-/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */
-
-/**********************************************************************/
-
-/* Shared RAM Area */
-#define SCB_BASE 0x0000
-#define STATUS_BASE 0x0100
-#define HOST_TO_ECF_BASE 0x0200
-#define ECF_TO_HOST_BASE 0x0300
-#define CCS_BASE 0x0400
-#define RCS_BASE 0x0800
-#define INFRA_TIM_BASE 0x0C00
-#define SSID_LIST_BASE 0x0D00
-#define TX_BUF_BASE 0x1000
-#define RX_BUF_BASE 0x8000
-
-#define NUMBER_OF_CCS 64
-#define NUMBER_OF_RCS 64
-/*#define NUMBER_OF_TX_CCS 14 */
-#define NUMBER_OF_TX_CCS 14
-
-#define TX_BUF_SIZE (2048 - sizeof(struct tx_msg))
-#define RX_BUFF_END 0x3FFF
-/* Values for buffer_status */
-#define CCS_BUFFER_FREE 0
-#define CCS_BUFFER_BUSY 1
-#define CCS_COMMAND_COMPLETE 2
-#define CCS_COMMAND_FAILED 3
-
-/* Values for cmd */
-#define CCS_DOWNLOAD_STARTUP_PARAMS 1
-#define CCS_UPDATE_PARAMS 2
-#define CCS_REPORT_PARAMS 3
-#define CCS_UPDATE_MULTICAST_LIST 4
-#define CCS_UPDATE_POWER_SAVINGS_MODE 5
-#define CCS_START_NETWORK 6
-#define CCS_JOIN_NETWORK 7
-#define CCS_START_ASSOCIATION 8
-#define CCS_TX_REQUEST 9
-#define CCS_TEST_MEMORY 0xa
-#define CCS_SHUTDOWN 0xb
-#define CCS_DUMP_MEMORY 0xc
-#define CCS_START_TIMER 0xe
-#define CCS_LAST_CMD CCS_START_TIMER
-
-/* Values for link field */
-#define CCS_END_LIST 0xff
-
-/* values for buffer_status field */
-#define RCS_BUFFER_FREE 0
-#define RCS_BUFFER_BUSY 1
-#define RCS_COMPLETE 2
-#define RCS_FAILED 3
-#define RCS_BUFFER_RELEASE 0xFF
-
-/* values for interrupt_id field */
-#define PROCESS_RX_PACKET 0x80 /* */
-#define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */
-#define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */
-#define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */
-
-/*****************************************************************************/
-/* Memory types for dump memory command */
-#define C_MEM_PROG 0
-#define C_MEM_XDATA 1
-#define C_MEM_SFR 2
-#define C_MEM_IDATA 3
-
-/*** Return values for hw_xmit **********/
-#define XMIT_OK (0)
-#define XMIT_MSG_BAD (-1)
-#define XMIT_NO_CCS (-2)
-#define XMIT_NO_INTR (-3)
-#define XMIT_NEED_AUTH (-4)
-
-/*** Values for card status */
-#define CARD_INSERTED (0)
-
-#define CARD_AWAITING_PARAM (1)
-#define CARD_INIT_ERROR (11)
-
-#define CARD_DL_PARAM (2)
-#define CARD_DL_PARAM_ERROR (12)
-
-#define CARD_DOING_ACQ (3)
-
-#define CARD_ACQ_COMPLETE (4)
-#define CARD_ACQ_FAILED (14)
-
-#define CARD_AUTH_COMPLETE (5)
-#define CARD_AUTH_REFUSED (15)
-
-#define CARD_ASSOC_COMPLETE (6)
-#define CARD_ASSOC_FAILED (16)
-
-/*** Values for authentication_state ***********************************/
-#define UNAUTHENTICATED (0)
-#define AWAITING_RESPONSE (1)
-#define AUTHENTICATED (2)
-#define NEED_TO_AUTH (3)
-
-/*** Values for authentication type ************************************/
-#define OPEN_AUTH_REQUEST (1)
-#define OPEN_AUTH_RESPONSE (2)
-#define BROADCAST_DEAUTH (0xc0)
-/*** Values for timer functions ****************************************/
-#define TODO_NOTHING (0)
-#define TODO_VERIFY_DL_START (-1)
-#define TODO_START_NET (-2)
-#define TODO_JOIN_NET (-3)
-#define TODO_AUTHENTICATE_TIMEOUT (-4)
-#define TODO_SEND_CCS (-5)
-/***********************************************************************/
-/* Parameter passing structure for update/report parameter CCS's */
-struct object_id {
- void *object_addr;
- unsigned char object_length;
-};
-
-#define OBJID_network_type 0
-#define OBJID_acting_as_ap_status 1
-#define OBJID_current_ess_id 2
-#define OBJID_scanning_mode 3
-#define OBJID_power_mgt_state 4
-#define OBJID_mac_address 5
-#define OBJID_frag_threshold 6
-#define OBJID_hop_time 7
-#define OBJID_beacon_period 8
-#define OBJID_dtim_period 9
-#define OBJID_retry_max 10
-#define OBJID_ack_timeout 11
-#define OBJID_sifs 12
-#define OBJID_difs 13
-#define OBJID_pifs 14
-#define OBJID_rts_threshold 15
-#define OBJID_scan_dwell_time 16
-#define OBJID_max_scan_dwell_time 17
-#define OBJID_assoc_resp_timeout 18
-#define OBJID_adhoc_scan_cycle_max 19
-#define OBJID_infra_scan_cycle_max 20
-#define OBJID_infra_super_cycle_max 21
-#define OBJID_promiscuous_mode 22
-#define OBJID_unique_word 23
-#define OBJID_slot_time 24
-#define OBJID_roaming_low_snr 25
-#define OBJID_low_snr_count_thresh 26
-#define OBJID_infra_missed_bcn 27
-#define OBJID_adhoc_missed_bcn 28
-#define OBJID_curr_country_code 29
-#define OBJID_hop_pattern 30
-#define OBJID_reserved 31
-#define OBJID_cw_max_msb 32
-#define OBJID_cw_min_msb 33
-#define OBJID_noise_filter_gain 34
-#define OBJID_noise_limit_offset 35
-#define OBJID_det_rssi_thresh_offset 36
-#define OBJID_med_busy_thresh_offset 37
-#define OBJID_det_sync_thresh 38
-#define OBJID_test_mode 39
-#define OBJID_test_min_chan_num 40
-#define OBJID_test_max_chan_num 41
-#define OBJID_allow_bcast_ID_prbrsp 42
-#define OBJID_privacy_must_start 43
-#define OBJID_privacy_can_join 44
-#define OBJID_basic_rate_set 45
-
-/**** Configuration/Status/Control Area ***************************/
-/* System Control Block (SCB) Area
- * Located at Shared RAM offset 0
- */
-struct scb {
- UCHAR ccs_index;
- UCHAR rcs_index;
-};
-
-/****** Status area at Shared RAM offset 0x0100 ******************************/
-struct status {
- UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/
- UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/
- UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/
- UCHAR reserved1;
- short mrx_overflow; /* ECF increments on rx overflow */
- short mrx_checksum_error; /* ECF increments on rx CRC error */
- short rx_hec_error; /* ECF incs on mac header CRC error */
- UCHAR rxnoise; /* Average RSL measurement */
-};
-
-/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/
-struct host_to_ecf_area {
-
-};
-
-/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/
-struct startup_res_518 {
- UCHAR startup_word;
- UCHAR station_addr[ADDRLEN];
- UCHAR calc_prog_chksum;
- UCHAR calc_cis_chksum;
- UCHAR ecf_spare[7];
- UCHAR japan_call_sign[12];
-};
-
-struct startup_res_6 {
- UCHAR startup_word;
- UCHAR station_addr[ADDRLEN];
- UCHAR reserved;
- UCHAR supp_rates[8];
- UCHAR japan_call_sign[12];
- UCHAR calc_prog_chksum;
- UCHAR calc_cis_chksum;
- UCHAR firmware_version[3];
- UCHAR asic_version;
- UCHAR tib_length;
-};
-
-struct start_join_net_params {
- UCHAR net_type;
- UCHAR ssid[ESSID_SIZE];
- UCHAR reserved;
- UCHAR privacy_can_join;
-};
-
-/****** Command Control Structure area at Shared ram offset 0x0400 ***********/
-/* Structures for command specific parameters (ccs.var) */
-struct update_param_cmd {
- UCHAR object_id;
- UCHAR number_objects;
- UCHAR failure_cause;
-};
-struct report_param_cmd {
- UCHAR object_id;
- UCHAR number_objects;
- UCHAR failure_cause;
- UCHAR length;
-};
-struct start_network_cmd {
- UCHAR update_param;
- UCHAR bssid[ADDRLEN];
- UCHAR net_initiated;
- UCHAR net_default_tx_rate;
- UCHAR encryption;
-};
-struct join_network_cmd {
- UCHAR update_param;
- UCHAR bssid[ADDRLEN];
- UCHAR net_initiated;
- UCHAR net_default_tx_rate;
- UCHAR encryption;
-};
-struct tx_requested_cmd {
-
- UCHAR tx_data_ptr[2];
- UCHAR tx_data_length[2];
- UCHAR host_reserved[2];
- UCHAR reserved[3];
- UCHAR tx_rate;
- UCHAR pow_sav_mode;
- UCHAR retries;
- UCHAR antenna;
-};
-struct tx_requested_cmd_4 {
-
- UCHAR tx_data_ptr[2];
- UCHAR tx_data_length[2];
- UCHAR dest_addr[ADDRLEN];
- UCHAR pow_sav_mode;
- UCHAR retries;
- UCHAR station_id;
-};
-struct memory_dump_cmd {
- UCHAR memory_type;
- UCHAR memory_ptr[2];
- UCHAR length;
-};
-struct update_association_cmd {
- UCHAR status;
- UCHAR aid[2];
-};
-struct start_timer_cmd {
- UCHAR duration[2];
-};
-
-struct ccs {
- UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */
- /* 2 = command complete, 3 = failed */
- UCHAR cmd; /* command to ECF */
- UCHAR link; /* link to next CCS, FF=end of list */
- /* command specific parameters */
- union {
- char reserved[13];
- struct update_param_cmd update_param;
- struct report_param_cmd report_param;
- UCHAR nummulticast;
- UCHAR mode;
- struct start_network_cmd start_network;
- struct join_network_cmd join_network;
- struct tx_requested_cmd tx_request;
- struct memory_dump_cmd memory_dump;
- struct update_association_cmd update_assoc;
- struct start_timer_cmd start_timer;
- } var;
-};
-
-/*****************************************************************************/
-/* Transmit buffer structures */
-struct tib_structure {
- UCHAR ccs_index;
- UCHAR psm;
- UCHAR pass_fail;
- UCHAR retry_count;
- UCHAR max_retries;
- UCHAR frags_remaining;
- UCHAR no_rb;
- UCHAR rts_reqd;
- UCHAR csma_tx_cntrl_2;
- UCHAR sifs_tx_cntrl_2;
- UCHAR tx_dma_addr_1[2];
- UCHAR tx_dma_addr_2[2];
- UCHAR var_dur_2mhz[2];
- UCHAR var_dur_1mhz[2];
- UCHAR max_dur_2mhz[2];
- UCHAR max_dur_1mhz[2];
- UCHAR hdr_len;
- UCHAR max_frag_len[2];
- UCHAR var_len[2];
- UCHAR phy_hdr_4;
- UCHAR mac_hdr_1;
- UCHAR mac_hdr_2;
- UCHAR sid[2];
-};
-
-struct phy_header {
- UCHAR sfd[2];
- UCHAR hdr_3;
- UCHAR hdr_4;
-};
-struct ray_rx_msg {
- struct mac_header mac;
- UCHAR var[];
-};
-
-struct tx_msg {
- struct tib_structure tib;
- struct phy_header phy;
- struct mac_header mac;
- UCHAR var[];
-};
-
-/****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */
-/* Structures for command specific parameters (rcs.var) */
-struct rx_packet_cmd {
- UCHAR rx_data_ptr[2];
- UCHAR rx_data_length[2];
- UCHAR rx_sig_lev;
- UCHAR next_frag_rcs_index;
- UCHAR totalpacketlength[2];
-};
-struct rejoin_net_cmplt_cmd {
- UCHAR reserved;
- UCHAR bssid[ADDRLEN];
-};
-struct japan_call_sign_rxd {
- UCHAR rxd_call_sign[8];
- UCHAR reserved[5];
-};
-
-struct rcs {
- UCHAR buffer_status;
- UCHAR interrupt_id;
- UCHAR link_field;
- /* command specific parameters */
- union {
- UCHAR reserved[13];
- struct rx_packet_cmd rx_packet;
- struct rejoin_net_cmplt_cmd rejoin_net_complete;
- struct japan_call_sign_rxd japan_call_sign;
- } var;
-};
-
-/****** Startup parameter structures for both versions of firmware ***********/
-struct b4_startup_params {
- UCHAR a_network_type; /* C_ADHOC, C_INFRA */
- UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */
- UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */
- UCHAR a_scanning_mode; /* passive 0, active 1 */
- UCHAR a_power_mgt_state; /* CAM 0, */
- UCHAR a_mac_addr[ADDRLEN]; /* */
- UCHAR a_frag_threshold[2]; /* 512 */
- UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */
- UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */
- UCHAR a_dtim_period; /* in beacons */
- UCHAR a_retry_max; /* */
- UCHAR a_ack_timeout; /* */
- UCHAR a_sifs; /* */
- UCHAR a_difs; /* */
- UCHAR a_pifs; /* */
- UCHAR a_rts_threshold[2]; /* */
- UCHAR a_scan_dwell_time[2]; /* */
- UCHAR a_max_scan_dwell_time[2]; /* */
- UCHAR a_assoc_resp_timeout_thresh; /* */
- UCHAR a_adhoc_scan_cycle_max; /* */
- UCHAR a_infra_scan_cycle_max; /* */
- UCHAR a_infra_super_scan_cycle_max; /* */
- UCHAR a_promiscuous_mode; /* */
- UCHAR a_unique_word[2]; /* */
- UCHAR a_slot_time; /* */
- UCHAR a_roaming_low_snr_thresh; /* */
- UCHAR a_low_snr_count_thresh; /* */
- UCHAR a_infra_missed_bcn_thresh; /* */
- UCHAR a_adhoc_missed_bcn_thresh; /* */
- UCHAR a_curr_country_code; /* C_USA */
- UCHAR a_hop_pattern; /* */
- UCHAR a_hop_pattern_length; /* */
-/* b4 - b5 differences start here */
- UCHAR a_cw_max; /* */
- UCHAR a_cw_min; /* */
- UCHAR a_noise_filter_gain; /* */
- UCHAR a_noise_limit_offset; /* */
- UCHAR a_det_rssi_thresh_offset; /* */
- UCHAR a_med_busy_thresh_offset; /* */
- UCHAR a_det_sync_thresh; /* */
- UCHAR a_test_mode; /* */
- UCHAR a_test_min_chan_num; /* */
- UCHAR a_test_max_chan_num; /* */
- UCHAR a_rx_tx_delay; /* */
- UCHAR a_current_bss_id[ADDRLEN]; /* */
- UCHAR a_hop_set; /* */
-};
-struct b5_startup_params {
- UCHAR a_network_type; /* C_ADHOC, C_INFRA */
- UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */
- UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */
- UCHAR a_scanning_mode; /* passive 0, active 1 */
- UCHAR a_power_mgt_state; /* CAM 0, */
- UCHAR a_mac_addr[ADDRLEN]; /* */
- UCHAR a_frag_threshold[2]; /* 512 */
- UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */
- UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */
- UCHAR a_dtim_period; /* in beacons */
- UCHAR a_retry_max; /* 4 */
- UCHAR a_ack_timeout; /* */
- UCHAR a_sifs; /* */
- UCHAR a_difs; /* */
- UCHAR a_pifs; /* */
- UCHAR a_rts_threshold[2]; /* */
- UCHAR a_scan_dwell_time[2]; /* */
- UCHAR a_max_scan_dwell_time[2]; /* */
- UCHAR a_assoc_resp_timeout_thresh; /* */
- UCHAR a_adhoc_scan_cycle_max; /* */
- UCHAR a_infra_scan_cycle_max; /* */
- UCHAR a_infra_super_scan_cycle_max; /* */
- UCHAR a_promiscuous_mode; /* */
- UCHAR a_unique_word[2]; /* */
- UCHAR a_slot_time; /* */
- UCHAR a_roaming_low_snr_thresh; /* */
- UCHAR a_low_snr_count_thresh; /* */
- UCHAR a_infra_missed_bcn_thresh; /* */
- UCHAR a_adhoc_missed_bcn_thresh; /* */
- UCHAR a_curr_country_code; /* C_USA */
- UCHAR a_hop_pattern; /* */
- UCHAR a_hop_pattern_length; /* */
-/* b4 - b5 differences start here */
- UCHAR a_cw_max[2]; /* */
- UCHAR a_cw_min[2]; /* */
- UCHAR a_noise_filter_gain; /* */
- UCHAR a_noise_limit_offset; /* */
- UCHAR a_det_rssi_thresh_offset; /* */
- UCHAR a_med_busy_thresh_offset; /* */
- UCHAR a_det_sync_thresh; /* */
- UCHAR a_test_mode; /* */
- UCHAR a_test_min_chan_num; /* */
- UCHAR a_test_max_chan_num; /* */
- UCHAR a_allow_bcast_SSID_probe_rsp;
- UCHAR a_privacy_must_start;
- UCHAR a_privacy_can_join;
- UCHAR a_basic_rate_set[8];
-};
-
-/*****************************************************************************/
-#define RAY_IOCG_PARMS (SIOCDEVPRIVATE)
-#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1)
-#define RAY_DO_CMD (SIOCDEVPRIVATE + 2)
-
-/****** ethernet <-> 802.11 translation **************************************/
-typedef struct snaphdr_t
-{
- UCHAR dsap;
- UCHAR ssap;
- UCHAR ctrl;
- UCHAR org[3];
- UCHAR ethertype[2];
-} snaphdr_t;
-
-#define BRIDGE_ENCAP 0xf80000
-#define RFC1042_ENCAP 0
-#define SNAP_ID 0x0003aaaa
-#define RAY_IPX_TYPE 0x8137
-#define APPLEARP_TYPE 0x80f3
-/*****************************************************************************/
-#endif /* _RAYCTL_H_ */
diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c
deleted file mode 100644
index e7fea7ded6d5..000000000000
--- a/drivers/net/wireless/legacy/rndis_wlan.c
+++ /dev/null
@@ -1,3760 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Driver for RNDIS based USB wireless devices.
- *
- * Copyright (C) 2007 by Bjorge Dijkstra <bjd@jooz.net>
- * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna@iki.fi>
- *
- * Portions of this file are based on NDISwrapper project,
- * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani
- * http://ndiswrapper.sourceforge.net/
- */
-
-// #define DEBUG // error path messages, extra info
-// #define VERBOSE // more; success messages
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/workqueue.h>
-#include <linux/mutex.h>
-#include <linux/mii.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/ieee80211.h>
-#include <linux/if_arp.h>
-#include <linux/ctype.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <net/cfg80211.h>
-#include <linux/usb/usbnet.h>
-#include <linux/usb/rndis_host.h>
-
-
-/* NOTE: All these are settings for Broadcom chipset */
-static char modparam_country[4] = "EU";
-module_param_string(country, modparam_country, 4, 0444);
-MODULE_PARM_DESC(country, "Country code (ISO 3166-1 alpha-2), default: EU");
-
-static int modparam_frameburst = 1;
-module_param_named(frameburst, modparam_frameburst, int, 0444);
-MODULE_PARM_DESC(frameburst, "enable frame bursting (default: on)");
-
-static int modparam_afterburner = 0;
-module_param_named(afterburner, modparam_afterburner, int, 0444);
-MODULE_PARM_DESC(afterburner,
- "enable afterburner aka '125 High Speed Mode' (default: off)");
-
-static int modparam_power_save = 0;
-module_param_named(power_save, modparam_power_save, int, 0444);
-MODULE_PARM_DESC(power_save,
- "set power save mode: 0=off, 1=on, 2=fast (default: off)");
-
-static int modparam_power_output = 3;
-module_param_named(power_output, modparam_power_output, int, 0444);
-MODULE_PARM_DESC(power_output,
- "set power output: 0=25%, 1=50%, 2=75%, 3=100% (default: 100%)");
-
-static int modparam_roamtrigger = -70;
-module_param_named(roamtrigger, modparam_roamtrigger, int, 0444);
-MODULE_PARM_DESC(roamtrigger,
- "set roaming dBm trigger: -80=optimize for distance, "
- "-60=bandwidth (default: -70)");
-
-static int modparam_roamdelta = 1;
-module_param_named(roamdelta, modparam_roamdelta, int, 0444);
-MODULE_PARM_DESC(roamdelta,
- "set roaming tendency: 0=aggressive, 1=moderate, "
- "2=conservative (default: moderate)");
-
-static int modparam_workaround_interval;
-module_param_named(workaround_interval, modparam_workaround_interval,
- int, 0444);
-MODULE_PARM_DESC(workaround_interval,
- "set stall workaround interval in msecs (0=disabled) (default: 0)");
-
-/* Typical noise/maximum signal level values taken from ndiswrapper iw_ndis.h */
-#define WL_NOISE -96 /* typical noise level in dBm */
-#define WL_SIGMAX -32 /* typical maximum signal level in dBm */
-
-
-/* Assume that Broadcom 4320 (only chipset at time of writing known to be
- * based on wireless rndis) has default txpower of 13dBm.
- * This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
- * 100% : 20 mW ~ 13dBm
- * 75% : 15 mW ~ 12dBm
- * 50% : 10 mW ~ 10dBm
- * 25% : 5 mW ~ 7dBm
- */
-#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
-#define BCM4320_DEFAULT_TXPOWER_DBM_75 12
-#define BCM4320_DEFAULT_TXPOWER_DBM_50 10
-#define BCM4320_DEFAULT_TXPOWER_DBM_25 7
-
-/* Known device types */
-#define RNDIS_UNKNOWN 0
-#define RNDIS_BCM4320A 1
-#define RNDIS_BCM4320B 2
-
-
-/* NDIS data structures. Taken from wpa_supplicant driver_ndis.c
- * slightly modified for datatype endianess, etc
- */
-#define NDIS_802_11_LENGTH_SSID 32
-#define NDIS_802_11_LENGTH_RATES 8
-#define NDIS_802_11_LENGTH_RATES_EX 16
-
-enum ndis_80211_net_type {
- NDIS_80211_TYPE_FREQ_HOP,
- NDIS_80211_TYPE_DIRECT_SEQ,
- NDIS_80211_TYPE_OFDM_A,
- NDIS_80211_TYPE_OFDM_G
-};
-
-enum ndis_80211_net_infra {
- NDIS_80211_INFRA_ADHOC,
- NDIS_80211_INFRA_INFRA,
- NDIS_80211_INFRA_AUTO_UNKNOWN
-};
-
-enum ndis_80211_auth_mode {
- NDIS_80211_AUTH_OPEN,
- NDIS_80211_AUTH_SHARED,
- NDIS_80211_AUTH_AUTO_SWITCH,
- NDIS_80211_AUTH_WPA,
- NDIS_80211_AUTH_WPA_PSK,
- NDIS_80211_AUTH_WPA_NONE,
- NDIS_80211_AUTH_WPA2,
- NDIS_80211_AUTH_WPA2_PSK
-};
-
-enum ndis_80211_encr_status {
- NDIS_80211_ENCR_WEP_ENABLED,
- NDIS_80211_ENCR_DISABLED,
- NDIS_80211_ENCR_WEP_KEY_ABSENT,
- NDIS_80211_ENCR_NOT_SUPPORTED,
- NDIS_80211_ENCR_TKIP_ENABLED,
- NDIS_80211_ENCR_TKIP_KEY_ABSENT,
- NDIS_80211_ENCR_CCMP_ENABLED,
- NDIS_80211_ENCR_CCMP_KEY_ABSENT
-};
-
-enum ndis_80211_priv_filter {
- NDIS_80211_PRIV_ACCEPT_ALL,
- NDIS_80211_PRIV_8021X_WEP
-};
-
-enum ndis_80211_status_type {
- NDIS_80211_STATUSTYPE_AUTHENTICATION,
- NDIS_80211_STATUSTYPE_MEDIASTREAMMODE,
- NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST,
- NDIS_80211_STATUSTYPE_RADIOSTATE,
-};
-
-enum ndis_80211_media_stream_mode {
- NDIS_80211_MEDIA_STREAM_OFF,
- NDIS_80211_MEDIA_STREAM_ON
-};
-
-enum ndis_80211_radio_status {
- NDIS_80211_RADIO_STATUS_ON,
- NDIS_80211_RADIO_STATUS_HARDWARE_OFF,
- NDIS_80211_RADIO_STATUS_SOFTWARE_OFF,
-};
-
-enum ndis_80211_addkey_bits {
- NDIS_80211_ADDKEY_8021X_AUTH = cpu_to_le32(1 << 28),
- NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ = cpu_to_le32(1 << 29),
- NDIS_80211_ADDKEY_PAIRWISE_KEY = cpu_to_le32(1 << 30),
- NDIS_80211_ADDKEY_TRANSMIT_KEY = cpu_to_le32(1 << 31)
-};
-
-enum ndis_80211_addwep_bits {
- NDIS_80211_ADDWEP_PERCLIENT_KEY = cpu_to_le32(1 << 30),
- NDIS_80211_ADDWEP_TRANSMIT_KEY = cpu_to_le32(1 << 31)
-};
-
-enum ndis_80211_power_mode {
- NDIS_80211_POWER_MODE_CAM,
- NDIS_80211_POWER_MODE_MAX_PSP,
- NDIS_80211_POWER_MODE_FAST_PSP,
-};
-
-enum ndis_80211_pmkid_cand_list_flag_bits {
- NDIS_80211_PMKID_CAND_PREAUTH = cpu_to_le32(1 << 0)
-};
-
-struct ndis_80211_auth_request {
- __le32 length;
- u8 bssid[ETH_ALEN];
- u8 padding[2];
- __le32 flags;
-} __packed;
-
-struct ndis_80211_pmkid_candidate {
- u8 bssid[ETH_ALEN];
- u8 padding[2];
- __le32 flags;
-} __packed;
-
-struct ndis_80211_pmkid_cand_list {
- __le32 version;
- __le32 num_candidates;
- struct ndis_80211_pmkid_candidate candidate_list[];
-} __packed;
-
-struct ndis_80211_status_indication {
- __le32 status_type;
- union {
- __le32 media_stream_mode;
- __le32 radio_status;
- DECLARE_FLEX_ARRAY(struct ndis_80211_auth_request, auth_request);
- struct ndis_80211_pmkid_cand_list cand_list;
- } u;
-} __packed;
-
-struct ndis_80211_ssid {
- __le32 length;
- u8 essid[NDIS_802_11_LENGTH_SSID];
-} __packed;
-
-struct ndis_80211_conf_freq_hop {
- __le32 length;
- __le32 hop_pattern;
- __le32 hop_set;
- __le32 dwell_time;
-} __packed;
-
-struct ndis_80211_conf {
- __le32 length;
- __le32 beacon_period;
- __le32 atim_window;
- __le32 ds_config;
- struct ndis_80211_conf_freq_hop fh_config;
-} __packed;
-
-struct ndis_80211_bssid_ex {
- __le32 length;
- u8 mac[ETH_ALEN];
- u8 padding[2];
- struct ndis_80211_ssid ssid;
- __le32 privacy;
- __le32 rssi;
- __le32 net_type;
- struct ndis_80211_conf config;
- __le32 net_infra;
- u8 rates[NDIS_802_11_LENGTH_RATES_EX];
- __le32 ie_length;
- u8 ies[];
-} __packed;
-
-struct ndis_80211_bssid_list_ex {
- __le32 num_items;
- u8 bssid_data[];
-} __packed;
-
-struct ndis_80211_fixed_ies {
- u8 timestamp[8];
- __le16 beacon_interval;
- __le16 capabilities;
-} __packed;
-
-struct ndis_80211_wep_key {
- __le32 size;
- __le32 index;
- __le32 length;
- u8 material[32];
-} __packed;
-
-struct ndis_80211_key {
- __le32 size;
- __le32 index;
- __le32 length;
- u8 bssid[ETH_ALEN];
- u8 padding[6];
- u8 rsc[8];
- u8 material[32];
-} __packed;
-
-struct ndis_80211_remove_key {
- __le32 size;
- __le32 index;
- u8 bssid[ETH_ALEN];
- u8 padding[2];
-} __packed;
-
-struct ndis_config_param {
- __le32 name_offs;
- __le32 name_length;
- __le32 type;
- __le32 value_offs;
- __le32 value_length;
-} __packed;
-
-struct ndis_80211_assoc_info {
- __le32 length;
- __le16 req_ies;
- struct req_ie {
- __le16 capa;
- __le16 listen_interval;
- u8 cur_ap_address[ETH_ALEN];
- } req_ie;
- __le32 req_ie_length;
- __le32 offset_req_ies;
- __le16 resp_ies;
- struct resp_ie {
- __le16 capa;
- __le16 status_code;
- __le16 assoc_id;
- } resp_ie;
- __le32 resp_ie_length;
- __le32 offset_resp_ies;
-} __packed;
-
-struct ndis_80211_capability {
- __le32 length;
- __le32 version;
- __le32 num_pmkids;
- __le32 num_auth_encr_pair;
-} __packed;
-
-struct ndis_80211_bssid_info {
- u8 bssid[ETH_ALEN];
- u8 pmkid[16];
-} __packed;
-
-struct ndis_80211_pmkid {
- __le32 length;
- __le32 bssid_info_count;
- struct ndis_80211_bssid_info bssid_info[];
-} __packed;
-
-/*
- * private data
- */
-#define CAP_MODE_80211A 1
-#define CAP_MODE_80211B 2
-#define CAP_MODE_80211G 4
-#define CAP_MODE_MASK 7
-
-#define WORK_LINK_UP 0
-#define WORK_LINK_DOWN 1
-#define WORK_SET_MULTICAST_LIST 2
-
-#define RNDIS_WLAN_ALG_NONE 0
-#define RNDIS_WLAN_ALG_WEP (1<<0)
-#define RNDIS_WLAN_ALG_TKIP (1<<1)
-#define RNDIS_WLAN_ALG_CCMP (1<<2)
-
-#define RNDIS_WLAN_NUM_KEYS 4
-#define RNDIS_WLAN_KEY_MGMT_NONE 0
-#define RNDIS_WLAN_KEY_MGMT_802_1X (1<<0)
-#define RNDIS_WLAN_KEY_MGMT_PSK (1<<1)
-
-#define COMMAND_BUFFER_SIZE (CONTROL_BUFFER_SIZE + sizeof(struct rndis_set))
-
-static const struct ieee80211_channel rndis_channels[] = {
- { .center_freq = 2412 },
- { .center_freq = 2417 },
- { .center_freq = 2422 },
- { .center_freq = 2427 },
- { .center_freq = 2432 },
- { .center_freq = 2437 },
- { .center_freq = 2442 },
- { .center_freq = 2447 },
- { .center_freq = 2452 },
- { .center_freq = 2457 },
- { .center_freq = 2462 },
- { .center_freq = 2467 },
- { .center_freq = 2472 },
- { .center_freq = 2484 },
-};
-
-static const struct ieee80211_rate rndis_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 60 },
- { .bitrate = 90 },
- { .bitrate = 120 },
- { .bitrate = 180 },
- { .bitrate = 240 },
- { .bitrate = 360 },
- { .bitrate = 480 },
- { .bitrate = 540 }
-};
-
-static const u32 rndis_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
-};
-
-struct rndis_wlan_encr_key {
- int len;
- u32 cipher;
- u8 material[32];
- u8 bssid[ETH_ALEN];
- bool pairwise;
- bool tx_key;
-};
-
-/* RNDIS device private data */
-struct rndis_wlan_private {
- struct usbnet *usbdev;
-
- struct wireless_dev wdev;
-
- struct cfg80211_scan_request *scan_request;
-
- struct workqueue_struct *workqueue;
- struct delayed_work dev_poller_work;
- struct delayed_work scan_work;
- struct work_struct work;
- struct mutex command_lock;
- unsigned long work_pending;
- int last_qual;
- s32 cqm_rssi_thold;
- u32 cqm_rssi_hyst;
- int last_cqm_event_rssi;
-
- struct ieee80211_supported_band band;
- struct ieee80211_channel channels[ARRAY_SIZE(rndis_channels)];
- struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)];
- u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)];
-
- int device_type;
- int caps;
- int multicast_size;
-
- /* module parameters */
- char param_country[4];
- int param_frameburst;
- int param_afterburner;
- int param_power_save;
- int param_power_output;
- int param_roamtrigger;
- int param_roamdelta;
- u32 param_workaround_interval;
-
- /* hardware state */
- bool radio_on;
- int power_mode;
- int infra_mode;
- bool connected;
- u8 bssid[ETH_ALEN];
- u32 current_command_oid;
-
- /* encryption stuff */
- u8 encr_tx_key_index;
- struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS];
- int wpa_version;
-
- u8 command_buffer[COMMAND_BUFFER_SIZE];
-};
-
-/*
- * cfg80211 ops
- */
-static int rndis_change_virtual_intf(struct wiphy *wiphy,
- struct net_device *dev,
- enum nl80211_iftype type,
- struct vif_params *params);
-
-static int rndis_scan(struct wiphy *wiphy,
- struct cfg80211_scan_request *request);
-
-static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
-
-static int rndis_set_tx_power(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- enum nl80211_tx_power_setting type,
- int mbm);
-static int rndis_get_tx_power(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- int *dbm);
-
-static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_connect_params *sme);
-
-static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev,
- u16 reason_code);
-
-static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_ibss_params *params);
-
-static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
-
-static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
- int link_id, u8 key_index, bool pairwise,
- const u8 *mac_addr, struct key_params *params);
-
-static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
- int link_id, u8 key_index, bool pairwise,
- const u8 *mac_addr);
-
-static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
- int link_id, u8 key_index, bool unicast,
- bool multicast);
-
-static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac, struct station_info *sinfo);
-
-static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
- int idx, u8 *mac, struct station_info *sinfo);
-
-static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa);
-
-static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa);
-
-static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev);
-
-static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
- bool enabled, int timeout);
-
-static int rndis_set_cqm_rssi_config(struct wiphy *wiphy,
- struct net_device *dev,
- s32 rssi_thold, u32 rssi_hyst);
-
-static const struct cfg80211_ops rndis_config_ops = {
- .change_virtual_intf = rndis_change_virtual_intf,
- .scan = rndis_scan,
- .set_wiphy_params = rndis_set_wiphy_params,
- .set_tx_power = rndis_set_tx_power,
- .get_tx_power = rndis_get_tx_power,
- .connect = rndis_connect,
- .disconnect = rndis_disconnect,
- .join_ibss = rndis_join_ibss,
- .leave_ibss = rndis_leave_ibss,
- .add_key = rndis_add_key,
- .del_key = rndis_del_key,
- .set_default_key = rndis_set_default_key,
- .get_station = rndis_get_station,
- .dump_station = rndis_dump_station,
- .set_pmksa = rndis_set_pmksa,
- .del_pmksa = rndis_del_pmksa,
- .flush_pmksa = rndis_flush_pmksa,
- .set_power_mgmt = rndis_set_power_mgmt,
- .set_cqm_rssi_config = rndis_set_cqm_rssi_config,
-};
-
-static void *rndis_wiphy_privid = &rndis_wiphy_privid;
-
-
-static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
-{
- return (struct rndis_wlan_private *)dev->driver_priv;
-}
-
-static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
-{
- switch (priv->param_power_output) {
- default:
- case 3:
- return BCM4320_DEFAULT_TXPOWER_DBM_100;
- case 2:
- return BCM4320_DEFAULT_TXPOWER_DBM_75;
- case 1:
- return BCM4320_DEFAULT_TXPOWER_DBM_50;
- case 0:
- return BCM4320_DEFAULT_TXPOWER_DBM_25;
- }
-}
-
-static bool is_wpa_key(struct rndis_wlan_private *priv, u8 idx)
-{
- int cipher = priv->encr_keys[idx].cipher;
-
- return (cipher == WLAN_CIPHER_SUITE_CCMP ||
- cipher == WLAN_CIPHER_SUITE_TKIP);
-}
-
-static int rndis_cipher_to_alg(u32 cipher)
-{
- switch (cipher) {
- default:
- return RNDIS_WLAN_ALG_NONE;
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- return RNDIS_WLAN_ALG_WEP;
- case WLAN_CIPHER_SUITE_TKIP:
- return RNDIS_WLAN_ALG_TKIP;
- case WLAN_CIPHER_SUITE_CCMP:
- return RNDIS_WLAN_ALG_CCMP;
- }
-}
-
-static int rndis_akm_suite_to_key_mgmt(u32 akm_suite)
-{
- switch (akm_suite) {
- default:
- return RNDIS_WLAN_KEY_MGMT_NONE;
- case WLAN_AKM_SUITE_8021X:
- return RNDIS_WLAN_KEY_MGMT_802_1X;
- case WLAN_AKM_SUITE_PSK:
- return RNDIS_WLAN_KEY_MGMT_PSK;
- }
-}
-
-#ifdef DEBUG
-static const char *oid_to_string(u32 oid)
-{
- switch (oid) {
-#define OID_STR(oid) case oid: return(#oid)
- /* from rndis_host.h */
- OID_STR(RNDIS_OID_802_3_PERMANENT_ADDRESS);
- OID_STR(RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE);
- OID_STR(RNDIS_OID_GEN_CURRENT_PACKET_FILTER);
- OID_STR(RNDIS_OID_GEN_PHYSICAL_MEDIUM);
-
- /* from rndis_wlan.c */
- OID_STR(RNDIS_OID_GEN_LINK_SPEED);
- OID_STR(RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER);
-
- OID_STR(RNDIS_OID_GEN_XMIT_OK);
- OID_STR(RNDIS_OID_GEN_RCV_OK);
- OID_STR(RNDIS_OID_GEN_XMIT_ERROR);
- OID_STR(RNDIS_OID_GEN_RCV_ERROR);
- OID_STR(RNDIS_OID_GEN_RCV_NO_BUFFER);
-
- OID_STR(RNDIS_OID_802_3_CURRENT_ADDRESS);
- OID_STR(RNDIS_OID_802_3_MULTICAST_LIST);
- OID_STR(RNDIS_OID_802_3_MAXIMUM_LIST_SIZE);
-
- OID_STR(RNDIS_OID_802_11_BSSID);
- OID_STR(RNDIS_OID_802_11_SSID);
- OID_STR(RNDIS_OID_802_11_INFRASTRUCTURE_MODE);
- OID_STR(RNDIS_OID_802_11_ADD_WEP);
- OID_STR(RNDIS_OID_802_11_REMOVE_WEP);
- OID_STR(RNDIS_OID_802_11_DISASSOCIATE);
- OID_STR(RNDIS_OID_802_11_AUTHENTICATION_MODE);
- OID_STR(RNDIS_OID_802_11_PRIVACY_FILTER);
- OID_STR(RNDIS_OID_802_11_BSSID_LIST_SCAN);
- OID_STR(RNDIS_OID_802_11_ENCRYPTION_STATUS);
- OID_STR(RNDIS_OID_802_11_ADD_KEY);
- OID_STR(RNDIS_OID_802_11_REMOVE_KEY);
- OID_STR(RNDIS_OID_802_11_ASSOCIATION_INFORMATION);
- OID_STR(RNDIS_OID_802_11_CAPABILITY);
- OID_STR(RNDIS_OID_802_11_PMKID);
- OID_STR(RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED);
- OID_STR(RNDIS_OID_802_11_NETWORK_TYPE_IN_USE);
- OID_STR(RNDIS_OID_802_11_TX_POWER_LEVEL);
- OID_STR(RNDIS_OID_802_11_RSSI);
- OID_STR(RNDIS_OID_802_11_RSSI_TRIGGER);
- OID_STR(RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD);
- OID_STR(RNDIS_OID_802_11_RTS_THRESHOLD);
- OID_STR(RNDIS_OID_802_11_SUPPORTED_RATES);
- OID_STR(RNDIS_OID_802_11_CONFIGURATION);
- OID_STR(RNDIS_OID_802_11_POWER_MODE);
- OID_STR(RNDIS_OID_802_11_BSSID_LIST);
-#undef OID_STR
- }
-
- return "?";
-}
-#else
-static const char *oid_to_string(u32 oid)
-{
- return "?";
-}
-#endif
-
-/* translate error code */
-static int rndis_error_status(__le32 rndis_status)
-{
- int ret = -EINVAL;
- switch (le32_to_cpu(rndis_status)) {
- case RNDIS_STATUS_SUCCESS:
- ret = 0;
- break;
- case RNDIS_STATUS_FAILURE:
- case RNDIS_STATUS_INVALID_DATA:
- ret = -EINVAL;
- break;
- case RNDIS_STATUS_NOT_SUPPORTED:
- ret = -EOPNOTSUPP;
- break;
- case RNDIS_STATUS_ADAPTER_NOT_READY:
- case RNDIS_STATUS_ADAPTER_NOT_OPEN:
- ret = -EBUSY;
- break;
- }
- return ret;
-}
-
-static int rndis_query_oid(struct usbnet *dev, u32 oid, void *data, int *len)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
- union {
- void *buf;
- struct rndis_msg_hdr *header;
- struct rndis_query *get;
- struct rndis_query_c *get_c;
- } u;
- int ret;
- size_t buflen, resplen, respoffs, copylen;
-
- buflen = *len + sizeof(*u.get);
- if (buflen < CONTROL_BUFFER_SIZE)
- buflen = CONTROL_BUFFER_SIZE;
-
- if (buflen > COMMAND_BUFFER_SIZE) {
- u.buf = kmalloc(buflen, GFP_KERNEL);
- if (!u.buf)
- return -ENOMEM;
- } else {
- u.buf = priv->command_buffer;
- }
-
- mutex_lock(&priv->command_lock);
-
- memset(u.get, 0, sizeof *u.get);
- u.get->msg_type = cpu_to_le32(RNDIS_MSG_QUERY);
- u.get->msg_len = cpu_to_le32(sizeof *u.get);
- u.get->oid = cpu_to_le32(oid);
-
- priv->current_command_oid = oid;
- ret = rndis_command(dev, u.header, buflen);
- priv->current_command_oid = 0;
- if (ret < 0)
- netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n",
- __func__, oid_to_string(oid), ret,
- le32_to_cpu(u.get_c->status));
-
- if (ret == 0) {
- resplen = le32_to_cpu(u.get_c->len);
- respoffs = le32_to_cpu(u.get_c->offset) + 8;
-
- if (respoffs > buflen) {
- /* Device returned data offset outside buffer, error. */
- netdev_dbg(dev->net,
- "%s(%s): received invalid data offset: %zu > %zu\n",
- __func__, oid_to_string(oid), respoffs, buflen);
-
- ret = -EINVAL;
- goto exit_unlock;
- }
-
- copylen = min(resplen, buflen - respoffs);
-
- if (copylen > *len)
- copylen = *len;
-
- memcpy(data, u.buf + respoffs, copylen);
-
- *len = resplen;
-
- ret = rndis_error_status(u.get_c->status);
- if (ret < 0)
- netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n",
- __func__, oid_to_string(oid),
- le32_to_cpu(u.get_c->status), ret);
- }
-
-exit_unlock:
- mutex_unlock(&priv->command_lock);
-
- if (u.buf != priv->command_buffer)
- kfree(u.buf);
- return ret;
-}
-
-static int rndis_set_oid(struct usbnet *dev, u32 oid, const void *data,
- int len)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev);
- union {
- void *buf;
- struct rndis_msg_hdr *header;
- struct rndis_set *set;
- struct rndis_set_c *set_c;
- } u;
- int ret, buflen;
-
- buflen = len + sizeof(*u.set);
- if (buflen < CONTROL_BUFFER_SIZE)
- buflen = CONTROL_BUFFER_SIZE;
-
- if (buflen > COMMAND_BUFFER_SIZE) {
- u.buf = kmalloc(buflen, GFP_KERNEL);
- if (!u.buf)
- return -ENOMEM;
- } else {
- u.buf = priv->command_buffer;
- }
-
- mutex_lock(&priv->command_lock);
-
- memset(u.set, 0, sizeof *u.set);
- u.set->msg_type = cpu_to_le32(RNDIS_MSG_SET);
- u.set->msg_len = cpu_to_le32(sizeof(*u.set) + len);
- u.set->oid = cpu_to_le32(oid);
- u.set->len = cpu_to_le32(len);
- u.set->offset = cpu_to_le32(sizeof(*u.set) - 8);
- u.set->handle = cpu_to_le32(0);
- memcpy(u.buf + sizeof(*u.set), data, len);
-
- priv->current_command_oid = oid;
- ret = rndis_command(dev, u.header, buflen);
- priv->current_command_oid = 0;
- if (ret < 0)
- netdev_dbg(dev->net, "%s(%s): rndis_command() failed, %d (%08x)\n",
- __func__, oid_to_string(oid), ret,
- le32_to_cpu(u.set_c->status));
-
- if (ret == 0) {
- ret = rndis_error_status(u.set_c->status);
-
- if (ret < 0)
- netdev_dbg(dev->net, "%s(%s): device returned error, 0x%08x (%d)\n",
- __func__, oid_to_string(oid),
- le32_to_cpu(u.set_c->status), ret);
- }
-
- mutex_unlock(&priv->command_lock);
-
- if (u.buf != priv->command_buffer)
- kfree(u.buf);
- return ret;
-}
-
-static int rndis_reset(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct rndis_reset *reset;
- int ret;
-
- mutex_lock(&priv->command_lock);
-
- reset = (void *)priv->command_buffer;
- memset(reset, 0, sizeof(*reset));
- reset->msg_type = cpu_to_le32(RNDIS_MSG_RESET);
- reset->msg_len = cpu_to_le32(sizeof(*reset));
- priv->current_command_oid = 0;
- ret = rndis_command(usbdev, (void *)reset, CONTROL_BUFFER_SIZE);
-
- mutex_unlock(&priv->command_lock);
-
- if (ret < 0)
- return ret;
- return 0;
-}
-
-/*
- * Specs say that we can only set config parameters only soon after device
- * initialization.
- * value_type: 0 = u32, 2 = unicode string
- */
-static int rndis_set_config_parameter(struct usbnet *dev, char *param,
- int value_type, void *value)
-{
- struct ndis_config_param *infobuf;
- int value_len, info_len, param_len, ret, i;
- __le16 *unibuf;
- __le32 *dst_value;
-
- if (value_type == 0)
- value_len = sizeof(__le32);
- else if (value_type == 2)
- value_len = strlen(value) * sizeof(__le16);
- else
- return -EINVAL;
-
- param_len = strlen(param) * sizeof(__le16);
- info_len = sizeof(*infobuf) + param_len + value_len;
-
-#ifdef DEBUG
- info_len += 12;
-#endif
- infobuf = kmalloc(info_len, GFP_KERNEL);
- if (!infobuf)
- return -ENOMEM;
-
-#ifdef DEBUG
- info_len -= 12;
- /* extra 12 bytes are for padding (debug output) */
- memset(infobuf, 0xCC, info_len + 12);
-#endif
-
- if (value_type == 2)
- netdev_dbg(dev->net, "setting config parameter: %s, value: %s\n",
- param, (u8 *)value);
- else
- netdev_dbg(dev->net, "setting config parameter: %s, value: %d\n",
- param, *(u32 *)value);
-
- infobuf->name_offs = cpu_to_le32(sizeof(*infobuf));
- infobuf->name_length = cpu_to_le32(param_len);
- infobuf->type = cpu_to_le32(value_type);
- infobuf->value_offs = cpu_to_le32(sizeof(*infobuf) + param_len);
- infobuf->value_length = cpu_to_le32(value_len);
-
- /* simple string to unicode string conversion */
- unibuf = (void *)infobuf + sizeof(*infobuf);
- for (i = 0; i < param_len / sizeof(__le16); i++)
- unibuf[i] = cpu_to_le16(param[i]);
-
- if (value_type == 2) {
- unibuf = (void *)infobuf + sizeof(*infobuf) + param_len;
- for (i = 0; i < value_len / sizeof(__le16); i++)
- unibuf[i] = cpu_to_le16(((u8 *)value)[i]);
- } else {
- dst_value = (void *)infobuf + sizeof(*infobuf) + param_len;
- *dst_value = cpu_to_le32(*(u32 *)value);
- }
-
-#ifdef DEBUG
- netdev_dbg(dev->net, "info buffer (len: %d)\n", info_len);
- for (i = 0; i < info_len; i += 12) {
- u32 *tmp = (u32 *)((u8 *)infobuf + i);
- netdev_dbg(dev->net, "%08X:%08X:%08X\n",
- cpu_to_be32(tmp[0]),
- cpu_to_be32(tmp[1]),
- cpu_to_be32(tmp[2]));
- }
-#endif
-
- ret = rndis_set_oid(dev, RNDIS_OID_GEN_RNDIS_CONFIG_PARAMETER,
- infobuf, info_len);
- if (ret != 0)
- netdev_dbg(dev->net, "setting rndis config parameter failed, %d\n",
- ret);
-
- kfree(infobuf);
- return ret;
-}
-
-static int rndis_set_config_parameter_str(struct usbnet *dev,
- char *param, char *value)
-{
- return rndis_set_config_parameter(dev, param, 2, value);
-}
-
-/*
- * data conversion functions
- */
-static int level_to_qual(int level)
-{
- int qual = 100 * (level - WL_NOISE) / (WL_SIGMAX - WL_NOISE);
- return qual >= 0 ? (qual <= 100 ? qual : 100) : 0;
-}
-
-/*
- * common functions
- */
-static int set_infra_mode(struct usbnet *usbdev, int mode);
-static void restore_keys(struct usbnet *usbdev);
-static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
- bool *matched);
-
-static int rndis_start_bssid_list_scan(struct usbnet *usbdev)
-{
- __le32 tmp;
-
- /* Note: RNDIS_OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */
- tmp = cpu_to_le32(1);
- return rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST_SCAN, &tmp,
- sizeof(tmp));
-}
-
-static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int ret;
-
- ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_SSID,
- ssid, sizeof(*ssid));
- if (ret < 0) {
- netdev_warn(usbdev->net, "setting SSID failed (%08X)\n", ret);
- return ret;
- }
- if (ret == 0) {
- priv->radio_on = true;
- netdev_dbg(usbdev->net, "%s(): radio_on = true\n", __func__);
- }
-
- return ret;
-}
-
-static int set_bssid(struct usbnet *usbdev, const u8 *bssid)
-{
- int ret;
-
- ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_BSSID,
- bssid, ETH_ALEN);
- if (ret < 0) {
- netdev_warn(usbdev->net, "setting BSSID[%pM] failed (%08X)\n",
- bssid, ret);
- return ret;
- }
-
- return ret;
-}
-
-static int clear_bssid(struct usbnet *usbdev)
-{
- static const u8 broadcast_mac[ETH_ALEN] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
-
- return set_bssid(usbdev, broadcast_mac);
-}
-
-static int get_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN])
-{
- int ret, len;
-
- len = ETH_ALEN;
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID,
- bssid, &len);
-
- if (ret != 0)
- eth_zero_addr(bssid);
-
- return ret;
-}
-
-static int get_association_info(struct usbnet *usbdev,
- struct ndis_80211_assoc_info *info, int len)
-{
- return rndis_query_oid(usbdev,
- RNDIS_OID_802_11_ASSOCIATION_INFORMATION,
- info, &len);
-}
-
-static bool is_associated(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- u8 bssid[ETH_ALEN];
-
- if (!priv->radio_on)
- return false;
-
- return (get_bssid(usbdev, bssid) == 0 && !is_zero_ether_addr(bssid));
-}
-
-static int disassociate(struct usbnet *usbdev, bool reset_ssid)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_ssid ssid;
- int i, ret = 0;
-
- if (priv->radio_on) {
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_DISASSOCIATE,
- NULL, 0);
- if (ret == 0) {
- priv->radio_on = false;
- netdev_dbg(usbdev->net, "%s(): radio_on = false\n",
- __func__);
-
- if (reset_ssid)
- msleep(100);
- }
- }
-
- /* disassociate causes radio to be turned off; if reset_ssid
- * is given, set random ssid to enable radio */
- if (reset_ssid) {
- /* Set device to infrastructure mode so we don't get ad-hoc
- * 'media connect' indications with the random ssid.
- */
- set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
-
- ssid.length = cpu_to_le32(sizeof(ssid.essid));
- get_random_bytes(&ssid.essid[2], sizeof(ssid.essid)-2);
- ssid.essid[0] = 0x1;
- ssid.essid[1] = 0xff;
- for (i = 2; i < sizeof(ssid.essid); i++)
- ssid.essid[i] = 0x1 + (ssid.essid[i] * 0xfe / 0xff);
- ret = set_essid(usbdev, &ssid);
- }
- return ret;
-}
-
-static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
- enum nl80211_auth_type auth_type, int keymgmt)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tmp;
- int auth_mode, ret;
-
- netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x authalg=0x%x keymgmt=0x%x\n",
- __func__, wpa_version, auth_type, keymgmt);
-
- if (wpa_version & NL80211_WPA_VERSION_2) {
- if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
- auth_mode = NDIS_80211_AUTH_WPA2;
- else
- auth_mode = NDIS_80211_AUTH_WPA2_PSK;
- } else if (wpa_version & NL80211_WPA_VERSION_1) {
- if (keymgmt & RNDIS_WLAN_KEY_MGMT_802_1X)
- auth_mode = NDIS_80211_AUTH_WPA;
- else if (keymgmt & RNDIS_WLAN_KEY_MGMT_PSK)
- auth_mode = NDIS_80211_AUTH_WPA_PSK;
- else
- auth_mode = NDIS_80211_AUTH_WPA_NONE;
- } else if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
- auth_mode = NDIS_80211_AUTH_SHARED;
- else if (auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
- auth_mode = NDIS_80211_AUTH_OPEN;
- else if (auth_type == NL80211_AUTHTYPE_AUTOMATIC)
- auth_mode = NDIS_80211_AUTH_AUTO_SWITCH;
- else
- return -ENOTSUPP;
-
- tmp = cpu_to_le32(auth_mode);
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_AUTHENTICATION_MODE,
- &tmp, sizeof(tmp));
- if (ret != 0) {
- netdev_warn(usbdev->net, "setting auth mode failed (%08X)\n",
- ret);
- return ret;
- }
-
- priv->wpa_version = wpa_version;
-
- return 0;
-}
-
-static int set_priv_filter(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tmp;
-
- netdev_dbg(usbdev->net, "%s(): wpa_version=0x%x\n",
- __func__, priv->wpa_version);
-
- if (priv->wpa_version & NL80211_WPA_VERSION_2 ||
- priv->wpa_version & NL80211_WPA_VERSION_1)
- tmp = cpu_to_le32(NDIS_80211_PRIV_8021X_WEP);
- else
- tmp = cpu_to_le32(NDIS_80211_PRIV_ACCEPT_ALL);
-
- return rndis_set_oid(usbdev,
- RNDIS_OID_802_11_PRIVACY_FILTER, &tmp,
- sizeof(tmp));
-}
-
-static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
-{
- __le32 tmp;
- int encr_mode, ret;
-
- netdev_dbg(usbdev->net, "%s(): cipher_pair=0x%x cipher_group=0x%x\n",
- __func__, pairwise, groupwise);
-
- if (pairwise & RNDIS_WLAN_ALG_CCMP)
- encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
- else if (pairwise & RNDIS_WLAN_ALG_TKIP)
- encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
- else if (pairwise & RNDIS_WLAN_ALG_WEP)
- encr_mode = NDIS_80211_ENCR_WEP_ENABLED;
- else if (groupwise & RNDIS_WLAN_ALG_CCMP)
- encr_mode = NDIS_80211_ENCR_CCMP_ENABLED;
- else if (groupwise & RNDIS_WLAN_ALG_TKIP)
- encr_mode = NDIS_80211_ENCR_TKIP_ENABLED;
- else
- encr_mode = NDIS_80211_ENCR_DISABLED;
-
- tmp = cpu_to_le32(encr_mode);
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_ENCRYPTION_STATUS, &tmp,
- sizeof(tmp));
- if (ret != 0) {
- netdev_warn(usbdev->net, "setting encr mode failed (%08X)\n",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-static int set_infra_mode(struct usbnet *usbdev, int mode)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tmp;
- int ret;
-
- netdev_dbg(usbdev->net, "%s(): infra_mode=0x%x\n",
- __func__, priv->infra_mode);
-
- tmp = cpu_to_le32(mode);
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_INFRASTRUCTURE_MODE,
- &tmp, sizeof(tmp));
- if (ret != 0) {
- netdev_warn(usbdev->net, "setting infra mode failed (%08X)\n",
- ret);
- return ret;
- }
-
- /* NDIS drivers clear keys when infrastructure mode is
- * changed. But Linux tools assume otherwise. So set the
- * keys */
- restore_keys(usbdev);
-
- priv->infra_mode = mode;
- return 0;
-}
-
-static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
-{
- __le32 tmp;
-
- netdev_dbg(usbdev->net, "%s(): %i\n", __func__, rts_threshold);
-
- if (rts_threshold == -1 || rts_threshold > 2347)
- rts_threshold = 2347;
-
- tmp = cpu_to_le32(rts_threshold);
- return rndis_set_oid(usbdev,
- RNDIS_OID_802_11_RTS_THRESHOLD,
- &tmp, sizeof(tmp));
-}
-
-static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
-{
- __le32 tmp;
-
- netdev_dbg(usbdev->net, "%s(): %i\n", __func__, frag_threshold);
-
- if (frag_threshold < 256 || frag_threshold > 2346)
- frag_threshold = 2346;
-
- tmp = cpu_to_le32(frag_threshold);
- return rndis_set_oid(usbdev,
- RNDIS_OID_802_11_FRAGMENTATION_THRESHOLD,
- &tmp, sizeof(tmp));
-}
-
-static void set_default_iw_params(struct usbnet *usbdev)
-{
- set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
- set_auth_mode(usbdev, 0, NL80211_AUTHTYPE_OPEN_SYSTEM,
- RNDIS_WLAN_KEY_MGMT_NONE);
- set_priv_filter(usbdev);
- set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE);
-}
-
-static int deauthenticate(struct usbnet *usbdev)
-{
- int ret;
-
- ret = disassociate(usbdev, true);
- set_default_iw_params(usbdev);
- return ret;
-}
-
-static int set_channel(struct usbnet *usbdev, int channel)
-{
- struct ndis_80211_conf config;
- unsigned int dsconfig;
- int len, ret;
-
- netdev_dbg(usbdev->net, "%s(%d)\n", __func__, channel);
-
- /* this OID is valid only when not associated */
- if (is_associated(usbdev))
- return 0;
-
- dsconfig = 1000 *
- ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
-
- len = sizeof(config);
- ret = rndis_query_oid(usbdev,
- RNDIS_OID_802_11_CONFIGURATION,
- &config, &len);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "%s(): querying configuration failed\n",
- __func__);
- return ret;
- }
-
- config.ds_config = cpu_to_le32(dsconfig);
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_CONFIGURATION,
- &config, sizeof(config));
-
- netdev_dbg(usbdev->net, "%s(): %d -> %d\n", __func__, channel, ret);
-
- return ret;
-}
-
-static struct ieee80211_channel *get_current_channel(struct usbnet *usbdev,
- u32 *beacon_period)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ieee80211_channel *channel;
- struct ndis_80211_conf config;
- int len, ret;
-
- /* Get channel and beacon interval */
- len = sizeof(config);
- ret = rndis_query_oid(usbdev,
- RNDIS_OID_802_11_CONFIGURATION,
- &config, &len);
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_CONFIGURATION -> %d\n",
- __func__, ret);
- if (ret < 0)
- return NULL;
-
- channel = ieee80211_get_channel(priv->wdev.wiphy,
- KHZ_TO_MHZ(le32_to_cpu(config.ds_config)));
- if (!channel)
- return NULL;
-
- if (beacon_period)
- *beacon_period = le32_to_cpu(config.beacon_period);
- return channel;
-}
-
-/* index must be 0 - N, as per NDIS */
-static int add_wep_key(struct usbnet *usbdev, const u8 *key, int key_len,
- u8 index)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_wep_key ndis_key;
- u32 cipher;
- int ret;
-
- netdev_dbg(usbdev->net, "%s(idx: %d, len: %d)\n",
- __func__, index, key_len);
-
- if (index >= RNDIS_WLAN_NUM_KEYS)
- return -EINVAL;
-
- if (key_len == 5)
- cipher = WLAN_CIPHER_SUITE_WEP40;
- else if (key_len == 13)
- cipher = WLAN_CIPHER_SUITE_WEP104;
- else
- return -EINVAL;
-
- memset(&ndis_key, 0, sizeof(ndis_key));
-
- ndis_key.size = cpu_to_le32(sizeof(ndis_key));
- ndis_key.length = cpu_to_le32(key_len);
- ndis_key.index = cpu_to_le32(index);
- memcpy(&ndis_key.material, key, key_len);
-
- if (index == priv->encr_tx_key_index) {
- ndis_key.index |= NDIS_80211_ADDWEP_TRANSMIT_KEY;
- ret = set_encr_mode(usbdev, RNDIS_WLAN_ALG_WEP,
- RNDIS_WLAN_ALG_NONE);
- if (ret)
- netdev_warn(usbdev->net, "encryption couldn't be enabled (%08X)\n",
- ret);
- }
-
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_ADD_WEP, &ndis_key,
- sizeof(ndis_key));
- if (ret != 0) {
- netdev_warn(usbdev->net, "adding encryption key %d failed (%08X)\n",
- index + 1, ret);
- return ret;
- }
-
- priv->encr_keys[index].len = key_len;
- priv->encr_keys[index].cipher = cipher;
- memcpy(&priv->encr_keys[index].material, key, key_len);
- eth_broadcast_addr(priv->encr_keys[index].bssid);
-
- return 0;
-}
-
-static int add_wpa_key(struct usbnet *usbdev, const u8 *key, int key_len,
- u8 index, const u8 *addr, const u8 *rx_seq,
- int seq_len, u32 cipher, __le32 flags)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_key ndis_key;
- bool is_addr_ok;
- int ret;
-
- if (index >= RNDIS_WLAN_NUM_KEYS) {
- netdev_dbg(usbdev->net, "%s(): index out of range (%i)\n",
- __func__, index);
- return -EINVAL;
- }
- if (key_len > sizeof(ndis_key.material) || key_len < 0) {
- netdev_dbg(usbdev->net, "%s(): key length out of range (%i)\n",
- __func__, key_len);
- return -EINVAL;
- }
- if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ) {
- if (!rx_seq || seq_len <= 0) {
- netdev_dbg(usbdev->net, "%s(): recv seq flag without buffer\n",
- __func__);
- return -EINVAL;
- }
- if (rx_seq && seq_len > sizeof(ndis_key.rsc)) {
- netdev_dbg(usbdev->net, "%s(): too big recv seq buffer\n", __func__);
- return -EINVAL;
- }
- }
-
- is_addr_ok = addr && !is_zero_ether_addr(addr) &&
- !is_broadcast_ether_addr(addr);
- if ((flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) && !is_addr_ok) {
- netdev_dbg(usbdev->net, "%s(): pairwise but bssid invalid (%pM)\n",
- __func__, addr);
- return -EINVAL;
- }
-
- netdev_dbg(usbdev->net, "%s(%i): flags:%i%i%i\n",
- __func__, index,
- !!(flags & NDIS_80211_ADDKEY_TRANSMIT_KEY),
- !!(flags & NDIS_80211_ADDKEY_PAIRWISE_KEY),
- !!(flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ));
-
- memset(&ndis_key, 0, sizeof(ndis_key));
-
- ndis_key.size = cpu_to_le32(sizeof(ndis_key) -
- sizeof(ndis_key.material) + key_len);
- ndis_key.length = cpu_to_le32(key_len);
- ndis_key.index = cpu_to_le32(index) | flags;
-
- if (cipher == WLAN_CIPHER_SUITE_TKIP && key_len == 32) {
- /* wpa_supplicant gives us the Michael MIC RX/TX keys in
- * different order than NDIS spec, so swap the order here. */
- memcpy(ndis_key.material, key, 16);
- memcpy(ndis_key.material + 16, key + 24, 8);
- memcpy(ndis_key.material + 24, key + 16, 8);
- } else
- memcpy(ndis_key.material, key, key_len);
-
- if (flags & NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ)
- memcpy(ndis_key.rsc, rx_seq, seq_len);
-
- if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY) {
- /* pairwise key */
- memcpy(ndis_key.bssid, addr, ETH_ALEN);
- } else {
- /* group key */
- if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
- eth_broadcast_addr(ndis_key.bssid);
- else
- get_bssid(usbdev, ndis_key.bssid);
- }
-
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_ADD_KEY, &ndis_key,
- le32_to_cpu(ndis_key.size));
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_ADD_KEY -> %08X\n",
- __func__, ret);
- if (ret != 0)
- return ret;
-
- memset(&priv->encr_keys[index], 0, sizeof(priv->encr_keys[index]));
- priv->encr_keys[index].len = key_len;
- priv->encr_keys[index].cipher = cipher;
- memcpy(&priv->encr_keys[index].material, key, key_len);
- if (flags & NDIS_80211_ADDKEY_PAIRWISE_KEY)
- memcpy(&priv->encr_keys[index].bssid, ndis_key.bssid, ETH_ALEN);
- else
- eth_broadcast_addr(priv->encr_keys[index].bssid);
-
- if (flags & NDIS_80211_ADDKEY_TRANSMIT_KEY)
- priv->encr_tx_key_index = index;
-
- return 0;
-}
-
-static int restore_key(struct usbnet *usbdev, u8 key_idx)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct rndis_wlan_encr_key key;
-
- if (is_wpa_key(priv, key_idx))
- return 0;
-
- key = priv->encr_keys[key_idx];
-
- netdev_dbg(usbdev->net, "%s(): %i:%i\n", __func__, key_idx, key.len);
-
- if (key.len == 0)
- return 0;
-
- return add_wep_key(usbdev, key.material, key.len, key_idx);
-}
-
-static void restore_keys(struct usbnet *usbdev)
-{
- int i;
-
- for (i = 0; i < 4; i++)
- restore_key(usbdev, i);
-}
-
-static void clear_key(struct rndis_wlan_private *priv, u8 idx)
-{
- memset(&priv->encr_keys[idx], 0, sizeof(priv->encr_keys[idx]));
-}
-
-/* remove_key is for both wep and wpa */
-static int remove_key(struct usbnet *usbdev, u8 index, const u8 *bssid)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_remove_key remove_key;
- __le32 keyindex;
- bool is_wpa;
- int ret;
-
- if (index >= RNDIS_WLAN_NUM_KEYS)
- return -ENOENT;
-
- if (priv->encr_keys[index].len == 0)
- return 0;
-
- is_wpa = is_wpa_key(priv, index);
-
- netdev_dbg(usbdev->net, "%s(): %i:%s:%i\n",
- __func__, index, is_wpa ? "wpa" : "wep",
- priv->encr_keys[index].len);
-
- clear_key(priv, index);
-
- if (is_wpa) {
- remove_key.size = cpu_to_le32(sizeof(remove_key));
- remove_key.index = cpu_to_le32(index);
- if (bssid) {
- /* pairwise key */
- if (!is_broadcast_ether_addr(bssid))
- remove_key.index |=
- NDIS_80211_ADDKEY_PAIRWISE_KEY;
- memcpy(remove_key.bssid, bssid,
- sizeof(remove_key.bssid));
- } else
- memset(remove_key.bssid, 0xff,
- sizeof(remove_key.bssid));
-
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_REMOVE_KEY,
- &remove_key, sizeof(remove_key));
- if (ret != 0)
- return ret;
- } else {
- keyindex = cpu_to_le32(index);
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_11_REMOVE_WEP,
- &keyindex, sizeof(keyindex));
- if (ret != 0) {
- netdev_warn(usbdev->net,
- "removing encryption key %d failed (%08X)\n",
- index, ret);
- return ret;
- }
- }
-
- /* if it is transmit key, disable encryption */
- if (index == priv->encr_tx_key_index)
- set_encr_mode(usbdev, RNDIS_WLAN_ALG_NONE, RNDIS_WLAN_ALG_NONE);
-
- return 0;
-}
-
-static void set_multicast_list(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct netdev_hw_addr *ha;
- __le32 filter, basefilter;
- int ret;
- char *mc_addrs = NULL;
- int mc_count;
-
- basefilter = filter = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED |
- RNDIS_PACKET_TYPE_BROADCAST);
-
- if (usbdev->net->flags & IFF_PROMISC) {
- filter |= cpu_to_le32(RNDIS_PACKET_TYPE_PROMISCUOUS |
- RNDIS_PACKET_TYPE_ALL_LOCAL);
- } else if (usbdev->net->flags & IFF_ALLMULTI) {
- filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST);
- }
-
- if (filter != basefilter)
- goto set_filter;
-
- /*
- * mc_list should be accessed holding the lock, so copy addresses to
- * local buffer first.
- */
- netif_addr_lock_bh(usbdev->net);
- mc_count = netdev_mc_count(usbdev->net);
- if (mc_count > priv->multicast_size) {
- filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST);
- } else if (mc_count) {
- int i = 0;
-
- mc_addrs = kmalloc_array(mc_count, ETH_ALEN, GFP_ATOMIC);
- if (!mc_addrs) {
- netif_addr_unlock_bh(usbdev->net);
- return;
- }
-
- netdev_for_each_mc_addr(ha, usbdev->net)
- memcpy(mc_addrs + i++ * ETH_ALEN,
- ha->addr, ETH_ALEN);
- }
- netif_addr_unlock_bh(usbdev->net);
-
- if (filter != basefilter)
- goto set_filter;
-
- if (mc_count) {
- ret = rndis_set_oid(usbdev,
- RNDIS_OID_802_3_MULTICAST_LIST,
- mc_addrs, mc_count * ETH_ALEN);
- kfree(mc_addrs);
- if (ret == 0)
- filter |= cpu_to_le32(RNDIS_PACKET_TYPE_MULTICAST);
- else
- filter |= cpu_to_le32(RNDIS_PACKET_TYPE_ALL_MULTICAST);
-
- netdev_dbg(usbdev->net, "RNDIS_OID_802_3_MULTICAST_LIST(%d, max: %d) -> %d\n",
- mc_count, priv->multicast_size, ret);
- }
-
-set_filter:
- ret = rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter,
- sizeof(filter));
- if (ret < 0) {
- netdev_warn(usbdev->net, "couldn't set packet filter: %08x\n",
- le32_to_cpu(filter));
- }
-
- netdev_dbg(usbdev->net, "RNDIS_OID_GEN_CURRENT_PACKET_FILTER(%08x) -> %d\n",
- le32_to_cpu(filter), ret);
-}
-
-#ifdef DEBUG
-static void debug_print_pmkids(struct usbnet *usbdev,
- struct ndis_80211_pmkid *pmkids,
- const char *func_str)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int i, len, count, max_pmkids, entry_len;
-
- max_pmkids = priv->wdev.wiphy->max_num_pmkids;
- len = le32_to_cpu(pmkids->length);
- count = le32_to_cpu(pmkids->bssid_info_count);
-
- entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1;
-
- netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: "
- "%d)\n", func_str, count, len, entry_len);
-
- if (count > max_pmkids)
- count = max_pmkids;
-
- for (i = 0; i < count; i++) {
- u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid;
-
- netdev_dbg(usbdev->net, "%s(): bssid: %pM, "
- "pmkid: %08X:%08X:%08X:%08X\n",
- func_str, pmkids->bssid_info[i].bssid,
- cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
- cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
- }
-}
-#else
-static void debug_print_pmkids(struct usbnet *usbdev,
- struct ndis_80211_pmkid *pmkids,
- const char *func_str)
-{
- return;
-}
-#endif
-
-static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_pmkid *pmkids;
- int len, ret, max_pmkids;
-
- max_pmkids = priv->wdev.wiphy->max_num_pmkids;
- len = struct_size(pmkids, bssid_info, max_pmkids);
-
- pmkids = kzalloc(len, GFP_KERNEL);
- if (!pmkids)
- return ERR_PTR(-ENOMEM);
-
- pmkids->length = cpu_to_le32(len);
- pmkids->bssid_info_count = cpu_to_le32(max_pmkids);
-
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_PMKID,
- pmkids, &len);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d)"
- " -> %d\n", __func__, len, max_pmkids, ret);
-
- kfree(pmkids);
- return ERR_PTR(ret);
- }
-
- if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids)
- pmkids->bssid_info_count = cpu_to_le32(max_pmkids);
-
- debug_print_pmkids(usbdev, pmkids, __func__);
-
- return pmkids;
-}
-
-static int set_device_pmkids(struct usbnet *usbdev,
- struct ndis_80211_pmkid *pmkids)
-{
- int ret, len, num_pmkids;
-
- num_pmkids = le32_to_cpu(pmkids->bssid_info_count);
- len = struct_size(pmkids, bssid_info, num_pmkids);
- pmkids->length = cpu_to_le32(len);
-
- debug_print_pmkids(usbdev, pmkids, __func__);
-
- ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID, pmkids,
- le32_to_cpu(pmkids->length));
- if (ret < 0) {
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_PMKID(%d, %d) -> %d"
- "\n", __func__, len, num_pmkids, ret);
- }
-
- kfree(pmkids);
- return ret;
-}
-
-static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev,
- struct ndis_80211_pmkid *pmkids,
- struct cfg80211_pmksa *pmksa,
- int max_pmkids)
-{
- int i, err;
- unsigned int count;
-
- count = le32_to_cpu(pmkids->bssid_info_count);
-
- if (count > max_pmkids)
- count = max_pmkids;
-
- for (i = 0; i < count; i++)
- if (ether_addr_equal(pmkids->bssid_info[i].bssid,
- pmksa->bssid))
- break;
-
- /* pmkid not found */
- if (i == count) {
- netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n",
- __func__, pmksa->bssid);
- err = -ENOENT;
- goto error;
- }
-
- for (; i + 1 < count; i++)
- pmkids->bssid_info[i] = pmkids->bssid_info[i + 1];
-
- count--;
- pmkids->length = cpu_to_le32(struct_size(pmkids, bssid_info, count));
- pmkids->bssid_info_count = cpu_to_le32(count);
-
- return pmkids;
-error:
- kfree(pmkids);
- return ERR_PTR(err);
-}
-
-static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
- struct ndis_80211_pmkid *pmkids,
- struct cfg80211_pmksa *pmksa,
- int max_pmkids)
-{
- struct ndis_80211_pmkid *new_pmkids;
- int i, err, newlen;
- unsigned int count;
-
- count = le32_to_cpu(pmkids->bssid_info_count);
-
- if (count > max_pmkids)
- count = max_pmkids;
-
- /* update with new pmkid */
- for (i = 0; i < count; i++) {
- if (!ether_addr_equal(pmkids->bssid_info[i].bssid,
- pmksa->bssid))
- continue;
-
- memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid,
- WLAN_PMKID_LEN);
-
- return pmkids;
- }
-
- /* out of space, return error */
- if (i == max_pmkids) {
- netdev_dbg(usbdev->net, "%s(): out of space\n", __func__);
- err = -ENOSPC;
- goto error;
- }
-
- /* add new pmkid */
- newlen = struct_size(pmkids, bssid_info, count + 1);
-
- new_pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
- if (!new_pmkids) {
- err = -ENOMEM;
- goto error;
- }
- pmkids = new_pmkids;
-
- pmkids->length = cpu_to_le32(newlen);
- pmkids->bssid_info_count = cpu_to_le32(count + 1);
-
- memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN);
- memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
-
- return pmkids;
-error:
- kfree(pmkids);
- return ERR_PTR(err);
-}
-
-/*
- * cfg80211 ops
- */
-static int rndis_change_virtual_intf(struct wiphy *wiphy,
- struct net_device *dev,
- enum nl80211_iftype type,
- struct vif_params *params)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- int mode;
-
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
- mode = NDIS_80211_INFRA_ADHOC;
- break;
- case NL80211_IFTYPE_STATION:
- mode = NDIS_80211_INFRA_INFRA;
- break;
- default:
- return -EINVAL;
- }
-
- priv->wdev.iftype = type;
-
- return set_infra_mode(usbdev, mode);
-}
-
-static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- int err;
-
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
- err = set_frag_threshold(usbdev, wiphy->frag_threshold);
- if (err < 0)
- return err;
- }
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- err = set_rts_threshold(usbdev, wiphy->rts_threshold);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static int rndis_set_tx_power(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- enum nl80211_tx_power_setting type,
- int mbm)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- netdev_dbg(usbdev->net, "%s(): type:0x%x mbm:%i\n",
- __func__, type, mbm);
-
- if (mbm < 0 || (mbm % 100))
- return -ENOTSUPP;
-
- /* Device doesn't support changing txpower after initialization, only
- * turn off/on radio. Support 'auto' mode and setting same dBm that is
- * currently used.
- */
- if (type == NL80211_TX_POWER_AUTOMATIC ||
- MBM_TO_DBM(mbm) == get_bcm4320_power_dbm(priv)) {
- if (!priv->radio_on)
- disassociate(usbdev, true); /* turn on radio */
-
- return 0;
- }
-
- return -ENOTSUPP;
-}
-
-static int rndis_get_tx_power(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- int *dbm)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- *dbm = get_bcm4320_power_dbm(priv);
-
- netdev_dbg(usbdev->net, "%s(): dbm:%i\n", __func__, *dbm);
-
- return 0;
-}
-
-#define SCAN_DELAY_JIFFIES (6 * HZ)
-static int rndis_scan(struct wiphy *wiphy,
- struct cfg80211_scan_request *request)
-{
- struct net_device *dev = request->wdev->netdev;
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int ret;
- int delay = SCAN_DELAY_JIFFIES;
-
- netdev_dbg(usbdev->net, "cfg80211.scan\n");
-
- /* Get current bssid list from device before new scan, as new scan
- * clears internal bssid list.
- */
- rndis_check_bssid_list(usbdev, NULL, NULL);
-
- if (priv->scan_request && priv->scan_request != request)
- return -EBUSY;
-
- priv->scan_request = request;
-
- ret = rndis_start_bssid_list_scan(usbdev);
- if (ret == 0) {
- if (priv->device_type == RNDIS_BCM4320A)
- delay = HZ;
-
- /* Wait before retrieving scan results from device */
- queue_delayed_work(priv->workqueue, &priv->scan_work, delay);
- }
-
- return ret;
-}
-
-static bool rndis_bss_info_update(struct usbnet *usbdev,
- struct ndis_80211_bssid_ex *bssid)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ieee80211_channel *channel;
- struct cfg80211_bss *bss;
- s32 signal;
- u64 timestamp;
- u16 capability;
- u16 beacon_interval;
- struct ndis_80211_fixed_ies *fixed;
- int ie_len, bssid_len;
- u8 *ie;
-
- netdev_dbg(usbdev->net, " found bssid: '%.32s' [%pM], len: %d\n",
- bssid->ssid.essid, bssid->mac, le32_to_cpu(bssid->length));
-
- /* parse bssid structure */
- bssid_len = le32_to_cpu(bssid->length);
-
- if (bssid_len < sizeof(struct ndis_80211_bssid_ex) +
- sizeof(struct ndis_80211_fixed_ies))
- return false;
-
- fixed = (struct ndis_80211_fixed_ies *)bssid->ies;
-
- ie = (void *)(bssid->ies + sizeof(struct ndis_80211_fixed_ies));
- ie_len = min(bssid_len - (int)sizeof(*bssid),
- (int)le32_to_cpu(bssid->ie_length));
- ie_len -= sizeof(struct ndis_80211_fixed_ies);
- if (ie_len < 0)
- return false;
-
- /* extract data for cfg80211_inform_bss */
- channel = ieee80211_get_channel(priv->wdev.wiphy,
- KHZ_TO_MHZ(le32_to_cpu(bssid->config.ds_config)));
- if (!channel)
- return false;
-
- signal = level_to_qual(le32_to_cpu(bssid->rssi));
- timestamp = le64_to_cpu(*(__le64 *)fixed->timestamp);
- capability = le16_to_cpu(fixed->capabilities);
- beacon_interval = le16_to_cpu(fixed->beacon_interval);
-
- bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
- CFG80211_BSS_FTYPE_UNKNOWN, bssid->mac,
- timestamp, capability, beacon_interval,
- ie, ie_len, signal, GFP_KERNEL);
- cfg80211_put_bss(priv->wdev.wiphy, bss);
-
- return (bss != NULL);
-}
-
-static struct ndis_80211_bssid_ex *next_bssid_list_item(
- struct ndis_80211_bssid_ex *bssid,
- int *bssid_len, void *buf, int len)
-{
- void *buf_end, *bssid_end;
-
- buf_end = (char *)buf + len;
- bssid_end = (char *)bssid + *bssid_len;
-
- if ((int)(buf_end - bssid_end) < sizeof(bssid->length)) {
- *bssid_len = 0;
- return NULL;
- } else {
- bssid = (void *)((char *)bssid + *bssid_len);
- *bssid_len = le32_to_cpu(bssid->length);
- return bssid;
- }
-}
-
-static bool check_bssid_list_item(struct ndis_80211_bssid_ex *bssid,
- int bssid_len, void *buf, int len)
-{
- void *buf_end, *bssid_end;
-
- if (!bssid || bssid_len <= 0 || bssid_len > len)
- return false;
-
- buf_end = (char *)buf + len;
- bssid_end = (char *)bssid + bssid_len;
-
- return (int)(buf_end - bssid_end) >= 0 && (int)(bssid_end - buf) >= 0;
-}
-
-static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid,
- bool *matched)
-{
- void *buf = NULL;
- struct ndis_80211_bssid_list_ex *bssid_list;
- struct ndis_80211_bssid_ex *bssid;
- int ret = -EINVAL, len, count, bssid_len, real_count, new_len;
-
- netdev_dbg(usbdev->net, "%s()\n", __func__);
-
- len = CONTROL_BUFFER_SIZE;
-resize_buf:
- buf = kzalloc(len, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* BSSID-list might have got bigger last time we checked, keep
- * resizing until it won't get any bigger.
- */
- new_len = len;
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_BSSID_LIST,
- buf, &new_len);
- if (ret != 0 || new_len < sizeof(struct ndis_80211_bssid_list_ex))
- goto out;
-
- if (new_len > len) {
- len = new_len;
- kfree(buf);
- goto resize_buf;
- }
-
- len = new_len;
-
- bssid_list = buf;
- count = le32_to_cpu(bssid_list->num_items);
- real_count = 0;
- netdev_dbg(usbdev->net, "%s(): buflen: %d\n", __func__, len);
-
- bssid_len = 0;
- bssid = next_bssid_list_item((void *)bssid_list->bssid_data,
- &bssid_len, buf, len);
-
- /* Device returns incorrect 'num_items'. Workaround by ignoring the
- * received 'num_items' and walking through full bssid buffer instead.
- */
- while (check_bssid_list_item(bssid, bssid_len, buf, len)) {
- if (rndis_bss_info_update(usbdev, bssid) && match_bssid &&
- matched) {
- if (ether_addr_equal(bssid->mac, match_bssid))
- *matched = true;
- }
-
- real_count++;
- bssid = next_bssid_list_item(bssid, &bssid_len, buf, len);
- }
-
- netdev_dbg(usbdev->net, "%s(): num_items from device: %d, really found:"
- " %d\n", __func__, count, real_count);
-
-out:
- kfree(buf);
- return ret;
-}
-
-static void rndis_get_scan_results(struct work_struct *work)
-{
- struct rndis_wlan_private *priv =
- container_of(work, struct rndis_wlan_private, scan_work.work);
- struct usbnet *usbdev = priv->usbdev;
- struct cfg80211_scan_info info = {};
- int ret;
-
- netdev_dbg(usbdev->net, "get_scan_results\n");
-
- if (!priv->scan_request)
- return;
-
- ret = rndis_check_bssid_list(usbdev, NULL, NULL);
-
- info.aborted = ret < 0;
- cfg80211_scan_done(priv->scan_request, &info);
-
- priv->scan_request = NULL;
-}
-
-static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_connect_params *sme)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- struct ieee80211_channel *channel = sme->channel;
- struct ndis_80211_ssid ssid;
- int pairwise = RNDIS_WLAN_ALG_NONE;
- int groupwise = RNDIS_WLAN_ALG_NONE;
- int keymgmt = RNDIS_WLAN_KEY_MGMT_NONE;
- int length, i, ret, chan = -1;
-
- if (channel)
- chan = ieee80211_frequency_to_channel(channel->center_freq);
-
- groupwise = rndis_cipher_to_alg(sme->crypto.cipher_group);
- for (i = 0; i < sme->crypto.n_ciphers_pairwise; i++)
- pairwise |=
- rndis_cipher_to_alg(sme->crypto.ciphers_pairwise[i]);
-
- if (sme->crypto.n_ciphers_pairwise > 0 &&
- pairwise == RNDIS_WLAN_ALG_NONE) {
- netdev_err(usbdev->net, "Unsupported pairwise cipher\n");
- return -ENOTSUPP;
- }
-
- for (i = 0; i < sme->crypto.n_akm_suites; i++)
- keymgmt |=
- rndis_akm_suite_to_key_mgmt(sme->crypto.akm_suites[i]);
-
- if (sme->crypto.n_akm_suites > 0 &&
- keymgmt == RNDIS_WLAN_KEY_MGMT_NONE) {
- netdev_err(usbdev->net, "Invalid keymgmt\n");
- return -ENOTSUPP;
- }
-
- netdev_dbg(usbdev->net, "cfg80211.connect('%.32s':[%pM]:%d:[%d,0x%x:0x%x]:[0x%x:0x%x]:0x%x)\n",
- sme->ssid, sme->bssid, chan,
- sme->privacy, sme->crypto.wpa_versions, sme->auth_type,
- groupwise, pairwise, keymgmt);
-
- if (is_associated(usbdev))
- disassociate(usbdev, false);
-
- ret = set_infra_mode(usbdev, NDIS_80211_INFRA_INFRA);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "connect: set_infra_mode failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
-
- ret = set_auth_mode(usbdev, sme->crypto.wpa_versions, sme->auth_type,
- keymgmt);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "connect: set_auth_mode failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
-
- set_priv_filter(usbdev);
-
- ret = set_encr_mode(usbdev, pairwise, groupwise);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "connect: set_encr_mode failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
-
- if (channel) {
- ret = set_channel(usbdev, chan);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "connect: set_channel failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
- }
-
- if (sme->key && ((groupwise | pairwise) & RNDIS_WLAN_ALG_WEP)) {
- priv->encr_tx_key_index = sme->key_idx;
- ret = add_wep_key(usbdev, sme->key, sme->key_len, sme->key_idx);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "connect: add_wep_key failed, %d (%d, %d)\n",
- ret, sme->key_len, sme->key_idx);
- goto err_turn_radio_on;
- }
- }
-
- if (sme->bssid && !is_zero_ether_addr(sme->bssid) &&
- !is_broadcast_ether_addr(sme->bssid)) {
- ret = set_bssid(usbdev, sme->bssid);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "connect: set_bssid failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
- } else
- clear_bssid(usbdev);
-
- length = sme->ssid_len;
- if (length > NDIS_802_11_LENGTH_SSID)
- length = NDIS_802_11_LENGTH_SSID;
-
- memset(&ssid, 0, sizeof(ssid));
- ssid.length = cpu_to_le32(length);
- memcpy(ssid.essid, sme->ssid, length);
-
- /* Pause and purge rx queue, so we don't pass packets before
- * 'media connect'-indication.
- */
- usbnet_pause_rx(usbdev);
- usbnet_purge_paused_rxq(usbdev);
-
- ret = set_essid(usbdev, &ssid);
- if (ret < 0)
- netdev_dbg(usbdev->net, "connect: set_essid failed, %d\n", ret);
- return ret;
-
-err_turn_radio_on:
- disassociate(usbdev, true);
-
- return ret;
-}
-
-static int rndis_disconnect(struct wiphy *wiphy, struct net_device *dev,
- u16 reason_code)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- netdev_dbg(usbdev->net, "cfg80211.disconnect(%d)\n", reason_code);
-
- priv->connected = false;
- eth_zero_addr(priv->bssid);
-
- return deauthenticate(usbdev);
-}
-
-static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_ibss_params *params)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- struct ieee80211_channel *channel = params->chandef.chan;
- struct ndis_80211_ssid ssid;
- enum nl80211_auth_type auth_type;
- int ret, alg, length, chan = -1;
-
- if (channel)
- chan = ieee80211_frequency_to_channel(channel->center_freq);
-
- /* TODO: How to handle ad-hoc encryption?
- * connect() has *key, join_ibss() doesn't. RNDIS requires key to be
- * pre-shared for encryption (open/shared/wpa), is key set before
- * join_ibss? Which auth_type to use (not in params)? What about WPA?
- */
- if (params->privacy) {
- auth_type = NL80211_AUTHTYPE_SHARED_KEY;
- alg = RNDIS_WLAN_ALG_WEP;
- } else {
- auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
- alg = RNDIS_WLAN_ALG_NONE;
- }
-
- netdev_dbg(usbdev->net, "cfg80211.join_ibss('%.32s':[%pM]:%d:%d)\n",
- params->ssid, params->bssid, chan, params->privacy);
-
- if (is_associated(usbdev))
- disassociate(usbdev, false);
-
- ret = set_infra_mode(usbdev, NDIS_80211_INFRA_ADHOC);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "join_ibss: set_infra_mode failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
-
- ret = set_auth_mode(usbdev, 0, auth_type, RNDIS_WLAN_KEY_MGMT_NONE);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "join_ibss: set_auth_mode failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
-
- set_priv_filter(usbdev);
-
- ret = set_encr_mode(usbdev, alg, RNDIS_WLAN_ALG_NONE);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "join_ibss: set_encr_mode failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
-
- if (channel) {
- ret = set_channel(usbdev, chan);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "join_ibss: set_channel failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
- }
-
- if (params->bssid && !is_zero_ether_addr(params->bssid) &&
- !is_broadcast_ether_addr(params->bssid)) {
- ret = set_bssid(usbdev, params->bssid);
- if (ret < 0) {
- netdev_dbg(usbdev->net, "join_ibss: set_bssid failed, %d\n",
- ret);
- goto err_turn_radio_on;
- }
- } else
- clear_bssid(usbdev);
-
- length = params->ssid_len;
- if (length > NDIS_802_11_LENGTH_SSID)
- length = NDIS_802_11_LENGTH_SSID;
-
- memset(&ssid, 0, sizeof(ssid));
- ssid.length = cpu_to_le32(length);
- memcpy(ssid.essid, params->ssid, length);
-
- /* Don't need to pause rx queue for ad-hoc. */
- usbnet_purge_paused_rxq(usbdev);
- usbnet_resume_rx(usbdev);
-
- ret = set_essid(usbdev, &ssid);
- if (ret < 0)
- netdev_dbg(usbdev->net, "join_ibss: set_essid failed, %d\n",
- ret);
- return ret;
-
-err_turn_radio_on:
- disassociate(usbdev, true);
-
- return ret;
-}
-
-static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- netdev_dbg(usbdev->net, "cfg80211.leave_ibss()\n");
-
- priv->connected = false;
- eth_zero_addr(priv->bssid);
-
- return deauthenticate(usbdev);
-}
-
-static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
- int link_id, u8 key_index, bool pairwise,
- const u8 *mac_addr, struct key_params *params)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- __le32 flags;
-
- netdev_dbg(usbdev->net, "%s(%i, %pM, %08x)\n",
- __func__, key_index, mac_addr, params->cipher);
-
- switch (params->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- return add_wep_key(usbdev, params->key, params->key_len,
- key_index);
- case WLAN_CIPHER_SUITE_TKIP:
- case WLAN_CIPHER_SUITE_CCMP:
- flags = 0;
-
- if (params->seq && params->seq_len > 0)
- flags |= NDIS_80211_ADDKEY_SET_INIT_RECV_SEQ;
- if (mac_addr)
- flags |= NDIS_80211_ADDKEY_PAIRWISE_KEY |
- NDIS_80211_ADDKEY_TRANSMIT_KEY;
-
- return add_wpa_key(usbdev, params->key, params->key_len,
- key_index, mac_addr, params->seq,
- params->seq_len, params->cipher, flags);
- default:
- netdev_dbg(usbdev->net, "%s(): unsupported cipher %08x\n",
- __func__, params->cipher);
- return -ENOTSUPP;
- }
-}
-
-static int rndis_del_key(struct wiphy *wiphy, struct net_device *netdev,
- int link_id, u8 key_index, bool pairwise,
- const u8 *mac_addr)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- netdev_dbg(usbdev->net, "%s(%i, %pM)\n", __func__, key_index, mac_addr);
-
- return remove_key(usbdev, key_index, mac_addr);
-}
-
-static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
- int link_id, u8 key_index, bool unicast,
- bool multicast)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- struct rndis_wlan_encr_key key;
-
- netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index);
-
- if (key_index >= RNDIS_WLAN_NUM_KEYS)
- return -ENOENT;
-
- priv->encr_tx_key_index = key_index;
-
- if (is_wpa_key(priv, key_index))
- return 0;
-
- key = priv->encr_keys[key_index];
-
- return add_wep_key(usbdev, key.material, key.len, key_index);
-}
-
-static void rndis_fill_station_info(struct usbnet *usbdev,
- struct station_info *sinfo)
-{
- __le32 linkspeed, rssi;
- int ret, len;
-
- memset(sinfo, 0, sizeof(*sinfo));
-
- len = sizeof(linkspeed);
- ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len);
- if (ret == 0) {
- sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
- }
-
- len = sizeof(rssi);
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI,
- &rssi, &len);
- if (ret == 0) {
- sinfo->signal = level_to_qual(le32_to_cpu(rssi));
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL);
- }
-}
-
-static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
- const u8 *mac, struct station_info *sinfo)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- if (!ether_addr_equal(priv->bssid, mac))
- return -ENOENT;
-
- rndis_fill_station_info(usbdev, sinfo);
-
- return 0;
-}
-
-static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
- int idx, u8 *mac, struct station_info *sinfo)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- if (idx != 0)
- return -ENOENT;
-
- memcpy(mac, priv->bssid, ETH_ALEN);
-
- rndis_fill_station_info(usbdev, sinfo);
-
- return 0;
-}
-
-static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- struct ndis_80211_pmkid *pmkids;
- u32 *tmp = (u32 *)pmksa->pmkid;
-
- netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__,
- pmksa->bssid,
- cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
- cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
-
- pmkids = get_device_pmkids(usbdev);
- if (IS_ERR(pmkids)) {
- /* couldn't read PMKID cache from device */
- return PTR_ERR(pmkids);
- }
-
- pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids);
- if (IS_ERR(pmkids)) {
- /* not found, list full, etc */
- return PTR_ERR(pmkids);
- }
-
- return set_device_pmkids(usbdev, pmkids);
-}
-
-static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
- struct cfg80211_pmksa *pmksa)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- struct ndis_80211_pmkid *pmkids;
- u32 *tmp = (u32 *)pmksa->pmkid;
-
- netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__,
- pmksa->bssid,
- cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
- cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
-
- pmkids = get_device_pmkids(usbdev);
- if (IS_ERR(pmkids)) {
- /* Couldn't read PMKID cache from device */
- return PTR_ERR(pmkids);
- }
-
- pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids);
- if (IS_ERR(pmkids)) {
- /* not found, etc */
- return PTR_ERR(pmkids);
- }
-
- return set_device_pmkids(usbdev, pmkids);
-}
-
-static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- struct ndis_80211_pmkid pmkid;
-
- netdev_dbg(usbdev->net, "%s()\n", __func__);
-
- memset(&pmkid, 0, sizeof(pmkid));
-
- pmkid.length = cpu_to_le32(sizeof(pmkid));
- pmkid.bssid_info_count = cpu_to_le32(0);
-
- return rndis_set_oid(usbdev, RNDIS_OID_802_11_PMKID,
- &pmkid, sizeof(pmkid));
-}
-
-static int rndis_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
- bool enabled, int timeout)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
- int power_mode;
- __le32 mode;
- int ret;
-
- if (priv->device_type != RNDIS_BCM4320B)
- return -ENOTSUPP;
-
- netdev_dbg(usbdev->net, "%s(): %s, %d\n", __func__,
- enabled ? "enabled" : "disabled",
- timeout);
-
- if (enabled)
- power_mode = NDIS_80211_POWER_MODE_FAST_PSP;
- else
- power_mode = NDIS_80211_POWER_MODE_CAM;
-
- if (power_mode == priv->power_mode)
- return 0;
-
- priv->power_mode = power_mode;
-
- mode = cpu_to_le32(power_mode);
- ret = rndis_set_oid(usbdev, RNDIS_OID_802_11_POWER_MODE,
- &mode, sizeof(mode));
-
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_POWER_MODE -> %d\n",
- __func__, ret);
-
- return ret;
-}
-
-static int rndis_set_cqm_rssi_config(struct wiphy *wiphy,
- struct net_device *dev,
- s32 rssi_thold, u32 rssi_hyst)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
-
- priv->cqm_rssi_thold = rssi_thold;
- priv->cqm_rssi_hyst = rssi_hyst;
- priv->last_cqm_event_rssi = 0;
-
- return 0;
-}
-
-static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
- struct ndis_80211_assoc_info *info)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ieee80211_channel *channel;
- struct ndis_80211_ssid ssid;
- struct cfg80211_bss *bss;
- s32 signal;
- u64 timestamp;
- u16 capability;
- u32 beacon_period = 0;
- __le32 rssi;
- u8 ie_buf[34];
- int len, ret, ie_len;
-
- /* Get signal quality, in case of error use rssi=0 and ignore error. */
- len = sizeof(rssi);
- rssi = 0;
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI,
- &rssi, &len);
- signal = level_to_qual(le32_to_cpu(rssi));
-
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_RSSI -> %d, "
- "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi),
- level_to_qual(le32_to_cpu(rssi)));
-
- /* Get AP capabilities */
- if (info) {
- capability = le16_to_cpu(info->resp_ie.capa);
- } else {
- /* Set atleast ESS/IBSS capability */
- capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ?
- WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS;
- }
-
- /* Get channel and beacon interval */
- channel = get_current_channel(usbdev, &beacon_period);
- if (!channel) {
- netdev_warn(usbdev->net, "%s(): could not get channel.\n",
- __func__);
- return;
- }
-
- /* Get SSID, in case of error, use zero length SSID and ignore error. */
- len = sizeof(ssid);
- memset(&ssid, 0, sizeof(ssid));
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_SSID,
- &ssid, &len);
- netdev_dbg(usbdev->net, "%s(): RNDIS_OID_802_11_SSID -> %d, len: %d, ssid: "
- "'%.32s'\n", __func__, ret,
- le32_to_cpu(ssid.length), ssid.essid);
-
- if (le32_to_cpu(ssid.length) > 32)
- ssid.length = cpu_to_le32(32);
-
- ie_buf[0] = WLAN_EID_SSID;
- ie_buf[1] = le32_to_cpu(ssid.length);
- memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length));
-
- ie_len = le32_to_cpu(ssid.length) + 2;
-
- /* no tsf */
- timestamp = 0;
-
- netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, "
- "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), "
- "signal:%d\n", __func__, (channel ? channel->center_freq : -1),
- bssid, (u32)timestamp, capability, beacon_period, ie_len,
- ssid.essid, signal);
-
- bss = cfg80211_inform_bss(priv->wdev.wiphy, channel,
- CFG80211_BSS_FTYPE_UNKNOWN, bssid,
- timestamp, capability, beacon_period,
- ie_buf, ie_len, signal, GFP_KERNEL);
- cfg80211_put_bss(priv->wdev.wiphy, bss);
-}
-
-/*
- * workers, indication handlers, device poller
- */
-static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_assoc_info *info = NULL;
- u8 bssid[ETH_ALEN];
- unsigned int resp_ie_len, req_ie_len;
- unsigned int offset;
- u8 *req_ie, *resp_ie;
- int ret;
- bool roamed = false;
- bool match_bss;
-
- if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) {
- /* received media connect indication while connected, either
- * device reassociated with same AP or roamed to new. */
- roamed = true;
- }
-
- req_ie_len = 0;
- resp_ie_len = 0;
- req_ie = NULL;
- resp_ie = NULL;
-
- if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
- info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
- if (!info) {
- /* No memory? Try resume work later */
- set_bit(WORK_LINK_UP, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
- return;
- }
-
- /* Get association info IEs from device. */
- ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE);
- if (!ret) {
- req_ie_len = le32_to_cpu(info->req_ie_length);
- if (req_ie_len > CONTROL_BUFFER_SIZE)
- req_ie_len = CONTROL_BUFFER_SIZE;
- if (req_ie_len != 0) {
- offset = le32_to_cpu(info->offset_req_ies);
-
- if (offset > CONTROL_BUFFER_SIZE)
- offset = CONTROL_BUFFER_SIZE;
-
- req_ie = (u8 *)info + offset;
-
- if (offset + req_ie_len > CONTROL_BUFFER_SIZE)
- req_ie_len =
- CONTROL_BUFFER_SIZE - offset;
- }
-
- resp_ie_len = le32_to_cpu(info->resp_ie_length);
- if (resp_ie_len > CONTROL_BUFFER_SIZE)
- resp_ie_len = CONTROL_BUFFER_SIZE;
- if (resp_ie_len != 0) {
- offset = le32_to_cpu(info->offset_resp_ies);
-
- if (offset > CONTROL_BUFFER_SIZE)
- offset = CONTROL_BUFFER_SIZE;
-
- resp_ie = (u8 *)info + offset;
-
- if (offset + resp_ie_len > CONTROL_BUFFER_SIZE)
- resp_ie_len =
- CONTROL_BUFFER_SIZE - offset;
- }
- } else {
- /* Since rndis_wlan_craft_connected_bss() might use info
- * later and expects info to contain valid data if
- * non-null, free info and set NULL here.
- */
- kfree(info);
- info = NULL;
- }
- } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC))
- return;
-
- ret = get_bssid(usbdev, bssid);
- if (ret < 0)
- memset(bssid, 0, sizeof(bssid));
-
- netdev_dbg(usbdev->net, "link up work: [%pM]%s\n",
- bssid, roamed ? " roamed" : "");
-
- /* Internal bss list in device should contain at least the currently
- * connected bss and we can get it to cfg80211 with
- * rndis_check_bssid_list().
- *
- * NDIS spec says: "If the device is associated, but the associated
- * BSSID is not in its BSSID scan list, then the driver must add an
- * entry for the BSSID at the end of the data that it returns in
- * response to query of RNDIS_OID_802_11_BSSID_LIST."
- *
- * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a.
- */
- match_bss = false;
- rndis_check_bssid_list(usbdev, bssid, &match_bss);
-
- if (!is_zero_ether_addr(bssid) && !match_bss) {
- /* Couldn't get bss from device, we need to manually craft bss
- * for cfg80211.
- */
- rndis_wlan_craft_connected_bss(usbdev, bssid, info);
- }
-
- if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
- if (!roamed) {
- cfg80211_connect_result(usbdev->net, bssid, req_ie,
- req_ie_len, resp_ie,
- resp_ie_len, 0, GFP_KERNEL);
- } else {
- struct cfg80211_roam_info roam_info = {
- .links[0].channel =
- get_current_channel(usbdev, NULL),
- .links[0].bssid = bssid,
- .req_ie = req_ie,
- .req_ie_len = req_ie_len,
- .resp_ie = resp_ie,
- .resp_ie_len = resp_ie_len,
- };
-
- cfg80211_roamed(usbdev->net, &roam_info, GFP_KERNEL);
- }
- } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
- cfg80211_ibss_joined(usbdev->net, bssid,
- get_current_channel(usbdev, NULL),
- GFP_KERNEL);
-
- kfree(info);
-
- priv->connected = true;
- memcpy(priv->bssid, bssid, ETH_ALEN);
-
- usbnet_resume_rx(usbdev);
- netif_carrier_on(usbdev->net);
-}
-
-static void rndis_wlan_do_link_down_work(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- if (priv->connected) {
- priv->connected = false;
- eth_zero_addr(priv->bssid);
-
- deauthenticate(usbdev);
-
- cfg80211_disconnected(usbdev->net, 0, NULL, 0, true, GFP_KERNEL);
- }
-
- netif_carrier_off(usbdev->net);
-}
-
-static void rndis_wlan_worker(struct work_struct *work)
-{
- struct rndis_wlan_private *priv =
- container_of(work, struct rndis_wlan_private, work);
- struct usbnet *usbdev = priv->usbdev;
-
- if (test_and_clear_bit(WORK_LINK_UP, &priv->work_pending))
- rndis_wlan_do_link_up_work(usbdev);
-
- if (test_and_clear_bit(WORK_LINK_DOWN, &priv->work_pending))
- rndis_wlan_do_link_down_work(usbdev);
-
- if (test_and_clear_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
- set_multicast_list(usbdev);
-}
-
-static void rndis_wlan_set_multicast_list(struct net_device *dev)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending))
- return;
-
- set_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
-}
-
-static void rndis_wlan_auth_indication(struct usbnet *usbdev,
- struct ndis_80211_status_indication *indication,
- int len)
-{
- u8 *buf;
- const char *type;
- int flags, buflen, key_id;
- bool pairwise_error, group_error;
- struct ndis_80211_auth_request *auth_req;
- enum nl80211_key_type key_type;
-
- /* must have at least one array entry */
- if (len < offsetof(struct ndis_80211_status_indication, u) +
- sizeof(struct ndis_80211_auth_request)) {
- netdev_info(usbdev->net, "authentication indication: too short message (%i)\n",
- len);
- return;
- }
-
- buf = (void *)&indication->u.auth_request[0];
- buflen = len - offsetof(struct ndis_80211_status_indication, u);
-
- while (buflen >= sizeof(*auth_req)) {
- auth_req = (void *)buf;
- if (buflen < le32_to_cpu(auth_req->length))
- return;
- type = "unknown";
- flags = le32_to_cpu(auth_req->flags);
- pairwise_error = false;
- group_error = false;
-
- if (flags & 0x1)
- type = "reauth request";
- if (flags & 0x2)
- type = "key update request";
- if (flags & 0x6) {
- pairwise_error = true;
- type = "pairwise_error";
- }
- if (flags & 0xe) {
- group_error = true;
- type = "group_error";
- }
-
- netdev_info(usbdev->net, "authentication indication: %s (0x%08x)\n",
- type, le32_to_cpu(auth_req->flags));
-
- if (pairwise_error) {
- key_type = NL80211_KEYTYPE_PAIRWISE;
- key_id = -1;
-
- cfg80211_michael_mic_failure(usbdev->net,
- auth_req->bssid,
- key_type, key_id, NULL,
- GFP_KERNEL);
- }
-
- if (group_error) {
- key_type = NL80211_KEYTYPE_GROUP;
- key_id = -1;
-
- cfg80211_michael_mic_failure(usbdev->net,
- auth_req->bssid,
- key_type, key_id, NULL,
- GFP_KERNEL);
- }
-
- buflen -= le32_to_cpu(auth_req->length);
- buf += le32_to_cpu(auth_req->length);
- }
-}
-
-static void rndis_wlan_pmkid_cand_list_indication(struct usbnet *usbdev,
- struct ndis_80211_status_indication *indication,
- int len)
-{
- struct ndis_80211_pmkid_cand_list *cand_list;
- int list_len, expected_len, i;
-
- if (len < offsetof(struct ndis_80211_status_indication, u) +
- sizeof(struct ndis_80211_pmkid_cand_list)) {
- netdev_info(usbdev->net, "pmkid candidate list indication: too short message (%i)\n",
- len);
- return;
- }
-
- list_len = le32_to_cpu(indication->u.cand_list.num_candidates) *
- sizeof(struct ndis_80211_pmkid_candidate);
- expected_len = sizeof(struct ndis_80211_pmkid_cand_list) + list_len +
- offsetof(struct ndis_80211_status_indication, u);
-
- if (len < expected_len) {
- netdev_info(usbdev->net, "pmkid candidate list indication: list larger than buffer (%i < %i)\n",
- len, expected_len);
- return;
- }
-
- cand_list = &indication->u.cand_list;
-
- netdev_info(usbdev->net, "pmkid candidate list indication: version %i, candidates %i\n",
- le32_to_cpu(cand_list->version),
- le32_to_cpu(cand_list->num_candidates));
-
- if (le32_to_cpu(cand_list->version) != 1)
- return;
-
- for (i = 0; i < le32_to_cpu(cand_list->num_candidates); i++) {
- struct ndis_80211_pmkid_candidate *cand =
- &cand_list->candidate_list[i];
- bool preauth = !!(cand->flags & NDIS_80211_PMKID_CAND_PREAUTH);
-
- netdev_dbg(usbdev->net, "cand[%i]: flags: 0x%08x, preauth: %d, bssid: %pM\n",
- i, le32_to_cpu(cand->flags), preauth, cand->bssid);
-
- cfg80211_pmksa_candidate_notify(usbdev->net, i, cand->bssid,
- preauth, GFP_ATOMIC);
- }
-}
-
-static void rndis_wlan_media_specific_indication(struct usbnet *usbdev,
- struct rndis_indicate *msg, int buflen)
-{
- struct ndis_80211_status_indication *indication;
- unsigned int len, offset;
-
- offset = offsetof(struct rndis_indicate, status) +
- le32_to_cpu(msg->offset);
- len = le32_to_cpu(msg->length);
-
- if (len < 8) {
- netdev_info(usbdev->net, "media specific indication, ignore too short message (%i < 8)\n",
- len);
- return;
- }
-
- if (len > buflen || offset > buflen || offset + len > buflen) {
- netdev_info(usbdev->net, "media specific indication, too large to fit to buffer (%i > %i)\n",
- offset + len, buflen);
- return;
- }
-
- indication = (void *)((u8 *)msg + offset);
-
- switch (le32_to_cpu(indication->status_type)) {
- case NDIS_80211_STATUSTYPE_RADIOSTATE:
- netdev_info(usbdev->net, "radio state indication: %i\n",
- le32_to_cpu(indication->u.radio_status));
- return;
-
- case NDIS_80211_STATUSTYPE_MEDIASTREAMMODE:
- netdev_info(usbdev->net, "media stream mode indication: %i\n",
- le32_to_cpu(indication->u.media_stream_mode));
- return;
-
- case NDIS_80211_STATUSTYPE_AUTHENTICATION:
- rndis_wlan_auth_indication(usbdev, indication, len);
- return;
-
- case NDIS_80211_STATUSTYPE_PMKID_CANDIDATELIST:
- rndis_wlan_pmkid_cand_list_indication(usbdev, indication, len);
- return;
-
- default:
- netdev_info(usbdev->net, "media specific indication: unknown status type 0x%08x\n",
- le32_to_cpu(indication->status_type));
- }
-}
-
-static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct rndis_indicate *msg = ind;
-
- switch (le32_to_cpu(msg->status)) {
- case RNDIS_STATUS_MEDIA_CONNECT:
- if (priv->current_command_oid == RNDIS_OID_802_11_ADD_KEY) {
- /* RNDIS_OID_802_11_ADD_KEY causes sometimes extra
- * "media connect" indications which confuses driver
- * and userspace to think that device is
- * roaming/reassociating when it isn't.
- */
- netdev_dbg(usbdev->net, "ignored RNDIS_OID_802_11_ADD_KEY triggered 'media connect'\n");
- return;
- }
-
- usbnet_pause_rx(usbdev);
-
- netdev_info(usbdev->net, "media connect\n");
-
- /* queue work to avoid recursive calls into rndis_command */
- set_bit(WORK_LINK_UP, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
- break;
-
- case RNDIS_STATUS_MEDIA_DISCONNECT:
- netdev_info(usbdev->net, "media disconnect\n");
-
- /* queue work to avoid recursive calls into rndis_command */
- set_bit(WORK_LINK_DOWN, &priv->work_pending);
- queue_work(priv->workqueue, &priv->work);
- break;
-
- case RNDIS_STATUS_MEDIA_SPECIFIC_INDICATION:
- rndis_wlan_media_specific_indication(usbdev, msg, buflen);
- break;
-
- default:
- netdev_info(usbdev->net, "indication: 0x%08x\n",
- le32_to_cpu(msg->status));
- break;
- }
-}
-
-static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy)
-{
- struct {
- __le32 num_items;
- __le32 items[8];
- } networks_supported;
- struct ndis_80211_capability caps;
- int len, retval, i, n;
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- /* determine supported modes */
- len = sizeof(networks_supported);
- retval = rndis_query_oid(usbdev,
- RNDIS_OID_802_11_NETWORK_TYPES_SUPPORTED,
- &networks_supported, &len);
- if (!retval) {
- n = le32_to_cpu(networks_supported.num_items);
- if (n > 8)
- n = 8;
- for (i = 0; i < n; i++) {
- switch (le32_to_cpu(networks_supported.items[i])) {
- case NDIS_80211_TYPE_FREQ_HOP:
- case NDIS_80211_TYPE_DIRECT_SEQ:
- priv->caps |= CAP_MODE_80211B;
- break;
- case NDIS_80211_TYPE_OFDM_A:
- priv->caps |= CAP_MODE_80211A;
- break;
- case NDIS_80211_TYPE_OFDM_G:
- priv->caps |= CAP_MODE_80211G;
- break;
- }
- }
- }
-
- /* get device 802.11 capabilities, number of PMKIDs */
- len = sizeof(caps);
- retval = rndis_query_oid(usbdev,
- RNDIS_OID_802_11_CAPABILITY,
- &caps, &len);
- if (!retval) {
- netdev_dbg(usbdev->net, "RNDIS_OID_802_11_CAPABILITY -> len %d, "
- "ver %d, pmkids %d, auth-encr-pairs %d\n",
- le32_to_cpu(caps.length),
- le32_to_cpu(caps.version),
- le32_to_cpu(caps.num_pmkids),
- le32_to_cpu(caps.num_auth_encr_pair));
- wiphy->max_num_pmkids = le32_to_cpu(caps.num_pmkids);
- } else
- wiphy->max_num_pmkids = 0;
-
- return retval;
-}
-
-static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- enum nl80211_cqm_rssi_threshold_event event;
- int thold, hyst, last_event;
-
- if (priv->cqm_rssi_thold >= 0 || rssi >= 0)
- return;
- if (priv->infra_mode != NDIS_80211_INFRA_INFRA)
- return;
-
- last_event = priv->last_cqm_event_rssi;
- thold = priv->cqm_rssi_thold;
- hyst = priv->cqm_rssi_hyst;
-
- if (rssi < thold && (last_event == 0 || rssi < last_event - hyst))
- event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
- else if (rssi > thold && (last_event == 0 || rssi > last_event + hyst))
- event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
- else
- return;
-
- priv->last_cqm_event_rssi = rssi;
- cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL);
-}
-
-#define DEVICE_POLLER_JIFFIES (HZ)
-static void rndis_device_poller(struct work_struct *work)
-{
- struct rndis_wlan_private *priv =
- container_of(work, struct rndis_wlan_private,
- dev_poller_work.work);
- struct usbnet *usbdev = priv->usbdev;
- __le32 rssi, tmp;
- int len, ret, j;
- int update_jiffies = DEVICE_POLLER_JIFFIES;
- void *buf;
-
- /* Only check/do workaround when connected. Calling is_associated()
- * also polls device with rndis_command() and catches for media link
- * indications.
- */
- if (!is_associated(usbdev)) {
- /* Workaround bad scanning in BCM4320a devices with active
- * background scanning when not associated.
- */
- if (priv->device_type == RNDIS_BCM4320A && priv->radio_on &&
- !priv->scan_request) {
- /* Get previous scan results */
- rndis_check_bssid_list(usbdev, NULL, NULL);
-
- /* Initiate new scan */
- rndis_start_bssid_list_scan(usbdev);
- }
-
- goto end;
- }
-
- len = sizeof(rssi);
- ret = rndis_query_oid(usbdev, RNDIS_OID_802_11_RSSI,
- &rssi, &len);
- if (ret == 0) {
- priv->last_qual = level_to_qual(le32_to_cpu(rssi));
- rndis_do_cqm(usbdev, le32_to_cpu(rssi));
- }
-
- netdev_dbg(usbdev->net, "dev-poller: RNDIS_OID_802_11_RSSI -> %d, rssi:%d, qual: %d\n",
- ret, le32_to_cpu(rssi), level_to_qual(le32_to_cpu(rssi)));
-
- /* Workaround transfer stalls on poor quality links.
- * TODO: find right way to fix these stalls (as stalls do not happen
- * with ndiswrapper/windows driver). */
- if (priv->param_workaround_interval > 0 && priv->last_qual <= 25) {
- /* Decrease stats worker interval to catch stalls.
- * faster. Faster than 400-500ms causes packet loss,
- * Slower doesn't catch stalls fast enough.
- */
- j = msecs_to_jiffies(priv->param_workaround_interval);
- if (j > DEVICE_POLLER_JIFFIES)
- j = DEVICE_POLLER_JIFFIES;
- else if (j <= 0)
- j = 1;
- update_jiffies = j;
-
- /* Send scan OID. Use of both OIDs is required to get device
- * working.
- */
- tmp = cpu_to_le32(1);
- rndis_set_oid(usbdev,
- RNDIS_OID_802_11_BSSID_LIST_SCAN,
- &tmp, sizeof(tmp));
-
- len = CONTROL_BUFFER_SIZE;
- buf = kmalloc(len, GFP_KERNEL);
- if (!buf)
- goto end;
-
- rndis_query_oid(usbdev,
- RNDIS_OID_802_11_BSSID_LIST,
- buf, &len);
- kfree(buf);
- }
-
-end:
- if (update_jiffies >= HZ)
- update_jiffies = round_jiffies_relative(update_jiffies);
- else {
- j = round_jiffies_relative(update_jiffies);
- if (abs(j - update_jiffies) <= 10)
- update_jiffies = j;
- }
-
- queue_delayed_work(priv->workqueue, &priv->dev_poller_work,
- update_jiffies);
-}
-
-/*
- * driver/device initialization
- */
-static void rndis_copy_module_params(struct usbnet *usbdev, int device_type)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- priv->device_type = device_type;
-
- priv->param_country[0] = modparam_country[0];
- priv->param_country[1] = modparam_country[1];
- priv->param_country[2] = 0;
- priv->param_frameburst = modparam_frameburst;
- priv->param_afterburner = modparam_afterburner;
- priv->param_power_save = modparam_power_save;
- priv->param_power_output = modparam_power_output;
- priv->param_roamtrigger = modparam_roamtrigger;
- priv->param_roamdelta = modparam_roamdelta;
-
- priv->param_country[0] = toupper(priv->param_country[0]);
- priv->param_country[1] = toupper(priv->param_country[1]);
- /* doesn't support EU as country code, use FI instead */
- if (!strcmp(priv->param_country, "EU"))
- strcpy(priv->param_country, "FI");
-
- if (priv->param_power_save < 0)
- priv->param_power_save = 0;
- else if (priv->param_power_save > 2)
- priv->param_power_save = 2;
-
- if (priv->param_power_output < 0)
- priv->param_power_output = 0;
- else if (priv->param_power_output > 3)
- priv->param_power_output = 3;
-
- if (priv->param_roamtrigger < -80)
- priv->param_roamtrigger = -80;
- else if (priv->param_roamtrigger > -60)
- priv->param_roamtrigger = -60;
-
- if (priv->param_roamdelta < 0)
- priv->param_roamdelta = 0;
- else if (priv->param_roamdelta > 2)
- priv->param_roamdelta = 2;
-
- if (modparam_workaround_interval < 0)
- priv->param_workaround_interval = 500;
- else
- priv->param_workaround_interval = modparam_workaround_interval;
-}
-
-static int unknown_early_init(struct usbnet *usbdev)
-{
- /* copy module parameters for unknown so that iwconfig reports txpower
- * and workaround parameter is copied to private structure correctly.
- */
- rndis_copy_module_params(usbdev, RNDIS_UNKNOWN);
-
- /* This is unknown device, so do not try set configuration parameters.
- */
-
- return 0;
-}
-
-static int bcm4320a_early_init(struct usbnet *usbdev)
-{
- /* copy module parameters for bcm4320a so that iwconfig reports txpower
- * and workaround parameter is copied to private structure correctly.
- */
- rndis_copy_module_params(usbdev, RNDIS_BCM4320A);
-
- /* bcm4320a doesn't handle configuration parameters well. Try
- * set any and you get partially zeroed mac and broken device.
- */
-
- return 0;
-}
-
-static int bcm4320b_early_init(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- char buf[8];
-
- rndis_copy_module_params(usbdev, RNDIS_BCM4320B);
-
- /* Early initialization settings, setting these won't have effect
- * if called after generic_rndis_bind().
- */
-
- rndis_set_config_parameter_str(usbdev, "Country", priv->param_country);
- rndis_set_config_parameter_str(usbdev, "FrameBursting",
- priv->param_frameburst ? "1" : "0");
- rndis_set_config_parameter_str(usbdev, "Afterburner",
- priv->param_afterburner ? "1" : "0");
- sprintf(buf, "%d", priv->param_power_save);
- rndis_set_config_parameter_str(usbdev, "PowerSaveMode", buf);
- sprintf(buf, "%d", priv->param_power_output);
- rndis_set_config_parameter_str(usbdev, "PwrOut", buf);
- sprintf(buf, "%d", priv->param_roamtrigger);
- rndis_set_config_parameter_str(usbdev, "RoamTrigger", buf);
- sprintf(buf, "%d", priv->param_roamdelta);
- rndis_set_config_parameter_str(usbdev, "RoamDelta", buf);
-
- return 0;
-}
-
-/* same as rndis_netdev_ops but with local multicast handler */
-static const struct net_device_ops rndis_wlan_netdev_ops = {
- .ndo_open = usbnet_open,
- .ndo_stop = usbnet_stop,
- .ndo_start_xmit = usbnet_start_xmit,
- .ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_get_stats64 = dev_get_tstats64,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_rx_mode = rndis_wlan_set_multicast_list,
-};
-
-static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
-{
- struct wiphy *wiphy;
- struct rndis_wlan_private *priv;
- int retval, len;
- __le32 tmp;
-
- /* allocate wiphy and rndis private data
- * NOTE: We only support a single virtual interface, so wiphy
- * and wireless_dev are somewhat synonymous for this device.
- */
- wiphy = wiphy_new(&rndis_config_ops, sizeof(struct rndis_wlan_private));
- if (!wiphy)
- return -ENOMEM;
-
- priv = wiphy_priv(wiphy);
- usbdev->net->ieee80211_ptr = &priv->wdev;
- priv->wdev.wiphy = wiphy;
- priv->wdev.iftype = NL80211_IFTYPE_STATION;
-
- /* These have to be initialized before calling generic_rndis_bind().
- * Otherwise we'll be in big trouble in rndis_wlan_early_init().
- */
- usbdev->driver_priv = priv;
- priv->usbdev = usbdev;
-
- mutex_init(&priv->command_lock);
-
- /* because rndis_command() sleeps we need to use workqueue */
- priv->workqueue = create_singlethread_workqueue("rndis_wlan");
- if (!priv->workqueue) {
- wiphy_free(wiphy);
- return -ENOMEM;
- }
- INIT_WORK(&priv->work, rndis_wlan_worker);
- INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller);
- INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results);
-
- /* try bind rndis_host */
- retval = generic_rndis_bind(usbdev, intf, FLAG_RNDIS_PHYM_WIRELESS);
- if (retval < 0)
- goto fail;
-
- /* generic_rndis_bind set packet filter to multicast_all+
- * promisc mode which doesn't work well for our devices (device
- * picks up rssi to closest station instead of to access point).
- *
- * rndis_host wants to avoid all OID as much as possible
- * so do promisc/multicast handling in rndis_wlan.
- */
- usbdev->net->netdev_ops = &rndis_wlan_netdev_ops;
-
- tmp = cpu_to_le32(RNDIS_PACKET_TYPE_DIRECTED | RNDIS_PACKET_TYPE_BROADCAST);
- retval = rndis_set_oid(usbdev,
- RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
- &tmp, sizeof(tmp));
-
- len = sizeof(tmp);
- retval = rndis_query_oid(usbdev,
- RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
- &tmp, &len);
- priv->multicast_size = le32_to_cpu(tmp);
- if (retval < 0 || priv->multicast_size < 0)
- priv->multicast_size = 0;
- if (priv->multicast_size > 0)
- usbdev->net->flags |= IFF_MULTICAST;
- else
- usbdev->net->flags &= ~IFF_MULTICAST;
-
- /* fill-out wiphy structure and register w/ cfg80211 */
- memcpy(wiphy->perm_addr, usbdev->net->dev_addr, ETH_ALEN);
- wiphy->privid = rndis_wiphy_privid;
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
- | BIT(NL80211_IFTYPE_ADHOC);
- wiphy->max_scan_ssids = 1;
-
- /* TODO: fill-out band/encr information based on priv->caps */
- rndis_wlan_get_caps(usbdev, wiphy);
-
- memcpy(priv->channels, rndis_channels, sizeof(rndis_channels));
- memcpy(priv->rates, rndis_rates, sizeof(rndis_rates));
- priv->band.channels = priv->channels;
- priv->band.n_channels = ARRAY_SIZE(rndis_channels);
- priv->band.bitrates = priv->rates;
- priv->band.n_bitrates = ARRAY_SIZE(rndis_rates);
- wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
-
- memcpy(priv->cipher_suites, rndis_cipher_suites,
- sizeof(rndis_cipher_suites));
- wiphy->cipher_suites = priv->cipher_suites;
- wiphy->n_cipher_suites = ARRAY_SIZE(rndis_cipher_suites);
-
- set_wiphy_dev(wiphy, &usbdev->udev->dev);
-
- if (wiphy_register(wiphy)) {
- retval = -ENODEV;
- goto fail;
- }
-
- set_default_iw_params(usbdev);
-
- priv->power_mode = -1;
-
- /* set default rts/frag */
- rndis_set_wiphy_params(wiphy,
- WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
-
- /* turn radio off on init */
- priv->radio_on = false;
- disassociate(usbdev, false);
- netif_carrier_off(usbdev->net);
-
- return 0;
-
-fail:
- cancel_delayed_work_sync(&priv->dev_poller_work);
- cancel_delayed_work_sync(&priv->scan_work);
- cancel_work_sync(&priv->work);
- destroy_workqueue(priv->workqueue);
-
- wiphy_free(wiphy);
- return retval;
-}
-
-static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-
- /* turn radio off */
- disassociate(usbdev, false);
-
- cancel_delayed_work_sync(&priv->dev_poller_work);
- cancel_delayed_work_sync(&priv->scan_work);
- cancel_work_sync(&priv->work);
- destroy_workqueue(priv->workqueue);
-
- rndis_unbind(usbdev, intf);
-
- wiphy_unregister(priv->wdev.wiphy);
- wiphy_free(priv->wdev.wiphy);
-}
-
-static int rndis_wlan_reset(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int retval;
-
- netdev_dbg(usbdev->net, "%s()\n", __func__);
-
- retval = rndis_reset(usbdev);
- if (retval)
- netdev_warn(usbdev->net, "rndis_reset failed: %d\n", retval);
-
- /* rndis_reset cleared multicast list, so restore here.
- (set_multicast_list() also turns on current packet filter) */
- set_multicast_list(usbdev);
-
- queue_delayed_work(priv->workqueue, &priv->dev_poller_work,
- round_jiffies_relative(DEVICE_POLLER_JIFFIES));
-
- return deauthenticate(usbdev);
-}
-
-static int rndis_wlan_stop(struct usbnet *usbdev)
-{
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- int retval;
- __le32 filter;
-
- netdev_dbg(usbdev->net, "%s()\n", __func__);
-
- retval = disassociate(usbdev, false);
-
- priv->work_pending = 0;
- cancel_delayed_work_sync(&priv->dev_poller_work);
- cancel_delayed_work_sync(&priv->scan_work);
- cancel_work_sync(&priv->work);
- flush_workqueue(priv->workqueue);
-
- if (priv->scan_request) {
- struct cfg80211_scan_info info = {
- .aborted = true,
- };
-
- cfg80211_scan_done(priv->scan_request, &info);
- priv->scan_request = NULL;
- }
-
- /* Set current packet filter zero to block receiving data packets from
- device. */
- filter = 0;
- rndis_set_oid(usbdev, RNDIS_OID_GEN_CURRENT_PACKET_FILTER, &filter,
- sizeof(filter));
-
- return retval;
-}
-
-static const struct driver_info bcm4320b_info = {
- .description = "Wireless RNDIS device, BCM4320b based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
- FLAG_AVOID_UNLINK_URBS,
- .bind = rndis_wlan_bind,
- .unbind = rndis_wlan_unbind,
- .status = rndis_status,
- .rx_fixup = rndis_rx_fixup,
- .tx_fixup = rndis_tx_fixup,
- .reset = rndis_wlan_reset,
- .stop = rndis_wlan_stop,
- .early_init = bcm4320b_early_init,
- .indication = rndis_wlan_indication,
-};
-
-static const struct driver_info bcm4320a_info = {
- .description = "Wireless RNDIS device, BCM4320a based",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
- FLAG_AVOID_UNLINK_URBS,
- .bind = rndis_wlan_bind,
- .unbind = rndis_wlan_unbind,
- .status = rndis_status,
- .rx_fixup = rndis_rx_fixup,
- .tx_fixup = rndis_tx_fixup,
- .reset = rndis_wlan_reset,
- .stop = rndis_wlan_stop,
- .early_init = bcm4320a_early_init,
- .indication = rndis_wlan_indication,
-};
-
-static const struct driver_info rndis_wlan_info = {
- .description = "Wireless RNDIS device",
- .flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT |
- FLAG_AVOID_UNLINK_URBS,
- .bind = rndis_wlan_bind,
- .unbind = rndis_wlan_unbind,
- .status = rndis_status,
- .rx_fixup = rndis_rx_fixup,
- .tx_fixup = rndis_tx_fixup,
- .reset = rndis_wlan_reset,
- .stop = rndis_wlan_stop,
- .early_init = unknown_early_init,
- .indication = rndis_wlan_indication,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static const struct usb_device_id products [] = {
-#define RNDIS_MASTER_INTERFACE \
- .bInterfaceClass = USB_CLASS_COMM, \
- .bInterfaceSubClass = 2 /* ACM */, \
- .bInterfaceProtocol = 0x0ff
-
-/* INF driver for these devices have DriverVer >= 4.xx.xx.xx and many custom
- * parameters available. Chipset marked as 'BCM4320SKFBG' in NDISwrapper-wiki.
- */
-{
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x0411,
- .idProduct = 0x00bc, /* Buffalo WLI-U2-KG125S */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x0baf,
- .idProduct = 0x011b, /* U.S. Robotics USR5421 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x050d,
- .idProduct = 0x011b, /* Belkin F5D7051 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x1799, /* Belkin has two vendor ids */
- .idProduct = 0x011b, /* Belkin F5D7051 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x13b1,
- .idProduct = 0x0014, /* Linksys WUSB54GSv2 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x13b1,
- .idProduct = 0x0026, /* Linksys WUSB54GSC */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x0b05,
- .idProduct = 0x1717, /* Asus WL169gE */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x0a5c,
- .idProduct = 0xd11b, /* Eminent EM4045 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x1690,
- .idProduct = 0x0715, /* BT Voyager 1055 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320b_info,
-},
-/* These devices have DriverVer < 4.xx.xx.xx and do not have any custom
- * parameters available, hardware probably contain older firmware version with
- * no way of updating. Chipset marked as 'BCM4320????' in NDISwrapper-wiki.
- */
-{
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x13b1,
- .idProduct = 0x000e, /* Linksys WUSB54GSv1 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320a_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x0baf,
- .idProduct = 0x0111, /* U.S. Robotics USR5420 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320a_info,
-}, {
- .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
- | USB_DEVICE_ID_MATCH_DEVICE,
- .idVendor = 0x0411,
- .idProduct = 0x004b, /* BUFFALO WLI-USB-G54 */
- RNDIS_MASTER_INTERFACE,
- .driver_info = (unsigned long) &bcm4320a_info,
-},
-/* Generic Wireless RNDIS devices that we don't have exact
- * idVendor/idProduct/chip yet.
- */
-{
- /* RNDIS is MSFT's un-official variant of CDC ACM */
- USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
- .driver_info = (unsigned long) &rndis_wlan_info,
-}, {
- /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
- USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
- .driver_info = (unsigned long) &rndis_wlan_info,
-},
- { }, // END
-};
-MODULE_DEVICE_TABLE(usb, products);
-
-static struct usb_driver rndis_wlan_driver = {
- .name = "rndis_wlan",
- .id_table = products,
- .probe = usbnet_probe,
- .disconnect = usbnet_disconnect,
- .suspend = usbnet_suspend,
- .resume = usbnet_resume,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(rndis_wlan_driver);
-
-MODULE_AUTHOR("Bjorge Dijkstra");
-MODULE_AUTHOR("Jussi Kivilinna");
-MODULE_DESCRIPTION("Driver for RNDIS based USB Wireless adapters");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/wireless/legacy/wl3501.h b/drivers/net/wireless/legacy/wl3501.h
deleted file mode 100644
index 91f276dd22a1..000000000000
--- a/drivers/net/wireless/legacy/wl3501.h
+++ /dev/null
@@ -1,615 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __WL3501_H__
-#define __WL3501_H__
-
-#include <linux/spinlock.h>
-#include <linux/ieee80211.h>
-
-/* define for WLA 2.0 */
-#define WL3501_BLKSZ 256
-/*
- * ID for input Signals of DRIVER block
- * bit[7-5] is block ID: 000
- * bit[4-0] is signal ID
-*/
-enum wl3501_signals {
- WL3501_SIG_ALARM,
- WL3501_SIG_MD_CONFIRM,
- WL3501_SIG_MD_IND,
- WL3501_SIG_ASSOC_CONFIRM,
- WL3501_SIG_ASSOC_IND,
- WL3501_SIG_AUTH_CONFIRM,
- WL3501_SIG_AUTH_IND,
- WL3501_SIG_DEAUTH_CONFIRM,
- WL3501_SIG_DEAUTH_IND,
- WL3501_SIG_DISASSOC_CONFIRM,
- WL3501_SIG_DISASSOC_IND,
- WL3501_SIG_GET_CONFIRM,
- WL3501_SIG_JOIN_CONFIRM,
- WL3501_SIG_PWR_MGMT_CONFIRM,
- WL3501_SIG_REASSOC_CONFIRM,
- WL3501_SIG_REASSOC_IND,
- WL3501_SIG_SCAN_CONFIRM,
- WL3501_SIG_SET_CONFIRM,
- WL3501_SIG_START_CONFIRM,
- WL3501_SIG_RESYNC_CONFIRM,
- WL3501_SIG_SITE_CONFIRM,
- WL3501_SIG_SAVE_CONFIRM,
- WL3501_SIG_RFTEST_CONFIRM,
-/*
- * ID for input Signals of MLME block
- * bit[7-5] is block ID: 010
- * bit[4-0] is signal ID
- */
- WL3501_SIG_ASSOC_REQ = 0x20,
- WL3501_SIG_AUTH_REQ,
- WL3501_SIG_DEAUTH_REQ,
- WL3501_SIG_DISASSOC_REQ,
- WL3501_SIG_GET_REQ,
- WL3501_SIG_JOIN_REQ,
- WL3501_SIG_PWR_MGMT_REQ,
- WL3501_SIG_REASSOC_REQ,
- WL3501_SIG_SCAN_REQ,
- WL3501_SIG_SET_REQ,
- WL3501_SIG_START_REQ,
- WL3501_SIG_MD_REQ,
- WL3501_SIG_RESYNC_REQ,
- WL3501_SIG_SITE_REQ,
- WL3501_SIG_SAVE_REQ,
- WL3501_SIG_RF_TEST_REQ,
- WL3501_SIG_MM_CONFIRM = 0x60,
- WL3501_SIG_MM_IND,
-};
-
-enum wl3501_mib_attribs {
- WL3501_MIB_ATTR_STATION_ID,
- WL3501_MIB_ATTR_AUTH_ALGORITHMS,
- WL3501_MIB_ATTR_AUTH_TYPE,
- WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT,
- WL3501_MIB_ATTR_CF_POLLABLE,
- WL3501_MIB_ATTR_CFP_PERIOD,
- WL3501_MIB_ATTR_CFPMAX_DURATION,
- WL3501_MIB_ATTR_AUTH_RESP_TMOUT,
- WL3501_MIB_ATTR_RX_DTIMS,
- WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
- WL3501_MIB_ATTR_PRIV_INVOKED,
- WL3501_MIB_ATTR_WEP_DEFAULT_KEYS,
- WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID,
- WL3501_MIB_ATTR_WEP_KEY_MAPPINGS,
- WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN,
- WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED,
- WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT,
- WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT,
- WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT,
- WL3501_MIB_ATTR_MAC_ADDR,
- WL3501_MIB_ATTR_GROUP_ADDRS,
- WL3501_MIB_ATTR_RTS_THRESHOLD,
- WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
- WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
- WL3501_MIB_ATTR_FRAG_THRESHOLD,
- WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME,
- WL3501_MIB_ATTR_MAX_RX_LIFETIME,
- WL3501_MIB_ATTR_MANUFACTURER_ID,
- WL3501_MIB_ATTR_PRODUCT_ID,
- WL3501_MIB_ATTR_TX_FRAG_COUNT,
- WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT,
- WL3501_MIB_ATTR_FAILED_COUNT,
- WL3501_MIB_ATTR_RX_FRAG_COUNT,
- WL3501_MIB_ATTR_MULTICAST_RX_COUNT,
- WL3501_MIB_ATTR_FCS_ERROR_COUNT,
- WL3501_MIB_ATTR_RETRY_COUNT,
- WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT,
- WL3501_MIB_ATTR_RTS_SUCCESS_COUNT,
- WL3501_MIB_ATTR_RTS_FAILURE_COUNT,
- WL3501_MIB_ATTR_ACK_FAILURE_COUNT,
- WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT,
- WL3501_MIB_ATTR_PHY_TYPE,
- WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT,
- WL3501_MIB_ATTR_CURRENT_REG_DOMAIN,
- WL3501_MIB_ATTR_SLOT_TIME,
- WL3501_MIB_ATTR_CCA_TIME,
- WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME,
- WL3501_MIB_ATTR_TX_PLCP_DELAY,
- WL3501_MIB_ATTR_RX_TX_SWITCH_TIME,
- WL3501_MIB_ATTR_TX_RAMP_ON_TIME,
- WL3501_MIB_ATTR_TX_RF_DELAY,
- WL3501_MIB_ATTR_SIFS_TIME,
- WL3501_MIB_ATTR_RX_RF_DELAY,
- WL3501_MIB_ATTR_RX_PLCP_DELAY,
- WL3501_MIB_ATTR_MAC_PROCESSING_DELAY,
- WL3501_MIB_ATTR_TX_RAMP_OFF_TIME,
- WL3501_MIB_ATTR_PREAMBLE_LEN,
- WL3501_MIB_ATTR_PLCP_HEADER_LEN,
- WL3501_MIB_ATTR_MPDU_DURATION_FACTOR,
- WL3501_MIB_ATTR_AIR_PROPAGATION_TIME,
- WL3501_MIB_ATTR_TEMP_TYPE,
- WL3501_MIB_ATTR_CW_MIN,
- WL3501_MIB_ATTR_CW_MAX,
- WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX,
- WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX,
- WL3501_MIB_ATTR_MPDU_MAX_LEN,
- WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS,
- WL3501_MIB_ATTR_CURRENT_TX_ANTENNA,
- WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS,
- WL3501_MIB_ATTR_DIVERSITY_SUPPORT,
- WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS,
- WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS,
- WL3501_MIB_ATTR_TX_PWR_LEVEL1,
- WL3501_MIB_ATTR_TX_PWR_LEVEL2,
- WL3501_MIB_ATTR_TX_PWR_LEVEL3,
- WL3501_MIB_ATTR_TX_PWR_LEVEL4,
- WL3501_MIB_ATTR_TX_PWR_LEVEL5,
- WL3501_MIB_ATTR_TX_PWR_LEVEL6,
- WL3501_MIB_ATTR_TX_PWR_LEVEL7,
- WL3501_MIB_ATTR_TX_PWR_LEVEL8,
- WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
- WL3501_MIB_ATTR_CURRENT_CHAN,
- WL3501_MIB_ATTR_CCA_MODE_SUPPORTED,
- WL3501_MIB_ATTR_CURRENT_CCA_MODE,
- WL3501_MIB_ATTR_ED_THRESHOLD,
- WL3501_MIB_ATTR_SINTHESIZER_LOCKED,
- WL3501_MIB_ATTR_CURRENT_PWR_STATE,
- WL3501_MIB_ATTR_DOZE_TURNON_TIME,
- WL3501_MIB_ATTR_RCR33,
- WL3501_MIB_ATTR_DEFAULT_CHAN,
- WL3501_MIB_ATTR_SSID,
- WL3501_MIB_ATTR_PWR_MGMT_ENABLE,
- WL3501_MIB_ATTR_NET_CAPABILITY,
- WL3501_MIB_ATTR_ROUTING,
-};
-
-enum wl3501_net_type {
- WL3501_NET_TYPE_INFRA,
- WL3501_NET_TYPE_ADHOC,
- WL3501_NET_TYPE_ANY_BSS,
-};
-
-enum wl3501_scan_type {
- WL3501_SCAN_TYPE_ACTIVE,
- WL3501_SCAN_TYPE_PASSIVE,
-};
-
-enum wl3501_tx_result {
- WL3501_TX_RESULT_SUCCESS,
- WL3501_TX_RESULT_NO_BSS,
- WL3501_TX_RESULT_RETRY_LIMIT,
-};
-
-enum wl3501_sys_type {
- WL3501_SYS_TYPE_OPEN,
- WL3501_SYS_TYPE_SHARE_KEY,
-};
-
-enum wl3501_status {
- WL3501_STATUS_SUCCESS,
- WL3501_STATUS_INVALID,
- WL3501_STATUS_TIMEOUT,
- WL3501_STATUS_REFUSED,
- WL3501_STATUS_MANY_REQ,
- WL3501_STATUS_ALREADY_BSS,
-};
-
-#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */
-#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */
-#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */
-#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */
-#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */
-
-#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */
-#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */
-#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */
-#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */
-#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */
-#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */
-#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */
-#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */
-
-#define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */
-
-enum iw_mgmt_rate_labels {
- IW_MGMT_RATE_LABEL_1MBIT = 2,
- IW_MGMT_RATE_LABEL_2MBIT = 4,
- IW_MGMT_RATE_LABEL_5_5MBIT = 11,
- IW_MGMT_RATE_LABEL_11MBIT = 22,
-};
-
-enum iw_mgmt_info_element_ids {
- IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */
- IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES,
- IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET,
- IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
- IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET,
- IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */
- IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET,
- /* 7-15: Reserved, unused */
- IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16,
- /* 17-31 Reserved for challenge text extension */
- /* 32-255 Reserved, unused */
-};
-
-struct iw_mgmt_info_element {
- u8 id; /* one of enum iw_mgmt_info_element_ids,
- but sizeof(enum) > sizeof(u8) :-( */
- u8 len;
- u8 data[];
-} __packed;
-
-struct iw_mgmt_essid_pset {
- struct iw_mgmt_info_element el;
- u8 essid[IW_ESSID_MAX_SIZE];
-} __packed;
-
-/*
- * According to 802.11 Wireless Networks, the definitive guide - O'Reilly
- * Pg 75
- */
-#define IW_DATA_RATE_MAX_LABELS 8
-
-struct iw_mgmt_data_rset {
- struct iw_mgmt_info_element el;
- u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS];
-} __packed;
-
-struct iw_mgmt_ds_pset {
- struct iw_mgmt_info_element el;
- u8 chan;
-} __packed;
-
-struct iw_mgmt_cf_pset {
- struct iw_mgmt_info_element el;
- u8 cfp_count;
- u8 cfp_period;
- u16 cfp_max_duration;
- u16 cfp_dur_remaining;
-} __packed;
-
-struct iw_mgmt_ibss_pset {
- struct iw_mgmt_info_element el;
- u16 atim_window;
-} __packed;
-
-struct wl3501_tx_hdr {
- u16 tx_cnt;
- u8 sync[16];
- u16 sfd;
- u8 signal;
- u8 service;
- u16 len;
- u16 crc16;
- u16 frame_ctrl;
- u16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- u16 seq_ctrl;
- u8 addr4[ETH_ALEN];
-};
-
-struct wl3501_rx_hdr {
- u16 rx_next_blk;
- u16 rc_next_frame_blk;
- u8 rx_blk_ctrl;
- u8 rx_next_frame;
- u8 rx_next_frame1;
- u8 rssi;
- char time[8];
- u8 signal;
- u8 service;
- u16 len;
- u16 crc16;
- u16 frame_ctrl;
- u16 duration;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- u16 seq;
- u8 addr4[ETH_ALEN];
-};
-
-struct wl3501_start_req {
- u16 next_blk;
- u8 sig_id;
- u8 bss_type;
- u16 beacon_period;
- u16 dtim_period;
- u16 probe_delay;
- u16 cap_info;
- struct iw_mgmt_essid_pset ssid;
- struct iw_mgmt_data_rset bss_basic_rset;
- struct iw_mgmt_data_rset operational_rset;
- struct iw_mgmt_cf_pset cf_pset;
- struct iw_mgmt_ds_pset ds_pset;
- struct iw_mgmt_ibss_pset ibss_pset;
-};
-
-struct wl3501_assoc_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 timeout;
- u16 cap_info;
- u16 listen_interval;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_assoc_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_assoc_ind {
- u16 next_blk;
- u8 sig_id;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_auth_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 type;
- u16 timeout;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_auth_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 type;
- u16 status;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_get_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 mib_attrib;
-};
-
-struct wl3501_get_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 mib_status;
- u16 mib_attrib;
- u8 mib_value[100];
-};
-
-struct wl3501_req {
- u16 beacon_period;
- u16 dtim_period;
- u16 cap_info;
- u8 bss_type;
- u8 bssid[ETH_ALEN];
- struct iw_mgmt_essid_pset ssid;
- struct iw_mgmt_ds_pset ds_pset;
- struct iw_mgmt_cf_pset cf_pset;
- struct iw_mgmt_ibss_pset ibss_pset;
- struct iw_mgmt_data_rset bss_basic_rset;
-};
-
-struct wl3501_join_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- struct iw_mgmt_data_rset operational_rset;
- u16 reserved2;
- u16 timeout;
- u16 probe_delay;
- u8 timestamp[8];
- u8 local_time[8];
- struct wl3501_req req;
-};
-
-struct wl3501_join_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_pwr_mgmt_req {
- u16 next_blk;
- u8 sig_id;
- u8 pwr_save;
- u8 wake_up;
- u8 receive_dtims;
-};
-
-struct wl3501_pwr_mgmt_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_scan_req {
- u16 next_blk;
- u8 sig_id;
- u8 bss_type;
- u16 probe_delay;
- u16 min_chan_time;
- u16 max_chan_time;
- u8 chan_list[14];
- u8 bssid[ETH_ALEN];
- struct iw_mgmt_essid_pset ssid;
- enum wl3501_scan_type scan_type;
-};
-
-struct wl3501_scan_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
- char timestamp[8];
- char localtime[8];
- struct wl3501_req req;
- u8 rssi;
-};
-
-struct wl3501_start_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_md_req {
- u16 next_blk;
- u8 sig_id;
- u8 routing;
- u16 data;
- u16 size;
- u8 pri;
- u8 service_class;
- struct {
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
- } addr;
-};
-
-struct wl3501_md_ind {
- u16 next_blk;
- u8 sig_id;
- u8 routing;
- u16 data;
- u16 size;
- u8 reception;
- u8 pri;
- u8 service_class;
- struct {
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
- } addr;
-};
-
-struct wl3501_md_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 data;
- u8 status;
- u8 pri;
- u8 service_class;
-};
-
-struct wl3501_resync_req {
- u16 next_blk;
- u8 sig_id;
-};
-
-/* Definitions for supporting clone adapters. */
-/* System Interface Registers (SIR space) */
-#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */
-#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */
-#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */
-#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */
-#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */
-#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */
-#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */
-#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */
-
-/* Bits in GCR */
-#define WL3501_GCR_SWRESET ((u8)0x80)
-#define WL3501_GCR_CORESET ((u8)0x40)
-#define WL3501_GCR_DISPWDN ((u8)0x20)
-#define WL3501_GCR_ECWAIT ((u8)0x10)
-#define WL3501_GCR_ECINT ((u8)0x08)
-#define WL3501_GCR_INT2EC ((u8)0x04)
-#define WL3501_GCR_ENECINT ((u8)0x02)
-#define WL3501_GCR_DAM ((u8)0x01)
-
-/* Bits in BSS (Bank Switching Select Register) */
-#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */
-#define WL3501_BSS_FPAGE1 ((u8)0x28)
-#define WL3501_BSS_FPAGE2 ((u8)0x30)
-#define WL3501_BSS_FPAGE3 ((u8)0x38)
-#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */
-#define WL3501_BSS_SPAGE1 ((u8)0x08)
-#define WL3501_BSS_SPAGE2 ((u8)0x10)
-#define WL3501_BSS_SPAGE3 ((u8)0x18)
-
-/* Define Driver Interface */
-/* Refer IEEE 802.11 */
-/* Tx packet header, include PLCP and MPDU */
-/* Tx PLCP Header */
-struct wl3501_80211_tx_plcp_hdr {
- u8 sync[16];
- u16 sfd;
- u8 signal;
- u8 service;
- u16 len;
- u16 crc16;
-} __packed;
-
-struct wl3501_80211_tx_hdr {
- struct wl3501_80211_tx_plcp_hdr pclp_hdr;
- struct ieee80211_hdr mac_hdr;
-} __packed __aligned(2);
-
-/*
- Reserve the beginning Tx space for descriptor use.
-
- TxBlockOffset --> *----*----*----*----* \
- (TxFreeDesc) | 0 | 1 | 2 | 3 | \
- | 4 | 5 | 6 | 7 | |
- | 8 | 9 | 10 | 11 | TX_DESC * 20
- | 12 | 13 | 14 | 15 | |
- | 16 | 17 | 18 | 19 | /
- TxBufferBegin --> *----*----*----*----* /
- (TxBufferHead) | |
- (TxBufferTail) | |
- | Send Buffer |
- | |
- | |
- *-------------------*
- TxBufferEnd -------------------------/
-
-*/
-
-struct wl3501_card {
- int base_addr;
- u8 mac_addr[ETH_ALEN];
- spinlock_t lock;
- wait_queue_head_t wait;
- struct wl3501_get_confirm sig_get_confirm;
- struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm;
- u16 tx_buffer_size;
- u16 tx_buffer_head;
- u16 tx_buffer_tail;
- u16 tx_buffer_cnt;
- u16 esbq_req_start;
- u16 esbq_req_end;
- u16 esbq_req_head;
- u16 esbq_req_tail;
- u16 esbq_confirm_start;
- u16 esbq_confirm_end;
- u16 esbq_confirm;
- struct iw_mgmt_essid_pset essid;
- struct iw_mgmt_essid_pset keep_essid;
- u8 bssid[ETH_ALEN];
- int net_type;
- char nick[32];
- char card_name[32];
- char firmware_date[32];
- u8 chan;
- u8 cap_info;
- u16 start_seg;
- u16 bss_cnt;
- u16 join_sta_bss;
- u8 rssi;
- u8 adhoc_times;
- u8 reg_domain;
- u8 version[2];
- struct wl3501_scan_confirm bss_set[20];
-
- struct iw_statistics wstats;
- struct iw_spy_data spy_data;
- struct iw_public_data wireless_data;
- struct pcmcia_device *p_dev;
-};
-#endif
diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c
deleted file mode 100644
index c45c4b7cbbaf..000000000000
--- a/drivers/net/wireless/legacy/wl3501_cs.c
+++ /dev/null
@@ -1,2036 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WL3501 Wireless LAN PCMCIA Card Driver for Linux
- * Written originally for Linux 2.0.30 by Fox Chen, mhchen@golf.ccl.itri.org.tw
- * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * Wireless extensions in 2.4 by Gustavo Niemeyer <niemeyer@conectiva.com>
- *
- * References used by Fox Chen while writing the original driver for 2.0.30:
- *
- * 1. WL24xx packet drivers (tooasm.asm)
- * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO
- * 3. IEEE 802.11
- * 4. Linux network driver (/usr/src/linux/drivers/net)
- * 5. ISA card driver - wl24.c
- * 6. Linux PCMCIA skeleton driver - skeleton.c
- * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c
- *
- * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12
- * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode.
- * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null
- * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct
- * ETHER/IP/UDP/TCP header, and acknowledgement overhead)
- *
- * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode,
- * 173 Kbytes/s in TCP.
- *
- * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode
- * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60)
- */
-
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fcntl.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-
-#include <net/iw_handler.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#include "wl3501.h"
-
-#ifndef __i386__
-#define slow_down_io()
-#endif
-
-/* For rough constant delay */
-#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); }
-
-
-
-#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); }
-#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); }
-#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); }
-
-#define WL3501_RELEASE_TIMEOUT (25 * HZ)
-#define WL3501_MAX_ADHOC_TRIES 16
-
-#define WL3501_RESUME 0
-#define WL3501_SUSPEND 1
-
-static int wl3501_config(struct pcmcia_device *link);
-static void wl3501_release(struct pcmcia_device *link);
-
-static const struct {
- int reg_domain;
- int min, max, deflt;
-} iw_channel_table[] = {
- {
- .reg_domain = IW_REG_DOMAIN_FCC,
- .min = 1,
- .max = 11,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_DOC,
- .min = 1,
- .max = 11,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_ETSI,
- .min = 1,
- .max = 13,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_SPAIN,
- .min = 10,
- .max = 11,
- .deflt = 10,
- },
- {
- .reg_domain = IW_REG_DOMAIN_FRANCE,
- .min = 10,
- .max = 13,
- .deflt = 10,
- },
- {
- .reg_domain = IW_REG_DOMAIN_MKK,
- .min = 14,
- .max = 14,
- .deflt = 14,
- },
- {
- .reg_domain = IW_REG_DOMAIN_MKK1,
- .min = 1,
- .max = 14,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_ISRAEL,
- .min = 3,
- .max = 9,
- .deflt = 9,
- },
-};
-
-/**
- * iw_valid_channel - validate channel in regulatory domain
- * @reg_domain: regulatory domain
- * @channel: channel to validate
- *
- * Returns 0 if invalid in the specified regulatory domain, non-zero if valid.
- */
-static int iw_valid_channel(int reg_domain, int channel)
-{
- int i, rc = 0;
-
- for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++)
- if (reg_domain == iw_channel_table[i].reg_domain) {
- rc = channel >= iw_channel_table[i].min &&
- channel <= iw_channel_table[i].max;
- break;
- }
- return rc;
-}
-
-/**
- * iw_default_channel - get default channel for a regulatory domain
- * @reg_domain: regulatory domain
- *
- * Returns the default channel for a regulatory domain
- */
-static int iw_default_channel(int reg_domain)
-{
- int i, rc = 1;
-
- for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++)
- if (reg_domain == iw_channel_table[i].reg_domain) {
- rc = iw_channel_table[i].deflt;
- break;
- }
- return rc;
-}
-
-static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id,
- struct iw_mgmt_info_element *el,
- void *value, int len)
-{
- el->id = id;
- el->len = len;
- memcpy(el->data, value, len);
-}
-
-static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to,
- struct iw_mgmt_info_element *from)
-{
- iw_set_mgmt_info_element(from->id, to, from->data, from->len);
-}
-
-static inline void wl3501_switch_page(struct wl3501_card *this, u8 page)
-{
- wl3501_outb(page, this->base_addr + WL3501_NIC_BSS);
-}
-
-/*
- * Get Ethernet MAC address.
- *
- * WARNING: We switch to FPAGE0 and switc back again.
- * Making sure there is no other WL function beening called by ISR.
- */
-static int wl3501_get_flash_mac_addr(struct wl3501_card *this)
-{
- int base_addr = this->base_addr;
-
- /* get MAC addr */
- wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */
- wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */
- wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */
-
- /* wait for reading EEPROM */
- WL3501_NOPLOOP(100);
- this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->reg_domain = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS);
- wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL);
- wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH);
- WL3501_NOPLOOP(100);
- this->version[0] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->version[1] = inb(base_addr + WL3501_NIC_IODPA);
- /* switch to SRAM Page 0 (for safety) */
- wl3501_switch_page(this, WL3501_BSS_SPAGE0);
-
- /* The MAC addr should be 00:60:... */
- return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60;
-}
-
-/**
- * wl3501_set_to_wla - Move 'size' bytes from PC to card
- * @this: Card
- * @dest: Card addressing space
- * @src: PC addressing space
- * @size: Bytes to move
- *
- * Move 'size' bytes from PC to card. (Shouldn't be interrupted)
- */
-static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src,
- int size)
-{
- /* switch to SRAM Page 0 */
- wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 :
- WL3501_BSS_SPAGE0);
- /* set LMAL and LMAH */
- wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL);
- wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH);
-
- /* rep out to Port A */
- wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size);
-}
-
-/**
- * wl3501_get_from_wla - Move 'size' bytes from card to PC
- * @this: Card
- * @src: Card addressing space
- * @dest: PC addressing space
- * @size: Bytes to move
- *
- * Move 'size' bytes from card to PC. (Shouldn't be interrupted)
- */
-static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
- int size)
-{
- /* switch to SRAM Page 0 */
- wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 :
- WL3501_BSS_SPAGE0);
- /* set LMAL and LMAH */
- wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL);
- wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH);
-
- /* rep get from Port A */
- insb(this->base_addr + WL3501_NIC_IODPA, dest, size);
-}
-
-/*
- * Get/Allocate a free Tx Data Buffer
- *
- * *--------------*-----------------*----------------------------------*
- * | PLCP | MAC Header | DST SRC Data ... |
- * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) |
- * *--------------*-----------------*----------------------------------*
- * \ \- IEEE 802.11 -/ \-------------- len --------------/
- * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/
- *
- * Return = Position in Card
- */
-static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len)
-{
- u16 next, blk_cnt = 0, zero = 0;
- u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len;
- u16 ret = 0;
-
- if (full_len > this->tx_buffer_cnt * 254)
- goto out;
- ret = this->tx_buffer_head;
- while (full_len) {
- if (full_len < 254)
- full_len = 0;
- else
- full_len -= 254;
- wl3501_get_from_wla(this, this->tx_buffer_head, &next,
- sizeof(next));
- if (!full_len)
- wl3501_set_to_wla(this, this->tx_buffer_head, &zero,
- sizeof(zero));
- this->tx_buffer_head = next;
- blk_cnt++;
- /* if buffer is not enough */
- if (!next && full_len) {
- this->tx_buffer_head = ret;
- ret = 0;
- goto out;
- }
- }
- this->tx_buffer_cnt -= blk_cnt;
-out:
- return ret;
-}
-
-/*
- * Free an allocated Tx Buffer. ptr must be correct position.
- */
-static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr)
-{
- /* check if all space is not free */
- if (!this->tx_buffer_head)
- this->tx_buffer_head = ptr;
- else
- wl3501_set_to_wla(this, this->tx_buffer_tail,
- &ptr, sizeof(ptr));
- while (ptr) {
- u16 next;
-
- this->tx_buffer_cnt++;
- wl3501_get_from_wla(this, ptr, &next, sizeof(next));
- this->tx_buffer_tail = ptr;
- ptr = next;
- }
-}
-
-static int wl3501_esbq_req_test(struct wl3501_card *this)
-{
- u8 tmp = 0;
-
- wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp));
- return tmp & 0x80;
-}
-
-static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr)
-{
- u16 tmp = 0;
-
- wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2);
- wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp));
- this->esbq_req_head += 4;
- if (this->esbq_req_head >= this->esbq_req_end)
- this->esbq_req_head = this->esbq_req_start;
-}
-
-static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size)
-{
- int rc = -EIO;
-
- if (wl3501_esbq_req_test(this)) {
- u16 ptr = wl3501_get_tx_buffer(this, sig_size);
- if (ptr) {
- wl3501_set_to_wla(this, ptr, sig, sig_size);
- wl3501_esbq_req(this, &ptr);
- rc = 0;
- }
- }
- return rc;
-}
-
-static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf)
-{
- struct wl3501_get_req sig = {
- .sig_id = WL3501_SIG_GET_REQ,
- .mib_attrib = index,
- };
- unsigned long flags;
- int rc = -EIO;
-
- spin_lock_irqsave(&this->lock, flags);
- if (wl3501_esbq_req_test(this)) {
- u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig));
- if (ptr) {
- wl3501_set_to_wla(this, ptr, &sig, sizeof(sig));
- wl3501_esbq_req(this, &ptr);
- this->sig_get_confirm.mib_status = 255;
- rc = 0;
- }
- }
- spin_unlock_irqrestore(&this->lock, flags);
-
- return rc;
-}
-
-static int wl3501_get_mib_value(struct wl3501_card *this, u8 index,
- void *bf, int size)
-{
- int rc;
-
- rc = wl3501_request_mib(this, index, bf);
- if (rc)
- return rc;
-
- rc = wait_event_interruptible(this->wait,
- this->sig_get_confirm.mib_status != 255);
- if (rc)
- return rc;
-
- memcpy(bf, this->sig_get_confirm.mib_value, size);
- return 0;
-}
-
-static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend)
-{
- struct wl3501_pwr_mgmt_req sig = {
- .sig_id = WL3501_SIG_PWR_MGMT_REQ,
- .pwr_save = suspend,
- .wake_up = !suspend,
- .receive_dtims = 10,
- };
- unsigned long flags;
- int rc = -EIO;
-
- spin_lock_irqsave(&this->lock, flags);
- if (wl3501_esbq_req_test(this)) {
- u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig));
- if (ptr) {
- wl3501_set_to_wla(this, ptr, &sig, sizeof(sig));
- wl3501_esbq_req(this, &ptr);
- this->sig_pwr_mgmt_confirm.status = 255;
- spin_unlock_irqrestore(&this->lock, flags);
- rc = wait_event_interruptible(this->wait,
- this->sig_pwr_mgmt_confirm.status != 255);
- printk(KERN_INFO "%s: %s status=%d\n", __func__,
- suspend ? "suspend" : "resume",
- this->sig_pwr_mgmt_confirm.status);
- goto out;
- }
- }
- spin_unlock_irqrestore(&this->lock, flags);
-out:
- return rc;
-}
-
-/**
- * wl3501_send_pkt - Send a packet.
- * @this: Card
- * @data: Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr,
- * data[6] - data[11] is Src MAC Addr)
- * @len: Packet length
- * Ref: IEEE 802.11
- */
-static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len)
-{
- u16 bf, sig_bf, next, tmplen, pktlen;
- struct wl3501_md_req sig = {
- .sig_id = WL3501_SIG_MD_REQ,
- };
- size_t sig_addr_len = sizeof(sig.addr);
- u8 *pdata = (char *)data;
- int rc = -EIO;
-
- if (wl3501_esbq_req_test(this)) {
- sig_bf = wl3501_get_tx_buffer(this, sizeof(sig));
- rc = -ENOMEM;
- if (!sig_bf) /* No free buffer available */
- goto out;
- bf = wl3501_get_tx_buffer(this, len + 26 + 24);
- if (!bf) {
- /* No free buffer available */
- wl3501_free_tx_buffer(this, sig_bf);
- goto out;
- }
- rc = 0;
- memcpy(&sig.addr, pdata, sig_addr_len);
- pktlen = len - sig_addr_len;
- pdata += sig_addr_len;
- sig.data = bf;
- if (((*pdata) * 256 + (*(pdata + 1))) > 1500) {
- u8 addr4[ETH_ALEN] = {
- [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00,
- };
-
- wl3501_set_to_wla(this, bf + 2 +
- offsetof(struct wl3501_tx_hdr, addr4),
- addr4, sizeof(addr4));
- sig.size = pktlen + 24 + 4 + 6;
- if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) {
- tmplen = 254 - sizeof(struct wl3501_tx_hdr);
- pktlen -= tmplen;
- } else {
- tmplen = pktlen;
- pktlen = 0;
- }
- wl3501_set_to_wla(this,
- bf + 2 + sizeof(struct wl3501_tx_hdr),
- pdata, tmplen);
- pdata += tmplen;
- wl3501_get_from_wla(this, bf, &next, sizeof(next));
- bf = next;
- } else {
- sig.size = pktlen + 24 + 4 - 2;
- pdata += 2;
- pktlen -= 2;
- if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) {
- tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6;
- pktlen -= tmplen;
- } else {
- tmplen = pktlen;
- pktlen = 0;
- }
- wl3501_set_to_wla(this, bf + 2 +
- offsetof(struct wl3501_tx_hdr, addr4),
- pdata, tmplen);
- pdata += tmplen;
- wl3501_get_from_wla(this, bf, &next, sizeof(next));
- bf = next;
- }
- while (pktlen > 0) {
- if (pktlen > 254) {
- tmplen = 254;
- pktlen -= 254;
- } else {
- tmplen = pktlen;
- pktlen = 0;
- }
- wl3501_set_to_wla(this, bf + 2, pdata, tmplen);
- pdata += tmplen;
- wl3501_get_from_wla(this, bf, &next, sizeof(next));
- bf = next;
- }
- wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig));
- wl3501_esbq_req(this, &sig_bf);
- }
-out:
- return rc;
-}
-
-static int wl3501_mgmt_resync(struct wl3501_card *this)
-{
- struct wl3501_resync_req sig = {
- .sig_id = WL3501_SIG_RESYNC_REQ,
- };
-
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static inline int wl3501_fw_bss_type(struct wl3501_card *this)
-{
- return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA :
- WL3501_NET_TYPE_ADHOC;
-}
-
-static inline int wl3501_fw_cap_info(struct wl3501_card *this)
-{
- return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS :
- WL3501_MGMT_CAPABILITY_IBSS;
-}
-
-static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time)
-{
- struct wl3501_scan_req sig = {
- .sig_id = WL3501_SIG_SCAN_REQ,
- .scan_type = WL3501_SCAN_TYPE_ACTIVE,
- .probe_delay = 0x10,
- .min_chan_time = chan_time,
- .max_chan_time = chan_time,
- .bss_type = wl3501_fw_bss_type(this),
- };
-
- this->bss_cnt = this->join_sta_bss = 0;
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
-{
- struct wl3501_join_req sig = {
- .sig_id = WL3501_SIG_JOIN_REQ,
- .timeout = 10,
- .req.ds_pset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
- .len = 1,
- },
- .chan = this->chan,
- },
- };
-
- memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req));
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static int wl3501_mgmt_start(struct wl3501_card *this)
-{
- struct wl3501_start_req sig = {
- .sig_id = WL3501_SIG_START_REQ,
- .beacon_period = 400,
- .dtim_period = 1,
- .ds_pset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
- .len = 1,
- },
- .chan = this->chan,
- },
- .bss_basic_rset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES,
- .len = 2,
- },
- .data_rate_labels = {
- [0] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_1MBIT,
- [1] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_2MBIT,
- },
- },
- .operational_rset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES,
- .len = 2,
- },
- .data_rate_labels = {
- [0] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_1MBIT,
- [1] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_2MBIT,
- },
- },
- .ibss_pset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET,
- .len = 2,
- },
- .atim_window = 10,
- },
- .bss_type = wl3501_fw_bss_type(this),
- .cap_info = wl3501_fw_cap_info(this),
- };
-
- iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el);
- iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el);
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr)
-{
- u16 i = 0;
- int matchflag = 0;
- struct wl3501_scan_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- if (sig.status == WL3501_STATUS_SUCCESS) {
- pr_debug("success");
- if ((this->net_type == IW_MODE_INFRA &&
- (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) ||
- (this->net_type == IW_MODE_ADHOC &&
- (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
- this->net_type == IW_MODE_AUTO) {
- if (!this->essid.el.len)
- matchflag = 1;
- else if (this->essid.el.len == 3 &&
- !memcmp(this->essid.essid, "ANY", 3))
- matchflag = 1;
- else if (this->essid.el.len != sig.req.ssid.el.len)
- matchflag = 0;
- else if (memcmp(this->essid.essid, sig.req.ssid.essid,
- this->essid.el.len))
- matchflag = 0;
- else
- matchflag = 1;
- if (matchflag) {
- for (i = 0; i < this->bss_cnt; i++) {
- if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid,
- sig.req.bssid)) {
- matchflag = 0;
- break;
- }
- }
- }
- if (matchflag && (i < 20)) {
- memcpy(&this->bss_set[i].req,
- &sig.req, sizeof(sig.req));
- this->bss_cnt++;
- this->rssi = sig.rssi;
- this->bss_set[i].rssi = sig.rssi;
- }
- }
- } else if (sig.status == WL3501_STATUS_TIMEOUT) {
- pr_debug("timeout");
- this->join_sta_bss = 0;
- for (i = this->join_sta_bss; i < this->bss_cnt; i++)
- if (!wl3501_mgmt_join(this, i))
- break;
- this->join_sta_bss = i;
- if (this->join_sta_bss == this->bss_cnt) {
- if (this->net_type == IW_MODE_INFRA)
- wl3501_mgmt_scan(this, 100);
- else {
- this->adhoc_times++;
- if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES)
- wl3501_mgmt_start(this);
- else
- wl3501_mgmt_scan(this, 100);
- }
- }
- }
-}
-
-/**
- * wl3501_block_interrupt - Mask interrupt from SUTRO
- * @this: Card
- *
- * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST)
- * Return: 1 if interrupt is originally enabled
- */
-static int wl3501_block_interrupt(struct wl3501_card *this)
-{
- u8 old = inb(this->base_addr + WL3501_NIC_GCR);
- u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC |
- WL3501_GCR_ENECINT));
-
- wl3501_outb(new, this->base_addr + WL3501_NIC_GCR);
- return old & WL3501_GCR_ENECINT;
-}
-
-/**
- * wl3501_unblock_interrupt - Enable interrupt from SUTRO
- * @this: Card
- *
- * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST)
- * Return: 1 if interrupt is originally enabled
- */
-static int wl3501_unblock_interrupt(struct wl3501_card *this)
-{
- u8 old = inb(this->base_addr + WL3501_NIC_GCR);
- u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) |
- WL3501_GCR_ENECINT;
-
- wl3501_outb(new, this->base_addr + WL3501_NIC_GCR);
- return old & WL3501_GCR_ENECINT;
-}
-
-/**
- * wl3501_receive - Receive data from Receive Queue.
- *
- * Receive data from Receive Queue.
- *
- * @this: card
- * @bf: address of host
- * @size: size of buffer.
- */
-static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size)
-{
- u16 next_addr, next_addr1;
- u8 *data = bf + 12;
-
- size -= 12;
- wl3501_get_from_wla(this, this->start_seg + 2,
- &next_addr, sizeof(next_addr));
- if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) {
- wl3501_get_from_wla(this,
- this->start_seg +
- sizeof(struct wl3501_rx_hdr), data,
- WL3501_BLKSZ -
- sizeof(struct wl3501_rx_hdr));
- size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr);
- data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr);
- } else {
- wl3501_get_from_wla(this,
- this->start_seg +
- sizeof(struct wl3501_rx_hdr),
- data, size);
- size = 0;
- }
- while (size > 0) {
- if (size > WL3501_BLKSZ - 5) {
- wl3501_get_from_wla(this, next_addr + 5, data,
- WL3501_BLKSZ - 5);
- size -= WL3501_BLKSZ - 5;
- data += WL3501_BLKSZ - 5;
- wl3501_get_from_wla(this, next_addr + 2, &next_addr1,
- sizeof(next_addr1));
- next_addr = next_addr1;
- } else {
- wl3501_get_from_wla(this, next_addr + 5, data, size);
- size = 0;
- }
- }
- return 0;
-}
-
-static void wl3501_esbq_req_free(struct wl3501_card *this)
-{
- u8 tmp;
- u16 addr;
-
- if (this->esbq_req_head == this->esbq_req_tail)
- goto out;
- wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp));
- if (!(tmp & 0x80))
- goto out;
- wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr));
- wl3501_free_tx_buffer(this, addr);
- this->esbq_req_tail += 4;
- if (this->esbq_req_tail >= this->esbq_req_end)
- this->esbq_req_tail = this->esbq_req_start;
-out:
- return;
-}
-
-static int wl3501_esbq_confirm(struct wl3501_card *this)
-{
- u8 tmp;
-
- wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp));
- return tmp & 0x80;
-}
-
-static void wl3501_online(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n",
- dev->name, this->bssid);
- netif_wake_queue(dev);
-}
-
-static void wl3501_esbq_confirm_done(struct wl3501_card *this)
-{
- u8 tmp = 0;
-
- wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp));
- this->esbq_confirm += 4;
- if (this->esbq_confirm >= this->esbq_confirm_end)
- this->esbq_confirm = this->esbq_confirm_start;
-}
-
-static int wl3501_mgmt_auth(struct wl3501_card *this)
-{
- struct wl3501_auth_req sig = {
- .sig_id = WL3501_SIG_AUTH_REQ,
- .type = WL3501_SYS_TYPE_OPEN,
- .timeout = 1000,
- };
-
- pr_debug("entry");
- memcpy(sig.mac_addr, this->bssid, ETH_ALEN);
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static int wl3501_mgmt_association(struct wl3501_card *this)
-{
- struct wl3501_assoc_req sig = {
- .sig_id = WL3501_SIG_ASSOC_REQ,
- .timeout = 1000,
- .listen_interval = 5,
- .cap_info = this->cap_info,
- };
-
- pr_debug("entry");
- memcpy(sig.mac_addr, this->bssid, ETH_ALEN);
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
-{
- struct wl3501_card *this = netdev_priv(dev);
- struct wl3501_join_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- if (sig.status == WL3501_STATUS_SUCCESS) {
- if (this->net_type == IW_MODE_INFRA) {
- if (this->join_sta_bss < this->bss_cnt) {
- const int i = this->join_sta_bss;
- memcpy(this->bssid,
- this->bss_set[i].req.bssid, ETH_ALEN);
- this->chan = this->bss_set[i].req.ds_pset.chan;
- iw_copy_mgmt_info_element(&this->keep_essid.el,
- &this->bss_set[i].req.ssid.el);
- wl3501_mgmt_auth(this);
- }
- } else {
- const int i = this->join_sta_bss;
-
- memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN);
- this->chan = this->bss_set[i].req.ds_pset.chan;
- iw_copy_mgmt_info_element(&this->keep_essid.el,
- &this->bss_set[i].req.ssid.el);
- wl3501_online(dev);
- }
- } else {
- int i;
- this->join_sta_bss++;
- for (i = this->join_sta_bss; i < this->bss_cnt; i++)
- if (!wl3501_mgmt_join(this, i))
- break;
- this->join_sta_bss = i;
- if (this->join_sta_bss == this->bss_cnt) {
- if (this->net_type == IW_MODE_INFRA)
- wl3501_mgmt_scan(this, 100);
- else {
- this->adhoc_times++;
- if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES)
- wl3501_mgmt_start(this);
- else
- wl3501_mgmt_scan(this, 100);
- }
- }
- }
-}
-
-static inline void wl3501_alarm_interrupt(struct net_device *dev,
- struct wl3501_card *this)
-{
- if (this->net_type == IW_MODE_INFRA) {
- printk(KERN_INFO "Wireless LAN offline\n");
- netif_stop_queue(dev);
- wl3501_mgmt_resync(this);
- }
-}
-
-static inline void wl3501_md_confirm_interrupt(struct net_device *dev,
- struct wl3501_card *this,
- u16 addr)
-{
- struct wl3501_md_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- wl3501_free_tx_buffer(this, sig.data);
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
-}
-
-static inline void wl3501_md_ind_interrupt(struct net_device *dev,
- struct wl3501_card *this, u16 addr)
-{
- struct wl3501_md_ind sig;
- struct sk_buff *skb;
- u8 rssi, addr4[ETH_ALEN];
- u16 pkt_len;
-
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- this->start_seg = sig.data;
- wl3501_get_from_wla(this,
- sig.data + offsetof(struct wl3501_rx_hdr, rssi),
- &rssi, sizeof(rssi));
- this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255;
-
- wl3501_get_from_wla(this,
- sig.data +
- offsetof(struct wl3501_rx_hdr, addr4),
- &addr4, sizeof(addr4));
- if (!(addr4[0] == 0xAA && addr4[1] == 0xAA &&
- addr4[2] == 0x03 && addr4[4] == 0x00)) {
- printk(KERN_INFO "Unsupported packet type!\n");
- return;
- }
- pkt_len = sig.size + 12 - 24 - 4 - 6;
-
- skb = dev_alloc_skb(pkt_len + 5);
-
- if (!skb) {
- printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n",
- dev->name, pkt_len);
- dev->stats.rx_dropped++;
- } else {
- skb->dev = dev;
- skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */
- skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr,
- sizeof(sig.addr));
- wl3501_receive(this, skb->data, pkt_len);
- skb_put(skb, pkt_len);
- skb->protocol = eth_type_trans(skb, dev);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- }
-}
-
-static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this,
- u16 addr, void *sig, int size)
-{
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &this->sig_get_confirm,
- sizeof(this->sig_get_confirm));
- wake_up(&this->wait);
-}
-
-static inline void wl3501_start_confirm_interrupt(struct net_device *dev,
- struct wl3501_card *this,
- u16 addr)
-{
- struct wl3501_start_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- if (sig.status == WL3501_STATUS_SUCCESS)
- netif_wake_queue(dev);
-}
-
-static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev,
- u16 addr)
-{
- struct wl3501_card *this = netdev_priv(dev);
- struct wl3501_assoc_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
-
- if (sig.status == WL3501_STATUS_SUCCESS)
- wl3501_online(dev);
-}
-
-static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this,
- u16 addr)
-{
- struct wl3501_auth_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
-
- if (sig.status == WL3501_STATUS_SUCCESS)
- wl3501_mgmt_association(this);
- else
- wl3501_mgmt_resync(this);
-}
-
-static inline void wl3501_rx_interrupt(struct net_device *dev)
-{
- int morepkts;
- u16 addr;
- u8 sig_id;
- struct wl3501_card *this = netdev_priv(dev);
-
- pr_debug("entry");
-loop:
- morepkts = 0;
- if (!wl3501_esbq_confirm(this))
- goto free;
- wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr));
- wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id));
-
- switch (sig_id) {
- case WL3501_SIG_DEAUTH_IND:
- case WL3501_SIG_DISASSOC_IND:
- case WL3501_SIG_ALARM:
- wl3501_alarm_interrupt(dev, this);
- break;
- case WL3501_SIG_MD_CONFIRM:
- wl3501_md_confirm_interrupt(dev, this, addr);
- break;
- case WL3501_SIG_MD_IND:
- wl3501_md_ind_interrupt(dev, this, addr);
- break;
- case WL3501_SIG_GET_CONFIRM:
- wl3501_get_confirm_interrupt(this, addr,
- &this->sig_get_confirm,
- sizeof(this->sig_get_confirm));
- break;
- case WL3501_SIG_PWR_MGMT_CONFIRM:
- wl3501_get_confirm_interrupt(this, addr,
- &this->sig_pwr_mgmt_confirm,
- sizeof(this->sig_pwr_mgmt_confirm));
- break;
- case WL3501_SIG_START_CONFIRM:
- wl3501_start_confirm_interrupt(dev, this, addr);
- break;
- case WL3501_SIG_SCAN_CONFIRM:
- wl3501_mgmt_scan_confirm(this, addr);
- break;
- case WL3501_SIG_JOIN_CONFIRM:
- wl3501_mgmt_join_confirm(dev, addr);
- break;
- case WL3501_SIG_ASSOC_CONFIRM:
- wl3501_assoc_confirm_interrupt(dev, addr);
- break;
- case WL3501_SIG_AUTH_CONFIRM:
- wl3501_auth_confirm_interrupt(this, addr);
- break;
- case WL3501_SIG_RESYNC_CONFIRM:
- wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */
- break;
- }
- wl3501_esbq_confirm_done(this);
- morepkts = 1;
- /* free request if necessary */
-free:
- wl3501_esbq_req_free(this);
- if (morepkts)
- goto loop;
-}
-
-static inline void wl3501_ack_interrupt(struct wl3501_card *this)
-{
- wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR);
-}
-
-/**
- * wl3501_interrupt - Hardware interrupt from card.
- * @irq: Interrupt number
- * @dev_id: net_device
- *
- * We must acknowledge the interrupt as soon as possible, and block the
- * interrupt from the same card immediately to prevent re-entry.
- *
- * Before accessing the Control_Status_Block, we must lock SUTRO first.
- * On the other hand, to prevent SUTRO from malfunctioning, we must
- * unlock the SUTRO as soon as possible.
- */
-static irqreturn_t wl3501_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct wl3501_card *this;
-
- this = netdev_priv(dev);
- spin_lock(&this->lock);
- wl3501_ack_interrupt(this);
- wl3501_block_interrupt(this);
- wl3501_rx_interrupt(dev);
- wl3501_unblock_interrupt(this);
- spin_unlock(&this->lock);
-
- return IRQ_HANDLED;
-}
-
-static int wl3501_reset_board(struct wl3501_card *this)
-{
- u8 tmp = 0;
- int i, rc = 0;
-
- /* Coreset */
- wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR);
- wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR);
- wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR);
-
- /* Reset SRAM 0x480 to zero */
- wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp));
-
- /* Start up */
- wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR);
-
- WL3501_NOPLOOP(1024 * 50);
-
- wl3501_unblock_interrupt(this); /* acme: was commented */
-
- /* Polling Self_Test_Status */
- for (i = 0; i < 10000; i++) {
- wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp));
-
- if (tmp == 'W') {
- /* firmware complete all test successfully */
- tmp = 'A';
- wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp));
- goto out;
- }
- WL3501_NOPLOOP(10);
- }
- printk(KERN_WARNING "%s: failed to reset the board!\n", __func__);
- rc = -ENODEV;
-out:
- return rc;
-}
-
-static int wl3501_init_firmware(struct wl3501_card *this)
-{
- u16 ptr, next;
- int rc = wl3501_reset_board(this);
-
- if (rc)
- goto fail;
- this->card_name[0] = '\0';
- wl3501_get_from_wla(this, 0x1a00,
- this->card_name, sizeof(this->card_name));
- this->card_name[sizeof(this->card_name) - 1] = '\0';
- this->firmware_date[0] = '\0';
- wl3501_get_from_wla(this, 0x1a40,
- this->firmware_date, sizeof(this->firmware_date));
- this->firmware_date[sizeof(this->firmware_date) - 1] = '\0';
- /* Switch to SRAM Page 0 */
- wl3501_switch_page(this, WL3501_BSS_SPAGE0);
- /* Read parameter from card */
- wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2);
- wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2);
- wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2);
- wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2);
- wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2);
- wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2);
- this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start;
- this->esbq_req_end += this->esbq_req_start;
- this->esbq_confirm = this->esbq_confirm_start;
- this->esbq_confirm_end += this->esbq_confirm_start;
- /* Initial Tx Buffer */
- this->tx_buffer_cnt = 1;
- ptr = this->tx_buffer_head;
- next = ptr + WL3501_BLKSZ;
- while ((next - this->tx_buffer_head) < this->tx_buffer_size) {
- this->tx_buffer_cnt++;
- wl3501_set_to_wla(this, ptr, &next, sizeof(next));
- ptr = next;
- next = ptr + WL3501_BLKSZ;
- }
- rc = 0;
- next = 0;
- wl3501_set_to_wla(this, ptr, &next, sizeof(next));
- this->tx_buffer_tail = ptr;
-out:
- return rc;
-fail:
- printk(KERN_WARNING "%s: failed!\n", __func__);
- goto out;
-}
-
-static int wl3501_close(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
- struct pcmcia_device *link;
- link = this->p_dev;
-
- spin_lock_irqsave(&this->lock, flags);
- link->open--;
-
- /* Stop wl3501_hard_start_xmit() from now on */
- netif_stop_queue(dev);
- wl3501_ack_interrupt(this);
-
- /* Mask interrupts from the SUTRO */
- wl3501_block_interrupt(this);
-
- printk(KERN_INFO "%s: WL3501 closed\n", dev->name);
- spin_unlock_irqrestore(&this->lock, flags);
- return 0;
-}
-
-/**
- * wl3501_reset - Reset the SUTRO.
- * @dev: network device
- *
- * It is almost the same as wl3501_open(). In fact, we may just wl3501_close()
- * and wl3501_open() again, but I wouldn't like to free_irq() when the driver
- * is running. It seems to be dangerous.
- */
-static int wl3501_reset(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int rc = -ENODEV;
- unsigned long flags;
-
- spin_lock_irqsave(&this->lock, flags);
- wl3501_block_interrupt(this);
-
- if (wl3501_init_firmware(this)) {
- printk(KERN_WARNING "%s: Can't initialize Firmware!\n",
- dev->name);
- /* Free IRQ, and mark IRQ as unused */
- free_irq(dev->irq, dev);
- goto out;
- }
-
- /*
- * Queue has to be started only when the Card is Started
- */
- netif_stop_queue(dev);
- this->adhoc_times = 0;
- wl3501_ack_interrupt(this);
- wl3501_unblock_interrupt(this);
- wl3501_mgmt_scan(this, 100);
- pr_debug("%s: device reset", dev->name);
- rc = 0;
-out:
- spin_unlock_irqrestore(&this->lock, flags);
- return rc;
-}
-
-static void wl3501_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct net_device_stats *stats = &dev->stats;
- int rc;
-
- stats->tx_errors++;
- rc = wl3501_reset(dev);
- if (rc)
- printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
- dev->name, rc);
- else {
- netif_trans_update(dev); /* prevent tx timeout */
- netif_wake_queue(dev);
- }
-}
-
-/*
- * Return : 0 - OK
- * 1 - Could not transmit (dev_queue_xmit will queue it)
- * and try to sent it later
- */
-static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- int enabled, rc;
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&this->lock, flags);
- enabled = wl3501_block_interrupt(this);
- rc = wl3501_send_pkt(this, skb->data, skb->len);
- if (enabled)
- wl3501_unblock_interrupt(this);
- if (rc) {
- ++dev->stats.tx_dropped;
- netif_stop_queue(dev);
- } else {
- ++dev->stats.tx_packets;
- dev->stats.tx_bytes += skb->len;
- dev_kfree_skb_irq(skb);
-
- if (this->tx_buffer_cnt < 2)
- netif_stop_queue(dev);
- }
- spin_unlock_irqrestore(&this->lock, flags);
- return NETDEV_TX_OK;
-}
-
-static int wl3501_open(struct net_device *dev)
-{
- int rc = -ENODEV;
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
- struct pcmcia_device *link;
- link = this->p_dev;
-
- spin_lock_irqsave(&this->lock, flags);
- if (!pcmcia_dev_present(link))
- goto out;
- netif_device_attach(dev);
- link->open++;
-
- /* Initial WL3501 firmware */
- pr_debug("%s: Initialize WL3501 firmware...", dev->name);
- if (wl3501_init_firmware(this))
- goto fail;
- /* Initial device variables */
- this->adhoc_times = 0;
- /* Acknowledge Interrupt, for cleaning last state */
- wl3501_ack_interrupt(this);
-
- /* Enable interrupt from card after all */
- wl3501_unblock_interrupt(this);
- wl3501_mgmt_scan(this, 100);
- rc = 0;
- pr_debug("%s: WL3501 opened", dev->name);
- printk(KERN_INFO "%s: Card Name: %s\n"
- "%s: Firmware Date: %s\n",
- dev->name, this->card_name,
- dev->name, this->firmware_date);
-out:
- spin_unlock_irqrestore(&this->lock, flags);
- return rc;
-fail:
- printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name);
- goto out;
-}
-
-static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
- struct iw_statistics *wstats = &this->wstats;
- u32 value; /* size checked: it is u32 */
-
- memset(wstats, 0, sizeof(*wstats));
- wstats->status = netif_running(dev);
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT,
- &value, sizeof(value)))
- wstats->discard.code += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT,
- &value, sizeof(value)))
- wstats->discard.code += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT,
- &value, sizeof(value)))
- wstats->discard.code += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT,
- &value, sizeof(value)))
- wstats->discard.retries = value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- return wstats;
-}
-
-/**
- * wl3501_detach - deletes a driver "instance"
- * @link: FILL_IN
- *
- * This deletes a driver "instance". The device is de-registered with Card
- * Services. If it has been released, all local data structures are freed.
- * Otherwise, the structures will be freed when the device is released.
- */
-static void wl3501_detach(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- /* If the device is currently configured and active, we won't actually
- * delete it yet. Instead, it is marked so that when the release()
- * function is called, that will trigger a proper detach(). */
-
- while (link->open > 0)
- wl3501_close(dev);
-
- netif_device_detach(dev);
- wl3501_release(link);
-
- unregister_netdev(dev);
- free_netdev(dev);
-}
-
-static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- strscpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name));
- return 0;
-}
-
-static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int channel = wrqu->freq.m;
- int rc = -EINVAL;
-
- if (iw_valid_channel(this->reg_domain, channel)) {
- this->chan = channel;
- rc = wl3501_reset(dev);
- }
- return rc;
-}
-
-static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->freq.m = 100000 *
- ieee80211_channel_to_frequency(this->chan, NL80211_BAND_2GHZ);
- wrqu->freq.e = 1;
- return 0;
-}
-
-static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int rc = -EINVAL;
-
- if (wrqu->mode == IW_MODE_INFRA ||
- wrqu->mode == IW_MODE_ADHOC ||
- wrqu->mode == IW_MODE_AUTO) {
- struct wl3501_card *this = netdev_priv(dev);
-
- this->net_type = wrqu->mode;
- rc = wl3501_reset(dev);
- }
- return rc;
-}
-
-static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->mode = this->net_type;
- return 0;
-}
-
-static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->sens.value = this->rssi;
- wrqu->sens.disabled = !wrqu->sens.value;
- wrqu->sens.fixed = 1;
- return 0;
-}
-
-static int wl3501_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_range *range = (struct iw_range *)extra;
-
- /* Set the length (very important for backward compatibility) */
- wrqu->data.length = sizeof(*range);
-
- /* Set all the info we don't care or don't know about to zero */
- memset(range, 0, sizeof(*range));
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 1;
- range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */
- /* FIXME: study the code to fill in more fields... */
- return 0;
-}
-
-static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int rc = -EINVAL;
-
- /* FIXME: we support other ARPHRDs...*/
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- goto out;
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) {
- /* FIXME: rescan? */
- } else
- memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
- /* FIXME: rescan? deassoc & scan? */
- rc = 0;
-out:
- return rc;
-}
-
-static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN);
- return 0;
-}
-
-static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * FIXME: trigger scanning with a reset, yes, I'm lazy
- */
- return wl3501_reset(dev);
-}
-
-static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int i;
- char *current_ev = extra;
- struct iw_event iwe;
-
- for (i = 0; i < this->bss_cnt; ++i) {
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_ADDR_LEN);
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- iwe.u.data.length = this->bss_set[i].req.ssid.el.len;
- current_ev = iwe_stream_add_point(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe,
- this->bss_set[i].req.ssid.essid);
- iwe.cmd = SIOCGIWMODE;
- iwe.u.mode = this->bss_set[i].req.bss_type;
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_UINT_LEN);
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_FREQ_LEN);
- iwe.cmd = SIOCGIWENCODE;
- if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, NULL);
- }
- /* Length of data */
- wrqu->data.length = (current_ev - extra);
- wrqu->data.flags = 0; /* FIXME: set properly these flags */
- return 0;
-}
-
-static int wl3501_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- if (wrqu->data.flags) {
- iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
- &this->essid.el,
- extra, wrqu->data.length);
- } else { /* We accept any ESSID */
- iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
- &this->essid.el, "ANY", 3);
- }
- return wl3501_reset(dev);
-}
-
-static int wl3501_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&this->lock, flags);
- wrqu->essid.flags = 1;
- wrqu->essid.length = this->essid.el.len;
- memcpy(extra, this->essid.essid, this->essid.el.len);
- spin_unlock_irqrestore(&this->lock, flags);
- return 0;
-}
-
-static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- if (wrqu->data.length > sizeof(this->nick))
- return -E2BIG;
- strscpy(this->nick, extra, wrqu->data.length);
- return 0;
-}
-
-static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- strscpy(extra, this->nick, 32);
- wrqu->data.length = strlen(extra);
- return 0;
-}
-
-static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * FIXME: have to see from where to get this info, perhaps this card
- * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most
- * common with the Planet Access Points. -acme
- */
- wrqu->bitrate.value = 2000000;
- wrqu->bitrate.fixed = 1;
- return 0;
-}
-
-static int wl3501_get_rts_threshold(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD,
- &threshold, sizeof(threshold));
- if (!rc) {
- wrqu->rts.value = threshold;
- wrqu->rts.disabled = threshold >= 2347;
- wrqu->rts.fixed = 1;
- }
- return rc;
-}
-
-static int wl3501_get_frag_threshold(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD,
- &threshold, sizeof(threshold));
- if (!rc) {
- wrqu->frag.value = threshold;
- wrqu->frag.disabled = threshold >= 2346;
- wrqu->frag.fixed = 1;
- }
- return rc;
-}
-
-static int wl3501_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u16 txpow;
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
- &txpow, sizeof(txpow));
- if (!rc) {
- wrqu->txpower.value = txpow;
- wrqu->txpower.disabled = 0;
- /*
- * From the MIB values I think this can be configurable,
- * as it lists several tx power levels -acme
- */
- wrqu->txpower.fixed = 0;
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- }
- return rc;
-}
-
-static int wl3501_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 retry; /* size checked: it is u8 */
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
- &retry, sizeof(retry));
- if (rc)
- goto out;
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- goto set_value;
- }
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
- &retry, sizeof(retry));
- if (rc)
- goto out;
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
-set_value:
- wrqu->retry.value = retry;
- wrqu->retry.disabled = 0;
-out:
- return rc;
-}
-
-static int wl3501_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 implemented, restricted, keys[100], len_keys, tocopy;
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
- &implemented, sizeof(implemented));
- if (rc)
- goto out;
- if (!implemented) {
- wrqu->encoding.flags = IW_ENCODE_DISABLED;
- goto out;
- }
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED,
- &restricted, sizeof(restricted));
- if (rc)
- goto out;
- wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED :
- IW_ENCODE_OPEN;
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN,
- &len_keys, sizeof(len_keys));
- if (rc)
- goto out;
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS,
- keys, len_keys);
- if (rc)
- goto out;
- tocopy = min_t(u16, len_keys, wrqu->encoding.length);
- tocopy = min_t(u8, tocopy, 100);
- wrqu->encoding.length = tocopy;
- memcpy(extra, keys, tocopy);
-out:
- return rc;
-}
-
-static int wl3501_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 pwr_state;
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_CURRENT_PWR_STATE,
- &pwr_state, sizeof(pwr_state));
- if (rc)
- goto out;
- wrqu->power.disabled = !pwr_state;
- wrqu->power.flags = IW_POWER_ON;
-out:
- return rc;
-}
-
-static const iw_handler wl3501_handler[] = {
- IW_HANDLER(SIOCGIWNAME, wl3501_get_name),
- IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq),
- IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq),
- IW_HANDLER(SIOCSIWMODE, wl3501_set_mode),
- IW_HANDLER(SIOCGIWMODE, wl3501_get_mode),
- IW_HANDLER(SIOCGIWSENS, wl3501_get_sens),
- IW_HANDLER(SIOCGIWRANGE, wl3501_get_range),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, wl3501_set_wap),
- IW_HANDLER(SIOCGIWAP, wl3501_get_wap),
- IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan),
- IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan),
- IW_HANDLER(SIOCSIWESSID, wl3501_set_essid),
- IW_HANDLER(SIOCGIWESSID, wl3501_get_essid),
- IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick),
- IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick),
- IW_HANDLER(SIOCGIWRATE, wl3501_get_rate),
- IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold),
- IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold),
- IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow),
- IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry),
- IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode),
- IW_HANDLER(SIOCGIWPOWER, wl3501_get_power),
-};
-
-static const struct iw_handler_def wl3501_handler_def = {
- .num_standard = ARRAY_SIZE(wl3501_handler),
- .standard = (iw_handler *)wl3501_handler,
- .get_wireless_stats = wl3501_get_wireless_stats,
-};
-
-static const struct net_device_ops wl3501_netdev_ops = {
- .ndo_open = wl3501_open,
- .ndo_stop = wl3501_close,
- .ndo_start_xmit = wl3501_hard_start_xmit,
- .ndo_tx_timeout = wl3501_tx_timeout,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int wl3501_probe(struct pcmcia_device *p_dev)
-{
- struct net_device *dev;
- struct wl3501_card *this;
- int ret;
-
- /* The io structure describes IO port mapping */
- p_dev->resource[0]->end = 16;
- p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8;
-
- /* General socket configuration */
- p_dev->config_flags = CONF_ENABLE_IRQ;
- p_dev->config_index = 1;
-
- dev = alloc_etherdev(sizeof(struct wl3501_card));
- if (!dev)
- return -ENOMEM;
-
- dev->netdev_ops = &wl3501_netdev_ops;
- dev->watchdog_timeo = 5 * HZ;
-
- this = netdev_priv(dev);
- this->wireless_data.spy_data = &this->spy_data;
- this->p_dev = p_dev;
- dev->wireless_data = &this->wireless_data;
- dev->wireless_handlers = &wl3501_handler_def;
- netif_stop_queue(dev);
- p_dev->priv = dev;
-
- ret = wl3501_config(p_dev);
- if (ret)
- goto out_free_etherdev;
-
- return 0;
-
-out_free_etherdev:
- free_netdev(dev);
- return ret;
-}
-
-static int wl3501_config(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
- int i = 0, j, ret;
- struct wl3501_card *this;
-
- /* Try allocating IO ports. This tries a few fixed addresses. If you
- * want, you can also read the card's config table to pick addresses --
- * see the serial driver for an example. */
- link->io_lines = 5;
-
- for (j = 0x280; j < 0x400; j += 0x20) {
- /* The '^0x300' is so that we probe 0x300-0x3ff first, then
- * 0x200-0x2ff, and so on, because this seems safer */
- link->resource[0]->start = j;
- link->resource[1]->start = link->resource[0]->start + 0x10;
- i = pcmcia_request_io(link);
- if (i == 0)
- break;
- }
- if (i != 0)
- goto failed;
-
- /* Now allocate an interrupt line. Note that this does not actually
- * assign a handler to the interrupt. */
-
- ret = pcmcia_request_irq(link, wl3501_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- SET_NETDEV_DEV(dev, &link->dev);
- if (register_netdev(dev)) {
- printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n");
- goto failed;
- }
-
- this = netdev_priv(dev);
-
- this->base_addr = dev->base_addr;
-
- if (!wl3501_get_flash_mac_addr(this)) {
- printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n",
- dev->name);
- unregister_netdev(dev);
- goto failed;
- }
-
- eth_hw_addr_set(dev, this->mac_addr);
-
- /* print probe information */
- printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
- "MAC addr in flash ROM:%pM\n",
- dev->name, this->base_addr, (int)dev->irq,
- dev->dev_addr);
- /*
- * Initialize card parameters - added by jss
- */
- this->net_type = IW_MODE_INFRA;
- this->bss_cnt = 0;
- this->join_sta_bss = 0;
- this->adhoc_times = 0;
- iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el,
- "ANY", 3);
- this->card_name[0] = '\0';
- this->firmware_date[0] = '\0';
- this->rssi = 255;
- this->chan = iw_default_channel(this->reg_domain);
- strscpy(this->nick, "Planet WL3501", sizeof(this->nick));
- spin_lock_init(&this->lock);
- init_waitqueue_head(&this->wait);
- netif_start_queue(dev);
- return 0;
-
-failed:
- wl3501_release(link);
- return -ENODEV;
-}
-
-static void wl3501_release(struct pcmcia_device *link)
-{
- pcmcia_disable_device(link);
-}
-
-static int wl3501_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND);
- if (link->open)
- netif_device_detach(dev);
-
- return 0;
-}
-
-static int wl3501_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME);
- if (link->open) {
- wl3501_reset(dev);
- netif_device_attach(dev);
- }
-
- return 0;
-}
-
-
-static const struct pcmcia_device_id wl3501_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
-
-static struct pcmcia_driver wl3501_driver = {
- .owner = THIS_MODULE,
- .name = "wl3501_cs",
- .probe = wl3501_probe,
- .remove = wl3501_detach,
- .id_table = wl3501_ids,
- .suspend = wl3501_suspend,
- .resume = wl3501_resume,
-};
-module_pcmcia_driver(wl3501_driver);
-
-MODULE_AUTHOR("Fox Chen <mhchen@golf.ccl.itri.org.tw>, "
- "Arnaldo Carvalho de Melo <acme@conectiva.com.br>,"
- "Gustavo Niemeyer <niemeyer@conectiva.com>");
-MODULE_DESCRIPTION("Planet wl3501 wireless driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig
index 6d62ab49aa8d..36b234bc5be8 100644
--- a/drivers/net/wireless/marvell/libertas/Kconfig
+++ b/drivers/net/wireless/marvell/libertas/Kconfig
@@ -1,9 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
config LIBERTAS
tristate "Marvell 8xxx Libertas WLAN driver support"
+ depends on USB || MMC || SPI
depends on CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
select LIB80211
select FW_LOADER
help
@@ -15,12 +14,6 @@ config LIBERTAS_USB
help
A driver for Marvell Libertas 8388 USB devices.
-config LIBERTAS_CS
- tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
- depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP
- help
- A driver for Marvell Libertas 8385 CompactFlash devices.
-
config LIBERTAS_SDIO
tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
depends on LIBERTAS && MMC
diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile
index 41b9b440a542..2ac04f4d61a5 100644
--- a/drivers/net/wireless/marvell/libertas/Makefile
+++ b/drivers/net/wireless/marvell/libertas/Makefile
@@ -17,6 +17,5 @@ libertas_spi-objs += if_spi.o
obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
-obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o
diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c
deleted file mode 100644
index 4103f15bca6b..000000000000
--- a/drivers/net/wireless/marvell/libertas/if_cs.c
+++ /dev/null
@@ -1,957 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
-
- Driver for the Marvell 8385 based compact flash WLAN cards.
-
- (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
-
-
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/moduleparam.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#include <linux/io.h>
-
-#define DRV_NAME "libertas_cs"
-
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-
-
-/********************************************************************/
-/* Module stuff */
-/********************************************************************/
-
-MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
-MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
-MODULE_LICENSE("GPL");
-
-
-
-/********************************************************************/
-/* Data structures */
-/********************************************************************/
-
-struct if_cs_card {
- struct pcmcia_device *p_dev;
- struct lbs_private *priv;
- void __iomem *iobase;
- bool align_regs;
- u32 model;
-};
-
-
-enum {
- MODEL_UNKNOWN = 0x00,
- MODEL_8305 = 0x01,
- MODEL_8381 = 0x02,
- MODEL_8385 = 0x03
-};
-
-static const struct lbs_fw_table fw_table[] = {
- { MODEL_8305, "libertas/cf8305.bin", NULL },
- { MODEL_8305, "libertas_cs_helper.fw", NULL },
- { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
- { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
- { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
- { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
- { 0, NULL, NULL }
-};
-MODULE_FIRMWARE("libertas/cf8305.bin");
-MODULE_FIRMWARE("libertas/cf8381_helper.bin");
-MODULE_FIRMWARE("libertas/cf8381.bin");
-MODULE_FIRMWARE("libertas/cf8385_helper.bin");
-MODULE_FIRMWARE("libertas/cf8385.bin");
-MODULE_FIRMWARE("libertas_cs_helper.fw");
-MODULE_FIRMWARE("libertas_cs.fw");
-
-
-/********************************************************************/
-/* Hardware access */
-/********************************************************************/
-
-/* This define enables wrapper functions which allow you
- to dump all register accesses. You normally won't this,
- except for development */
-/* #define DEBUG_IO */
-
-#ifdef DEBUG_IO
-static int debug_output = 0;
-#else
-/* This way the compiler optimizes the printk's away */
-#define debug_output 0
-#endif
-
-static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
-{
- unsigned int val = ioread8(card->iobase + reg);
- if (debug_output)
- printk(KERN_INFO "inb %08x<%02x\n", reg, val);
- return val;
-}
-static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
-{
- unsigned int val = ioread16(card->iobase + reg);
- if (debug_output)
- printk(KERN_INFO "inw %08x<%04x\n", reg, val);
- return val;
-}
-static inline void if_cs_read16_rep(
- struct if_cs_card *card,
- uint reg,
- void *buf,
- unsigned long count)
-{
- if (debug_output)
- printk(KERN_INFO "insw %08x<(0x%lx words)\n",
- reg, count);
- ioread16_rep(card->iobase + reg, buf, count);
-}
-
-static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
-{
- if (debug_output)
- printk(KERN_INFO "outb %08x>%02x\n", reg, val);
- iowrite8(val, card->iobase + reg);
-}
-
-static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
-{
- if (debug_output)
- printk(KERN_INFO "outw %08x>%04x\n", reg, val);
- iowrite16(val, card->iobase + reg);
-}
-
-static inline void if_cs_write16_rep(
- struct if_cs_card *card,
- uint reg,
- const void *buf,
- unsigned long count)
-{
- if (debug_output)
- printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
- reg, count);
- iowrite16_rep(card->iobase + reg, buf, count);
-}
-
-
-/*
- * I know that polling/delaying is frowned upon. However, this procedure
- * with polling is needed while downloading the firmware. At this stage,
- * the hardware does unfortunately not create any interrupts.
- *
- * Fortunately, this function is never used once the firmware is in
- * the card. :-)
- *
- * As a reference, see the "Firmware Specification v5.1", page 18
- * and 19. I did not follow their suggested timing to the word,
- * but this works nice & fast anyway.
- */
-static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
-{
- int i;
-
- for (i = 0; i < 100000; i++) {
- u8 val = if_cs_read8(card, addr);
- if (val == reg)
- return 0;
- udelay(5);
- }
- return -ETIME;
-}
-
-
-
-/*
- * First the bitmasks for the host/card interrupt/status registers:
- */
-#define IF_CS_BIT_TX 0x0001
-#define IF_CS_BIT_RX 0x0002
-#define IF_CS_BIT_COMMAND 0x0004
-#define IF_CS_BIT_RESP 0x0008
-#define IF_CS_BIT_EVENT 0x0010
-#define IF_CS_BIT_MASK 0x001f
-
-
-
-/*
- * It's not really clear to me what the host status register is for. It
- * needs to be set almost in union with "host int cause". The following
- * bits from above are used:
- *
- * IF_CS_BIT_TX driver downloaded a data packet
- * IF_CS_BIT_RX driver got a data packet
- * IF_CS_BIT_COMMAND driver downloaded a command
- * IF_CS_BIT_RESP not used (has some meaning with powerdown)
- * IF_CS_BIT_EVENT driver read a host event
- */
-#define IF_CS_HOST_STATUS 0x00000000
-
-/*
- * With the host int cause register can the host (that is, Linux) cause
- * an interrupt in the firmware, to tell the firmware about those events:
- *
- * IF_CS_BIT_TX a data packet has been downloaded
- * IF_CS_BIT_RX a received data packet has retrieved
- * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded
- * IF_CS_BIT_RESP not used (has some meaning with powerdown)
- * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved
- */
-#define IF_CS_HOST_INT_CAUSE 0x00000002
-
-/*
- * The host int mask register is used to enable/disable interrupt. However,
- * I have the suspicion that disabled interrupts are lost.
- */
-#define IF_CS_HOST_INT_MASK 0x00000004
-
-/*
- * Used to send or receive data packets:
- */
-#define IF_CS_WRITE 0x00000016
-#define IF_CS_WRITE_LEN 0x00000014
-#define IF_CS_READ 0x00000010
-#define IF_CS_READ_LEN 0x00000024
-
-/*
- * Used to send commands (and to send firmware block) and to
- * receive command responses:
- */
-#define IF_CS_CMD 0x0000001A
-#define IF_CS_CMD_LEN 0x00000018
-#define IF_CS_RESP 0x00000012
-#define IF_CS_RESP_LEN 0x00000030
-
-/*
- * The card status registers shows what the card/firmware actually
- * accepts:
- *
- * IF_CS_BIT_TX you may send a data packet
- * IF_CS_BIT_RX you may retrieve a data packet
- * IF_CS_BIT_COMMAND you may send a command
- * IF_CS_BIT_RESP you may retrieve a command response
- * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc)
- *
- * When reading this register several times, you will get back the same
- * results --- with one exception: the IF_CS_BIT_EVENT clear itself
- * automatically.
- *
- * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because
- * we handle this via the card int cause register.
- */
-#define IF_CS_CARD_STATUS 0x00000020
-#define IF_CS_CARD_STATUS_MASK 0x7f00
-
-/*
- * The card int cause register is used by the card/firmware to notify us
- * about the following events:
- *
- * IF_CS_BIT_TX a data packet has successfully been sentx
- * IF_CS_BIT_RX a data packet has been received and can be retrieved
- * IF_CS_BIT_COMMAND not used
- * IF_CS_BIT_RESP the firmware has a command response for us
- * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc)
- */
-#define IF_CS_CARD_INT_CAUSE 0x00000022
-
-/*
- * This is used to for handshaking with the card's bootloader/helper image
- * to synchronize downloading of firmware blocks.
- */
-#define IF_CS_SQ_READ_LOW 0x00000028
-#define IF_CS_SQ_HELPER_OK 0x10
-
-/*
- * The scratch register tells us ...
- *
- * IF_CS_SCRATCH_BOOT_OK the bootloader runs
- * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs
- */
-#define IF_CS_SCRATCH 0x0000003F
-#define IF_CS_SCRATCH_BOOT_OK 0x00
-#define IF_CS_SCRATCH_HELPER_OK 0x5a
-
-/*
- * Used to detect ancient chips:
- */
-#define IF_CS_PRODUCT_ID 0x0000001C
-#define IF_CS_CF8385_B1_REV 0x12
-#define IF_CS_CF8381_B3_REV 0x04
-#define IF_CS_CF8305_B1_REV 0x03
-
-/*
- * Used to detect other cards than CF8385 since their revisions of silicon
- * doesn't match those from CF8385, eg. CF8381 B3 works with this driver.
- */
-#define CF8305_MANFID 0x02db
-#define CF8305_CARDID 0x8103
-#define CF8381_MANFID 0x02db
-#define CF8381_CARDID 0x6064
-#define CF8385_MANFID 0x02df
-#define CF8385_CARDID 0x8103
-
-/*
- * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
- * that gets fixed. Currently there's no way to access it from the probe hook.
- */
-static inline u32 get_model(u16 manf_id, u16 card_id)
-{
- /* NOTE: keep in sync with if_cs_ids */
- if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
- return MODEL_8305;
- else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
- return MODEL_8381;
- else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
- return MODEL_8385;
- return MODEL_UNKNOWN;
-}
-
-/********************************************************************/
-/* I/O and interrupt handling */
-/********************************************************************/
-
-static inline void if_cs_enable_ints(struct if_cs_card *card)
-{
- if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
-}
-
-static inline void if_cs_disable_ints(struct if_cs_card *card)
-{
- if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
-}
-
-/*
- * Called from if_cs_host_to_card to send a command to the hardware
- */
-static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
-{
- struct if_cs_card *card = (struct if_cs_card *)priv->card;
- int ret = -1;
- int loops = 0;
-
- if_cs_disable_ints(card);
-
- /* Is hardware ready? */
- while (1) {
- u16 status = if_cs_read16(card, IF_CS_CARD_STATUS);
- if (status & IF_CS_BIT_COMMAND)
- break;
- if (++loops > 100) {
- netdev_err(priv->dev, "card not ready for commands\n");
- goto done;
- }
- mdelay(1);
- }
-
- if_cs_write16(card, IF_CS_CMD_LEN, nb);
-
- if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2);
- /* Are we supposed to transfer an odd amount of bytes? */
- if (nb & 1)
- if_cs_write8(card, IF_CS_CMD, buf[nb-1]);
-
- /* "Assert the download over interrupt command in the Host
- * status register" */
- if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
-
- /* "Assert the download over interrupt command in the Card
- * interrupt case register" */
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
- ret = 0;
-
-done:
- if_cs_enable_ints(card);
- return ret;
-}
-
-/*
- * Called from if_cs_host_to_card to send a data to the hardware
- */
-static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
-{
- struct if_cs_card *card = (struct if_cs_card *)priv->card;
- u16 status;
-
- if_cs_disable_ints(card);
-
- status = if_cs_read16(card, IF_CS_CARD_STATUS);
- BUG_ON((status & IF_CS_BIT_TX) == 0);
-
- if_cs_write16(card, IF_CS_WRITE_LEN, nb);
-
- /* write even number of bytes, then odd byte if necessary */
- if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2);
- if (nb & 1)
- if_cs_write8(card, IF_CS_WRITE, buf[nb-1]);
-
- if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
- if_cs_enable_ints(card);
-}
-
-/*
- * Get the command result out of the card.
- */
-static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
-{
- unsigned long flags;
- int ret = -1;
- u16 status;
-
- /* is hardware ready? */
- status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
- if ((status & IF_CS_BIT_RESP) == 0) {
- netdev_err(priv->dev, "no cmd response in card\n");
- *len = 0;
- goto out;
- }
-
- *len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
- if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
- netdev_err(priv->dev,
- "card cmd buffer has invalid # of bytes (%d)\n",
- *len);
- goto out;
- }
-
- /* read even number of bytes, then odd byte if necessary */
- if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16));
- if (*len & 1)
- data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP);
-
- /* This is a workaround for a firmware that reports too much
- * bytes */
- *len -= 8;
- ret = 0;
-
- /* Clear this flag again */
- spin_lock_irqsave(&priv->driver_lock, flags);
- priv->dnld_sent = DNLD_RES_RECEIVED;
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-out:
- return ret;
-}
-
-static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
-{
- struct sk_buff *skb = NULL;
- u16 len;
- u8 *data;
-
- len = if_cs_read16(priv->card, IF_CS_READ_LEN);
- if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- netdev_err(priv->dev,
- "card data buffer has invalid # of bytes (%d)\n",
- len);
- priv->dev->stats.rx_dropped++;
- goto dat_err;
- }
-
- skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
- if (!skb)
- goto out;
- skb_put(skb, len);
- skb_reserve(skb, 2);/* 16 byte align */
- data = skb->data;
-
- /* read even number of bytes, then odd byte if necessary */
- if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
- if (len & 1)
- data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
-
-dat_err:
- if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
- if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
-
-out:
- return skb;
-}
-
-static irqreturn_t if_cs_interrupt(int irq, void *data)
-{
- struct if_cs_card *card = data;
- struct lbs_private *priv = card->priv;
- u16 cause;
-
- /* Ask card interrupt cause register if there is something for us */
- cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
- lbs_deb_cs("cause 0x%04x\n", cause);
-
- if (cause == 0) {
- /* Not for us */
- return IRQ_NONE;
- }
-
- if (cause == 0xffff) {
- /* Read in junk, the card has probably been removed */
- card->priv->surpriseremoved = 1;
- return IRQ_HANDLED;
- }
-
- if (cause & IF_CS_BIT_RX) {
- struct sk_buff *skb;
- lbs_deb_cs("rx packet\n");
- skb = if_cs_receive_data(priv);
- if (skb)
- lbs_process_rxed_packet(priv, skb);
- }
-
- if (cause & IF_CS_BIT_TX) {
- lbs_deb_cs("tx done\n");
- lbs_host_to_card_done(priv);
- }
-
- if (cause & IF_CS_BIT_RESP) {
- unsigned long flags;
- u8 i;
-
- lbs_deb_cs("cmd resp\n");
- spin_lock_irqsave(&priv->driver_lock, flags);
- i = (priv->resp_idx == 0) ? 1 : 0;
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
- BUG_ON(priv->resp_len[i]);
- if_cs_receive_cmdres(priv, priv->resp_buf[i],
- &priv->resp_len[i]);
-
- spin_lock_irqsave(&priv->driver_lock, flags);
- lbs_notify_command_response(priv, i);
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- }
-
- if (cause & IF_CS_BIT_EVENT) {
- u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
- if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
- IF_CS_BIT_EVENT);
- lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8);
- }
-
- /* Clear interrupt cause */
- if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
-
- return IRQ_HANDLED;
-}
-
-
-
-
-/********************************************************************/
-/* Firmware */
-/********************************************************************/
-
-/*
- * Tries to program the helper firmware.
- *
- * Return 0 on success
- */
-static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
-{
- int ret = 0;
- int sent = 0;
- u8 scratch;
-
- /*
- * This is the only place where an unaligned register access happens on
- * the CF8305 card, therefore for the sake of speed of the driver, we do
- * the alignment correction here.
- */
- if (card->align_regs)
- scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8;
- else
- scratch = if_cs_read8(card, IF_CS_SCRATCH);
-
- /* "If the value is 0x5a, the firmware is already
- * downloaded successfully"
- */
- if (scratch == IF_CS_SCRATCH_HELPER_OK)
- goto done;
-
- /* "If the value is != 00, it is invalid value of register */
- if (scratch != IF_CS_SCRATCH_BOOT_OK) {
- ret = -ENODEV;
- goto done;
- }
-
- lbs_deb_cs("helper size %td\n", fw->size);
-
- /* "Set the 5 bytes of the helper image to 0" */
- /* Not needed, this contains an ARM branch instruction */
-
- for (;;) {
- /* "the number of bytes to send is 256" */
- int count = 256;
- int remain = fw->size - sent;
-
- if (remain < count)
- count = remain;
-
- /*
- * "write the number of bytes to be sent to the I/O Command
- * write length register"
- */
- if_cs_write16(card, IF_CS_CMD_LEN, count);
-
- /* "write this to I/O Command port register as 16 bit writes */
- if (count)
- if_cs_write16_rep(card, IF_CS_CMD,
- &fw->data[sent],
- count >> 1);
-
- /*
- * "Assert the download over interrupt command in the Host
- * status register"
- */
- if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
-
- /*
- * "Assert the download over interrupt command in the Card
- * interrupt case register"
- */
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
-
- /*
- * "The host polls the Card Status register ... for 50 ms before
- * declaring a failure"
- */
- ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
- IF_CS_BIT_COMMAND);
- if (ret < 0) {
- pr_err("can't download helper at 0x%x, ret %d\n",
- sent, ret);
- goto done;
- }
-
- if (count == 0)
- break;
-
- sent += count;
- }
-
-done:
- return ret;
-}
-
-
-static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
-{
- int ret = 0;
- int retry = 0;
- int len = 0;
- int sent;
-
- lbs_deb_cs("fw size %td\n", fw->size);
-
- ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
- IF_CS_SQ_HELPER_OK);
- if (ret < 0) {
- pr_err("helper firmware doesn't answer\n");
- goto done;
- }
-
- for (sent = 0; sent < fw->size; sent += len) {
- len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
- if (len & 1) {
- retry++;
- pr_info("odd, need to retry this firmware block\n");
- } else {
- retry = 0;
- }
-
- if (retry > 20) {
- pr_err("could not download firmware\n");
- ret = -ENODEV;
- goto done;
- }
- if (retry) {
- sent -= len;
- }
-
-
- if_cs_write16(card, IF_CS_CMD_LEN, len);
-
- if_cs_write16_rep(card, IF_CS_CMD,
- &fw->data[sent],
- (len+1) >> 1);
- if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
-
- ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
- IF_CS_BIT_COMMAND);
- if (ret < 0) {
- pr_err("can't download firmware at 0x%x\n", sent);
- goto done;
- }
- }
-
- ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
- if (ret < 0)
- pr_err("firmware download failed\n");
-
-done:
- return ret;
-}
-
-static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
- const struct firmware *helper,
- const struct firmware *mainfw)
-{
- struct if_cs_card *card = priv->card;
-
- if (ret) {
- pr_err("failed to find firmware (%d)\n", ret);
- return;
- }
-
- /* Load the firmware */
- ret = if_cs_prog_helper(card, helper);
- if (ret == 0 && (card->model != MODEL_8305))
- ret = if_cs_prog_real(card, mainfw);
- if (ret)
- return;
-
- /* Now actually get the IRQ */
- ret = request_irq(card->p_dev->irq, if_cs_interrupt,
- IRQF_SHARED, DRV_NAME, card);
- if (ret) {
- pr_err("error in request_irq\n");
- return;
- }
-
- /*
- * Clear any interrupt cause that happened while sending
- * firmware/initializing card
- */
- if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
- if_cs_enable_ints(card);
-
- /* And finally bring the card up */
- priv->fw_ready = 1;
- if (lbs_start_card(priv) != 0) {
- pr_err("could not activate card\n");
- free_irq(card->p_dev->irq, card);
- }
-}
-
-
-/********************************************************************/
-/* Callback functions for libertas.ko */
-/********************************************************************/
-
-/* Send commands or data packets to the card */
-static int if_cs_host_to_card(struct lbs_private *priv,
- u8 type,
- u8 *buf,
- u16 nb)
-{
- int ret = -1;
-
- switch (type) {
- case MVMS_DAT:
- priv->dnld_sent = DNLD_DATA_SENT;
- if_cs_send_data(priv, buf, nb);
- ret = 0;
- break;
- case MVMS_CMD:
- priv->dnld_sent = DNLD_CMD_SENT;
- ret = if_cs_send_cmd(priv, buf, nb);
- break;
- default:
- netdev_err(priv->dev, "%s: unsupported type %d\n",
- __func__, type);
- }
-
- return ret;
-}
-
-
-static void if_cs_release(struct pcmcia_device *p_dev)
-{
- struct if_cs_card *card = p_dev->priv;
-
- free_irq(p_dev->irq, card);
- pcmcia_disable_device(p_dev);
- if (card->iobase)
- ioport_unmap(card->iobase);
-}
-
-
-static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
-{
- p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
- if (p_dev->resource[1]->end) {
- pr_err("wrong CIS (check number of IO windows)\n");
- return -ENODEV;
- }
-
- /* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(p_dev);
-}
-
-static int if_cs_probe(struct pcmcia_device *p_dev)
-{
- int ret = -ENOMEM;
- unsigned int prod_id;
- struct lbs_private *priv;
- struct if_cs_card *card;
-
- card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
- if (!card)
- goto out;
-
- card->p_dev = p_dev;
- p_dev->priv = card;
-
- p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
- if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
- pr_err("error in pcmcia_loop_config\n");
- goto out1;
- }
-
- /*
- * Allocate an interrupt line. Note that this does not assign
- * a handler to the interrupt, unless the 'Handler' member of
- * the irq structure is initialized.
- */
- if (!p_dev->irq)
- goto out1;
-
- /* Initialize io access */
- card->iobase = ioport_map(p_dev->resource[0]->start,
- resource_size(p_dev->resource[0]));
- if (!card->iobase) {
- pr_err("error in ioport_map\n");
- ret = -EIO;
- goto out1;
- }
-
- ret = pcmcia_enable_device(p_dev);
- if (ret) {
- pr_err("error in pcmcia_enable_device\n");
- goto out2;
- }
-
- /* Finally, report what we've done */
- lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]);
-
- /*
- * Most of the libertas cards can do unaligned register access, but some
- * weird ones cannot. That's especially true for the CF8305 card.
- */
- card->align_regs = false;
-
- card->model = get_model(p_dev->manf_id, p_dev->card_id);
- if (card->model == MODEL_UNKNOWN) {
- pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
- p_dev->manf_id, p_dev->card_id);
- ret = -ENODEV;
- goto out2;
- }
-
- /* Check if we have a current silicon */
- prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
- if (card->model == MODEL_8305) {
- card->align_regs = true;
- if (prod_id < IF_CS_CF8305_B1_REV) {
- pr_err("8305 rev B0 and older are not supported\n");
- ret = -ENODEV;
- goto out2;
- }
- }
-
- if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
- pr_err("8381 rev B2 and older are not supported\n");
- ret = -ENODEV;
- goto out2;
- }
-
- if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
- pr_err("8385 rev B0 and older are not supported\n");
- ret = -ENODEV;
- goto out2;
- }
-
- /* Make this card known to the libertas driver */
- priv = lbs_add_card(card, &p_dev->dev);
- if (IS_ERR(priv)) {
- ret = PTR_ERR(priv);
- goto out2;
- }
-
- /* Set up fields in lbs_private */
- card->priv = priv;
- priv->card = card;
- priv->hw_host_to_card = if_cs_host_to_card;
- priv->enter_deep_sleep = NULL;
- priv->exit_deep_sleep = NULL;
- priv->reset_deep_sleep_wakeup = NULL;
-
- /* Get firmware */
- ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table,
- if_cs_prog_firmware);
- if (ret) {
- pr_err("failed to find firmware (%d)\n", ret);
- goto out3;
- }
-
- goto out;
-
-out3:
- lbs_remove_card(priv);
-out2:
- ioport_unmap(card->iobase);
-out1:
- pcmcia_disable_device(p_dev);
-out:
- return ret;
-}
-
-
-static void if_cs_detach(struct pcmcia_device *p_dev)
-{
- struct if_cs_card *card = p_dev->priv;
-
- lbs_stop_card(card->priv);
- lbs_remove_card(card->priv);
- if_cs_disable_ints(card);
- if_cs_release(p_dev);
- kfree(card);
-}
-
-
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-static const struct pcmcia_device_id if_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
- PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
- PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
- /* NOTE: keep in sync with get_model() */
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
-
-static struct pcmcia_driver lbs_driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .probe = if_cs_probe,
- .remove = if_cs_detach,
- .id_table = if_cs_ids,
-};
-module_pcmcia_driver(lbs_driver);
diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
index 7a15ea8072e6..3604abcbcff9 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -2047,6 +2047,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
mwifiex_set_sys_config_invalid_data(bss_cfg);
+ memcpy(bss_cfg->mac_addr, priv->curr_addr, ETH_ALEN);
+
if (params->beacon_interval)
bss_cfg->beacon_period = params->beacon_interval;
if (params->dtim_period)
diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
index 3756aa247e77..9eff29a25544 100644
--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
@@ -1244,8 +1244,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
u8 *pbuf, u32 upld_len)
{
struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf;
- struct mwifiex_private *priv =
- mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
uint16_t result = le16_to_cpu(cmd->result);
uint16_t command = le16_to_cpu(cmd->command);
uint16_t seq_num = le16_to_cpu(cmd->seq_num);
@@ -1260,12 +1258,6 @@ mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
"cmd: CMD_RESP: 0x%x, result %d, len %d, seqno 0x%x\n",
command, result, le16_to_cpu(cmd->size), seq_num);
- /* Get BSS number and corresponding priv */
- priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
- HostCmd_GET_BSS_TYPE(seq_num));
- if (!priv)
- priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
-
/* Update sequence number */
seq_num = HostCmd_GET_SEQ_NO(seq_num);
/* Clear RET_BIT from HostCmd */
diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h
index 8e6db904e5b2..62f3c9a52a1d 100644
--- a/drivers/net/wireless/marvell/mwifiex/fw.h
+++ b/drivers/net/wireless/marvell/mwifiex/fw.h
@@ -165,6 +165,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
#define TLV_TYPE_BSSID (PROPRIETARY_TLV_BASE_ID + 35)
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
+#define TLV_TYPE_UAP_MAC_ADDRESS (PROPRIETARY_TLV_BASE_ID + 43)
#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
#define TLV_TYPE_UAP_BCAST_SSID (PROPRIETARY_TLV_BASE_ID + 48)
diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h
index 091e7ca79376..e8825f302de8 100644
--- a/drivers/net/wireless/marvell/mwifiex/ioctl.h
+++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h
@@ -107,6 +107,7 @@ struct mwifiex_uap_bss_param {
u8 qos_info;
u8 power_constraint;
struct mwifiex_types_wmm_info wmm_info;
+ u8 mac_addr[ETH_ALEN];
};
enum {
diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c
index a6e254a1185c..9d98a1908dd6 100644
--- a/drivers/net/wireless/marvell/mwifiex/join.c
+++ b/drivers/net/wireless/marvell/mwifiex/join.c
@@ -1427,8 +1427,8 @@ int mwifiex_adhoc_join(struct mwifiex_private *priv,
/* Check if the requested SSID is already joined */
if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
- !mwifiex_ssid_cmp(&bss_desc->ssid,
- &priv->curr_bss_params.bss_descriptor.ssid) &&
+ cfg80211_ssid_eq(&bss_desc->ssid,
+ &priv->curr_bss_params.bss_descriptor.ssid) &&
(priv->curr_bss_params.bss_descriptor.bss_mode ==
NL80211_IFTYPE_ADHOC)) {
mwifiex_dbg(priv->adapter, INFO,
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index d263eae6078c..318b42b1896f 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -1152,7 +1152,6 @@ void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
struct cmd_ctrl_node *cmd_node);
int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp);
-s32 mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2);
int mwifiex_associate(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc);
int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c
index 72904c275461..a2ddac363b10 100644
--- a/drivers/net/wireless/marvell/mwifiex/scan.c
+++ b/drivers/net/wireless/marvell/mwifiex/scan.c
@@ -180,17 +180,6 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
}
/*
- * This function compares two SSIDs and checks if they match.
- */
-s32
-mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2)
-{
- if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
- return -1;
- return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
-}
-
-/*
* This function checks if wapi is enabled in driver and scanned network is
* compatible with it.
*/
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index 6462a0ffe698..75f53c2f1e1f 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -331,6 +331,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
.can_dump_fw = false,
.can_auto_tdls = false,
.can_ext_scan = false,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -346,6 +347,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
.can_dump_fw = false,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -361,6 +363,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
.can_dump_fw = false,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -376,6 +379,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
.can_dump_fw = true,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8977 = {
@@ -392,6 +396,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8977 = {
.fw_dump_enh = true,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8978 = {
@@ -408,6 +413,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8978 = {
.fw_dump_enh = true,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = {
@@ -425,6 +431,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = {
.fw_dump_enh = true,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
@@ -440,6 +447,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
.can_dump_fw = false,
.can_auto_tdls = true,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8987 = {
@@ -456,6 +464,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8987 = {
.fw_dump_enh = true,
.can_auto_tdls = true,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = {
@@ -471,6 +480,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = {
.can_dump_fw = false,
.can_auto_tdls = false,
.can_ext_scan = true,
+ .fw_ready_extra_delay = false,
};
static struct memory_type_mapping generic_mem_type_map[] = {
@@ -563,6 +573,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
card->fw_dump_enh = data->fw_dump_enh;
card->can_auto_tdls = data->can_auto_tdls;
card->can_ext_scan = data->can_ext_scan;
+ card->fw_ready_extra_delay = data->fw_ready_extra_delay;
INIT_WORK(&card->work, mwifiex_sdio_work);
}
@@ -766,8 +777,9 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
u32 poll_num)
{
+ struct sdio_mmc_card *card = adapter->card;
int ret = 0;
- u16 firmware_stat;
+ u16 firmware_stat = 0;
u32 tries;
for (tries = 0; tries < poll_num; tries++) {
@@ -783,6 +795,13 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
ret = -1;
}
+ if (card->fw_ready_extra_delay &&
+ firmware_stat == FIRMWARE_READY_SDIO)
+ /* firmware might pretend to be ready, when it's not.
+ * Wait a little bit more as a workaround.
+ */
+ msleep(100);
+
return ret;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.h b/drivers/net/wireless/marvell/mwifiex/sdio.h
index b86a9263a6a8..cb63ad55d675 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.h
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.h
@@ -255,6 +255,7 @@ struct sdio_mmc_card {
bool fw_dump_enh;
bool can_auto_tdls;
bool can_ext_scan;
+ bool fw_ready_extra_delay;
struct mwifiex_sdio_mpa_tx mpa_tx;
struct mwifiex_sdio_mpa_rx mpa_rx;
@@ -278,6 +279,7 @@ struct mwifiex_sdio_device {
bool fw_dump_enh;
bool can_auto_tdls;
bool can_ext_scan;
+ bool fw_ready_extra_delay;
};
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
index a2ad2b53f016..32a27fad7b79 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
@@ -345,8 +345,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
/* Adhoc mode */
/* If the requested SSID matches current SSID, return */
if (bss_desc && bss_desc->ssid.ssid_len &&
- (!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor.
- ssid, &bss_desc->ssid))) {
+ cfg80211_ssid_eq(&priv->curr_bss_params.bss_descriptor.ssid,
+ &bss_desc->ssid)) {
ret = 0;
goto done;
}
diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
index e78a201cd150..491e36611909 100644
--- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
@@ -468,6 +468,7 @@ void mwifiex_config_uap_11d(struct mwifiex_private *priv,
static int
mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
{
+ struct host_cmd_tlv_mac_addr *mac_tlv;
struct host_cmd_tlv_dtim_period *dtim_period;
struct host_cmd_tlv_beacon_period *beacon_period;
struct host_cmd_tlv_ssid *ssid;
@@ -487,6 +488,13 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
int i;
u16 cmd_size = *param_size;
+ mac_tlv = (struct host_cmd_tlv_mac_addr *)tlv;
+ mac_tlv->header.type = cpu_to_le16(TLV_TYPE_UAP_MAC_ADDRESS);
+ mac_tlv->header.len = cpu_to_le16(ETH_ALEN);
+ memcpy(mac_tlv->mac_addr, bss_cfg->mac_addr, ETH_ALEN);
+ cmd_size += sizeof(struct host_cmd_tlv_mac_addr);
+ tlv += sizeof(struct host_cmd_tlv_mac_addr);
+
if (bss_cfg->ssid.ssid_len) {
ssid = (struct host_cmd_tlv_ssid *)tlv;
ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index d3ab9572e711..515e6db410f2 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -687,7 +687,7 @@ static struct usb_driver mwifiex_usb_driver = {
.suspend = mwifiex_usb_suspend,
.resume = mwifiex_usb_resume,
.soft_unbind = 1,
- .drvwrap.driver = {
+ .driver = {
.coredump = mwifiex_usb_coredump,
},
};
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 68ad915203aa..00230f106294 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -9,11 +9,11 @@
#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)
-#define Q_READ(_dev, _q, _field) ({ \
+#define Q_READ(_q, _field) ({ \
u32 _offset = offsetof(struct mt76_queue_regs, _field); \
u32 _val; \
if ((_q)->flags & MT_QFLAG_WED) \
- _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed, \
+ _val = mtk_wed_device_reg_read((_q)->wed, \
((_q)->wed_regs + \
_offset)); \
else \
@@ -21,10 +21,10 @@
_val; \
})
-#define Q_WRITE(_dev, _q, _field, _val) do { \
+#define Q_WRITE(_q, _field, _val) do { \
u32 _offset = offsetof(struct mt76_queue_regs, _field); \
if ((_q)->flags & MT_QFLAG_WED) \
- mtk_wed_device_reg_write(&(_dev)->mmio.wed, \
+ mtk_wed_device_reg_write((_q)->wed, \
((_q)->wed_regs + _offset), \
_val); \
else \
@@ -33,8 +33,8 @@
#else
-#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field)
-#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field)
+#define Q_READ(_q, _field) readl(&(_q)->regs->_field)
+#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field)
#endif
@@ -188,41 +188,67 @@ EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi);
static void
mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
{
- Q_WRITE(dev, q, desc_base, q->desc_dma);
- Q_WRITE(dev, q, ring_size, q->ndesc);
- q->head = Q_READ(dev, q, dma_idx);
+ Q_WRITE(q, desc_base, q->desc_dma);
+ if (q->flags & MT_QFLAG_WED_RRO_EN)
+ Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc);
+ else
+ Q_WRITE(q, ring_size, q->ndesc);
+ q->head = Q_READ(q, dma_idx);
q->tail = q->head;
}
static void
-mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
+__mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
+ bool reset_idx)
{
- int i;
-
if (!q || !q->ndesc)
return;
- /* clear descriptors */
- for (i = 0; i < q->ndesc; i++)
- q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
+ if (!mt76_queue_is_wed_rro_ind(q)) {
+ int i;
+
+ /* clear descriptors */
+ for (i = 0; i < q->ndesc; i++)
+ q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
+ }
- Q_WRITE(dev, q, cpu_idx, 0);
- Q_WRITE(dev, q, dma_idx, 0);
+ if (reset_idx) {
+ Q_WRITE(q, cpu_idx, 0);
+ Q_WRITE(q, dma_idx, 0);
+ }
mt76_dma_sync_idx(dev, q);
}
+static void
+mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
+{
+ __mt76_dma_queue_reset(dev, q, true);
+}
+
static int
mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_buf *buf, void *data)
{
- struct mt76_desc *desc = &q->desc[q->head];
struct mt76_queue_entry *entry = &q->entry[q->head];
struct mt76_txwi_cache *txwi = NULL;
- u32 buf1 = 0, ctrl;
+ struct mt76_desc *desc;
int idx = q->head;
+ u32 buf1 = 0, ctrl;
int rx_token;
+ if (mt76_queue_is_wed_rro_ind(q)) {
+ struct mt76_wed_rro_desc *rro_desc;
+
+ rro_desc = (struct mt76_wed_rro_desc *)q->desc;
+ data = &rro_desc[q->head];
+ goto done;
+ }
+
+ desc = &q->desc[q->head];
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32);
+#endif
if (mt76_queue_is_wed_rx(q)) {
txwi = mt76_get_rxwi(dev);
@@ -244,6 +270,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
WRITE_ONCE(desc->info, 0);
+done:
entry->dma_addr[0] = buf->addr;
entry->dma_len[0] = buf->len;
entry->txwi = txwi;
@@ -288,11 +315,18 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
entry->dma_len[0] = buf[0].len;
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ info |= FIELD_PREP(MT_DMA_CTL_SDP0_H, buf[0].addr >> 32);
+#endif
if (i < nbufs - 1) {
entry->dma_addr[1] = buf[1].addr;
entry->dma_len[1] = buf[1].len;
buf1 = buf[1].addr;
ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ info |= FIELD_PREP(MT_DMA_CTL_SDP1_H,
+ buf[1].addr >> 32);
+#endif
if (buf[1].skip_unmap)
entry->skip_buf1 = true;
}
@@ -343,7 +377,7 @@ static void
mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
wmb();
- Q_WRITE(dev, q, cpu_idx, q->head);
+ Q_WRITE(q, cpu_idx, q->head);
}
static void
@@ -359,7 +393,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
if (flush)
last = -1;
else
- last = Q_READ(dev, q, dma_idx);
+ last = Q_READ(q, dma_idx);
while (q->queued > 0 && q->tail != last) {
mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
@@ -371,7 +405,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
}
if (!flush && q->tail == last)
- last = Q_READ(dev, q, dma_idx);
+ last = Q_READ(q, dma_idx);
}
spin_unlock_bh(&q->cleanup_lock);
@@ -392,19 +426,26 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
{
struct mt76_queue_entry *e = &q->entry[idx];
struct mt76_desc *desc = &q->desc[idx];
- void *buf;
+ u32 ctrl, desc_info, buf1;
+ void *buf = e->buf;
+
+ if (mt76_queue_is_wed_rro_ind(q))
+ goto done;
+ ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
if (len) {
- u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
*len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl);
*more = !(ctrl & MT_DMA_CTL_LAST_SEC0);
}
+ desc_info = le32_to_cpu(desc->info);
if (info)
- *info = le32_to_cpu(desc->info);
+ *info = desc_info;
+
+ buf1 = le32_to_cpu(desc->buf1);
+ mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info);
if (mt76_queue_is_wed_rx(q)) {
- u32 buf1 = le32_to_cpu(desc->buf1);
u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1);
struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token);
@@ -420,23 +461,16 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
t->ptr = NULL;
mt76_put_rxwi(dev, t);
-
- if (drop) {
- u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
-
- *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A |
- MT_DMA_CTL_DROP));
-
+ if (drop)
*drop |= !!(buf1 & MT_DMA_CTL_WO_DROP);
- }
} else {
- buf = e->buf;
- e->buf = NULL;
dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],
SKB_WITH_OVERHEAD(q->buf_size),
page_pool_get_dma_dir(q->page_pool));
}
+done:
+ e->buf = NULL;
return buf;
}
@@ -450,11 +484,16 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
if (!q->queued)
return NULL;
- if (flush)
- q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE);
- else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE)))
+ if (mt76_queue_is_wed_rro_data(q))
return NULL;
+ if (!mt76_queue_is_wed_rro_ind(q)) {
+ if (flush)
+ q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE);
+ else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE)))
+ return NULL;
+ }
+
q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
@@ -606,11 +645,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
+ struct mt76_queue_buf qbuf = {};
enum dma_data_direction dir;
- struct mt76_queue_buf qbuf;
dma_addr_t addr;
int offset;
- void *buf;
+ void *buf = NULL;
+
+ if (mt76_queue_is_wed_rro_ind(q))
+ goto done;
buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
if (!buf)
@@ -621,6 +663,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
dma_sync_single_for_device(dev->dma_dev, addr, len, dir);
qbuf.addr = addr + q->buf_offset;
+done:
qbuf.len = len - q->buf_offset;
qbuf.skip_unmap = false;
if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {
@@ -630,7 +673,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
frames++;
}
- if (frames)
+ if (frames || mt76_queue_is_wed_rx(q))
mt76_dma_kick_queue(dev, q);
spin_unlock_bh(&q->lock);
@@ -641,15 +684,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
- struct mtk_wed_device *wed = &dev->mmio.wed;
- int ret, type, ring;
- u8 flags;
+ int ret = 0, type, ring;
+ u16 flags;
if (!q || !q->ndesc)
return -EINVAL;
flags = q->flags;
- if (!mtk_wed_device_active(wed))
+ if (!q->wed || !mtk_wed_device_active(q->wed))
q->flags &= ~MT_QFLAG_WED;
if (!(q->flags & MT_QFLAG_WED))
@@ -660,29 +702,52 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
switch (type) {
case MT76_WED_Q_TX:
- ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset);
+ ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs,
+ reset);
if (!ret)
- q->wed_regs = wed->tx_ring[ring].reg_base;
+ q->wed_regs = q->wed->tx_ring[ring].reg_base;
break;
case MT76_WED_Q_TXFREE:
/* WED txfree queue needs ring to be initialized before setup */
q->flags = 0;
mt76_dma_queue_reset(dev, q);
mt76_dma_rx_fill(dev, q, false);
- q->flags = flags;
- ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
+ ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs);
if (!ret)
- q->wed_regs = wed->txfree_ring.reg_base;
+ q->wed_regs = q->wed->txfree_ring.reg_base;
break;
case MT76_WED_Q_RX:
- ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset);
+ ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs,
+ reset);
if (!ret)
- q->wed_regs = wed->rx_ring[ring].reg_base;
+ q->wed_regs = q->wed->rx_ring[ring].reg_base;
+ break;
+ case MT76_WED_RRO_Q_DATA:
+ q->flags &= ~MT_QFLAG_WED;
+ __mt76_dma_queue_reset(dev, q, false);
+ mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs);
+ q->head = q->ndesc - 1;
+ q->queued = q->head;
+ break;
+ case MT76_WED_RRO_Q_MSDU_PG:
+ q->flags &= ~MT_QFLAG_WED;
+ __mt76_dma_queue_reset(dev, q, false);
+ mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs);
+ q->head = q->ndesc - 1;
+ q->queued = q->head;
+ break;
+ case MT76_WED_RRO_Q_IND:
+ q->flags &= ~MT_QFLAG_WED;
+ mt76_dma_queue_reset(dev, q);
+ mt76_dma_rx_fill(dev, q, false);
+ mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs);
break;
default:
ret = -EINVAL;
+ break;
}
+ q->flags = flags;
return ret;
#else
@@ -706,11 +771,26 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
q->buf_size = bufsize;
q->hw_idx = idx;
- size = q->ndesc * sizeof(struct mt76_desc);
- q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL);
+ size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc)
+ : sizeof(struct mt76_desc);
+ q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size,
+ &q->desc_dma, GFP_KERNEL);
if (!q->desc)
return -ENOMEM;
+ if (mt76_queue_is_wed_rro_ind(q)) {
+ struct mt76_wed_rro_desc *rro_desc;
+ int i;
+
+ rro_desc = (struct mt76_wed_rro_desc *)q->desc;
+ for (i = 0; i < q->ndesc; i++) {
+ struct mt76_wed_rro_ind *cmd;
+
+ cmd = (struct mt76_wed_rro_ind *)&rro_desc[i];
+ cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1;
+ }
+ }
+
size = q->ndesc * sizeof(*q->entry);
q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
if (!q->entry)
@@ -724,8 +804,13 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
if (ret)
return ret;
- if (q->flags != MT_WED_Q_TXFREE)
- mt76_dma_queue_reset(dev, q);
+ if (mtk_wed_device_active(&dev->mmio.wed)) {
+ if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) ||
+ mt76_queue_is_wed_tx_free(q))
+ return 0;
+ }
+
+ mt76_dma_queue_reset(dev, q);
return 0;
}
@@ -747,7 +832,8 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
- mt76_put_page_pool_buf(buf, false);
+ if (!mt76_queue_is_wed_rro(q))
+ mt76_put_page_pool_buf(buf, false);
} while (1);
spin_lock_bh(&q->lock);
@@ -763,22 +849,31 @@ static void
mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
{
struct mt76_queue *q = &dev->q_rx[qid];
- int i;
if (!q->ndesc)
return;
- for (i = 0; i < q->ndesc; i++)
- q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
+ if (!mt76_queue_is_wed_rro_ind(q)) {
+ int i;
+
+ for (i = 0; i < q->ndesc; i++)
+ q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
+ }
mt76_dma_rx_cleanup(dev, q);
/* reset WED rx queues */
mt76_dma_wed_setup(dev, q, true);
- if (q->flags != MT_WED_Q_TXFREE) {
- mt76_dma_sync_idx(dev, q);
- mt76_dma_rx_fill(dev, q, false);
- }
+
+ if (mt76_queue_is_wed_tx_free(q))
+ return;
+
+ if (mtk_wed_device_active(&dev->mmio.wed) &&
+ mt76_queue_is_wed_rro(q))
+ return;
+
+ mt76_dma_sync_idx(dev, q);
+ mt76_dma_rx_fill(dev, q, false);
}
static void
@@ -819,8 +914,8 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
bool more;
if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
- q->flags == MT_WED_Q_TXFREE) {
- dma_idx = Q_READ(dev, q, dma_idx);
+ mt76_queue_is_wed_tx_free(q)) {
+ dma_idx = Q_READ(q, dma_idx);
check_ddone = true;
}
@@ -830,7 +925,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
if (check_ddone) {
if (q->tail == dma_idx)
- dma_idx = Q_READ(dev, q, dma_idx);
+ dma_idx = Q_READ(q, dma_idx);
if (q->tail == dma_idx)
break;
@@ -959,6 +1054,20 @@ void mt76_dma_attach(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76_dma_attach);
+void mt76_dma_wed_reset(struct mt76_dev *dev)
+{
+ struct mt76_mmio *mmio = &dev->mmio;
+
+ if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state))
+ return;
+
+ complete(&mmio->wed_reset);
+
+ if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ))
+ dev_err(dev->dev, "wed reset complete timeout\n");
+}
+EXPORT_SYMBOL_GPL(mt76_dma_wed_reset);
+
void mt76_dma_cleanup(struct mt76_dev *dev)
{
int i;
@@ -983,16 +1092,23 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
+ if (mtk_wed_device_active(&dev->mmio.wed) &&
+ mt76_queue_is_wed_rro(q))
+ continue;
+
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
page_pool_destroy(q->page_pool);
}
- mt76_free_pending_txwi(dev);
- mt76_free_pending_rxwi(dev);
-
if (mtk_wed_device_active(&dev->mmio.wed))
mtk_wed_device_detach(&dev->mmio.wed);
+
+ if (mtk_wed_device_active(&dev->mmio.wed_hif2))
+ mtk_wed_device_detach(&dev->mmio.wed_hif2);
+
+ mt76_free_pending_txwi(dev);
+ mt76_free_pending_rxwi(dev);
}
EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h
index 1b090d78cd05..c479cc6388ef 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.h
+++ b/drivers/net/wireless/mediatek/mt76/dma.h
@@ -19,12 +19,23 @@
#define MT_DMA_CTL_TO_HOST_A BIT(12)
#define MT_DMA_CTL_DROP BIT(14)
#define MT_DMA_CTL_TOKEN GENMASK(31, 16)
+#define MT_DMA_CTL_SDP1_H GENMASK(19, 16)
+#define MT_DMA_CTL_SDP0_H GENMASK(3, 0)
#define MT_DMA_CTL_WO_DROP BIT(8)
#define MT_DMA_PPE_CPU_REASON GENMASK(15, 11)
#define MT_DMA_PPE_ENTRY GENMASK(30, 16)
+#define MT_DMA_INFO_DMA_FRAG BIT(9)
#define MT_DMA_INFO_PPE_VLD BIT(31)
+#define MT_DMA_CTL_PN_CHK_FAIL BIT(13)
+#define MT_DMA_CTL_VER_MASK BIT(7)
+
+#define MT_DMA_RRO_EN BIT(13)
+
+#define MT_DMA_WED_IND_CMD_CNT 8
+#define MT_DMA_WED_IND_REASON GENMASK(15, 12)
+
#define MT_DMA_HDR_LEN 4
#define MT_RX_INFO_LEN 4
#define MT_FCE_INFO_LEN 4
@@ -37,6 +48,11 @@ struct mt76_desc {
__le32 info;
} __packed __aligned(4);
+struct mt76_wed_rro_desc {
+ __le32 buf0;
+ __le32 buf1;
+} __packed __aligned(4);
+
enum mt76_qsel {
MT_QSEL_MGMT,
MT_QSEL_HCCA,
@@ -54,9 +70,47 @@ enum mt76_mcu_evt_type {
EVT_EVENT_DFS_DETECT_RSP,
};
+enum mt76_dma_wed_ind_reason {
+ MT_DMA_WED_IND_REASON_NORMAL,
+ MT_DMA_WED_IND_REASON_REPEAT,
+ MT_DMA_WED_IND_REASON_OLDPKT,
+};
+
int mt76_dma_rx_poll(struct napi_struct *napi, int budget);
void mt76_dma_attach(struct mt76_dev *dev);
void mt76_dma_cleanup(struct mt76_dev *dev);
int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset);
+void mt76_dma_wed_reset(struct mt76_dev *dev);
+
+static inline void
+mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
+{
+ dev->queue_ops->reset_q(dev, q);
+ if (mtk_wed_device_active(&dev->mmio.wed))
+ mt76_dma_wed_setup(dev, q, true);
+}
+
+static inline void
+mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info)
+{
+ if (!drop)
+ return;
+
+ *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP));
+ if (!(ctrl & MT_DMA_CTL_VER_MASK))
+ return;
+
+ switch (FIELD_GET(MT_DMA_WED_IND_REASON, buf1)) {
+ case MT_DMA_WED_IND_REASON_REPEAT:
+ *drop = true;
+ break;
+ case MT_DMA_WED_IND_REASON_OLDPKT:
+ *drop = !(info & MT_DMA_INFO_DMA_FRAG);
+ break;
+ default:
+ *drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL);
+ break;
+ }
+}
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index 7725dd6763ef..0bc66cc19acd 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -28,7 +28,7 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
return 0;
}
-static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
+int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
{
#ifdef CONFIG_MTD
struct device_node *np = dev->dev->of_node;
@@ -67,7 +67,7 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs
goto out_put_node;
}
- offset = be32_to_cpup(list);
+ offset += be32_to_cpup(list);
ret = mtd_read(mtd, offset, len, &retlen, eep);
put_mtd_device(mtd);
if (mtd_is_bitflip(ret))
@@ -105,8 +105,10 @@ out_put_node:
return -ENOENT;
#endif
}
+EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);
-static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int len)
+int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
+ const char *cell_name, int len)
{
struct device_node *np = dev->dev->of_node;
struct nvmem_cell *cell;
@@ -114,7 +116,7 @@ static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int le
size_t retlen;
int ret = 0;
- cell = of_nvmem_cell_get(np, "eeprom");
+ cell = of_nvmem_cell_get(np, cell_name);
if (IS_ERR(cell))
return PTR_ERR(cell);
@@ -136,8 +138,9 @@ exit:
return ret;
}
+EXPORT_SYMBOL_GPL(mt76_get_of_data_from_nvmem);
-int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
+static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
{
struct device_node *np = dev->dev->of_node;
int ret;
@@ -149,13 +152,12 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
if (!ret)
return 0;
- ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len);
+ ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
if (!ret)
return 0;
- return mt76_get_of_epprom_from_nvmem(dev, eep, len);
+ return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
}
-EXPORT_SYMBOL_GPL(mt76_get_of_eeprom);
void
mt76_eeprom_override(struct mt76_phy *phy)
@@ -379,7 +381,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
if (!np)
return target_power;
- txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask));
+ txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask));
val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
@@ -412,6 +414,6 @@ mt76_eeprom_init(struct mt76_dev *dev, int len)
if (!dev->eeprom.data)
return -ENOMEM;
- return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len);
+ return !mt76_get_of_eeprom(dev, dev->eeprom.data, len);
}
EXPORT_SYMBOL_GPL(mt76_eeprom_init);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 51a767121b0d..8a3a90d1bfac 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -197,10 +197,33 @@ static int mt76_led_init(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
struct ieee80211_hw *hw = phy->hw;
+ struct device_node *np = dev->dev->of_node;
if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
return 0;
+ np = of_get_child_by_name(np, "led");
+ if (np) {
+ if (!of_device_is_available(np)) {
+ of_node_put(np);
+ dev_info(dev->dev,
+ "led registration was explicitly disabled by dts\n");
+ return 0;
+ }
+
+ if (phy == &dev->phy) {
+ int led_pin;
+
+ if (!of_property_read_u32(np, "led-sources", &led_pin))
+ phy->leds.pin = led_pin;
+
+ phy->leds.al =
+ of_property_read_bool(np, "led-active-low");
+ }
+
+ of_node_put(np);
+ }
+
snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
wiphy_name(hw->wiphy));
@@ -211,20 +234,8 @@ static int mt76_led_init(struct mt76_phy *phy)
mt76_tpt_blink,
ARRAY_SIZE(mt76_tpt_blink));
- if (phy == &dev->phy) {
- struct device_node *np = dev->dev->of_node;
-
- np = of_get_child_by_name(np, "led");
- if (np) {
- int led_pin;
-
- if (!of_property_read_u32(np, "led-sources", &led_pin))
- phy->leds.pin = led_pin;
- phy->leds.al = of_property_read_bool(np,
- "led-active-low");
- of_node_put(np);
- }
- }
+ dev_info(dev->dev,
+ "registering led '%s'\n", phy->leds.name);
return led_classdev_register(dev->dev, &phy->leds.cdev);
}
@@ -1537,7 +1548,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int *dbm)
{
struct mt76_phy *phy = hw->priv;
- int n_chains = hweight8(phy->antenna_mask);
+ int n_chains = hweight16(phy->chainmask);
int delta = mt76_tx_power_nss_delta(n_chains);
*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
@@ -1725,7 +1736,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna);
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
- int ring_base, u32 flags)
+ int ring_base, void *wed, u32 flags)
{
struct mt76_queue *hwq;
int err;
@@ -1735,6 +1746,7 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
return ERR_PTR(-ENOMEM);
hwq->flags = flags;
+ hwq->wed = wed;
err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
if (err < 0)
@@ -1842,3 +1854,19 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
return MT_DFS_STATE_ACTIVE;
}
EXPORT_SYMBOL_GPL(mt76_phy_dfs_state);
+
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct net_device *netdev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct mt76_phy *phy = hw->priv;
+ struct mtk_wed_device *wed = &phy->dev->mmio.wed;
+
+ if (!mtk_wed_device_active(wed))
+ return -EOPNOTSUPP;
+
+ return mtk_wed_device_setup_tc(wed, netdev, type, type_data);
+}
+EXPORT_SYMBOL_GPL(mt76_net_setup_tc);
+#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c
index 86e3d2ac4d0d..c3e0e23e0161 100644
--- a/drivers/net/wireless/mediatek/mt76/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mmio.c
@@ -4,6 +4,7 @@
*/
#include "mt76.h"
+#include "dma.h"
#include "trace.h"
static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset)
@@ -84,6 +85,113 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
}
EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
+{
+ struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+ int i;
+
+ for (i = 0; i < dev->rx_token_size; i++) {
+ struct mt76_txwi_cache *t;
+
+ t = mt76_rx_token_release(dev, i);
+ if (!t || !t->ptr)
+ continue;
+
+ mt76_put_page_pool_buf(t->ptr, false);
+ t->ptr = NULL;
+
+ mt76_put_rxwi(dev, t);
+ }
+
+ mt76_free_pending_rxwi(dev);
+}
+EXPORT_SYMBOL_GPL(mt76_mmio_wed_release_rx_buf);
+
+u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
+{
+ struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
+ struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
+ int i, len = SKB_WITH_OVERHEAD(q->buf_size);
+ struct mt76_txwi_cache *t = NULL;
+
+ for (i = 0; i < size; i++) {
+ enum dma_data_direction dir;
+ dma_addr_t addr;
+ u32 offset;
+ int token;
+ void *buf;
+
+ t = mt76_get_rxwi(dev);
+ if (!t)
+ goto unmap;
+
+ buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
+ if (!buf)
+ goto unmap;
+
+ addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
+ dir = page_pool_get_dma_dir(q->page_pool);
+ dma_sync_single_for_device(dev->dma_dev, addr, len, dir);
+
+ desc->buf0 = cpu_to_le32(addr);
+ token = mt76_rx_token_consume(dev, buf, t, addr);
+ if (token < 0) {
+ mt76_put_page_pool_buf(buf, false);
+ goto unmap;
+ }
+
+ token = FIELD_PREP(MT_DMA_CTL_TOKEN, token);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32);
+#endif
+ desc->token |= cpu_to_le32(token);
+ desc++;
+ }
+
+ return 0;
+
+unmap:
+ if (t)
+ mt76_put_rxwi(dev, t);
+ mt76_mmio_wed_release_rx_buf(wed);
+
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf);
+
+int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed)
+{
+ struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+
+ spin_lock_bh(&dev->token_lock);
+ dev->token_size = wed->wlan.token_start;
+ spin_unlock_bh(&dev->token_lock);
+
+ return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ);
+}
+EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_enable);
+
+void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed)
+{
+ struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+
+ spin_lock_bh(&dev->token_lock);
+ dev->token_size = dev->drv->token_size;
+ spin_unlock_bh(&dev->token_lock);
+}
+EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable);
+
+void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed)
+{
+ struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
+
+ complete(&dev->mmio.wed_reset_complete);
+}
+EXPORT_SYMBOL_GPL(mt76_mmio_wed_reset_complete);
+#endif /*CONFIG_NET_MEDIATEK_SOC_WED */
+
void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs)
{
static const struct mt76_bus_ops mt76_mmio_ops = {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index ea828ba0b83a..b20c34d5a0f7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -29,15 +29,22 @@
#define MT76_TOKEN_FREE_THR 64
#define MT_QFLAG_WED_RING GENMASK(1, 0)
-#define MT_QFLAG_WED_TYPE GENMASK(3, 2)
-#define MT_QFLAG_WED BIT(4)
+#define MT_QFLAG_WED_TYPE GENMASK(4, 2)
+#define MT_QFLAG_WED BIT(5)
+#define MT_QFLAG_WED_RRO BIT(6)
+#define MT_QFLAG_WED_RRO_EN BIT(7)
#define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \
FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \
FIELD_PREP(MT_QFLAG_WED_RING, _n))
+#define __MT_WED_RRO_Q(_type, _n) (MT_QFLAG_WED_RRO | __MT_WED_Q(_type, _n))
+
#define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n)
#define MT_WED_Q_RX(_n) __MT_WED_Q(MT76_WED_Q_RX, _n)
#define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0)
+#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n)
+#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n)
+#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0)
struct mt76_dev;
struct mt76_phy;
@@ -59,6 +66,9 @@ enum mt76_wed_type {
MT76_WED_Q_TX,
MT76_WED_Q_TXFREE,
MT76_WED_Q_RX,
+ MT76_WED_RRO_Q_DATA,
+ MT76_WED_RRO_Q_MSDU_PG,
+ MT76_WED_RRO_Q_IND,
};
struct mt76_bus_ops {
@@ -107,6 +117,16 @@ enum mt76_rxq_id {
MT_RXQ_MAIN_WA,
MT_RXQ_BAND2,
MT_RXQ_BAND2_WA,
+ MT_RXQ_RRO_BAND0,
+ MT_RXQ_RRO_BAND1,
+ MT_RXQ_RRO_BAND2,
+ MT_RXQ_MSDU_PAGE_BAND0,
+ MT_RXQ_MSDU_PAGE_BAND1,
+ MT_RXQ_MSDU_PAGE_BAND2,
+ MT_RXQ_TXFREE_BAND0,
+ MT_RXQ_TXFREE_BAND1,
+ MT_RXQ_TXFREE_BAND2,
+ MT_RXQ_RRO_IND,
__MT_RXQ_MAX
};
@@ -163,7 +183,7 @@ struct mt76_queue_entry {
struct urb *urb;
int buf_sz;
};
- u32 dma_addr[2];
+ dma_addr_t dma_addr[2];
u16 dma_len[2];
u16 wcid;
bool skip_buf0:1;
@@ -184,6 +204,7 @@ struct mt76_queue {
spinlock_t lock;
spinlock_t cleanup_lock;
struct mt76_queue_entry *entry;
+ struct mt76_rro_desc *rro_desc;
struct mt76_desc *desc;
u16 first;
@@ -197,8 +218,9 @@ struct mt76_queue {
u8 buf_offset;
u8 hw_idx;
- u8 flags;
+ u16 flags;
+ struct mtk_wed_device *wed;
u32 wed_regs;
dma_addr_t desc_dma;
@@ -353,6 +375,17 @@ struct mt76_txq {
bool aggr;
};
+struct mt76_wed_rro_ind {
+ u32 se_id : 12;
+ u32 rsv : 4;
+ u32 start_sn : 12;
+ u32 ind_reason : 4;
+ u32 ind_cnt : 13;
+ u32 win_sz : 3;
+ u32 rsv2 : 13;
+ u32 magic_cnt : 3;
+};
+
struct mt76_txwi_cache {
struct list_head list;
dma_addr_t dma_addr;
@@ -371,6 +404,7 @@ struct mt76_rx_tid {
spinlock_t lock;
struct delayed_work reorder_work;
+ u16 id;
u16 head;
u16 size;
u16 nframes;
@@ -575,8 +609,7 @@ struct mt76_sdio {
struct mt76_worker txrx_worker;
struct mt76_worker status_worker;
struct mt76_worker net_worker;
-
- struct work_struct stat_work;
+ struct mt76_worker stat_worker;
u8 *xmit_buf;
u32 xmit_buf_sz;
@@ -603,6 +636,7 @@ struct mt76_mmio {
u32 irqmask;
struct mtk_wed_device wed;
+ struct mtk_wed_device wed_hif2;
struct completion wed_reset;
struct completion wed_reset_complete;
};
@@ -1047,6 +1081,12 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs);
void mt76_pci_disable_aspm(struct pci_dev *pdev);
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct net_device *netdev, enum tc_setup_type type,
+ void *type_data);
+#endif /*CONFIG_NET_MEDIATEK_SOC_WED */
+
static inline u16 mt76_chip(struct mt76_dev *dev)
{
return dev->rev >> 16;
@@ -1057,6 +1097,14 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
return dev->rev & 0xffff;
}
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size);
+void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed);
+int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed);
+void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed);
+void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed);
+#endif /*CONFIG_NET_MEDIATEK_SOC_WED */
+
#define mt76xx_chip(dev) mt76_chip(&((dev)->mt76))
#define mt76xx_rev(dev) mt76_rev(&((dev)->mt76))
@@ -1102,19 +1150,22 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_phy *phy);
-int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len);
+int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
+int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
+ const char *cell_name, int len);
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
- int ring_base, u32 flags);
+ int ring_base, void *wed, u32 flags);
u16 mt76_calculate_default_rate(struct mt76_phy *phy,
struct ieee80211_vif *vif, int rateidx);
static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx,
- int n_desc, int ring_base, u32 flags)
+ int n_desc, int ring_base, void *wed,
+ u32 flags)
{
struct mt76_queue *q;
- q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags);
+ q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, wed, flags);
if (IS_ERR(q))
return PTR_ERR(q);
@@ -1128,7 +1179,7 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx,
{
struct mt76_queue *q;
- q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0);
+ q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, NULL, 0);
if (IS_ERR(q))
return PTR_ERR(q);
@@ -1547,10 +1598,38 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
struct mt76_power_limits *dest,
s8 target_power);
-static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
+static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q)
{
return (q->flags & MT_QFLAG_WED) &&
- FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX;
+ FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE;
+}
+
+static inline bool mt76_queue_is_wed_rro(struct mt76_queue *q)
+{
+ return q->flags & MT_QFLAG_WED_RRO;
+}
+
+static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q)
+{
+ return mt76_queue_is_wed_rro(q) &&
+ FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND;
+}
+
+static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q)
+{
+ return mt76_queue_is_wed_rro(q) &&
+ (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA ||
+ FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG);
+}
+
+static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
+{
+ if (!(q->flags & MT_QFLAG_WED))
+ return false;
+
+ return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX ||
+ mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q);
+
}
struct mt76_txwi_cache *
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
index 03ba11a61c90..7a2f5d38562b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
@@ -173,13 +173,14 @@ int mt7603_dma_init(struct mt7603_dev *dev)
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
- MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0);
+ MT7603_TX_RING_SIZE, MT_TX_RING_BASE,
+ NULL, 0);
if (ret)
return ret;
}
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
- MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0);
+ MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
@@ -189,12 +190,12 @@ int mt7603_dma_init(struct mt7603_dev *dev)
return ret;
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN,
- MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0);
+ MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC,
- MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0);
+ MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 89d738deea62..e2146d30e553 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -728,6 +728,7 @@ const struct ieee80211_ops mt7603_ops = {
.set_sar_specs = mt7603_set_sar_specs,
};
+MODULE_DESCRIPTION("MediaTek MT7603E and MT76x8 wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
static int __init mt7603_init(void)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
index ba927033bbe8..ec02148a7f1f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
@@ -52,15 +52,12 @@ error:
return ret;
}
-static int
-mt76_wmac_remove(struct platform_device *pdev)
+static void mt76_wmac_remove(struct platform_device *pdev)
{
struct mt76_dev *mdev = platform_get_drvdata(pdev);
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
mt7603_unregister_device(dev);
-
- return 0;
}
static const struct of_device_id of_wmac_match[] = {
@@ -74,7 +71,7 @@ MODULE_FIRMWARE(MT7628_FIRMWARE_E2);
struct platform_driver mt76_wmac_driver = {
.probe = mt76_wmac_probe,
- .remove = mt76_wmac_remove,
+ .remove_new = mt76_wmac_remove,
.driver = {
.name = "mt76_wmac",
.of_match_table = of_wmac_match,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 0ce01ccc5dce..e7135b2f1742 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -26,14 +26,14 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
MT7615_TX_RING_SIZE / 2,
- MT_TX_RING_BASE, 0);
+ MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
}
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT,
MT7615_TX_MGMT_RING_SIZE,
- MT_TX_RING_BASE, 0);
+ MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
@@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
return mt7622_init_tx_queues_multi(dev);
ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE,
- MT_TX_RING_BASE, 0);
+ MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index dab16b5fc386..0971c164b57e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -1375,4 +1375,5 @@ const struct ieee80211_ops mt7615_ops = {
};
EXPORT_SYMBOL_GPL(mt7615_ops);
+MODULE_DESCRIPTION("MediaTek MT7615E and MT7663E wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 955974a82180..ae34d019e588 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -453,7 +453,7 @@ mt7615_mcu_scan_event(struct mt7615_dev *dev, struct sk_buff *skb)
else
mphy = &dev->mt76.phy;
- phy = (struct mt7615_phy *)mphy->priv;
+ phy = mphy->priv;
spin_lock_bh(&dev->mt76.lock);
__skb_queue_tail(&phy->scan_event_list, skb);
@@ -481,7 +481,7 @@ mt7615_mcu_roc_event(struct mt7615_dev *dev, struct sk_buff *skb)
ieee80211_ready_on_channel(mphy->hw);
- phy = (struct mt7615_phy *)mphy->priv;
+ phy = mphy->priv;
phy->roc_grant = true;
wake_up(&phy->roc_wait);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index ac036a072439..87a956ea3ad7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -270,4 +270,5 @@ static void __exit mt7615_exit(void)
module_init(mt7615_init);
module_exit(mt7615_exit);
+MODULE_DESCRIPTION("MediaTek MT7615E MMIO helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
index fc547a0031ea..9692890ba51b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -204,8 +204,8 @@ static int mt7663s_suspend(struct device *dev)
mt76_worker_disable(&mdev->mt76.sdio.txrx_worker);
mt76_worker_disable(&mdev->mt76.sdio.status_worker);
mt76_worker_disable(&mdev->mt76.sdio.net_worker);
+ mt76_worker_disable(&mdev->mt76.sdio.stat_worker);
- cancel_work_sync(&mdev->mt76.sdio.stat_work);
clear_bit(MT76_READING_STATS, &mdev->mphy.state);
mt76_tx_status_check(&mdev->mt76, true);
@@ -253,4 +253,5 @@ module_sdio_driver(mt7663s_driver);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT7663S (SDIO) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
index f13d1b418742..12e3e4a91d27 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
@@ -45,13 +45,11 @@ static int mt7622_wmac_probe(struct platform_device *pdev)
return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map);
}
-static int mt7622_wmac_remove(struct platform_device *pdev)
+static void mt7622_wmac_remove(struct platform_device *pdev)
{
struct mt7615_dev *dev = platform_get_drvdata(pdev);
mt7615_unregister_device(dev);
-
- return 0;
}
static const struct of_device_id mt7622_wmac_of_match[] = {
@@ -65,7 +63,7 @@ struct platform_driver mt7622_wmac_driver = {
.of_match_table = mt7622_wmac_of_match,
},
.probe = mt7622_wmac_probe,
- .remove = mt7622_wmac_remove,
+ .remove_new = mt7622_wmac_remove,
};
MODULE_FIRMWARE(MT7622_FIRMWARE_N9);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
index 04963b9f7498..df737e1ff27b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
@@ -281,4 +281,5 @@ module_usb_driver(mt7663u_driver);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT7663U (USB) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
index 0052d103e276..820b39590027 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
@@ -349,4 +349,5 @@ EXPORT_SYMBOL_GPL(mt7663_usb_sdio_register_device);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek MT7663 SDIO/USB helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 1f29d8cd900c..fdde3d70b300 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -222,6 +222,11 @@ static inline bool is_mt7996(struct mt76_dev *dev)
return mt76_chip(dev) == 0x7990;
}
+static inline bool is_mt7992(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7992;
+}
+
static inline bool is_mt7622(struct mt76_dev *dev)
{
if (!IS_ENABLED(CONFIG_MT7622_WMAC))
@@ -391,7 +396,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm)
void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss);
int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
- int ring_base, u32 flags);
+ int ring_base, void *wed, u32 flags);
+
void mt76_connac_write_hw_txp(struct mt76_dev *dev,
struct mt76_tx_info *tx_info,
void *txp_ptr, u32 id);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
index 2250252b2047..83dcd964bfd0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h
@@ -239,11 +239,13 @@ enum tx_mgnt_type {
#define MT_TXD6_TX_SRC GENMASK(31, 30)
#define MT_TXD6_VTA BIT(28)
-#define MT_TXD6_BW GENMASK(25, 22)
+#define MT_TXD6_FIXED_BW BIT(25)
+#define MT_TXD6_BW GENMASK(24, 22)
#define MT_TXD6_TX_RATE GENMASK(21, 16)
#define MT_TXD6_TIMESTAMP_OFS_EN BIT(15)
#define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10)
#define MT_TXD6_MSDU_CNT GENMASK(9, 4)
+#define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10)
#define MT_TXD6_DIS_MAT BIT(3)
#define MT_TXD6_DAS BIT(2)
#define MT_TXD6_AMSDU_CAP BIT(1)
@@ -259,6 +261,9 @@ enum tx_mgnt_type {
#define MT_TXD9_WLAN_IDX GENMASK(23, 8)
+#define MT_TXP_BUF_LEN GENMASK(11, 0)
+#define MT_TXP_DMA_ADDR_H GENMASK(15, 12)
+
#define MT_TX_RATE_STBC BIT(14)
#define MT_TX_RATE_NSS GENMASK(13, 10)
#define MT_TX_RATE_MODE GENMASK(9, 6)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 93402d2c2538..c7914643e9c0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -256,11 +256,12 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev,
EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap);
int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
- int ring_base, u32 flags)
+ int ring_base, void *wed, u32 flags)
{
int i, err;
- err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags);
+ err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base,
+ wed, flags);
if (err < 0)
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index ae6bf3c968df..3a20ba0d2492 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -67,7 +67,8 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len,
if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) ||
(is_mt7921(dev) && addr == 0x900000) ||
(is_mt7925(dev) && addr == 0x900000) ||
- (is_mt7996(dev) && addr == 0x900000))
+ (is_mt7996(dev) && addr == 0x900000) ||
+ (is_mt7992(dev) && addr == 0x900000))
cmd = MCU_CMD(PATCH_START_REQ);
else
cmd = MCU_CMD(TARGET_ADDRESS_LEN_REQ);
@@ -1359,7 +1360,7 @@ u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
sband = phy->hw->wiphy->bands[band];
eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type);
- if (!eht_cap || !eht_cap->has_eht)
+ if (!eht_cap || !eht_cap->has_eht || !vif->bss_conf.eht_support)
return mode;
switch (band) {
@@ -3159,4 +3160,5 @@ exit:
EXPORT_SYMBOL_GPL(mt76_connac2_mcu_fill_message);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT76x connac layer helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 0563b1b22f48..ae6d0179727d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -416,6 +416,14 @@ struct sta_rec_he_6g_capa {
u8 rsv[2];
} __packed;
+struct sta_rec_pn_info {
+ __le16 tag;
+ __le16 len;
+ u8 pn[6];
+ u8 tsc_type;
+ u8 rsv;
+} __packed;
+
struct sec_key {
u8 cipher_id;
u8 cipher_len;
@@ -768,6 +776,7 @@ struct wtbl_raw {
sizeof(struct sta_rec_sec) + \
sizeof(struct sta_rec_ra_fixed) + \
sizeof(struct sta_rec_he_6g_capa) + \
+ sizeof(struct sta_rec_pn_info) + \
sizeof(struct tlv) + \
MT76_CONNAC_WTBL_UPDATE_MAX_SIZE)
@@ -798,6 +807,7 @@ enum {
STA_REC_HE_V2 = 0x19,
STA_REC_MLD = 0x20,
STA_REC_EHT = 0x22,
+ STA_REC_PN_INFO = 0x26,
STA_REC_HDRT = 0x28,
STA_REC_HDR_TRANS = 0x2B,
STA_REC_MAX_NUM
@@ -1021,7 +1031,9 @@ enum {
MCU_UNI_EVENT_RDD_REPORT = 0x11,
MCU_UNI_EVENT_ROC = 0x27,
MCU_UNI_EVENT_TX_DONE = 0x2d,
+ MCU_UNI_EVENT_THERMAL = 0x35,
MCU_UNI_EVENT_NIC_CAPAB = 0x43,
+ MCU_UNI_EVENT_WED_RRO = 0x57,
MCU_UNI_EVENT_PER_STA_INFO = 0x6d,
MCU_UNI_EVENT_ALL_STA_INFO = 0x6e,
};
@@ -1088,6 +1100,13 @@ enum mcu_cipher_type {
MCU_CIPHER_GCMP_256,
MCU_CIPHER_WAPI,
MCU_CIPHER_BIP_CMAC_128,
+ MCU_CIPHER_BIP_CMAC_256,
+ MCU_CIPHER_BCN_PROT_CMAC_128,
+ MCU_CIPHER_BCN_PROT_CMAC_256,
+ MCU_CIPHER_BCN_PROT_GMAC_128,
+ MCU_CIPHER_BCN_PROT_GMAC_256,
+ MCU_CIPHER_BIP_GMAC_128,
+ MCU_CIPHER_BIP_GMAC_256,
};
enum {
@@ -1240,6 +1259,7 @@ enum {
MCU_UNI_CMD_CHANNEL_SWITCH = 0x34,
MCU_UNI_CMD_THERMAL = 0x35,
MCU_UNI_CMD_VOW = 0x37,
+ MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
MCU_UNI_CMD_RRO = 0x57,
MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
MCU_UNI_CMD_PER_STA_INFO = 0x6d,
@@ -1307,6 +1327,7 @@ enum {
UNI_BSS_INFO_RATE = 11,
UNI_BSS_INFO_QBSS = 15,
UNI_BSS_INFO_SEC = 16,
+ UNI_BSS_INFO_BCN_PROT = 17,
UNI_BSS_INFO_TXCMD = 18,
UNI_BSS_INFO_UAPSD = 19,
UNI_BSS_INFO_PS = 21,
@@ -1325,7 +1346,7 @@ enum {
};
enum UNI_ALL_STA_INFO_TAG {
- UNI_ALL_STA_TX_RATE,
+ UNI_ALL_STA_TXRX_RATE,
UNI_ALL_STA_TX_STAT,
UNI_ALL_STA_TXRX_ADM_STAT,
UNI_ALL_STA_TXRX_AIR_TIME,
@@ -1768,6 +1789,12 @@ mt76_connac_mcu_get_cipher(int cipher)
return MCU_CIPHER_GCMP;
case WLAN_CIPHER_SUITE_GCMP_256:
return MCU_CIPHER_GCMP_256;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ return MCU_CIPHER_BIP_GMAC_128;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ return MCU_CIPHER_BIP_GMAC_256;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ return MCU_CIPHER_BIP_CMAC_256;
case WLAN_CIPHER_SUITE_SMS4:
return MCU_CIPHER_WAPI;
default:
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
index c3a392a1a659..bcd24c9072ec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
@@ -342,4 +342,5 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev)
return 0;
}
+MODULE_DESCRIPTION("MediaTek MT76x EEPROM helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index 9277ff38b7a2..293e66fa83d5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -302,6 +302,7 @@ static const struct pci_device_id mt76x0e_device_table[] = {
MODULE_DEVICE_TABLE(pci, mt76x0e_device_table);
MODULE_FIRMWARE(MT7610E_FIRMWARE);
MODULE_FIRMWARE(MT7650E_FIRMWARE);
+MODULE_DESCRIPTION("MediaTek MT76x0E (PCIe) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
static struct pci_driver mt76x0e_driver = {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 0422c332354a..dd042949cf82 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -336,6 +336,7 @@ err:
MODULE_DEVICE_TABLE(usb, mt76x0_device_table);
MODULE_FIRMWARE(MT7610E_FIRMWARE);
MODULE_FIRMWARE(MT7610U_FIRMWARE);
+MODULE_DESCRIPTION("MediaTek MT76x0U (USB) wireless driver");
MODULE_LICENSE("GPL");
static struct usb_driver mt76x0_driver = {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index 9b5e3fb7b0df..e5ad635d3c56 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -199,13 +199,14 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i),
MT76x02_TX_RING_SIZE,
- MT_TX_RING_BASE, 0);
+ MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
}
ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
- MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0);
+ MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE,
+ NULL, 0);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
index 02da543dfc5c..b2cc44914294 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
@@ -293,4 +293,5 @@ void mt76x02u_init_mcu(struct mt76_dev *dev)
EXPORT_SYMBOL_GPL(mt76x02u_init_mcu);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
+MODULE_DESCRIPTION("MediaTek MT76x02 MCU helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 8a0e8124b894..8020446be37b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -696,4 +696,5 @@ void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list);
+MODULE_DESCRIPTION("MediaTek MT76x02 helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
index 8c01855885ce..1fe5f5a02f93 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
@@ -506,4 +506,5 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76x2_eeprom_init);
+MODULE_DESCRIPTION("MediaTek MT76x2 EEPROM helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
index df85ebc6e1df..30959746e924 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
@@ -165,6 +165,7 @@ mt76x2e_resume(struct pci_dev *pdev)
MODULE_DEVICE_TABLE(pci, mt76x2e_device_table);
MODULE_FIRMWARE(MT7662_FIRMWARE);
MODULE_FIRMWARE(MT7662_ROM_PATCH);
+MODULE_DESCRIPTION("MediaTek MT76x2E (PCIe) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
static struct pci_driver mt76pci_driver = {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
index 55068f3252ef..ca78e14251c2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -147,4 +147,5 @@ static struct usb_driver mt76x2u_driver = {
module_usb_driver(mt76x2u_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
+MODULE_DESCRIPTION("MediaTek MT76x2U (USB) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 59a44d79aaed..c91a1c54027f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -9,18 +9,20 @@ static int
mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base)
{
struct mt7915_dev *dev = phy->dev;
+ struct mtk_wed_device *wed = NULL;
- if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
if (is_mt798x(&dev->mt76))
ring_base += MT_TXQ_ID(0) * MT_RING_SIZE;
else
ring_base = MT_WED_TX_RING_BASE;
idx -= MT_TXQ_ID(0);
+ wed = &dev->mt76.mmio.wed;
}
return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base,
- MT_WED_Q_TX(idx));
+ wed, MT_WED_Q_TX(idx));
}
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
@@ -492,7 +494,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) {
wa_rx_base = MT_WED_RX_RING_BASE;
wa_rx_idx = MT7915_RXQ_MCU_WA;
- dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE;
+ mdev->q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE;
+ mdev->q_rx[MT_RXQ_MCU_WA].wed = &mdev->mmio.wed;
} else {
wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA);
wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA);
@@ -507,9 +510,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
if (!dev->phy.mt76->band_idx) {
if (mtk_wed_device_active(&mdev->mmio.wed) &&
mtk_wed_get_rx_capa(&mdev->mmio.wed)) {
- dev->mt76.q_rx[MT_RXQ_MAIN].flags =
+ mdev->q_rx[MT_RXQ_MAIN].flags =
MT_WED_Q_RX(MT7915_RXQ_BAND0);
dev->mt76.rx_token_size += MT7915_RX_RING_SIZE;
+ mdev->q_rx[MT_RXQ_MAIN].wed = &mdev->mmio.wed;
}
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
@@ -528,6 +532,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
if (mtk_wed_device_active(&mdev->mmio.wed)) {
mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE;
+ mdev->q_rx[MT_RXQ_MAIN_WA].wed = &mdev->mmio.wed;
if (is_mt7916(mdev)) {
wa_rx_base = MT_WED_RX_RING_BASE;
wa_rx_idx = MT7915_RXQ_MCU_WA;
@@ -544,9 +549,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
if (dev->dbdc_support || dev->phy.mt76->band_idx) {
if (mtk_wed_device_active(&mdev->mmio.wed) &&
mtk_wed_get_rx_capa(&mdev->mmio.wed)) {
- dev->mt76.q_rx[MT_RXQ_BAND1].flags =
+ mdev->q_rx[MT_RXQ_BAND1].flags =
MT_WED_Q_RX(MT7915_RXQ_BAND1);
dev->mt76.rx_token_size += MT7915_RX_RING_SIZE;
+ mdev->q_rx[MT_RXQ_BAND1].wed = &mdev->mmio.wed;
}
/* rx data queue for band1 */
@@ -581,28 +587,6 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
return 0;
}
-static void mt7915_dma_wed_reset(struct mt7915_dev *dev)
-{
- struct mt76_dev *mdev = &dev->mt76;
-
- if (!test_bit(MT76_STATE_WED_RESET, &dev->mphy.state))
- return;
-
- complete(&mdev->mmio.wed_reset);
-
- if (!wait_for_completion_timeout(&dev->mt76.mmio.wed_reset_complete,
- 3 * HZ))
- dev_err(dev->mt76.dev, "wed reset complete timeout\n");
-}
-
-static void
-mt7915_dma_reset_tx_queue(struct mt7915_dev *dev, struct mt76_queue *q)
-{
- mt76_queue_reset(dev, q);
- if (mtk_wed_device_active(&dev->mt76.mmio.wed))
- mt76_dma_wed_setup(&dev->mt76, q, true);
-}
-
int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
{
struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1];
@@ -630,20 +614,20 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
mtk_wed_device_dma_reset(wed);
mt7915_dma_disable(dev, force);
- mt7915_dma_wed_reset(dev);
+ mt76_dma_wed_reset(&dev->mt76);
/* reset hw queues */
for (i = 0; i < __MT_TXQ_MAX; i++) {
- mt7915_dma_reset_tx_queue(dev, dev->mphy.q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]);
if (mphy_ext)
- mt7915_dma_reset_tx_queue(dev, mphy_ext->q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, mphy_ext->q_tx[i]);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
mt76_for_each_q_rx(&dev->mt76, i) {
- if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE)
+ if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i]))
continue;
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index 76be7308460b..3bb2643d1b26 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -11,6 +11,7 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
u8 *eeprom = mdev->eeprom.data;
u32 val = eeprom[MT_EE_DO_PRE_CAL];
u32 offs;
+ int ret;
if (!dev->flash_mode)
return 0;
@@ -25,7 +26,11 @@ static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
offs = is_mt7915(&dev->mt76) ? MT_EE_PRECAL : MT_EE_PRECAL_V2;
- return mt76_get_of_eeprom(mdev, dev->cal, offs, val);
+ ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, val);
+ if (!ret)
+ return ret;
+
+ return mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", val);
}
static int mt7915_check_eeprom(struct mt7915_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
index f3e56817d36e..adc26a222823 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
@@ -144,7 +144,8 @@ static inline bool
mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
{
u8 *eep = dev->mt76.eeprom.data;
- u8 val = eep[MT_EE_WIFI_CONF + 7];
+ u8 offs = is_mt7981(&dev->mt76) ? 8 : 7;
+ u8 val = eep[MT_EE_WIFI_CONF + offs];
if (band == NL80211_BAND_2GHZ)
return val & MT_EE_WIFI_CONF7_TSSI0_2G;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 81478289f17e..cea2f6d9050a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -275,10 +275,11 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
mt7915_led_set_config(led_cdev, 0xff, 0);
}
-void mt7915_init_txpower(struct mt7915_dev *dev,
- struct ieee80211_supported_band *sband)
+static void __mt7915_init_txpower(struct mt7915_phy *phy,
+ struct ieee80211_supported_band *sband)
{
- int i, n_chains = hweight8(dev->mphy.antenna_mask);
+ struct mt7915_dev *dev = phy->dev;
+ int i, n_chains = hweight16(phy->mt76->chainmask);
int nss_delta = mt76_tx_power_nss_delta(n_chains);
int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band);
struct mt76_power_limits limits;
@@ -296,7 +297,7 @@ void mt7915_init_txpower(struct mt7915_dev *dev,
}
target_power += pwr_delta;
- target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
+ target_power = mt76_get_rate_power_limits(phy->mt76, chan,
&limits,
target_power);
target_power += nss_delta;
@@ -307,6 +308,19 @@ void mt7915_init_txpower(struct mt7915_dev *dev,
}
}
+void mt7915_init_txpower(struct mt7915_phy *phy)
+{
+ if (!phy)
+ return;
+
+ if (phy->mt76->cap.has_2ghz)
+ __mt7915_init_txpower(phy, &phy->mt76->sband_2g.sband);
+ if (phy->mt76->cap.has_5ghz)
+ __mt7915_init_txpower(phy, &phy->mt76->sband_5g.sband);
+ if (phy->mt76->cap.has_6ghz)
+ __mt7915_init_txpower(phy, &phy->mt76->sband_6g.sband);
+}
+
static void
mt7915_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
@@ -322,9 +336,7 @@ mt7915_regd_notifier(struct wiphy *wiphy,
if (dev->mt76.region == NL80211_DFS_UNSET)
mt7915_mcu_rdd_background_enable(phy, NULL);
- mt7915_init_txpower(dev, &mphy->sband_2g.sband);
- mt7915_init_txpower(dev, &mphy->sband_5g.sband);
- mt7915_init_txpower(dev, &mphy->sband_6g.sband);
+ mt7915_init_txpower(phy);
mphy->dfs_state = MT_DFS_STATE_UNKNOWN;
mt7915_dfs_init_radar_detector(phy);
@@ -442,6 +454,7 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
mt76_set_stream_caps(phy->mt76, true);
mt7915_set_stream_vht_txbf_caps(phy);
mt7915_set_stream_he_caps(phy);
+ mt7915_init_txpower(phy);
wiphy->available_antennas_rx = phy->mt76->antenna_mask;
wiphy->available_antennas_tx = phy->mt76->antenna_mask;
@@ -703,9 +716,6 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_mcu_set_eeprom(dev);
mt7915_mac_init(dev);
- mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
- mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
- mt7915_init_txpower(dev, &dev->mphy.sband_6g.sband);
mt7915_txbf_init(dev);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 2222fb9aa103..b01edbed969c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -1247,7 +1247,7 @@ mt7915_phy_get_nf(struct mt7915_phy *phy, int idx)
void mt7915_update_channel(struct mt76_phy *mphy)
{
- struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv;
+ struct mt7915_phy *phy = mphy->priv;
struct mt76_channel_state *state = mphy->chan_state;
int nf;
@@ -1401,8 +1401,8 @@ mt7915_mac_restart(struct mt7915_dev *dev)
goto out;
mt7915_mac_init(dev);
- mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
- mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
+ mt7915_init_txpower(&dev->phy);
+ mt7915_init_txpower(phy2);
ret = mt7915_txbf_init(dev);
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index a3fd54cc1911..df2d4279790d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -1059,8 +1059,9 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
phy->mt76->antenna_mask = tx_ant;
- /* handle a variant of mt7916 which has 3T3R but nss2 on 5 GHz band */
- if (is_mt7916(&dev->mt76) && band && hweight8(tx_ant) == max_nss)
+ /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */
+ if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) &&
+ band && hweight8(tx_ant) == max_nss)
phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift;
else
phy->mt76->chainmask = tx_ant << (chainshift * band);
@@ -1653,20 +1654,6 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw,
return 0;
}
-
-static int
-mt7915_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct net_device *netdev, enum tc_setup_type type,
- void *type_data)
-{
- struct mt7915_dev *dev = mt7915_hw_dev(hw);
- struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
-
- if (!mtk_wed_device_active(wed))
- return -EOPNOTSUPP;
-
- return mtk_wed_device_setup_tc(wed, netdev, type, type_data);
-}
#endif
const struct ieee80211_ops mt7915_ops = {
@@ -1721,6 +1708,6 @@ const struct ieee80211_ops mt7915_ops = {
.set_radar_background = mt7915_set_radar_background,
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
.net_fill_forward_path = mt7915_net_fill_forward_path,
- .net_setup_tc = mt7915_net_setup_tc,
+ .net_setup_tc = mt76_net_setup_tc,
#endif
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index b22f06d4411a..c67c4f6ca2aa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -269,7 +269,7 @@ mt7915_mcu_rx_thermal_notify(struct mt7915_dev *dev, struct sk_buff *skb)
dev->mt76.phys[MT_BAND1])
mphy = dev->mt76.phys[MT_BAND1];
- phy = (struct mt7915_phy *)mphy->priv;
+ phy = mphy->priv;
phy->throttle_state = t->ctrl.duty.duty_cycle;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 1592b5d6751a..b41ac4aaced7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -519,7 +519,7 @@ static inline s8
mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower)
{
struct mt76_phy *mphy = phy->mt76;
- int n_chains = hweight8(mphy->antenna_mask);
+ int n_chains = hweight16(mphy->chainmask);
txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2);
txpower -= mt76_tx_power_nss_delta(n_chains);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index e7d8e03f826f..3039f53e2245 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -542,105 +542,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
}
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
-static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed)
-{
- struct mt7915_dev *dev;
-
- dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
-
- spin_lock_bh(&dev->mt76.token_lock);
- dev->mt76.token_size = wed->wlan.token_start;
- spin_unlock_bh(&dev->mt76.token_lock);
-
- return !wait_event_timeout(dev->mt76.tx_wait,
- !dev->mt76.wed_token_count, HZ);
-}
-
-static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
-{
- struct mt7915_dev *dev;
-
- dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
-
- spin_lock_bh(&dev->mt76.token_lock);
- dev->mt76.token_size = MT7915_TOKEN_SIZE;
- spin_unlock_bh(&dev->mt76.token_lock);
-}
-
-static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
-{
- struct mt7915_dev *dev;
- int i;
-
- dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
- for (i = 0; i < dev->mt76.rx_token_size; i++) {
- struct mt76_txwi_cache *t;
-
- t = mt76_rx_token_release(&dev->mt76, i);
- if (!t || !t->ptr)
- continue;
-
- mt76_put_page_pool_buf(t->ptr, false);
- t->ptr = NULL;
-
- mt76_put_rxwi(&dev->mt76, t);
- }
-
- mt76_free_pending_rxwi(&dev->mt76);
-}
-
-static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
-{
- struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc;
- struct mt76_txwi_cache *t = NULL;
- struct mt7915_dev *dev;
- struct mt76_queue *q;
- int i, len;
-
- dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
- q = &dev->mt76.q_rx[MT_RXQ_MAIN];
- len = SKB_WITH_OVERHEAD(q->buf_size);
-
- for (i = 0; i < size; i++) {
- enum dma_data_direction dir;
- dma_addr_t addr;
- u32 offset;
- int token;
- void *buf;
-
- t = mt76_get_rxwi(&dev->mt76);
- if (!t)
- goto unmap;
-
- buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
- if (!buf)
- goto unmap;
-
- addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
- dir = page_pool_get_dma_dir(q->page_pool);
- dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir);
-
- desc->buf0 = cpu_to_le32(addr);
- token = mt76_rx_token_consume(&dev->mt76, buf, t, addr);
- if (token < 0) {
- mt76_put_page_pool_buf(buf, false);
- goto unmap;
- }
-
- desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN,
- token));
- desc++;
- }
-
- return 0;
-
-unmap:
- if (t)
- mt76_put_rxwi(&dev->mt76, t);
- mt7915_mmio_wed_release_rx_buf(wed);
- return -ENOMEM;
-}
-
static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed,
struct mtk_wed_wo_rx_stats *stats)
{
@@ -694,13 +595,6 @@ out:
return ret;
}
-
-static void mt7915_mmio_wed_reset_complete(struct mtk_wed_device *wed)
-{
- struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
-
- complete(&dev->mmio.wed_reset_complete);
-}
#endif
int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
@@ -742,7 +636,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
if (!res)
- return -ENOMEM;
+ return 0;
wed->wlan.platform_dev = plat_dev;
wed->wlan.bus_type = MTK_WED_BUS_AXI;
@@ -778,13 +672,13 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
}
wed->wlan.init_buf = mt7915_wed_init_buf;
- wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable;
- wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable;
- wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf;
- wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf;
+ wed->wlan.offload_enable = mt76_mmio_wed_offload_enable;
+ wed->wlan.offload_disable = mt76_mmio_wed_offload_disable;
+ wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf;
+ wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf;
wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats;
wed->wlan.reset = mt7915_mmio_wed_reset;
- wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete;
+ wed->wlan.reset_complete = mt76_mmio_wed_reset_complete;
dev->mt76.rx_token_size = wed->wlan.rx_npkt;
@@ -1064,4 +958,5 @@ static void __exit mt7915_exit(void)
module_init(mt7915_init);
module_exit(mt7915_exit);
+MODULE_DESCRIPTION("MediaTek MT7915E MMIO helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index d317c523b23f..4727d9c7b11d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -425,8 +425,7 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset);
int mt7915_txbf_init(struct mt7915_dev *dev);
-void mt7915_init_txpower(struct mt7915_dev *dev,
- struct ieee80211_supported_band *sband);
+void mt7915_init_txpower(struct mt7915_phy *phy);
void mt7915_reset(struct mt7915_dev *dev);
int mt7915_run(struct ieee80211_hw *hw);
int mt7915_mcu_init(struct mt7915_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
index 06e3d9db996c..8b4809703efc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c
@@ -1282,13 +1282,11 @@ free_device:
return ret;
}
-static int mt798x_wmac_remove(struct platform_device *pdev)
+static void mt798x_wmac_remove(struct platform_device *pdev)
{
struct mt7915_dev *dev = platform_get_drvdata(pdev);
mt7915_unregister_device(dev);
-
- return 0;
}
static const struct of_device_id mt798x_wmac_of_match[] = {
@@ -1305,7 +1303,7 @@ struct platform_driver mt798x_wmac_driver = {
.of_match_table = mt798x_wmac_of_match,
},
.probe = mt798x_wmac_probe,
- .remove = mt798x_wmac_remove,
+ .remove_new = mt798x_wmac_remove,
};
MODULE_FIRMWARE(MT7986_FIRMWARE_WA);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 7d6a9d746011..48433c6d5e7d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -110,24 +110,37 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
}
}
+void mt7921_regd_update(struct mt792x_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct ieee80211_hw *hw = mdev->hw;
+ struct wiphy *wiphy = hw->wiphy;
+
+ mt7921_mcu_set_clc(dev, mdev->alpha2, dev->country_ie_env);
+ mt7921_regd_channel_update(wiphy, dev);
+ mt76_connac_mcu_set_channel_domain(hw->priv);
+ mt7921_set_tx_sar_pwr(hw, NULL);
+}
+EXPORT_SYMBOL_GPL(mt7921_regd_update);
+
static void
mt7921_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt76_connac_pm *pm = &dev->pm;
memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
dev->mt76.region = request->dfs_region;
dev->country_ie_env = request->country_ie_env;
+ if (pm->suspended)
+ return;
+
mt792x_mutex_acquire(dev);
- mt7921_mcu_set_clc(dev, request->alpha2, request->country_ie_env);
- mt76_connac_mcu_set_channel_domain(hw->priv);
- mt7921_set_tx_sar_pwr(hw, NULL);
+ mt7921_regd_update(dev);
mt792x_mutex_release(dev);
-
- mt7921_regd_channel_update(wiphy, dev);
}
int mt7921_mac_init(struct mt792x_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 510a575a973b..0d5adc5ddae3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -683,17 +683,45 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
}
static void
-mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif)
+mt7921_calc_vif_num(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ u32 *num = priv;
+
+ if (!priv)
+ return;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ *num += 1;
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_phy *phy = mvif->phy;
struct mt792x_dev *dev = phy->dev;
+ u32 valid_vif_num = 0;
+
+ ieee80211_iterate_active_interfaces(mt76_hw(dev),
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7921_calc_vif_num, &valid_vif_num);
- if (hweight64(dev->mt76.vif_mask) > 1) {
+ if (valid_vif_num > 1) {
phy->power_type = MT_AP_DEFAULT;
goto out;
}
+ if (!is_add)
+ vif->bss_conf.power_type = IEEE80211_REG_UNSET_AP;
+
switch (vif->bss_conf.power_type) {
case IEEE80211_REG_SP_AP:
phy->power_type = MT_AP_SP;
@@ -705,6 +733,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif)
phy->power_type = MT_AP_LPI;
break;
case IEEE80211_REG_UNSET_AP:
+ phy->power_type = MT_AP_UNSET;
+ break;
default:
phy->power_type = MT_AP_DEFAULT;
break;
@@ -749,7 +779,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (ret)
return ret;
- mt7921_regd_set_6ghz_power_type(vif);
+ mt7921_regd_set_6ghz_power_type(vif, true);
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
@@ -811,6 +841,8 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
list_del_init(&msta->wcid.poll_list);
spin_unlock_bh(&dev->mt76.sta_poll_lock);
+ mt7921_regd_set_6ghz_power_type(vif, false);
+
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove);
@@ -1386,5 +1418,6 @@ const struct ieee80211_ops mt7921_ops = {
};
EXPORT_SYMBOL_GPL(mt7921_ops);
+MODULE_DESCRIPTION("MediaTek MT7921 core driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 2cc2d2788f83..f5582477c7e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -160,7 +160,7 @@ static void
mt7921_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
+ struct mt792x_phy *phy = mphy->priv;
spin_lock_bh(&dev->mt76.lock);
__skb_queue_tail(&phy->scan_event_list, skb);
@@ -1261,15 +1261,19 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
u8 alpha2[2];
u8 type[2];
u8 env_6g;
- u8 rsvd[63];
+ u8 mtcl_conf;
+ u8 rsvd[62];
} __packed req = {
+ .ver = 1,
.idx = idx,
.env = env_cap,
.env_6g = dev->phy.power_type,
.acpi_conf = mt792x_acpi_get_flags(&dev->phy),
+ .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2),
};
int ret, valid_cnt = 0;
- u8 i, *pos;
+ u16 buf_len = 0;
+ u8 *pos;
if (!clc)
return 0;
@@ -1279,12 +1283,15 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
if (mt76_find_power_limits_node(&dev->mt76))
req.cap |= CLC_CAP_DTS_EN;
+ buf_len = le16_to_cpu(clc->len) - sizeof(*clc);
pos = clc->data;
- for (i = 0; i < clc->nr_country; i++) {
+ while (buf_len > 16) {
struct mt7921_clc_rule *rule = (struct mt7921_clc_rule *)pos;
u16 len = le16_to_cpu(rule->len);
+ u16 offset = len + sizeof(*rule);
- pos += len + sizeof(*rule);
+ pos += offset;
+ buf_len -= offset;
if (rule->alpha2[0] != alpha2[0] ||
rule->alpha2[1] != alpha2[1])
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index f28621121927..1cb21133992b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -12,7 +12,8 @@
#define MT7921_TX_FWDL_RING_SIZE 128
#define MT7921_RX_RING_SIZE 1536
-#define MT7921_RX_MCU_RING_SIZE 512
+#define MT7921_RX_MCU_RING_SIZE 8
+#define MT7921_RX_MCU_WA_RING_SIZE 512
#define MT7921_EEPROM_SIZE 3584
#define MT7921_TOKEN_SIZE 8192
@@ -233,6 +234,7 @@ mt7921_l1_rmw(struct mt792x_dev *dev, u32 addr, u32 mask, u32 val)
#define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val)
#define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0)
+void mt7921_regd_update(struct mt792x_dev *dev);
int mt7921_mac_init(struct mt792x_dev *dev);
bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask);
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index f04e7095e181..dde26f327478 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -171,7 +171,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev)
/* init tx queue */
ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0,
MT7921_TX_RING_SIZE,
- MT_TX_RING_BASE, 0);
+ MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
@@ -200,7 +200,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev)
/* Change mcu queue after firmware download */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT7921_RXQ_MCU_WM,
- MT7921_RX_MCU_RING_SIZE,
+ MT7921_RX_MCU_WA_RING_SIZE,
MT_RX_BUF_SIZE, MT_WFDMA0(0x540));
if (ret)
return ret;
@@ -507,6 +507,9 @@ static int mt7921_pci_resume(struct device *device)
mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
err = mt76_connac_mcu_set_hif_suspend(mdev, false);
+
+ mt7921_regd_update(dev);
+
failed:
pm->suspended = false;
@@ -541,4 +544,5 @@ MODULE_FIRMWARE(MT7922_FIRMWARE_WM);
MODULE_FIRMWARE(MT7922_ROM_PATCH);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
index dc1beb76df3e..a9ce1e746b95 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c
@@ -228,7 +228,7 @@ static int mt7921s_suspend(struct device *__dev)
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&mdev->tx_worker);
mt76_worker_disable(&mdev->sdio.status_worker);
- cancel_work_sync(&mdev->sdio.stat_work);
+ mt76_worker_disable(&mdev->sdio.stat_worker);
clear_bit(MT76_READING_STATS, &dev->mphy.state);
mt76_tx_status_check(mdev, true);
@@ -260,6 +260,7 @@ restore_txrx_worker:
restore_worker:
mt76_worker_enable(&mdev->tx_worker);
mt76_worker_enable(&mdev->sdio.status_worker);
+ mt76_worker_enable(&mdev->sdio.stat_worker);
if (!pm->ds_enable)
mt76_connac_mcu_set_deep_sleep(mdev, false);
@@ -292,6 +293,7 @@ static int mt7921s_resume(struct device *__dev)
mt76_worker_enable(&mdev->sdio.txrx_worker);
mt76_worker_enable(&mdev->sdio.status_worker);
mt76_worker_enable(&mdev->sdio.net_worker);
+ mt76_worker_enable(&mdev->sdio.stat_worker);
/* restore previous ds setting */
if (!pm->ds_enable)
@@ -321,5 +323,6 @@ static struct sdio_driver mt7921s_driver = {
.drv.pm = pm_sleep_ptr(&mt7921s_pm_ops),
};
module_sdio_driver(mt7921s_driver);
+MODULE_DESCRIPTION("MediaTek MT7921S (SDIO) wireless driver");
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
index 8edd0291c128..389eb0903807 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c
@@ -107,7 +107,7 @@ int mt7921s_mac_reset(struct mt792x_dev *dev)
mt76_worker_disable(&dev->mt76.sdio.txrx_worker);
mt76_worker_disable(&dev->mt76.sdio.status_worker);
mt76_worker_disable(&dev->mt76.sdio.net_worker);
- cancel_work_sync(&dev->mt76.sdio.stat_work);
+ mt76_worker_disable(&dev->mt76.sdio.stat_worker);
mt7921s_disable_irq(&dev->mt76);
mt7921s_wfsys_reset(dev);
@@ -115,6 +115,7 @@ int mt7921s_mac_reset(struct mt792x_dev *dev)
mt76_worker_enable(&dev->mt76.sdio.txrx_worker);
mt76_worker_enable(&dev->mt76.sdio.status_worker);
mt76_worker_enable(&dev->mt76.sdio.net_worker);
+ mt76_worker_enable(&dev->mt76.sdio.stat_worker);
dev->fw_assert = false;
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index e5258c74fc07..8b7c03c47598 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -336,5 +336,6 @@ static struct usb_driver mt7921u_driver = {
};
module_usb_driver(mt7921u_driver);
+MODULE_DESCRIPTION("MediaTek MT7921U (USB) wireless driver");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index aa918b9b0469..125a1be3cb64 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -154,8 +154,7 @@ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band,
static void
mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,
- struct ieee80211_sband_iftype_data *data,
- enum nl80211_iftype iftype)
+ struct ieee80211_sband_iftype_data *data)
{
struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap;
struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;
@@ -256,7 +255,7 @@ __mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy,
data[n].types_mask = BIT(i);
mt7925_init_he_caps(phy, band, &data[n], i);
- mt7925_init_eht_caps(phy, band, &data[n], i);
+ mt7925_init_eht_caps(phy, band, &data[n]);
n++;
}
@@ -1451,4 +1450,5 @@ const struct ieee80211_ops mt7925_ops = {
EXPORT_SYMBOL_GPL(mt7925_ops);
MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek MT7925 core driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 9c0e397537ac..c5fd7116929b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -345,7 +345,7 @@ static void
mt7925_mcu_scan_event(struct mt792x_dev *dev, struct sk_buff *skb)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
+ struct mt792x_phy *phy = mphy->priv;
spin_lock_bh(&dev->mt76.lock);
__skb_queue_tail(&phy->scan_event_list, skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index 08ef75e24e1c..1fd99a856541 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -218,7 +218,7 @@ static int mt7925_dma_init(struct mt792x_dev *dev)
/* init tx queue */
ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0,
MT7925_TX_RING_SIZE,
- MT_TX_RING_BASE, 0);
+ MT_TX_RING_BASE, NULL, 0);
if (ret)
return ret;
@@ -583,4 +583,5 @@ MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
MODULE_FIRMWARE(MT7925_ROM_PATCH);
MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
index 9b885c5b3ed5..1e0f094fc905 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
@@ -329,4 +329,5 @@ static struct usb_driver mt7925u_driver = {
module_usb_driver(mt7925u_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT7925U (USB) wireless driver");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 36fae736dd19..3c897b34aaa7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -382,6 +382,7 @@ int mt792xe_mcu_fw_pmctrl(struct mt792x_dev *dev);
int mt792x_init_acpi_sar(struct mt792x_dev *dev);
int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default);
u8 mt792x_acpi_get_flags(struct mt792x_phy *phy);
+u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2);
#else
static inline int mt792x_init_acpi_sar(struct mt792x_dev *dev)
{
@@ -398,6 +399,11 @@ static inline u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)
{
return 0;
}
+
+static inline u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2)
+{
+ return 0xf;
+}
#endif
#endif /* __MT7925_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
index 303c0f5c9c66..e7afea87e82e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c
@@ -348,3 +348,56 @@ u8 mt792x_acpi_get_flags(struct mt792x_phy *phy)
return flags;
}
EXPORT_SYMBOL_GPL(mt792x_acpi_get_flags);
+
+static u8
+mt792x_acpi_get_mtcl_map(int row, int column, struct mt792x_asar_cl *cl)
+{
+ u8 config = 0;
+
+ if (cl->cl6g[row] & BIT(column))
+ config |= (cl->mode_6g & 0x3) << 2;
+ if (cl->version > 1 && cl->cl5g9[row] & BIT(column))
+ config |= (cl->mode_5g9 & 0x3);
+
+ return config;
+}
+
+u8 mt792x_acpi_get_mtcl_conf(struct mt792x_phy *phy, char *alpha2)
+{
+ static const char * const cc_list_all[] = {
+ "00", "EU", "AR", "AU", "AZ", "BY", "BO", "BR",
+ "CA", "CL", "CN", "ID", "JP", "MY", "MX", "ME",
+ "MA", "NZ", "NG", "PH", "RU", "RS", "SG", "KR",
+ "TW", "TH", "UA", "GB", "US", "VN", "KH", "PY",
+ };
+ static const char * const cc_list_eu[] = {
+ "AT", "BE", "BG", "CY", "CZ", "HR", "DK", "EE",
+ "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT",
+ "LV", "LI", "LT", "LU", "MT", "NL", "NO", "PL",
+ "PT", "RO", "MT", "SK", "SI", "ES", "CH",
+ };
+ struct mt792x_acpi_sar *sar = phy->acpisar;
+ struct mt792x_asar_cl *cl;
+ int col, row, i;
+
+ if (!sar)
+ return 0xf;
+
+ cl = sar->countrylist;
+ if (!cl)
+ return 0xc;
+
+ for (i = 0; i < ARRAY_SIZE(cc_list_all); i++) {
+ col = 7 - i % 8;
+ row = i / 8;
+ if (!memcmp(cc_list_all[i], alpha2, 2))
+ return mt792x_acpi_get_mtcl_map(row, col, cl);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cc_list_eu); i++)
+ if (!memcmp(cc_list_eu[i], alpha2, 2))
+ return mt792x_acpi_get_mtcl_map(0, 6, cl);
+
+ return mt792x_acpi_get_mtcl_map(0, 7, cl);
+}
+EXPORT_SYMBOL_GPL(mt792x_acpi_get_mtcl_conf);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
index d6d332e863ba..2298983b6342 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.h
@@ -77,6 +77,8 @@ struct mt792x_asar_cl {
u8 version;
u8 mode_6g;
u8 cl6g[6];
+ u8 mode_5g9;
+ u8 cl5g9[6];
} __packed;
struct mt792x_asar_fg {
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
index 502be22dbe36..c42101aa9e45 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
@@ -862,5 +862,6 @@ int mt792x_load_firmware(struct mt792x_dev *dev)
}
EXPORT_SYMBOL_GPL(mt792x_load_firmware);
+MODULE_DESCRIPTION("MediaTek MT792x core driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c
index 5d1f8229fdc1..eb29434abee1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c
@@ -223,7 +223,7 @@ static void
mt792x_phy_update_channel(struct mt76_phy *mphy, int idx)
{
struct mt792x_dev *dev = container_of(mphy->dev, struct mt792x_dev, mt76);
- struct mt792x_phy *phy = (struct mt792x_phy *)mphy->priv;
+ struct mt792x_phy *phy = mphy->priv;
struct mt76_channel_state *state;
u64 busy_time, tx_time, rx_time, obss_time;
int nf;
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 2dd283caed36..589a3efb9f8c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -314,5 +314,6 @@ void mt792xu_disconnect(struct usb_interface *usb_intf)
}
EXPORT_SYMBOL_GPL(mt792xu_disconnect);
+MODULE_DESCRIPTION("MediaTek MT792x USB helpers");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
index 4d40ec7ff57f..9bd953586b04 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
@@ -476,7 +476,7 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s)
{
struct mt76_mib_stats *mib = &phy->mib;
static const char * const bw[] = {
- "BW20", "BW40", "BW80", "BW160"
+ "BW20", "BW40", "BW80", "BW160", "BW320"
};
/* Tx Beamformer monitor */
@@ -489,8 +489,9 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s)
/* Tx Beamformer Rx feedback monitor */
seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
- seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
+ seq_printf(s, "All: %d, EHT: %d, HE: %d, VHT: %d, HT: %d, ",
mib->tx_bf_rx_fb_all_cnt,
+ mib->tx_bf_rx_fb_eht_cnt,
mib->tx_bf_rx_fb_he_cnt,
mib->tx_bf_rx_fb_vht_cnt,
mib->tx_bf_rx_fb_ht_cnt);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
index 586e247a1e06..483ad81b6eec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
@@ -7,6 +7,26 @@
#include "../dma.h"
#include "mac.h"
+int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc,
+ int ring_base, struct mtk_wed_device *wed)
+{
+ struct mt7996_dev *dev = phy->dev;
+ u32 flags = 0;
+
+ if (mtk_wed_device_active(wed)) {
+ ring_base += MT_TXQ_ID(0) * MT_RING_SIZE;
+ idx -= MT_TXQ_ID(0);
+
+ if (phy->mt76->band_idx == MT_BAND2)
+ flags = MT_WED_Q_TX(0);
+ else
+ flags = MT_WED_Q_TX(idx);
+ }
+
+ return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc,
+ ring_base, wed, flags);
+}
+
static int mt7996_poll_tx(struct napi_struct *napi, int budget)
{
struct mt7996_dev *dev;
@@ -37,18 +57,51 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM);
RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA);
- /* band0/band1 */
+ /* mt7996: band0 and band1, mt7992: band0 */
RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0);
RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN);
- /* band2 */
- RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2);
- RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI);
+ if (is_mt7996(&dev->mt76)) {
+ /* mt7996 band2 */
+ RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2);
+ RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI);
+ } else {
+ /* mt7992 band1 */
+ RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1);
+ RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT);
+ }
+
+ if (dev->has_rro) {
+ /* band0 */
+ RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0,
+ MT7996_RXQ_RRO_BAND0);
+ RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0,
+ MT7996_RXQ_MSDU_PG_BAND0);
+ RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN,
+ MT7996_RXQ_TXFREE0);
+ /* band1 */
+ RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1,
+ MT7996_RXQ_MSDU_PG_BAND1);
+ /* band2 */
+ RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2,
+ MT7996_RXQ_RRO_BAND2);
+ RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2,
+ MT7996_RXQ_MSDU_PG_BAND2);
+ RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI,
+ MT7996_RXQ_TXFREE2);
+
+ RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND,
+ MT7996_RXQ_RRO_IND);
+ }
/* data tx queue */
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
- TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
- TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
+ if (is_mt7996(&dev->mt76)) {
+ TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
+ TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
+ } else {
+ TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
+ }
/* mcu tx queue */
MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM);
@@ -56,22 +109,57 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL);
}
+static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth)
+{
+ u32 ret = *base << 16 | depth;
+
+ *base = *base + (depth << 4);
+
+ return ret;
+}
+
static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs)
{
-#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth))
+ u16 base = 0;
+ u8 queue;
+
+#define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth)))
/* prefetch SRAM wrapping boundary for tx/rx ring. */
- mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x2));
- mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2));
- mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4));
- mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4));
- mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2));
- mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10));
+ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x8));
+ mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8));
+ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2));
+
+ queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA;
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2));
+
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10));
+
+ queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2 : MT_RXQ_BAND1;
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x10));
+
+ if (dev->has_rro) {
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs,
+ PREFETCH(0x10));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs,
+ PREFETCH(0x10));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs,
+ PREFETCH(0x4));
+ }
+#undef PREFETCH
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE);
}
@@ -128,8 +216,9 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset)
}
}
-void mt7996_dma_start(struct mt7996_dev *dev, bool reset)
+void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset)
{
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
u32 hif1_ofs = 0;
u32 irq_mask;
@@ -138,37 +227,49 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset)
/* enable WFDMA Tx/Rx */
if (!reset) {
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed))
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_EXT_EN);
+ else
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
if (dev->hif2)
mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 |
+ MT_WFDMA0_GLO_CFG_EXT_EN);
}
/* enable interrupts for TX/RX rings */
- irq_mask = MT_INT_MCU_CMD;
- if (reset)
- goto done;
+ irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU;
- irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU;
-
- if (!dev->mphy.band_idx)
+ if (mt7996_band_valid(dev, MT_BAND0))
irq_mask |= MT_INT_BAND0_RX_DONE;
- if (dev->dbdc_support)
+ if (mt7996_band_valid(dev, MT_BAND1))
irq_mask |= MT_INT_BAND1_RX_DONE;
- if (dev->tbtc_support)
+ if (mt7996_band_valid(dev, MT_BAND2))
irq_mask |= MT_INT_BAND2_RX_DONE;
-done:
+ if (mtk_wed_device_active(wed) && wed_reset) {
+ u32 wed_irq_mask = irq_mask;
+
+ wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1;
+ mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
+ mtk_wed_device_start(wed, wed_irq_mask);
+ }
+
+ irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;
+
mt7996_irq_enable(dev, irq_mask);
mt7996_irq_disable(dev, 0);
}
@@ -223,6 +324,12 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1,
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
+ /* WFDMA rx threshold */
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH, 0xc000c);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH, 0x20);
+
if (dev->hif2) {
/* GLO_CFG_EXT0 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
@@ -234,24 +341,108 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
- MT_WFDMA_HOST_CONFIG_PDMA_BAND);
+ MT_WFDMA_HOST_CONFIG_PDMA_BAND |
+ MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
+
+ /* AXI read outstanding number */
+ mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
+ MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
+
+ /* WFDMA rx threshold */
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH + hif1_ofs, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH + hif1_ofs, 0x20);
}
if (dev->hif2) {
/* fix hardware limitation, pcie1's rx ring3 is not available
* so, redirect pcie0 rx ring3 interrupt to pcie1
*/
- mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL,
- MT_WFDMA0_RX_INT_SEL_RING3);
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ dev->has_rro)
+ mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs,
+ MT_WFDMA0_RX_INT_SEL_RING6);
+ else
+ mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL,
+ MT_WFDMA0_RX_INT_SEL_RING3);
+ }
+
+ mt7996_dma_start(dev, reset, true);
+}
+
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+int mt7996_dma_rro_init(struct mt7996_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ u32 irq_mask;
+ int ret;
- /* TODO: redirect rx ring6 interrupt to pcie0 for wed function */
+ /* ind cmd */
+ mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND;
+ mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed;
+ ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND],
+ MT_RXQ_ID(MT_RXQ_RRO_IND),
+ MT7996_RX_RING_SIZE,
+ 0, MT_RXQ_RRO_IND_RING_BASE);
+ if (ret)
+ return ret;
+
+ /* rx msdu page queue for band0 */
+ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags =
+ MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN;
+ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed;
+ ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0],
+ MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_MSDU_PAGE_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0));
+ if (ret)
+ return ret;
+
+ if (mt7996_band_valid(dev, MT_BAND1)) {
+ /* rx msdu page queue for band1 */
+ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags =
+ MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN;
+ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed;
+ ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1],
+ MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_MSDU_PAGE_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1));
+ if (ret)
+ return ret;
}
- mt7996_dma_start(dev, reset);
+ if (mt7996_band_valid(dev, MT_BAND2)) {
+ /* rx msdu page queue for band2 */
+ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags =
+ MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN;
+ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed;
+ ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2],
+ MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_MSDU_PAGE_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2));
+ if (ret)
+ return ret;
+ }
+
+ irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE |
+ MT_INT_TX_DONE_BAND2;
+ mt76_wr(dev, MT_INT_MASK_CSR, irq_mask);
+ mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false);
+ mt7996_irq_enable(dev, irq_mask);
+
+ return 0;
}
+#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
int mt7996_dma_init(struct mt7996_dev *dev)
{
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+ struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2;
+ u32 rx_base;
u32 hif1_ofs = 0;
int ret;
@@ -265,10 +456,11 @@ int mt7996_dma_init(struct mt7996_dev *dev)
mt7996_dma_disable(dev, true);
/* init tx queue */
- ret = mt76_connac_init_tx_queues(dev->phy.mt76,
- MT_TXQ_ID(dev->mphy.band_idx),
- MT7996_TX_RING_SIZE,
- MT_TXQ_RING_BASE(0), 0);
+ ret = mt7996_init_tx_queues(&dev->phy,
+ MT_TXQ_ID(dev->mphy.band_idx),
+ MT7996_TX_RING_SIZE,
+ MT_TXQ_RING_BASE(0),
+ wed);
if (ret)
return ret;
@@ -314,7 +506,12 @@ int mt7996_dma_init(struct mt7996_dev *dev)
if (ret)
return ret;
- /* rx data queue for band0 and band1 */
+ /* rx data queue for band0 and mt7996 band1 */
+ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) {
+ dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0);
+ dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed;
+ }
+
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
MT_RXQ_ID(MT_RXQ_MAIN),
MT7996_RX_RING_SIZE,
@@ -324,6 +521,11 @@ int mt7996_dma_init(struct mt7996_dev *dev)
return ret;
/* tx free notify event from WA for band0 */
+ if (mtk_wed_device_active(wed) && !dev->has_rro) {
+ dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE;
+ dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed;
+ }
+
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA],
MT_RXQ_ID(MT_RXQ_MAIN_WA),
MT7996_RX_MCU_RING_SIZE,
@@ -332,19 +534,25 @@ int mt7996_dma_init(struct mt7996_dev *dev)
if (ret)
return ret;
- if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) {
- /* rx data queue for band2 */
+ if (mt7996_band_valid(dev, MT_BAND2)) {
+ /* rx data queue for mt7996 band2 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs;
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2],
MT_RXQ_ID(MT_RXQ_BAND2),
MT7996_RX_RING_SIZE,
MT_RX_BUF_SIZE,
- MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs);
+ rx_base);
if (ret)
return ret;
- /* tx free notify event from WA for band2
+ /* tx free notify event from WA for mt7996 band2
* use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1
*/
+ if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) {
+ dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE;
+ dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2;
+ }
+
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA],
MT_RXQ_ID(MT_RXQ_BAND2_WA),
MT7996_RX_MCU_RING_SIZE,
@@ -352,6 +560,80 @@ int mt7996_dma_init(struct mt7996_dev *dev)
MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA));
if (ret)
return ret;
+ } else if (mt7996_band_valid(dev, MT_BAND1)) {
+ /* rx data queue for mt7992 band1 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs;
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1],
+ MT_RXQ_ID(MT_RXQ_BAND1),
+ MT7996_RX_RING_SIZE,
+ MT_RX_BUF_SIZE,
+ rx_base);
+ if (ret)
+ return ret;
+
+ /* tx free notify event from WA for mt7992 band1 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs;
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA],
+ MT_RXQ_ID(MT_RXQ_BAND1_WA),
+ MT7996_RX_MCU_RING_SIZE,
+ MT_RX_BUF_SIZE,
+ rx_base);
+ if (ret)
+ return ret;
+ }
+
+ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) &&
+ dev->has_rro) {
+ /* rx rro data queue for band0 */
+ dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags =
+ MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN;
+ dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed;
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0],
+ MT_RXQ_ID(MT_RXQ_RRO_BAND0),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0));
+ if (ret)
+ return ret;
+
+ /* tx free notify event from WA for band0 */
+ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE;
+ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed;
+
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0],
+ MT_RXQ_ID(MT_RXQ_TXFREE_BAND0),
+ MT7996_RX_MCU_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0));
+ if (ret)
+ return ret;
+
+ if (mt7996_band_valid(dev, MT_BAND2)) {
+ /* rx rro data queue for band2 */
+ dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags =
+ MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN;
+ dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed;
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2],
+ MT_RXQ_ID(MT_RXQ_RRO_BAND2),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs);
+ if (ret)
+ return ret;
+
+ /* tx free notify event from MAC for band2 */
+ if (mtk_wed_device_active(wed_hif2)) {
+ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE;
+ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2;
+ }
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2],
+ MT_RXQ_ID(MT_RXQ_TXFREE_BAND2),
+ MT7996_RX_MCU_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs);
+ if (ret)
+ return ret;
+ }
}
ret = mt76_init_queues(dev, mt76_dma_rx_poll);
@@ -405,21 +687,33 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
if (force)
mt7996_wfsys_reset(dev);
+ if (dev->hif2 && mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_dma_reset(&dev->mt76.mmio.wed_hif2);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_dma_reset(&dev->mt76.mmio.wed);
+
mt7996_dma_disable(dev, force);
+ mt76_dma_wed_reset(&dev->mt76);
/* reset hw queues */
for (i = 0; i < __MT_TXQ_MAX; i++) {
- mt76_queue_reset(dev, dev->mphy.q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]);
if (phy2)
- mt76_queue_reset(dev, phy2->q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, phy2->q_tx[i]);
if (phy3)
- mt76_queue_reset(dev, phy3->q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, phy3->q_tx[i]);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
mt76_for_each_q_rx(&dev->mt76, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) ||
+ mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i]))
+ continue;
+
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
index 544b6c6f1ea3..4a8237118287 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
@@ -14,7 +14,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
switch (val) {
case 0x7990:
- return 0;
+ return is_mt7996(&dev->mt76) ? 0 : -EINVAL;
+ case 0x7992:
+ return is_mt7992(&dev->mt76) ? 0 : -EINVAL;
default:
return -EINVAL;
}
@@ -22,8 +24,14 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
static char *mt7996_eeprom_name(struct mt7996_dev *dev)
{
- /* reserve for future variants */
- return MT7996_EEPROM_DEFAULT;
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7990:
+ return MT7996_EEPROM_DEFAULT;
+ case 0x7992:
+ return MT7992_EEPROM_DEFAULT;
+ default:
+ return MT7996_EEPROM_DEFAULT;
+ }
}
static int
@@ -103,7 +111,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP);
}
- if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4)
+ if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 ||
+ is_mt7992(&dev->mt76))
dev->wtbl_size_group = 2; /* set default */
return 0;
@@ -148,36 +157,49 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
{
- u8 path, nss, band_idx = phy->mt76->band_idx;
+ u8 path, rx_path, nss, band_idx = phy->mt76->band_idx;
u8 *eeprom = dev->mt76.eeprom.data;
struct mt76_phy *mphy = phy->mt76;
+ int max_path = 5, max_nss = 4;
int ret;
switch (band_idx) {
case MT_BAND1:
path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
eeprom[MT_EE_WIFI_CONF + 2]);
+ rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1,
+ eeprom[MT_EE_WIFI_CONF + 3]);
nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
eeprom[MT_EE_WIFI_CONF + 5]);
break;
case MT_BAND2:
path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
eeprom[MT_EE_WIFI_CONF + 2]);
+ rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2,
+ eeprom[MT_EE_WIFI_CONF + 4]);
nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
eeprom[MT_EE_WIFI_CONF + 5]);
break;
default:
path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
eeprom[MT_EE_WIFI_CONF + 1]);
+ rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0,
+ eeprom[MT_EE_WIFI_CONF + 3]);
nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
eeprom[MT_EE_WIFI_CONF + 4]);
break;
}
- if (!path || path > 4)
- path = 4;
+ if (!path || path > max_path)
+ path = max_path;
+
+ if (!nss || nss > max_nss)
+ nss = max_nss;
+
+ nss = min_t(u8, nss, path);
- nss = min_t(u8, min_t(u8, 4, nss), path);
+ if (path != rx_path)
+ phy->has_aux_rx = true;
mphy->antenna_mask = BIT(nss) - 1;
mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h
index 0c749774f6b1..412d6e2f8014 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h
@@ -33,6 +33,9 @@ enum mt7996_eeprom_field {
#define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3)
+#define MT_EE_WIFI_CONF3_RX_PATH_BAND0 GENMASK(2, 0)
+#define MT_EE_WIFI_CONF3_RX_PATH_BAND1 GENMASK(5, 3)
+#define MT_EE_WIFI_CONF4_RX_PATH_BAND2 GENMASK(2, 0)
#define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index 55cb1770fa34..0cf0d1fe420a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -5,6 +5,8 @@
#include <linux/etherdevice.h>
#include <linux/of.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/thermal.h>
#include "mt7996.h"
#include "mac.h"
@@ -43,6 +45,183 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
+static ssize_t mt7996_thermal_temp_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mt7996_phy *phy = dev_get_drvdata(dev);
+ int i = to_sensor_dev_attr(attr)->index;
+ int temperature;
+
+ switch (i) {
+ case 0:
+ temperature = mt7996_mcu_get_temperature(phy);
+ if (temperature < 0)
+ return temperature;
+ /* display in millidegree celcius */
+ return sprintf(buf, "%u\n", temperature * 1000);
+ case 1:
+ case 2:
+ return sprintf(buf, "%u\n",
+ phy->throttle_temp[i - 1] * 1000);
+ case 3:
+ return sprintf(buf, "%hhu\n", phy->throttle_state);
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t mt7996_thermal_temp_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mt7996_phy *phy = dev_get_drvdata(dev);
+ int ret, i = to_sensor_dev_attr(attr)->index;
+ long val;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130);
+
+ /* add a safety margin ~10 */
+ if ((i - 1 == MT7996_CRIT_TEMP_IDX &&
+ val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) ||
+ (i - 1 == MT7996_MAX_TEMP_IDX &&
+ val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) {
+ dev_err(phy->dev->mt76.dev,
+ "temp1_max shall be 10 degrees higher than temp1_crit.");
+ mutex_unlock(&phy->dev->mt76.mutex);
+ return -EINVAL;
+ }
+
+ phy->throttle_temp[i - 1] = val;
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+ ret = mt7996_mcu_set_thermal_protect(phy, true);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0);
+static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1);
+static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2);
+static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3);
+
+static struct attribute *mt7996_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_throttle1.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(mt7996_hwmon);
+
+static int
+mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = MT7996_CDEV_THROTTLE_MAX;
+
+ return 0;
+}
+
+static int
+mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct mt7996_phy *phy = cdev->devdata;
+
+ *state = phy->cdev_state;
+
+ return 0;
+}
+
+static int
+mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct mt7996_phy *phy = cdev->devdata;
+ u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
+ int ret;
+
+ if (state > MT7996_CDEV_THROTTLE_MAX) {
+ dev_err(phy->dev->mt76.dev,
+ "please specify a valid throttling state\n");
+ return -EINVAL;
+ }
+
+ if (state == phy->cdev_state)
+ return 0;
+
+ /* cooling_device convention: 0 = no cooling, more = more cooling
+ * mcu convention: 1 = max cooling, more = less cooling
+ */
+ ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
+ if (ret)
+ return ret;
+
+ phy->cdev_state = state;
+
+ return 0;
+}
+
+static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
+ .get_max_state = mt7996_thermal_get_max_throttle_state,
+ .get_cur_state = mt7996_thermal_get_cur_throttle_state,
+ .set_cur_state = mt7996_thermal_set_cur_throttle_state,
+};
+
+static void mt7996_unregister_thermal(struct mt7996_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+
+ if (!phy->cdev)
+ return;
+
+ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
+ thermal_cooling_device_unregister(phy->cdev);
+}
+
+static int mt7996_thermal_init(struct mt7996_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct thermal_cooling_device *cdev;
+ struct device *hwmon;
+ const char *name;
+
+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
+ wiphy_name(wiphy));
+
+ cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
+ if (!IS_ERR(cdev)) {
+ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
+ "cooling_device") < 0)
+ thermal_cooling_device_unregister(cdev);
+ else
+ phy->cdev = cdev;
+ }
+
+ /* initialize critical/maximum high temperature */
+ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
+ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
+
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
+ mt7996_hwmon_groups);
+
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ return 0;
+}
+
static void mt7996_led_set_config(struct led_classdev *led_cdev,
u8 delay_on, u8 delay_off)
{
@@ -109,10 +288,11 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev,
mt7996_led_set_config(led_cdev, 0xff, 0);
}
-void mt7996_init_txpower(struct mt7996_dev *dev,
- struct ieee80211_supported_band *sband)
+static void __mt7996_init_txpower(struct mt7996_phy *phy,
+ struct ieee80211_supported_band *sband)
{
- int i, nss = hweight8(dev->mphy.antenna_mask);
+ struct mt7996_dev *dev = phy->dev;
+ int i, nss = hweight16(phy->mt76->chainmask);
int nss_delta = mt76_tx_power_nss_delta(nss);
int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band);
struct mt76_power_limits limits;
@@ -122,7 +302,7 @@ void mt7996_init_txpower(struct mt7996_dev *dev,
int target_power = mt7996_eeprom_get_target_power(dev, chan);
target_power += pwr_delta;
- target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
+ target_power = mt76_get_rate_power_limits(phy->mt76, chan,
&limits,
target_power);
target_power += nss_delta;
@@ -133,6 +313,19 @@ void mt7996_init_txpower(struct mt7996_dev *dev,
}
}
+void mt7996_init_txpower(struct mt7996_phy *phy)
+{
+ if (!phy)
+ return;
+
+ if (phy->mt76->cap.has_2ghz)
+ __mt7996_init_txpower(phy, &phy->mt76->sband_2g.sband);
+ if (phy->mt76->cap.has_5ghz)
+ __mt7996_init_txpower(phy, &phy->mt76->sband_5g.sband);
+ if (phy->mt76->cap.has_6ghz)
+ __mt7996_init_txpower(phy, &phy->mt76->sband_6g.sband);
+}
+
static void
mt7996_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
@@ -147,16 +340,14 @@ mt7996_regd_notifier(struct wiphy *wiphy,
if (dev->mt76.region == NL80211_DFS_UNSET)
mt7996_mcu_rdd_background_enable(phy, NULL);
- mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband);
- mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband);
- mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband);
+ mt7996_init_txpower(phy);
phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
mt7996_dfs_init_radar_detector(phy);
}
static void
-mt7996_init_wiphy(struct ieee80211_hw *hw)
+mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
{
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt76_dev *mdev = &phy->dev->mt76;
@@ -168,11 +359,14 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
hw->max_rx_aggregation_subframes = max_subframes;
hw->max_tx_aggregation_subframes = max_subframes;
hw->netdev_features = NETIF_F_RXCSUM;
+ if (mtk_wed_device_active(wed))
+ hw->netdev_features |= NETIF_F_HW_TC;
hw->radiotap_timestamp.units_pos =
IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US;
phy->slottime = 9;
+ phy->beacon_rate = -1;
hw->sta_data_size = sizeof(struct mt7996_sta);
hw->vif_data_size = sizeof(struct mt7996_vif);
@@ -242,6 +436,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
mt76_set_stream_caps(phy->mt76, true);
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
+ mt7996_init_txpower(phy);
wiphy->available_antennas_rx = phy->mt76->antenna_mask;
wiphy->available_antennas_tx = phy->mt76->antenna_mask;
@@ -287,11 +482,12 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) {
u16 rate = mt76_rates[i].hw_value;
- u16 idx = MT7996_BASIC_RATES_TBL + i;
+ /* odd index for driver, even index for firmware */
+ u16 idx = MT7996_BASIC_RATES_TBL + 2 * i;
rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) |
FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0));
- mt7996_mac_set_fixed_rate_table(dev, idx, rate);
+ mt7996_mcu_set_fixed_rate_table(&dev->phy, idx, rate, false);
}
}
@@ -317,9 +513,23 @@ void mt7996_mac_init(struct mt7996_dev *dev)
mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0);
/* rro module init */
- mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
- mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
- mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
+ if (is_mt7996(&dev->mt76))
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
+ else
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE,
+ dev->hif2 ? 7 : 0);
+
+ if (dev->has_rro) {
+ u16 timeout;
+
+ timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128;
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout);
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1);
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0);
+ } else {
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
+ }
mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
MCU_WA_PARAM_HW_PATH_HIF_VER,
@@ -335,7 +545,8 @@ int mt7996_txbf_init(struct mt7996_dev *dev)
{
int ret;
- if (dev->dbdc_support) {
+ if (mt7996_band_valid(dev, MT_BAND1) ||
+ mt7996_band_valid(dev, MT_BAND2)) {
ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL);
if (ret)
return ret;
@@ -356,19 +567,18 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
struct mt76_phy *mphy;
u32 mac_ofs, hif1_ofs = 0;
int ret;
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
- if (band != MT_BAND1 && band != MT_BAND2)
- return 0;
-
- if ((band == MT_BAND1 && !dev->dbdc_support) ||
- (band == MT_BAND2 && !dev->tbtc_support))
+ if (!mt7996_band_valid(dev, band) || band == MT_BAND0)
return 0;
if (phy)
return 0;
- if (band == MT_BAND2 && dev->hif2)
+ if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) {
hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+ wed = &dev->mt76.mmio.wed_hif2;
+ }
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band);
if (!mphy)
@@ -401,11 +611,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
mt76_eeprom_override(mphy);
/* init wiphy according to mphy and phy */
- mt7996_init_wiphy(mphy->hw);
- ret = mt76_connac_init_tx_queues(phy->mt76,
- MT_TXQ_ID(band),
- MT7996_TX_RING_SIZE,
- MT_TXQ_RING_BASE(band) + hif1_ofs, 0);
+ mt7996_init_wiphy(mphy->hw, wed);
+ ret = mt7996_init_tx_queues(mphy->priv,
+ MT_TXQ_ID(band),
+ MT7996_TX_RING_SIZE,
+ MT_TXQ_RING_BASE(band) + hif1_ofs,
+ wed);
if (ret)
goto error;
@@ -414,10 +625,21 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
if (ret)
goto error;
+ ret = mt7996_thermal_init(phy);
+ if (ret)
+ goto error;
+
ret = mt7996_init_debugfs(phy);
if (ret)
goto error;
+ if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) {
+ u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2;
+
+ mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask);
+ mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask);
+ }
+
return 0;
error:
@@ -434,6 +656,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
if (!phy)
return;
+ mt7996_unregister_thermal(phy);
+
mphy = phy->dev->mt76.phys[band];
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
@@ -447,9 +671,6 @@ static void mt7996_init_work(struct work_struct *work)
mt7996_mcu_set_eeprom(dev);
mt7996_mac_init(dev);
- mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
mt7996_txbf_init(dev);
}
@@ -462,16 +683,225 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)
msleep(20);
}
+static int mt7996_wed_rro_init(struct mt7996_dev *dev)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+ u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0;
+ struct mt7996_wed_rro_addr *addr;
+ void *ptr;
+ int i;
+
+ if (!dev->has_rro)
+ return 0;
+
+ if (!mtk_wed_device_active(wed))
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) {
+ ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_BA_BITMAP_CR_SIZE,
+ &dev->wed_rro.ba_bitmap[i].phy_addr,
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dev->wed_rro.ba_bitmap[i].ptr = ptr;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+ int j;
+
+ ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr),
+ &dev->wed_rro.addr_elem[i].phy_addr,
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dev->wed_rro.addr_elem[i].ptr = ptr;
+ memset(dev->wed_rro.addr_elem[i].ptr, 0,
+ MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr));
+
+ addr = dev->wed_rro.addr_elem[i].ptr;
+ for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) {
+ addr->signature = 0xff;
+ addr++;
+ }
+
+ wed->wlan.ind_cmd.addr_elem_phys[i] =
+ dev->wed_rro.addr_elem[i].phy_addr;
+ }
+
+ ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr),
+ &dev->wed_rro.session.phy_addr,
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dev->wed_rro.session.ptr = ptr;
+ addr = dev->wed_rro.session.ptr;
+ for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
+ addr->signature = 0xff;
+ addr++;
+ }
+
+ /* rro hw init */
+ /* TODO: remove line after WM has set */
+ mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK);
+
+ /* setup BA bitmap cache address */
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0,
+ dev->wed_rro.ba_bitmap[0].phy_addr);
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0);
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0,
+ dev->wed_rro.ba_bitmap[1].phy_addr);
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0);
+
+ /* setup Address element address */
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+ mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4);
+ reg += 4;
+ }
+
+ /* setup Address element address - separate address segment mode */
+ mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
+ MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
+
+ wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
+ wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION;
+ wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr;
+ wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN;
+ wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL;
+
+ mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00);
+ mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1,
+ MT_RRO_IND_CMD_SIGNATURE_BASE1_EN);
+
+ /* particular session configure */
+ /* use max session idx + 1 as particular session id */
+ mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr);
+ mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
+ MT_RRO_PARTICULAR_CONFG_EN |
+ FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION));
+
+ /* interrupt enable */
+ mt76_wr(dev, MT_RRO_HOST_INT_ENA,
+ MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
+
+ /* rro ind cmd queue init */
+ return mt7996_dma_rro_init(dev);
+#else
+ return 0;
+#endif
+}
+
+static void mt7996_wed_rro_free(struct mt7996_dev *dev)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ int i;
+
+ if (!dev->has_rro)
+ return;
+
+ if (!mtk_wed_device_active(&dev->mt76.mmio.wed))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) {
+ if (!dev->wed_rro.ba_bitmap[i].ptr)
+ continue;
+
+ dmam_free_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_BA_BITMAP_CR_SIZE,
+ dev->wed_rro.ba_bitmap[i].ptr,
+ dev->wed_rro.ba_bitmap[i].phy_addr);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+ if (!dev->wed_rro.addr_elem[i].ptr)
+ continue;
+
+ dmam_free_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_SIZE *
+ sizeof(struct mt7996_wed_rro_addr),
+ dev->wed_rro.addr_elem[i].ptr,
+ dev->wed_rro.addr_elem[i].phy_addr);
+ }
+
+ if (!dev->wed_rro.session.ptr)
+ return;
+
+ dmam_free_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_LEN *
+ sizeof(struct mt7996_wed_rro_addr),
+ dev->wed_rro.session.ptr,
+ dev->wed_rro.session.phy_addr);
+#endif
+}
+
+static void mt7996_wed_rro_work(struct work_struct *work)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ struct mt7996_dev *dev;
+ LIST_HEAD(list);
+
+ dev = (struct mt7996_dev *)container_of(work, struct mt7996_dev,
+ wed_rro.work);
+
+ spin_lock_bh(&dev->wed_rro.lock);
+ list_splice_init(&dev->wed_rro.poll_list, &list);
+ spin_unlock_bh(&dev->wed_rro.lock);
+
+ while (!list_empty(&list)) {
+ struct mt7996_wed_rro_session_id *e;
+ int i;
+
+ e = list_first_entry(&list, struct mt7996_wed_rro_session_id,
+ list);
+ list_del_init(&e->list);
+
+ for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
+ void *ptr = dev->wed_rro.session.ptr;
+ struct mt7996_wed_rro_addr *elem;
+ u32 idx, elem_id = i;
+
+ if (e->id == MT7996_RRO_MAX_SESSION)
+ goto reset;
+
+ idx = e->id / MT7996_RRO_BA_BITMAP_SESSION_SIZE;
+ if (idx >= ARRAY_SIZE(dev->wed_rro.addr_elem))
+ goto out;
+
+ ptr = dev->wed_rro.addr_elem[idx].ptr;
+ elem_id +=
+ (e->id % MT7996_RRO_BA_BITMAP_SESSION_SIZE) *
+ MT7996_RRO_WINDOW_MAX_LEN;
+reset:
+ elem = ptr + elem_id * sizeof(*elem);
+ elem->signature = 0xff;
+ }
+ mt7996_mcu_wed_rro_reset_sessions(dev, e->id);
+out:
+ kfree(e);
+ }
+#endif
+}
+
static int mt7996_init_hardware(struct mt7996_dev *dev)
{
int ret, idx;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
+ if (is_mt7992(&dev->mt76)) {
+ mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND0), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0);
+ mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND1), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0);
+ }
INIT_WORK(&dev->init_work, mt7996_init_work);
-
- dev->dbdc_support = true;
- dev->tbtc_support = true;
+ INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work);
+ INIT_LIST_HEAD(&dev->wed_rro.poll_list);
+ spin_lock_init(&dev->wed_rro.lock);
ret = mt7996_dma_init(dev);
if (ret)
@@ -483,6 +913,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
if (ret)
return ret;
+ ret = mt7996_wed_rro_init(dev);
+ if (ret)
+ return ret;
+
ret = mt7996_eeprom_init(dev);
if (ret < 0)
return ret;
@@ -889,14 +1323,16 @@ int mt7996_register_device(struct mt7996_dev *dev)
if (ret)
return ret;
- mt7996_init_wiphy(hw);
+ mt7996_init_wiphy(hw, &dev->mt76.mmio.wed);
ret = mt76_register_device(&dev->mt76, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
return ret;
- ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+ ret = mt7996_thermal_init(&dev->phy);
+ if (ret)
+ return ret;
ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
if (ret)
@@ -906,21 +1342,35 @@ int mt7996_register_device(struct mt7996_dev *dev)
if (ret)
return ret;
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
dev->recovery.hw_init_done = true;
ret = mt7996_init_debugfs(&dev->phy);
if (ret)
- return ret;
+ goto error;
+
+ ret = mt7996_coredump_register(dev);
+ if (ret)
+ goto error;
- return mt7996_coredump_register(dev);
+ return 0;
+
+error:
+ cancel_work_sync(&dev->init_work);
+
+ return ret;
}
void mt7996_unregister_device(struct mt7996_dev *dev)
{
+ cancel_work_sync(&dev->wed_rro.work);
mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
+ mt7996_unregister_thermal(&dev->phy);
mt7996_coredump_unregister(dev);
mt76_unregister_device(&dev->mt76);
+ mt7996_wed_rro_free(dev);
mt7996_mcu_exit(dev);
mt7996_tx_token_put(dev);
mt7996_dma_cleanup(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 04540833485f..53258488d49f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -102,7 +102,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
};
struct ieee80211_sta *sta;
struct mt7996_sta *msta;
- struct rate_info *rate;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
int i;
@@ -118,7 +117,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
u32 addr, val;
u16 idx;
s8 rssi[4];
- u8 bw;
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&sta_poll_list)) {
@@ -174,49 +172,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
}
- /* We don't support reading GI info from txs packets.
- * For accurate tx status reporting and AQL improvement,
- * we need to make sure that flags match so polling GI
- * from per-sta counters directly.
- */
- rate = &msta->wcid.rate;
-
- switch (rate->bw) {
- case RATE_INFO_BW_320:
- bw = IEEE80211_STA_RX_BW_320;
- break;
- case RATE_INFO_BW_160:
- bw = IEEE80211_STA_RX_BW_160;
- break;
- case RATE_INFO_BW_80:
- bw = IEEE80211_STA_RX_BW_80;
- break;
- case RATE_INFO_BW_40:
- bw = IEEE80211_STA_RX_BW_40;
- break;
- default:
- bw = IEEE80211_STA_RX_BW_20;
- break;
- }
-
- addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
- val = mt76_rr(dev, addr);
- if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
- addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
- val = mt76_rr(dev, addr);
- rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
- } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
- u8 offs = 24 + 2 * bw;
-
- rate->he_gi = (val & (0x3 << offs)) >> offs;
- } else if (rate->flags &
- (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
- if (val & BIT(12 + bw))
- rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
- else
- rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
- }
-
/* get signal strength of resp frames (CTS/BA/ACK) */
addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
val = mt76_rr(dev, addr);
@@ -248,17 +203,6 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
mt76_clear(dev, addr, BIT(5));
}
-void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
- u8 tbl_idx, u16 rate_idx)
-{
- u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;
-
- mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);
- /* use wtbl spe idx */
- mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);
- mt76_wr(dev, MT_WTBL_ITCR, ctrl);
-}
-
/* The HW does not translate the mac header to 802.3 for mesh point */
static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
{
@@ -449,8 +393,36 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
return 0;
}
+static void
+mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q,
+ struct mt7996_sta *msta, struct sk_buff *skb,
+ u32 info)
+{
+ struct ieee80211_vif *vif;
+ struct wireless_dev *wdev;
+
+ if (!msta || !msta->vif)
+ return;
+
+ if (!mt76_queue_is_wed_rx(q))
+ return;
+
+ if (!(info & MT_DMA_INFO_PPE_VLD))
+ return;
+
+ vif = container_of((void *)msta->vif, struct ieee80211_vif,
+ drv_priv);
+ wdev = ieee80211_vif_to_wdev(vif);
+ skb->dev = wdev->netdev;
+
+ mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb,
+ FIELD_GET(MT_DMA_PPE_CPU_REASON, info),
+ FIELD_GET(MT_DMA_PPE_ENTRY, info));
+}
+
static int
-mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ struct sk_buff *skb, u32 *info)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -475,7 +447,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
u16 seq_ctrl = 0;
__le16 fc = 0;
int idx;
+ u8 hw_aggr = false;
+ struct mt7996_sta *msta = NULL;
+ hw_aggr = status->aggr;
memset(status, 0, sizeof(*status));
band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
@@ -502,8 +477,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
if (status->wcid) {
- struct mt7996_sta *msta;
-
msta = container_of(status->wcid, struct mt7996_sta, wcid);
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&msta->wcid.poll_list))
@@ -708,12 +681,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
}
} else {
status->flag |= RX_FLAG_8023;
+ mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb,
+ *info);
}
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
- if (!status->wcid || !ieee80211_is_data_qos(fc))
+ if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
return 0;
status->aggr = unicast &&
@@ -840,10 +815,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct mt76_vif *mvif;
u16 tx_count = 15;
u32 val;
- bool beacon = !!(changed & (BSS_CHANGED_BEACON |
- BSS_CHANGED_BEACON_ENABLED));
bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
BSS_CHANGED_FILS_DISCOVERY));
+ bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
if (mvif) {
@@ -898,8 +873,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
val |= MT_TXD5_TX_STATUS_HOST;
txwi[5] = cpu_to_le32(val);
- val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
- FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+ val = MT_TXD6_DIS_MAT | MT_TXD6_DAS;
+ if (is_mt7996(&dev->mt76))
+ val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+ else
+ val |= FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1);
txwi[6] = cpu_to_le32(val);
txwi[7] = 0;
@@ -923,7 +901,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
idx = mvif->basic_rates_idx;
}
- txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
+ val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW;
+ txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
}
@@ -963,8 +942,16 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
+ u16 len;
+
+ len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ len |= FIELD_PREP(MT_TXP_DMA_ADDR_H,
+ tx_info->buf[i + 1].addr >> 32);
+#endif
+
txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
- txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
+ txp->fw.len[i] = cpu_to_le16(len);
}
txp->fw.nbuf = nbuf;
@@ -996,6 +983,29 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return 0;
}
+u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
+{
+ struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE;
+ __le32 *txwi = ptr;
+ u32 val;
+
+ memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp));
+
+ val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) |
+ FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT);
+ txwi[0] = cpu_to_le32(val);
+
+ val = BIT(31) |
+ FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3);
+ txwi[1] = cpu_to_le32(val);
+
+ txp->token = cpu_to_le16(token_id);
+ txp->nbuf = 1;
+ txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp));
+
+ return MT_TXD_SIZE + sizeof(*txp);
+}
+
static void
mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
{
@@ -1074,7 +1084,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
struct mt76_phy *phy3 = mdev->phys[MT_BAND2];
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
- struct mt76_wcid *wcid;
+ struct mt76_wcid *wcid = NULL;
LIST_HEAD(free_list);
struct sk_buff *skb, *tmp;
void *end = data + len;
@@ -1254,6 +1264,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
goto out;
rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+ if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+ rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case MT_PHY_TYPE_HE_SU:
case MT_PHY_TYPE_HE_EXT_SU:
@@ -1403,6 +1415,12 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
switch (type) {
case PKT_TYPE_TXRX_NOTIFY:
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2) &&
+ q == MT_RXQ_TXFREE_BAND2) {
+ dev_kfree_skb(skb);
+ break;
+ }
+
mt7996_mac_tx_free(dev, skb->data, skb->len);
napi_consume_skb(skb, 1);
break;
@@ -1419,7 +1437,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
dev_kfree_skb(skb);
break;
case PKT_TYPE_NORMAL:
- if (!mt7996_mac_fill_rx(dev, skb)) {
+ if (!mt7996_mac_fill_rx(dev, q, skb, info)) {
mt76_rx(&dev->mt76, q, skb);
return;
}
@@ -1525,7 +1543,7 @@ mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
void mt7996_update_channel(struct mt76_phy *mphy)
{
- struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
+ struct mt7996_phy *phy = mphy->priv;
struct mt76_channel_state *state = mphy->chan_state;
int nf;
@@ -1652,6 +1670,10 @@ mt7996_mac_restart(struct mt7996_dev *dev)
/* disable all tx/rx napi */
mt76_worker_disable(&dev->mt76.tx_worker);
mt76_for_each_q_rx(mdev, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&mdev->q_rx[i]))
+ continue;
+
if (mdev->q_rx[i].ndesc)
napi_disable(&dev->mt76.napi[i]);
}
@@ -1665,6 +1687,10 @@ mt7996_mac_restart(struct mt7996_dev *dev)
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&mdev->q_rx[i]))
+ continue;
+
if (mdev->q_rx[i].ndesc) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
@@ -1697,9 +1723,9 @@ mt7996_mac_restart(struct mt7996_dev *dev)
goto out;
mt7996_mac_init(dev);
- mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
+ mt7996_init_txpower(&dev->phy);
+ mt7996_init_txpower(phy2);
+ mt7996_init_txpower(phy3);
ret = mt7996_txbf_init(dev);
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
@@ -1754,6 +1780,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
if (phy3)
ieee80211_stop_queues(phy3->mt76->hw);
+ cancel_work_sync(&dev->wed_rro.work);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (phy2)
cancel_delayed_work_sync(&phy2->mt76->mac_work);
@@ -1836,6 +1863,13 @@ void mt7996_mac_reset_work(struct work_struct *work)
dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
wiphy_name(dev->mt76.hw->wiphy));
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_stop(&dev->mt76.mmio.wed);
+
ieee80211_stop_queues(mt76_hw(dev));
if (phy2)
ieee80211_stop_queues(phy2->mt76->hw);
@@ -1845,6 +1879,8 @@ void mt7996_mac_reset_work(struct work_struct *work)
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
+
+ cancel_work_sync(&dev->wed_rro.work);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (phy2) {
set_bit(MT76_RESET, &phy2->mt76->state);
@@ -1855,8 +1891,13 @@ void mt7996_mac_reset_work(struct work_struct *work)
cancel_delayed_work_sync(&phy3->mt76->mac_work);
}
mt76_worker_disable(&dev->mt76.tx_worker);
- mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_for_each_q_rx(&dev->mt76, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
+ continue;
+
napi_disable(&dev->mt76.napi[i]);
+ }
napi_disable(&dev->mt76.tx_napi);
mutex_lock(&dev->mt76.mutex);
@@ -1877,7 +1918,28 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
/* enable DMA Tx/Tx and interrupt */
- mt7996_dma_start(dev, false);
+ mt7996_dma_start(dev, false, false);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+ u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 |
+ dev->mt76.mmio.irqmask;
+
+ if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
+ wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND;
+
+ mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
+
+ mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask,
+ true);
+ mt7996_irq_enable(dev, wed_irq_mask);
+ mt7996_irq_disable(dev, 0);
+ }
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) {
+ mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT);
+ mtk_wed_device_start(&dev->mt76.mmio.wed_hif2,
+ MT_INT_TX_RX_DONE_EXT);
+ }
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
@@ -1888,6 +1950,10 @@ void mt7996_mac_reset_work(struct work_struct *work)
local_bh_disable();
mt76_for_each_q_rx(&dev->mt76, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
+ continue;
+
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
@@ -2187,7 +2253,9 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
IEEE80211_RC_BW_CHANGED))
mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
- /* TODO: smps change */
+ if (changed & IEEE80211_RC_SMPS_CHANGED)
+ mt7996_mcu_set_fixed_field(dev, vif, sta, NULL,
+ RATE_PARAM_MMPS_UPDATE);
spin_lock_bh(&dev->mt76.sta_poll_lock);
}
@@ -2212,6 +2280,7 @@ void mt7996_mac_work(struct work_struct *work)
mt7996_mac_update_stats(phy);
+ mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE);
if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT);
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 09c7a28a3d51..51deea84b642 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -51,6 +51,14 @@ int mt7996_run(struct ieee80211_hw *hw)
if (ret)
goto out;
+ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
+ if (ret)
+ goto out;
+
+ ret = mt7996_mcu_set_thermal_protect(phy, true);
+ if (ret)
+ goto out;
+
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
@@ -342,6 +350,8 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -365,9 +375,13 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
}
mt76_wcid_key_setup(&dev->mt76, wcid, key);
- err = mt7996_mcu_add_key(&dev->mt76, vif, &msta->bip,
- key, MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
- &msta->wcid, cmd);
+
+ if (key->keyidx == 6 || key->keyidx == 7)
+ err = mt7996_mcu_bcn_prot_enable(dev, vif, key);
+ else
+ err = mt7996_mcu_add_key(&dev->mt76, vif, key,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
+ &msta->wcid, cmd);
out:
mutex_unlock(&dev->mt76.mutex);
@@ -388,6 +402,13 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_wake_queues(hw);
}
+ if (changed & (IEEE80211_CONF_CHANGE_POWER |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
+ ret = mt7996_mcu_set_txpower_sku(phy);
+ if (ret)
+ return ret;
+ }
+
mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
@@ -514,24 +535,25 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
struct mt76_phy *mphy = hw->priv;
u16 rate;
- u8 i, idx, ht;
+ u8 i, idx;
rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast);
- ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM;
- if (beacon && ht) {
- struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ if (beacon) {
+ struct mt7996_phy *phy = mphy->priv;
+
+ /* odd index for driver, even index for firmware */
+ idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx;
+ if (phy->beacon_rate != rate)
+ mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon);
- /* must odd index */
- idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
- mt7996_mac_set_fixed_rate_table(dev, idx, rate);
return idx;
}
idx = FIELD_GET(MT_TX_RATE_IDX, rate);
for (i = 0; i < ARRAY_SIZE(mt76_rates); i++)
if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx)
- return MT7996_BASIC_RATES_TBL + i;
+ return MT7996_BASIC_RATES_TBL + 2 * i;
return mvif->basic_rates_idx;
}
@@ -956,8 +978,8 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
mt76_set_stream_caps(phy->mt76, true);
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
+ mt7996_mcu_set_txpower_sku(phy);
- /* TODO: update bmc_wtbl spe_idx when antenna changes */
mutex_unlock(&dev->mt76.mutex);
return 0;
@@ -982,6 +1004,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
sinfo->txrate.he_gi = txrate->he_gi;
sinfo->txrate.he_dcm = txrate->he_dcm;
sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ sinfo->txrate.eht_gi = txrate->eht_gi;
}
sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
@@ -1388,6 +1411,44 @@ out:
return ret;
}
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static int
+mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct net_device_path_ctx *ctx,
+ struct net_device_path *path)
+{
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+
+ if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2)
+ wed = &dev->mt76.mmio.wed_hif2;
+
+ if (!mtk_wed_device_active(wed))
+ return -ENODEV;
+
+ if (msta->wcid.idx > MT7996_WTBL_STA)
+ return -EIO;
+
+ path->type = DEV_PATH_MTK_WDMA;
+ path->dev = ctx->dev;
+ path->mtk_wdma.wdma_idx = wed->wdma_idx;
+ path->mtk_wdma.bss = mvif->mt76.idx;
+ path->mtk_wdma.queue = 0;
+ path->mtk_wdma.wcid = msta->wcid.idx;
+
+ path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed);
+ ctx->dev = NULL;
+
+ return 0;
+}
+
+#endif
+
const struct ieee80211_ops mt7996_ops = {
.tx = mt7996_tx,
.start = mt7996_start,
@@ -1432,4 +1493,8 @@ const struct ieee80211_ops mt7996_ops = {
.sta_add_debugfs = mt7996_sta_add_debugfs,
#endif
.set_radar_background = mt7996_set_radar_background,
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ .net_fill_forward_path = mt7996_net_fill_forward_path,
+ .net_setup_tc = mt76_net_setup_tc,
+#endif
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index bf917beb9439..699be57309c2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -10,6 +10,20 @@
#include "mac.h"
#include "eeprom.h"
+#define fw_name(_dev, name, ...) ({ \
+ char *_fw; \
+ switch (mt76_chip(&(_dev)->mt76)) { \
+ case 0x7992: \
+ _fw = MT7992_##name; \
+ break; \
+ case 0x7990: \
+ default: \
+ _fw = MT7996_##name; \
+ break; \
+ } \
+ _fw; \
+})
+
struct mt7996_patch_hdr {
char build_date[16];
char platform[4];
@@ -449,6 +463,43 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
}
}
+static int
+mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate)
+{
+ switch (mcu_rate->tx_mode) {
+ case MT_PHY_TYPE_CCK:
+ case MT_PHY_TYPE_OFDM:
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ case MT_PHY_TYPE_VHT:
+ if (mcu_rate->tx_gi)
+ rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+ else
+ rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT_PHY_TYPE_HE_SU:
+ case MT_PHY_TYPE_HE_EXT_SU:
+ case MT_PHY_TYPE_HE_TB:
+ case MT_PHY_TYPE_HE_MU:
+ if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2)
+ return -EINVAL;
+ rate->he_gi = mcu_rate->tx_gi;
+ break;
+ case MT_PHY_TYPE_EHT_SU:
+ case MT_PHY_TYPE_EHT_TRIG:
+ case MT_PHY_TYPE_EHT_MU:
+ if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2)
+ return -EINVAL;
+ rate->eht_gi = mcu_rate->tx_gi;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void
mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
@@ -465,6 +516,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
struct mt76_wcid *wcid;
switch (le16_to_cpu(res->tag)) {
+ case UNI_ALL_STA_TXRX_RATE:
+ wlan_idx = le16_to_cpu(res->rate[i].wlan_idx);
+ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+
+ if (!wcid)
+ break;
+
+ if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i]))
+ dev_err(dev->mt76.dev, "Failed to update TX GI\n");
+ break;
case UNI_ALL_STA_TXRX_ADM_STAT:
wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx);
wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
@@ -498,6 +559,34 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
}
static void
+mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+#define THERMAL_NOTIFY_TAG 0x4
+#define THERMAL_NOTIFY 0x2
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt7996_mcu_thermal_notify *n;
+ struct mt7996_phy *phy;
+
+ n = (struct mt7996_mcu_thermal_notify *)skb->data;
+
+ if (le16_to_cpu(n->tag) != THERMAL_NOTIFY_TAG)
+ return;
+
+ if (n->event_id != THERMAL_NOTIFY)
+ return;
+
+ if (n->band_idx > MT_BAND2)
+ return;
+
+ mphy = dev->mt76.phys[n->band_idx];
+ if (!mphy)
+ return;
+
+ phy = (struct mt7996_phy *)mphy->priv;
+ phy->throttle_state = n->duty_percent;
+}
+
+static void
mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
@@ -520,6 +609,9 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_EVENT_EXT:
mt7996_mcu_rx_ext_event(dev, skb);
break;
+ case MCU_UNI_EVENT_THERMAL:
+ mt7996_mcu_rx_thermal_notify(dev, skb);
+ break;
default:
break;
}
@@ -527,6 +619,73 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
}
static void
+mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+ struct mt7996_mcu_wed_rro_event *event = (void *)skb->data;
+
+ if (!dev->has_rro)
+ return;
+
+ skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4);
+
+ switch (le16_to_cpu(event->tag)) {
+ case UNI_WED_RRO_BA_SESSION_STATUS: {
+ struct mt7996_mcu_wed_rro_ba_event *e;
+
+ while (skb->len >= sizeof(*e)) {
+ struct mt76_rx_tid *tid;
+ struct mt76_wcid *wcid;
+ u16 idx;
+
+ e = (void *)skb->data;
+ idx = le16_to_cpu(e->wlan_id);
+ if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+ break;
+
+ wcid = rcu_dereference(dev->mt76.wcid[idx]);
+ if (!wcid || !wcid->sta)
+ break;
+
+ if (e->tid >= ARRAY_SIZE(wcid->aggr))
+ break;
+
+ tid = rcu_dereference(wcid->aggr[e->tid]);
+ if (!tid)
+ break;
+
+ tid->id = le16_to_cpu(e->id);
+ skb_pull(skb, sizeof(*e));
+ }
+ break;
+ }
+ case UNI_WED_RRO_BA_SESSION_DELETE: {
+ struct mt7996_mcu_wed_rro_ba_delete_event *e;
+
+ while (skb->len >= sizeof(*e)) {
+ struct mt7996_wed_rro_session_id *session;
+
+ e = (void *)skb->data;
+ session = kzalloc(sizeof(*session), GFP_ATOMIC);
+ if (!session)
+ break;
+
+ session->id = le16_to_cpu(e->session_id);
+
+ spin_lock_bh(&dev->wed_rro.lock);
+ list_add_tail(&session->list, &dev->wed_rro.poll_list);
+ spin_unlock_bh(&dev->wed_rro.lock);
+
+ ieee80211_queue_work(mt76_hw(dev), &dev->wed_rro.work);
+ skb_pull(skb, sizeof(*e));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
@@ -544,6 +703,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_ALL_STA_INFO:
mt7996_mcu_rx_all_sta_info_event(dev, skb);
break;
+ case MCU_UNI_EVENT_WED_RRO:
+ mt7996_mcu_wed_rro_event(dev, skb);
+ break;
default:
break;
}
@@ -963,7 +1125,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
}
static int
-mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
+mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif,
struct ieee80211_ampdu_params *params,
bool enable, bool tx)
{
@@ -972,7 +1134,7 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
struct sk_buff *skb;
struct tlv *tlv;
- skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid,
MT7996_STA_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -986,8 +1148,9 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
ba->ba_en = enable << params->tid;
ba->amsdu = params->amsdu;
ba->tid = params->tid;
+ ba->ba_rdd_rro = !tx && enable && dev->has_rro;
- return mt76_mcu_skb_send_msg(dev, skb,
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
@@ -1002,8 +1165,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
if (enable && !params->amsdu)
msta->wcid.amsdu = false;
- return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
- enable, true);
+ return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true);
}
int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
@@ -1013,8 +1175,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
struct mt7996_vif *mvif = msta->vif;
- return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
- enable, false);
+ return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false);
}
static void
@@ -1108,7 +1269,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
static void
mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
- struct sta_rec_ht *ht;
+ struct sta_rec_ht_uni *ht;
struct tlv *tlv;
if (!sta->deflink.ht_cap.ht_supported)
@@ -1116,8 +1277,12 @@ mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
- ht = (struct sta_rec_ht *)tlv;
+ ht = (struct sta_rec_ht_uni *)tlv;
ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
+ ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor,
+ IEEE80211_HT_AMPDU_PARM_FACTOR) |
+ u8_encode_bits(sta->deflink.ht_cap.ampdu_density,
+ IEEE80211_HT_AMPDU_PARM_DENSITY);
}
static void
@@ -1575,44 +1740,6 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
}
static void
-mt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
-{
- struct sta_rec_phy *phy;
- struct tlv *tlv;
- u8 af = 0, mm = 0;
-
- if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa)
- return;
-
- tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));
-
- phy = (struct sta_rec_phy *)tlv;
- if (sta->deflink.ht_cap.ht_supported) {
- af = sta->deflink.ht_cap.ampdu_factor;
- mm = sta->deflink.ht_cap.ampdu_density;
- }
-
- if (sta->deflink.vht_cap.vht_supported) {
- u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
- sta->deflink.vht_cap.cap);
-
- af = max_t(u8, af, vht_af);
- }
-
- if (sta->deflink.he_6ghz_capa.capa) {
- af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
- IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
- mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
- IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
- }
-
- phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) |
- FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm);
- phy->max_ampdu_len = af;
-}
-
-static void
mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct sta_rec_hdrt *hdrt;
@@ -1700,14 +1827,13 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
MCU_WM_UNI_CMD(RA), true);
}
-static int
-mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, void *data, u32 field)
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *data, u32 field)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
- struct sta_phy *phy = data;
- struct sta_rec_ra_fixed *ra;
+ struct sta_phy_uni *phy = data;
+ struct sta_rec_ra_fixed_uni *ra;
struct sk_buff *skb;
struct tlv *tlv;
@@ -1718,7 +1844,7 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
- ra = (struct sta_rec_ra_fixed *)tlv;
+ ra = (struct sta_rec_ra_fixed_uni *)tlv;
switch (field) {
case RATE_PARAM_AUTO:
@@ -1730,6 +1856,9 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
if (phy)
ra->phy = *phy;
break;
+ case RATE_PARAM_MMPS_UPDATE:
+ ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode);
+ break;
default:
break;
}
@@ -1747,7 +1876,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif
struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
enum nl80211_band band = chandef->chan->band;
- struct sta_phy phy = {};
+ struct sta_phy_uni phy = {};
int ret, nrates = 0;
#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \
@@ -1835,13 +1964,13 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
struct cfg80211_chan_def *chandef = &mphy->chandef;
struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
enum nl80211_band band = chandef->chan->band;
- struct sta_rec_ra *ra;
+ struct sta_rec_ra_uni *ra;
struct tlv *tlv;
u32 supp_rate = sta->deflink.supp_rates[band];
u32 cap = sta->wme ? STA_CAP_WMM : 0;
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
- ra = (struct sta_rec_ra *)tlv;
+ ra = (struct sta_rec_ra_uni *)tlv;
ra->valid = true;
ra->auto_rate = true;
@@ -2018,8 +2147,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
/* tag order is in accordance with firmware dependency. */
if (sta) {
- /* starec phy */
- mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta);
/* starec hdrt mode */
mt7996_mcu_sta_hdrt_tlv(dev, skb);
/* starec bfer */
@@ -2058,7 +2185,6 @@ out:
static int
mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
- struct mt76_connac_sta_key_conf *sta_key_conf,
struct sk_buff *skb,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd)
@@ -2079,43 +2205,22 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
return -EOPNOTSUPP;
sec_key = &sec->key[0];
+ sec_key->wlan_idx = cpu_to_le16(wcid->idx);
+ sec_key->mgmt_prot = 0;
+ sec_key->cipher_id = cipher;
sec_key->cipher_len = sizeof(*sec_key);
-
- if (cipher == MCU_CIPHER_BIP_CMAC_128) {
- sec_key->wlan_idx = cpu_to_le16(wcid->idx);
- sec_key->cipher_id = MCU_CIPHER_AES_CCMP;
- sec_key->key_id = sta_key_conf->keyidx;
- sec_key->key_len = 16;
- memcpy(sec_key->key, sta_key_conf->key, 16);
-
- sec_key = &sec->key[1];
- sec_key->wlan_idx = cpu_to_le16(wcid->idx);
- sec_key->cipher_id = MCU_CIPHER_BIP_CMAC_128;
- sec_key->cipher_len = sizeof(*sec_key);
- sec_key->key_len = 16;
- memcpy(sec_key->key, key->key, 16);
- sec->n_cipher = 2;
- } else {
- sec_key->wlan_idx = cpu_to_le16(wcid->idx);
- sec_key->cipher_id = cipher;
- sec_key->key_id = key->keyidx;
- sec_key->key_len = key->keylen;
- memcpy(sec_key->key, key->key, key->keylen);
-
- if (cipher == MCU_CIPHER_TKIP) {
- /* Rx/Tx MIC keys are swapped */
- memcpy(sec_key->key + 16, key->key + 24, 8);
- memcpy(sec_key->key + 24, key->key + 16, 8);
- }
-
- /* store key_conf for BIP batch update */
- if (cipher == MCU_CIPHER_AES_CCMP) {
- memcpy(sta_key_conf->key, key->key, key->keylen);
- sta_key_conf->keyidx = key->keyidx;
- }
-
- sec->n_cipher = 1;
+ sec_key->key_id = key->keyidx;
+ sec_key->key_len = key->keylen;
+ sec_key->need_resp = 0;
+ memcpy(sec_key->key, key->key, key->keylen);
+
+ if (cipher == MCU_CIPHER_TKIP) {
+ /* Rx/Tx MIC keys are swapped */
+ memcpy(sec_key->key + 16, key->key + 24, 8);
+ memcpy(sec_key->key + 24, key->key + 16, 8);
}
+
+ sec->n_cipher = 1;
} else {
sec->n_cipher = 0;
}
@@ -2124,7 +2229,6 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
}
int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
- struct mt76_connac_sta_key_conf *sta_key_conf,
struct ieee80211_key_conf *key, int mcu_cmd,
struct mt76_wcid *wcid, enum set_key_cmd cmd)
{
@@ -2137,13 +2241,99 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
if (IS_ERR(skb))
return PTR_ERR(skb);
- ret = mt7996_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd);
+ ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd);
if (ret)
return ret;
return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
}
+static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ u8 *pn)
+{
+#define TSC_TYPE_BIGTK_PN 2
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct sta_rec_pn_info *pn_info;
+ struct sk_buff *skb, *rskb;
+ struct tlv *tlv;
+ int ret;
+
+ skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &mvif->sta.wcid);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PN_INFO, sizeof(*pn_info));
+ pn_info = (struct sta_rec_pn_info *)tlv;
+
+ pn_info->tsc_type = TSC_TYPE_BIGTK_PN;
+ ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb,
+ MCU_WM_UNI_CMD_QUERY(STA_REC_UPDATE),
+ true, &rskb);
+ if (ret)
+ return ret;
+
+ skb_pull(rskb, 4);
+
+ pn_info = (struct sta_rec_pn_info *)rskb->data;
+ if (le16_to_cpu(pn_info->tag) == STA_REC_PN_INFO)
+ memcpy(pn, pn_info->pn, 6);
+
+ dev_kfree_skb(rskb);
+ return 0;
+}
+
+int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *key)
+{
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_mcu_bcn_prot_tlv *bcn_prot;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+ u8 pn[6] = {};
+ int len = sizeof(struct bss_req_hdr) +
+ sizeof(struct mt7996_mcu_bcn_prot_tlv);
+ int ret;
+
+ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BCN_PROT, sizeof(*bcn_prot));
+
+ bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv;
+
+ ret = mt7996_mcu_get_pn(dev, vif, pn);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+ }
+
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256;
+ break;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ default:
+ dev_err(dev->mt76.dev, "Not supported Bigtk Cipher\n");
+ dev_kfree_skb(skb);
+ return -EOPNOTSUPP;
+ }
+
+ pn[0]++;
+ memcpy(bcn_prot->pn, pn, 6);
+ bcn_prot->enable = BP_SW_MODE;
+ memcpy(bcn_prot->key, key->key, WLAN_MAX_KEY_LEN);
+ bcn_prot->key_id = key->keyidx;
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+}
int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
struct ieee80211_vif *vif, bool enable)
{
@@ -2463,7 +2653,7 @@ static int mt7996_load_patch(struct mt7996_dev *dev)
return -EAGAIN;
}
- ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev);
+ ret = request_firmware(&fw, fw_name(dev, ROM_PATCH), dev->mt76.dev);
if (ret)
goto out;
@@ -2626,17 +2816,17 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
{
int ret;
- ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM,
+ ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM),
MT7996_RAM_TYPE_WM);
if (ret)
return ret;
- ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP,
+ ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP),
MT7996_RAM_TYPE_DSP);
if (ret)
return ret;
- return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA,
+ return __mt7996_load_ram(dev, "WA", fw_name(dev, FIRMWARE_WA),
MT7996_RAM_TYPE_WA);
}
@@ -2788,9 +2978,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
{
struct uni_header hdr = {};
struct sk_buff *skb;
- int len, num;
+ int len, num, i;
- num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support);
+ num = 2 + 2 * (mt7996_band_valid(dev, MT_BAND1) +
+ mt7996_band_valid(dev, MT_BAND2));
len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime);
skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
if (!skb)
@@ -2798,13 +2989,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
skb_put_data(skb, &hdr, sizeof(hdr));
- mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx);
-
- if (dev->dbdc_support)
- mt7996_add_rx_airtime_tlv(skb, MT_BAND1);
-
- if (dev->tbtc_support)
- mt7996_add_rx_airtime_tlv(skb, MT_BAND2);
+ for (i = 0; i < __MT_MAX_BAND; i++) {
+ if (mt7996_band_valid(dev, i))
+ mt7996_add_rx_airtime_tlv(skb, i);
+ }
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WM_UNI_CMD(VOW), true);
@@ -3230,7 +3418,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
.center_ch = ieee80211_frequency_to_channel(freq1),
.bw = mt76_connac_chan_bw(chandef),
.tx_path_num = hweight16(phy->mt76->chainmask),
- .rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx],
+ .rx_path = mt7996_rx_chainmask(phy) >> dev->chainshift[band_idx],
.band_idx = band_idx,
.channel_band = ch_band[chandef->chan->band],
};
@@ -3502,6 +3690,121 @@ out:
return 0;
}
+int mt7996_mcu_get_temperature(struct mt7996_phy *phy)
+{
+#define TEMPERATURE_QUERY 0
+#define GET_TEMPERATURE 0
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 rsv1;
+ u8 action;
+ u8 band_idx;
+ u8 rsv2;
+ } req = {
+ .tag = cpu_to_le16(TEMPERATURE_QUERY),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .action = GET_TEMPERATURE,
+ .band_idx = phy->mt76->band_idx,
+ };
+ struct mt7996_mcu_thermal {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ __le32 rsv;
+ __le32 temperature;
+ } __packed * res;
+ struct sk_buff *skb;
+ int ret;
+
+ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (void *)skb->data;
+
+ return le32_to_cpu(res->temperature);
+}
+
+int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
+{
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ struct mt7996_mcu_thermal_ctrl ctrl;
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .ctrl = {
+ .band_idx = phy->mt76->band_idx,
+ },
+ };
+ int level, ret;
+
+ /* set duty cycle and level */
+ for (level = 0; level < 4; level++) {
+ req.ctrl.duty.duty_level = level;
+ req.ctrl.duty.duty_cycle = state;
+ state /= 2;
+
+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req), false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable)
+{
+#define SUSTAIN_PERIOD 10
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ struct mt7996_mcu_thermal_ctrl ctrl;
+ struct mt7996_mcu_thermal_enable enable;
+ } __packed req = {
+ .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
+ .ctrl = {
+ .band_idx = phy->mt76->band_idx,
+ .type.protect_type = 1,
+ .type.trigger_type = 1,
+ },
+ };
+ int ret;
+
+ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
+
+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req) - sizeof(req.enable), false);
+ if (ret || !enable)
+ return ret;
+
+ /* set high-temperature trigger threshold */
+ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
+ req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0]);
+ req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
+ req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
+
+ req.len = cpu_to_le16(sizeof(req) - 4);
+
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req), false);
+}
+
int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
{
struct {
@@ -3964,6 +4267,35 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
+int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx,
+ u16 rate_idx, bool beacon)
+{
+#define UNI_FIXED_RATE_TABLE_SET 0
+#define SPE_IXD_SELECT_TXD 0
+#define SPE_IXD_SELECT_BMC_WTBL 1
+ struct mt7996_dev *dev = phy->dev;
+ struct fixed_rate_table_ctrl req = {
+ .tag = cpu_to_le16(UNI_FIXED_RATE_TABLE_SET),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .table_idx = table_idx,
+ .rate_idx = cpu_to_le16(rate_idx),
+ .gi = 1,
+ .he_ltf = 1,
+ };
+ u8 band_idx = phy->mt76->band_idx;
+
+ if (beacon) {
+ req.spe_idx_sel = SPE_IXD_SELECT_TXD;
+ req.spe_idx = 24 + band_idx;
+ phy->beacon_rate = rate_idx;
+ } else {
+ req.spe_idx_sel = SPE_IXD_SELECT_BMC_WTBL;
+ }
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(FIXED_RATE_TABLE),
+ &req, sizeof(req), false);
+}
+
int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set)
{
struct {
@@ -4019,14 +4351,12 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev)
&req, sizeof(req), false);
}
-int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
+int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val)
{
struct {
u8 __rsv1[4];
-
__le16 tag;
__le16 len;
-
union {
struct {
u8 type;
@@ -4041,6 +4371,11 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
u8 path;
u8 __rsv2[3];
} __packed txfree_path;
+ struct {
+ __le16 flush_one;
+ __le16 flush_all;
+ u8 __rsv2[4];
+ } __packed timeout;
};
} __packed req = {
.tag = cpu_to_le16(tag),
@@ -4057,6 +4392,10 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
case UNI_RRO_SET_TXFREE_PATH:
req.txfree_path.path = val;
break;
+ case UNI_RRO_SET_FLUSH_TIMEOUT:
+ req.timeout.flush_one = cpu_to_le16(val);
+ req.timeout.flush_all = cpu_to_le16(2 * val);
+ break;
default:
return -EINVAL;
}
@@ -4081,3 +4420,81 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag)
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO),
&req, sizeof(req), false);
}
+
+int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
+{
+ struct {
+ u8 __rsv[4];
+
+ __le16 tag;
+ __le16 len;
+ __le16 session_id;
+ u8 pad[4];
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_RRO_DEL_BA_SESSION),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .session_id = cpu_to_le16(id),
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
+ sizeof(req), true);
+}
+
+int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+{
+#define TX_POWER_LIMIT_TABLE_RATE 0
+ struct mt7996_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct ieee80211_hw *hw = mphy->hw;
+ struct tx_power_limit_table_ctrl {
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+ u8 power_ctrl_id;
+ u8 power_limit_type;
+ u8 band_idx;
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL),
+ .len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4),
+ .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL,
+ .power_limit_type = TX_POWER_LIMIT_TABLE_RATE,
+ .band_idx = phy->mt76->band_idx,
+ };
+ struct mt76_power_limits la = {};
+ struct sk_buff *skb;
+ int i, tx_power;
+
+ tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
+ tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+ &la, tx_power);
+ mphy->txpower_cur = tx_power;
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
+ sizeof(req) + MT7996_SKU_RATE_NUM);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, &req, sizeof(req));
+ /* cck and ofdm */
+ skb_put_data(skb, &la.cck, sizeof(la.cck));
+ skb_put_data(skb, &la.ofdm, sizeof(la.ofdm));
+ /* ht20 */
+ skb_put_data(skb, &la.mcs[0], 8);
+ /* ht40 */
+ skb_put_data(skb, &la.mcs[1], 9);
+
+ /* vht */
+ for (i = 0; i < 4; i++) {
+ skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i]));
+ skb_put_zero(skb, 2); /* padding */
+ }
+
+ /* he */
+ skb_put_data(skb, &la.ru[0], sizeof(la.ru));
+ /* eht */
+ skb_put_data(skb, &la.eht[0], sizeof(la.eht));
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WM_UNI_CMD(TXPOWER), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index a88f6af323da..36cacc495c75 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
__le32 status; /* 0: success, others: fail */
} __packed;
+struct mt7996_mcu_thermal_ctrl {
+ u8 ctrl_id;
+ u8 band_idx;
+ union {
+ struct {
+ u8 protect_type; /* 1: duty admit, 2: radio off */
+ u8 trigger_type; /* 0: low, 1: high */
+ } __packed type;
+ struct {
+ u8 duty_level; /* level 0~3 */
+ u8 duty_cycle;
+ } __packed duty;
+ };
+} __packed;
+
+struct mt7996_mcu_thermal_enable {
+ __le32 trigger_temp;
+ __le32 restore_temp;
+ __le16 sustain_time;
+ u8 rsv[2];
+} __packed;
+
struct mt7996_mcu_csa_notify {
struct mt7996_mcu_rxd rxd;
@@ -153,6 +175,27 @@ struct mt7996_mcu_mib {
__le64 data;
} __packed;
+struct all_sta_trx_rate {
+ __le16 wlan_idx;
+ u8 __rsv1[2];
+ u8 tx_mode;
+ u8 flags;
+ u8 tx_stbc;
+ u8 tx_gi;
+ u8 tx_bw;
+ u8 tx_ldpc;
+ u8 tx_mcs;
+ u8 tx_nss;
+ u8 rx_rate;
+ u8 rx_mode;
+ u8 rx_nsts;
+ u8 rx_gi;
+ u8 rx_coding;
+ u8 rx_stbc;
+ u8 rx_bw;
+ u8 __rsv2;
+} __packed;
+
struct mt7996_mcu_all_sta_info_event {
u8 rsv[4];
__le16 tag;
@@ -160,23 +203,75 @@ struct mt7996_mcu_all_sta_info_event {
u8 more;
u8 rsv2;
__le16 sta_num;
- u8 rsv3[2];
+ u8 rsv3[4];
union {
- struct {
+ DECLARE_FLEX_ARRAY(struct all_sta_trx_rate, rate);
+ DECLARE_FLEX_ARRAY(struct {
__le16 wlan_idx;
u8 rsv[2];
__le32 tx_bytes[IEEE80211_NUM_ACS];
__le32 rx_bytes[IEEE80211_NUM_ACS];
- } adm_stat[0];
+ } __packed, adm_stat);
- struct {
+ DECLARE_FLEX_ARRAY(struct {
__le16 wlan_idx;
u8 rsv[2];
__le32 tx_msdu_cnt;
__le32 rx_msdu_cnt;
- } msdu_cnt[0];
- };
+ } __packed, msdu_cnt);
+ } __packed;
+} __packed;
+
+struct mt7996_mcu_wed_rro_event {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+} __packed;
+
+struct mt7996_mcu_wed_rro_ba_event {
+ __le16 tag;
+ __le16 len;
+
+ __le16 wlan_id;
+ u8 tid;
+ u8 __rsv1;
+ __le32 status;
+ __le16 id;
+ u8 __rsv2[2];
+} __packed;
+
+struct mt7996_mcu_wed_rro_ba_delete_event {
+ __le16 tag;
+ __le16 len;
+
+ __le16 session_id;
+ u8 __rsv2[2];
+} __packed;
+
+enum {
+ UNI_WED_RRO_BA_SESSION_STATUS,
+ UNI_WED_RRO_BA_SESSION_TBL,
+ UNI_WED_RRO_BA_SESSION_DELETE,
+};
+
+struct mt7996_mcu_thermal_notify {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 event_id;
+ u8 band_idx;
+ u8 level_idx;
+ u8 duty_percent;
+ __le32 restore_temp;
+ u8 __rsv2[4];
} __packed;
enum mt7996_chan_mib_offs {
@@ -247,7 +342,24 @@ struct bss_rate_tlv {
u8 short_preamble;
u8 bc_fixed_rate;
u8 mc_fixed_rate;
- u8 __rsv2[1];
+ u8 __rsv2[9];
+} __packed;
+
+enum {
+ BP_DISABLE,
+ BP_SW_MODE,
+ BP_HW_MODE,
+};
+
+struct mt7996_mcu_bcn_prot_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 pn[6];
+ u8 enable;
+ u8 cipher_id;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 key_id;
+ u8 __rsv[3];
} __packed;
struct bss_ra_tlv {
@@ -372,6 +484,15 @@ struct bss_mld_tlv {
u8 __rsv[3];
} __packed;
+struct sta_rec_ht_uni {
+ __le16 tag;
+ __le16 len;
+ __le16 ht_cap;
+ __le16 ht_cap_ext;
+ u8 ampdu_param;
+ u8 _rsv[3];
+} __packed;
+
struct sta_rec_ba_uni {
__le16 tag;
__le16 len;
@@ -421,6 +542,73 @@ struct sta_rec_sec_uni {
struct sec_key_uni key[2];
} __packed;
+struct sta_phy_uni {
+ u8 type;
+ u8 flag;
+ u8 stbc;
+ u8 sgi;
+ u8 bw;
+ u8 ldpc;
+ u8 mcs;
+ u8 nss;
+ u8 he_ltf;
+ u8 rsv[3];
+};
+
+struct sta_rec_ra_uni {
+ __le16 tag;
+ __le16 len;
+
+ u8 valid;
+ u8 auto_rate;
+ u8 phy_mode;
+ u8 channel;
+ u8 bw;
+ u8 disable_cck;
+ u8 ht_mcs32;
+ u8 ht_gf;
+ u8 ht_mcs[4];
+ u8 mmps_mode;
+ u8 gband_256;
+ u8 af;
+ u8 auth_wapi_mode;
+ u8 rate_len;
+
+ u8 supp_mode;
+ u8 supp_cck_rate;
+ u8 supp_ofdm_rate;
+ __le32 supp_ht_mcs;
+ __le16 supp_vht_mcs[4];
+
+ u8 op_mode;
+ u8 op_vht_chan_width;
+ u8 op_vht_rx_nss;
+ u8 op_vht_rx_nss_type;
+
+ __le32 sta_cap;
+
+ struct sta_phy_uni phy;
+ u8 rx_rcpi[4];
+} __packed;
+
+struct sta_rec_ra_fixed_uni {
+ __le16 tag;
+ __le16 len;
+
+ __le32 field;
+ u8 op_mode;
+ u8 op_vht_chan_width;
+ u8 op_vht_rx_nss;
+ u8 op_vht_rx_nss_type;
+
+ struct sta_phy_uni phy;
+
+ u8 spe_idx;
+ u8 short_preamble;
+ u8 is_5g;
+ u8 mmps_mode;
+} __packed;
+
struct sta_rec_hdrt {
__le16 tag;
__le16 len;
@@ -596,17 +784,16 @@ enum {
#define MT7996_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct sta_rec_basic) + \
sizeof(struct sta_rec_bf) + \
- sizeof(struct sta_rec_ht) + \
+ sizeof(struct sta_rec_ht_uni) + \
sizeof(struct sta_rec_he_v2) + \
sizeof(struct sta_rec_ba_uni) + \
sizeof(struct sta_rec_vht) + \
sizeof(struct sta_rec_uapsd) + \
sizeof(struct sta_rec_amsdu) + \
sizeof(struct sta_rec_bfee) + \
- sizeof(struct sta_rec_phy) + \
- sizeof(struct sta_rec_ra) + \
+ sizeof(struct sta_rec_ra_uni) + \
sizeof(struct sta_rec_sec) + \
- sizeof(struct sta_rec_ra_fixed) + \
+ sizeof(struct sta_rec_ra_fixed_uni) + \
sizeof(struct sta_rec_he_6g_capa) + \
sizeof(struct sta_rec_eht) + \
sizeof(struct sta_rec_hdrt) + \
@@ -622,6 +809,18 @@ enum {
#define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \
MT7996_BEACON_UPDATE_SIZE)
+static inline s8
+mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
+{
+ struct mt76_phy *mphy = phy->mt76;
+ int n_chains = hweight16(mphy->chainmask);
+
+ txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2);
+ txpower -= mt76_tx_power_nss_delta(n_chains);
+
+ return txpower;
+}
+
enum {
UNI_BAND_CONFIG_RADIO_ENABLE,
UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
@@ -669,6 +868,8 @@ enum {
UNI_RRO_GET_BA_SESSION_TABLE,
UNI_RRO_SET_BYPASS_MODE,
UNI_RRO_SET_TXFREE_PATH,
+ UNI_RRO_DEL_BA_SESSION,
+ UNI_RRO_SET_FLUSH_TIMEOUT
};
enum{
@@ -683,6 +884,16 @@ enum{
};
enum {
+ UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
+ UNI_CMD_THERMAL_PROTECT_DISABLE,
+ UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
+};
+
+enum {
+ UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
+};
+
+enum {
UNI_CMD_ACCESS_REG_BASIC = 0x0,
UNI_CMD_ACCESS_RF_REG_BASIC,
};
@@ -720,4 +931,24 @@ enum {
#define MT7996_SEC_KEY_IDX GENMASK(2, 1)
#define MT7996_SEC_IV BIT(3)
+struct fixed_rate_table_ctrl {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 table_idx;
+ u8 antenna_idx;
+ __le16 rate_idx;
+ u8 spe_idx_sel;
+ u8 spe_idx;
+ u8 gi;
+ u8 he_ltf;
+ bool ldpc;
+ bool txbf;
+ bool dynamic_bw;
+
+ u8 _rsv2;
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
index 3a591a7b47ae..9f2abfa273c9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
@@ -6,10 +6,16 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/rtnetlink.h>
#include "mt7996.h"
#include "mac.h"
+#include "mcu.h"
#include "../trace.h"
+#include "../dma.h"
+
+static bool wed_enable;
+module_param(wed_enable, bool, 0644);
static const struct __base mt7996_reg_base[] = {
[WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } },
@@ -24,6 +30,58 @@ static const struct __base mt7996_reg_base[] = {
[WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } },
};
+static const u32 mt7996_offs[] = {
+ [MIB_RVSR0] = 0x720,
+ [MIB_RVSR1] = 0x724,
+ [MIB_BTSCR5] = 0x788,
+ [MIB_BTSCR6] = 0x798,
+ [MIB_RSCR1] = 0x7ac,
+ [MIB_RSCR27] = 0x954,
+ [MIB_RSCR28] = 0x958,
+ [MIB_RSCR29] = 0x95c,
+ [MIB_RSCR30] = 0x960,
+ [MIB_RSCR31] = 0x964,
+ [MIB_RSCR33] = 0x96c,
+ [MIB_RSCR35] = 0x974,
+ [MIB_RSCR36] = 0x978,
+ [MIB_BSCR0] = 0x9cc,
+ [MIB_BSCR1] = 0x9d0,
+ [MIB_BSCR2] = 0x9d4,
+ [MIB_BSCR3] = 0x9d8,
+ [MIB_BSCR4] = 0x9dc,
+ [MIB_BSCR5] = 0x9e0,
+ [MIB_BSCR6] = 0x9e4,
+ [MIB_BSCR7] = 0x9e8,
+ [MIB_BSCR17] = 0xa10,
+ [MIB_TRDR1] = 0xa28,
+};
+
+static const u32 mt7992_offs[] = {
+ [MIB_RVSR0] = 0x760,
+ [MIB_RVSR1] = 0x764,
+ [MIB_BTSCR5] = 0x7c8,
+ [MIB_BTSCR6] = 0x7d8,
+ [MIB_RSCR1] = 0x7f0,
+ [MIB_RSCR27] = 0x998,
+ [MIB_RSCR28] = 0x99c,
+ [MIB_RSCR29] = 0x9a0,
+ [MIB_RSCR30] = 0x9a4,
+ [MIB_RSCR31] = 0x9a8,
+ [MIB_RSCR33] = 0x9b0,
+ [MIB_RSCR35] = 0x9b8,
+ [MIB_RSCR36] = 0x9bc,
+ [MIB_BSCR0] = 0xac8,
+ [MIB_BSCR1] = 0xacc,
+ [MIB_BSCR2] = 0xad0,
+ [MIB_BSCR3] = 0xad4,
+ [MIB_BSCR4] = 0xad8,
+ [MIB_BSCR5] = 0xadc,
+ [MIB_BSCR6] = 0xae0,
+ [MIB_BSCR7] = 0xae4,
+ [MIB_BSCR17] = 0xb0c,
+ [MIB_TRDR1] = 0xb24,
+};
+
static const struct __map mt7996_reg_map[] = {
{ 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */
{ 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */
@@ -191,6 +249,169 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val);
}
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed)
+{
+ struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ struct mt76_phy *mphy = &dev->mphy;
+ int ret;
+
+ ASSERT_RTNL();
+
+ if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state))
+ return -EBUSY;
+
+ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1,
+ mphy->band_idx);
+ if (ret)
+ goto out;
+
+ rtnl_unlock();
+ if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) {
+ dev_err(mdev->dev, "wed reset timeout\n");
+ ret = -ETIMEDOUT;
+ }
+ rtnl_lock();
+out:
+ clear_bit(MT76_STATE_WED_RESET, &mphy->state);
+
+ return ret;
+}
+#endif
+
+int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ bool hif2, int *irq)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+ struct pci_dev *pci_dev = pdev_ptr;
+ u32 hif1_ofs = 0;
+
+ if (!wed_enable)
+ return 0;
+
+ dev->has_rro = true;
+
+ hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+
+ if (hif2)
+ wed = &dev->mt76.mmio.wed_hif2;
+
+ wed->wlan.pci_dev = pci_dev;
+ wed->wlan.bus_type = MTK_WED_BUS_PCIE;
+
+ wed->wlan.base = devm_ioremap(dev->mt76.dev,
+ pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+ wed->wlan.phy_base = pci_resource_start(pci_dev, 0);
+
+ if (hif2) {
+ wed->wlan.wpdma_int = wed->wlan.phy_base +
+ MT_INT_PCIE1_SOURCE_CSR_EXT;
+ wed->wlan.wpdma_mask = wed->wlan.phy_base +
+ MT_INT_PCIE1_MASK_CSR;
+ wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs +
+ MT_TXQ_RING_BASE(0) +
+ MT7996_TXQ_BAND2 * MT_RING_SIZE;
+ if (dev->has_rro) {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
+ } else {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE;
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1;
+ }
+
+ wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG;
+ wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) +
+ MT7996_RXQ_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.id = 0x7991;
+ wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1;
+ } else {
+ wed->wlan.hw_rro = dev->has_rro; /* default on */
+ wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR;
+ wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR;
+ wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) +
+ MT7996_TXQ_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG;
+
+ wed->wlan.wpdma_rx = wed->wlan.phy_base +
+ MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) +
+ MT7996_RXQ_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base +
+ MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) +
+ MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE;
+ wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) +
+ MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE;
+ wed->wlan.wpdma_rx_pg = wed->wlan.phy_base +
+ MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) +
+ MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.rx_nbuf = 65536;
+ wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576;
+ wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE);
+
+ wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1;
+ wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1;
+
+ wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1;
+ wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1;
+
+ wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1;
+ wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1;
+ wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1;
+
+ wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1;
+ wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1;
+ if (dev->has_rro) {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_TXFREE0 * MT_RING_SIZE;
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1;
+ } else {
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1;
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
+ }
+ dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt;
+ }
+
+ wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE;
+ wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf;
+
+ wed->wlan.amsdu_max_subframes = 8;
+ wed->wlan.amsdu_max_len = 1536;
+
+ wed->wlan.init_buf = mt7996_wed_init_buf;
+ wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf;
+ wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf;
+ wed->wlan.offload_enable = mt76_mmio_wed_offload_enable;
+ wed->wlan.offload_disable = mt76_mmio_wed_offload_disable;
+ if (!hif2) {
+ wed->wlan.reset = mt7996_mmio_wed_reset;
+ wed->wlan.reset_complete = mt76_mmio_wed_reset_complete;
+ }
+
+ if (mtk_wed_device_attach(wed))
+ return 0;
+
+ *irq = wed->irq;
+ dev->mt76.dma_dev = wed->dev;
+
+ return 1;
+#else
+ return 0;
+#endif
+}
+
static int mt7996_mmio_init(struct mt76_dev *mdev,
void __iomem *mem_base,
u32 device_id)
@@ -204,6 +425,13 @@ static int mt7996_mmio_init(struct mt76_dev *mdev,
switch (device_id) {
case 0x7990:
dev->reg.base = mt7996_reg_base;
+ dev->reg.offs_rev = mt7996_offs;
+ dev->reg.map = mt7996_reg_map;
+ dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map);
+ break;
+ case 0x7992:
+ dev->reg.base = mt7996_reg_base;
+ dev->reg.offs_rev = mt7992_offs;
dev->reg.map = mt7996_reg_map;
dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map);
break;
@@ -241,8 +469,17 @@ void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg,
mdev->mmio.irqmask |= set;
if (write_reg) {
- mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask);
- mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask);
+ if (mtk_wed_device_active(&mdev->mmio.wed)) {
+ mtk_wed_device_irq_set_mask(&mdev->mmio.wed,
+ mdev->mmio.irqmask);
+ if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) {
+ mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2,
+ mdev->mmio.irqmask);
+ }
+ } else {
+ mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask);
+ mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask);
+ }
}
spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags);
@@ -260,22 +497,36 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev,
static void mt7996_irq_tasklet(struct tasklet_struct *t)
{
struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+ struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2;
u32 i, intr, mask, intr1;
- mt76_wr(dev, MT_INT_MASK_CSR, 0);
- if (dev->hif2)
- mt76_wr(dev, MT_INT1_MASK_CSR, 0);
-
- intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
- intr &= dev->mt76.mmio.irqmask;
- mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
-
- if (dev->hif2) {
- intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR);
- intr1 &= dev->mt76.mmio.irqmask;
- mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1);
+ if (dev->hif2 && mtk_wed_device_active(wed_hif2)) {
+ mtk_wed_device_irq_set_mask(wed_hif2, 0);
+ intr1 = mtk_wed_device_irq_get(wed_hif2,
+ dev->mt76.mmio.irqmask);
+ if (intr1 & MT_INT_RX_TXFREE_EXT)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]);
+ }
- intr |= intr1;
+ if (mtk_wed_device_active(wed)) {
+ mtk_wed_device_irq_set_mask(wed, 0);
+ intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask);
+ intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT);
+ } else {
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+ if (dev->hif2)
+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+
+ intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+ intr &= dev->mt76.mmio.irqmask;
+ mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
+ if (dev->hif2) {
+ intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR);
+ intr1 &= dev->mt76.mmio.irqmask;
+ mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1);
+ intr |= intr1;
+ }
}
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
@@ -308,9 +559,17 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance)
{
struct mt7996_dev *dev = dev_instance;
- mt76_wr(dev, MT_INT_MASK_CSR, 0);
- if (dev->hif2)
- mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0);
+ else
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
+ if (dev->hif2) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0);
+ else
+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+ }
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
@@ -391,4 +650,5 @@ static void __exit mt7996_exit(void)
module_init(mt7996_init);
module_exit(mt7996_exit);
+MODULE_DESCRIPTION("MediaTek MT7996 MMIO helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index e53cf6a3704c..bc73bcb47bf0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -13,6 +13,7 @@
#define MT7996_MAX_INTERFACES 19 /* per-band */
#define MT7996_MAX_WMM_SETS 4
+#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64)
#define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1)
#define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \
mt7996_max_interface_num(dev))
@@ -33,22 +34,54 @@
#define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
#define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
+#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin"
+#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin"
+#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin"
+#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin"
+
#define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
+#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin"
#define MT7996_EEPROM_SIZE 7680
#define MT7996_EEPROM_BLOCK_SIZE 16
#define MT7996_TOKEN_SIZE 16384
+#define MT7996_HW_TOKEN_SIZE 8192
#define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
+#define MT7996_SKU_RATE_NUM 417
+
#define MT7996_MAX_TWT_AGRT 16
#define MT7996_MAX_STA_TWT_AGRT 8
#define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3)
/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
-#define MT7996_BASIC_RATES_TBL 11
+#define MT7996_BASIC_RATES_TBL 31
#define MT7996_BEACON_RATES_TBL 25
+#define MT7996_THERMAL_THROTTLE_MAX 100
+#define MT7996_CDEV_THROTTLE_MAX 99
+#define MT7996_CRIT_TEMP_IDX 0
+#define MT7996_MAX_TEMP_IDX 1
+#define MT7996_CRIT_TEMP 110
+#define MT7996_MAX_TEMP 120
+
+#define MT7996_RRO_MAX_SESSION 1024
+#define MT7996_RRO_WINDOW_MAX_LEN 1024
+#define MT7996_RRO_ADDR_ELEM_LEN 128
+#define MT7996_RRO_BA_BITMAP_LEN 2
+#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \
+ MT7996_RRO_BA_BITMAP_LEN)
+#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \
+ MT7996_RRO_ADDR_ELEM_LEN)
+#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \
+ MT7996_RRO_BA_BITMAP_SESSION_SIZE)
+
+#define MT7996_RX_BUF_SIZE (1800 + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+#define MT7996_RX_MSDU_PAGE_SIZE (128 + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
@@ -73,11 +106,21 @@ enum mt7996_rxq_id {
MT7996_RXQ_MCU_WM = 0,
MT7996_RXQ_MCU_WA,
MT7996_RXQ_MCU_WA_MAIN = 2,
- MT7996_RXQ_MCU_WA_EXT = 2,/* unused */
+ MT7996_RXQ_MCU_WA_EXT = 3, /* for mt7992 */
MT7996_RXQ_MCU_WA_TRI = 3,
MT7996_RXQ_BAND0 = 4,
- MT7996_RXQ_BAND1 = 4,/* unused */
+ MT7996_RXQ_BAND1 = 5, /* for mt7992 */
MT7996_RXQ_BAND2 = 5,
+ MT7996_RXQ_RRO_BAND0 = 8,
+ MT7996_RXQ_RRO_BAND1 = 8,/* unused */
+ MT7996_RXQ_RRO_BAND2 = 6,
+ MT7996_RXQ_MSDU_PG_BAND0 = 10,
+ MT7996_RXQ_MSDU_PG_BAND1 = 11,
+ MT7996_RXQ_MSDU_PG_BAND2 = 12,
+ MT7996_RXQ_TXFREE0 = 9,
+ MT7996_RXQ_TXFREE1 = 9,
+ MT7996_RXQ_TXFREE2 = 7,
+ MT7996_RXQ_RRO_IND = 0,
};
struct mt7996_twt_flow {
@@ -146,6 +189,20 @@ struct mt7996_hif {
int irq;
};
+struct mt7996_wed_rro_addr {
+ u32 head_low;
+ u32 head_high : 4;
+ u32 count: 11;
+ u32 oor: 1;
+ u32 rsv : 8;
+ u32 signature : 8;
+};
+
+struct mt7996_wed_rro_session_id {
+ struct list_head list;
+ u16 id;
+};
+
struct mt7996_phy {
struct mt76_phy *mt76;
struct mt7996_dev *dev;
@@ -154,6 +211,11 @@ struct mt7996_phy {
struct ieee80211_vif *monitor_vif;
+ struct thermal_cooling_device *cdev;
+ u8 cdev_state;
+ u8 throttle_state;
+ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
+
u32 rxfilter;
u64 omac_mask;
@@ -164,11 +226,15 @@ struct mt7996_phy {
u8 rdd_state;
+ u16 beacon_rate;
+
u32 rx_ampdu_ts;
u32 ampdu_ref;
struct mt76_mib_stats mib;
struct mt76_channel_state state_ts;
+
+ bool has_aux_rx;
};
struct mt7996_dev {
@@ -221,10 +287,28 @@ struct mt7996_dev {
u32 hw_pattern;
- bool dbdc_support:1;
- bool tbtc_support:1;
bool flash_mode:1;
bool has_eht:1;
+ bool has_rro:1;
+
+ struct {
+ struct {
+ void *ptr;
+ dma_addr_t phy_addr;
+ } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN];
+ struct {
+ void *ptr;
+ dma_addr_t phy_addr;
+ } addr_elem[MT7996_RRO_ADDR_ELEM_LEN];
+ struct {
+ void *ptr;
+ dma_addr_t phy_addr;
+ } session;
+
+ struct work_struct work;
+ struct list_head poll_list;
+ spinlock_t lock;
+ } wed_rro;
bool ibf;
u8 fw_debug_wm;
@@ -314,6 +398,20 @@ mt7996_phy3(struct mt7996_dev *dev)
return __mt7996_phy(dev, MT_BAND2);
}
+static inline bool
+mt7996_band_valid(struct mt7996_dev *dev, u8 band)
+{
+ if (is_mt7992(&dev->mt76))
+ return band <= MT_BAND1;
+
+ /* tri-band support */
+ if (band <= MT_BAND2 &&
+ mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1)
+ return true;
+
+ return band == MT_BAND0 || band == MT_BAND2;
+}
+
extern const struct ieee80211_ops mt7996_ops;
extern struct pci_driver mt7996_pci_driver;
extern struct pci_driver mt7996_hif_driver;
@@ -334,9 +432,10 @@ int mt7996_dma_init(struct mt7996_dev *dev);
void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
void mt7996_dma_prefetch(struct mt7996_dev *dev);
void mt7996_dma_cleanup(struct mt7996_dev *dev);
-void mt7996_dma_start(struct mt7996_dev *dev, bool reset);
-void mt7996_init_txpower(struct mt7996_dev *dev,
- struct ieee80211_supported_band *sband);
+void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset);
+int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx,
+ int n_desc, int ring_base, struct mtk_wed_device *wed);
+void mt7996_init_txpower(struct mt7996_phy *phy);
int mt7996_txbf_init(struct mt7996_dev *dev);
void mt7996_reset(struct mt7996_dev *dev);
int mt7996_run(struct ieee80211_hw *hw);
@@ -373,6 +472,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif);
int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
void *data, u16 version);
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *data, u32 field);
int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset);
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
@@ -388,13 +489,19 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif);
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
+int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
+int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
+int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
+int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
u8 rx_sel, u8 val);
int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
struct cfg80211_chan_def *chandef);
+int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx,
+ u16 rate_idx, bool beacon);
int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set);
int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans);
-int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val);
+int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val);
int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
@@ -402,15 +509,18 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
+int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
- return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support);
+ return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) +
+ mt7996_band_valid(dev, MT_BAND2)),
+ MT7996_WTBL_BMC_SIZE);
}
static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev)
{
- return (dev->wtbl_size_group << 8) + 64;
+ return (dev->wtbl_size_group << 8) + MT7996_WTBL_BMC_SIZE;
}
void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg,
@@ -437,6 +547,18 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask)
void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
size_t len);
+static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy)
+{
+ int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx);
+ int cur_nss = hweight8(phy->mt76->antenna_mask);
+ u16 tx_chainmask = phy->mt76->chainmask;
+
+ if (cur_nss != max_nss)
+ return tx_chainmask;
+
+ return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx);
+}
+
void mt7996_mac_init(struct mt7996_dev *dev);
u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw);
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
@@ -445,8 +567,6 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
struct ieee80211_vif *vif, bool enable);
-void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
- u8 tbl_idx, u16 rate_idx);
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
@@ -485,9 +605,10 @@ int mt7996_init_debugfs(struct mt7996_phy *phy);
void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len);
bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len);
int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
- struct mt76_connac_sta_key_conf *sta_key_conf,
struct ieee80211_key_conf *key, int mcu_cmd,
struct mt76_wcid *wcid, enum set_key_cmd cmd);
+int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *key);
int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@@ -495,5 +616,16 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
#endif
+int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ bool hif2, int *irq);
+u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
+
+#ifdef CONFIG_MTK_DEBUG
+int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
+#endif
+
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+int mt7996_dma_rro_init(struct mt7996_dev *dev);
+#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
index c5301050ff8b..04056181368a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
@@ -17,11 +17,13 @@ static u32 hif_idx;
static const struct pci_device_id mt7996_pci_device_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7990) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7992) },
{ },
};
static const struct pci_device_id mt7996_hif_device_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7991) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x799a) },
{ },
};
@@ -60,7 +62,9 @@ static void mt7996_put_hif2(struct mt7996_hif *hif)
static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev)
{
hif_idx++;
- if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL))
+
+ if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x7991, NULL) &&
+ !pci_get_device(PCI_VENDOR_ID_MEDIATEK, 0x799a, NULL))
return NULL;
writel(hif_idx | MT_PCIE_RECOG_ID_SEM,
@@ -92,10 +96,10 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct pci_dev *hif2_dev;
+ struct mt7996_hif *hif2;
struct mt7996_dev *dev;
+ int irq, hif2_irq, ret;
struct mt76_dev *mdev;
- struct mt7996_hif *hif2;
- int irq, ret;
ret = pcim_enable_device(pdev);
if (ret)
@@ -107,13 +111,17 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
+ if (ret)
+ return ret;
+
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
mt76_pci_disable_aspm(pdev);
- if (id->device == 0x7991)
+ if (id->device == 0x7991 || id->device == 0x799a)
return mt7996_pci_hif2_probe(pdev);
dev = mt7996_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0],
@@ -125,15 +133,22 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
mt7996_wfsys_reset(dev);
hif2 = mt7996_pci_init_hif2(pdev);
- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ ret = mt7996_mmio_wed_init(dev, pdev, false, &irq);
if (ret < 0)
- goto free_device;
+ goto free_wed_or_irq_vector;
+
+ if (!ret) {
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto free_device;
+
+ irq = pdev->irq;
+ }
- irq = pdev->irq;
ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
- goto free_irq_vector;
+ goto free_wed_or_irq_vector;
mt76_wr(dev, MT_INT_MASK_CSR, 0);
/* master switch of PCIe tnterrupt enable */
@@ -143,16 +158,25 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
hif2_dev = container_of(hif2->dev, struct pci_dev, dev);
dev->hif2 = hif2;
- ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES);
+ ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq);
if (ret < 0)
- goto free_hif2;
+ goto free_hif2_wed_irq_vector;
+
+ if (!ret) {
+ ret = pci_alloc_irq_vectors(hif2_dev, 1, 1,
+ PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto free_hif2;
- dev->hif2->irq = hif2_dev->irq;
- ret = devm_request_irq(mdev->dev, dev->hif2->irq,
- mt7996_irq_handler, IRQF_SHARED,
- KBUILD_MODNAME "-hif", dev);
+ dev->hif2->irq = hif2_dev->irq;
+ hif2_irq = dev->hif2->irq;
+ }
+
+ ret = devm_request_irq(mdev->dev, hif2_irq, mt7996_irq_handler,
+ IRQF_SHARED, KBUILD_MODNAME "-hif",
+ dev);
if (ret)
- goto free_hif2_irq_vector;
+ goto free_hif2_wed_irq_vector;
mt76_wr(dev, MT_INT1_MASK_CSR, 0);
/* master switch of PCIe tnterrupt enable */
@@ -167,16 +191,23 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
free_hif2_irq:
if (dev->hif2)
- devm_free_irq(mdev->dev, dev->hif2->irq, dev);
-free_hif2_irq_vector:
- if (dev->hif2)
- pci_free_irq_vectors(hif2_dev);
+ devm_free_irq(mdev->dev, hif2_irq, dev);
+free_hif2_wed_irq_vector:
+ if (dev->hif2) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2);
+ else
+ pci_free_irq_vectors(hif2_dev);
+ }
free_hif2:
if (dev->hif2)
put_device(dev->hif2->dev);
devm_free_irq(mdev->dev, irq, dev);
-free_irq_vector:
- pci_free_irq_vectors(pdev);
+free_wed_or_irq_vector:
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_detach(&dev->mt76.mmio.wed);
+ else
+ pci_free_irq_vectors(pdev);
free_device:
mt76_free_device(&dev->mt76);
@@ -221,3 +252,7 @@ MODULE_FIRMWARE(MT7996_FIRMWARE_WA);
MODULE_FIRMWARE(MT7996_FIRMWARE_WM);
MODULE_FIRMWARE(MT7996_FIRMWARE_DSP);
MODULE_FIRMWARE(MT7996_ROM_PATCH);
+MODULE_FIRMWARE(MT7992_FIRMWARE_WA);
+MODULE_FIRMWARE(MT7992_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7992_FIRMWARE_DSP);
+MODULE_FIRMWARE(MT7992_ROM_PATCH);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
index 0086a7866657..47b429d8bfbe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
@@ -19,6 +19,7 @@ struct __base {
/* used to differentiate between generations */
struct mt7996_reg_desc {
const struct __base *base;
+ const u32 *offs_rev;
const struct __map *map;
u32 map_size;
};
@@ -39,6 +40,73 @@ enum base_rev {
#define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)])
+enum offs_rev {
+ MIB_RVSR0,
+ MIB_RVSR1,
+ MIB_BTSCR5,
+ MIB_BTSCR6,
+ MIB_RSCR1,
+ MIB_RSCR27,
+ MIB_RSCR28,
+ MIB_RSCR29,
+ MIB_RSCR30,
+ MIB_RSCR31,
+ MIB_RSCR33,
+ MIB_RSCR35,
+ MIB_RSCR36,
+ MIB_BSCR0,
+ MIB_BSCR1,
+ MIB_BSCR2,
+ MIB_BSCR3,
+ MIB_BSCR4,
+ MIB_BSCR5,
+ MIB_BSCR6,
+ MIB_BSCR7,
+ MIB_BSCR17,
+ MIB_TRDR1,
+ __MT_OFFS_MAX,
+};
+
+#define __OFFS(id) (dev->reg.offs_rev[(id)])
+
+/* RRO TOP */
+#define MT_RRO_TOP_BASE 0xA000
+#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs))
+
+#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8)
+#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC)
+#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8)
+#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12)
+#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34)
+#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31)
+
+#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38)
+#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C)
+#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40)
+#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31)
+
+#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C)
+#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60)
+#define MT_RRO_PARTICULAR_CONFG_EN BIT(31)
+#define MT_RRO_PARTICULAR_SID GENMASK(30, 16)
+
+#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70)
+#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74)
+#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204)
+#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0)
+
+#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400)
+
+#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50)
+#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16)
+#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0)
+
+#define MT_RRO_DBG_RD_CTRL MT_RRO_TOP(0xe0)
+#define MT_RRO_DBG_RD_ADDR GENMASK(15, 0)
+#define MT_RRO_DBG_RD_EXEC BIT(31)
+
+#define MT_RRO_DBG_RDAT_DW(_n) MT_RRO_TOP(0xf0 + (_n) * 0x4)
+
#define MT_MCU_INT_EVENT 0x2108
#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0)
#define MT_MCU_INT_EVENT_DMA_INIT BIT(1)
@@ -140,32 +208,32 @@ enum base_rev {
#define MT_WF_MIB_BASE(_band) __BASE(WF_MIB_BASE, (_band))
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
-#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, 0x9cc)
-#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, 0x9d0)
-#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, 0x9d4)
-#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, 0x9d8)
-#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, 0x9dc)
-#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, 0x9e0)
-#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, 0x9e4)
-#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, 0x9e8)
-#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, 0xa10)
+#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR0))
+#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR1))
+#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR2))
+#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR3))
+#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR4))
+#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR5))
+#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR6))
+#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7))
+#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17))
#define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4)
#define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8)
#define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0)
-#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, 0x7ac)
+#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1))
/* rx mpdu counter, full 32 bits */
-#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, 0x964)
-#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, 0x96c)
+#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR31))
+#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR33))
#define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020)
#define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0)
-#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, 0x720)
+#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR0))
-#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, 0x974)
-#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, 0x978)
+#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR35))
+#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36))
/* tx ampdu cnt, full 32 bits */
#define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0)
@@ -178,16 +246,16 @@ enum base_rev {
#define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0)
/* rx ampdu count, 32-bit */
-#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, 0x954)
+#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27))
/* rx ampdu bytes count, 32-bit */
-#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, 0x958)
+#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR28))
/* rx ampdu valid subframe count */
-#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, 0x95c)
+#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR29))
/* rx ampdu valid subframe bytes count, 32bits */
-#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, 0x960)
+#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR30))
/* remaining windows protected stats */
#define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x080)
@@ -196,18 +264,18 @@ enum base_rev {
#define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x084)
#define MT_MIB_SDR28_TX_RWP_NEED_CNT GENMASK(15, 0)
-#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, 0x724)
+#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1))
/* rx blockack count, 32 bits */
#define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4)
#define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0)
-#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, 0x788)
-#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, 0x798)
+#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5))
+#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR6))
#define MT_MIB_BFTFCR(_band) MT_WF_MIB(_band, 0x5d0)
-#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa28 + ((n) << 2))
+#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(MIB_TRDR1) + ((n) << 2))
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 4)) & GENMASK(9, 0))
@@ -330,15 +398,22 @@ enum base_rev {
#define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154)
#define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3)
+#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6)
#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
-#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
-#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21)
+#define MT_WFDMA0_GLO_CFG_EXT_EN BIT(26)
+#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
+#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
+
+#define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268)
+#define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c)
+#define MT_WFDMA0_PAUSE_RX_Q_89_TH MT_WFDMA0(0x270)
+#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c)
#define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0)
#define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18)
@@ -362,10 +437,14 @@ enum base_rev {
#define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30)
#define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0)
+#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22)
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
+#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500)
+#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0)
+
#define MT_PCIE_RECOG_ID 0xd7090
#define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0)
#define MT_PCIE_RECOG_ID_SEM BIT(31)
@@ -374,6 +453,9 @@ enum base_rev {
#define MT_WFDMA0_PCIE1_BASE 0xd8000
#define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs))
+#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118)
+#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c)
+
#define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c)
#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0)
#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1)
@@ -394,6 +476,7 @@ enum base_rev {
#define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300)
#define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300)
#define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500)
+#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40)
#define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \
MT_MCUQ_ID(q) * 0x4)
@@ -409,17 +492,27 @@ enum base_rev {
#define MT_INT1_MASK_CSR MT_WFDMA0_PCIE1(0x204)
#define MT_INT_RX_DONE_BAND0 BIT(12)
-#define MT_INT_RX_DONE_BAND1 BIT(12)
+#define MT_INT_RX_DONE_BAND1 BIT(13) /* for mt7992 */
#define MT_INT_RX_DONE_BAND2 BIT(13)
#define MT_INT_RX_DONE_WM BIT(0)
#define MT_INT_RX_DONE_WA BIT(1)
#define MT_INT_RX_DONE_WA_MAIN BIT(2)
-#define MT_INT_RX_DONE_WA_EXT BIT(2)
+#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */
#define MT_INT_RX_DONE_WA_TRI BIT(3)
#define MT_INT_RX_TXFREE_MAIN BIT(17)
#define MT_INT_RX_TXFREE_TRI BIT(15)
+#define MT_INT_RX_DONE_BAND2_EXT BIT(23)
+#define MT_INT_RX_TXFREE_EXT BIT(26)
#define MT_INT_MCU_CMD BIT(29)
+#define MT_INT_RX_DONE_RRO_BAND0 BIT(16)
+#define MT_INT_RX_DONE_RRO_BAND1 BIT(16)
+#define MT_INT_RX_DONE_RRO_BAND2 BIT(14)
+#define MT_INT_RX_DONE_RRO_IND BIT(11)
+#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18)
+#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19)
+#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23)
+
#define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)])
#define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)])
@@ -427,20 +520,31 @@ enum base_rev {
MT_INT_RX(MT_RXQ_MCU_WA))
#define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \
- MT_INT_RX(MT_RXQ_MAIN_WA))
+ MT_INT_RX(MT_RXQ_MAIN_WA) | \
+ MT_INT_RX(MT_RXQ_TXFREE_BAND0))
#define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \
MT_INT_RX(MT_RXQ_BAND1_WA) | \
- MT_INT_RX(MT_RXQ_MAIN_WA))
+ MT_INT_RX(MT_RXQ_MAIN_WA) | \
+ MT_INT_RX(MT_RXQ_TXFREE_BAND0))
#define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \
MT_INT_RX(MT_RXQ_BAND2_WA) | \
- MT_INT_RX(MT_RXQ_MAIN_WA))
+ MT_INT_RX(MT_RXQ_MAIN_WA) | \
+ MT_INT_RX(MT_RXQ_TXFREE_BAND0))
+
+#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \
+ MT_INT_RX(MT_RXQ_RRO_BAND1) | \
+ MT_INT_RX(MT_RXQ_RRO_BAND2) | \
+ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \
+ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \
+ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2))
#define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \
MT_INT_BAND0_RX_DONE | \
MT_INT_BAND1_RX_DONE | \
- MT_INT_BAND2_RX_DONE)
+ MT_INT_BAND2_RX_DONE | \
+ MT_INT_RRO_RX_DONE)
#define MT_INT_TX_DONE_FWDL BIT(26)
#define MT_INT_TX_DONE_MCU_WM BIT(27)
@@ -449,6 +553,10 @@ enum base_rev {
#define MT_INT_TX_DONE_BAND1 BIT(31)
#define MT_INT_TX_DONE_BAND2 BIT(15)
+#define MT_INT_TX_RX_DONE_EXT (MT_INT_TX_DONE_BAND2 | \
+ MT_INT_RX_DONE_BAND2_EXT | \
+ MT_INT_RX_TXFREE_EXT)
+
#define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \
MT_INT_TX_MCU(MT_MCUQ_WM) | \
MT_INT_TX_MCU(MT_MCUQ_FWDL))
@@ -552,7 +660,12 @@ enum base_rev {
#define MT_TOP_MISC MT_TOP(0xf0)
#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
+#define MT_PAD_GPIO 0x700056f0
+#define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15)
+
#define MT_HW_REV 0x70010204
+#define MT_HW_REV1 0x8a00
+
#define MT_WF_SUBSYS_RST 0x70028600
/* PCIE MAC */
@@ -601,4 +714,11 @@ enum base_rev {
#define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200)
#define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204)
+/* CONN AFE CTL CON */
+#define MT_AFE_CTL_BASE 0x18043000
+#define MT_AFE_CTL_BAND(_band, ofs) (MT_AFE_CTL_BASE + \
+ ((_band) * 0x1000) + (ofs))
+#define MT_AFE_CTL_BAND_PLL_03(_band) MT_AFE_CTL_BAND(_band, 0x2c)
+#define MT_AFE_CTL_BAND_PLL_03_MSB_EN BIT(1)
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c
index 419723118ded..3e88798df017 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio.c
@@ -481,21 +481,21 @@ static void mt76s_status_worker(struct mt76_worker *w)
if (dev->drv->tx_status_data && ndata_frames > 0 &&
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state) &&
!test_bit(MT76_STATE_SUSPEND, &dev->phy.state))
- ieee80211_queue_work(dev->hw, &dev->sdio.stat_work);
+ mt76_worker_schedule(&sdio->stat_worker);
} while (nframes > 0);
if (resched)
mt76_worker_schedule(&dev->tx_worker);
}
-static void mt76s_tx_status_data(struct work_struct *work)
+static void mt76s_tx_status_data(struct mt76_worker *worker)
{
struct mt76_sdio *sdio;
struct mt76_dev *dev;
u8 update = 1;
u16 count = 0;
- sdio = container_of(work, struct mt76_sdio, stat_work);
+ sdio = container_of(worker, struct mt76_sdio, stat_worker);
dev = container_of(sdio, struct mt76_dev, sdio);
while (true) {
@@ -508,7 +508,7 @@ static void mt76s_tx_status_data(struct work_struct *work)
}
if (count && test_bit(MT76_STATE_RUNNING, &dev->phy.state))
- ieee80211_queue_work(dev->hw, &sdio->stat_work);
+ mt76_worker_schedule(&sdio->status_worker);
else
clear_bit(MT76_READING_STATS, &dev->phy.state);
}
@@ -600,8 +600,8 @@ void mt76s_deinit(struct mt76_dev *dev)
mt76_worker_teardown(&sdio->txrx_worker);
mt76_worker_teardown(&sdio->status_worker);
mt76_worker_teardown(&sdio->net_worker);
+ mt76_worker_teardown(&sdio->stat_worker);
- cancel_work_sync(&sdio->stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
mt76_tx_status_check(dev, true);
@@ -644,10 +644,14 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
if (err)
return err;
+ err = mt76_worker_setup(dev->hw, &sdio->stat_worker, mt76s_tx_status_data,
+ "sdio-sta");
+ if (err)
+ return err;
+
sched_set_fifo_low(sdio->status_worker.task);
sched_set_fifo_low(sdio->net_worker.task);
-
- INIT_WORK(&sdio->stat_work, mt76s_tx_status_data);
+ sched_set_fifo_low(sdio->stat_worker.task);
dev->queue_ops = &sdio_queue_ops;
dev->bus = bus_ops;
@@ -668,4 +672,5 @@ EXPORT_SYMBOL_GPL(mt76s_init);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_DESCRIPTION("MediaTek MT76x SDIO helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 1584665fe3cb..5a0bcb5071bd 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -1128,4 +1128,5 @@ int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf)
EXPORT_SYMBOL_GPL(mt76u_init);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
+MODULE_DESCRIPTION("MediaTek MT76x USB helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
index fc76c66ff1a5..d6c01a2dd198 100644
--- a/drivers/net/wireless/mediatek/mt76/util.c
+++ b/drivers/net/wireless/mediatek/mt76/util.c
@@ -138,4 +138,5 @@ int __mt76_worker_fn(void *ptr)
}
EXPORT_SYMBOL_GPL(__mt76_worker_fn);
+MODULE_DESCRIPTION("MediaTek MT76x helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
index da52f91693b5..ad2509d8c99a 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -105,10 +105,9 @@ struct wilc_ch_list_elem {
} __packed;
static void cfg_scan_result(enum scan_event scan_event,
- struct wilc_rcvd_net_info *info, void *user_void)
+ struct wilc_rcvd_net_info *info,
+ struct wilc_priv *priv)
{
- struct wilc_priv *priv = user_void;
-
if (!priv->cfg_scanning)
return;
@@ -162,9 +161,8 @@ static void cfg_scan_result(enum scan_event scan_event,
}
static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
- void *priv_data)
+ struct wilc_priv *priv)
{
- struct wilc_priv *priv = priv_data;
struct net_device *dev = priv->dev;
struct wilc_vif *vif = netdev_priv(dev);
struct wilc *wl = vif->wilc;
@@ -286,9 +284,8 @@ static int scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
else
scan_type = WILC_FW_PASSIVE_SCAN;
- ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type, scan_ch_list,
- request->n_channels, cfg_scan_result, (void *)priv,
- request);
+ ret = wilc_scan(vif, WILC_FW_USER_SCAN, scan_type,
+ scan_ch_list, cfg_scan_result, request);
if (ret) {
priv->scan_req = NULL;
@@ -412,9 +409,8 @@ static int connect(struct wiphy *wiphy, struct net_device *dev,
wfi_drv->conn_info.security = security;
wfi_drv->conn_info.auth_type = auth_type;
- wfi_drv->conn_info.ch = ch;
wfi_drv->conn_info.conn_result = cfg_connect_result;
- wfi_drv->conn_info.arg = priv;
+ wfi_drv->conn_info.priv = priv;
wfi_drv->conn_info.param = join_params;
if (sme->mfp == NL80211_MFP_OPTIONAL)
@@ -1094,9 +1090,8 @@ static void wilc_wfi_mgmt_tx_complete(void *priv, int status)
kfree(pv_data);
}
-static void wilc_wfi_remain_on_channel_expired(void *data, u64 cookie)
+static void wilc_wfi_remain_on_channel_expired(struct wilc_vif *vif, u64 cookie)
{
- struct wilc_vif *vif = data;
struct wilc_priv *priv = &vif->priv;
struct wilc_wfi_p2p_listen_params *params = &priv->remain_on_ch_params;
@@ -1128,9 +1123,8 @@ static int remain_on_channel(struct wiphy *wiphy,
if (id == 0)
id = ++priv->inc_roc_cookie;
- ret = wilc_remain_on_channel(vif, id, duration, chan->hw_value,
- wilc_wfi_remain_on_channel_expired,
- (void *)vif);
+ ret = wilc_remain_on_channel(vif, id, chan->hw_value,
+ wilc_wfi_remain_on_channel_expired);
if (ret)
return ret;
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
index a28da5938481..839f142663e8 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.c
+++ b/drivers/net/wireless/microchip/wilc1000/hif.c
@@ -144,18 +144,19 @@ static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt)
scan_req = &hif_drv->usr_scan_req;
if (scan_req->scan_result) {
- scan_req->scan_result(evt, NULL, scan_req->arg);
+ scan_req->scan_result(evt, NULL, scan_req->priv);
scan_req->scan_result = NULL;
}
return result;
}
-int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
- u8 *ch_freq_list, u8 ch_list_len,
+int wilc_scan(struct wilc_vif *vif, u8 scan_source,
+ u8 scan_type, u8 *ch_freq_list,
void (*scan_result_fn)(enum scan_event,
- struct wilc_rcvd_net_info *, void *),
- void *user_arg, struct cfg80211_scan_request *request)
+ struct wilc_rcvd_net_info *,
+ struct wilc_priv *),
+ struct cfg80211_scan_request *request)
{
int result = 0;
struct wid wid_list[WILC_SCAN_WID_LIST_SIZE];
@@ -164,6 +165,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
u8 *buffer;
u8 valuesize = 0;
u8 *search_ssid_vals = NULL;
+ const u8 ch_list_len = request->n_channels;
struct host_if_drv *hif_drv = vif->hif_drv;
if (hif_drv->hif_state >= HOST_IF_SCANNING &&
@@ -249,7 +251,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
index++;
hif_drv->usr_scan_req.scan_result = scan_result_fn;
- hif_drv->usr_scan_req.arg = user_arg;
+ hif_drv->usr_scan_req.priv = &vif->priv;
result = wilc_send_config_pkt(vif, WILC_SET_CFG, wid_list, index);
if (result) {
@@ -348,7 +350,7 @@ static void handle_connect_timeout(struct work_struct *work)
if (hif_drv->conn_info.conn_result) {
hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_CONN_RESP,
WILC_MAC_STATUS_DISCONNECTED,
- hif_drv->conn_info.arg);
+ hif_drv->conn_info.priv);
} else {
netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
@@ -371,8 +373,9 @@ out:
kfree(msg);
}
-void *wilc_parse_join_bss_param(struct cfg80211_bss *bss,
- struct cfg80211_crypto_settings *crypto)
+struct wilc_join_bss_param *
+wilc_parse_join_bss_param(struct cfg80211_bss *bss,
+ struct cfg80211_crypto_settings *crypto)
{
struct wilc_join_bss_param *param;
struct ieee80211_p2p_noa_attr noa_attr;
@@ -545,7 +548,7 @@ static void handle_rcvd_ntwrk_info(struct work_struct *work)
if (scan_req->scan_result)
scan_req->scan_result(SCAN_EVENT_NETWORK_FOUND, rcvd_info,
- scan_req->arg);
+ scan_req->priv);
done:
kfree(rcvd_info->mgmt);
@@ -627,7 +630,7 @@ static inline void host_int_parse_assoc_resp_info(struct wilc_vif *vif,
del_timer(&hif_drv->connect_timer);
conn_info->conn_result(CONN_DISCONN_EVENT_CONN_RESP, mac_status,
- hif_drv->conn_info.arg);
+ hif_drv->conn_info.priv);
if (mac_status == WILC_MAC_STATUS_CONNECTED &&
conn_info->status == WLAN_STATUS_SUCCESS) {
@@ -657,7 +660,7 @@ void wilc_handle_disconnect(struct wilc_vif *vif)
if (hif_drv->conn_info.conn_result)
hif_drv->conn_info.conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF,
- 0, hif_drv->conn_info.arg);
+ 0, hif_drv->conn_info.priv);
eth_zero_addr(hif_drv->assoc_bssid);
@@ -729,7 +732,7 @@ int wilc_disconnect(struct wilc_vif *vif)
if (scan_req->scan_result) {
del_timer(&hif_drv->scan_timer);
- scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->arg);
+ scan_req->scan_result(SCAN_EVENT_ABORTED, NULL, scan_req->priv);
scan_req->scan_result = NULL;
}
@@ -739,7 +742,7 @@ int wilc_disconnect(struct wilc_vif *vif)
del_timer(&hif_drv->connect_timer);
conn_info->conn_result(CONN_DISCONN_EVENT_DISCONN_NOTIF, 0,
- conn_info->arg);
+ conn_info->priv);
} else {
netdev_err(vif->ndev, "%s: conn_result is NULL\n", __func__);
}
@@ -878,7 +881,7 @@ static int handle_remain_on_chan(struct wilc_vif *vif,
if (result)
return -EBUSY;
- hif_drv->remain_on_ch.arg = hif_remain_ch->arg;
+ hif_drv->remain_on_ch.vif = hif_remain_ch->vif;
hif_drv->remain_on_ch.expired = hif_remain_ch->expired;
hif_drv->remain_on_ch.ch = hif_remain_ch->ch;
hif_drv->remain_on_ch.cookie = hif_remain_ch->cookie;
@@ -915,7 +918,7 @@ static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
}
if (hif_drv->remain_on_ch.expired) {
- hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.arg,
+ hif_drv->remain_on_ch.expired(hif_drv->remain_on_ch.vif,
cookie);
}
} else {
@@ -1538,7 +1541,7 @@ int wilc_deinit(struct wilc_vif *vif)
if (hif_drv->usr_scan_req.scan_result) {
hif_drv->usr_scan_req.scan_result(SCAN_EVENT_ABORTED, NULL,
- hif_drv->usr_scan_req.arg);
+ hif_drv->usr_scan_req.priv);
hif_drv->usr_scan_req.scan_result = NULL;
}
@@ -1669,18 +1672,15 @@ void wilc_scan_complete_received(struct wilc *wilc, u8 *buffer, u32 length)
}
}
-int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
- u32 duration, u16 chan,
- void (*expired)(void *, u64),
- void *user_arg)
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan,
+ void (*expired)(struct wilc_vif *, u64))
{
struct wilc_remain_ch roc;
int result;
roc.ch = chan;
roc.expired = expired;
- roc.arg = user_arg;
- roc.duration = duration;
+ roc.vif = vif;
roc.cookie = cookie;
result = handle_remain_on_chan(vif, &roc);
if (result)
diff --git a/drivers/net/wireless/microchip/wilc1000/hif.h b/drivers/net/wireless/microchip/wilc1000/hif.h
index 8e386db72e45..0d380586b1d9 100644
--- a/drivers/net/wireless/microchip/wilc1000/hif.h
+++ b/drivers/net/wireless/microchip/wilc1000/hif.h
@@ -95,34 +95,37 @@ struct wilc_rcvd_net_info {
struct ieee80211_mgmt *mgmt;
};
+struct wilc_priv;
struct wilc_user_scan_req {
void (*scan_result)(enum scan_event evt,
- struct wilc_rcvd_net_info *info, void *priv);
- void *arg;
+ struct wilc_rcvd_net_info *info,
+ struct wilc_priv *priv);
+ struct wilc_priv *priv;
u32 ch_cnt;
};
+struct wilc_join_bss_param;
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;
u8 *resp_ies;
u16 resp_ies_len;
u16 status;
- void (*conn_result)(enum conn_event evt, u8 status, void *priv_data);
- void *arg;
- void *param;
+ void (*conn_result)(enum conn_event evt, u8 status,
+ struct wilc_priv *priv);
+ struct wilc_priv *priv;
+ struct wilc_join_bss_param *param;
};
+struct wilc_vif;
struct wilc_remain_ch {
u16 ch;
- u32 duration;
- void (*expired)(void *priv, u64 cookie);
- void *arg;
+ void (*expired)(struct wilc_vif *vif, u64 cookie);
+ struct wilc_vif *vif;
u64 cookie;
};
@@ -150,7 +153,6 @@ struct host_if_drv {
u8 assoc_resp[WILC_MAX_ASSOC_RESP_FRAME_SIZE];
};
-struct wilc_vif;
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);
@@ -171,11 +173,12 @@ int wilc_set_join_req(struct wilc_vif *vif, u8 *bssid, const u8 *ies,
int wilc_disconnect(struct wilc_vif *vif);
int wilc_set_mac_chnl_num(struct wilc_vif *vif, u8 channel);
int wilc_get_rssi(struct wilc_vif *vif, s8 *rssi_level);
-int wilc_scan(struct wilc_vif *vif, u8 scan_source, u8 scan_type,
- u8 *ch_freq_list, u8 ch_list_len,
+int wilc_scan(struct wilc_vif *vif, u8 scan_source,
+ u8 scan_type, u8 *ch_freq_list,
void (*scan_result_fn)(enum scan_event,
- struct wilc_rcvd_net_info *, void *),
- void *user_arg, struct cfg80211_scan_request *request);
+ struct wilc_rcvd_net_info *,
+ struct wilc_priv *),
+ struct cfg80211_scan_request *request);
int wilc_hif_set_cfg(struct wilc_vif *vif,
struct cfg_param_attr *cfg_param);
int wilc_init(struct net_device *dev, struct host_if_drv **hif_drv_handler);
@@ -192,10 +195,8 @@ int wilc_edit_station(struct wilc_vif *vif, const u8 *mac,
int wilc_set_power_mgmt(struct wilc_vif *vif, bool enabled, u32 timeout);
int wilc_setup_multicast_filter(struct wilc_vif *vif, u32 enabled, u32 count,
u8 *mc_list);
-int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie,
- u32 duration, u16 chan,
- void (*expired)(void *, u64),
- void *user_arg);
+int wilc_remain_on_channel(struct wilc_vif *vif, u64 cookie, u16 chan,
+ void (*expired)(struct wilc_vif *, u64));
int wilc_listen_state_expired(struct wilc_vif *vif, u64 cookie);
void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg);
int wilc_set_operation_mode(struct wilc_vif *vif, int index, u8 mode,
@@ -210,8 +211,9 @@ int wilc_set_external_auth_param(struct wilc_vif *vif,
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);
+struct wilc_join_bss_param *
+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);
void wilc_handle_disconnect(struct wilc_vif *vif);
diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c
index 91d71e0f7ef2..81e8f25863f5 100644
--- a/drivers/net/wireless/microchip/wilc1000/netdev.c
+++ b/drivers/net/wireless/microchip/wilc1000/netdev.c
@@ -1018,5 +1018,6 @@ unregister_netdev:
return ERR_PTR(ret);
}
+MODULE_DESCRIPTION("Atmel WILC1000 core wireless driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(WILC1000_FW(WILC1000_API_VER));
diff --git a/drivers/net/wireless/microchip/wilc1000/sdio.c b/drivers/net/wireless/microchip/wilc1000/sdio.c
index 87948ba69a22..d6d394693090 100644
--- a/drivers/net/wireless/microchip/wilc1000/sdio.c
+++ b/drivers/net/wireless/microchip/wilc1000/sdio.c
@@ -106,9 +106,10 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
size = cmd->count;
if (cmd->use_global_buf) {
- if (size > sizeof(u32))
- return -EINVAL;
-
+ if (size > sizeof(u32)) {
+ ret = -EINVAL;
+ goto out;
+ }
buf = sdio_priv->cmd53_buf;
}
@@ -123,7 +124,7 @@ static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
if (cmd->use_global_buf)
memcpy(cmd->buffer, buf, size);
}
-
+out:
sdio_release_host(func);
if (ret)
@@ -983,4 +984,5 @@ static struct sdio_driver wilc_sdio_driver = {
module_driver(wilc_sdio_driver,
sdio_register_driver,
sdio_unregister_driver);
+MODULE_DESCRIPTION("Atmel WILC1000 SDIO wireless driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/microchip/wilc1000/spi.c b/drivers/net/wireless/microchip/wilc1000/spi.c
index 77b4cdff73c3..1d8b241ce43c 100644
--- a/drivers/net/wireless/microchip/wilc1000/spi.c
+++ b/drivers/net/wireless/microchip/wilc1000/spi.c
@@ -273,6 +273,7 @@ static struct spi_driver wilc_spi_driver = {
.remove = wilc_bus_remove,
};
module_spi_driver(wilc_spi_driver);
+MODULE_DESCRIPTION("Atmel WILC1000 SPI wireless driver");
MODULE_LICENSE("GPL");
static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len)
diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c
index 76d0a778636a..311676c1ece0 100644
--- a/drivers/net/wireless/purelifi/plfxlc/usb.c
+++ b/drivers/net/wireless/purelifi/plfxlc/usb.c
@@ -493,9 +493,12 @@ int plfxlc_usb_wreq_async(struct plfxlc_usb *usb, const u8 *buffer,
void *context)
{
struct usb_device *udev = interface_to_usbdev(usb->ez_usb);
- struct urb *urb = usb_alloc_urb(0, GFP_ATOMIC);
+ struct urb *urb;
int r;
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
(void *)buffer, buffer_len, complete_fn, context);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h
index 48521e45577d..8930589b4967 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
@@ -3194,4 +3194,8 @@ enum rt2800_eeprom_word {
*/
#define BCN_TBTT_OFFSET 64
+/* Watchdog type mask */
+#define RT2800_WATCHDOG_HANG BIT(0)
+#define RT2800_WATCHDOG_DMA_BUSY BIT(1)
+
#endif /* RT2800_H */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
index ee880f749b3c..aaf31857ae1e 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -30,9 +30,10 @@
#include "rt2800lib.h"
#include "rt2800.h"
-static bool modparam_watchdog;
-module_param_named(watchdog, modparam_watchdog, bool, S_IRUGO);
-MODULE_PARM_DESC(watchdog, "Enable watchdog to detect tx/rx hangs and reset hardware if detected");
+static unsigned int modparam_watchdog = RT2800_WATCHDOG_DMA_BUSY;
+module_param_named(watchdog, modparam_watchdog, uint, 0444);
+MODULE_PARM_DESC(watchdog, "Enable watchdog to recover tx/rx hangs.\n"
+ "\t\t(0=disabled, 1=hang watchdog, 2=DMA watchdog(default), 3=both)");
/*
* Register access.
@@ -1261,15 +1262,12 @@ static void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
}
-void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+static bool rt2800_watchdog_hung(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
bool hung_tx = false;
bool hung_rx = false;
- if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
- return;
-
rt2800_update_survey(rt2x00dev);
queue_for_each(rt2x00dev, queue) {
@@ -1297,18 +1295,72 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
}
}
+ if (!hung_tx && !hung_rx)
+ return false;
+
if (hung_tx)
rt2x00_warn(rt2x00dev, "Watchdog TX hung detected\n");
if (hung_rx)
rt2x00_warn(rt2x00dev, "Watchdog RX hung detected\n");
- if (hung_tx || hung_rx) {
- queue_for_each(rt2x00dev, queue)
- queue->wd_count = 0;
+ queue_for_each(rt2x00dev, queue)
+ queue->wd_count = 0;
+
+ return true;
+}
+
+static bool rt2800_watchdog_dma_busy(struct rt2x00_dev *rt2x00dev)
+{
+ bool busy_rx, busy_tx;
+ u32 reg_cfg = rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG);
+ u32 reg_int = rt2800_register_read(rt2x00dev, INT_SOURCE_CSR);
+
+ if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_RX_DMA_BUSY) &&
+ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_RX_COHERENT))
+ rt2x00dev->rxdma_busy++;
+ else
+ rt2x00dev->rxdma_busy = 0;
+
+ if (rt2x00_get_field32(reg_cfg, WPDMA_GLO_CFG_TX_DMA_BUSY) &&
+ rt2x00_get_field32(reg_int, INT_SOURCE_CSR_TX_COHERENT))
+ rt2x00dev->txdma_busy++;
+ else
+ rt2x00dev->txdma_busy = 0;
+
+ busy_rx = rt2x00dev->rxdma_busy > 30;
+ busy_tx = rt2x00dev->txdma_busy > 30;
+
+ if (!busy_rx && !busy_tx)
+ return false;
+ if (busy_rx)
+ rt2x00_warn(rt2x00dev, "Watchdog RX DMA busy detected\n");
+
+ if (busy_tx)
+ rt2x00_warn(rt2x00dev, "Watchdog TX DMA busy detected\n");
+
+ rt2x00dev->rxdma_busy = 0;
+ rt2x00dev->txdma_busy = 0;
+
+ return true;
+}
+
+void rt2800_watchdog(struct rt2x00_dev *rt2x00dev)
+{
+ bool reset = false;
+
+ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
+ return;
+
+ if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_DMA_BUSY)
+ reset = rt2800_watchdog_dma_busy(rt2x00dev);
+
+ if (rt2x00dev->link.watchdog & RT2800_WATCHDOG_HANG)
+ reset = rt2800_watchdog_hung(rt2x00dev) || reset;
+
+ if (reset)
ieee80211_restart_hw(rt2x00dev->hw);
- }
}
EXPORT_SYMBOL_GPL(rt2800_watchdog);
@@ -6048,7 +6100,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
- rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
+ rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 0);
rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
reg = rt2800_register_read(rt2x00dev, OFDM_PROT_CFG);
@@ -6061,7 +6113,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
- rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
+ rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 0);
rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
reg = rt2800_register_read(rt2x00dev, MM20_PROT_CFG);
@@ -8659,7 +8711,7 @@ static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev)
rt2800_rfcsr_write_bank(rt2x00dev, 5, 4, saverfb5r4);
rt2800_rfcsr_write_bank(rt2x00dev, 7, 4, saverfb7r4);
- rt2800_bbp_write(rt2x00dev, 158, 141);
+ rt2800_bbp_write(rt2x00dev, 158, 140);
bbpreg = rt2800_bbp_read(rt2x00dev, 159);
bbpreg = bbpreg & (~0x40);
rt2800_bbp_write(rt2x00dev, 159, bbpreg);
@@ -12013,11 +12065,13 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev)
__set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
}
- if (modparam_watchdog) {
+ rt2x00dev->link.watchdog = modparam_watchdog;
+ /* USB NICs don't support DMA watchdog as INT_SOURCE_CSR is invalid */
+ if (rt2x00_is_usb(rt2x00dev))
+ rt2x00dev->link.watchdog &= ~RT2800_WATCHDOG_DMA_BUSY;
+ if (rt2x00dev->link.watchdog) {
__set_bit(CAPABILITY_RESTART_HW, &rt2x00dev->cap_flags);
rt2x00dev->link.watchdog_interval = msecs_to_jiffies(100);
- } else {
- rt2x00dev->link.watchdog_disabled = true;
}
/*
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index aaaf99331967..82af01448a0a 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -334,7 +334,7 @@ struct link {
*/
struct delayed_work watchdog_work;
unsigned int watchdog_interval;
- bool watchdog_disabled;
+ unsigned int watchdog;
/*
* Work structure for scheduling periodic AGC adjustments.
@@ -926,6 +926,9 @@ struct rt2x00_dev {
*/
u16 beacon_int;
+ /* Rx/Tx DMA busy watchdog counter */
+ u16 rxdma_busy, txdma_busy;
+
/**
* Timestamp of last received beacon
*/
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
index c88ce446e117..9e7d9dbe954c 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -101,6 +101,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
rt2x00link_stop_tuner(rt2x00dev);
rt2x00queue_stop_queues(rt2x00dev);
rt2x00queue_flush_queues(rt2x00dev, true);
+ rt2x00queue_stop_queue(rt2x00dev->bcn);
/*
* Disable radio.
@@ -1286,6 +1287,7 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
rt2x00dev->intf_ap_count = 0;
rt2x00dev->intf_sta_count = 0;
rt2x00dev->intf_associated = 0;
+ rt2x00dev->intf_beaconing = 0;
/* Enable the radio */
retval = rt2x00lib_enable_radio(rt2x00dev);
@@ -1312,6 +1314,7 @@ void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev)
rt2x00dev->intf_ap_count = 0;
rt2x00dev->intf_sta_count = 0;
rt2x00dev->intf_associated = 0;
+ rt2x00dev->intf_beaconing = 0;
}
static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
index 6cf7e7c997c2..fb23d409fba8 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00link.c
@@ -384,7 +384,7 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev)
struct link *link = &rt2x00dev->link;
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- rt2x00dev->ops->lib->watchdog && !link->watchdog_disabled)
+ rt2x00dev->ops->lib->watchdog && link->watchdog)
ieee80211_queue_delayed_work(rt2x00dev->hw,
&link->watchdog_work,
link->watchdog_interval);
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
index 4202c6517783..75fda72c14ca 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -598,6 +598,17 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
*/
if (changes & BSS_CHANGED_BEACON_ENABLED) {
mutex_lock(&intf->beacon_skb_mutex);
+
+ /*
+ * Clear the 'enable_beacon' flag and clear beacon because
+ * the beacon queue has been stopped after hardware reset.
+ */
+ if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) &&
+ intf->enable_beacon) {
+ intf->enable_beacon = false;
+ rt2x00queue_clear_beacon(rt2x00dev, vif);
+ }
+
if (!bss_conf->enable_beacon && intf->enable_beacon) {
rt2x00dev->intf_beaconing--;
intf->enable_beacon = false;
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
index 98df0aef8168..013003777fee 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
@@ -416,9 +416,6 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
else
__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
- if (tx_info->control.rts_cts_rate_idx >= 0)
- rate =
- ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
}
/*
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 43ee7592bc6e..180907319e8c 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -7961,6 +7961,18 @@ static const struct usb_device_id dev_table[] = {
.driver_info = (unsigned long)&rtl8192eu_fops},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818c, 0xff, 0xff, 0xff),
.driver_info = (unsigned long)&rtl8192eu_fops},
+/* D-Link DWA-131 rev C1 */
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3312, 0xff, 0xff, 0xff),
+ .driver_info = (unsigned long)&rtl8192eu_fops},
+/* TP-Link TL-WN8200ND V2 */
+{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0126, 0xff, 0xff, 0xff),
+ .driver_info = (unsigned long)&rtl8192eu_fops},
+/* Mercusys MW300UM */
+{USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0100, 0xff, 0xff, 0xff),
+ .driver_info = (unsigned long)&rtl8192eu_fops},
+/* Mercusys MW300UH */
+{USB_DEVICE_AND_INTERFACE_INFO(0x2c4e, 0x0104, 0xff, 0xff, 0xff),
+ .driver_info = (unsigned long)&rtl8192eu_fops},
#endif
{ }
};
diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
index 7ce37fb4fdbf..1a8d715b7c07 100644
--- a/drivers/net/wireless/realtek/rtlwifi/base.c
+++ b/drivers/net/wireless/realtek/rtlwifi/base.c
@@ -1402,10 +1402,6 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
sta_entry =
(struct rtl_sta_info *)sta->drv_priv;
- if (!sta_entry) {
- rcu_read_unlock();
- return true;
- }
capab =
le16_to_cpu(mgmt->u.action.u.addba_req.capab);
tid = (capab &
@@ -1760,8 +1756,6 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return -EINVAL;
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
- if (!sta_entry)
- return -ENXIO;
tid_data = &sta_entry->tids[tid];
rtl_dbg(rtlpriv, COMP_SEND, DBG_DMESG,
@@ -1818,8 +1812,6 @@ int rtl_rx_agg_start(struct ieee80211_hw *hw,
}
sta_entry = (struct rtl_sta_info *)sta->drv_priv;
- if (!sta_entry)
- return -ENXIO;
tid_data = &sta_entry->tids[tid];
rtl_dbg(rtlpriv, COMP_RECV, DBG_DMESG,
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c
index 9886e719739b..96ce05bcf0b3 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.c
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.c
@@ -64,13 +64,12 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
- u8 init_aspm;
+ u16 init_aspm;
ppsc->reg_rfps_level = 0;
ppsc->support_aspm = false;
/*Update PCI ASPM setting */
- ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm;
switch (rtlpci->const_pci_aspm) {
case 0:
/*No ASPM */
@@ -151,9 +150,10 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
/* toshiba aspm issue, toshiba will set aspm selfly
* so we should not set aspm in driver
*/
- pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm);
+ pcie_capability_read_word(rtlpci->pdev, PCI_EXP_LNKCTL, &init_aspm);
if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE &&
- init_aspm == 0x43)
+ ((u8)init_aspm) == (PCI_EXP_LNKCTL_ASPM_L0S |
+ PCI_EXP_LNKCTL_ASPM_L1 | PCI_EXP_LNKCTL_CCC))
ppsc->support_aspm = false;
}
@@ -164,21 +164,29 @@ static bool _rtl_pci_platform_switch_device_pci_aspm(
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ value &= PCI_EXP_LNKCTL_ASPMC;
+
if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)
- value |= 0x40;
+ value |= PCI_EXP_LNKCTL_CCC;
- pci_write_config_byte(rtlpci->pdev, 0x80, value);
+ pcie_capability_clear_and_set_word(rtlpci->pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC | value,
+ value);
return false;
}
-/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
-static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
+/* @value is PCI_EXP_LNKCTL_CLKREQ_EN or 0 to enable/disable clk request. */
+static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u16 value)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- pci_write_config_byte(rtlpci->pdev, 0x81, value);
+ value &= PCI_EXP_LNKCTL_CLKREQ_EN;
+
+ pcie_capability_clear_and_set_word(rtlpci->pdev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_CLKREQ_EN,
+ value);
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
udelay(100);
@@ -192,13 +200,10 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
- u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
/*Retrieve original configuration settings. */
u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
- u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
- pcibridge_linkctrlreg;
u16 aspmlevel = 0;
- u8 tmp_u1b = 0;
+ u16 tmp_u1b = 0;
if (!ppsc->support_aspm)
return;
@@ -216,21 +221,13 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
}
/*for promising device will in L0 state after an I/O. */
- pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
+ pcie_capability_read_word(rtlpci->pdev, PCI_EXP_LNKCTL, &tmp_u1b);
/*Set corresponding value. */
- aspmlevel |= BIT(0) | BIT(1);
+ aspmlevel |= PCI_EXP_LNKCTL_ASPM_L0S | PCI_EXP_LNKCTL_ASPM_L1;
linkctrl_reg &= ~aspmlevel;
- pcibridge_linkctrlreg &= ~(BIT(0) | BIT(1));
_rtl_pci_platform_switch_device_pci_aspm(hw, linkctrl_reg);
- udelay(50);
-
- /*4 Disable Pci Bridge ASPM */
- pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
- pcibridge_linkctrlreg);
-
- udelay(50);
}
/*Enable RTL8192SE ASPM & Enable Pci Bridge ASPM for
@@ -245,9 +242,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
- u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
u16 aspmlevel;
- u8 u_pcibridge_aspmsetting;
u8 u_device_aspmsetting;
if (!ppsc->support_aspm)
@@ -259,25 +254,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
return;
}
- /*4 Enable Pci Bridge ASPM */
-
- u_pcibridge_aspmsetting =
- pcipriv->ndis_adapter.pcibridge_linkctrlreg |
- rtlpci->const_hostpci_aspm_setting;
-
- if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
- u_pcibridge_aspmsetting &= ~BIT(0);
-
- pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
- u_pcibridge_aspmsetting);
-
- rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
- "PlatformEnableASPM(): Write reg[%x] = %x\n",
- (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
- u_pcibridge_aspmsetting);
-
- udelay(50);
-
/*Get ASPM level (with/without Clock Req) */
aspmlevel = rtlpci->const_devicepci_aspm_setting;
u_device_aspmsetting = pcipriv->ndis_adapter.linkctrl_reg;
@@ -291,7 +267,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_CLK_REQ) {
_rtl_pci_switch_clk_req(hw, (ppsc->reg_rfps_level &
- RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
+ RT_RF_OFF_LEVL_CLK_REQ) ?
+ PCI_EXP_LNKCTL_CLKREQ_EN : 0);
RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
}
udelay(100);
@@ -358,22 +335,6 @@ static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
return tpriv != NULL;
}
-static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
-{
- struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
- u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
- u8 linkctrl_reg;
- u8 num4bbytes;
-
- num4bbytes = (capabilityoffset + 0x10) / 4;
-
- /*Read Link Control Register */
- pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg);
-
- pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
-}
-
static void rtl_pci_parse_configuration(struct pci_dev *pdev,
struct ieee80211_hw *hw)
{
@@ -390,9 +351,8 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev,
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n",
pcipriv->ndis_adapter.linkctrl_reg);
- pci_read_config_byte(pdev, 0x98, &tmp);
- tmp |= BIT(4);
- pci_write_config_byte(pdev, 0x98, tmp);
+ pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
+ PCI_EXP_DEVCTL2_COMP_TMOUT_DIS);
tmp = 0x17;
pci_write_config_byte(pdev, 0x70f, tmp);
@@ -2008,7 +1968,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
*/
if (bridge_pdev) {
/*find bridge info if available */
- pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
pcipriv->ndis_adapter.pcibridge_vendor = tmp;
@@ -2028,12 +1987,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
PCI_SLOT(bridge_pdev->devfn);
pcipriv->ndis_adapter.pcibridge_funcnum =
PCI_FUNC(bridge_pdev->devfn);
- pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
- pci_pcie_cap(bridge_pdev);
- pcipriv->ndis_adapter.num4bytes =
- (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4;
-
- rtl_pci_get_linkcontrol_field(hw);
if (pcipriv->ndis_adapter.pcibridge_vendor ==
PCI_BRIDGE_VENDOR_AMD) {
@@ -2050,13 +2003,11 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg);
rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG,
- "pci_bridge busnumber:devnumber:funcnumber:vendor:pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n",
+ "pci_bridge busnumber:devnumber:funcnumber:vendor:amd %d:%d:%d:%x:%x\n",
pcipriv->ndis_adapter.pcibridge_busnum,
pcipriv->ndis_adapter.pcibridge_devnum,
pcipriv->ndis_adapter.pcibridge_funcnum,
pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor],
- pcipriv->ndis_adapter.pcibridge_pciehdr_offset,
- pcipriv->ndis_adapter.pcibridge_linkctrlreg,
pcipriv->ndis_adapter.amd_l1_patch);
rtl_pci_parse_configuration(pdev, hw);
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h
index 866861626a0a..e8fa022df8b4 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.h
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.h
@@ -44,18 +44,6 @@
#define ATI_DEVICE_ID 0x7914
#define AMD_VENDOR_ID 0x1022
-#define PCI_MAX_BRIDGE_NUMBER 255
-#define PCI_MAX_DEVICES 32
-#define PCI_MAX_FUNCTION 8
-
-#define PCI_CONF_ADDRESS 0x0CF8 /*PCI Configuration Space Address */
-#define PCI_CONF_DATA 0x0CFC /*PCI Configuration Space Data */
-
-#define PCI_CLASS_BRIDGE_DEV 0x06
-#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04
-#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10
-#define PCI_CAP_ID_EXP 0x10
-
#define U1DONTCARE 0xFF
#define U2DONTCARE 0xFFFF
#define U4DONTCARE 0xFFFFFFFF
@@ -113,11 +101,6 @@ enum pci_bridge_vendor {
PCI_BRIDGE_VENDOR_MAX,
};
-struct rtl_pci_capabilities_header {
- u8 capability_id;
- u8 next;
-};
-
/* In new TRX flow, Buffer_desc is new concept
* But TX wifi info == TX descriptor in old flow
* RX wifi info == RX descriptor in old flow
@@ -195,7 +178,6 @@ struct rtl_pci {
u32 reg_bcn_ctrl_val;
/*ASPM*/ u8 const_pci_aspm;
- u8 const_amdpci_aspm;
u8 const_hwsw_rfoff_d3;
u8 const_support_pciaspm;
/*pci-e bridge */
@@ -233,13 +215,6 @@ struct mp_adapter {
u8 pcibridge_funcnum;
u8 pcibridge_vendor;
- u16 pcibridge_vendorid;
- u16 pcibridge_deviceid;
-
- u8 num4bytes;
-
- u8 pcibridge_pciehdr_offset;
- u8 pcibridge_linkctrlreg;
bool amd_l1_patch;
};
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
index 12d0b3a87af7..0fab3a0c7d49 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
@@ -16,12 +16,6 @@ static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
-static u32 _rtl88e_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw);
static bool _rtl88e_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
static bool phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
@@ -51,7 +45,7 @@ u32 rtl88e_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
@@ -74,7 +68,7 @@ void rtl88e_phy_set_bb_reg(struct ieee80211_hw *hw,
if (bitmask != MASKDWORD) {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) | (data << bitshift));
}
@@ -99,7 +93,7 @@ u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl88e_phy_rf_serial_read(hw, rfpath, regaddr);
- bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -127,7 +121,7 @@ void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl88e_phy_rf_serial_read(hw,
rfpath,
regaddr);
- bitshift = _rtl88e_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
index b77937fe2448..37bb59fa8bfa 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
@@ -21,9 +21,6 @@ static void rtl88e_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/* ASPM PS mode.
* 0 - Disable ASPM,
* 1 - Enable ASPM without Clock Req,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
index 3d29c8dbb255..3730613a3962 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
@@ -17,7 +17,7 @@ u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x)\n",
regaddr, bitmask);
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
@@ -40,7 +40,7 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
if (bitmask != MASKDWORD) {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) | (data << bitshift));
}
@@ -143,14 +143,6 @@ void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(_rtl92c_phy_rf_serial_write);
-u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
-EXPORT_SYMBOL(_rtl92c_phy_calculate_bit_shift);
-
static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw)
{
rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2);
@@ -1487,12 +1479,8 @@ EXPORT_SYMBOL(rtl92c_phy_lc_calibrate);
void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, s8 delta)
{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- if (rtlphy->apk_done)
- return;
if (IS_92C_SERIAL(rtlhal->version))
_rtl92c_phy_ap_calibrate(hw, delta, true);
else
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h
index 75afa6253ad0..e64d377dfe9e 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.h
@@ -196,7 +196,6 @@ bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw);
void rtl92c_phy_set_io(struct ieee80211_hw *hw);
void rtl92c_bb_block_on(struct ieee80211_hw *hw);
-u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask);
long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
enum wireless_mode wirelessmode,
u8 txpwridx);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.c
index da54e51badd3..fa70a7d5539f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.c
@@ -39,7 +39,7 @@ u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
rfpath, regaddr);
}
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -110,7 +110,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl92c_phy_rf_serial_read(hw,
rfpath,
regaddr);
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
@@ -122,7 +122,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl92c_phy_fw_rf_serial_read(hw,
rfpath,
regaddr);
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h
index 7582a162bd11..c7a0d4c776f0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/phy.h
@@ -94,7 +94,6 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, enum radio_path rfpath,
u32 offset);
u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset);
-u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask);
void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset, u32 data);
void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
index e452275d8789..e20f2bec45c4 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c
@@ -24,9 +24,6 @@ static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/*
* ASPM PS mode.
* 0 - Disable ASPM,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/phy.c
index a8d9fe269f31..0b8cb7e61fd8 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/phy.c
@@ -32,7 +32,7 @@ u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl92c_phy_fw_rf_serial_read(hw,
rfpath, regaddr);
}
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
@@ -56,7 +56,7 @@ void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl92c_phy_rf_serial_read(hw,
rfpath,
regaddr);
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
@@ -67,7 +67,7 @@ void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
original_value = _rtl92c_phy_fw_rf_serial_read(hw,
rfpath,
regaddr);
- bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
index d18c092b6142..d835a27429f0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
@@ -169,13 +169,6 @@ static const u8 channel_all[59] = {
157, 159, 161, 163, 165
};
-static u32 _rtl92d_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
-
u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -198,7 +191,7 @@ u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
} else {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
}
- bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
"BBR MASK=0x%x Addr[0x%x]=0x%x\n",
@@ -230,7 +223,7 @@ void rtl92d_phy_set_bb_reg(struct ieee80211_hw *hw,
dbi_direct);
else
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) | (data << bitshift));
}
if (rtlhal->during_mac1init_radioa || rtlhal->during_mac0init_radiob)
@@ -317,7 +310,7 @@ u32 rtl92d_phy_query_rf_reg(struct ieee80211_hw *hw,
regaddr, rfpath, bitmask);
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr);
- bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
@@ -343,7 +336,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl92d_phy_rf_serial_read(hw,
rfpath, regaddr);
- bitshift = _rtl92d_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((original_value & (~bitmask)) |
(data << bitshift));
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c
index 11f319c97124..afd685ed460a 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c
@@ -21,9 +21,6 @@ static void rtl92d_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/*
* ASPM PS mode.
* 0 - Disable ASPM,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c
index 5a828a934fe9..17486e3f322c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c
@@ -432,10 +432,8 @@ static void rtl92ee_dm_check_rssi_monitor(struct ieee80211_hw *hw)
static void rtl92ee_dm_init_primary_cca_check(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct dynamic_primary_cca *primarycca = &rtlpriv->primarycca;
- rtlhal->rts_en = 0;
primarycca->dup_rts_flag = 0;
primarycca->intf_flag = 0;
primarycca->intf_type = 0;
@@ -562,7 +560,7 @@ static void rtl92ee_dm_write_dynamic_cca(struct ieee80211_hw *hw,
primarycca->mf_state = cur_mf_state;
}
-static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw)
+static void rtl92ee_dm_dynamic_primary_cca_check(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct false_alarm_statistics *falsealm_cnt = &rtlpriv->falsealm_cnt;
@@ -615,13 +613,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw)
rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
primarycca->pricca_flag = 1;
primarycca->dup_rts_flag = 1;
- rtlpriv->rtlhal.rts_en = 1;
} else {
primarycca->intf_type = 0;
primarycca->intf_flag = 0;
cur_mf_state = MF_USC_LSC;
rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
- rtlpriv->rtlhal.rts_en = 0;
primarycca->dup_rts_flag = 0;
}
} else if (sec_ch_offset == 1) {
@@ -642,13 +638,11 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw)
rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
primarycca->pricca_flag = 1;
primarycca->dup_rts_flag = 1;
- rtlpriv->rtlhal.rts_en = 1;
} else {
primarycca->intf_type = 0;
primarycca->intf_flag = 0;
cur_mf_state = MF_USC_LSC;
rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
- rtlpriv->rtlhal.rts_en = 0;
primarycca->dup_rts_flag = 0;
}
}
@@ -660,7 +654,6 @@ static void rtl92ee_dm_dynamic_primary_cca_ckeck(struct ieee80211_hw *hw)
cur_mf_state = MF_USC_LSC;
/* default */
rtl92ee_dm_write_dynamic_cca(hw, cur_mf_state);
- rtlpriv->rtlhal.rts_en = 0;
primarycca->dup_rts_flag = 0;
primarycca->intf_type = 0;
primarycca->intf_flag = 0;
@@ -1090,7 +1083,7 @@ void rtl92ee_dm_watchdog(struct ieee80211_hw *hw)
rtl92ee_dm_refresh_rate_adaptive_mask(hw);
rtl92ee_dm_check_edca_turbo(hw);
rtl92ee_dm_dynamic_atc_switch(hw);
- rtl92ee_dm_dynamic_primary_cca_ckeck(hw);
+ rtl92ee_dm_dynamic_primary_cca_check(hw);
}
spin_unlock(&rtlpriv->locks.rf_ps_lock);
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
index ebb7abd0c9ad..d4da5cdc8414 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
@@ -1320,7 +1320,6 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw)
err = 1;
return err;
}
- rtlhal->rx_tag = 0;
rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, 0x8000);
err = rtl92ee_download_fw(hw, false);
if (err) {
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c
index cc0bcaf13e96..73ef602bfb01 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c
@@ -16,7 +16,6 @@ static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw,
static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
-static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask);
static bool _rtl92ee_phy_bb8192ee_config_parafile(struct ieee80211_hw *hw);
static bool _rtl92ee_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
static bool phy_config_bb_with_hdr_file(struct ieee80211_hw *hw,
@@ -46,7 +45,7 @@ u32 rtl92ee_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
@@ -68,7 +67,7 @@ void rtl92ee_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
if (bitmask != MASKDWORD) {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) | (data << bitshift));
}
@@ -92,7 +91,7 @@ u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw,
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl92ee_phy_rf_serial_read(hw , rfpath, regaddr);
- bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -119,7 +118,7 @@ void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw,
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl92ee_phy_rf_serial_read(hw, rfpath, addr);
- bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = (original_value & (~bitmask)) | (data << bitshift);
}
@@ -201,13 +200,6 @@ static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw,
pphyreg->rf3wire_offset, data_and_addr);
}
-static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
-
bool rtl92ee_phy_mac_config(struct ieee80211_hw *hw)
{
return _rtl92ee_phy_config_mac_with_headerfile(hw);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c
index 011ce82efeff..7bde20fdbeab 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c
@@ -24,9 +24,6 @@ static void rtl92ee_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/**
* ASPM PS mode.
* 0 - Disable ASPM,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
index 09591a0b5a81..d9ef7e1da1db 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
@@ -14,13 +14,6 @@
#include "hw.h"
#include "table.h"
-static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
-
u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -30,7 +23,7 @@ u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
regaddr, bitmask);
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE, "BBR MASK=0x%x Addr[0x%x]=0x%x\n",
@@ -52,7 +45,7 @@ void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
if (bitmask != MASKDWORD) {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) | (data << bitshift));
}
@@ -157,7 +150,7 @@ u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr);
- bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -188,7 +181,7 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
if (bitmask != RFREG_OFFSET_MASK) {
original_value = _rtl92s_phy_rf_serial_read(hw, rfpath,
regaddr);
- bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((original_value & (~bitmask)) | (data << bitshift));
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c
index 30bce381c3bb..675bdd32feb1 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c
@@ -21,9 +21,6 @@ static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/* ASPM PS mode.
* 0 - Disable ASPM,
* 1 - Enable ASPM without Clock Req,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
index fe9b407dc2af..71e29b103da5 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
@@ -49,7 +49,7 @@ u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw,
rfpath, regaddr);
}
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -80,7 +80,7 @@ void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw,
original_value = rtl8723_phy_rf_serial_read(hw,
rfpath,
regaddr);
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
@@ -89,7 +89,7 @@ void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw,
rtl8723_phy_rf_serial_write(hw, rfpath, regaddr, data);
} else {
if (bitmask != RFREG_OFFSET_MASK) {
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data =
((original_value & (~bitmask)) |
(data << bitshift));
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
index c821436a1991..dd7505e2f22c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c
@@ -26,9 +26,6 @@ static void rtl8723e_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/**
* ASPM PS mode.
* 0 - Disable ASPM,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c
index 2b9313cb93db..094cb36153f5 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c
@@ -41,7 +41,7 @@ u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
spin_lock(&rtlpriv->locks.rf_lock);
original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr);
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -68,7 +68,7 @@ void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path,
if (bitmask != RFREG_OFFSET_MASK) {
original_value = rtl8723_phy_rf_serial_read(hw, path,
regaddr);
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((original_value & (~bitmask)) |
(data << bitshift));
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
index 43b611d5288d..162c34f0e9b7 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c
@@ -26,9 +26,6 @@ static void rtl8723be_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/* ASPM PS mode.
* 0 - Disable ASPM,
* 1 - Enable ASPM without Clock Req,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c
index 47b6c1aa36b0..d97c88ebce75 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c
@@ -17,7 +17,7 @@ u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw,
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
"regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
@@ -39,7 +39,7 @@ void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
if (bitmask != MASKDWORD) {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = rtl8723_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) | (data << bitshift));
}
@@ -51,14 +51,6 @@ void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
}
EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg);
-u32 rtl8723_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
-EXPORT_SYMBOL_GPL(rtl8723_phy_calculate_bit_shift);
-
u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset)
{
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h
index edf1c52f0ee2..af85c3287507 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.h
@@ -27,7 +27,6 @@ u32 rtl8723_phy_query_bb_reg(struct ieee80211_hw *hw,
u32 regaddr, u32 bitmask);
void rtl8723_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
u32 bitmask, u32 data);
-u32 rtl8723_phy_calculate_bit_shift(u32 bitmask);
u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset);
void rtl8723_phy_rf_serial_write(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index 1633328bc3d1..f4b232f038a9 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -2270,67 +2270,27 @@ static void _rtl8821ae_clear_pci_pme_status(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u16 cap_hdr;
- u8 cap_pointer;
- u8 cap_id = 0xff;
- u8 pmcs_reg;
- u8 cnt = 0;
+ struct pci_dev *pdev = rtlpci->pdev;
+ u16 pmcs_reg;
+ u8 pm_cap;
- /* Get the Capability pointer first,
- * the Capability Pointer is located at
- * offset 0x34 from the Function Header */
-
- pci_read_config_byte(rtlpci->pdev, 0x34, &cap_pointer);
- rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
- "PCI configuration 0x34 = 0x%2x\n", cap_pointer);
-
- do {
- pci_read_config_word(rtlpci->pdev, cap_pointer, &cap_hdr);
- cap_id = cap_hdr & 0xFF;
-
- rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
- "in pci configuration, cap_pointer%x = %x\n",
- cap_pointer, cap_id);
-
- if (cap_id == 0x01) {
- break;
- } else {
- /* point to next Capability */
- cap_pointer = (cap_hdr >> 8) & 0xFF;
- /* 0: end of pci capability, 0xff: invalid value */
- if (cap_pointer == 0x00 || cap_pointer == 0xff) {
- cap_id = 0xff;
- break;
- }
- }
- } while (cnt++ < 200);
-
- if (cap_id == 0x01) {
- /* Get the PM CSR (Control/Status Register),
- * The PME_Status is located at PM Capatibility offset 5, bit 7
- */
- pci_read_config_byte(rtlpci->pdev, cap_pointer + 5, &pmcs_reg);
-
- if (pmcs_reg & BIT(7)) {
- /* PME event occured, clear the PM_Status by write 1 */
- pmcs_reg = pmcs_reg | BIT(7);
-
- pci_write_config_byte(rtlpci->pdev, cap_pointer + 5,
- pmcs_reg);
- /* Read it back to check */
- pci_read_config_byte(rtlpci->pdev, cap_pointer + 5,
- &pmcs_reg);
- rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG,
- "Clear PME status 0x%2x to 0x%2x\n",
- cap_pointer + 5, pmcs_reg);
- } else {
- rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG,
- "PME status(0x%2x) = 0x%2x\n",
- cap_pointer + 5, pmcs_reg);
- }
- } else {
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (!pm_cap) {
rtl_dbg(rtlpriv, COMP_INIT, DBG_WARNING,
"Cannot find PME Capability\n");
+ return;
+ }
+
+ pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmcs_reg);
+ if (pmcs_reg & PCI_PM_CTRL_PME_STATUS) {
+ /* Clear PME_Status with write */
+ pci_write_config_word(pdev, pm_cap + PCI_PM_CTRL, pmcs_reg);
+ pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pmcs_reg);
+ rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG,
+ "Cleared PME status, PMCS reg = 0x%4x\n", pmcs_reg);
+ } else {
+ rtl_dbg(rtlpriv, COMP_INIT, DBG_DMESG,
+ "PMCS reg = 0x%4x\n", pmcs_reg);
}
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
index 5323ead30db0..1be51ea3f3c8 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
@@ -27,12 +27,6 @@ static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw,
static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
-static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i = ffs(bitmask);
-
- return i ? i - 1 : 32;
-}
static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw);
/*static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);*/
static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
@@ -105,7 +99,7 @@ u32 rtl8821ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
"regaddr(%#x), bitmask(%#x)\n",
regaddr, bitmask);
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
returnvalue = (originalvalue & bitmask) >> bitshift;
rtl_dbg(rtlpriv, COMP_RF, DBG_TRACE,
@@ -126,7 +120,7 @@ void rtl8821ae_phy_set_bb_reg(struct ieee80211_hw *hw,
if (bitmask != MASKDWORD) {
originalvalue = rtl_read_dword(rtlpriv, regaddr);
- bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((originalvalue & (~bitmask)) |
((data << bitshift) & bitmask));
}
@@ -152,7 +146,7 @@ u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw,
spin_lock(&rtlpriv->locks.rf_lock);
original_value = _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr);
- bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
readback_value = (original_value & bitmask) >> bitshift;
spin_unlock(&rtlpriv->locks.rf_lock);
@@ -180,7 +174,7 @@ void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw,
if (bitmask != RFREG_OFFSET_MASK) {
original_value =
_rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr);
- bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask);
+ bitshift = calculate_bit_shift(bitmask);
data = ((original_value & (~bitmask)) | (data << bitshift));
}
@@ -2038,15 +2032,9 @@ static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
/*don't need the hw_body*/
if (!_rtl8821ae_check_condition(hw, v1)) {
i += 2; /* skip the pair of expression*/
- v1 = array[i];
v2 = array[i+1];
- v3 = array[i+2];
- while (v2 != 0xDEAD) {
+ while (v2 != 0xDEAD)
i += 3;
- v1 = array[i];
- v2 = array[i+1];
- v3 = array[i+2];
- }
}
}
}
@@ -3543,7 +3531,6 @@ u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw)
struct rtl_phy *rtlphy = &rtlpriv->phy;
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u32 timeout = 1000, timecount = 0;
- u8 channel = rtlphy->current_channel;
if (rtlphy->sw_chnl_inprogress)
return 0;
@@ -3566,8 +3553,6 @@ u8 rtl8821ae_phy_sw_chnl(struct ieee80211_hw *hw)
rtl8821ae_phy_switch_wirelessband(hw, BAND_ON_2_4G);
rtlphy->sw_chnl_inprogress = true;
- if (channel == 0)
- channel = 1;
rtl_dbg(rtlpriv, COMP_SCAN, DBG_TRACE,
"switch to channel%d, band type is %d\n",
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
index 0bca542e103f..7b911695db33 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
@@ -23,9 +23,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
/**
* ASPM PS mode.
* 0 - Disable ASPM,
diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h
index 31a481f43a07..d87cd2252eac 100644
--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -1316,7 +1316,6 @@ struct rtl_phy {
u8 sw_chnl_stage;
u8 sw_chnl_step;
u8 current_channel;
- u8 h2c_box_num;
u8 set_io_inprogress;
u8 lck_inprogress;
@@ -1329,9 +1328,6 @@ struct rtl_phy {
s32 reg_ebc;
s32 reg_ec4;
s32 reg_ecc;
- u8 rfpienable;
- u8 reserve_0;
- u16 reserve_1;
u32 reg_c04, reg_c08, reg_874;
u32 adda_backup[16];
u32 iqk_mac_backup[IQK_MAC_REG_NUM];
@@ -1345,7 +1341,6 @@ struct rtl_phy {
struct iqk_matrix_regs iqk_matrix[IQK_MATRIX_SETTINGS_NUM];
bool rfpi_enable;
- bool iqk_in_progress;
u8 pwrgroup_cnt;
u8 cck_high_power;
@@ -1383,7 +1378,6 @@ struct rtl_phy {
[MAX_RF_PATH_NUM];
u32 rfreg_chnlval[2];
- bool apk_done;
u32 reg_rf3c[2]; /* pathA / pathB */
u32 backup_rf_0x1a;/*92ee*/
@@ -1395,7 +1389,6 @@ struct rtl_phy {
struct phy_parameters hwparam_tables[MAX_TAB];
u16 rf_pathmap;
- u8 hw_rof_enable; /*Enable GPIO[9] as WL RF HW PDn source*/
enum rt_polarity_ctl polarity_ctl;
};
@@ -1610,7 +1603,6 @@ struct rtl_hal {
bool up_first_time;
bool first_init;
bool being_init_adapter;
- bool bbrf_ready;
bool mac_func_enable;
bool pre_edcca_enable;
struct bt_coexist_8723 hal_coex_8723;
@@ -1623,9 +1615,7 @@ struct rtl_hal {
u8 state; /*stop 0, start 1 */
u8 board_type;
u8 package_type;
- u8 external_pa;
- u8 pa_mode;
u8 pa_type_2g;
u8 pa_type_5g;
u8 lna_type_2g;
@@ -1691,14 +1681,9 @@ struct rtl_hal {
bool master_of_dmsp;
bool slave_of_dmsp;
- u16 rx_tag;/*for 92ee*/
- u8 rts_en;
-
/*for wowlan*/
- bool wow_enable;
bool enter_pnp_sleep;
bool wake_from_pnp_sleep;
- bool wow_enabled;
time64_t last_suspend_sec;
u32 wowlan_fwsize;
u8 *wowlan_firmware;
@@ -2023,8 +2008,6 @@ struct rtl_ps_ctl {
u32 cur_ps_level;
u32 reg_rfps_level;
- /*just for PCIE ASPM */
- u8 const_amdpci_aspm;
bool pwrdown_mode;
enum rf_pwrstate inactive_pwrstate;
@@ -3069,4 +3052,11 @@ static inline struct ieee80211_sta *rtl_find_sta(struct ieee80211_hw *hw,
return ieee80211_find_sta(mac->vif, mac_addr);
}
+static inline u32 calculate_bit_shift(u32 bitmask)
+{
+ if (WARN_ON_ONCE(!bitmask))
+ return 0;
+
+ return __ffs(bitmask);
+}
#endif
diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index 35bc37a3c469..1b2ad81838be 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -1314,8 +1314,8 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev)
#ifdef CONFIG_RTW88_DEBUG
-void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
- const char *fmt, ...)
+void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
+ const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -1330,6 +1330,6 @@ void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
va_end(args);
}
-EXPORT_SYMBOL(__rtw_dbg);
+EXPORT_SYMBOL(rtw_dbg);
#endif /* CONFIG_RTW88_DEBUG */
diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h
index a03ced11bbe0..f20c0471c82a 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.h
+++ b/drivers/net/wireless/realtek/rtw88/debug.h
@@ -43,10 +43,8 @@ static inline void rtw_debugfs_init(struct rtw_dev *rtwdev) {}
#ifdef CONFIG_RTW88_DEBUG
__printf(3, 4)
-void __rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
- const char *fmt, ...);
-
-#define rtw_dbg(rtwdev, a...) __rtw_dbg(rtwdev, ##a)
+void rtw_dbg(struct rtw_dev *rtwdev, enum rtw_debug_mask mask,
+ const char *fmt, ...);
static inline bool rtw_dbg_is_enabled(struct rtw_dev *rtwdev,
enum rtw_debug_mask mask)
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index acd78311c8c4..3f037ddcecf1 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -998,7 +998,7 @@ static u8 rtw_get_rsvd_page_probe_req_location(struct rtw_dev *rtwdev,
if (rsvd_pkt->type != RSVD_PROBE_REQ)
continue;
if ((!ssid && !rsvd_pkt->ssid) ||
- rtw_ssid_equal(rsvd_pkt->ssid, ssid))
+ cfg80211_ssid_eq(rsvd_pkt->ssid, ssid))
location = rsvd_pkt->page;
}
@@ -1015,7 +1015,7 @@ static u16 rtw_get_rsvd_page_probe_req_size(struct rtw_dev *rtwdev,
if (rsvd_pkt->type != RSVD_PROBE_REQ)
continue;
if ((!ssid && !rsvd_pkt->ssid) ||
- rtw_ssid_equal(rsvd_pkt->ssid, ssid))
+ cfg80211_ssid_eq(rsvd_pkt->ssid, ssid))
size = rsvd_pkt->probe_req_size;
}
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index a99b53d44267..d8d68f16014e 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -280,9 +280,9 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & FIF_ALLMULTI) {
if (*new_flags & FIF_ALLMULTI)
- rtwdev->hal.rcr |= BIT_AM | BIT_AB;
+ rtwdev->hal.rcr |= BIT_AM;
else
- rtwdev->hal.rcr &= ~(BIT_AM | BIT_AB);
+ rtwdev->hal.rcr &= ~(BIT_AM);
}
if (changed_flags & FIF_FCSFAIL) {
if (*new_flags & FIF_FCSFAIL)
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 4a33d2e47f33..6d22628129d0 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -2008,6 +2008,11 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev)
efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0;
efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0;
+ if (!is_valid_ether_addr(efuse->addr)) {
+ eth_random_addr(efuse->addr);
+ dev_warn(rtwdev->dev, "efuse MAC invalid, using random\n");
+ }
+
out_disable:
rtw_chip_efuse_disable(rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index b6bfd4c02e2d..e14d1da43940 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -2090,18 +2090,6 @@ static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw_vif *rtwvif)
return container_of(p, struct ieee80211_vif, drv_priv);
}
-static inline bool rtw_ssid_equal(struct cfg80211_ssid *a,
- struct cfg80211_ssid *b)
-{
- if (!a || !b || a->ssid_len != b->ssid_len)
- return false;
-
- if (memcmp(a->ssid, b->ssid, a->ssid_len))
- return false;
-
- return true;
-}
-
static inline void rtw_chip_efuse_grant_on(struct rtw_dev *rtwdev)
{
if (rtwdev->chip->ops->efuse_grant)
diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c
index 2c1fb2dabd40..0cae5746f540 100644
--- a/drivers/net/wireless/realtek/rtw88/sdio.c
+++ b/drivers/net/wireless/realtek/rtw88/sdio.c
@@ -500,19 +500,40 @@ static u32 rtw_sdio_get_tx_addr(struct rtw_dev *rtwdev, size_t size,
static int rtw_sdio_read_port(struct rtw_dev *rtwdev, u8 *buf, size_t count)
{
struct rtw_sdio *rtwsdio = (struct rtw_sdio *)rtwdev->priv;
+ struct mmc_host *host = rtwsdio->sdio_func->card->host;
bool bus_claim = rtw_sdio_bus_claim_needed(rtwsdio);
u32 rxaddr = rtwsdio->rx_addr++;
- int ret;
+ int ret = 0, err;
+ size_t bytes;
if (bus_claim)
sdio_claim_host(rtwsdio->sdio_func);
- ret = sdio_memcpy_fromio(rtwsdio->sdio_func, buf,
- RTW_SDIO_ADDR_RX_RX0FF_GEN(rxaddr), count);
- if (ret)
- rtw_warn(rtwdev,
- "Failed to read %zu byte(s) from SDIO port 0x%08x",
- count, rxaddr);
+ while (count > 0) {
+ bytes = min_t(size_t, host->max_req_size, count);
+
+ err = sdio_memcpy_fromio(rtwsdio->sdio_func, buf,
+ RTW_SDIO_ADDR_RX_RX0FF_GEN(rxaddr),
+ bytes);
+ if (err) {
+ rtw_warn(rtwdev,
+ "Failed to read %zu byte(s) from SDIO port 0x%08x: %d",
+ bytes, rxaddr, err);
+
+ /* Signal to the caller that reading did not work and
+ * that the data in the buffer is short/corrupted.
+ */
+ ret = err;
+
+ /* Don't stop here - instead drain the remaining data
+ * from the card's buffer, else the card will return
+ * corrupt data for the next rtw_sdio_read_port() call.
+ */
+ }
+
+ count -= bytes;
+ buf += bytes;
+ }
if (bus_claim)
sdio_release_host(rtwsdio->sdio_func);
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index f63900b6621d..c02ac673be32 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -656,9 +656,8 @@ void __rtw_tx_work(struct rtw_dev *rtwdev)
list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) {
struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq);
unsigned long frame_cnt;
- unsigned long byte_cnt;
- ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt);
+ ieee80211_txq_get_depth(txq, &frame_cnt, NULL);
rtw_txq_push(rtwdev, rtwtxq, frame_cnt);
list_del_init(&rtwtxq->list);
diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c
index 8aaf83a2a6b4..2e7326a8e3e4 100644
--- a/drivers/net/wireless/realtek/rtw89/acpi.c
+++ b/drivers/net/wireless/realtek/rtw89/acpi.c
@@ -12,27 +12,74 @@ static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
0x82, 0xBD, 0xFE, 0x86,
0x07, 0x80, 0x3A, 0xA7);
-static int rtw89_acpi_dsm_get(struct rtw89_dev *rtwdev, union acpi_object *obj,
- u8 *value)
+static
+int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj,
+ u8 *value)
{
- switch (obj->type) {
- case ACPI_TYPE_INTEGER:
- *value = (u8)obj->integer.value;
- break;
- case ACPI_TYPE_BUFFER:
- *value = obj->buffer.pointer[0];
- break;
- default:
- rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
- "acpi dsm return unhandled type: %d\n", obj->type);
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI,
+ "acpi: expect integer but type: %d\n", obj->type);
return -EINVAL;
}
+ *value = (u8)obj->integer.value;
+ return 0;
+}
+
+static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p)
+{
+ return p->signature[0] == 0x00 &&
+ p->signature[1] == 0xE0 &&
+ p->signature[2] == 0x4C;
+}
+
+static
+int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
+ union acpi_object *obj,
+ struct rtw89_acpi_policy_6ghz **policy_6ghz)
+{
+ const struct rtw89_acpi_policy_6ghz *ptr;
+ u32 expect_len;
+ u32 len;
+
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI,
+ "acpi: expect buffer but type: %d\n", obj->type);
+ return -EINVAL;
+ }
+
+ len = obj->buffer.length;
+ if (len < sizeof(*ptr)) {
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
+ __func__, len);
+ return -EINVAL;
+ }
+
+ ptr = (typeof(ptr))obj->buffer.pointer;
+ if (!chk_acpi_policy_6ghz_sig(ptr)) {
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
+ return -EINVAL;
+ }
+
+ expect_len = struct_size(ptr, country_list, ptr->country_count);
+ if (len < expect_len) {
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n",
+ __func__, expect_len, len);
+ return -EINVAL;
+ }
+
+ *policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL);
+ if (!*policy_6ghz)
+ return -ENOMEM;
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz,
+ expect_len);
return 0;
}
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
- enum rtw89_acpi_dsm_func func, u8 *value)
+ enum rtw89_acpi_dsm_func func,
+ struct rtw89_acpi_dsm_result *res)
{
union acpi_object *obj;
int ret;
@@ -40,12 +87,16 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
0, func, NULL);
if (!obj) {
- rtw89_debug(rtwdev, RTW89_DBG_UNEXP,
+ rtw89_debug(rtwdev, RTW89_DBG_ACPI,
"acpi dsm fail to evaluate func: %d\n", func);
return -ENOENT;
}
- ret = rtw89_acpi_dsm_get(rtwdev, obj, value);
+ if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
+ ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
+ &res->u.policy_6ghz);
+ else
+ ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);
ACPI_FREE(obj);
return ret;
diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h
index ed74d8ceb733..fe85b40cf076 100644
--- a/drivers/net/wireless/realtek/rtw89/acpi.h
+++ b/drivers/net/wireless/realtek/rtw89/acpi.h
@@ -15,7 +15,37 @@ enum rtw89_acpi_dsm_func {
RTW89_ACPI_DSM_FUNC_59G_EN = 6,
};
+enum rtw89_acpi_policy_mode {
+ RTW89_ACPI_POLICY_BLOCK = 0,
+ RTW89_ACPI_POLICY_ALLOW = 1,
+};
+
+struct rtw89_acpi_country_code {
+ /* below are allowed:
+ * * ISO alpha2 country code
+ * * EU for countries in Europe
+ */
+ char alpha2[2];
+} __packed;
+
+struct rtw89_acpi_policy_6ghz {
+ u8 signature[3];
+ u8 rsvd;
+ u8 policy_mode;
+ u8 country_count;
+ struct rtw89_acpi_country_code country_list[] __counted_by(country_count);
+} __packed;
+
+struct rtw89_acpi_dsm_result {
+ union {
+ u8 value;
+ /* caller needs to free it after using */
+ struct rtw89_acpi_policy_6ghz *policy_6ghz;
+ } u;
+};
+
int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
- enum rtw89_acpi_dsm_func func, u8 *value);
+ enum rtw89_acpi_dsm_func func,
+ struct rtw89_acpi_dsm_result *res);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c
index f5301c2bbf13..914c94988b2f 100644
--- a/drivers/net/wireless/realtek/rtw89/cam.c
+++ b/drivers/net/wireless/realtek/rtw89/cam.c
@@ -488,6 +488,20 @@ static int rtw89_cam_get_avail_addr_cam(struct rtw89_dev *rtwdev,
return 0;
}
+static u8 rtw89_get_addr_cam_entry_size(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ switch (chip->chip_id) {
+ case RTL8852A:
+ case RTL8852B:
+ case RTL8851B:
+ return ADDR_CAM_ENT_SIZE;
+ default:
+ return ADDR_CAM_ENT_SHORT_SIZE;
+ }
+}
+
int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
struct rtw89_addr_cam_entry *addr_cam,
const struct rtw89_bssid_cam_entry *bssid_cam)
@@ -509,7 +523,7 @@ int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev,
}
addr_cam->addr_cam_idx = addr_cam_idx;
- addr_cam->len = ADDR_CAM_ENT_SIZE;
+ addr_cam->len = rtw89_get_addr_cam_entry_size(rtwdev);
addr_cam->offset = 0;
addr_cam->valid = true;
addr_cam->addr_mask = 0;
diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c
index bdcc172639e4..f37afb4cbb63 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.c
+++ b/drivers/net/wireless/realtek/rtw89/coex.c
@@ -6,6 +6,7 @@
#include "debug.h"
#include "fw.h"
#include "mac.h"
+#include "phy.h"
#include "ps.h"
#include "reg.h"
@@ -122,7 +123,8 @@ static const u32 cxtbl[] = {
0xea55556a, /* 21 */
0xaafafafa, /* 22 */
0xfafaaafa, /* 23 */
- 0xfafffaff /* 24 */
+ 0xfafffaff, /* 24 */
+ 0xea6a5a5a, /* 25 */
};
static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
@@ -131,7 +133,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
+ .fwlrole = 2, .frptmap = 3, .fcxctrl = 1,
.info_buf = 1800, .max_role_num = 6,
},
{RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0),
@@ -159,7 +161,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = {
.fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5,
.fcxstep = 3, .fcxnullsta = 2, .fcxmreg = 2, .fcxgpiodbg = 1,
.fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1,
- .fwlrole = 1, .frptmap = 3, .fcxctrl = 1,
+ .fwlrole = 2, .frptmap = 3, .fcxctrl = 1,
.info_buf = 1800, .max_role_num = 6,
},
{RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0),
@@ -246,6 +248,11 @@ struct rtw89_btc_btf_set_mon_reg {
struct rtw89_btc_fbtc_mreg regs[] __counted_by(reg_num);
} __packed;
+struct _wl_rinfo_now {
+ u8 link_mode;
+ u32 dbcc_2g_phy: 2;
+};
+
enum btc_btf_set_cx_policy {
CXPOLICY_TDMA = 0x0,
CXPOLICY_SLOT = 0x1,
@@ -262,6 +269,8 @@ enum btc_b2w_scoreboard {
BTC_BSCB_RFK_RUN = BIT(5),
BTC_BSCB_RFK_REQ = BIT(6),
BTC_BSCB_LPS = BIT(7),
+ BTC_BSCB_BT_LNAB0 = BIT(8),
+ BTC_BSCB_BT_LNAB1 = BIT(10),
BTC_BSCB_WLRFK = BIT(11),
BTC_BSCB_BT_HILNA = BIT(13),
BTC_BSCB_BT_CONNECT = BIT(16),
@@ -405,11 +414,14 @@ enum btc_cx_poicy_type {
/* TDMA Fix slot-8: W1:B1 = user-define */
BTC_CXP_FIX_TDW1B1 = (BTC_CXP_FIX << 8) | 8,
- /* TDMA Fix slot-9: W1:B1 = 40:20 */
- BTC_CXP_FIX_TD4020 = (BTC_CXP_FIX << 8) | 9,
-
/* TDMA Fix slot-9: W1:B1 = 40:10 */
- BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 10,
+ BTC_CXP_FIX_TD4010ISO = (BTC_CXP_FIX << 8) | 9,
+
+ /* TDMA Fix slot-10: W1:B1 = 40:10 */
+ BTC_CXP_FIX_TD4010ISO_DL = (BTC_CXP_FIX << 8) | 10,
+
+ /* TDMA Fix slot-11: W1:B1 = 40:10 */
+ BTC_CXP_FIX_TD4010ISO_UL = (BTC_CXP_FIX << 8) | 11,
/* PS-TDMA Fix slot-0: W1:B1 = 30:30 */
BTC_CXP_PFIX_TD3030 = (BTC_CXP_PFIX << 8) | 0,
@@ -710,7 +722,8 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
if (type & BTC_RESET_CX)
memset(cx, 0, sizeof(*cx));
- else if (type & BTC_RESET_BTINFO) /* only for BT enable */
+
+ if (type & BTC_RESET_BTINFO) /* only for BT enable */
memset(bt, 0, sizeof(*bt));
if (type & BTC_RESET_CTRL) {
@@ -739,12 +752,115 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type)
btc->dm.coex_info_map = BTC_COEX_INFO_ALL;
btc->dm.wl_tx_limit.tx_time = BTC_MAX_TX_TIME_DEF;
btc->dm.wl_tx_limit.tx_retry = BTC_MAX_TX_RETRY_DEF;
+ btc->dm.wl_pre_agc_rb = BTC_PREAGC_NOTFOUND;
+ btc->dm.wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_NOTFOUND;
}
if (type & BTC_RESET_MDINFO)
memset(&btc->mdinfo, 0, sizeof(btc->mdinfo));
}
+static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u8 i;
+
+ for (i = 0; i < mreg_num; i++)
+ if (le16_to_cpu(chip->mon_reg[i].type) == reg_type &&
+ le32_to_cpu(chip->mon_reg[i].offset) == target) {
+ return i;
+ }
+ return BTC_REG_NOTFOUND;
+}
+
+static void _get_reg_status(struct rtw89_dev *rtwdev, u8 type, u8 *val)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_btc_module *md = &btc->mdinfo;
+ union rtw89_btc_fbtc_mreg_val *pmreg;
+ u32 pre_agc_addr = R_BTC_BB_PRE_AGC_S1;
+ u32 reg_val;
+ u8 idx;
+
+ if (md->ant.btg_pos == RF_PATH_A)
+ pre_agc_addr = R_BTC_BB_PRE_AGC_S0;
+
+ switch (type) {
+ case BTC_CSTATUS_TXDIV_POS:
+ if (md->switch_type == BTC_SWITCH_INTERNAL)
+ *val = BTC_ANT_DIV_MAIN;
+ break;
+ case BTC_CSTATUS_RXDIV_POS:
+ if (md->switch_type == BTC_SWITCH_INTERNAL)
+ *val = BTC_ANT_DIV_MAIN;
+ break;
+ case BTC_CSTATUS_BB_GNT_MUX:
+ reg_val = rtw89_phy_read32(rtwdev, R_BTC_BB_BTG_RX);
+ *val = !(reg_val & B_BTC_BB_GNT_MUX);
+ break;
+ case BTC_CSTATUS_BB_GNT_MUX_MON:
+ if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
+ return;
+
+ pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
+ if (ver->fcxmreg == 1) {
+ idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
+ REG_BB, R_BTC_BB_BTG_RX);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]);
+ *val = !(reg_val & B_BTC_BB_GNT_MUX);
+ }
+ } else if (ver->fcxmreg == 2) {
+ idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
+ REG_BB, R_BTC_BB_BTG_RX);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_BTGCTRL_BB_GNT_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]);
+ *val = !(reg_val & B_BTC_BB_GNT_MUX);
+ }
+ }
+ break;
+ case BTC_CSTATUS_BB_PRE_AGC:
+ reg_val = rtw89_phy_read32(rtwdev, pre_agc_addr);
+ reg_val &= B_BTC_BB_PRE_AGC_MASK;
+ *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
+ break;
+ case BTC_CSTATUS_BB_PRE_AGC_MON:
+ if (!btc->fwinfo.rpt_fbtc_mregval.cinfo.valid)
+ return;
+
+ pmreg = &btc->fwinfo.rpt_fbtc_mregval.finfo;
+ if (ver->fcxmreg == 1) {
+ idx = _search_reg_index(rtwdev, pmreg->v1.reg_num,
+ REG_BB, pre_agc_addr);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_PREAGC_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v1.mreg_val[idx]) &
+ B_BTC_BB_PRE_AGC_MASK;
+ *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
+ }
+ } else if (ver->fcxmreg == 2) {
+ idx = _search_reg_index(rtwdev, pmreg->v2.reg_num,
+ REG_BB, pre_agc_addr);
+ if (idx == BTC_REG_NOTFOUND) {
+ *val = BTC_PREAGC_NOTFOUND;
+ } else {
+ reg_val = le32_to_cpu(pmreg->v2.mreg_val[idx]) &
+ B_BTC_BB_PRE_AGC_MASK;
+ *val = (reg_val == B_BTC_BB_PRE_AGC_VAL);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
#define BTC_RPT_HDR_SIZE 3
#define BTC_CHK_WLSLOT_DRIFT_MAX 15
#define BTC_CHK_BTSLOT_DRIFT_MAX 15
@@ -1003,7 +1119,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
u16 wl_slot_set = 0, wl_slot_real = 0;
u32 trace_step = btc->ctrl.trace_step, rpt_len = 0, diff_t = 0;
u32 cnt_leak_slot, bt_slot_real, bt_slot_set, cnt_rx_imr;
- u8 i;
+ u8 i, val = 0;
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): index:%d\n",
@@ -1508,6 +1624,19 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev,
goto err;
}
break;
+ case BTC_RPT_TYPE_MREG:
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX_MON, &val);
+ if (dm->wl_btg_rx == BTC_BTGCTRL_BB_GNT_FWCTRL)
+ dm->wl_btg_rx_rb = BTC_BTGCTRL_BB_GNT_FWCTRL;
+ else
+ dm->wl_btg_rx_rb = val;
+
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC_MON, &val);
+ if (dm->wl_pre_agc == BTC_PREAGC_BB_FWCTRL)
+ dm->wl_pre_agc_rb = BTC_PREAGC_BB_FWCTRL;
+ else
+ dm->wl_pre_agc_rb = val;
+ break;
case BTC_RPT_TYPE_BT_VER:
case BTC_RPT_TYPE_BT_SCAN:
case BTC_RPT_TYPE_BT_AFH:
@@ -1576,13 +1705,13 @@ static void _append_tdma(struct rtw89_dev *rtwdev)
if (ver->fcxtdma == 1) {
v = (struct rtw89_btc_fbtc_tdma *)&tlv->val[0];
tlv->len = sizeof(*v);
- memcpy(v, &dm->tdma, sizeof(*v));
+ *v = dm->tdma;
btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v);
} else {
tlv->len = sizeof(*v3);
v3 = (struct rtw89_btc_fbtc_tdma_v3 *)&tlv->val[0];
v3->fver = ver->fcxtdma;
- memcpy(&v3->tdma, &dm->tdma, sizeof(v3->tdma));
+ v3->tdma = dm->tdma;
btc->policy_len += BTC_TLV_HDR_LEN + sizeof(*v3);
}
@@ -2155,8 +2284,9 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
- if (bt->rf_para.rx_gain_freerun == level ||
- level > BTC_BT_RX_NORMAL_LVL)
+ if ((bt->rf_para.rx_gain_freerun == level ||
+ level > BTC_BT_RX_NORMAL_LVL) &&
+ (!rtwdev->chip->scbd || bt->lna_constrain == level))
return;
bt->rf_para.rx_gain_freerun = level;
@@ -2171,32 +2301,59 @@ static void _set_bt_rx_gain(struct rtw89_dev *rtwdev, u8 level)
else
_write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
- _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, 1);
+ _send_fw_cmd(rtwdev, BTFC_SET, SET_BT_LNA_CONSTRAIN, &level, sizeof(level));
}
static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
struct rtw89_btc *btc = &rtwdev->btc;
+ const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_dm *dm = &btc->dm;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
struct rtw89_btc_bt_info *bt = &btc->cx.bt;
struct rtw89_btc_bt_link_info *b = &bt->link_info;
+ struct rtw89_btc_wl_smap *wl_smap = &wl->status.map;
struct rtw89_btc_rf_trx_para para;
u32 wl_stb_chg = 0;
- u8 level_id = 0;
+ u8 level_id = 0, link_mode = 0, i, dbcc_2g_phy = 0;
- if (!dm->freerun) {
- /* fix LNA2 = level-5 for BT ACI issue at BTG */
+ if (ver->fwlrole == 0) {
+ link_mode = wl->role_info.link_mode;
+ for (i = 0; i < RTW89_PHY_MAX; i++) {
+ if (wl->dbcc_info.real_band[i] == RTW89_BAND_2G)
+ dbcc_2g_phy = i;
+ }
+ } else if (ver->fwlrole == 1) {
+ link_mode = wl->role_info_v1.link_mode;
+ dbcc_2g_phy = wl->role_info_v1.dbcc_2g_phy;
+ } else if (ver->fwlrole == 2) {
+ link_mode = wl->role_info_v2.link_mode;
+ dbcc_2g_phy = wl->role_info_v2.dbcc_2g_phy;
+ }
+
+ /* decide trx_para_level */
+ if (btc->mdinfo.ant.type == BTC_ANT_SHARED) {
+ /* fix LNA2 + TIA gain not change by GNT_BT */
if ((btc->dm.wl_btg_rx && b->profile_cnt.now != 0) ||
dm->bt_only == 1)
- dm->trx_para_level = 1;
+ dm->trx_para_level = 1; /* for better BT ACI issue */
else
dm->trx_para_level = 0;
+ } else { /* non-shared antenna */
+ dm->trx_para_level = 5;
+ /* modify trx_para if WK 2.4G-STA-DL + bt link */
+ if (b->profile_cnt.now != 0 &&
+ link_mode == BTC_WLINK_2G_STA &&
+ wl->status.map.traffic_dir & BIT(RTW89_TFC_UL)) { /* uplink */
+ if (wl->rssi_level == 4 && bt->rssi_level > 2)
+ dm->trx_para_level = 6;
+ else if (wl->rssi_level == 3 && bt->rssi_level > 3)
+ dm->trx_para_level = 7;
+ }
}
- level_id = (u8)dm->trx_para_level;
-
+ level_id = dm->trx_para_level;
if (level_id >= chip->rf_para_dlink_num ||
level_id >= chip->rf_para_ulink_num) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -2210,25 +2367,26 @@ static void _set_rf_trx_para(struct rtw89_dev *rtwdev)
else
para = chip->rf_para_dlink[level_id];
- if (para.wl_tx_power != RTW89_BTC_WL_DEF_TX_PWR)
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): wl_tx_power=%d\n",
- __func__, para.wl_tx_power);
- _set_wl_tx_power(rtwdev, para.wl_tx_power);
- _set_wl_rx_gain(rtwdev, para.wl_rx_gain);
- _set_bt_tx_power(rtwdev, para.bt_tx_power);
- _set_bt_rx_gain(rtwdev, para.bt_rx_gain);
-
- if (bt->enable.now == 0 || wl->status.map.rf_off == 1 ||
- wl->status.map.lps == BTC_LPS_RF_OFF)
+ if (dm->fddt_train) {
+ _set_wl_rx_gain(rtwdev, 1);
+ _write_scbd(rtwdev, BTC_WSCB_RXGAIN, true);
+ } else {
+ _set_wl_tx_power(rtwdev, para.wl_tx_power);
+ _set_wl_rx_gain(rtwdev, para.wl_rx_gain);
+ _set_bt_tx_power(rtwdev, para.bt_tx_power);
+ _set_bt_rx_gain(rtwdev, para.bt_rx_gain);
+ }
+
+ if (!bt->enable.now || dm->wl_only || wl_smap->rf_off ||
+ wl_smap->lps == BTC_LPS_RF_OFF ||
+ link_mode == BTC_WLINK_5G ||
+ link_mode == BTC_WLINK_NOLINK ||
+ (rtwdev->dbcc_en && dbcc_2g_phy != RTW89_PHY_1))
wl_stb_chg = 0;
else
wl_stb_chg = 1;
if (wl_stb_chg != dm->wl_stb_chg) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): wl_stb_chg=%d\n",
- __func__, wl_stb_chg);
dm->wl_stb_chg = wl_stb_chg;
chip->ops->btc_wl_s1_standby(rtwdev, dm->wl_stb_chg);
}
@@ -2661,9 +2819,17 @@ void rtw89_btc_set_policy(struct rtw89_dev *rtwdev, u16 policy_type)
_slot_set(btc, CXST_W1, 40, tbl_w1, SLOT_ISO);
_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
break;
- case BTC_CXP_FIX_TD4020:
- _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX);
- _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX);
+ case BTC_CXP_FIX_TD4010ISO:
+ _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
+ break;
+ case BTC_CXP_FIX_TD4010ISO_DL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
+ break;
+ case BTC_CXP_FIX_TD4010ISO_UL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
break;
case BTC_CXP_FIX_TD7010:
_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
@@ -3002,9 +3168,13 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type)
_slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_ISO);
_slot_set(btc, CXST_B1, 10, tbl_b1, SLOT_MIX);
break;
- case BTC_CXP_FIX_TD4020:
- _slot_set(btc, CXST_W1, 40, cxtbl[1], SLOT_MIX);
- _slot_set(btc, CXST_B1, 20, tbl_b1, SLOT_MIX);
+ case BTC_CXP_FIX_TD4010ISO_DL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[25], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_ISO);
+ break;
+ case BTC_CXP_FIX_TD4010ISO_UL:
+ _slot_set(btc, CXST_W1, 40, cxtbl[20], SLOT_ISO);
+ _slot_set(btc, CXST_B1, 10, cxtbl[25], SLOT_MIX);
break;
case BTC_CXP_FIX_TD7010:
_slot_set(btc, CXST_W1, 70, tbl_w1, SLOT_ISO);
@@ -3381,17 +3551,32 @@ static void _action_wl_init(struct rtw89_dev *rtwdev)
_set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_INIT);
}
-static void _action_wl_off(struct rtw89_dev *rtwdev)
+static void _action_wl_off(struct rtw89_dev *rtwdev, u8 mode)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): !!\n", __func__);
- if (wl->status.map.rf_off || btc->dm.bt_only)
+ if (wl->status.map.rf_off || btc->dm.bt_only) {
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_WOFF);
+ } else if (wl->status.map.lps == BTC_LPS_RF_ON) {
+ if (wl->role_info.link_mode == BTC_WLINK_5G)
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W5G);
+ else
+ _set_ant(rtwdev, FC_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
+ }
- _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
+ if (mode == BTC_WLINK_5G) {
+ _set_policy(rtwdev, BTC_CXP_OFF_EQ0, BTC_ACT_WL_OFF);
+ } else if (wl->status.map.lps == BTC_LPS_RF_ON) {
+ if (btc->cx.bt.link_info.a2dp_desc.active)
+ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
+ else
+ _set_policy(rtwdev, BTC_CXP_OFF_BWB1, BTC_ACT_WL_OFF);
+ } else {
+ _set_policy(rtwdev, BTC_CXP_OFF_BT, BTC_ACT_WL_OFF);
+ }
}
static void _action_freerun(struct rtw89_dev *rtwdev)
@@ -3426,31 +3611,25 @@ static void _action_bt_idle(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
struct rtw89_btc_bt_link_info *b = &btc->cx.bt.link_info;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
_set_ant(rtwdev, NM_EXEC, BTC_PHY_ALL, BTC_ANT_W2G);
if (btc->mdinfo.ant.type == BTC_ANT_SHARED) { /* shared-antenna */
switch (btc->cx.state_map) {
case BTC_WBUSY_BNOSCAN: /*wl-busy + bt idle*/
- if (b->profile_cnt.now > 0)
- _set_policy(rtwdev, BTC_CXP_FIX_TD4010,
- BTC_ACT_BT_IDLE);
+ case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
+ if (b->status.map.connect)
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010, BTC_ACT_BT_IDLE);
+ else if (wl->status.map.traffic_dir & BIT(RTW89_TFC_DL))
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_DL, BTC_ACT_BT_IDLE);
else
- _set_policy(rtwdev, BTC_CXP_FIX_TD4020,
- BTC_ACT_BT_IDLE);
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO_UL, BTC_ACT_BT_IDLE);
break;
case BTC_WBUSY_BSCAN: /*wl-busy + bt-inq */
_set_policy(rtwdev, BTC_CXP_PFIX_TD5050,
BTC_ACT_BT_IDLE);
break;
- case BTC_WSCAN_BNOSCAN: /* wl-scan + bt-idle */
- if (b->profile_cnt.now > 0)
- _set_policy(rtwdev, BTC_CXP_FIX_TD4010,
- BTC_ACT_BT_IDLE);
- else
- _set_policy(rtwdev, BTC_CXP_FIX_TD4020,
- BTC_ACT_BT_IDLE);
- break;
case BTC_WSCAN_BSCAN: /* wl-scan + bt-inq */
_set_policy(rtwdev, BTC_CXP_FIX_TD5050,
BTC_ACT_BT_IDLE);
@@ -3617,7 +3796,7 @@ static void _action_bt_pan(struct rtw89_dev *rtwdev)
_set_policy(rtwdev, BTC_CXP_FIX_TD3060, BTC_ACT_BT_PAN);
break;
case BTC_WLINKING: /* wl-connecting + bt-PAN */
- _set_policy(rtwdev, BTC_CXP_FIX_TD4020, BTC_ACT_BT_PAN);
+ _set_policy(rtwdev, BTC_CXP_FIX_TD4010ISO, BTC_ACT_BT_PAN);
break;
case BTC_WIDLE: /* wl-idle + bt-pan */
_set_policy(rtwdev, BTC_CXP_PFIX_TD2080, BTC_ACT_BT_PAN);
@@ -3798,46 +3977,134 @@ static void _action_wl_rfk(struct rtw89_dev *rtwdev)
static void _set_btg_ctrl(struct rtw89_dev *rtwdev)
{
struct rtw89_btc *btc = &rtwdev->btc;
- const struct rtw89_btc_ver *ver = btc->ver;
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
- struct rtw89_btc_wl_role_info *wl_rinfo = &wl->role_info;
struct rtw89_btc_wl_role_info_v1 *wl_rinfo_v1 = &wl->role_info_v1;
struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2;
+ struct rtw89_btc_wl_role_info *wl_rinfo_v0 = &wl->role_info;
struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info;
- bool is_btg;
- u8 mode;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ struct _wl_rinfo_now wl_rinfo;
+ u32 run_reason = btc->dm.run_reason;
+ u32 is_btg;
+ u8 i, val;
if (btc->ctrl.manual)
return;
if (ver->fwlrole == 0)
- mode = wl_rinfo->link_mode;
+ wl_rinfo.link_mode = wl_rinfo_v0->link_mode;
else if (ver->fwlrole == 1)
- mode = wl_rinfo_v1->link_mode;
+ wl_rinfo.link_mode = wl_rinfo_v1->link_mode;
else if (ver->fwlrole == 2)
- mode = wl_rinfo_v2->link_mode;
+ wl_rinfo.link_mode = wl_rinfo_v2->link_mode;
else
return;
- /* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */
- if (mode == BTC_WLINK_5G) /* always 0 if 5G */
- is_btg = false;
- else if (mode == BTC_WLINK_25G_DBCC &&
- wl_dinfo->real_band[RTW89_PHY_1] != RTW89_BAND_2G)
- is_btg = false;
+ if (rtwdev->dbcc_en) {
+ if (ver->fwlrole == 0) {
+ for (i = 0; i < RTW89_PHY_MAX; i++) {
+ if (wl_dinfo->real_band[i] == RTW89_BAND_2G)
+ wl_rinfo.dbcc_2g_phy = i;
+ }
+ } else if (ver->fwlrole == 1) {
+ wl_rinfo.dbcc_2g_phy = wl_rinfo_v1->dbcc_2g_phy;
+ } else if (ver->fwlrole == 2) {
+ wl_rinfo.dbcc_2g_phy = wl_rinfo_v2->dbcc_2g_phy;
+ } else {
+ return;
+ }
+ }
+
+ if (wl_rinfo.link_mode == BTC_WLINK_25G_MCC)
+ is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL;
+ else if (!(bt->run_patch_code && bt->enable.now))
+ is_btg = BTC_BTGCTRL_DISABLE;
+ else if (wl_rinfo.link_mode == BTC_WLINK_5G)
+ is_btg = BTC_BTGCTRL_DISABLE;
+ else if (dm->freerun)
+ is_btg = BTC_BTGCTRL_DISABLE;
+ else if (rtwdev->dbcc_en && wl_rinfo.dbcc_2g_phy != RTW89_PHY_1)
+ is_btg = BTC_BTGCTRL_DISABLE;
else
- is_btg = true;
+ is_btg = BTC_BTGCTRL_ENABLE;
- if (btc->dm.run_reason != BTC_RSN_NTFY_INIT &&
- is_btg == btc->dm.wl_btg_rx)
- return;
+ if (dm->wl_btg_rx_rb != dm->wl_btg_rx &&
+ dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) {
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX, &val);
+ dm->wl_btg_rx_rb = val;
+ }
- btc->dm.wl_btg_rx = is_btg;
+ if (run_reason == BTC_RSN_NTFY_INIT ||
+ run_reason == BTC_RSN_NTFY_SWBAND ||
+ dm->wl_btg_rx_rb != dm->wl_btg_rx ||
+ is_btg != dm->wl_btg_rx) {
+
+ dm->wl_btg_rx = is_btg;
+
+ if (is_btg > BTC_BTGCTRL_ENABLE)
+ return;
- if (mode == BTC_WLINK_25G_MCC)
+ chip->ops->ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0);
+ }
+}
+
+static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info;
+ struct rtw89_btc_wl_info *wl = &btc->cx.wl;
+ struct rtw89_btc_wl_role_info_v2 *wl_rinfo = &wl->role_info_v2;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_btc_ver *ver = btc->ver;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ struct rtw89_btc_dm *dm = &btc->dm;
+ u8 is_preagc, val;
+
+ if (btc->ctrl.manual)
return;
- rtw89_ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0);
+ if (wl_rinfo->link_mode == BTC_WLINK_25G_MCC)
+ is_preagc = BTC_PREAGC_BB_FWCTRL;
+ else if (!(bt->run_patch_code && bt->enable.now))
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (wl_rinfo->link_mode == BTC_WLINK_5G)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (wl_rinfo->link_mode == BTC_WLINK_NOLINK ||
+ btc->cx.bt.link_info.profile_cnt.now == 0)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (dm->tdma_now.type != CXTDMA_OFF &&
+ !bt_linfo->hfp_desc.exist &&
+ !bt_linfo->hid_desc.exist &&
+ dm->fddt_train == BTC_FDDT_DISABLE)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (ver->fwlrole == 2 && wl_rinfo->dbcc_en &&
+ wl_rinfo->dbcc_2g_phy != RTW89_PHY_1)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else if (btc->mdinfo.ant.type == BTC_ANT_SHARED)
+ is_preagc = BTC_PREAGC_DISABLE;
+ else
+ is_preagc = BTC_PREAGC_ENABLE;
+
+ if (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
+ dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) {
+ _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val);
+ dm->wl_pre_agc_rb = val;
+ }
+
+ if ((wl->coex_mode == BTC_MODE_NORMAL &&
+ (dm->run_reason == BTC_RSN_NTFY_INIT ||
+ dm->run_reason == BTC_RSN_NTFY_SWBAND ||
+ dm->wl_pre_agc_rb != dm->wl_pre_agc)) ||
+ is_preagc != dm->wl_pre_agc) {
+ dm->wl_pre_agc = is_preagc;
+
+ if (is_preagc > BTC_PREAGC_ENABLE)
+ return;
+ chip->ops->ctrl_nbtg_bt_tx(rtwdev, dm->wl_pre_agc, RTW89_PHY_0);
+ }
}
struct rtw89_txtime_data {
@@ -4024,6 +4291,7 @@ static void _action_common(struct rtw89_dev *rtwdev)
struct rtw89_btc_wl_info *wl = &btc->cx.wl;
_set_btg_ctrl(rtwdev);
+ _set_wl_preagc_ctrl(rtwdev);
_set_wl_tx_limit(rtwdev);
_set_bt_afh_info(rtwdev);
_set_bt_rx_agc(rtwdev);
@@ -5008,8 +5276,7 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
return;
}
- if (!(val & BTC_BSCB_ON) ||
- btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] >= BTC_CHK_HANG_MAX)
+ if (!(val & BTC_BSCB_ON))
bt->enable.now = 0;
else
bt->enable.now = 1;
@@ -5035,6 +5302,9 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update)
bt->btg_type = val & BTC_BSCB_BT_S1 ? BTC_BT_BTG : BTC_BT_ALONE;
bt->link_info.a2dp_desc.exist = !!(val & BTC_BSCB_A2DP_ACT);
+ bt->lna_constrain = !!(val & BTC_BSCB_BT_LNAB0) +
+ !!(val & BTC_BSCB_BT_LNAB1) * 2 + 4;
+
/* if rfk run 1->0 */
if (bt->rfk_info.map.run && !(val & BTC_BSCB_RFK_RUN))
status_change = true;
@@ -5128,17 +5398,28 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
}
if (wl->status.map.rf_off_pre == wl->status.map.rf_off &&
- wl->status.map.lps_pre == wl->status.map.lps &&
- (reason == BTC_RSN_NTFY_POWEROFF ||
- reason == BTC_RSN_NTFY_RADIO_STATE)) {
- rtw89_debug(rtwdev, RTW89_DBG_BTC,
- "[BTC], %s(): return for WL rf off state no change!!\n",
- __func__);
- return;
+ wl->status.map.lps_pre == wl->status.map.lps) {
+ if (reason == BTC_RSN_NTFY_POWEROFF ||
+ reason == BTC_RSN_NTFY_RADIO_STATE) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return for WL rf off state no change!!\n",
+ __func__);
+ return;
+ }
+ if (wl->status.map.rf_off == 1 ||
+ wl->status.map.lps == BTC_LPS_RF_OFF) {
+ rtw89_debug(rtwdev, RTW89_DBG_BTC,
+ "[BTC], %s(): return for WL rf off state!!\n",
+ __func__);
+ return;
+ }
}
+ dm->freerun = false;
dm->cnt_dm[BTC_DCNT_RUN]++;
dm->fddt_train = BTC_FDDT_DISABLE;
+ btc->ctrl.igno_bt = false;
+ bt->scan_rx_low_pri = false;
if (btc->ctrl.always_freerun) {
_action_freerun(rtwdev);
@@ -5153,15 +5434,11 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
}
if (wl->status.map.rf_off || wl->status.map.lps || dm->bt_only) {
- _action_wl_off(rtwdev);
+ _action_wl_off(rtwdev, mode);
btc->ctrl.igno_bt = true;
goto exit;
}
- btc->ctrl.igno_bt = false;
- dm->freerun = false;
- bt->scan_rx_low_pri = false;
-
if (reason == BTC_RSN_NTFY_INIT) {
_action_wl_init(rtwdev);
goto exit;
@@ -5186,12 +5463,14 @@ void _run_coex(struct rtw89_dev *rtwdev, enum btc_reason_and_action reason)
if (mode == BTC_WLINK_NOLINK || mode == BTC_WLINK_2G_STA ||
mode == BTC_WLINK_5G) {
_action_wl_scan(rtwdev);
+ bt->scan_rx_low_pri = false;
goto exit;
}
}
if (wl->status.map.scan) {
_action_wl_scan(rtwdev);
+ bt->scan_rx_low_pri = false;
goto exit;
}
@@ -5308,6 +5587,7 @@ void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode)
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): mode=%d\n", __func__, mode);
+ wl->coex_mode = mode;
dm->cnt_notify[BTC_NCNT_INIT_COEX]++;
dm->wl_only = mode == BTC_MODE_WL ? 1 : 0;
dm->bt_only = mode == BTC_MODE_BT ? 1 : 0;
@@ -5352,6 +5632,10 @@ void rtw89_btc_ntfy_scan_start(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): phy_idx=%d, band=%d\n",
__func__, phy_idx, band);
+
+ if (phy_idx >= RTW89_PHY_MAX)
+ return;
+
btc->dm.cnt_notify[BTC_NCNT_SCAN_START]++;
wl->status.map.scan = true;
wl->scan_info.band[phy_idx] = band;
@@ -5396,6 +5680,10 @@ void rtw89_btc_ntfy_switch_band(struct rtw89_dev *rtwdev, u8 phy_idx, u8 band)
rtw89_debug(rtwdev, RTW89_DBG_BTC,
"[BTC], %s(): phy_idx=%d, band=%d\n",
__func__, phy_idx, band);
+
+ if (phy_idx >= RTW89_PHY_MAX)
+ return;
+
btc->dm.cnt_notify[BTC_NCNT_SWITCH_BAND]++;
wl->scan_info.band[phy_idx] = band;
@@ -5517,6 +5805,37 @@ void rtw89_btc_ntfy_icmp_packet_work(struct work_struct *work)
mutex_unlock(&rtwdev->mutex);
}
+static u8 _update_bt_rssi_level(struct rtw89_dev *rtwdev, u8 rssi)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_btc *btc = &rtwdev->btc;
+ struct rtw89_btc_bt_info *bt = &btc->cx.bt;
+ u8 *rssi_st, rssi_th, rssi_level = 0;
+ u8 i;
+
+ /* for rssi locate in which {40, 36, 31, 28}
+ * if rssi >= 40% (-60dBm) --> rssi_level = 4
+ * if 36% <= rssi < 40% --> rssi_level = 3
+ * if 31% <= rssi < 36% --> rssi_level = 2
+ * if 28% <= rssi < 31% --> rssi_level = 1
+ * if rssi < 28% --> rssi_level = 0
+ */
+
+ /* check if rssi across bt_rssi_thres boundary */
+ for (i = 0; i < BTC_BT_RSSI_THMAX; i++) {
+ rssi_th = chip->bt_rssi_thres[i];
+ rssi_st = &bt->link_info.rssi_state[i];
+
+ *rssi_st = _update_rssi_state(rtwdev, *rssi_st, rssi, rssi_th);
+
+ if (BTC_RSSI_HIGH(*rssi_st)) {
+ rssi_level = BTC_BT_RSSI_THMAX - i;
+ break;
+ }
+ }
+ return rssi_level;
+}
+
#define BT_PROFILE_PROTOCOL_MASK GENMASK(7, 4)
static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
@@ -5592,7 +5911,8 @@ static void _update_bt_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len)
btinfo.val = bt->raw_info[BTC_BTINFO_H0];
/* raw val is dBm unit, translate from -100~ 0dBm to 0~100%*/
b->rssi = chip->ops->btc_get_bt_rssi(rtwdev, btinfo.hb0.rssi);
- btc->dm.trx_info.bt_rssi = b->rssi;
+ bt->rssi_level = _update_bt_rssi_level(rtwdev, b->rssi);
+ btc->dm.trx_info.bt_rssi = bt->rssi_level;
/* parse raw info high-Byte1 */
btinfo.val = bt->raw_info[BTC_BTINFO_H1];
@@ -5796,22 +6116,22 @@ void rtw89_btc_ntfy_radio_state(struct rtw89_dev *rtwdev, enum btc_rfctrl rf_sta
chip->ops->btc_init_cfg(rtwdev);
} else {
rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_ALL, false);
- if (rf_state == BTC_RFCTRL_WL_OFF)
+ if (rf_state == BTC_RFCTRL_FW_CTRL)
+ _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
+ else if (rf_state == BTC_RFCTRL_WL_OFF)
_write_scbd(rtwdev, BTC_WSCB_ALL, false);
- else if (rf_state == BTC_RFCTRL_LPS_WL_ON &&
- wl->status.map.lps_pre != BTC_LPS_OFF)
+ else
+ _write_scbd(rtwdev, BTC_WSCB_ACTIVE, false);
+
+ if (rf_state == BTC_RFCTRL_LPS_WL_ON &&
+ wl->status.map.lps_pre != BTC_LPS_OFF)
_update_bt_scbd(rtwdev, true);
}
btc->dm.cnt_dm[BTC_DCNT_BTCNT_HANG] = 0;
- if (wl->status.map.lps_pre == BTC_LPS_OFF &&
- wl->status.map.lps_pre != wl->status.map.lps)
- btc->dm.tdma_instant_excute = 1;
- else
- btc->dm.tdma_instant_excute = 0;
+ btc->dm.tdma_instant_excute = 1;
_run_coex(rtwdev, BTC_RSN_NTFY_RADIO_STATE);
- btc->dm.tdma_instant_excute = 0;
wl->status.map.rf_off_pre = wl->status.map.rf_off;
wl->status.map.lps_pre = wl->status.map.lps;
}
@@ -6050,6 +6370,13 @@ static void rtw89_btc_ntfy_wl_sta_iter(void *data, struct ieee80211_sta *sta)
dm->trx_info.tx_tp = link_info_t->tx_throughput;
dm->trx_info.rx_tp = link_info_t->rx_throughput;
+ /* Trigger coex-run if 0x10980 reg-value is diff with coex setup */
+ if ((dm->wl_btg_rx_rb != dm->wl_btg_rx &&
+ dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) ||
+ (dm->wl_pre_agc_rb != dm->wl_pre_agc &&
+ dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND))
+ iter_data->is_sta_change = true;
+
if (is_sta_change)
iter_data->is_sta_change = true;
@@ -6435,8 +6762,9 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
bt_linfo->pan_desc.active ? "Y" : "N");
seq_printf(m,
- " %-15s : rssi:%ddBm, tx_rate:%dM, %s%s%s",
+ " %-15s : rssi:%ddBm(lvl:%d), tx_rate:%dM, %s%s%s",
"[link]", bt_linfo->rssi - 100,
+ bt->rssi_level,
bt_linfo->tx_3m ? 3 : 2,
bt_linfo->status.map.inq_pag ? " inq-page!!" : "",
bt_linfo->status.map.acl_busy ? " acl_busy!!" : "",
@@ -6545,6 +6873,8 @@ static void _show_bt_info(struct rtw89_dev *rtwdev, struct seq_file *m)
case BTC_CXP_ ## e | BTC_POLICY_EXT_BIT: return #e
#define CASE_BTC_SLOT_STR(e) case CXST_ ## e: return #e
#define CASE_BTC_EVT_STR(e) case CXEVNT_## e: return #e
+#define CASE_BTC_INIT(e) case BTC_MODE_## e: return #e
+#define CASE_BTC_ANTPATH_STR(e) case BTC_ANT_##e: return #e
static const char *steps_to_str(u16 step)
{
@@ -6625,8 +6955,9 @@ static const char *steps_to_str(u16 step)
CASE_BTC_POLICY_STR(FIX_TD3060);
CASE_BTC_POLICY_STR(FIX_TD2080);
CASE_BTC_POLICY_STR(FIX_TDW1B1);
- CASE_BTC_POLICY_STR(FIX_TD4020);
CASE_BTC_POLICY_STR(FIX_TD4010ISO);
+ CASE_BTC_POLICY_STR(FIX_TD4010ISO_DL);
+ CASE_BTC_POLICY_STR(FIX_TD4010ISO_UL);
CASE_BTC_POLICY_STR(PFIX_TD3030);
CASE_BTC_POLICY_STR(PFIX_TD5050);
CASE_BTC_POLICY_STR(PFIX_TD2030);
@@ -6719,6 +7050,37 @@ static const char *id_to_evt(u32 id)
}
}
+static const char *id_to_mode(u8 id)
+{
+ switch (id) {
+ CASE_BTC_INIT(NORMAL);
+ CASE_BTC_INIT(WL);
+ CASE_BTC_INIT(BT);
+ CASE_BTC_INIT(WLOFF);
+ default:
+ return "unknown";
+ }
+}
+
+static const char *id_to_ant(u32 id)
+{
+ switch (id) {
+ CASE_BTC_ANTPATH_STR(WPOWERON);
+ CASE_BTC_ANTPATH_STR(WINIT);
+ CASE_BTC_ANTPATH_STR(WONLY);
+ CASE_BTC_ANTPATH_STR(WOFF);
+ CASE_BTC_ANTPATH_STR(W2G);
+ CASE_BTC_ANTPATH_STR(W5G);
+ CASE_BTC_ANTPATH_STR(W25G);
+ CASE_BTC_ANTPATH_STR(FREERUN);
+ CASE_BTC_ANTPATH_STR(WRFK);
+ CASE_BTC_ANTPATH_STR(BRFK);
+ CASE_BTC_ANTPATH_STR(MAX);
+ default:
+ return "unknown";
+ }
+}
+
static
void seq_print_segment(struct seq_file *m, const char *prefix, u16 *data,
u8 len, u8 seg_len, u8 start_idx, u8 ring_len)
@@ -6773,12 +7135,13 @@ static void _show_dm_info(struct rtw89_dev *rtwdev, struct seq_file *m)
(btc->ctrl.manual ? "(Manual)" : "(Auto)"));
seq_printf(m,
- " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%ld, run_cnt:%d\n",
+ " %-15s : type:%s, reason:%s(), action:%s(), ant_path:%s, init_mode:%s, run_cnt:%d\n",
"[status]",
module->ant.type == BTC_ANT_SHARED ? "shared" : "dedicated",
steps_to_str(dm->run_reason),
steps_to_str(dm->run_action | BTC_ACT_EXT_BIT),
- FIELD_GET(GENMASK(7, 0), dm->set_ant_path),
+ id_to_ant(FIELD_GET(GENMASK(7, 0), dm->set_ant_path)),
+ id_to_mode(wl->coex_mode),
dm->cnt_dm[BTC_DCNT_RUN]);
_show_dm_step(rtwdev, m);
@@ -7681,7 +8044,8 @@ static void _get_gnt(struct rtw89_dev *rtwdev, struct rtw89_mac_ax_coex_gnt *gnt
struct rtw89_mac_ax_gnt *gnt;
u32 val, status;
- if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B) {
+ if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
+ chip->chip_id == RTL8851B) {
rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_1, &val);
rtw89_mac_read_lte(rtwdev, R_AX_GNT_VAL, &status);
@@ -7743,27 +8107,25 @@ static void _show_mreg_v1(struct rtw89_dev *rtwdev, struct seq_file *m)
bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
- /* To avoid I/O if WL LPS or power-off */
- if (!wl->status.map.lps && !wl->status.map.rf_off) {
- btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ _get_gnt(rtwdev, &gnt_cfg);
+
+ gnt = gnt_cfg.band[0];
+ seq_printf(m,
+ " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
+ "[gnt_status]",
+ chip->chip_id == RTL8852C ? "HW" :
+ btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
+ gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
+
+ gnt = gnt_cfg.band[1];
+ seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
+ gnt.gnt_wl_sw_en ? "SW" : "HW",
+ gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW",
+ gnt.gnt_bt);
- _get_gnt(rtwdev, &gnt_cfg);
- gnt = gnt_cfg.band[0];
- seq_printf(m,
- " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
- "[gnt_status]",
- chip->chip_id == RTL8852C ? "HW" :
- btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
- gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
-
- gnt = gnt_cfg.band[1];
- seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
- gnt.gnt_wl_sw_en ? "SW" : "HW",
- gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW",
- gnt.gnt_bt);
- }
pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
if (!pcinfo->valid) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
@@ -7847,27 +8209,25 @@ static void _show_mreg_v2(struct rtw89_dev *rtwdev, struct seq_file *m)
bt->scbd, cx->cnt_bt[BTC_BCNT_SCBDREAD],
cx->cnt_bt[BTC_BCNT_SCBDUPDATE]);
- /* To avoid I/O if WL LPS or power-off */
- if (!wl->status.map.lps && !wl->status.map.rf_off) {
- btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ btc->dm.pta_owner = rtw89_mac_get_ctrl_path(rtwdev);
+ _get_gnt(rtwdev, &gnt_cfg);
+
+ gnt = gnt_cfg.band[0];
+ seq_printf(m,
+ " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
+ "[gnt_status]",
+ chip->chip_id == RTL8852C ? "HW" :
+ btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
+ gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
+
+ gnt = gnt_cfg.band[1];
+ seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
+ gnt.gnt_wl_sw_en ? "SW" : "HW",
+ gnt.gnt_wl,
+ gnt.gnt_bt_sw_en ? "SW" : "HW",
+ gnt.gnt_bt);
- _get_gnt(rtwdev, &gnt_cfg);
- gnt = gnt_cfg.band[0];
- seq_printf(m,
- " %-15s : pta_owner:%s, phy-0[gnt_wl:%s-%d/gnt_bt:%s-%d], ",
- "[gnt_status]",
- chip->chip_id == RTL8852C ? "HW" :
- btc->dm.pta_owner == BTC_CTRL_BY_WL ? "WL" : "BT",
- gnt.gnt_wl_sw_en ? "SW" : "HW", gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW", gnt.gnt_bt);
-
- gnt = gnt_cfg.band[1];
- seq_printf(m, "phy-1[gnt_wl:%s-%d/gnt_bt:%s-%d]\n",
- gnt.gnt_wl_sw_en ? "SW" : "HW",
- gnt.gnt_wl,
- gnt.gnt_bt_sw_en ? "SW" : "HW",
- gnt.gnt_bt);
- }
pcinfo = &pfwinfo->rpt_fbtc_mregval.cinfo;
if (!pcinfo->valid) {
rtw89_debug(rtwdev, RTW89_DBG_BTC,
diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h
index e76153709793..46e25c6f88a6 100644
--- a/drivers/net/wireless/realtek/rtw89/coex.h
+++ b/drivers/net/wireless/realtek/rtw89/coex.h
@@ -142,6 +142,44 @@ enum btc_lps_state {
BTC_LPS_RF_ON = 2
};
+#define R_BTC_BB_BTG_RX 0x980
+#define R_BTC_BB_PRE_AGC_S1 0x476C
+#define R_BTC_BB_PRE_AGC_S0 0x4688
+
+#define B_BTC_BB_GNT_MUX GENMASK(20, 17)
+#define B_BTC_BB_PRE_AGC_MASK GENMASK(31, 24)
+#define B_BTC_BB_PRE_AGC_VAL BIT(31)
+
+#define BTC_REG_NOTFOUND 0xff
+
+enum btc_ant_div_pos {
+ BTC_ANT_DIV_MAIN = 0,
+ BTC_ANT_DIV_AUX = 1,
+};
+
+enum btc_get_reg_status {
+ BTC_CSTATUS_TXDIV_POS = 0,
+ BTC_CSTATUS_RXDIV_POS = 1,
+ BTC_CSTATUS_BB_GNT_MUX = 2,
+ BTC_CSTATUS_BB_GNT_MUX_MON = 3,
+ BTC_CSTATUS_BB_PRE_AGC = 4,
+ BTC_CSTATUS_BB_PRE_AGC_MON = 5,
+};
+
+enum btc_preagc_type {
+ BTC_PREAGC_DISABLE,
+ BTC_PREAGC_ENABLE,
+ BTC_PREAGC_BB_FWCTRL,
+ BTC_PREAGC_NOTFOUND,
+};
+
+enum btc_btgctrl_type {
+ BTC_BTGCTRL_DISABLE,
+ BTC_BTGCTRL_ENABLE,
+ BTC_BTGCTRL_BB_GNT_FWCTRL,
+ BTC_BTGCTRL_BB_GNT_NOTFOUND,
+};
+
void rtw89_btc_ntfy_poweron(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_poweroff(struct rtw89_dev *rtwdev);
void rtw89_btc_ntfy_init(struct rtw89_dev *rtwdev, u8 mode);
diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c
index 3d75165e48be..fd527a249996 100644
--- a/drivers/net/wireless/realtek/rtw89/core.c
+++ b/drivers/net/wireless/realtek/rtw89/core.c
@@ -1407,29 +1407,65 @@ static int rtw89_core_rx_process_mac_ppdu(struct rtw89_dev *rtwdev,
struct sk_buff *skb,
struct rtw89_rx_phy_ppdu *phy_ppdu)
{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_rxinfo *rxinfo = (const struct rtw89_rxinfo *)skb->data;
+ const struct rtw89_rxinfo_user *user;
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+ int rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE;
bool rx_cnt_valid = false;
+ bool invalid = false;
u8 plcp_size = 0;
- u8 usr_num = 0;
u8 *phy_sts;
+ u8 usr_num;
+ int i;
+
+ if (chip_gen == RTW89_CHIP_BE) {
+ invalid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_INVALID_V1);
+ rx_cnt_size = RTW89_PPDU_MAC_RX_CNT_SIZE_V1;
+ }
+
+ if (invalid)
+ return -EINVAL;
rx_cnt_valid = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_RX_CNT_VLD);
- plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3;
- usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM);
- if (usr_num > RTW89_PPDU_MAX_USR) {
- rtw89_warn(rtwdev, "Invalid user number in mac info\n");
+ if (chip_gen == RTW89_CHIP_BE) {
+ plcp_size = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_PLCP_LEN_V1) << 3;
+ usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM_V1);
+ } else {
+ plcp_size = le32_get_bits(rxinfo->w1, RTW89_RXINFO_W1_PLCP_LEN) << 3;
+ usr_num = le32_get_bits(rxinfo->w0, RTW89_RXINFO_W0_USR_NUM);
+ }
+ if (usr_num > chip->ppdu_max_usr) {
+ rtw89_warn(rtwdev, "Invalid user number (%d) in mac info\n",
+ usr_num);
return -EINVAL;
}
+ /* For WiFi 7 chips, RXWD.mac_id of PPDU status is not set by hardware,
+ * so update mac_id by rxinfo_user[].mac_id.
+ */
+ for (i = 0; i < usr_num && chip_gen == RTW89_CHIP_BE; i++) {
+ user = &rxinfo->user[i];
+ if (!le32_get_bits(user->w0, RTW89_RXINFO_USER_MAC_ID_VALID))
+ continue;
+
+ phy_ppdu->mac_id =
+ le32_get_bits(user->w0, RTW89_RXINFO_USER_MACID);
+ break;
+ }
+
phy_sts = skb->data + RTW89_PPDU_MAC_INFO_SIZE;
phy_sts += usr_num * RTW89_PPDU_MAC_INFO_USR_SIZE;
/* 8-byte alignment */
if (usr_num & BIT(0))
phy_sts += RTW89_PPDU_MAC_INFO_USR_SIZE;
if (rx_cnt_valid)
- phy_sts += RTW89_PPDU_MAC_RX_CNT_SIZE;
+ phy_sts += rx_cnt_size;
phy_sts += plcp_size;
+ if (phy_sts > skb->data + skb->len)
+ return -EINVAL;
+
phy_ppdu->buf = phy_sts;
phy_ppdu->len = skb->data + skb->len - phy_sts;
@@ -1477,14 +1513,24 @@ static void rtw89_core_rx_process_phy_ppdu_iter(void *data,
static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev,
const struct rtw89_phy_sts_iehdr *iehdr)
{
- static const u8 physts_ie_len_tab[32] = {
- 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
- VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
- VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
+ static const u8 physts_ie_len_tabs[RTW89_CHIP_GEN_NUM][32] = {
+ [RTW89_CHIP_AX] = {
+ 16, 32, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
+ VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
+ VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
+ },
+ [RTW89_CHIP_BE] = {
+ 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN,
+ VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN,
+ VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32
+ },
};
+ const u8 *physts_ie_len_tab;
u16 ie_len;
u8 ie;
+ physts_ie_len_tab = physts_ie_len_tabs[rtwdev->chip->chip_gen];
+
ie = le32_get_bits(iehdr->w0, RTW89_PHY_STS_IEHDR_TYPE);
if (physts_ie_len_tab[ie] != VAR_LEN)
ie_len = physts_ie_len_tab[ie];
@@ -1563,9 +1609,17 @@ static int rtw89_core_rx_process_phy_ppdu(struct rtw89_dev *rtwdev,
{
const struct rtw89_phy_sts_hdr *hdr = phy_ppdu->buf;
u32 len_from_header;
+ bool physts_valid;
+
+ physts_valid = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_VALID);
+ if (!physts_valid)
+ return -EINVAL;
len_from_header = le32_get_bits(hdr->w0, RTW89_PHY_STS_HDR_W0_LEN) << 3;
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ len_from_header += PHY_STS_HDR_LEN;
+
if (len_from_header != phy_ppdu->len) {
rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "phy ppdu len mismatch\n");
return -EINVAL;
@@ -2052,13 +2106,19 @@ static void rtw89_core_rx_process_ppdu_sts(struct rtw89_dev *rtwdev,
.mac_id = desc_info->mac_id};
int ret;
- if (desc_info->mac_info_valid)
- rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu);
+ if (desc_info->mac_info_valid) {
+ ret = rtw89_core_rx_process_mac_ppdu(rtwdev, skb, &phy_ppdu);
+ if (ret)
+ goto out;
+ }
+
ret = rtw89_core_rx_process_phy_ppdu(rtwdev, &phy_ppdu);
if (ret)
- rtw89_debug(rtwdev, RTW89_DBG_TXRX, "process ppdu failed\n");
+ goto out;
rtw89_core_rx_process_phy_sts(rtwdev, &phy_ppdu);
+
+out:
rtw89_core_rx_pending_skb(rtwdev, &phy_ppdu, desc_info, skb);
dev_kfree_skb_any(skb);
}
@@ -2823,9 +2883,6 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
lockdep_assert_held(&rtwdev->mutex);
- ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work,
- msecs_to_jiffies(rtwvif->roc.duration));
-
rtw89_leave_ips_by_hwflags(rtwdev);
rtw89_leave_lps(rtwdev);
rtw89_chanctx_pause(rtwdev, RTW89_CHANCTX_PAUSE_REASON_ROC);
@@ -2847,6 +2904,9 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
B_AX_A_UC_CAM_MATCH | B_AX_A_BC_CAM_MATCH);
ieee80211_ready_on_channel(hw);
+ cancel_delayed_work(&rtwvif->roc.roc_work);
+ ieee80211_queue_delayed_work(hw, &rtwvif->roc.roc_work,
+ msecs_to_jiffies(rtwvif->roc.duration));
}
void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
@@ -2886,7 +2946,7 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
if (hw->conf.flags & IEEE80211_CONF_IDLE)
ieee80211_queue_delayed_work(hw, &roc->roc_work,
- RTW89_ROC_IDLE_TIMEOUT);
+ msecs_to_jiffies(RTW89_ROC_IDLE_TIMEOUT));
}
void rtw89_roc_work(struct work_struct *work)
@@ -3069,6 +3129,7 @@ static void rtw89_track_work(struct work_struct *work)
rtw89_phy_tx_path_div_track(rtwdev);
rtw89_phy_antdiv_track(rtwdev);
rtw89_phy_ul_tb_ctrl_track(rtwdev);
+ rtw89_phy_edcca_track(rtwdev);
rtw89_tas_track(rtwdev);
rtw89_chanctx_track(rtwdev);
@@ -3895,10 +3956,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev)
/* efuse process */
/* pre-config BB/RF, BB reset/RFC reset */
- ret = rtw89_chip_disable_bb_rf(rtwdev);
- if (ret)
- return ret;
- ret = rtw89_chip_enable_bb_rf(rtwdev);
+ ret = rtw89_chip_reset_bb_rf(rtwdev);
if (ret)
return ret;
@@ -4156,17 +4214,18 @@ out:
static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
int ret;
ret = rtw89_mac_partial_init(rtwdev, false);
if (ret)
return ret;
- ret = rtw89_parse_efuse_map(rtwdev);
+ ret = mac->parse_efuse_map(rtwdev);
if (ret)
return ret;
- ret = rtw89_parse_phycap_map(rtwdev);
+ ret = mac->parse_phycap_map(rtwdev);
if (ret)
return ret;
@@ -4176,6 +4235,8 @@ static int rtw89_chip_efuse_info_setup(struct rtw89_dev *rtwdev)
rtw89_core_setup_phycap(rtwdev);
+ rtw89_hci_mac_pre_deinit(rtwdev);
+
rtw89_mac_pwr_off(rtwdev);
return 0;
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h
index 91e4d4e79eea..ea6df859ba15 100644
--- a/drivers/net/wireless/realtek/rtw89/core.h
+++ b/drivers/net/wireless/realtek/rtw89/core.h
@@ -16,6 +16,9 @@ struct rtw89_dev;
struct rtw89_pci_info;
struct rtw89_mac_gen_def;
struct rtw89_phy_gen_def;
+struct rtw89_efuse_block_cfg;
+struct rtw89_fw_txpwr_track_cfg;
+struct rtw89_phy_rfk_log_fmt;
extern const struct ieee80211_ops rtw89_ops;
@@ -37,6 +40,8 @@ extern const struct ieee80211_ops rtw89_ops;
#define RSSI_FACTOR 1
#define RTW89_RSSI_RAW_TO_DBM(rssi) ((s8)((rssi) >> RSSI_FACTOR) - MAX_RSSI)
#define RTW89_TX_DIV_RSSI_RAW_TH (2 << RSSI_FACTOR)
+#define DELTA_SWINGIDX_SIZE 30
+
#define RTW89_RADIOTAP_ROOM_HE sizeof(struct ieee80211_radiotap_he)
#define RTW89_RADIOTAP_ROOM_EHT \
(sizeof(struct ieee80211_radiotap_tlv) + \
@@ -103,6 +108,14 @@ enum rtw89_gain_offset {
RTW89_GAIN_OFFSET_5G_LOW,
RTW89_GAIN_OFFSET_5G_MID,
RTW89_GAIN_OFFSET_5G_HIGH,
+ RTW89_GAIN_OFFSET_6G_L0,
+ RTW89_GAIN_OFFSET_6G_L1,
+ RTW89_GAIN_OFFSET_6G_M0,
+ RTW89_GAIN_OFFSET_6G_M1,
+ RTW89_GAIN_OFFSET_6G_H0,
+ RTW89_GAIN_OFFSET_6G_H1,
+ RTW89_GAIN_OFFSET_6G_UH0,
+ RTW89_GAIN_OFFSET_6G_UH1,
RTW89_GAIN_OFFSET_NR,
};
@@ -1693,6 +1706,7 @@ struct rtw89_btc_wl_info {
u8 port_id[RTW89_WIFI_ROLE_MLME_MAX];
u8 rssi_level;
u8 cn_report;
+ u8 coex_mode;
bool scbd_change;
u32 scbd;
@@ -1800,6 +1814,7 @@ struct rtw89_btc_bt_info {
union rtw89_btc_bt_rfk_info_map rfk_info;
u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */
+ u8 rssi_level;
u32 scbd;
u32 feature;
@@ -1816,7 +1831,8 @@ struct rtw89_btc_bt_info {
u32 hi_lna_rx: 1;
u32 scan_rx_low_pri: 1;
u32 scan_info_update: 1;
- u32 rsvd: 20;
+ u32 lna_constrain: 3;
+ u32 rsvd: 17;
};
struct rtw89_btc_cx {
@@ -2294,12 +2310,6 @@ struct rtw89_btc_fbtc_fddt_cell_status {
u8 state_phase; /* [0:3] train state, [4:7] train phase */
} __packed;
-struct rtw89_btc_fbtc_fddt_cell_status_v5 {
- s8 wl_tx_pwr;
- s8 bt_tx_pwr;
- s8 bt_rx_gain;
-} __packed;
-
struct rtw89_btc_fbtc_cysta_v3 { /* statistics for cycles */
u8 fver;
u8 rsvd;
@@ -2363,9 +2373,9 @@ struct rtw89_btc_fbtc_cysta_v5 { /* statistics for cycles */
struct rtw89_btc_fbtc_cycle_a2dp_empty_info a2dp_ept;
struct rtw89_btc_fbtc_a2dp_trx_stat_v4 a2dp_trx[BTC_CYCLE_SLOT_MAX];
struct rtw89_btc_fbtc_cycle_fddt_info_v5 fddt_trx[BTC_CYCLE_SLOT_MAX];
- struct rtw89_btc_fbtc_fddt_cell_status_v5 fddt_cells[FDD_TRAIN_WL_DIRECTION]
- [FDD_TRAIN_WL_RSSI_LEVEL]
- [FDD_TRAIN_BT_RSSI_LEVEL];
+ struct rtw89_btc_fbtc_fddt_cell_status fddt_cells[FDD_TRAIN_WL_DIRECTION]
+ [FDD_TRAIN_WL_RSSI_LEVEL]
+ [FDD_TRAIN_BT_RSSI_LEVEL];
__le32 except_map;
} __packed;
@@ -2498,18 +2508,22 @@ struct rtw89_btc_dm {
u32 noisy_level: 3;
u32 coex_info_map: 8;
u32 bt_only: 1;
- u32 wl_btg_rx: 1;
+ u32 wl_btg_rx: 2;
u32 trx_para_level: 8;
u32 wl_stb_chg: 1;
u32 pta_owner: 1;
+
u32 tdma_instant_excute: 1;
+ u32 wl_btg_rx_rb: 2;
u16 slot_dur[CXST_MAX];
u8 run_reason;
u8 run_action;
+ u8 wl_pre_agc: 2;
u8 wl_lna2: 1;
+ u8 wl_pre_agc_rb: 2;
};
struct rtw89_btc_ctrl {
@@ -2777,6 +2791,20 @@ enum rtw89_rx_frame_type {
RTW89_RX_TYPE_RSVD = 3,
};
+enum rtw89_efuse_block {
+ RTW89_EFUSE_BLOCK_SYS = 0,
+ RTW89_EFUSE_BLOCK_RF = 1,
+ RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO = 2,
+ RTW89_EFUSE_BLOCK_HCI_DIG_USB = 3,
+ RTW89_EFUSE_BLOCK_HCI_PHY_PCIE = 4,
+ RTW89_EFUSE_BLOCK_HCI_PHY_USB3 = 5,
+ RTW89_EFUSE_BLOCK_HCI_PHY_USB2 = 6,
+ RTW89_EFUSE_BLOCK_ADIE = 7,
+
+ RTW89_EFUSE_BLOCK_NUM,
+ RTW89_EFUSE_BLOCK_IGNORE,
+};
+
struct rtw89_ra_info {
u8 is_dis_ra:1;
/* Bit0 : CCK
@@ -2815,10 +2843,10 @@ struct rtw89_ra_info {
u8 csi_bw:3;
};
-#define RTW89_PPDU_MAX_USR 4
#define RTW89_PPDU_MAC_INFO_USR_SIZE 4
#define RTW89_PPDU_MAC_INFO_SIZE 8
#define RTW89_PPDU_MAC_RX_CNT_SIZE 96
+#define RTW89_PPDU_MAC_RX_CNT_SIZE_V1 128
#define RTW89_MAX_RX_AGG_NUM 64
#define RTW89_MAX_TX_AGG_NUM 128
@@ -3064,6 +3092,7 @@ struct rtw89_hci_ops {
void (*write32)(struct rtw89_dev *rtwdev, u32 addr, u32 data);
int (*mac_pre_init)(struct rtw89_dev *rtwdev);
+ int (*mac_pre_deinit)(struct rtw89_dev *rtwdev);
int (*mac_post_init)(struct rtw89_dev *rtwdev);
int (*deinit)(struct rtw89_dev *rtwdev);
@@ -3118,7 +3147,8 @@ struct rtw89_chip_ops {
const struct rtw89_chan *chan,
enum rtw89_mac_idx mac_idx,
enum rtw89_phy_idx phy_idx);
- int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map);
+ int (*read_efuse)(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block);
int (*read_phycap)(struct rtw89_dev *rtwdev, u8 *phycap_map);
void (*fem_setup)(struct rtw89_dev *rtwdev);
void (*rfe_gpio)(struct rtw89_dev *rtwdev);
@@ -3267,6 +3297,8 @@ struct rtw89_dle_size {
u16 pge_size;
u16 lnk_pge_num;
u16 unlnk_pge_num;
+ /* for WiFi 7 chips below */
+ u32 srt_ofst;
};
struct rtw89_wde_quota {
@@ -3289,6 +3321,26 @@ struct rtw89_ple_quota {
u16 wd_rel;
u16 cpu_io;
u16 tx_rpt;
+ /* for WiFi 7 chips below */
+ u16 h2d;
+};
+
+struct rtw89_rsvd_quota {
+ u16 mpdu_info_tbl;
+ u16 b0_csi;
+ u16 b1_csi;
+ u16 b0_lmr;
+ u16 b1_lmr;
+ u16 b0_ftm;
+ u16 b1_ftm;
+ u16 b0_smr;
+ u16 b1_smr;
+ u16 others;
+};
+
+struct rtw89_dle_rsvd_size {
+ u32 srt_ofst;
+ u32 size;
};
struct rtw89_dle_mem {
@@ -3299,6 +3351,10 @@ struct rtw89_dle_mem {
const struct rtw89_wde_quota *wde_max_qt;
const struct rtw89_ple_quota *ple_min_qt;
const struct rtw89_ple_quota *ple_max_qt;
+ /* for WiFi 7 chips below */
+ const struct rtw89_rsvd_quota *rsvd_qt;
+ const struct rtw89_dle_rsvd_size *rsvd0_size;
+ const struct rtw89_dle_rsvd_size *rsvd1_size;
};
struct rtw89_reg_def {
@@ -3325,6 +3381,12 @@ struct rtw89_reg5_def {
u32 data;
};
+struct rtw89_reg_imr {
+ u32 addr;
+ u32 clr;
+ u32 set;
+};
+
struct rtw89_phy_table {
const struct rtw89_reg2_def *regs;
u32 n_regs;
@@ -3534,6 +3596,11 @@ struct rtw89_imr_info {
u32 tmac_imr_set;
};
+struct rtw89_imr_table {
+ const struct rtw89_reg_imr *regs;
+ u32 n_regs;
+};
+
struct rtw89_xtal_info {
u32 xcap_reg;
u32 sc_xo_mask;
@@ -3565,6 +3632,22 @@ struct rtw89_dig_regs {
struct rtw89_reg_def p1_s20_pagcugc_en;
};
+struct rtw89_edcca_regs {
+ u32 edcca_level;
+ u32 edcca_mask;
+ u32 edcca_p_mask;
+ u32 ppdu_level;
+ u32 ppdu_mask;
+ u32 rpt_a;
+ u32 rpt_b;
+ u32 rpt_sel;
+ u32 rpt_sel_mask;
+ u32 rpt_sel_be;
+ u32 rpt_sel_be_mask;
+ u32 tx_collision_t2r_st;
+ u32 tx_collision_t2r_st_mask;
+};
+
struct rtw89_phy_ul_tb_info {
bool dyn_tb_tri_en;
u8 def_if_bandedge;
@@ -3625,8 +3708,8 @@ struct rtw89_chip_info {
u32 rsvd_ple_ofst;
const struct rtw89_hfc_param_ini *hfc_param_ini;
const struct rtw89_dle_mem *dle_mem;
- u8 wde_qempty_acq_num;
- u8 wde_qempty_mgq_sel;
+ u8 wde_qempty_acq_grpnum;
+ u8 wde_qempty_mgq_grpsel;
u32 rf_base_addr[2];
u8 support_chanctx_num;
u8 support_bands;
@@ -3644,6 +3727,7 @@ struct rtw89_chip_info {
u8 bacam_num;
u8 bacam_dynamic_num;
enum rtw89_bacam_ver bacam_ver;
+ u8 ppdu_max_usr;
u8 sec_ctrl_efuse_size;
u32 physical_efuse_size;
@@ -3653,6 +3737,7 @@ struct rtw89_chip_info {
u32 dav_log_efuse_size;
u32 phycap_addr;
u32 phycap_size;
+ const struct rtw89_efuse_block_cfg *efuse_blocks;
const struct rtw89_pwr_cfg * const *pwr_on_seq;
const struct rtw89_pwr_cfg * const *pwr_off_seq;
@@ -3710,11 +3795,13 @@ struct rtw89_chip_info {
const struct rtw89_reg_def *dcfo_comp;
u8 dcfo_comp_sft;
const struct rtw89_imr_info *imr_info;
+ const struct rtw89_imr_table *imr_dmac_table;
+ const struct rtw89_imr_table *imr_cmac_table;
const struct rtw89_rrsr_cfgs *rrsr_cfgs;
struct rtw89_reg_def bss_clr_vld;
u32 bss_clr_map_reg;
u32 dma_ch_mask;
- u32 edcca_lvl_reg;
+ const struct rtw89_edcca_regs *edcca_regs;
const struct wiphy_wowlan_support *wowlan_stub;
const struct rtw89_xtal_info *xtal_info;
};
@@ -3738,8 +3825,10 @@ enum rtw89_hcifc_mode {
};
struct rtw89_dle_info {
+ const struct rtw89_rsvd_quota *rsvd_qt;
enum rtw89_qta_mode qta_mode;
u16 ple_pg_size;
+ u16 ple_free_pg;
u16 c0_rx_qta;
u16 c1_rx_qta;
};
@@ -3864,6 +3953,8 @@ struct rtw89_fw_elm_info {
struct rtw89_phy_table *bb_gain;
struct rtw89_phy_table *rf_radio[RF_PATH_MAX];
struct rtw89_phy_table *rf_nctl;
+ struct rtw89_fw_txpwr_track_cfg *txpwr_trk;
+ struct rtw89_phy_rfk_log_fmt *rfk_log_fmt;
};
struct rtw89_fw_info {
@@ -3983,6 +4074,17 @@ struct rtw89_sub_entity {
struct rtw89_chanctx_cfg *cfg;
};
+struct rtw89_edcca_bak {
+ u8 a;
+ u8 p;
+ u8 ppdu;
+ u8 th_old;
+};
+
+enum rtw89_dm_type {
+ RTW89_DM_DYNAMIC_EDCCA,
+};
+
struct rtw89_hal {
u32 rx_fltr;
u8 cv;
@@ -4007,7 +4109,8 @@ struct rtw89_hal {
bool entity_pause;
enum rtw89_entity_mode entity_mode;
- u32 edcca_bak;
+ struct rtw89_edcca_bak edcca_bak;
+ u32 disabled_dm_bitmap; /* bitmap of enum rtw89_dm_type */
};
#define RTW89_MAX_MAC_ID_NUM 128
@@ -4015,6 +4118,9 @@ struct rtw89_hal {
enum rtw89_flags {
RTW89_FLAG_POWERON,
+ RTW89_FLAG_DMAC_FUNC,
+ RTW89_FLAG_CMAC0_FUNC,
+ RTW89_FLAG_CMAC1_FUNC,
RTW89_FLAG_FW_RDY,
RTW89_FLAG_RUNNING,
RTW89_FLAG_BFEE_MON,
@@ -4318,6 +4424,7 @@ struct rtw89_power_trim_info {
bool pg_pa_bias_trim;
u8 thermal_trim[RF_PATH_MAX];
u8 pa_bias_trim[RF_PATH_MAX];
+ u8 pad_bias_trim[RF_PATH_MAX];
};
struct rtw89_regd {
@@ -4325,9 +4432,12 @@ struct rtw89_regd {
u8 txpwr_regd[RTW89_BAND_NUM];
};
+#define RTW89_REGD_MAX_COUNTRY_NUM U8_MAX
+
struct rtw89_regulatory_info {
const struct rtw89_regd *regd;
enum rtw89_reg_6ghz_power reg_6ghz_power;
+ DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
};
enum rtw89_ifs_clm_application {
@@ -4802,6 +4912,11 @@ static inline void rtw89_hci_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch)
return rtwdev->hci.ops->tx_kick_off(rtwdev, txch);
}
+static inline int rtw89_hci_mac_pre_deinit(struct rtw89_dev *rtwdev)
+{
+ return rtwdev->hci.ops->mac_pre_deinit(rtwdev);
+}
+
static inline void rtw89_hci_flush_queues(struct rtw89_dev *rtwdev, u32 queues,
bool drop)
{
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index a3f795d240ea..44829a148185 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -3330,13 +3330,14 @@ out:
static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_cpuio_ctrl ctrl_para = {0};
u16 pkt_id;
int ret;
rtw89_leave_ps_mode(rtwdev);
- ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id);
+ ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id);
if (ret)
return ret;
@@ -3348,7 +3349,7 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS;
ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT;
- if (rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true))
+ if (mac->set_cpuio(rtwdev, &ctrl_para, true))
return -EFAULT;
return 0;
@@ -3770,6 +3771,58 @@ static int rtw89_debug_priv_stations_get(struct seq_file *m, void *v)
return 0;
}
+#define DM_INFO(type) {RTW89_DM_ ## type, #type}
+
+static const struct rtw89_disabled_dm_info {
+ enum rtw89_dm_type type;
+ const char *name;
+} rtw89_disabled_dm_infos[] = {
+ DM_INFO(DYNAMIC_EDCCA),
+};
+
+static int
+rtw89_debug_priv_disable_dm_get(struct seq_file *m, void *v)
+{
+ struct rtw89_debugfs_priv *debugfs_priv = m->private;
+ struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
+ const struct rtw89_disabled_dm_info *info;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 disabled;
+ int i;
+
+ seq_printf(m, "Disabled DM: 0x%x\n", hal->disabled_dm_bitmap);
+
+ for (i = 0; i < ARRAY_SIZE(rtw89_disabled_dm_infos); i++) {
+ info = &rtw89_disabled_dm_infos[i];
+ disabled = BIT(info->type) & hal->disabled_dm_bitmap;
+
+ seq_printf(m, "[%d] %s: %c\n", info->type, info->name,
+ disabled ? 'X' : 'O');
+ }
+
+ return 0;
+}
+
+static ssize_t
+rtw89_debug_priv_disable_dm_set(struct file *filp, const char __user *user_buf,
+ size_t count, loff_t *loff)
+{
+ struct seq_file *m = (struct seq_file *)filp->private_data;
+ struct rtw89_debugfs_priv *debugfs_priv = m->private;
+ struct rtw89_dev *rtwdev = debugfs_priv->rtwdev;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 conf;
+ int ret;
+
+ ret = kstrtou32_from_user(user_buf, count, 0, &conf);
+ if (ret)
+ return -EINVAL;
+
+ hal->disabled_dm_bitmap = conf;
+
+ return count;
+}
+
static struct rtw89_debugfs_priv rtw89_debug_priv_read_reg = {
.cb_read = rtw89_debug_priv_read_reg_get,
.cb_write = rtw89_debug_priv_read_reg_select,
@@ -3845,6 +3898,11 @@ static struct rtw89_debugfs_priv rtw89_debug_priv_stations = {
.cb_read = rtw89_debug_priv_stations_get,
};
+static struct rtw89_debugfs_priv rtw89_debug_priv_disable_dm = {
+ .cb_read = rtw89_debug_priv_disable_dm_get,
+ .cb_write = rtw89_debug_priv_disable_dm_set,
+};
+
#define rtw89_debugfs_add(name, mode, fopname, parent) \
do { \
rtw89_debug_priv_ ##name.rtwdev = rtwdev; \
@@ -3885,13 +3943,13 @@ void rtw89_debugfs_init(struct rtw89_dev *rtwdev)
rtw89_debugfs_add_w(fw_log_manual);
rtw89_debugfs_add_r(phy_info);
rtw89_debugfs_add_r(stations);
+ rtw89_debugfs_add_rw(disable_dm);
}
#endif
#ifdef CONFIG_RTW89_DEBUGMSG
-void __rtw89_debug(struct rtw89_dev *rtwdev,
- enum rtw89_debug_mask mask,
- const char *fmt, ...)
+void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask,
+ const char *fmt, ...)
{
struct va_format vaf = {
.fmt = fmt,
@@ -3907,5 +3965,5 @@ void __rtw89_debug(struct rtw89_dev *rtwdev,
va_end(args);
}
-EXPORT_SYMBOL(__rtw89_debug);
+EXPORT_SYMBOL(rtw89_debug);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h
index 079269bb5251..800ea59873a1 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.h
+++ b/drivers/net/wireless/realtek/rtw89/debug.h
@@ -29,6 +29,8 @@ enum rtw89_debug_mask {
RTW89_DBG_WOW = BIT(18),
RTW89_DBG_UL_TB = BIT(19),
RTW89_DBG_CHAN = BIT(20),
+ RTW89_DBG_ACPI = BIT(21),
+ RTW89_DBG_EDCCA = BIT(22),
RTW89_DBG_UNEXP = BIT(31),
};
@@ -57,12 +59,10 @@ static inline void rtw89_debugfs_init(struct rtw89_dev *rtwdev) {}
#ifdef CONFIG_RTW89_DEBUGMSG
extern unsigned int rtw89_debug_mask;
-#define rtw89_debug(rtwdev, a...) __rtw89_debug(rtwdev, ##a)
__printf(3, 4)
-void __rtw89_debug(struct rtw89_dev *rtwdev,
- enum rtw89_debug_mask mask,
- const char *fmt, ...);
+void rtw89_debug(struct rtw89_dev *rtwdev, enum rtw89_debug_mask mask,
+ const char *fmt, ...);
static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev,
enum rtw89_debug_mask mask,
const char *prefix_str,
@@ -73,6 +73,12 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev,
print_hex_dump_bytes(prefix_str, DUMP_PREFIX_OFFSET, buf, len);
}
+
+static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev,
+ enum rtw89_debug_mask mask)
+{
+ return !!(rtw89_debug_mask & mask);
+}
#else
static inline void rtw89_debug(struct rtw89_dev *rtwdev,
enum rtw89_debug_mask mask,
@@ -81,6 +87,11 @@ static inline void rtw89_hex_dump(struct rtw89_dev *rtwdev,
enum rtw89_debug_mask mask,
const char *prefix_str,
const void *buf, size_t len) {}
+static inline bool rtw89_debug_is_enabled(struct rtw89_dev *rtwdev,
+ enum rtw89_debug_mask mask)
+{
+ return false;
+}
#endif
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/efuse.c b/drivers/net/wireless/realtek/rtw89/efuse.c
index 2aaf4d013e46..e1236079a84a 100644
--- a/drivers/net/wireless/realtek/rtw89/efuse.c
+++ b/drivers/net/wireless/realtek/rtw89/efuse.c
@@ -114,6 +114,11 @@ static int rtw89_dump_physical_efuse_map_ddv(struct rtw89_dev *rtwdev, u8 *map,
return 0;
}
+int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle)
+{
+ return 0;
+}
+
static int rtw89_dump_physical_efuse_map_dav(struct rtw89_dev *rtwdev, u8 *map,
u32 dump_addr, u32 dump_size)
{
@@ -231,7 +236,7 @@ static int rtw89_dump_logical_efuse_map(struct rtw89_dev *rtwdev, u8 *phy_map,
return 0;
}
-int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
+int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev)
{
u32 phy_size = rtwdev->chip->physical_efuse_size;
u32 log_size = rtwdev->chip->logical_efuse_size;
@@ -286,7 +291,7 @@ int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev)
rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, full_log_size);
- ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map);
+ ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, RTW89_EFUSE_BLOCK_IGNORE);
if (ret) {
rtw89_warn(rtwdev, "failed to read efuse map\n");
goto out_free;
@@ -300,7 +305,7 @@ out_free:
return ret;
}
-int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev)
+int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev)
{
u32 phycap_addr = rtwdev->chip->phycap_addr;
u32 phycap_size = rtwdev->chip->phycap_size;
diff --git a/drivers/net/wireless/realtek/rtw89/efuse.h b/drivers/net/wireless/realtek/rtw89/efuse.h
index 79071aff28de..5c6787179bad 100644
--- a/drivers/net/wireless/realtek/rtw89/efuse.h
+++ b/drivers/net/wireless/realtek/rtw89/efuse.h
@@ -7,8 +7,21 @@
#include "core.h"
-int rtw89_parse_efuse_map(struct rtw89_dev *rtwdev);
-int rtw89_parse_phycap_map(struct rtw89_dev *rtwdev);
+#define RTW89_EFUSE_BLOCK_ID_MASK GENMASK(31, 16)
+#define RTW89_EFUSE_BLOCK_SIZE_MASK GENMASK(15, 0)
+#define RTW89_EFUSE_MAX_BLOCK_SIZE 0x10000
+
+struct rtw89_efuse_block_cfg {
+ u32 offset;
+ u32 size;
+};
+
+int rtw89_parse_efuse_map_ax(struct rtw89_dev *rtwdev);
+int rtw89_parse_phycap_map_ax(struct rtw89_dev *rtwdev);
+int rtw89_cnv_efuse_state_ax(struct rtw89_dev *rtwdev, bool idle);
+int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev);
+int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev);
+int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle);
int rtw89_read_efuse_ver(struct rtw89_dev *rtwdev, u8 *efv);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/efuse_be.c b/drivers/net/wireless/realtek/rtw89/efuse_be.c
new file mode 100644
index 000000000000..8e8b7cd315f7
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/efuse_be.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#include "debug.h"
+#include "efuse.h"
+#include "mac.h"
+#include "reg.h"
+
+static void rtw89_enable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool aphy_patch = true;
+
+ if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
+ aphy_patch = false;
+
+ rtw89_write8_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+
+ if (aphy_patch) {
+ rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
+ mdelay(1);
+ rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
+ rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
+ }
+
+ rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
+}
+
+static void rtw89_disable_efuse_pwr_cut_ddv_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ bool aphy_patch = true;
+
+ if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
+ aphy_patch = false;
+
+ if (aphy_patch) {
+ rtw89_write16_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
+ rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
+ mdelay(1);
+ rtw89_write16_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
+ }
+
+ rtw89_write8_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+ rtw89_write32_clr(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_EF_BURST);
+}
+
+static int rtw89_dump_physical_efuse_map_ddv_be(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size)
+{
+ u32 efuse_ctl;
+ u32 addr;
+ u32 data;
+ int ret;
+
+ if (!IS_ALIGNED(dump_addr, 4) || !IS_ALIGNED(dump_size, 4)) {
+ rtw89_err(rtwdev, "Efuse addr 0x%x or size 0x%x not aligned\n",
+ dump_addr, dump_size);
+ return -EINVAL;
+ }
+
+ rtw89_enable_efuse_pwr_cut_ddv_be(rtwdev);
+
+ for (addr = dump_addr; addr < dump_addr + dump_size; addr += 4, map += 4) {
+ efuse_ctl = u32_encode_bits(addr, B_BE_EF_ADDR_MASK);
+ rtw89_write32(rtwdev, R_BE_EFUSE_CTRL, efuse_ctl & ~B_BE_EF_RDY);
+
+ ret = read_poll_timeout_atomic(rtw89_read32, efuse_ctl,
+ efuse_ctl & B_BE_EF_RDY, 1, 1000000,
+ true, rtwdev, R_BE_EFUSE_CTRL);
+ if (ret)
+ return -EBUSY;
+
+ data = rtw89_read32(rtwdev, R_BE_EFUSE_CTRL_1_V1);
+ *((__le32 *)map) = cpu_to_le32(data);
+ }
+
+ rtw89_disable_efuse_pwr_cut_ddv_be(rtwdev);
+
+ return 0;
+}
+
+static int rtw89_dump_physical_efuse_map_dav_be(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size)
+{
+ u32 addr;
+ u8 val8;
+ int err;
+ int ret;
+
+ for (addr = dump_addr; addr < dump_addr + dump_size; addr++) {
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0x40,
+ FULL_BIT_MASK);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_LOW_ADDR, addr & 0xff,
+ XTAL_SI_LOW_ADDR_MASK);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, addr >> 8,
+ XTAL_SI_HIGH_ADDR_MASK);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_CTRL, 0,
+ XTAL_SI_MODE_SEL_MASK);
+ if (ret)
+ return ret;
+
+ ret = read_poll_timeout_atomic(rtw89_mac_read_xtal_si, err,
+ !err && (val8 & XTAL_SI_RDY),
+ 1, 10000, false,
+ rtwdev, XTAL_SI_CTRL, &val8);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to read dav efuse\n");
+ return ret;
+ }
+
+ ret = rtw89_mac_read_xtal_si(rtwdev, XTAL_SI_READ_VAL, &val8);
+ if (ret)
+ return ret;
+ *map++ = val8;
+ }
+
+ return 0;
+}
+
+int rtw89_cnv_efuse_state_be(struct rtw89_dev *rtwdev, bool idle)
+{
+ u32 val;
+ int ret = 0;
+
+ if (idle) {
+ rtw89_write32_set(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
+ } else {
+ rtw89_write32_clr(rtwdev, R_BE_WL_BT_PWR_CTRL, B_BE_BT_DISN_EN);
+
+ ret = read_poll_timeout(rtw89_read32_mask, val,
+ val == MAC_AX_SYS_ACT, 50, 5000,
+ false, rtwdev, R_BE_IC_PWR_STATE,
+ B_BE_WHOLE_SYS_PWR_STE_MASK);
+ if (ret)
+ rtw89_warn(rtwdev, "failed to convert efuse state\n");
+ }
+
+ return ret;
+}
+
+static int rtw89_dump_physical_efuse_map_be(struct rtw89_dev *rtwdev, u8 *map,
+ u32 dump_addr, u32 dump_size, bool dav)
+{
+ int ret;
+
+ if (!map || dump_size == 0)
+ return 0;
+
+ rtw89_cnv_efuse_state_be(rtwdev, false);
+
+ if (dav) {
+ ret = rtw89_dump_physical_efuse_map_dav_be(rtwdev, map,
+ dump_addr, dump_size);
+ if (ret)
+ return ret;
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map dav: ", map, dump_size);
+ } else {
+ ret = rtw89_dump_physical_efuse_map_ddv_be(rtwdev, map,
+ dump_addr, dump_size);
+ if (ret)
+ return ret;
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "phy_map ddv: ", map, dump_size);
+ }
+
+ rtw89_cnv_efuse_state_be(rtwdev, true);
+
+ return 0;
+}
+
+#define EFUSE_HDR_CONST_MASK GENMASK(23, 20)
+#define EFUSE_HDR_PAGE_MASK GENMASK(19, 17)
+#define EFUSE_HDR_OFFSET_MASK GENMASK(16, 4)
+#define EFUSE_HDR_OFFSET_DAV_MASK GENMASK(11, 4)
+#define EFUSE_HDR_WORD_EN_MASK GENMASK(3, 0)
+
+#define invalid_efuse_header_be(hdr1, hdr2, hdr3) \
+ ((hdr1) == 0xff || (hdr2) == 0xff || (hdr3) == 0xff)
+#define invalid_efuse_content_be(word_en, i) \
+ (((word_en) & BIT(i)) != 0x0)
+#define get_efuse_blk_idx_be(hdr1, hdr2, hdr3) \
+ (((hdr1) << 16) | ((hdr2) << 8) | (hdr3))
+#define block_idx_to_logical_idx_be(blk_idx, i) \
+ (((blk_idx) << 3) + ((i) << 1))
+
+#define invalid_efuse_header_dav_be(hdr1, hdr2) \
+ ((hdr1) == 0xff || (hdr2) == 0xff)
+#define get_efuse_blk_idx_dav_be(hdr1, hdr2) \
+ (((hdr1) << 8) | (hdr2))
+
+static int rtw89_eeprom_parser_be(struct rtw89_dev *rtwdev,
+ const u8 *phy_map, u32 phy_size, u8 *log_map,
+ const struct rtw89_efuse_block_cfg *efuse_block)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ enum rtw89_efuse_block blk_page, page;
+ u32 size = efuse_block->size;
+ u32 phy_idx, log_idx;
+ u32 hdr, page_offset;
+ u8 hdr1, hdr2, hdr3;
+ u8 i, val0, val1;
+ u32 min, max;
+ u16 blk_idx;
+ u8 word_en;
+
+ page = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_ID_MASK);
+ page_offset = u32_get_bits(efuse_block->offset, RTW89_EFUSE_BLOCK_SIZE_MASK);
+
+ min = ALIGN_DOWN(page_offset, 2);
+ max = ALIGN(page_offset + size, 2);
+
+ memset(log_map, 0xff, size);
+
+ phy_idx = chip->sec_ctrl_efuse_size;
+
+ do {
+ if (page == RTW89_EFUSE_BLOCK_ADIE) {
+ hdr1 = phy_map[phy_idx];
+ hdr2 = phy_map[phy_idx + 1];
+ if (invalid_efuse_header_dav_be(hdr1, hdr2))
+ break;
+
+ phy_idx += 2;
+
+ hdr = get_efuse_blk_idx_dav_be(hdr1, hdr2);
+
+ blk_page = RTW89_EFUSE_BLOCK_ADIE;
+ blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_DAV_MASK);
+ word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
+ } else {
+ hdr1 = phy_map[phy_idx];
+ hdr2 = phy_map[phy_idx + 1];
+ hdr3 = phy_map[phy_idx + 2];
+ if (invalid_efuse_header_be(hdr1, hdr2, hdr3))
+ break;
+
+ phy_idx += 3;
+
+ hdr = get_efuse_blk_idx_be(hdr1, hdr2, hdr3);
+
+ blk_page = u32_get_bits(hdr, EFUSE_HDR_PAGE_MASK);
+ blk_idx = u32_get_bits(hdr, EFUSE_HDR_OFFSET_MASK);
+ word_en = u32_get_bits(hdr, EFUSE_HDR_WORD_EN_MASK);
+ }
+
+ if (blk_idx >= RTW89_EFUSE_MAX_BLOCK_SIZE >> 3) {
+ rtw89_err(rtwdev, "[ERR]efuse idx:0x%X\n", phy_idx - 3);
+ rtw89_err(rtwdev, "[ERR]read hdr:0x%X\n", hdr);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (invalid_efuse_content_be(word_en, i))
+ continue;
+
+ if (phy_idx >= phy_size - 1)
+ return -EINVAL;
+
+ log_idx = block_idx_to_logical_idx_be(blk_idx, i);
+
+ if (blk_page == page && log_idx >= min && log_idx < max) {
+ val0 = phy_map[phy_idx];
+ val1 = phy_map[phy_idx + 1];
+
+ if (log_idx == min && page_offset > min) {
+ log_map[log_idx - page_offset + 1] = val1;
+ } else if (log_idx + 2 == max &&
+ page_offset + size < max) {
+ log_map[log_idx - page_offset] = val0;
+ } else {
+ log_map[log_idx - page_offset] = val0;
+ log_map[log_idx - page_offset + 1] = val1;
+ }
+ }
+ phy_idx += 2;
+ }
+ } while (phy_idx < phy_size);
+
+ return 0;
+}
+
+static int rtw89_parse_logical_efuse_block_be(struct rtw89_dev *rtwdev,
+ const u8 *phy_map, u32 phy_size,
+ enum rtw89_efuse_block block)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_efuse_block_cfg *efuse_block;
+ u8 *log_map;
+ int ret;
+
+ efuse_block = &chip->efuse_blocks[block];
+
+ log_map = kmalloc(efuse_block->size, GFP_KERNEL);
+ if (!log_map)
+ return -ENOMEM;
+
+ ret = rtw89_eeprom_parser_be(rtwdev, phy_map, phy_size, log_map, efuse_block);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump efuse logical block %d\n", block);
+ goto out_free;
+ }
+
+ rtw89_hex_dump(rtwdev, RTW89_DBG_FW, "log_map: ", log_map, efuse_block->size);
+
+ ret = rtwdev->chip->ops->read_efuse(rtwdev, log_map, block);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to read efuse map\n");
+ goto out_free;
+ }
+
+out_free:
+ kfree(log_map);
+
+ return ret;
+}
+
+int rtw89_parse_efuse_map_be(struct rtw89_dev *rtwdev)
+{
+ u32 phy_size = rtwdev->chip->physical_efuse_size;
+ u32 dav_phy_size = rtwdev->chip->dav_phy_efuse_size;
+ enum rtw89_efuse_block block;
+ u8 *phy_map = NULL;
+ u8 *dav_phy_map = NULL;
+ int ret;
+
+ if (rtw89_read16(rtwdev, R_BE_SYS_WL_EFUSE_CTRL) & B_BE_AUTOLOAD_SUS)
+ rtwdev->efuse.valid = true;
+ else
+ rtw89_warn(rtwdev, "failed to check efuse autoload\n");
+
+ phy_map = kmalloc(phy_size, GFP_KERNEL);
+ if (dav_phy_size)
+ dav_phy_map = kmalloc(dav_phy_size, GFP_KERNEL);
+
+ if (!phy_map || (dav_phy_size && !dav_phy_map)) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, phy_map, 0, phy_size, false);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump efuse physical map\n");
+ goto out_free;
+ }
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, dav_phy_map, 0, dav_phy_size, true);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump efuse dav physical map\n");
+ goto out_free;
+ }
+
+ if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
+ block = RTW89_EFUSE_BLOCK_HCI_DIG_USB;
+ else
+ block = RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO;
+
+ ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size, block);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
+ RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO);
+ goto out_free;
+ }
+
+ ret = rtw89_parse_logical_efuse_block_be(rtwdev, phy_map, phy_size,
+ RTW89_EFUSE_BLOCK_RF);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to parse efuse logic block %d\n",
+ RTW89_EFUSE_BLOCK_RF);
+ goto out_free;
+ }
+
+out_free:
+ kfree(dav_phy_map);
+ kfree(phy_map);
+
+ return ret;
+}
+
+int rtw89_parse_phycap_map_be(struct rtw89_dev *rtwdev)
+{
+ u32 phycap_addr = rtwdev->chip->phycap_addr;
+ u32 phycap_size = rtwdev->chip->phycap_size;
+ u8 *phycap_map = NULL;
+ int ret = 0;
+
+ if (!phycap_size)
+ return 0;
+
+ phycap_map = kmalloc(phycap_size, GFP_KERNEL);
+ if (!phycap_map)
+ return -ENOMEM;
+
+ ret = rtw89_dump_physical_efuse_map_be(rtwdev, phycap_map,
+ phycap_addr, phycap_size, false);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to dump phycap map\n");
+ goto out_free;
+ }
+
+ ret = rtwdev->chip->ops->read_phycap(rtwdev, phycap_map);
+ if (ret) {
+ rtw89_warn(rtwdev, "failed to read phycap map\n");
+ goto out_free;
+ }
+
+out_free:
+ kfree(phycap_map);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c
index a732c22a2d54..09684cea9731 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.c
+++ b/drivers/net/wireless/realtek/rtw89/fw.c
@@ -401,10 +401,14 @@ int __rtw89_fw_recognize_from_elm(struct rtw89_dev *rtwdev,
const union rtw89_fw_element_arg arg)
{
enum rtw89_fw_type type = arg.fw_type;
+ struct rtw89_hal *hal = &rtwdev->hal;
struct rtw89_fw_suit *fw_suit;
+ if (hal->cv != elm->u.bbmcu.cv)
+ return 1; /* ignore this element */
+
fw_suit = rtw89_fw_suit_get(rtwdev, type);
- fw_suit->data = elm->u.common.contents;
+ fw_suit->data = elm->u.bbmcu.contents;
fw_suit->size = le32_to_cpu(elm->size);
return rtw89_fw_update_ver(rtwdev, type, fw_suit);
@@ -453,6 +457,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = {
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER),
__CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER),
+ __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER),
};
static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw,
@@ -658,6 +663,97 @@ setup:
return 0;
}
+static
+int rtw89_build_txpwr_trk_tbl_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const union rtw89_fw_element_arg arg)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ u32 needed_bitmap = 0;
+ u32 offset = 0;
+ int subband;
+ u32 bitmap;
+ int type;
+
+ if (chip->support_bands & BIT(NL80211_BAND_6GHZ))
+ needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_6GHZ;
+ if (chip->support_bands & BIT(NL80211_BAND_5GHZ))
+ needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_5GHZ;
+ if (chip->support_bands & BIT(NL80211_BAND_2GHZ))
+ needed_bitmap |= RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_2GHZ;
+
+ bitmap = le32_to_cpu(elm->u.txpwr_trk.bitmap);
+
+ if ((bitmap & needed_bitmap) != needed_bitmap) {
+ rtw89_warn(rtwdev, "needed txpwr trk bitmap %08x but %0x8x\n",
+ needed_bitmap, bitmap);
+ return -ENOENT;
+ }
+
+ elm_info->txpwr_trk = kzalloc(sizeof(*elm_info->txpwr_trk), GFP_KERNEL);
+ if (!elm_info->txpwr_trk)
+ return -ENOMEM;
+
+ for (type = 0; bitmap; type++, bitmap >>= 1) {
+ if (!(bitmap & BIT(0)))
+ continue;
+
+ if (type >= __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_START &&
+ type <= __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_MAX)
+ subband = 4;
+ else if (type >= __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_START &&
+ type <= __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_MAX)
+ subband = 3;
+ else if (type >= __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_START &&
+ type <= __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_MAX)
+ subband = 1;
+ else
+ break;
+
+ elm_info->txpwr_trk->delta[type] = &elm->u.txpwr_trk.contents[offset];
+
+ offset += subband;
+ if (offset * DELTA_SWINGIDX_SIZE > le32_to_cpu(elm->size))
+ goto err;
+ }
+
+ return 0;
+
+err:
+ rtw89_warn(rtwdev, "unexpected txpwr trk offset %d over size %d\n",
+ offset, le32_to_cpu(elm->size));
+ kfree(elm_info->txpwr_trk);
+ elm_info->txpwr_trk = NULL;
+
+ return -EFAULT;
+}
+
+static
+int rtw89_build_rfk_log_fmt_from_elm(struct rtw89_dev *rtwdev,
+ const struct rtw89_fw_element_hdr *elm,
+ const union rtw89_fw_element_arg arg)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ u8 rfk_id;
+
+ if (elm_info->rfk_log_fmt)
+ goto allocated;
+
+ elm_info->rfk_log_fmt = kzalloc(sizeof(*elm_info->rfk_log_fmt), GFP_KERNEL);
+ if (!elm_info->rfk_log_fmt)
+ return 1; /* this is an optional element, so just ignore this */
+
+allocated:
+ rfk_id = elm->u.rfk_log_fmt.rfk_id;
+ if (rfk_id >= RTW89_PHY_C2H_RFK_LOG_FUNC_NUM)
+ return 1;
+
+ elm_info->rfk_log_fmt->elm[rfk_id] = elm;
+
+ return 0;
+}
+
static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
[RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm,
{ .fw_type = RTW89_FW_BBMCU0 }, NULL},
@@ -710,6 +806,12 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = {
rtw89_fw_recognize_txpwr_from_elm,
{ .offset = offsetof(struct rtw89_rfe_data, tx_shape_lmt_ru.conf) }, NULL,
},
+ [RTW89_FW_ELEMENT_ID_TXPWR_TRK] = {
+ rtw89_build_txpwr_trk_tbl_from_elm, {}, "PWR_TRK",
+ },
+ [RTW89_FW_ELEMENT_ID_RFKLOG_FMT] = {
+ rtw89_build_rfk_log_fmt_from_elm, {}, NULL,
+ },
};
int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
@@ -750,6 +852,8 @@ int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev)
goto next;
ret = handler->fn(rtwdev, hdr, handler->arg);
+ if (ret == 1) /* ignore this element */
+ goto next;
if (ret)
return ret;
@@ -956,16 +1060,24 @@ static int rtw89_fw_download_main(struct rtw89_dev *rtwdev,
static void rtw89_fw_prog_cnt_dump(struct rtw89_dev *rtwdev)
{
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+ u32 addr = R_AX_DBG_PORT_SEL;
u32 val32;
u16 index;
+ if (chip_gen == RTW89_CHIP_BE) {
+ addr = R_BE_WLCPU_PORT_PC;
+ goto dump;
+ }
+
rtw89_write32(rtwdev, R_AX_DBG_CTRL,
FIELD_PREP(B_AX_DBG_SEL0, FW_PROG_CNTR_DBG_SEL) |
FIELD_PREP(B_AX_DBG_SEL1, FW_PROG_CNTR_DBG_SEL));
rtw89_write32_mask(rtwdev, R_AX_SYS_STATUS1, B_AX_SEL_0XC0_MASK, MAC_DBG_SEL);
+dump:
for (index = 0; index < 15; index++) {
- val32 = rtw89_read32(rtwdev, R_AX_DBG_PORT_SEL);
+ val32 = rtw89_read32(rtwdev, addr);
rtw89_err(rtwdev, "[ERR]fw PC = 0x%x\n", val32);
fsleep(10);
}
@@ -1135,6 +1247,9 @@ static void rtw89_unload_firmware_elements(struct rtw89_dev *rtwdev)
for (i = 0; i < ARRAY_SIZE(elm_info->rf_radio); i++)
rtw89_free_phy_tbl_from_elm(elm_info->rf_radio[i]);
rtw89_free_phy_tbl_from_elm(elm_info->rf_nctl);
+
+ kfree(elm_info->txpwr_trk);
+ kfree(elm_info->rfk_log_fmt);
}
void rtw89_unload_firmware(struct rtw89_dev *rtwdev)
@@ -2215,6 +2330,41 @@ fail:
return ret;
}
+int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en)
+{
+ struct rtw89_h2c_notify_dbcc *h2c;
+ u32 len = sizeof(*h2c);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len);
+ if (!skb) {
+ rtw89_err(rtwdev, "failed to alloc skb for h2c notify dbcc\n");
+ return -ENOMEM;
+ }
+ skb_put(skb, len);
+ h2c = (struct rtw89_h2c_notify_dbcc *)skb->data;
+
+ h2c->w0 = le32_encode_bits(en, RTW89_H2C_NOTIFY_DBCC_EN);
+
+ rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C,
+ H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT,
+ H2C_FUNC_NOTIFY_DBCC, 0, 1,
+ len);
+
+ ret = rtw89_h2c_tx(rtwdev, skb, false);
+ if (ret) {
+ rtw89_err(rtwdev, "failed to send h2c\n");
+ goto fail;
+ }
+
+ return 0;
+fail:
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp,
bool pause)
{
@@ -3451,6 +3601,8 @@ static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev,
return false;
case RTW89_C2H_CAT_MAC:
return rtw89_mac_c2h_chk_atomic(rtwdev, class, func);
+ case RTW89_C2H_CAT_OUTSRC:
+ return rtw89_phy_c2h_chk_atomic(rtwdev, class, func);
}
}
@@ -3867,6 +4019,8 @@ static void rtw89_hw_scan_add_chan(struct rtw89_dev *rtwdev, int chan_type,
if (info->channel_6ghz &&
ch_info->pri_ch != info->channel_6ghz)
continue;
+ else if (info->channel_6ghz && probe_count != 0)
+ ch_info->period += RTW89_CHANNEL_TIME_6G;
ch_info->pkt_id[probe_count++] = info->id;
if (probe_count >= RTW89_SCANOFLD_MAX_SSID)
break;
@@ -4043,6 +4197,7 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
rtw89_core_scan_complete(rtwdev, vif, true);
ieee80211_scan_completed(rtwdev->hw, &info);
ieee80211_wake_queues(rtwdev->hw);
+ rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true);
rtw89_release_pkt_list(rtwdev);
rtwvif = (struct rtw89_vif *)vif->drv_priv;
@@ -4060,6 +4215,19 @@ void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
rtw89_hw_scan_complete(rtwdev, vif, true);
}
+static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_vif *rtwvif;
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+ /* This variable implies connected or during attempt to connect */
+ if (!is_zero_ether_addr(rtwvif->bssid))
+ return true;
+ }
+
+ return false;
+}
+
int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
bool enable)
{
@@ -4072,8 +4240,7 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
if (!rtwvif)
return -EINVAL;
- /* This variable implies connected or during attempt to connect */
- connected = !is_zero_ether_addr(rtwvif->bssid);
+ connected = rtw89_is_any_vif_connected_or_connecting(rtwdev);
opt.enable = enable;
opt.target_ch_mode = connected;
if (enable) {
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index d4db9ab0b5e8..01016588b1fc 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -1685,6 +1685,12 @@ static inline void SET_JOININFO_SELF_ROLE(void *h2c, u32 val)
le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 30));
}
+struct rtw89_h2c_notify_dbcc {
+ __le32 w0;
+} __packed;
+
+#define RTW89_H2C_NOTIFY_DBCC_EN BIT(0)
+
static inline void SET_GENERAL_PKT_MACID(void *h2c, u32 val)
{
le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0));
@@ -3426,6 +3432,8 @@ enum rtw89_fw_element_id {
RTW89_FW_ELEMENT_ID_TXPWR_LMT_RU_6GHZ = 15,
RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT = 16,
RTW89_FW_ELEMENT_ID_TX_SHAPE_LMT_RU = 17,
+ RTW89_FW_ELEMENT_ID_TXPWR_TRK = 18,
+ RTW89_FW_ELEMENT_ID_RFKLOG_FMT = 19,
RTW89_FW_ELEMENT_ID_NUM,
};
@@ -3446,6 +3454,7 @@ enum rtw89_fw_element_id {
BIT(RTW89_FW_ELEMENT_ID_RADIO_A) | \
BIT(RTW89_FW_ELEMENT_ID_RADIO_B) | \
BIT(RTW89_FW_ELEMENT_ID_RF_NCTL) | \
+ BIT(RTW89_FW_ELEMENT_ID_TXPWR_TRK) | \
BITS_OF_RTW89_TXPWR_FW_ELEMENTS)
struct __rtw89_fw_txpwr_element {
@@ -3457,6 +3466,59 @@ struct __rtw89_fw_txpwr_element {
u8 content[];
} __packed;
+enum rtw89_fw_txpwr_trk_type {
+ __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_START = 0,
+ RTW89_FW_TXPWR_TRK_TYPE_6GB_N = 0,
+ RTW89_FW_TXPWR_TRK_TYPE_6GB_P = 1,
+ RTW89_FW_TXPWR_TRK_TYPE_6GA_N = 2,
+ RTW89_FW_TXPWR_TRK_TYPE_6GA_P = 3,
+ __RTW89_FW_TXPWR_TRK_TYPE_6GHZ_MAX = 3,
+
+ __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_START = 4,
+ RTW89_FW_TXPWR_TRK_TYPE_5GB_N = 4,
+ RTW89_FW_TXPWR_TRK_TYPE_5GB_P = 5,
+ RTW89_FW_TXPWR_TRK_TYPE_5GA_N = 6,
+ RTW89_FW_TXPWR_TRK_TYPE_5GA_P = 7,
+ __RTW89_FW_TXPWR_TRK_TYPE_5GHZ_MAX = 7,
+
+ __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_START = 8,
+ RTW89_FW_TXPWR_TRK_TYPE_2GB_N = 8,
+ RTW89_FW_TXPWR_TRK_TYPE_2GB_P = 9,
+ RTW89_FW_TXPWR_TRK_TYPE_2GA_N = 10,
+ RTW89_FW_TXPWR_TRK_TYPE_2GA_P = 11,
+ RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_N = 12,
+ RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_P = 13,
+ RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N = 14,
+ RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P = 15,
+ __RTW89_FW_TXPWR_TRK_TYPE_2GHZ_MAX = 15,
+
+ RTW89_FW_TXPWR_TRK_TYPE_NR,
+};
+
+struct rtw89_fw_txpwr_track_cfg {
+ const s8 (*delta[RTW89_FW_TXPWR_TRK_TYPE_NR])[DELTA_SWINGIDX_SIZE];
+};
+
+#define RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_6GHZ \
+ (BIT(RTW89_FW_TXPWR_TRK_TYPE_6GB_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_6GB_P) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_6GA_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_6GA_P))
+#define RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_5GHZ \
+ (BIT(RTW89_FW_TXPWR_TRK_TYPE_5GB_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_5GB_P) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_5GA_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_5GA_P))
+#define RTW89_DEFAULT_NEEDED_FW_TXPWR_TRK_2GHZ \
+ (BIT(RTW89_FW_TXPWR_TRK_TYPE_2GB_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2GB_P) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2GA_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2GA_P) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_B_P) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N) | \
+ BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P))
+
struct rtw89_fw_element_hdr {
__le32 id; /* enum rtw89_fw_element_id */
__le32 size; /* exclude header size */
@@ -3477,6 +3539,23 @@ struct rtw89_fw_element_hdr {
__le32 data;
} __packed regs[];
} __packed reg2;
+ struct {
+ u8 cv;
+ u8 priv[7];
+ u8 contents[];
+ } __packed bbmcu;
+ struct {
+ __le32 bitmap; /* bitmap of enum rtw89_fw_txpwr_trk_type */
+ __le32 rsvd;
+ s8 contents[][DELTA_SWINGIDX_SIZE];
+ } __packed txpwr_trk;
+ struct {
+ u8 nr;
+ u8 rsvd[3];
+ u8 rfk_id; /* enum rtw89_phy_c2h_rfk_log_func */
+ u8 rsvd1[3];
+ __le16 offset[];
+ } __packed rfk_log_fmt;
struct __rtw89_fw_txpwr_element txpwr;
} __packed u;
} __packed;
@@ -3577,6 +3656,7 @@ struct rtw89_fw_h2c_rf_reg_info {
#define H2C_CL_MAC_MEDIA_RPT 0x8
#define H2C_FUNC_MAC_JOININFO 0x0
#define H2C_FUNC_MAC_FWROLE_MAINTAIN 0x4
+#define H2C_FUNC_NOTIFY_DBCC 0x5
/* CLASS 9 - FW offload */
#define H2C_CL_MAC_FW_OFLD 0x9
@@ -3649,9 +3729,78 @@ struct rtw89_fw_h2c_rf_get_mccch {
__le32 current_band_type;
} __packed;
-#define RTW89_FW_RSVD_PLE_SIZE 0x800
+enum rtw89_rf_log_type {
+ RTW89_RF_RUN_LOG = 0,
+ RTW89_RF_RPT_LOG = 1,
+};
-#define RTW89_WCPU_BASE_MASK GENMASK(27, 0)
+struct rtw89_c2h_rf_log_hdr {
+ u8 type; /* enum rtw89_rf_log_type */
+ __le16 len;
+ u8 content[];
+} __packed;
+
+struct rtw89_c2h_rf_run_log {
+ __le32 fmt_idx;
+ __le32 arg[4];
+} __packed;
+
+struct rtw89_c2h_rf_dpk_rpt_log {
+ u8 ver;
+ u8 idx[2];
+ u8 band[2];
+ u8 bw[2];
+ u8 ch[2];
+ u8 path_ok[2];
+ u8 txagc[2];
+ u8 ther[2];
+ u8 gs[2];
+ u8 dc_i[4];
+ u8 dc_q[4];
+ u8 corr_val[2];
+ u8 corr_idx[2];
+ u8 is_timeout[2];
+ u8 rxbb_ov[2];
+ u8 rsvd;
+} __packed;
+
+struct rtw89_c2h_rf_dack_rpt_log {
+ u8 fwdack_ver;
+ u8 fwdack_rpt_ver;
+ u8 msbk_d[2][2][16];
+ u8 dadck_d[2][2];
+ u8 cdack_d[2][2][2];
+ __le16 addck2_d[2][2][2];
+ u8 adgaink_d[2][2];
+ __le16 biask_d[2][2];
+ u8 addck_timeout;
+ u8 cdack_timeout;
+ u8 dadck_timeout;
+ u8 msbk_timeout;
+ u8 adgaink_timeout;
+ u8 dack_fail;
+} __packed;
+
+struct rtw89_c2h_rf_rxdck_rpt_log {
+ u8 ver;
+ u8 band[2];
+ u8 bw[2];
+ u8 ch[2];
+ u8 timeout[2];
+} __packed;
+
+struct rtw89_c2h_rf_txgapk_rpt_log {
+ __le32 r0x8010[2];
+ __le32 chk_cnt;
+ u8 track_d[2][17];
+ u8 power_d[2][17];
+ u8 is_txgapk_ok;
+ u8 chk_id;
+ u8 ver;
+ u8 rsv1;
+} __packed;
+
+#define RTW89_FW_RSVD_PLE_SIZE 0x800
#define RTW89_FW_BACKTRACE_INFO_SIZE 8
#define RTW89_VALID_FW_BACKTRACE_SIZE(_size) \
@@ -3704,6 +3853,7 @@ int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev,
enum rtw89_upd_mode upd_mode);
int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
struct rtw89_sta *rtwsta, bool dis_conn);
+int rtw89_fw_h2c_notify_dbcc(struct rtw89_dev *rtwdev, bool en);
int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp,
bool pause);
int rtw89_fw_h2c_set_edca(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c
index 0c5768f41d55..c485ef2cc3d3 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.c
+++ b/drivers/net/wireless/realtek/rtw89/mac.c
@@ -5,6 +5,7 @@
#include "cam.h"
#include "chan.h"
#include "debug.h"
+#include "efuse.h"
#include "fw.h"
#include "mac.h"
#include "pci.h"
@@ -56,8 +57,8 @@ static u32 rtw89_mac_mem_read(struct rtw89_dev *rtwdev, u32 offset,
return rtw89_read32(rtwdev, mac->indir_access_addr);
}
-int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 mac_idx,
- enum rtw89_mac_hwmod_sel sel)
+static int rtw89_mac_check_mac_en_ax(struct rtw89_dev *rtwdev, u8 mac_idx,
+ enum rtw89_mac_hwmod_sel sel)
{
u32 val, r_val;
@@ -112,8 +113,7 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val)
return ret;
}
-static
-int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl)
+int rtw89_mac_dle_dfi_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl)
{
u32 ctrl_reg, data_reg, ctrl_data;
u32 val;
@@ -153,8 +153,8 @@ int dle_dfi_ctrl(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl)
return 0;
}
-static int dle_dfi_quota(struct rtw89_dev *rtwdev,
- struct rtw89_mac_dle_dfi_quota *quota)
+int rtw89_mac_dle_dfi_quota_cfg(struct rtw89_dev *rtwdev,
+ struct rtw89_mac_dle_dfi_quota *quota)
{
struct rtw89_mac_dle_dfi_ctrl ctrl;
int ret;
@@ -162,9 +162,9 @@ static int dle_dfi_quota(struct rtw89_dev *rtwdev,
ctrl.type = quota->dle_type;
ctrl.target = DLE_DFI_TYPE_QUOTA;
ctrl.addr = quota->qtaid;
- ret = dle_dfi_ctrl(rtwdev, &ctrl);
+ ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl);
if (ret) {
- rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret);
+ rtw89_warn(rtwdev, "[ERR] dle dfi quota %d\n", ret);
return ret;
}
@@ -173,8 +173,8 @@ static int dle_dfi_quota(struct rtw89_dev *rtwdev,
return 0;
}
-static int dle_dfi_qempty(struct rtw89_dev *rtwdev,
- struct rtw89_mac_dle_dfi_qempty *qempty)
+int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev,
+ struct rtw89_mac_dle_dfi_qempty *qempty)
{
struct rtw89_mac_dle_dfi_ctrl ctrl;
u32 ret;
@@ -182,9 +182,9 @@ static int dle_dfi_qempty(struct rtw89_dev *rtwdev,
ctrl.type = qempty->dle_type;
ctrl.target = DLE_DFI_TYPE_QEMPTY;
ctrl.addr = qempty->grpsel;
- ret = dle_dfi_ctrl(rtwdev, &ctrl);
+ ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl);
if (ret) {
- rtw89_warn(rtwdev, "[ERR]dle_dfi_ctrl %d\n", ret);
+ rtw89_warn(rtwdev, "[ERR] dle dfi qempty %d\n", ret);
return ret;
}
@@ -192,7 +192,7 @@ static int dle_dfi_qempty(struct rtw89_dev *rtwdev,
return 0;
}
-static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev)
+static void dump_err_status_dispatcher_ax(struct rtw89_dev *rtwdev)
{
rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ALWAYS_IMR=0x%08x ",
rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR));
@@ -208,7 +208,7 @@ static void dump_err_status_dispatcher(struct rtw89_dev *rtwdev)
rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR));
}
-static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev)
+static void rtw89_mac_dump_qta_lost_ax(struct rtw89_dev *rtwdev)
{
struct rtw89_mac_dle_dfi_qempty qempty;
struct rtw89_mac_dle_dfi_quota quota;
@@ -219,7 +219,7 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev)
qempty.dle_type = DLE_CTRL_TYPE_PLE;
qempty.grpsel = 0;
qempty.qempty = ~(u32)0;
- ret = dle_dfi_qempty(rtwdev, &qempty);
+ ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty);
if (ret)
rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
else
@@ -231,19 +231,19 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev)
ctrl.type = DLE_CTRL_TYPE_PLE;
ctrl.target = DLE_DFI_TYPE_QLNKTBL;
ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) |
- FIELD_PREP(QLNKTBL_ADDR_TBL_IDX_MASK, i);
- ret = dle_dfi_ctrl(rtwdev, &ctrl);
+ u32_encode_bits(i, QLNKTBL_ADDR_TBL_IDX_MASK);
+ ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl);
if (ret)
rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
else
- rtw89_info(rtwdev, "qidx%d pktcnt = %ld\n", i,
- FIELD_GET(QLNKTBL_DATA_SEL1_PKT_CNT_MASK,
- ctrl.out_data));
+ rtw89_info(rtwdev, "qidx%d pktcnt = %d\n", i,
+ u32_get_bits(ctrl.out_data,
+ QLNKTBL_DATA_SEL1_PKT_CNT_MASK));
}
quota.dle_type = DLE_CTRL_TYPE_PLE;
quota.qtaid = 6;
- ret = dle_dfi_quota(rtwdev, &quota);
+ ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, &quota);
if (ret)
rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
else
@@ -251,33 +251,74 @@ static void rtw89_mac_dump_qta_lost(struct rtw89_dev *rtwdev)
quota.rsv_pgnum, quota.use_pgnum);
val = rtw89_read32(rtwdev, R_AX_PLE_QTA6_CFG);
- rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%lx\n",
- FIELD_GET(B_AX_PLE_Q6_MIN_SIZE_MASK, val));
- rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%lx\n",
- FIELD_GET(B_AX_PLE_Q6_MAX_SIZE_MASK, val));
+ rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%x\n",
+ u32_get_bits(val, B_AX_PLE_Q6_MIN_SIZE_MASK));
+ rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%x\n",
+ u32_get_bits(val, B_AX_PLE_Q6_MAX_SIZE_MASK));
+ val = rtw89_read32(rtwdev, R_AX_RX_FLTR_OPT);
+ rtw89_info(rtwdev, "[PLE][CMAC0_RX]B_AX_RX_MPDU_MAX_LEN=0x%x\n",
+ u32_get_bits(val, B_AX_RX_MPDU_MAX_LEN_MASK));
+ rtw89_info(rtwdev, "R_AX_RSP_CHK_SIG=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RSP_CHK_SIG));
+ rtw89_info(rtwdev, "R_AX_TRXPTCL_RESP_0=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_TRXPTCL_RESP_0));
+ rtw89_info(rtwdev, "R_AX_CCA_CONTROL=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_CCA_CONTROL));
+
+ if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) {
+ quota.dle_type = DLE_CTRL_TYPE_PLE;
+ quota.qtaid = 7;
+ ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, &quota);
+ if (ret)
+ rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
+ else
+ rtw89_info(rtwdev, "quota7 rsv/use: 0x%x/0x%x\n",
+ quota.rsv_pgnum, quota.use_pgnum);
+
+ val = rtw89_read32(rtwdev, R_AX_PLE_QTA7_CFG);
+ rtw89_info(rtwdev, "[PLE][CMAC1_RX]min_pgnum=0x%x\n",
+ u32_get_bits(val, B_AX_PLE_Q7_MIN_SIZE_MASK));
+ rtw89_info(rtwdev, "[PLE][CMAC1_RX]max_pgnum=0x%x\n",
+ u32_get_bits(val, B_AX_PLE_Q7_MAX_SIZE_MASK));
+ val = rtw89_read32(rtwdev, R_AX_RX_FLTR_OPT_C1);
+ rtw89_info(rtwdev, "[PLE][CMAC1_RX]B_AX_RX_MPDU_MAX_LEN=0x%x\n",
+ u32_get_bits(val, B_AX_RX_MPDU_MAX_LEN_MASK));
+ rtw89_info(rtwdev, "R_AX_RSP_CHK_SIG_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RSP_CHK_SIG_C1));
+ rtw89_info(rtwdev, "R_AX_TRXPTCL_RESP_0_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_TRXPTCL_RESP_0_C1));
+ rtw89_info(rtwdev, "R_AX_CCA_CONTROL_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_CCA_CONTROL_C1));
+ }
+
+ rtw89_info(rtwdev, "R_AX_DLE_EMPTY0=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_DLE_EMPTY0));
+ rtw89_info(rtwdev, "R_AX_DLE_EMPTY1=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_DLE_EMPTY1));
- dump_err_status_dispatcher(rtwdev);
+ dump_err_status_dispatcher_ax(rtwdev);
}
-static void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev,
- enum mac_ax_err_info err)
+void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev,
+ enum mac_ax_err_info err)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
u32 dbg, event;
dbg = rtw89_read32(rtwdev, R_AX_SER_DBG_INFO);
- event = FIELD_GET(B_AX_L0_TO_L1_EVENT_MASK, dbg);
+ event = u32_get_bits(dbg, B_AX_L0_TO_L1_EVENT_MASK);
switch (event) {
case MAC_AX_L0_TO_L1_RX_QTA_LOST:
rtw89_info(rtwdev, "quota lost!\n");
- rtw89_mac_dump_qta_lost(rtwdev);
+ mac->dump_qta_lost(rtwdev);
break;
default:
break;
}
}
-static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
+void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
u32 dmac_err;
@@ -357,6 +398,21 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
rtw89_info(rtwdev, "sel=%x,R_AX_SEC_DEBUG2=0x%08x\n",
i, rtw89_read32(rtwdev, R_AX_SEC_DEBUG2));
}
+ } else if (chip->chip_id == RTL8922A) {
+ rtw89_info(rtwdev, "R_BE_SEC_ERROR_FLAG=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_ERROR_FLAG));
+ rtw89_info(rtwdev, "R_BE_SEC_ERROR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_ERROR_IMR));
+ rtw89_info(rtwdev, "R_BE_SEC_ENG_CTRL=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_ENG_CTRL));
+ rtw89_info(rtwdev, "R_BE_SEC_MPDU_PROC=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_MPDU_PROC));
+ rtw89_info(rtwdev, "R_BE_SEC_CAM_ACCESS=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_CAM_ACCESS));
+ rtw89_info(rtwdev, "R_BE_SEC_CAM_RDATA=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_CAM_RDATA));
+ rtw89_info(rtwdev, "R_BE_SEC_DEBUG2=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SEC_DEBUG2));
} else {
rtw89_info(rtwdev, "R_AX_SEC_ERR_IMR_ISR=0x%08x\n",
rtw89_read32(rtwdev, R_AX_SEC_DEBUG));
@@ -393,10 +449,17 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
}
if (dmac_err & B_AX_STA_SCHEDULER_ERR_FLAG) {
- rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR));
- rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR));
+ if (chip->chip_id == RTL8922A) {
+ rtw89_info(rtwdev, "R_BE_INTERRUPT_MASK_REG=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_INTERRUPT_MASK_REG));
+ rtw89_info(rtwdev, "R_BE_INTERRUPT_STS_REG=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_INTERRUPT_STS_REG));
+ } else {
+ rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_IMR));
+ rtw89_info(rtwdev, "R_AX_STA_SCHEDULER_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_STA_SCHEDULER_ERR_ISR));
+ }
}
if (dmac_err & B_AX_WDE_DLE_ERR_FLAG) {
@@ -411,7 +474,7 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
}
if (dmac_err & B_AX_TXPKTCTRL_ERR_FLAG) {
- if (chip->chip_id == RTL8852C) {
+ if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) {
rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_IMR=0x%08x\n",
rtw89_read32(rtwdev, R_AX_TXPKTCTL_B0_ERRFLAG_IMR));
rtw89_info(rtwdev, "R_AX_TXPKTCTL_B0_ERRFLAG_ISR=0x%08x\n",
@@ -443,30 +506,41 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_1));
rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_2=0x%08x\n",
rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_2));
- rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS));
rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_0=0x%08x\n",
rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_0));
rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_1=0x%08x\n",
rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_1));
rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_2=0x%08x\n",
rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_2));
- rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS));
- if (chip->chip_id == RTL8852C) {
- rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RX_CTRL0));
- rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RX_CTRL1));
- rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RX_CTRL2));
+ if (chip->chip_id == RTL8922A) {
+ rtw89_info(rtwdev, "R_BE_WD_CPUQ_OP_3=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_WD_CPUQ_OP_3));
+ rtw89_info(rtwdev, "R_BE_WD_CPUQ_OP_STATUS=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_WD_CPUQ_OP_STATUS));
+ rtw89_info(rtwdev, "R_BE_PLE_CPUQ_OP_3=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_PL_CPUQ_OP_3));
+ rtw89_info(rtwdev, "R_BE_PL_CPUQ_OP_STATUS=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_PL_CPUQ_OP_STATUS));
} else {
- rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0));
- rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1));
- rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2));
+ rtw89_info(rtwdev, "R_AX_WD_CPUQ_OP_STATUS=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_WD_CPUQ_OP_STATUS));
+ rtw89_info(rtwdev, "R_AX_PL_CPUQ_OP_STATUS=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_PL_CPUQ_OP_STATUS));
+ if (chip->chip_id == RTL8852C) {
+ rtw89_info(rtwdev, "R_AX_RX_CTRL0=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RX_CTRL0));
+ rtw89_info(rtwdev, "R_AX_RX_CTRL1=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RX_CTRL1));
+ rtw89_info(rtwdev, "R_AX_RX_CTRL2=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RX_CTRL2));
+ } else {
+ rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_0=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_0));
+ rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_1=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_1));
+ rtw89_info(rtwdev, "R_AX_RXDMA_PKT_INFO_2=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RXDMA_PKT_INFO_2));
+ }
}
}
@@ -478,22 +552,37 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
}
if (dmac_err & B_AX_DISPATCH_ERR_FLAG) {
- rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR));
- rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR));
- rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR));
- rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR));
- rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR));
- rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR));
+ if (chip->chip_id == RTL8922A) {
+ rtw89_info(rtwdev, "R_BE_DISP_HOST_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_HOST_IMR));
+ rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR1));
+ rtw89_info(rtwdev, "R_BE_DISP_CPU_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_CPU_IMR));
+ rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR2=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR2));
+ rtw89_info(rtwdev, "R_BE_DISP_OTHER_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_OTHER_IMR));
+ rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR0=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR0));
+ } else {
+ rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_IMR));
+ rtw89_info(rtwdev, "R_AX_HOST_DISPATCHER_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_HOST_DISPATCHER_ERR_ISR));
+ rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_IMR));
+ rtw89_info(rtwdev, "R_AX_CPU_DISPATCHER_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_CPU_DISPATCHER_ERR_ISR));
+ rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_IMR));
+ rtw89_info(rtwdev, "R_AX_OTHER_DISPATCHER_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_OTHER_DISPATCHER_ERR_ISR));
+ }
}
if (dmac_err & B_AX_BBRPT_ERR_FLAG) {
- if (chip->chip_id == RTL8852C) {
+ if (chip->chip_id == RTL8852C || chip->chip_id == RTL8922A) {
rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_IMR=0x%08x\n",
rtw89_read32(rtwdev, R_AX_BBRPT_COM_ERR_IMR));
rtw89_info(rtwdev, "R_AX_BBRPT_COM_ERR_ISR=0x%08x\n",
@@ -518,18 +607,54 @@ static void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev)
rtw89_info(rtwdev, "R_AX_BBRPT_DFS_ERR_ISR=0x%08x\n",
rtw89_read32(rtwdev, R_AX_BBRPT_DFS_ERR_ISR));
}
+ if (chip->chip_id == RTL8922A) {
+ rtw89_info(rtwdev, "R_BE_LA_ERRFLAG_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_LA_ERRFLAG_IMR));
+ rtw89_info(rtwdev, "R_BE_LA_ERRFLAG_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_LA_ERRFLAG_ISR));
+ }
+ }
+
+ if (dmac_err & B_AX_HAXIDMA_ERR_FLAG) {
+ if (chip->chip_id == RTL8922A) {
+ rtw89_info(rtwdev, "R_BE_HAXI_IDCT_MSK=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_HAXI_IDCT_MSK));
+ rtw89_info(rtwdev, "R_BE_HAXI_IDCT=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_HAXI_IDCT));
+ } else if (chip->chip_id == RTL8852C) {
+ rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK));
+ rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_HAXI_IDCT));
+ }
}
- if (dmac_err & B_AX_HAXIDMA_ERR_FLAG && chip->chip_id == RTL8852C) {
- rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_IMR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_HAXI_IDCT_MSK));
- rtw89_info(rtwdev, "R_AX_HAXIDMA_ERR_ISR=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_HAXI_IDCT));
+ if (dmac_err & B_BE_P_AXIDMA_ERR_INT) {
+ rtw89_info(rtwdev, "R_BE_PL_AXIDMA_IDCT_MSK=0x%08x\n",
+ rtw89_mac_mem_read(rtwdev, R_BE_PL_AXIDMA_IDCT_MSK,
+ RTW89_MAC_MEM_AXIDMA));
+ rtw89_info(rtwdev, "R_BE_PL_AXIDMA_IDCT=0x%08x\n",
+ rtw89_mac_mem_read(rtwdev, R_BE_PL_AXIDMA_IDCT,
+ RTW89_MAC_MEM_AXIDMA));
+ }
+
+ if (dmac_err & B_BE_MLO_ERR_INT) {
+ rtw89_info(rtwdev, "R_BE_MLO_ERR_IDCT_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_MLO_ERR_IDCT_IMR));
+ rtw89_info(rtwdev, "R_BE_PKTIN_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_MLO_ERR_IDCT_ISR));
+ }
+
+ if (dmac_err & B_BE_PLRLS_ERR_INT) {
+ rtw89_info(rtwdev, "R_BE_PLRLS_ERR_IMR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_PLRLS_ERR_IMR));
+ rtw89_info(rtwdev, "R_BE_PLRLS_ERR_ISR=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_PLRLS_ERR_ISR));
}
}
-static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev,
- u8 band)
+static void rtw89_mac_dump_cmac_err_status_ax(struct rtw89_dev *rtwdev,
+ u8 band)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
u32 offset = 0;
@@ -619,8 +744,8 @@ static void rtw89_mac_dump_cmac_err_status(struct rtw89_dev *rtwdev,
rtw89_read32(rtwdev, R_AX_CMAC_ERR_IMR + offset));
}
-static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev,
- enum mac_ax_err_info err)
+static void rtw89_mac_dump_err_status_ax(struct rtw89_dev *rtwdev,
+ enum mac_ax_err_info err)
{
if (err != MAC_AX_ERR_L1_ERR_DMAC &&
err != MAC_AX_ERR_L0_PROMOTE_TO_L1 &&
@@ -632,11 +757,16 @@ static void rtw89_mac_dump_err_status(struct rtw89_dev *rtwdev,
rtw89_info(rtwdev, "--->\nerr=0x%x\n", err);
rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n",
rtw89_read32(rtwdev, R_AX_SER_DBG_INFO));
+ rtw89_info(rtwdev, "R_AX_SER_DBG_INFO =0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_SER_DBG_INFO));
+ rtw89_info(rtwdev, "DBG Counter 1 (R_AX_DRV_FW_HSK_4)=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_DRV_FW_HSK_4));
+ rtw89_info(rtwdev, "DBG Counter 2 (R_AX_DRV_FW_HSK_5)=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_DRV_FW_HSK_5));
rtw89_mac_dump_dmac_err_status(rtwdev);
- rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_0);
- if (rtwdev->dbcc_en)
- rtw89_mac_dump_cmac_err_status(rtwdev, RTW89_MAC_1);
+ rtw89_mac_dump_cmac_err_status_ax(rtwdev, RTW89_MAC_0);
+ rtw89_mac_dump_cmac_err_status_ax(rtwdev, RTW89_MAC_1);
rtwdev->hci.ops->dump_err_status(rtwdev);
@@ -681,6 +811,7 @@ static bool rtw89_mac_suppress_log(struct rtw89_dev *rtwdev, u32 err)
u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
u32 err, err_scnr;
int ret;
@@ -706,7 +837,7 @@ u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev)
return err;
rtw89_fw_st_dbg_dump(rtwdev);
- rtw89_mac_dump_err_status(rtwdev, err);
+ mac->dump_err_status(rtwdev, err);
return err;
}
@@ -900,7 +1031,7 @@ static int hfc_pub_ctrl(struct rtw89_dev *rtwdev)
return 0;
}
-static int hfc_upd_mix_info(struct rtw89_dev *rtwdev)
+static void hfc_get_mix_info_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_page_regs *regs = chip->page_regs;
@@ -909,11 +1040,6 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev)
struct rtw89_hfc_prec_cfg *prec_cfg = &param->prec_cfg;
struct rtw89_hfc_pub_info *info = &param->pub_info;
u32 val;
- int ret;
-
- ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
- if (ret)
- return ret;
val = rtw89_read32(rtwdev, regs->pub_page_info1);
info->g0_used = u32_get_bits(val, B_AX_G0_USE_PG_MASK);
@@ -958,6 +1084,19 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev)
val = rtw89_read32(rtwdev, regs->pub_page_ctrl1);
pub_cfg->grp0 = u32_get_bits(val, B_AX_PUBPG_G0_MASK);
pub_cfg->grp1 = u32_get_bits(val, B_AX_PUBPG_G1_MASK);
+}
+
+static int hfc_upd_mix_info(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
+ if (ret)
+ return ret;
+
+ mac->hfc_get_mix_info(rtwdev);
ret = hfc_pub_info_chk(rtwdev);
if (param->en && ret)
@@ -966,7 +1105,7 @@ static int hfc_upd_mix_info(struct rtw89_dev *rtwdev)
return 0;
}
-static void hfc_h2c_cfg(struct rtw89_dev *rtwdev)
+static void hfc_h2c_cfg_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_page_regs *regs = chip->page_regs;
@@ -982,7 +1121,7 @@ static void hfc_h2c_cfg(struct rtw89_dev *rtwdev)
prec_cfg->h2c_full_cond);
}
-static void hfc_mix_cfg(struct rtw89_dev *rtwdev)
+static void hfc_mix_cfg_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_page_regs *regs = chip->page_regs;
@@ -1017,7 +1156,7 @@ static void hfc_mix_cfg(struct rtw89_dev *rtwdev)
rtw89_write32(rtwdev, regs->hci_fc_ctrl, val);
}
-static void hfc_func_en(struct rtw89_dev *rtwdev, bool en, bool h2c_en)
+static void hfc_func_en_ax(struct rtw89_dev *rtwdev, bool en, bool h2c_en)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_page_regs *regs = chip->page_regs;
@@ -1033,8 +1172,9 @@ static void hfc_func_en(struct rtw89_dev *rtwdev, bool en, bool h2c_en)
rtw89_write32(rtwdev, regs->hci_fc_ctrl, val);
}
-static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en)
+int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_chip_info *chip = rtwdev->chip;
u32 dma_ch_mask = chip->dma_ch_mask;
u8 ch;
@@ -1049,11 +1189,11 @@ static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en)
if (ret)
return ret;
- hfc_func_en(rtwdev, false, false);
+ mac->hfc_func_en(rtwdev, false, false);
if (!en && h2c_en) {
- hfc_h2c_cfg(rtwdev);
- hfc_func_en(rtwdev, en, h2c_en);
+ mac->hfc_h2c_cfg(rtwdev);
+ mac->hfc_func_en(rtwdev, en, h2c_en);
return ret;
}
@@ -1069,9 +1209,9 @@ static int hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en)
if (ret)
return ret;
- hfc_mix_cfg(rtwdev);
+ mac->hfc_mix_cfg(rtwdev);
if (en || h2c_en) {
- hfc_func_en(rtwdev, en, h2c_en);
+ mac->hfc_func_en(rtwdev, en, h2c_en);
udelay(10);
}
for (ch = RTW89_DMA_ACH0; ch < RTW89_DMA_H2C; ch++) {
@@ -1333,9 +1473,14 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on)
if (on) {
set_bit(RTW89_FLAG_POWERON, rtwdev->flags);
+ set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags);
+ set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags);
rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_TP_MAJOR);
} else {
clear_bit(RTW89_FLAG_POWERON, rtwdev->flags);
+ clear_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags);
+ clear_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags);
+ clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags);
clear_bit(RTW89_FLAG_FW_RDY, rtwdev->flags);
rtw89_write8(rtwdev, R_AX_SCOREBOARD + 3, MAC_AX_NOTIFY_PWR_MAJOR);
rtw89_set_entity_state(rtwdev, false);
@@ -1350,7 +1495,7 @@ void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev)
rtw89_mac_power_switch(rtwdev, false);
}
-static int cmac_func_en(struct rtw89_dev *rtwdev, u8 mac_idx, bool en)
+static int cmac_func_en_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool en)
{
u32 func_en = 0;
u32 ck_en = 0;
@@ -1396,7 +1541,7 @@ static int cmac_func_en(struct rtw89_dev *rtwdev, u8 mac_idx, bool en)
return 0;
}
-static int dmac_func_en(struct rtw89_dev *rtwdev)
+static int dmac_func_en_ax(struct rtw89_dev *rtwdev)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
u32 val32;
@@ -1428,7 +1573,7 @@ static int dmac_func_en(struct rtw89_dev *rtwdev)
return 0;
}
-static int chip_func_en(struct rtw89_dev *rtwdev)
+static int chip_func_en_ax(struct rtw89_dev *rtwdev)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
@@ -1439,19 +1584,19 @@ static int chip_func_en(struct rtw89_dev *rtwdev)
return 0;
}
-static int rtw89_mac_sys_init(struct rtw89_dev *rtwdev)
+static int sys_init_ax(struct rtw89_dev *rtwdev)
{
int ret;
- ret = dmac_func_en(rtwdev);
+ ret = dmac_func_en_ax(rtwdev);
if (ret)
return ret;
- ret = cmac_func_en(rtwdev, 0, true);
+ ret = cmac_func_en_ax(rtwdev, 0, true);
if (ret)
return ret;
- ret = chip_func_en(rtwdev);
+ ret = chip_func_en_ax(rtwdev);
if (ret)
return ret;
@@ -1460,10 +1605,14 @@ static int rtw89_mac_sys_init(struct rtw89_dev *rtwdev)
const struct rtw89_mac_size_set rtw89_mac_size = {
.hfc_preccfg_pcie = {2, 40, 0, 0, 1, 0, 0, 0},
+ .hfc_prec_cfg_c0 = {2, 32, 0, 0, 0, 0, 0, 0},
+ .hfc_prec_cfg_c2 = {0, 256, 0, 0, 0, 0, 0, 0},
/* PCIE 64 */
.wde_size0 = {RTW89_WDE_PG_64, 4095, 1,},
+ .wde_size0_v1 = {RTW89_WDE_PG_64, 3328, 0, 0,},
/* DLFW */
.wde_size4 = {RTW89_WDE_PG_64, 0, 4096,},
+ .wde_size4_v1 = {RTW89_WDE_PG_64, 0, 3328, 0,},
/* PCIE 64 */
.wde_size6 = {RTW89_WDE_PG_64, 512, 0,},
/* 8852B PCIE SCC */
@@ -1476,6 +1625,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
.wde_size19 = {RTW89_WDE_PG_64, 3328, 0,},
/* PCIE */
.ple_size0 = {RTW89_PLE_PG_128, 1520, 16,},
+ .ple_size0_v1 = {RTW89_PLE_PG_128, 2672, 256, 212992,},
+ .ple_size3_v1 = {RTW89_PLE_PG_128, 2928, 0, 212992,},
/* DLFW */
.ple_size4 = {RTW89_PLE_PG_128, 64, 1472,},
/* PCIE 64 */
@@ -1488,6 +1639,7 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
.ple_size19 = {RTW89_PLE_PG_128, 1904, 16,},
/* PCIE 64 */
.wde_qt0 = {3792, 196, 0, 107,},
+ .wde_qt0_v1 = {3302, 6, 0, 20,},
/* DLFW */
.wde_qt4 = {0, 0, 0, 0,},
/* PCIE 64 */
@@ -1498,10 +1650,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
.wde_qt17 = {0, 0, 0, 0,},
/* 8852C PCIE SCC */
.wde_qt18 = {3228, 60, 0, 40,},
+ .ple_qt0 = {320, 0, 32, 16, 13, 13, 292, 0, 32, 18, 1, 4, 0,},
+ .ple_qt1 = {320, 0, 32, 16, 1944, 1944, 2223, 0, 1963, 1949, 1, 1935, 0,},
/* PCIE SCC */
.ple_qt4 = {264, 0, 16, 20, 26, 13, 356, 0, 32, 40, 8,},
/* PCIE SCC */
.ple_qt5 = {264, 0, 32, 20, 64, 13, 1101, 0, 64, 128, 120,},
+ .ple_qt9 = {0, 0, 32, 256, 0, 0, 0, 0, 0, 0, 1, 0, 0,},
/* DLFW */
.ple_qt13 = {0, 0, 16, 48, 0, 0, 0, 0, 0, 0, 0,},
/* PCIE 64 */
@@ -1522,6 +1677,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = {
.ple_qt_52b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,},
/* 8851B PCIE WOW */
.ple_qt_51b_wow = {147, 0, 16, 20, 157, 13, 133, 0, 172, 14, 24, 0,},
+ .ple_rsvd_qt0 = {2, 112, 56, 6, 6, 6, 6, 0, 0, 62,},
+ .ple_rsvd_qt1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+ .rsvd0_size0 = {212992, 0,},
+ .rsvd1_size0 = {587776, 2048,},
};
EXPORT_SYMBOL(rtw89_mac_size);
@@ -1540,7 +1699,9 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev,
return NULL;
}
+ mac->dle_info.rsvd_qt = cfg->rsvd_qt;
mac->dle_info.ple_pg_size = cfg->ple_size->pge_size;
+ mac->dle_info.ple_free_pg = cfg->ple_size->lnk_pge_num;
mac->dle_info.qta_mode = mode;
mac->dle_info.c0_rx_qta = cfg->ple_min_qt->cma0_dma;
mac->dle_info.c1_rx_qta = cfg->ple_min_qt->cma1_dma;
@@ -1548,33 +1709,86 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev,
return cfg;
}
-static bool mac_is_txq_empty(struct rtw89_dev *rtwdev)
+int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev,
+ enum rtw89_mac_dle_rsvd_qt_type type,
+ struct rtw89_mac_dle_rsvd_qt_cfg *cfg)
+{
+ struct rtw89_dle_info *dle_info = &rtwdev->mac.dle_info;
+ const struct rtw89_rsvd_quota *rsvd_qt = dle_info->rsvd_qt;
+
+ switch (type) {
+ case DLE_RSVD_QT_MPDU_INFO:
+ cfg->pktid = dle_info->ple_free_pg;
+ cfg->pg_num = rsvd_qt->mpdu_info_tbl;
+ break;
+ case DLE_RSVD_QT_B0_CSI:
+ cfg->pktid = dle_info->ple_free_pg + rsvd_qt->mpdu_info_tbl;
+ cfg->pg_num = rsvd_qt->b0_csi;
+ break;
+ case DLE_RSVD_QT_B1_CSI:
+ cfg->pktid = dle_info->ple_free_pg +
+ rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi;
+ cfg->pg_num = rsvd_qt->b1_csi;
+ break;
+ case DLE_RSVD_QT_B0_LMR:
+ cfg->pktid = dle_info->ple_free_pg +
+ rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi;
+ cfg->pg_num = rsvd_qt->b0_lmr;
+ break;
+ case DLE_RSVD_QT_B1_LMR:
+ cfg->pktid = dle_info->ple_free_pg +
+ rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi +
+ rsvd_qt->b0_lmr;
+ cfg->pg_num = rsvd_qt->b1_lmr;
+ break;
+ case DLE_RSVD_QT_B0_FTM:
+ cfg->pktid = dle_info->ple_free_pg +
+ rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi +
+ rsvd_qt->b0_lmr + rsvd_qt->b1_lmr;
+ cfg->pg_num = rsvd_qt->b0_ftm;
+ break;
+ case DLE_RSVD_QT_B1_FTM:
+ cfg->pktid = dle_info->ple_free_pg +
+ rsvd_qt->mpdu_info_tbl + rsvd_qt->b0_csi + rsvd_qt->b1_csi +
+ rsvd_qt->b0_lmr + rsvd_qt->b1_lmr + rsvd_qt->b0_ftm;
+ cfg->pg_num = rsvd_qt->b1_ftm;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cfg->size = (u32)cfg->pg_num * dle_info->ple_pg_size;
+
+ return 0;
+}
+
+static bool mac_is_txq_empty_ax(struct rtw89_dev *rtwdev)
{
struct rtw89_mac_dle_dfi_qempty qempty;
- u32 qnum, qtmp, val32, msk32;
+ u32 grpnum, qtmp, val32, msk32;
int i, j, ret;
- qnum = rtwdev->chip->wde_qempty_acq_num;
+ grpnum = rtwdev->chip->wde_qempty_acq_grpnum;
qempty.dle_type = DLE_CTRL_TYPE_WDE;
- for (i = 0; i < qnum; i++) {
+ for (i = 0; i < grpnum; i++) {
qempty.grpsel = i;
- ret = dle_dfi_qempty(rtwdev, &qempty);
+ ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty);
if (ret) {
rtw89_warn(rtwdev, "dle dfi acq empty %d\n", ret);
return false;
}
qtmp = qempty.qempty;
for (j = 0 ; j < QEMP_ACQ_GRP_MACID_NUM; j++) {
- val32 = FIELD_GET(QEMP_ACQ_GRP_QSEL_MASK, qtmp);
+ val32 = u32_get_bits(qtmp, QEMP_ACQ_GRP_QSEL_MASK);
if (val32 != QEMP_ACQ_GRP_QSEL_MASK)
return false;
qtmp >>= QEMP_ACQ_GRP_QSEL_SH;
}
}
- qempty.grpsel = rtwdev->chip->wde_qempty_mgq_sel;
- ret = dle_dfi_qempty(rtwdev, &qempty);
+ qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel;
+ ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty);
if (ret) {
rtw89_warn(rtwdev, "dle dfi mgq empty %d\n", ret);
return false;
@@ -1602,11 +1816,21 @@ static bool mac_is_txq_empty(struct rtw89_dev *rtwdev)
return (val32 & msk32) == msk32;
}
-static inline u32 dle_used_size(const struct rtw89_dle_size *wde,
- const struct rtw89_dle_size *ple)
+static inline u32 dle_used_size(const struct rtw89_dle_mem *cfg)
{
- return wde->pge_size * (wde->lnk_pge_num + wde->unlnk_pge_num) +
+ const struct rtw89_dle_size *wde = cfg->wde_size;
+ const struct rtw89_dle_size *ple = cfg->ple_size;
+ u32 used;
+
+ used = wde->pge_size * (wde->lnk_pge_num + wde->unlnk_pge_num) +
ple->pge_size * (ple->lnk_pge_num + ple->unlnk_pge_num);
+
+ if (cfg->rsvd0_size && cfg->rsvd1_size) {
+ used += cfg->rsvd0_size->size;
+ used += cfg->rsvd1_size->size;
+ }
+
+ return used;
}
static u32 dle_expected_used_size(struct rtw89_dev *rtwdev,
@@ -1620,7 +1844,7 @@ static u32 dle_expected_used_size(struct rtw89_dev *rtwdev,
return size;
}
-static void dle_func_en(struct rtw89_dev *rtwdev, bool enable)
+static void dle_func_en_ax(struct rtw89_dev *rtwdev, bool enable)
{
if (enable)
rtw89_write32_set(rtwdev, R_AX_DMAC_FUNC_EN,
@@ -1630,7 +1854,7 @@ static void dle_func_en(struct rtw89_dev *rtwdev, bool enable)
B_AX_DLE_WDE_EN | B_AX_DLE_PLE_EN);
}
-static void dle_clk_en(struct rtw89_dev *rtwdev, bool enable)
+static void dle_clk_en_ax(struct rtw89_dev *rtwdev, bool enable)
{
u32 val = B_AX_DLE_WDE_CLK_EN | B_AX_DLE_PLE_CLK_EN;
@@ -1643,7 +1867,7 @@ static void dle_clk_en(struct rtw89_dev *rtwdev, bool enable)
}
}
-static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg)
+static int dle_mix_cfg_ax(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg)
{
const struct rtw89_dle_size *size_cfg;
u32 val;
@@ -1700,6 +1924,23 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg
return 0;
}
+static int chk_dle_rdy_ax(struct rtw89_dev *rtwdev, bool wde_or_ple)
+{
+ u32 reg, mask;
+ u32 ini;
+
+ if (wde_or_ple) {
+ reg = R_AX_WDE_INI_STATUS;
+ mask = WDE_MGN_INI_RDY;
+ } else {
+ reg = R_AX_PLE_INI_STATUS;
+ mask = PLE_MGN_INI_RDY;
+ }
+
+ return read_poll_timeout(rtw89_read32, ini, (ini & mask) == mask, 1,
+ 2000, false, rtwdev, reg);
+}
+
#define INVALID_QT_WCPU U16_MAX
#define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \
do { \
@@ -1712,10 +1953,10 @@ static int dle_mix_cfg(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg
#define SET_QUOTA(_x, _module, _idx) \
SET_QUOTA_VAL(min_cfg->_x, max_cfg->_x, _module, _idx)
-static void wde_quota_cfg(struct rtw89_dev *rtwdev,
- const struct rtw89_wde_quota *min_cfg,
- const struct rtw89_wde_quota *max_cfg,
- u16 ext_wde_min_qt_wcpu)
+static void wde_quota_cfg_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_wde_quota *min_cfg,
+ const struct rtw89_wde_quota *max_cfg,
+ u16 ext_wde_min_qt_wcpu)
{
u16 min_qt_wcpu = ext_wde_min_qt_wcpu != INVALID_QT_WCPU ?
ext_wde_min_qt_wcpu : min_cfg->wcpu;
@@ -1727,9 +1968,9 @@ static void wde_quota_cfg(struct rtw89_dev *rtwdev,
SET_QUOTA(cpu_io, WDE, 4);
}
-static void ple_quota_cfg(struct rtw89_dev *rtwdev,
- const struct rtw89_ple_quota *min_cfg,
- const struct rtw89_ple_quota *max_cfg)
+static void ple_quota_cfg_ax(struct rtw89_dev *rtwdev,
+ const struct rtw89_ple_quota *min_cfg,
+ const struct rtw89_ple_quota *max_cfg)
{
u32 val;
@@ -1794,17 +2035,19 @@ static void dle_quota_cfg(struct rtw89_dev *rtwdev,
const struct rtw89_dle_mem *cfg,
u16 ext_wde_min_qt_wcpu)
{
- wde_quota_cfg(rtwdev, cfg->wde_min_qt, cfg->wde_max_qt, ext_wde_min_qt_wcpu);
- ple_quota_cfg(rtwdev, cfg->ple_min_qt, cfg->ple_max_qt);
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ mac->wde_quota_cfg(rtwdev, cfg->wde_min_qt, cfg->wde_max_qt, ext_wde_min_qt_wcpu);
+ mac->ple_quota_cfg(rtwdev, cfg->ple_min_qt, cfg->ple_max_qt);
}
-static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode,
- enum rtw89_qta_mode ext_mode)
+int rtw89_mac_dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode,
+ enum rtw89_qta_mode ext_mode)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_dle_mem *cfg, *ext_cfg;
u16 ext_wde_min_qt_wcpu = INVALID_QT_WCPU;
- int ret = 0;
- u32 ini;
+ int ret;
ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
if (ret)
@@ -1828,36 +2071,31 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode,
ext_wde_min_qt_wcpu = ext_cfg->wde_min_qt->wcpu;
}
- if (dle_used_size(cfg->wde_size, cfg->ple_size) !=
- dle_expected_used_size(rtwdev, mode)) {
+ if (dle_used_size(cfg) != dle_expected_used_size(rtwdev, mode)) {
rtw89_err(rtwdev, "[ERR]wd/dle mem cfg\n");
ret = -EINVAL;
goto error;
}
- dle_func_en(rtwdev, false);
- dle_clk_en(rtwdev, true);
+ mac->dle_func_en(rtwdev, false);
+ mac->dle_clk_en(rtwdev, true);
- ret = dle_mix_cfg(rtwdev, cfg);
+ ret = mac->dle_mix_cfg(rtwdev, cfg);
if (ret) {
rtw89_err(rtwdev, "[ERR] dle mix cfg\n");
goto error;
}
dle_quota_cfg(rtwdev, cfg, ext_wde_min_qt_wcpu);
- dle_func_en(rtwdev, true);
+ mac->dle_func_en(rtwdev, true);
- ret = read_poll_timeout(rtw89_read32, ini,
- (ini & WDE_MGN_INI_RDY) == WDE_MGN_INI_RDY, 1,
- 2000, false, rtwdev, R_AX_WDE_INI_STATUS);
+ ret = mac->chk_dle_rdy(rtwdev, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]WDE cfg ready\n");
return ret;
}
- ret = read_poll_timeout(rtw89_read32, ini,
- (ini & WDE_MGN_INI_RDY) == WDE_MGN_INI_RDY, 1,
- 2000, false, rtwdev, R_AX_PLE_INI_STATUS);
+ ret = mac->chk_dle_rdy(rtwdev, false);
if (ret) {
rtw89_err(rtwdev, "[ERR]PLE cfg ready\n");
return ret;
@@ -1865,7 +2103,7 @@ static int dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode,
return 0;
error:
- dle_func_en(rtwdev, false);
+ mac->dle_func_en(rtwdev, false);
rtw89_err(rtwdev, "[ERR]trxcfg wde 0x8900 = %x\n",
rtw89_read32(rtwdev, R_AX_WDE_INI_STATUS));
rtw89_err(rtwdev, "[ERR]trxcfg ple 0x8D00 = %x\n",
@@ -1900,8 +2138,8 @@ static bool is_qta_poh(struct rtw89_dev *rtwdev)
return rtwdev->hci.type == RTW89_HCI_TYPE_PCIE;
}
-static int preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx,
- enum rtw89_qta_mode mode)
+int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx,
+ enum rtw89_qta_mode mode)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
@@ -1950,7 +2188,7 @@ static void _patch_ss2f_path(struct rtw89_dev *rtwdev)
SS2F_PATH_WLCPU);
}
-static int sta_sch_init(struct rtw89_dev *rtwdev)
+static int sta_sch_init_ax(struct rtw89_dev *rtwdev)
{
u32 p_val;
u8 val;
@@ -1979,7 +2217,7 @@ static int sta_sch_init(struct rtw89_dev *rtwdev)
return 0;
}
-static int mpdu_proc_init(struct rtw89_dev *rtwdev)
+static int mpdu_proc_init_ax(struct rtw89_dev *rtwdev)
{
int ret;
@@ -1996,7 +2234,7 @@ static int mpdu_proc_init(struct rtw89_dev *rtwdev)
return 0;
}
-static int sec_eng_init(struct rtw89_dev *rtwdev)
+static int sec_eng_init_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
u32 val = 0;
@@ -2031,41 +2269,41 @@ static int sec_eng_init(struct rtw89_dev *rtwdev)
return 0;
}
-static int dmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int dmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
int ret;
- ret = dle_init(rtwdev, rtwdev->mac.qta_mode, RTW89_QTA_INVALID);
+ ret = rtw89_mac_dle_init(rtwdev, rtwdev->mac.qta_mode, RTW89_QTA_INVALID);
if (ret) {
rtw89_err(rtwdev, "[ERR]DLE init %d\n", ret);
return ret;
}
- ret = preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode);
+ ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode);
if (ret) {
rtw89_err(rtwdev, "[ERR]preload init %d\n", ret);
return ret;
}
- ret = hfc_init(rtwdev, true, true, true);
+ ret = rtw89_mac_hfc_init(rtwdev, true, true, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]HCI FC init %d\n", ret);
return ret;
}
- ret = sta_sch_init(rtwdev);
+ ret = sta_sch_init_ax(rtwdev);
if (ret) {
rtw89_err(rtwdev, "[ERR]STA SCH init %d\n", ret);
return ret;
}
- ret = mpdu_proc_init(rtwdev);
+ ret = mpdu_proc_init_ax(rtwdev);
if (ret) {
rtw89_err(rtwdev, "[ERR]MPDU Proc init %d\n", ret);
return ret;
}
- ret = sec_eng_init(rtwdev);
+ ret = sec_eng_init_ax(rtwdev);
if (ret) {
rtw89_err(rtwdev, "[ERR]Security Engine init %d\n", ret);
return ret;
@@ -2074,7 +2312,7 @@ static int dmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return ret;
}
-static int addr_cam_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int addr_cam_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 val, reg;
u16 p_val;
@@ -2101,7 +2339,7 @@ static int addr_cam_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int scheduler_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 ret;
u32 reg;
@@ -2142,10 +2380,10 @@ static int scheduler_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev,
- enum rtw89_machdr_frame_type type,
- enum rtw89_mac_fwd_target fwd_target,
- u8 mac_idx)
+static int rtw89_mac_typ_fltr_opt_ax(struct rtw89_dev *rtwdev,
+ enum rtw89_machdr_frame_type type,
+ enum rtw89_mac_fwd_target fwd_target,
+ u8 mac_idx)
{
u32 reg;
u32 val;
@@ -2184,7 +2422,7 @@ int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev,
return 0;
}
-static int rx_fltr_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int rx_fltr_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
int ret, i;
u32 mac_ftlr, plcp_ftlr;
@@ -2194,8 +2432,8 @@ static int rx_fltr_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return ret;
for (i = RTW89_MGNT; i <= RTW89_DATA; i++) {
- ret = rtw89_mac_typ_fltr_opt(rtwdev, i, RTW89_FWD_TO_HOST,
- mac_idx);
+ ret = rtw89_mac_typ_fltr_opt_ax(rtwdev, i, RTW89_FWD_TO_HOST,
+ mac_idx);
if (ret)
return ret;
}
@@ -2246,7 +2484,7 @@ static void _patch_dis_resp_chk(struct rtw89_dev *rtwdev, u8 mac_idx)
}
}
-static int cca_ctrl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int cca_ctrl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 val, reg;
int ret;
@@ -2278,7 +2516,7 @@ static int cca_ctrl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int nav_ctrl_init(struct rtw89_dev *rtwdev)
+static int nav_ctrl_init_ax(struct rtw89_dev *rtwdev)
{
rtw89_write32_set(rtwdev, R_AX_WMAC_NAV_CTL, B_AX_WMAC_PLCP_UP_NAV_EN |
B_AX_WMAC_TF_UP_NAV_EN |
@@ -2288,7 +2526,7 @@ static int nav_ctrl_init(struct rtw89_dev *rtwdev)
return 0;
}
-static int spatial_reuse_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int spatial_reuse_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 reg;
int ret;
@@ -2302,7 +2540,7 @@ static int spatial_reuse_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int tmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int tmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 reg;
int ret;
@@ -2324,7 +2562,7 @@ static int tmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int trxptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int trxptcl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
const struct rtw89_rrsr_cfgs *rrsr = chip->rrsr_cfgs;
@@ -2381,7 +2619,7 @@ static void rst_bacam(struct rtw89_dev *rtwdev)
rtw89_warn(rtwdev, "failed to reset BA CAM\n");
}
-static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int rmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
#define TRXCFG_RMAC_CCA_TO 32
#define TRXCFG_RMAC_DATA_TO 15
@@ -2439,7 +2677,7 @@ static int rmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return ret;
}
-static int cmac_com_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int cmac_com_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
u32 val, reg;
@@ -2464,7 +2702,7 @@ static int cmac_com_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static bool is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
+bool rtw89_mac_is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
{
const struct rtw89_dle_mem *cfg;
@@ -2477,7 +2715,7 @@ static bool is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
return (cfg->ple_min_qt->cma1_dma && cfg->ple_max_qt->cma1_dma);
}
-static int ptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int ptcl_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
u32 val, reg;
int ret;
@@ -2520,7 +2758,7 @@ static int ptcl_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int cmac_dma_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int cmac_dma_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
u32 reg;
@@ -2539,82 +2777,82 @@ static int cmac_dma_init(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
+static int cmac_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx)
{
int ret;
- ret = scheduler_init(rtwdev, mac_idx);
+ ret = scheduler_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d SCH init %d\n", mac_idx, ret);
return ret;
}
- ret = addr_cam_init(rtwdev, mac_idx);
+ ret = addr_cam_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d ADDR_CAM reset %d\n", mac_idx,
ret);
return ret;
}
- ret = rx_fltr_init(rtwdev, mac_idx);
+ ret = rx_fltr_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d RX filter init %d\n", mac_idx,
ret);
return ret;
}
- ret = cca_ctrl_init(rtwdev, mac_idx);
+ ret = cca_ctrl_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d CCA CTRL init %d\n", mac_idx,
ret);
return ret;
}
- ret = nav_ctrl_init(rtwdev);
+ ret = nav_ctrl_init_ax(rtwdev);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d NAV CTRL init %d\n", mac_idx,
ret);
return ret;
}
- ret = spatial_reuse_init(rtwdev, mac_idx);
+ ret = spatial_reuse_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d Spatial Reuse init %d\n",
mac_idx, ret);
return ret;
}
- ret = tmac_init(rtwdev, mac_idx);
+ ret = tmac_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d TMAC init %d\n", mac_idx, ret);
return ret;
}
- ret = trxptcl_init(rtwdev, mac_idx);
+ ret = trxptcl_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d TRXPTCL init %d\n", mac_idx, ret);
return ret;
}
- ret = rmac_init(rtwdev, mac_idx);
+ ret = rmac_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d RMAC init %d\n", mac_idx, ret);
return ret;
}
- ret = cmac_com_init(rtwdev, mac_idx);
+ ret = cmac_com_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d Com init %d\n", mac_idx, ret);
return ret;
}
- ret = ptcl_init(rtwdev, mac_idx);
+ ret = ptcl_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d PTCL init %d\n", mac_idx, ret);
return ret;
}
- ret = cmac_dma_init(rtwdev, mac_idx);
+ ret = cmac_dma_init_ax(rtwdev, mac_idx);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d DMA init %d\n", mac_idx, ret);
return ret;
@@ -2626,20 +2864,26 @@ static int cmac_init(struct rtw89_dev *rtwdev, u8 mac_idx)
static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev,
struct rtw89_mac_c2h_info *c2h_info)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_mac_h2c_info h2c_info = {0};
u32 ret;
+ mac->cnv_efuse_state(rtwdev, false);
+
h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE;
h2c_info.content_len = 0;
ret = rtw89_fw_msg_reg(rtwdev, &h2c_info, c2h_info);
if (ret)
- return ret;
+ goto out;
if (c2h_info->id != RTW89_FWCMD_C2HREG_FUNC_PHY_CAP)
- return -EINVAL;
+ ret = -EINVAL;
- return 0;
+out:
+ mac->cnv_efuse_state(rtwdev, true);
+
+ return ret;
}
int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev)
@@ -2871,7 +3115,7 @@ int rtw89_mac_resume_sch_tx_v1(struct rtw89_dev *rtwdev, u8 mac_idx, u32 tx_en)
}
EXPORT_SYMBOL(rtw89_mac_resume_sch_tx_v1);
-int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id)
+static int dle_buf_req_ax(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id)
{
u32 val, reg;
int ret;
@@ -2895,7 +3139,7 @@ int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *p
return 0;
}
-int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev,
+static int set_cpuio_ax(struct rtw89_dev *rtwdev,
struct rtw89_cpuio_ctrl *ctrl_para, bool wd)
{
u32 val, cmd_type, reg;
@@ -2948,8 +3192,9 @@ int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev,
return 0;
}
-static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
+int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_dle_mem *cfg;
struct rtw89_cpuio_ctrl ctrl_para = {0};
u16 pkt_id;
@@ -2961,15 +3206,14 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
return -EINVAL;
}
- if (dle_used_size(cfg->wde_size, cfg->ple_size) !=
- dle_expected_used_size(rtwdev, mode)) {
+ if (dle_used_size(cfg) != dle_expected_used_size(rtwdev, mode)) {
rtw89_err(rtwdev, "[ERR]wd/dle mem cfg\n");
return -EINVAL;
}
dle_quota_cfg(rtwdev, cfg, INVALID_QT_WCPU);
- ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, true, &pkt_id);
+ ret = mac->dle_buf_req(rtwdev, 0x20, true, &pkt_id);
if (ret) {
rtw89_err(rtwdev, "[ERR]WDE DLE buf req\n");
return ret;
@@ -2981,13 +3225,13 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
ctrl_para.pkt_num = 0;
ctrl_para.dst_pid = WDE_DLE_PORT_ID_WDRLS;
ctrl_para.dst_qid = WDE_DLE_QUEID_NO_REPORT;
- ret = rtw89_mac_set_cpuio(rtwdev, &ctrl_para, true);
+ ret = mac->set_cpuio(rtwdev, &ctrl_para, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]WDE DLE enqueue to head\n");
return -EFAULT;
}
- ret = rtw89_mac_dle_buf_req(rtwdev, 0x20, false, &pkt_id);
+ ret = mac->dle_buf_req(rtwdev, 0x20, false, &pkt_id);
if (ret) {
rtw89_err(rtwdev, "[ERR]PLE DLE buf req\n");
return ret;
@@ -2999,7 +3243,7 @@ static int dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode)
ctrl_para.pkt_num = 0;
ctrl_para.dst_pid = PLE_DLE_PORT_ID_PLRLS;
ctrl_para.dst_qid = PLE_DLE_QUEID_NO_REPORT;
- ret = rtw89_mac_set_cpuio(rtwdev, &ctrl_para, false);
+ ret = mac->set_cpuio(rtwdev, &ctrl_para, false);
if (ret) {
rtw89_err(rtwdev, "[ERR]PLE DLE enqueue to head\n");
return -EFAULT;
@@ -3031,7 +3275,7 @@ static int band_idle_ck_b(struct rtw89_dev *rtwdev, u8 mac_idx)
return 0;
}
-static int band1_enable(struct rtw89_dev *rtwdev)
+static int band1_enable_ax(struct rtw89_dev *rtwdev)
{
int ret, i;
u32 sleep_bak[4] = {0};
@@ -3057,7 +3301,7 @@ static int band1_enable(struct rtw89_dev *rtwdev)
return ret;
}
- ret = dle_quota_change(rtwdev, rtwdev->mac.qta_mode);
+ ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode);
if (ret) {
rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret);
return ret;
@@ -3074,13 +3318,13 @@ static int band1_enable(struct rtw89_dev *rtwdev)
return ret;
}
- ret = cmac_func_en(rtwdev, 1, true);
+ ret = cmac_func_en_ax(rtwdev, 1, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC1 func en %d\n", ret);
return ret;
}
- ret = cmac_init(rtwdev, 1);
+ ret = cmac_init_ax(rtwdev, 1);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC1 init %d\n", ret);
return ret;
@@ -3289,8 +3533,8 @@ static void rtw89_tmac_imr_enable(struct rtw89_dev *rtwdev, u8 mac_idx)
rtw89_write32_set(rtwdev, reg, imr->tmac_imr_set);
}
-static int rtw89_mac_enable_imr(struct rtw89_dev *rtwdev, u8 mac_idx,
- enum rtw89_mac_hwmod_sel sel)
+static int enable_imr_ax(struct rtw89_dev *rtwdev, u8 mac_idx,
+ enum rtw89_mac_hwmod_sel sel)
{
int ret;
@@ -3327,7 +3571,7 @@ static int rtw89_mac_enable_imr(struct rtw89_dev *rtwdev, u8 mac_idx,
return 0;
}
-static void rtw89_mac_err_imr_ctrl(struct rtw89_dev *rtwdev, bool en)
+static void err_imr_ctrl_ax(struct rtw89_dev *rtwdev, bool en)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
@@ -3340,18 +3584,18 @@ static void rtw89_mac_err_imr_ctrl(struct rtw89_dev *rtwdev, bool en)
en ? CMAC1_ERR_IMR_EN : CMAC1_ERR_IMR_DIS);
}
-static int rtw89_mac_dbcc_enable(struct rtw89_dev *rtwdev, bool enable)
+static int dbcc_enable_ax(struct rtw89_dev *rtwdev, bool enable)
{
int ret = 0;
if (enable) {
- ret = band1_enable(rtwdev);
+ ret = band1_enable_ax(rtwdev);
if (ret) {
rtw89_err(rtwdev, "[ERR] band1_enable %d\n", ret);
return ret;
}
- ret = rtw89_mac_enable_imr(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL);
+ ret = enable_imr_ax(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL);
if (ret) {
rtw89_err(rtwdev, "[ERR] enable CMAC1 IMR %d\n", ret);
return ret;
@@ -3364,7 +3608,7 @@ static int rtw89_mac_dbcc_enable(struct rtw89_dev *rtwdev, bool enable)
return 0;
}
-static int set_host_rpr(struct rtw89_dev *rtwdev)
+static int set_host_rpr_ax(struct rtw89_dev *rtwdev)
{
if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) {
rtw89_write32_mask(rtwdev, R_AX_WDRLS_CFG,
@@ -3384,46 +3628,46 @@ static int set_host_rpr(struct rtw89_dev *rtwdev)
return 0;
}
-static int rtw89_mac_trx_init(struct rtw89_dev *rtwdev)
+static int trx_init_ax(struct rtw89_dev *rtwdev)
{
enum rtw89_qta_mode qta_mode = rtwdev->mac.qta_mode;
int ret;
- ret = dmac_init(rtwdev, 0);
+ ret = dmac_init_ax(rtwdev, 0);
if (ret) {
rtw89_err(rtwdev, "[ERR]DMAC init %d\n", ret);
return ret;
}
- ret = cmac_init(rtwdev, 0);
+ ret = cmac_init_ax(rtwdev, 0);
if (ret) {
rtw89_err(rtwdev, "[ERR]CMAC%d init %d\n", 0, ret);
return ret;
}
- if (is_qta_dbcc(rtwdev, qta_mode)) {
- ret = rtw89_mac_dbcc_enable(rtwdev, true);
+ if (rtw89_mac_is_qta_dbcc(rtwdev, qta_mode)) {
+ ret = dbcc_enable_ax(rtwdev, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]dbcc_enable init %d\n", ret);
return ret;
}
}
- ret = rtw89_mac_enable_imr(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
+ ret = enable_imr_ax(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
if (ret) {
rtw89_err(rtwdev, "[ERR] enable DMAC IMR %d\n", ret);
return ret;
}
- ret = rtw89_mac_enable_imr(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
+ ret = enable_imr_ax(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
if (ret) {
rtw89_err(rtwdev, "[ERR] to enable CMAC0 IMR %d\n", ret);
return ret;
}
- rtw89_mac_err_imr_ctrl(rtwdev, true);
+ err_imr_ctrl_ax(rtwdev, true);
- ret = set_host_rpr(rtwdev);
+ ret = set_host_rpr_ax(rtwdev);
if (ret) {
rtw89_err(rtwdev, "[ERR] set host rpr %d\n", ret);
return ret;
@@ -3514,11 +3758,10 @@ static int rtw89_mac_enable_cpu_ax(struct rtw89_dev *rtwdev, u8 boot_reason,
return 0;
}
-static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev)
+static void rtw89_mac_hci_func_en_ax(struct rtw89_dev *rtwdev)
{
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
u32 val;
- int ret;
if (chip_id == RTL8852C)
val = B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_DISPATCHER_EN |
@@ -3527,6 +3770,12 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev)
val = B_AX_MAC_FUNC_EN | B_AX_DMAC_FUNC_EN | B_AX_DISPATCHER_EN |
B_AX_PKT_BUF_EN;
rtw89_write32(rtwdev, R_AX_DMAC_FUNC_EN, val);
+}
+
+static void rtw89_mac_dmac_func_pre_en_ax(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
+ u32 val;
if (chip_id == RTL8851B)
val = B_AX_DISPATCHER_CLK_EN | B_AX_AXIDMA_CLK_EN;
@@ -3535,7 +3784,7 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev)
rtw89_write32(rtwdev, R_AX_DMAC_CLK_EN, val);
if (chip_id != RTL8852C)
- goto dle;
+ return;
val = rtw89_read32(rtwdev, R_AX_HAXI_INIT_CFG1);
val &= ~(B_AX_DMA_MODE_MASK | B_AX_STOP_AXI_MST);
@@ -3550,15 +3799,23 @@ static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev)
B_AX_STOP_CH12 | B_AX_STOP_ACH2);
rtw89_write32_clr(rtwdev, R_AX_HAXI_DMA_STOP2, B_AX_STOP_CH10 | B_AX_STOP_CH11);
rtw89_write32_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_AXIDMA_EN);
+}
+
+static int rtw89_mac_dmac_pre_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ int ret;
+
+ mac->hci_func_en(rtwdev);
+ mac->dmac_func_pre_en(rtwdev);
-dle:
- ret = dle_init(rtwdev, RTW89_QTA_DLFW, rtwdev->mac.qta_mode);
+ ret = rtw89_mac_dle_init(rtwdev, RTW89_QTA_DLFW, rtwdev->mac.qta_mode);
if (ret) {
rtw89_err(rtwdev, "[ERR]DLE pre init %d\n", ret);
return ret;
}
- ret = hfc_init(rtwdev, true, false, true);
+ ret = rtw89_mac_hfc_init(rtwdev, true, false, true);
if (ret) {
rtw89_err(rtwdev, "[ERR]HCI FC pre init %d\n", ret);
return ret;
@@ -3632,6 +3889,7 @@ int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb)
int rtw89_mac_init(struct rtw89_dev *rtwdev)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_chip_info *chip = rtwdev->chip;
bool include_bb = !!chip->bbmcu_nr;
int ret;
@@ -3644,11 +3902,11 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev)
if (ret)
goto fail;
- ret = rtw89_mac_sys_init(rtwdev);
+ ret = mac->sys_init(rtwdev);
if (ret)
goto fail;
- ret = rtw89_mac_trx_init(rtwdev);
+ ret = mac->trx_init(rtwdev);
if (ret)
goto fail;
@@ -3747,6 +4005,50 @@ static const struct rtw89_port_reg rtw89_port_base_ax = {
R_AX_PORT_HGQ_WINDOW_CFG + 3},
};
+static void rtw89_mac_check_packet_ctrl(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif, u8 type)
+{
+ u8 mask = B_AX_PTCL_DBG_INFO_MASK_BY_PORT(rtwvif->port);
+ u32 reg_info, reg_ctrl;
+ u32 val;
+ int ret;
+
+ reg_info = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_DBG_INFO, rtwvif->mac_idx);
+ reg_ctrl = rtw89_mac_reg_by_idx(rtwdev, R_AX_PTCL_DBG, rtwvif->mac_idx);
+
+ rtw89_write32_mask(rtwdev, reg_ctrl, B_AX_PTCL_DBG_SEL_MASK, type);
+ rtw89_write32_set(rtwdev, reg_ctrl, B_AX_PTCL_DBG_EN);
+ fsleep(100);
+
+ ret = read_poll_timeout(rtw89_read32_mask, val, val == 0, 1000, 100000,
+ true, rtwdev, reg_info, mask);
+ if (ret)
+ rtw89_warn(rtwdev, "Polling beacon packet empty fail\n");
+}
+
+static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ const struct rtw89_port_reg *p = mac->port_base;
+
+ rtw89_write32_set(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port));
+ rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK, 1);
+ rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_area, B_AX_BCN_MSK_AREA_MASK, 0);
+ rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 0);
+ rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK, 2);
+ rtw89_write16_port_mask(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK, 1);
+ rtw89_write32_port_mask(rtwdev, rtwvif, p->bcn_space, B_AX_BCN_SPACE_MASK, 1);
+ rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN);
+
+ rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM0);
+ if (rtwvif->port == RTW89_PORT_0)
+ rtw89_mac_check_packet_ctrl(rtwdev, rtwvif, AX_PTCL_DBG_BCNQ_NUM1);
+
+ rtw89_write32_clr(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port));
+ rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN);
+ fsleep(2);
+}
+
#define BCN_INTERVAL 100
#define BCN_ERLY_DEF 160
#define BCN_SETUP_DEF 2
@@ -3762,21 +4064,36 @@ static void rtw89_mac_port_cfg_func_sw(struct rtw89_dev *rtwdev,
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif);
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ bool need_backup = false;
+ u32 backup_val;
if (!rtw89_read32_port_mask(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN))
return;
- rtw89_write32_port_clr(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK);
- rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 1);
- rtw89_write16_port_clr(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK);
- rtw89_write16_port_clr(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK);
+ if (chip->chip_id == RTL8852A && rtwvif->port != RTW89_PORT_0) {
+ need_backup = true;
+ backup_val = rtw89_read32_port(rtwdev, rtwvif, p->tbtt_prohib);
+ }
- msleep(vif->bss_conf.beacon_int + 1);
+ if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
+ rtw89_mac_bcn_drop(rtwdev, rtwvif);
+
+ if (chip->chip_id == RTL8852A) {
+ rtw89_write32_port_clr(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_SETUP_MASK);
+ rtw89_write32_port_mask(rtwdev, rtwvif, p->tbtt_prohib, B_AX_TBTT_HOLD_MASK, 1);
+ rtw89_write16_port_clr(rtwdev, rtwvif, p->tbtt_early, B_AX_TBTTERLY_MASK);
+ rtw89_write16_port_clr(rtwdev, rtwvif, p->bcn_early, B_AX_BCNERLY_MASK);
+ }
+ msleep(vif->bss_conf.beacon_int + 1);
rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_PORT_FUNC_EN |
B_AX_BRK_SETUP);
rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSFTR_RST);
rtw89_write32_port(rtwdev, rtwvif, p->bcn_cnt_tmr, 0);
+
+ if (need_backup)
+ rtw89_write32_port(rtwdev, rtwvif, p->tbtt_prohib, backup_val);
}
static void rtw89_mac_port_cfg_tx_rpt(struct rtw89_dev *rtwdev,
@@ -3857,12 +4174,10 @@ static void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev,
}
static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev,
- struct rtw89_vif *rtwvif)
+ struct rtw89_vif *rtwvif, bool en)
{
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
const struct rtw89_port_reg *p = mac->port_base;
- bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE ||
- rtwvif->net_type == RTW89_NET_TYPE_AD_HOC;
if (en)
rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN);
@@ -3870,6 +4185,24 @@ static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev,
rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_BCNTX_EN);
}
+static void rtw89_mac_port_cfg_tx_sw_by_nettype(struct rtw89_dev *rtwdev,
+ struct rtw89_vif *rtwvif)
+{
+ bool en = rtwvif->net_type == RTW89_NET_TYPE_AP_MODE ||
+ rtwvif->net_type == RTW89_NET_TYPE_AD_HOC;
+
+ rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en);
+}
+
+void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en)
+{
+ struct rtw89_vif *rtwvif;
+
+ rtw89_for_each_rtwvif(rtwdev, rtwvif)
+ if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE)
+ rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif, en);
+}
+
static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev,
struct rtw89_vif *rtwvif)
{
@@ -4176,7 +4509,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif);
rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif);
rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif);
- rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif);
+ rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif);
rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif);
rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif);
rtw89_mac_port_cfg_hiq_dtim(rtwdev, rtwvif);
@@ -4261,7 +4594,7 @@ void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
{
- rtw89_mac_port_cfg_func_en(rtwdev, rtwvif, false);
+ rtw89_mac_port_cfg_func_sw(rtwdev, rtwvif);
}
int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
@@ -4338,8 +4671,10 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
switch (reason) {
case RTW89_SCAN_LEAVE_CH_NOTIFY:
- if (rtw89_is_op_chan(rtwdev, band, chan))
+ if (rtw89_is_op_chan(rtwdev, band, chan)) {
+ rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, false);
ieee80211_stop_queues(rtwdev->hw);
+ }
return;
case RTW89_SCAN_END_SCAN_NOTIFY:
if (rtwvif && rtwvif->scan_req &&
@@ -4357,6 +4692,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
if (rtw89_is_op_chan(rtwdev, band, chan)) {
rtw89_assign_entity_chan(rtwdev, rtwvif->sub_entity_idx,
&rtwdev->scan_info.op_chan);
+ rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true);
ieee80211_wake_queues(rtwdev->hw);
} else {
rtw89_chan_create(&new, chan, chan, band,
@@ -5171,7 +5507,8 @@ bool rtw89_mac_get_ctrl_path(struct rtw89_dev *rtwdev)
if (chip->chip_id == RTL8852C)
return false;
- else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B)
+ else if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B ||
+ chip->chip_id == RTL8851B)
val = rtw89_read8_mask(rtwdev, R_AX_SYS_SDIO_CTRL + 3,
B_AX_LTE_MUX_CTRL_PATH >> 24);
@@ -5616,7 +5953,8 @@ int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev,
return 0;
}
-int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask)
+static
+int rtw89_mac_write_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask)
{
u32 val32;
int ret;
@@ -5638,9 +5976,9 @@ int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask
return 0;
}
-EXPORT_SYMBOL(rtw89_mac_write_xtal_si);
-int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
+static
+int rtw89_mac_read_xtal_si_ax(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
{
u32 val32;
int ret;
@@ -5663,7 +6001,6 @@ int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
return 0;
}
-EXPORT_SYMBOL(rtw89_mac_read_xtal_si);
static
void rtw89_mac_pkt_drop_sta(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta)
@@ -5713,6 +6050,7 @@ void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif)
int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
enum rtw89_mac_idx band)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
struct rtw89_pkt_drop_params params = {0};
bool empty;
int i, ret = 0, try_cnt = 3;
@@ -5721,7 +6059,7 @@ int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
params.sel = RTW89_PKT_DROP_SEL_BAND_ONCE;
for (i = 0; i < try_cnt; i++) {
- ret = read_poll_timeout(mac_is_txq_empty, empty, empty, 50,
+ ret = read_poll_timeout(mac->is_txq_empty, empty, empty, 50,
50000, false, rtwdev);
if (ret && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw))
rtw89_fw_h2c_pkt_drop(rtwdev, &params);
@@ -5769,13 +6107,44 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = {
B_AX_BFMEE_HE_NDPA_EN,
},
+ .check_mac_en = rtw89_mac_check_mac_en_ax,
+ .sys_init = sys_init_ax,
+ .trx_init = trx_init_ax,
+ .hci_func_en = rtw89_mac_hci_func_en_ax,
+ .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_ax,
+ .dle_func_en = dle_func_en_ax,
+ .dle_clk_en = dle_clk_en_ax,
.bf_assoc = rtw89_mac_bf_assoc_ax,
+ .typ_fltr_opt = rtw89_mac_typ_fltr_opt_ax,
+
+ .dle_mix_cfg = dle_mix_cfg_ax,
+ .chk_dle_rdy = chk_dle_rdy_ax,
+ .dle_buf_req = dle_buf_req_ax,
+ .hfc_func_en = hfc_func_en_ax,
+ .hfc_h2c_cfg = hfc_h2c_cfg_ax,
+ .hfc_mix_cfg = hfc_mix_cfg_ax,
+ .hfc_get_mix_info = hfc_get_mix_info_ax,
+ .wde_quota_cfg = wde_quota_cfg_ax,
+ .ple_quota_cfg = ple_quota_cfg_ax,
+ .set_cpuio = set_cpuio_ax,
+
.disable_cpu = rtw89_mac_disable_cpu_ax,
.fwdl_enable_wcpu = rtw89_mac_enable_cpu_ax,
.fwdl_get_status = rtw89_fw_get_rdy_ax,
.fwdl_check_path_ready = rtw89_fwdl_check_path_ready_ax,
+ .parse_efuse_map = rtw89_parse_efuse_map_ax,
+ .parse_phycap_map = rtw89_parse_phycap_map_ax,
+ .cnv_efuse_state = rtw89_cnv_efuse_state_ax,
.get_txpwr_cr = rtw89_mac_get_txpwr_cr_ax,
+
+ .write_xtal_si = rtw89_mac_write_xtal_si_ax,
+ .read_xtal_si = rtw89_mac_read_xtal_si_ax,
+
+ .dump_qta_lost = rtw89_mac_dump_qta_lost_ax,
+ .dump_err_status = rtw89_mac_dump_err_status_ax,
+
+ .is_txq_empty = mac_is_txq_empty_ax,
};
EXPORT_SYMBOL(rtw89_mac_gen_ax);
diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h
index c11c904f87fe..ed98b49809a4 100644
--- a/drivers/net/wireless/realtek/rtw89/mac.h
+++ b/drivers/net/wireless/realtek/rtw89/mac.h
@@ -10,6 +10,7 @@
#define MAC_MEM_DUMP_PAGE_SIZE 0x40000
#define ADDR_CAM_ENT_SIZE 0x40
+#define ADDR_CAM_ENT_SHORT_SIZE 0x20
#define BSSID_CAM_ENT_SIZE 0x08
#define HFC_PAGE_UNIT 64
#define RPWM_TRY_CNT 3
@@ -536,6 +537,9 @@ enum rtw89_mac_bf_rrsc_rate {
#define B_CMAC1_MGQ_NO_PWRSAV BIT(11)
#define B_CMAC1_CPUMGQ BIT(12)
+#define B_CMAC0_MGQ_NORMAL_BE BIT(2)
+#define B_CMAC1_MGQ_NORMAL_BE BIT(30)
+
#define QEMP_ACQ_GRP_MACID_NUM 8
#define QEMP_ACQ_GRP_QSEL_SH 4
#define QEMP_ACQ_GRP_QSEL_MASK 0xF
@@ -649,6 +653,22 @@ struct rtw89_mac_dle_dfi_qempty {
u32 qempty;
};
+enum rtw89_mac_dle_rsvd_qt_type {
+ DLE_RSVD_QT_MPDU_INFO,
+ DLE_RSVD_QT_B0_CSI,
+ DLE_RSVD_QT_B1_CSI,
+ DLE_RSVD_QT_B0_LMR,
+ DLE_RSVD_QT_B1_LMR,
+ DLE_RSVD_QT_B0_FTM,
+ DLE_RSVD_QT_B1_FTM,
+};
+
+struct rtw89_mac_dle_rsvd_qt_cfg {
+ u16 pktid;
+ u16 pg_num;
+ u32 size;
+};
+
enum rtw89_mac_error_scenario {
RTW89_RXI300_ERROR = 1,
RTW89_WCPU_CPU_EXCEPTION = 2,
@@ -817,27 +837,37 @@ enum mac_ax_err_info {
struct rtw89_mac_size_set {
const struct rtw89_hfc_prec_cfg hfc_preccfg_pcie;
+ const struct rtw89_hfc_prec_cfg hfc_prec_cfg_c0;
+ const struct rtw89_hfc_prec_cfg hfc_prec_cfg_c2;
const struct rtw89_dle_size wde_size0;
+ const struct rtw89_dle_size wde_size0_v1;
const struct rtw89_dle_size wde_size4;
+ const struct rtw89_dle_size wde_size4_v1;
const struct rtw89_dle_size wde_size6;
const struct rtw89_dle_size wde_size7;
const struct rtw89_dle_size wde_size9;
const struct rtw89_dle_size wde_size18;
const struct rtw89_dle_size wde_size19;
const struct rtw89_dle_size ple_size0;
+ const struct rtw89_dle_size ple_size0_v1;
+ const struct rtw89_dle_size ple_size3_v1;
const struct rtw89_dle_size ple_size4;
const struct rtw89_dle_size ple_size6;
const struct rtw89_dle_size ple_size8;
const struct rtw89_dle_size ple_size18;
const struct rtw89_dle_size ple_size19;
const struct rtw89_wde_quota wde_qt0;
+ const struct rtw89_wde_quota wde_qt0_v1;
const struct rtw89_wde_quota wde_qt4;
const struct rtw89_wde_quota wde_qt6;
const struct rtw89_wde_quota wde_qt7;
const struct rtw89_wde_quota wde_qt17;
const struct rtw89_wde_quota wde_qt18;
+ const struct rtw89_ple_quota ple_qt0;
+ const struct rtw89_ple_quota ple_qt1;
const struct rtw89_ple_quota ple_qt4;
const struct rtw89_ple_quota ple_qt5;
+ const struct rtw89_ple_quota ple_qt9;
const struct rtw89_ple_quota ple_qt13;
const struct rtw89_ple_quota ple_qt18;
const struct rtw89_ple_quota ple_qt44;
@@ -848,6 +878,10 @@ struct rtw89_mac_size_set {
const struct rtw89_ple_quota ple_qt_52a_wow;
const struct rtw89_ple_quota ple_qt_52b_wow;
const struct rtw89_ple_quota ple_qt_51b_wow;
+ const struct rtw89_rsvd_quota ple_rsvd_qt0;
+ const struct rtw89_rsvd_quota ple_rsvd_qt1;
+ const struct rtw89_dle_rsvd_size rsvd0_size0;
+ const struct rtw89_dle_rsvd_size rsvd1_size0;
};
extern const struct rtw89_mac_size_set rtw89_mac_size;
@@ -864,18 +898,60 @@ struct rtw89_mac_gen_def {
struct rtw89_reg_def muedca_ctrl;
struct rtw89_reg_def bfee_ctrl;
+ int (*check_mac_en)(struct rtw89_dev *rtwdev, u8 band,
+ enum rtw89_mac_hwmod_sel sel);
+ int (*sys_init)(struct rtw89_dev *rtwdev);
+ int (*trx_init)(struct rtw89_dev *rtwdev);
+ void (*hci_func_en)(struct rtw89_dev *rtwdev);
+ void (*dmac_func_pre_en)(struct rtw89_dev *rtwdev);
+ void (*dle_func_en)(struct rtw89_dev *rtwdev, bool enable);
+ void (*dle_clk_en)(struct rtw89_dev *rtwdev, bool enable);
void (*bf_assoc)(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+ int (*typ_fltr_opt)(struct rtw89_dev *rtwdev,
+ enum rtw89_machdr_frame_type type,
+ enum rtw89_mac_fwd_target fwd_target,
+ u8 mac_idx);
+
+ int (*dle_mix_cfg)(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg);
+ int (*chk_dle_rdy)(struct rtw89_dev *rtwdev, bool wde_or_ple);
+ int (*dle_buf_req)(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id);
+ void (*hfc_func_en)(struct rtw89_dev *rtwdev, bool en, bool h2c_en);
+ void (*hfc_h2c_cfg)(struct rtw89_dev *rtwdev);
+ void (*hfc_mix_cfg)(struct rtw89_dev *rtwdev);
+ void (*hfc_get_mix_info)(struct rtw89_dev *rtwdev);
+ void (*wde_quota_cfg)(struct rtw89_dev *rtwdev,
+ const struct rtw89_wde_quota *min_cfg,
+ const struct rtw89_wde_quota *max_cfg,
+ u16 ext_wde_min_qt_wcpu);
+ void (*ple_quota_cfg)(struct rtw89_dev *rtwdev,
+ const struct rtw89_ple_quota *min_cfg,
+ const struct rtw89_ple_quota *max_cfg);
+ int (*set_cpuio)(struct rtw89_dev *rtwdev,
+ struct rtw89_cpuio_ctrl *ctrl_para, bool wd);
+
void (*disable_cpu)(struct rtw89_dev *rtwdev);
int (*fwdl_enable_wcpu)(struct rtw89_dev *rtwdev, u8 boot_reason,
bool dlfw, bool include_bb);
u8 (*fwdl_get_status)(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type);
int (*fwdl_check_path_ready)(struct rtw89_dev *rtwdev, bool h2c_or_fwdl);
+ int (*parse_efuse_map)(struct rtw89_dev *rtwdev);
+ int (*parse_phycap_map)(struct rtw89_dev *rtwdev);
+ int (*cnv_efuse_state)(struct rtw89_dev *rtwdev, bool idle);
bool (*get_txpwr_cr)(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx,
u32 reg_base, u32 *cr);
+
+ int (*write_xtal_si)(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask);
+ int (*read_xtal_si)(struct rtw89_dev *rtwdev, u8 offset, u8 *val);
+
+ void (*dump_qta_lost)(struct rtw89_dev *rtwdev);
+ void (*dump_err_status)(struct rtw89_dev *rtwdev,
+ enum mac_ax_err_info err);
+
+ bool (*is_txq_empty)(struct rtw89_dev *rtwdev);
};
extern const struct rtw89_mac_gen_def rtw89_mac_gen_ax;
@@ -977,10 +1053,31 @@ rtw89_write32_port_set(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
void rtw89_mac_pwr_off(struct rtw89_dev *rtwdev);
int rtw89_mac_partial_init(struct rtw89_dev *rtwdev, bool include_bb);
int rtw89_mac_init(struct rtw89_dev *rtwdev);
+int rtw89_mac_dle_init(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode,
+ enum rtw89_qta_mode ext_mode);
+int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_en);
+int rtw89_mac_preload_init(struct rtw89_dev *rtwdev, enum rtw89_mac_idx mac_idx,
+ enum rtw89_qta_mode mode);
+bool rtw89_mac_is_qta_dbcc(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode);
+static inline
int rtw89_mac_check_mac_en(struct rtw89_dev *rtwdev, u8 band,
- enum rtw89_mac_hwmod_sel sel);
+ enum rtw89_mac_hwmod_sel sel)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ return mac->check_mac_en(rtwdev, band, sel);
+}
+
int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val);
int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val);
+int rtw89_mac_dle_dfi_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_ctrl *ctrl);
+int rtw89_mac_dle_dfi_quota_cfg(struct rtw89_dev *rtwdev,
+ struct rtw89_mac_dle_dfi_quota *quota);
+void rtw89_mac_dump_dmac_err_status(struct rtw89_dev *rtwdev);
+int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev,
+ struct rtw89_mac_dle_dfi_qempty *qempty);
+void rtw89_mac_dump_l0_to_l1(struct rtw89_dev *rtwdev,
+ enum mac_ax_err_info err);
int rtw89_mac_add_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev,
@@ -992,6 +1089,7 @@ int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif,
void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif);
void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
+void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en);
int rtw89_mac_remove_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *vif);
int rtw89_mac_enable_bb_rf(struct rtw89_dev *rtwdev);
int rtw89_mac_disable_bb_rf(struct rtw89_dev *rtwdev);
@@ -1010,6 +1108,23 @@ static inline int rtw89_chip_disable_bb_rf(struct rtw89_dev *rtwdev)
return chip->ops->disable_bb_rf(rtwdev);
}
+static inline int rtw89_chip_reset_bb_rf(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ if (rtwdev->chip->chip_gen != RTW89_CHIP_AX)
+ return 0;
+
+ ret = rtw89_chip_disable_bb_rf(rtwdev);
+ if (ret)
+ return ret;
+ ret = rtw89_chip_enable_bb_rf(rtwdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev);
int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err);
bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func);
@@ -1185,6 +1300,7 @@ enum rtw89_mac_xtal_si_offset {
#define XTAL_SC_XI_MASK GENMASK(7, 0)
XTAL_SI_XTAL_SC_XO = 0x05,
#define XTAL_SC_XO_MASK GENMASK(7, 0)
+ XTAL_SI_XREF_MODE = 0x0B,
XTAL_SI_PWR_CUT = 0x10,
#define XTAL_SI_SMALL_PWR_CUT BIT(0)
#define XTAL_SI_BIG_PWR_CUT BIT(1)
@@ -1194,6 +1310,8 @@ enum rtw89_mac_xtal_si_offset {
#define XTAL_SI_LDO_LPS GENMASK(6, 4)
XTAL_SI_XTAL_XMD_4 = 0x26,
#define XTAL_SI_LPS_CAP GENMASK(3, 0)
+ XTAL_SI_XREF_RF1 = 0x2D,
+ XTAL_SI_XREF_RF2 = 0x2E,
XTAL_SI_CV = 0x41,
#define XTAL_SI_ACV_MASK GENMASK(3, 0)
XTAL_SI_LOW_ADDR = 0x62,
@@ -1221,20 +1339,34 @@ enum rtw89_mac_xtal_si_offset {
XTAL_SI_SRAM_CTRL = 0xA1,
#define XTAL_SI_SRAM_DIS BIT(1)
#define FULL_BIT_MASK GENMASK(7, 0)
+ XTAL_SI_PLL = 0xE0,
+ XTAL_SI_PLL_1 = 0xE1,
};
-int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask);
-int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val);
+static inline
+int rtw89_mac_write_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ return mac->write_xtal_si(rtwdev, offset, val, mask);
+}
+
+static inline
+int rtw89_mac_read_xtal_si(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
+{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+
+ return mac->read_xtal_si(rtwdev, offset, val);
+}
+
void rtw89_mac_pkt_drop_vif(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif);
-int rtw89_mac_dle_buf_req(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id);
-int rtw89_mac_set_cpuio(struct rtw89_dev *rtwdev,
- struct rtw89_cpuio_ctrl *ctrl_para, bool wd);
-int rtw89_mac_typ_fltr_opt(struct rtw89_dev *rtwdev,
- enum rtw89_machdr_frame_type type,
- enum rtw89_mac_fwd_target fwd_target, u8 mac_idx);
int rtw89_mac_resize_ple_rx_quota(struct rtw89_dev *rtwdev, bool wow);
int rtw89_mac_ptk_drop_by_band_and_wait(struct rtw89_dev *rtwdev,
enum rtw89_mac_idx band);
void rtw89_mac_hw_mgnt_sec(struct rtw89_dev *rtwdev, bool wow);
+int rtw89_mac_dle_quota_change(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode);
+int rtw89_mac_get_dle_rsvd_qt_cfg(struct rtw89_dev *rtwdev,
+ enum rtw89_mac_dle_rsvd_qt_type type,
+ struct rtw89_mac_dle_rsvd_qt_cfg *cfg);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 31d1f7891675..93889d2fface 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -226,6 +226,7 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,
{
struct rtw89_dev *rtwdev = hw->priv;
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
+ u32 rx_fltr;
mutex_lock(&rtwdev->mutex);
rtw89_leave_ps_mode(rtwdev);
@@ -272,16 +273,29 @@ static void rtw89_ops_configure_filter(struct ieee80211_hw *hw,
}
}
+ rx_fltr = rtwdev->hal.rx_fltr;
+
+ /* mac80211 doesn't configure filter when HW scan, driver need to
+ * set by itself. However, during P2P scan might have configure
+ * filter to overwrite filter that HW scan needed, so we need to
+ * check scan and append related filter
+ */
+ if (rtwdev->scanning) {
+ rx_fltr &= ~B_AX_A_BCN_CHK_EN;
+ rx_fltr &= ~B_AX_A_BC;
+ rx_fltr &= ~B_AX_A_A1_MATCH;
+ }
+
rtw89_write32_mask(rtwdev,
rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_0),
B_AX_RX_FLTR_CFG_MASK,
- rtwdev->hal.rx_fltr);
+ rx_fltr);
if (!rtwdev->dbcc_en)
goto out;
rtw89_write32_mask(rtwdev,
rtw89_mac_reg_by_idx(rtwdev, mac->rx_fltr, RTW89_MAC_1),
B_AX_RX_FLTR_CFG_MASK,
- rtwdev->hal.rx_fltr);
+ rx_fltr);
out:
mutex_unlock(&rtwdev->mutex);
@@ -477,6 +491,9 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw,
return -EOPNOTSUPP;
}
+ if (rtwdev->scanning)
+ rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif);
+
ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid);
rtw89_cam_bssid_changed(rtwdev, rtwvif);
rtw89_mac_port_update(rtwdev, rtwvif);
diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c
index 3278f241db6e..be30c9346293 100644
--- a/drivers/net/wireless/realtek/rtw89/mac_be.c
+++ b/drivers/net/wireless/realtek/rtw89/mac_be.c
@@ -3,6 +3,7 @@
*/
#include "debug.h"
+#include "efuse.h"
#include "fw.h"
#include "mac.h"
#include "reg.h"
@@ -56,6 +57,369 @@ static const struct rtw89_port_reg rtw89_port_base_be = {
R_BE_PORT_HGQ_WINDOW_CFG + 3},
};
+static int rtw89_mac_check_mac_en_be(struct rtw89_dev *rtwdev, u8 mac_idx,
+ enum rtw89_mac_hwmod_sel sel)
+{
+ if (sel == RTW89_DMAC_SEL &&
+ test_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags))
+ return 0;
+ if (sel == RTW89_CMAC_SEL && mac_idx == RTW89_MAC_0 &&
+ test_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags))
+ return 0;
+ if (sel == RTW89_CMAC_SEL && mac_idx == RTW89_MAC_1 &&
+ test_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags))
+ return 0;
+
+ return -EFAULT;
+}
+
+static bool is_qta_poh(struct rtw89_dev *rtwdev)
+{
+ return rtwdev->hci.type == RTW89_HCI_TYPE_PCIE;
+}
+
+static void hfc_get_mix_info_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param;
+ struct rtw89_hfc_prec_cfg *prec_cfg = &param->prec_cfg;
+ struct rtw89_hfc_pub_cfg *pub_cfg = &param->pub_cfg;
+ struct rtw89_hfc_pub_info *info = &param->pub_info;
+ u32 val;
+
+ val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO1);
+ info->g0_used = u32_get_bits(val, B_BE_G0_USE_PG_MASK);
+ info->g1_used = u32_get_bits(val, B_BE_G1_USE_PG_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO3);
+ info->g0_aval = u32_get_bits(val, B_BE_G0_AVAL_PG_MASK);
+ info->g1_aval = u32_get_bits(val, B_BE_G1_AVAL_PG_MASK);
+ info->pub_aval = u32_get_bits(rtw89_read32(rtwdev, R_BE_PUB_PAGE_INFO2),
+ B_BE_PUB_AVAL_PG_MASK);
+ info->wp_aval = u32_get_bits(rtw89_read32(rtwdev, R_BE_WP_PAGE_INFO1),
+ B_BE_WP_AVAL_PG_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL);
+ param->en = !!(val & B_BE_HCI_FC_EN);
+ param->h2c_en = !!(val & B_BE_HCI_FC_CH12_EN);
+ param->mode = u32_get_bits(val, B_BE_HCI_FC_MODE_MASK);
+ prec_cfg->ch011_full_cond = u32_get_bits(val, B_BE_HCI_FC_WD_FULL_COND_MASK);
+ prec_cfg->h2c_full_cond = u32_get_bits(val, B_BE_HCI_FC_CH12_FULL_COND_MASK);
+ prec_cfg->wp_ch07_full_cond =
+ u32_get_bits(val, B_BE_HCI_FC_WP_CH07_FULL_COND_MASK);
+ prec_cfg->wp_ch811_full_cond =
+ u32_get_bits(val, B_BE_HCI_FC_WP_CH811_FULL_COND_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_CH_PAGE_CTRL);
+ prec_cfg->ch011_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH011_V1_MASK);
+ prec_cfg->h2c_prec = u32_get_bits(val, B_BE_PREC_PAGE_CH12_V1_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL2);
+ pub_cfg->pub_max = u32_get_bits(val, B_BE_PUBPG_ALL_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL1);
+ prec_cfg->wp_ch07_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH07_MASK);
+ prec_cfg->wp_ch811_prec = u32_get_bits(val, B_BE_PREC_PAGE_WP_CH811_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_WP_PAGE_CTRL2);
+ pub_cfg->wp_thrd = u32_get_bits(val, B_BE_WP_THRD_MASK);
+
+ val = rtw89_read32(rtwdev, R_BE_PUB_PAGE_CTRL1);
+ pub_cfg->grp0 = u32_get_bits(val, B_BE_PUBPG_G0_MASK);
+ pub_cfg->grp1 = u32_get_bits(val, B_BE_PUBPG_G1_MASK);
+}
+
+static void hfc_h2c_cfg_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param;
+ const struct rtw89_hfc_prec_cfg *prec_cfg = &param->prec_cfg;
+ u32 val;
+
+ val = u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK);
+ rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val);
+}
+
+static void hfc_mix_cfg_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param;
+ const struct rtw89_hfc_prec_cfg *prec_cfg = &param->prec_cfg;
+ const struct rtw89_hfc_pub_cfg *pub_cfg = &param->pub_cfg;
+ u32 val;
+
+ val = u32_encode_bits(prec_cfg->ch011_prec, B_BE_PREC_PAGE_CH011_V1_MASK) |
+ u32_encode_bits(prec_cfg->h2c_prec, B_BE_PREC_PAGE_CH12_V1_MASK);
+ rtw89_write32(rtwdev, R_BE_CH_PAGE_CTRL, val);
+
+ val = u32_encode_bits(pub_cfg->pub_max, B_BE_PUBPG_ALL_MASK);
+ rtw89_write32(rtwdev, R_BE_PUB_PAGE_CTRL2, val);
+
+ val = u32_encode_bits(prec_cfg->wp_ch07_prec, B_BE_PREC_PAGE_WP_CH07_MASK) |
+ u32_encode_bits(prec_cfg->wp_ch811_prec, B_BE_PREC_PAGE_WP_CH811_MASK);
+ rtw89_write32(rtwdev, R_BE_WP_PAGE_CTRL1, val);
+
+ val = u32_replace_bits(rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL),
+ param->mode, B_BE_HCI_FC_MODE_MASK);
+ val = u32_replace_bits(val, prec_cfg->ch011_full_cond,
+ B_BE_HCI_FC_WD_FULL_COND_MASK);
+ val = u32_replace_bits(val, prec_cfg->h2c_full_cond,
+ B_BE_HCI_FC_CH12_FULL_COND_MASK);
+ val = u32_replace_bits(val, prec_cfg->wp_ch07_full_cond,
+ B_BE_HCI_FC_WP_CH07_FULL_COND_MASK);
+ val = u32_replace_bits(val, prec_cfg->wp_ch811_full_cond,
+ B_BE_HCI_FC_WP_CH811_FULL_COND_MASK);
+ rtw89_write32(rtwdev, R_BE_HCI_FC_CTRL, val);
+}
+
+static void hfc_func_en_be(struct rtw89_dev *rtwdev, bool en, bool h2c_en)
+{
+ struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param;
+ u32 val;
+
+ val = rtw89_read32(rtwdev, R_BE_HCI_FC_CTRL);
+ param->en = en;
+ param->h2c_en = h2c_en;
+ val = en ? (val | B_BE_HCI_FC_EN) : (val & ~B_BE_HCI_FC_EN);
+ val = h2c_en ? (val | B_BE_HCI_FC_CH12_EN) :
+ (val & ~B_BE_HCI_FC_CH12_EN);
+ rtw89_write32(rtwdev, R_BE_HCI_FC_CTRL, val);
+}
+
+static void dle_func_en_be(struct rtw89_dev *rtwdev, bool enable)
+{
+ if (enable)
+ rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN,
+ B_BE_DLE_WDE_EN | B_BE_DLE_PLE_EN);
+ else
+ rtw89_write32_clr(rtwdev, R_BE_DMAC_FUNC_EN,
+ B_BE_DLE_WDE_EN | B_BE_DLE_PLE_EN);
+}
+
+static void dle_clk_en_be(struct rtw89_dev *rtwdev, bool enable)
+{
+ if (enable)
+ rtw89_write32_set(rtwdev, R_BE_DMAC_CLK_EN,
+ B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN);
+ else
+ rtw89_write32_clr(rtwdev, R_BE_DMAC_CLK_EN,
+ B_BE_DLE_WDE_CLK_EN | B_BE_DLE_PLE_CLK_EN);
+}
+
+static int dle_mix_cfg_be(struct rtw89_dev *rtwdev, const struct rtw89_dle_mem *cfg)
+{
+ const struct rtw89_dle_size *wde_size_cfg, *ple_size_cfg;
+ u32 bound;
+ u32 val;
+
+ wde_size_cfg = cfg->wde_size;
+ ple_size_cfg = cfg->ple_size;
+
+ val = rtw89_read32(rtwdev, R_BE_WDE_PKTBUF_CFG);
+
+ switch (wde_size_cfg->pge_size) {
+ default:
+ case RTW89_WDE_PG_64:
+ val = u32_replace_bits(val, S_AX_WDE_PAGE_SEL_64,
+ B_BE_WDE_PAGE_SEL_MASK);
+ break;
+ case RTW89_WDE_PG_128:
+ val = u32_replace_bits(val, S_AX_WDE_PAGE_SEL_128,
+ B_BE_WDE_PAGE_SEL_MASK);
+ break;
+ case RTW89_WDE_PG_256:
+ rtw89_err(rtwdev, "[ERR]WDE DLE doesn't support 256 byte!\n");
+ return -EINVAL;
+ }
+
+ bound = wde_size_cfg->srt_ofst / DLE_BOUND_UNIT;
+ val = u32_replace_bits(val, bound, B_BE_WDE_START_BOUND_MASK);
+ val = u32_replace_bits(val, wde_size_cfg->lnk_pge_num,
+ B_BE_WDE_FREE_PAGE_NUM_MASK);
+ rtw89_write32(rtwdev, R_BE_WDE_PKTBUF_CFG, val);
+
+ val = rtw89_read32(rtwdev, R_BE_PLE_PKTBUF_CFG);
+
+ switch (ple_size_cfg->pge_size) {
+ default:
+ case RTW89_PLE_PG_64:
+ rtw89_err(rtwdev, "[ERR]PLE DLE doesn't support 64 byte!\n");
+ return -EINVAL;
+ case RTW89_PLE_PG_128:
+ val = u32_replace_bits(val, S_AX_PLE_PAGE_SEL_128,
+ B_BE_PLE_PAGE_SEL_MASK);
+ break;
+ case RTW89_PLE_PG_256:
+ val = u32_replace_bits(val, S_AX_PLE_PAGE_SEL_256,
+ B_BE_PLE_PAGE_SEL_MASK);
+ break;
+ }
+
+ bound = ple_size_cfg->srt_ofst / DLE_BOUND_UNIT;
+ val = u32_replace_bits(val, bound, B_BE_PLE_START_BOUND_MASK);
+ val = u32_replace_bits(val, ple_size_cfg->lnk_pge_num,
+ B_BE_PLE_FREE_PAGE_NUM_MASK);
+ rtw89_write32(rtwdev, R_BE_PLE_PKTBUF_CFG, val);
+
+ return 0;
+}
+
+static int chk_dle_rdy_be(struct rtw89_dev *rtwdev, bool wde_or_ple)
+{
+ u32 reg, mask;
+ u32 ini;
+
+ if (wde_or_ple) {
+ reg = R_AX_WDE_INI_STATUS;
+ mask = WDE_MGN_INI_RDY;
+ } else {
+ reg = R_AX_PLE_INI_STATUS;
+ mask = PLE_MGN_INI_RDY;
+ }
+
+ return read_poll_timeout(rtw89_read32, ini, (ini & mask) == mask, 1,
+ 2000, false, rtwdev, reg);
+}
+
+#define INVALID_QT_WCPU U16_MAX
+#define SET_QUOTA_VAL(_min_x, _max_x, _module, _idx) \
+ do { \
+ val = u32_encode_bits(_min_x, B_BE_ ## _module ## _Q ## _idx ## _MIN_SIZE_MASK) | \
+ u32_encode_bits(_max_x, B_BE_ ## _module ## _Q ## _idx ## _MAX_SIZE_MASK); \
+ rtw89_write32(rtwdev, \
+ R_BE_ ## _module ## _QTA ## _idx ## _CFG, \
+ val); \
+ } while (0)
+#define SET_QUOTA(_x, _module, _idx) \
+ SET_QUOTA_VAL(min_cfg->_x, max_cfg->_x, _module, _idx)
+
+static void wde_quota_cfg_be(struct rtw89_dev *rtwdev,
+ const struct rtw89_wde_quota *min_cfg,
+ const struct rtw89_wde_quota *max_cfg,
+ u16 ext_wde_min_qt_wcpu)
+{
+ u16 min_qt_wcpu = ext_wde_min_qt_wcpu != INVALID_QT_WCPU ?
+ ext_wde_min_qt_wcpu : min_cfg->wcpu;
+ u16 max_qt_wcpu = max(max_cfg->wcpu, min_qt_wcpu);
+ u32 val;
+
+ SET_QUOTA(hif, WDE, 0);
+ SET_QUOTA_VAL(min_qt_wcpu, max_qt_wcpu, WDE, 1);
+ SET_QUOTA_VAL(0, 0, WDE, 2);
+ SET_QUOTA(pkt_in, WDE, 3);
+ SET_QUOTA(cpu_io, WDE, 4);
+}
+
+static void ple_quota_cfg_be(struct rtw89_dev *rtwdev,
+ const struct rtw89_ple_quota *min_cfg,
+ const struct rtw89_ple_quota *max_cfg)
+{
+ u32 val;
+
+ SET_QUOTA(cma0_tx, PLE, 0);
+ SET_QUOTA(cma1_tx, PLE, 1);
+ SET_QUOTA(c2h, PLE, 2);
+ SET_QUOTA(h2c, PLE, 3);
+ SET_QUOTA(wcpu, PLE, 4);
+ SET_QUOTA(mpdu_proc, PLE, 5);
+ SET_QUOTA(cma0_dma, PLE, 6);
+ SET_QUOTA(cma1_dma, PLE, 7);
+ SET_QUOTA(bb_rpt, PLE, 8);
+ SET_QUOTA(wd_rel, PLE, 9);
+ SET_QUOTA(cpu_io, PLE, 10);
+ SET_QUOTA(tx_rpt, PLE, 11);
+ SET_QUOTA(h2d, PLE, 12);
+}
+
+static void rtw89_mac_hci_func_en_be(struct rtw89_dev *rtwdev)
+{
+ rtw89_write32_set(rtwdev, R_BE_HCI_FUNC_EN, B_BE_HCI_TXDMA_EN |
+ B_BE_HCI_RXDMA_EN);
+}
+
+static void rtw89_mac_dmac_func_pre_en_be(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1);
+
+ switch (rtwdev->hci.type) {
+ case RTW89_HCI_TYPE_PCIE:
+ val = u32_replace_bits(val, S_BE_DMA_MOD_PCIE_NO_DATA_CPU,
+ B_BE_DMA_MODE_MASK);
+ break;
+ case RTW89_HCI_TYPE_USB:
+ val = u32_replace_bits(val, S_BE_DMA_MOD_USB, B_BE_DMA_MODE_MASK);
+ val = (val & ~B_BE_STOP_AXI_MST) | B_BE_TXDMA_EN | B_BE_RXDMA_EN;
+ break;
+ case RTW89_HCI_TYPE_SDIO:
+ val = u32_replace_bits(val, S_BE_DMA_MOD_SDIO, B_BE_DMA_MODE_MASK);
+ val = (val & ~B_BE_STOP_AXI_MST) | B_BE_TXDMA_EN | B_BE_RXDMA_EN;
+ break;
+ default:
+ return;
+ }
+
+ rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val);
+
+ rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1,
+ B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 |
+ B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 |
+ B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 |
+ B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11 |
+ B_BE_STOP_CH12 | B_BE_STOP_CH13 | B_BE_STOP_CH14);
+
+ rtw89_write32_set(rtwdev, R_BE_DMAC_TABLE_CTRL, B_BE_DMAC_ADDR_MODE);
+}
+
+static
+int rtw89_mac_write_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 val, u8 mask)
+{
+ u32 val32;
+ int ret;
+
+ val32 = u32_encode_bits(offset, B_BE_WL_XTAL_SI_ADDR_MASK) |
+ u32_encode_bits(val, B_BE_WL_XTAL_SI_DATA_MASK) |
+ u32_encode_bits(mask, B_BE_WL_XTAL_SI_BITMASK_MASK) |
+ u32_encode_bits(XTAL_SI_NORMAL_WRITE, B_BE_WL_XTAL_SI_MODE_MASK) |
+ u32_encode_bits(0, B_BE_WL_XTAL_SI_CHIPID_MASK) |
+ B_BE_WL_XTAL_SI_CMD_POLL;
+ rtw89_write32(rtwdev, R_BE_WLAN_XTAL_SI_CTRL, val32);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_WL_XTAL_SI_CMD_POLL),
+ 50, 50000, false, rtwdev, R_BE_WLAN_XTAL_SI_CTRL);
+ if (ret) {
+ rtw89_warn(rtwdev, "xtal si not ready(W): offset=%x val=%x mask=%x\n",
+ offset, val, mask);
+ return ret;
+ }
+
+ return 0;
+}
+
+static
+int rtw89_mac_read_xtal_si_be(struct rtw89_dev *rtwdev, u8 offset, u8 *val)
+{
+ u32 val32;
+ int ret;
+
+ val32 = u32_encode_bits(offset, B_BE_WL_XTAL_SI_ADDR_MASK) |
+ u32_encode_bits(0x0, B_BE_WL_XTAL_SI_DATA_MASK) |
+ u32_encode_bits(0x0, B_BE_WL_XTAL_SI_BITMASK_MASK) |
+ u32_encode_bits(XTAL_SI_NORMAL_READ, B_BE_WL_XTAL_SI_MODE_MASK) |
+ u32_encode_bits(0, B_BE_WL_XTAL_SI_CHIPID_MASK) |
+ B_BE_WL_XTAL_SI_CMD_POLL;
+ rtw89_write32(rtwdev, R_BE_WLAN_XTAL_SI_CTRL, val32);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_WL_XTAL_SI_CMD_POLL),
+ 50, 50000, false, rtwdev, R_BE_WLAN_XTAL_SI_CTRL);
+ if (ret) {
+ rtw89_warn(rtwdev, "xtal si not ready(R): offset=%x\n", offset);
+ return ret;
+ }
+
+ *val = rtw89_read8(rtwdev, R_BE_WLAN_XTAL_SI_CTRL + 1);
+
+ return 0;
+}
+
static void rtw89_mac_disable_cpu_be(struct rtw89_dev *rtwdev)
{
u32 val32;
@@ -92,8 +456,6 @@ static int wcpu_on(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw)
u32 val32;
int ret;
- rtw89_write32_set(rtwdev, R_BE_UDM0, B_BE_UDM0_DBG_MODE_CTRL);
-
val32 = rtw89_read32(rtwdev, R_BE_HALT_C2H);
if (val32) {
rtw89_warn(rtwdev, "[SER] AON L2 Debug register not empty before Boot.\n");
@@ -117,6 +479,10 @@ static int wcpu_on(struct rtw89_dev *rtwdev, u8 boot_reason, bool dlfw)
rtw89_write32(rtwdev, R_BE_HALT_H2C_CTRL, 0);
rtw89_write32(rtwdev, R_BE_HALT_C2H_CTRL, 0);
+ val32 = rtw89_read32(rtwdev, R_BE_HISR0);
+ rtw89_write32(rtwdev, R_BE_HISR0, B_BE_HALT_C2H_INT);
+ rtw89_debug(rtwdev, RTW89_DBG_SER, "HISR0=0x%x\n", val32);
+
rtw89_write32_set(rtwdev, R_BE_SYS_CLK_CTRL, B_BE_CPU_CLK_EN);
rtw89_write32_clr(rtwdev, R_BE_SYS_CFG5,
B_BE_WDT_WAKE_PCIE_EN | B_BE_WDT_WAKE_USB_EN);
@@ -205,6 +571,1153 @@ static int rtw89_fwdl_check_path_ready_be(struct rtw89_dev *rtwdev,
rtwdev, R_BE_WCPU_FW_CTRL);
}
+static int dmac_func_en_be(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static int cmac_func_en_be(struct rtw89_dev *rtwdev, u8 mac_idx, bool en)
+{
+ u32 reg;
+
+ if (mac_idx > RTW89_MAC_1)
+ return -EINVAL;
+
+ if (mac_idx == RTW89_MAC_0)
+ return 0;
+
+ if (en) {
+ rtw89_write32_set(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP);
+ rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx);
+ rtw89_write32_set(rtwdev, reg, B_BE_CK_EN_SET);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx);
+ rtw89_write32_set(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET);
+
+ set_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags);
+ } else {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CMAC_FUNC_EN, mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_BE_CMAC_FUNC_EN_SET);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CK_EN, mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_BE_CK_EN_SET);
+
+ rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_CMAC1_FEN);
+ rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL_EXTEND, B_BE_R_SYM_ISO_CMAC12PP);
+ rtw89_write32_clr(rtwdev, R_BE_AFE_CTRL1, B_BE_AFE_CTRL1_SET);
+
+ clear_bit(RTW89_FLAG_CMAC1_FUNC, rtwdev->flags);
+ }
+
+ return 0;
+}
+
+static int chip_func_en_be(struct rtw89_dev *rtwdev)
+{
+ return 0;
+}
+
+static int sys_init_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ ret = dmac_func_en_be(rtwdev);
+ if (ret)
+ return ret;
+
+ ret = cmac_func_en_be(rtwdev, RTW89_MAC_0, true);
+ if (ret)
+ return ret;
+
+ ret = chip_func_en_be(rtwdev);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int sta_sch_init_be(struct rtw89_dev *rtwdev)
+{
+ u32 p_val;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
+ if (ret)
+ return ret;
+
+ rtw89_write8_set(rtwdev, R_BE_SS_CTRL, B_BE_SS_EN);
+
+ ret = read_poll_timeout(rtw89_read32, p_val, p_val & B_BE_SS_INIT_DONE,
+ 1, TRXCFG_WAIT_CNT, false, rtwdev, R_BE_SS_CTRL);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]STA scheduler init\n");
+ return ret;
+ }
+
+ rtw89_write32_set(rtwdev, R_BE_SS_CTRL, B_BE_WARM_INIT);
+ rtw89_write32_clr(rtwdev, R_BE_SS_CTRL, B_BE_BAND_TRIG_EN | B_BE_BAND1_TRIG_EN);
+
+ return 0;
+}
+
+static int mpdu_proc_init_be(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_MPDU_PROC, B_BE_APPEND_FCS);
+ rtw89_write32(rtwdev, R_BE_CUT_AMSDU_CTRL, TRXCFG_MPDU_PROC_CUT_CTRL);
+
+ val32 = rtw89_read32(rtwdev, R_BE_HDR_SHCUT_SETTING);
+ val32 |= (B_BE_TX_HW_SEQ_EN | B_BE_TX_HW_ACK_POLICY_EN | B_BE_TX_MAC_MPDU_PROC_EN);
+ val32 &= ~B_BE_TX_ADDR_MLD_TO_LIK;
+ rtw89_write32_set(rtwdev, R_BE_HDR_SHCUT_SETTING, val32);
+
+ rtw89_write32(rtwdev, R_BE_RX_HDRTRNS, TRXCFG_MPDU_PROC_RX_HDR_CONV);
+
+ val32 = rtw89_read32(rtwdev, R_BE_DISP_FWD_WLAN_0);
+ val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_DATA_MASK);
+ val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_MNG_MASK);
+ val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_0_CTL_MASK);
+ val32 = u32_replace_bits(val32, 1, B_BE_FWD_WLAN_CPU_TYPE_1_MASK);
+ rtw89_write32(rtwdev, R_BE_DISP_FWD_WLAN_0, val32);
+
+ return 0;
+}
+
+static int sec_eng_init_be(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
+ if (ret)
+ return ret;
+
+ val32 = rtw89_read32(rtwdev, R_BE_SEC_ENG_CTRL);
+ val32 |= B_BE_CLK_EN_CGCMP | B_BE_CLK_EN_WAPI | B_BE_CLK_EN_WEP_TKIP |
+ B_BE_SEC_TX_ENC | B_BE_SEC_RX_DEC |
+ B_BE_MC_DEC | B_BE_BC_DEC |
+ B_BE_BMC_MGNT_DEC | B_BE_UC_MGNT_DEC;
+ val32 &= ~B_BE_SEC_PRE_ENQUE_TX;
+ rtw89_write32(rtwdev, R_BE_SEC_ENG_CTRL, val32);
+
+ rtw89_write32_set(rtwdev, R_BE_SEC_MPDU_PROC, B_BE_APPEND_ICV | B_BE_APPEND_MIC);
+
+ return 0;
+}
+
+static int txpktctrl_init_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mac_dle_rsvd_qt_cfg qt_cfg;
+ u32 val32;
+ int ret;
+
+ ret = rtw89_mac_get_dle_rsvd_qt_cfg(rtwdev, DLE_RSVD_QT_MPDU_INFO, &qt_cfg);
+ if (ret) {
+ rtw89_err(rtwdev, "get dle rsvd qt %d cfg fail %d\n",
+ DLE_RSVD_QT_MPDU_INFO, ret);
+ return ret;
+ }
+
+ val32 = rtw89_read32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG);
+ val32 = u32_replace_bits(val32, qt_cfg.pktid, B_BE_MPDUINFO_PKTID_MASK);
+ val32 = u32_replace_bits(val32, MPDU_INFO_B1_OFST, B_BE_MPDUINFO_B1_BADDR_MASK);
+ val32 |= B_BE_MPDUINFO_FEN;
+ rtw89_write32(rtwdev, R_BE_TXPKTCTL_MPDUINFO_CFG, val32);
+
+ return 0;
+}
+
+static int mlo_init_be(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+ int ret;
+
+ val32 = rtw89_read32(rtwdev, R_BE_MLO_INIT_CTL);
+
+ val32 |= B_BE_MLO_TABLE_REINIT;
+ rtw89_write32(rtwdev, R_BE_MLO_INIT_CTL, val32);
+ val32 &= ~B_BE_MLO_TABLE_REINIT;
+ rtw89_write32(rtwdev, R_BE_MLO_INIT_CTL, val32);
+
+ ret = read_poll_timeout_atomic(rtw89_read32, val32,
+ val32 & B_BE_MLO_TABLE_INIT_DONE,
+ 1, 1000, false, rtwdev, R_BE_MLO_INIT_CTL);
+ if (ret)
+ rtw89_err(rtwdev, "[MLO]%s: MLO init polling timeout\n", __func__);
+
+ rtw89_write32_set(rtwdev, R_BE_SS_CTRL, B_BE_MLO_HW_CHGLINK_EN);
+ rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_ACQCHK_CFG_0, B_BE_R_MACID_ACQ_CHK_EN);
+
+ return ret;
+}
+
+static int dmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ int ret;
+
+ ret = rtw89_mac_dle_init(rtwdev, rtwdev->mac.qta_mode, RTW89_QTA_INVALID);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]DLE init %d\n", ret);
+ return ret;
+ }
+
+ ret = rtw89_mac_preload_init(rtwdev, RTW89_MAC_0, rtwdev->mac.qta_mode);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]preload init %d\n", ret);
+ return ret;
+ }
+
+ ret = rtw89_mac_hfc_init(rtwdev, true, true, true);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]HCI FC init %d\n", ret);
+ return ret;
+ }
+
+ ret = sta_sch_init_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]STA SCH init %d\n", ret);
+ return ret;
+ }
+
+ ret = mpdu_proc_init_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]MPDU Proc init %d\n", ret);
+ return ret;
+ }
+
+ ret = sec_eng_init_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]Security Engine init %d\n", ret);
+ return ret;
+ }
+
+ ret = txpktctrl_init_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]TX pkt ctrl init %d\n", ret);
+ return ret;
+ }
+
+ ret = mlo_init_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]MLO init %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int scheduler_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 val32;
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_HE_CTN_CHK_CCA_NAV, mac_idx);
+ val32 = B_BE_HE_CTN_CHK_CCA_P20 | B_BE_HE_CTN_CHK_EDCCA_P20 |
+ B_BE_HE_CTN_CHK_CCA_BITMAP | B_BE_HE_CTN_CHK_EDCCA_BITMAP |
+ B_BE_HE_CTN_CHK_NO_GNT_WL | B_BE_HE_CTN_CHK_BASIC_NAV |
+ B_BE_HE_CTN_CHK_INTRA_NAV | B_BE_HE_CTN_CHK_TX_NAV;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_HE_SIFS_CHK_CCA_NAV, mac_idx);
+ val32 = B_BE_HE_SIFS_CHK_EDCCA_P20 | B_BE_HE_SIFS_CHK_EDCCA_BITMAP |
+ B_BE_HE_SIFS_CHK_NO_GNT_WL;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TB_CHK_CCA_NAV, mac_idx);
+ val32 = B_BE_TB_CHK_EDCCA_BITMAP | B_BE_TB_CHK_NO_GNT_WL | B_BE_TB_CHK_BASIC_NAV;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CCA_CFG_0, mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_BE_NO_GNT_WL_EN);
+
+ if (is_qta_poh(rtwdev)) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PREBKF_CFG_0, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_PREBKF_TIME_MASK,
+ SCH_PREBKF_24US);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CTN_CFG_0, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_PREBKF_TIME_NONAC_MASK,
+ SCH_PREBKF_24US);
+ }
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_EDCA_BCNQ_PARAM, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_CW_MASK, 0x32);
+ rtw89_write32_mask(rtwdev, reg, B_BE_BCNQ_AIFS_MASK, BCN_IFS_25US);
+
+ return 0;
+}
+
+static int addr_cam_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 val32;
+ u16 val16;
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_ADDR_CAM_CTRL, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, ADDR_CAM_SERCH_RANGE, B_BE_ADDR_CAM_RANGE_MASK);
+ val32 |= B_BE_ADDR_CAM_EN;
+ if (mac_idx == RTW89_MAC_0)
+ val32 |= B_BE_ADDR_CAM_CLR;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_ADDR_CAM_CTRL, mac_idx);
+ ret = read_poll_timeout_atomic(rtw89_read16, val16, !(val16 & B_BE_ADDR_CAM_CLR),
+ 1, TRXCFG_WAIT_CNT, false, rtwdev, reg);
+ if (ret)
+ rtw89_err(rtwdev, "[ERR]ADDR_CAM reset\n");
+
+ return ret;
+}
+
+static int rtw89_mac_typ_fltr_opt_be(struct rtw89_dev *rtwdev,
+ enum rtw89_machdr_frame_type type,
+ enum rtw89_mac_fwd_target fwd_target,
+ u8 mac_idx)
+{
+ u32 reg;
+ u32 val;
+
+ switch (fwd_target) {
+ case RTW89_FWD_DONT_CARE:
+ val = RX_FLTR_FRAME_DROP_BE;
+ break;
+ case RTW89_FWD_TO_HOST:
+ case RTW89_FWD_TO_WLAN_CPU:
+ val = RX_FLTR_FRAME_ACCEPT_BE;
+ break;
+ default:
+ rtw89_err(rtwdev, "[ERR]set rx filter fwd target err\n");
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case RTW89_MGNT:
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MGNT_FLTR, mac_idx);
+ break;
+ case RTW89_CTRL:
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_CTRL_FLTR, mac_idx);
+ break;
+ case RTW89_DATA:
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_DATA_FLTR, mac_idx);
+ break;
+ default:
+ rtw89_err(rtwdev, "[ERR]set rx filter type err\n");
+ return -EINVAL;
+ }
+ rtw89_write32(rtwdev, reg, val);
+
+ return 0;
+}
+
+static int rx_fltr_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 reg;
+ u32 val;
+
+ rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_MGNT, RTW89_FWD_TO_HOST, mac_idx);
+ rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_CTRL, RTW89_FWD_TO_HOST, mac_idx);
+ rtw89_mac_typ_fltr_opt_be(rtwdev, RTW89_DATA, RTW89_FWD_TO_HOST, mac_idx);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_FLTR_OPT, mac_idx);
+ val = B_BE_A_BC_CAM_MATCH | B_BE_A_UC_CAM_MATCH | B_BE_A_MC |
+ B_BE_A_BC | B_BE_A_A1_MATCH | B_BE_SNIFFER_MODE |
+ u32_encode_bits(15, B_BE_UID_FILTER_MASK);
+ rtw89_write32(rtwdev, reg, val);
+ u32p_replace_bits(&rtwdev->hal.rx_fltr, 15, B_BE_UID_FILTER_MASK);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx);
+ val = B_BE_HE_SIGB_CRC_CHK | B_BE_VHT_MU_SIGB_CRC_CHK |
+ B_BE_VHT_SU_SIGB_CRC_CHK | B_BE_SIGA_CRC_CHK |
+ B_BE_LSIG_PARITY_CHK_EN | B_BE_CCK_SIG_CHK | B_BE_CCK_CRC_CHK;
+ rtw89_write16(rtwdev, reg, val);
+
+ return 0;
+}
+
+static int cca_ctrl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ return 0;
+}
+
+static int nav_ctrl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 val32;
+ u32 reg;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_NAV_CTL, mac_idx);
+
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 &= ~B_BE_WMAC_PLCP_UP_NAV_EN;
+ val32 |= B_BE_WMAC_TF_UP_NAV_EN | B_BE_WMAC_NAV_UPPER_EN;
+ val32 = u32_replace_bits(val32, NAV_25MS, B_BE_WMAC_NAV_UPPER_MASK);
+
+ rtw89_write32(rtwdev, reg, val32);
+
+ return 0;
+}
+
+static int spatial_reuse_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_SR_CTRL, mac_idx);
+ rtw89_write8_clr(rtwdev, reg, B_BE_SR_EN | B_BE_SR_CTRL_PLCP_EN);
+
+ return 0;
+}
+
+static int tmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 reg;
+
+ rtw89_write32_clr(rtwdev, R_BE_TB_PPDU_CTRL, B_BE_QOSNULL_UPD_MUEDCA_EN);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMTX_TCR_BE_4, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK, 0x12);
+ rtw89_write32_mask(rtwdev, reg, B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK, 0xe);
+
+ return 0;
+}
+
+static int trxptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_rrsr_cfgs *rrsr = chip->rrsr_cfgs;
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 val32;
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_MAC_LOOPBACK, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, S_BE_MACLBK_PLCP_DLY_DEF,
+ B_BE_MACLBK_PLCP_DLY_MASK);
+ val32 &= ~B_BE_MACLBK_EN;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_0, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, WMAC_SPEC_SIFS_CCK,
+ B_BE_WMAC_SPEC_SIFS_CCK_MASK);
+ val32 = u32_replace_bits(val32, WMAC_SPEC_SIFS_OFDM_1115E,
+ B_BE_WMAC_SPEC_SIFS_OFDM_MASK);
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_LEGACY, mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_HE, mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_BE_ACK_BA_RESP_HE_CHK_EDCCA);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC, mac_idx);
+ rtw89_write32_clr(rtwdev, reg, B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RXTRIG_TEST_USER_2, mac_idx);
+ rtw89_write32_set(rtwdev, reg, B_BE_RXTRIG_FCSCHK_EN);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_TRXPTCL_RESP_1, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 &= B_BE_FTM_RRSR_RATE_EN_MASK | B_BE_WMAC_RESP_DOPPLEB_BE_EN |
+ B_BE_WMAC_RESP_DCM_EN | B_BE_WMAC_RESP_REF_RATE_MASK;
+ rtw89_write32(rtwdev, reg, val32);
+ rtw89_write32_mask(rtwdev, reg, rrsr->ref_rate.mask, rrsr->ref_rate.data);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_RRSR1, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 &= B_BE_RRSR_RATE_EN_MASK | B_BE_RRSR_CCK_MASK | B_BE_RSC_MASK;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_RRSR0, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 &= B_BE_RRSR_OFDM_MASK | B_BE_RRSR_HT_MASK | B_BE_RRSR_VHT_MASK |
+ B_BE_RRSR_HE_MASK;
+ rtw89_write32(rtwdev, reg, val32);
+
+ if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_RRSR1, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_RSC_MASK, 1);
+ }
+
+ return 0;
+}
+
+static int rst_bacam_be(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+ int ret;
+
+ rtw89_write32_mask(rtwdev, R_BE_RESPBA_CAM_CTRL, B_BE_BACAM_RST_MASK,
+ S_BE_BACAM_RST_ALL);
+
+ ret = read_poll_timeout_atomic(rtw89_read32_mask, val, val == S_BE_BACAM_RST_DONE,
+ 1, 1000, false,
+ rtwdev, R_BE_RESPBA_CAM_CTRL, B_BE_BACAM_RST_MASK);
+ if (ret)
+ rtw89_err(rtwdev, "[ERR]bacam rst timeout\n");
+
+ return ret;
+}
+
+#define PLD_RLS_MAX_PG 127
+#define RX_MAX_LEN_UNIT 512
+#define RX_SPEC_MAX_LEN (11454 + RX_MAX_LEN_UNIT)
+
+static int rmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 rx_min_qta, rx_max_len, rx_max_pg;
+ u16 val16;
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ if (mac_idx == RTW89_MAC_0) {
+ ret = rst_bacam_be(rtwdev);
+ if (ret)
+ return ret;
+ }
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_DLK_PROTECT_CTL, mac_idx);
+ val16 = rtw89_read16(rtwdev, reg);
+ val16 = u16_replace_bits(val16, TRXCFG_RMAC_DATA_TO, B_BE_RX_DLK_DATA_TIME_MASK);
+ val16 = u16_replace_bits(val16, TRXCFG_RMAC_CCA_TO, B_BE_RX_DLK_CCA_TIME_MASK);
+ val16 |= B_BE_RX_DLK_RST_EN;
+ rtw89_write16(rtwdev, reg, val16);
+
+ if (mac_idx == RTW89_MAC_0)
+ rx_min_qta = rtwdev->mac.dle_info.c0_rx_qta;
+ else
+ rx_min_qta = rtwdev->mac.dle_info.c1_rx_qta;
+ rx_max_pg = min_t(u32, rx_min_qta, PLD_RLS_MAX_PG);
+ rx_max_len = rx_max_pg * rtwdev->mac.dle_info.ple_pg_size;
+ rx_max_len = min_t(u32, rx_max_len, RX_SPEC_MAX_LEN);
+ rx_max_len /= RX_MAX_LEN_UNIT;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_FLTR_OPT, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_RX_MPDU_MAX_LEN_MASK, rx_max_len);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PLCP_HDR_FLTR, mac_idx);
+ rtw89_write8_clr(rtwdev, reg, B_BE_VHT_SU_SIGB_CRC_CHK);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RCR, mac_idx);
+ rtw89_write16_set(rtwdev, reg, B_BE_BUSY_CHKSN);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_PLCP_EXT_OPTION_1, mac_idx);
+ rtw89_write16_set(rtwdev, reg, B_BE_PLCP_SU_PSDU_LEN_SRC);
+
+ return 0;
+}
+
+static int resp_pktctl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ struct rtw89_mac_dle_rsvd_qt_cfg qt_cfg;
+ enum rtw89_mac_dle_rsvd_qt_type type;
+ u32 reg;
+ int ret;
+
+ if (mac_idx == RTW89_MAC_1)
+ type = DLE_RSVD_QT_B1_CSI;
+ else
+ type = DLE_RSVD_QT_B0_CSI;
+
+ ret = rtw89_mac_get_dle_rsvd_qt_cfg(rtwdev, type, &qt_cfg);
+ if (ret) {
+ rtw89_err(rtwdev, "get dle rsvd qt %d cfg fail %d\n", type, ret);
+ return ret;
+ }
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RESP_CSI_RESERVED_PAGE, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_START_PAGE_MASK, qt_cfg.pktid);
+ rtw89_write32_mask(rtwdev, reg, B_BE_CSI_RESERVED_PAGE_NUM_MASK, qt_cfg.pg_num);
+
+ return 0;
+}
+
+static int cmac_com_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 val32;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ if (mac_idx == RTW89_MAC_0) {
+ val32 = rtw89_read32(rtwdev, R_BE_TX_SUB_BAND_VALUE);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_20M_8, B_BE_TXSB_20M_MASK);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_40M_4, B_BE_TXSB_40M_MASK);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_80M_2, B_BE_TXSB_80M_MASK);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_160M_1, B_BE_TXSB_160M_MASK);
+ rtw89_write32(rtwdev, R_BE_TX_SUB_BAND_VALUE, val32);
+ } else {
+ val32 = rtw89_read32(rtwdev, R_BE_TX_SUB_BAND_VALUE_C1);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_20M_2, B_BE_TXSB_20M_MASK);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_40M_1, B_BE_TXSB_40M_MASK);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_80M_0, B_BE_TXSB_80M_MASK);
+ val32 = u32_replace_bits(val32, S_BE_TXSB_160M_0, B_BE_TXSB_160M_MASK);
+ rtw89_write32(rtwdev, R_BE_TX_SUB_BAND_VALUE_C1, val32);
+ }
+
+ return 0;
+}
+
+static int ptcl_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 val32;
+ u8 val8;
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ if (is_qta_poh(rtwdev)) {
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_SIFS_SETTING, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_1K,
+ B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK);
+ val32 = u32_replace_bits(val32, S_AX_CTS2S_TH_SEC_256B,
+ B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK);
+ val32 |= B_BE_HW_CTS2SELF_EN;
+ rtw89_write32(rtwdev, reg, val32);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_FSM_MON, mac_idx);
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, S_AX_PTCL_TO_2MS,
+ B_BE_PTCL_TX_ARB_TO_THR_MASK);
+ val32 &= ~B_BE_PTCL_TX_ARB_TO_MODE;
+ rtw89_write32(rtwdev, reg, val32);
+ }
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_COMMON_SETTING_0, mac_idx);
+ val8 = rtw89_read8(rtwdev, reg);
+ val8 |= B_BE_CMAC_TX_MODE_0 | B_BE_CMAC_TX_MODE_1;
+ val8 &= ~(B_BE_PTCL_TRIGGER_SS_EN_0 |
+ B_BE_PTCL_TRIGGER_SS_EN_1 |
+ B_BE_PTCL_TRIGGER_SS_EN_UL);
+ rtw89_write8(rtwdev, reg, val8);
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_AMPDU_AGG_LIMIT, mac_idx);
+ rtw89_write32_mask(rtwdev, reg, B_BE_AMPDU_MAX_TIME_MASK, AMPDU_MAX_TIME);
+
+ return 0;
+}
+
+static int cmac_dma_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 val32;
+ u32 reg;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_RX_CTRL_1, mac_idx);
+
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, WLCPU_RXCH2_QID,
+ B_BE_RXDMA_TXRPT_QUEUE_ID_SW_MASK);
+ val32 = u32_replace_bits(val32, WLCPU_RXCH2_QID,
+ B_BE_RXDMA_F2PCMDRPT_QUEUE_ID_SW_MASK);
+ rtw89_write32(rtwdev, reg, val32);
+
+ return 0;
+}
+
+static int cmac_init_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ int ret;
+
+ ret = scheduler_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d SCH init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = addr_cam_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d ADDR_CAM reset %d\n", mac_idx,
+ ret);
+ return ret;
+ }
+
+ ret = rx_fltr_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d RX filter init %d\n", mac_idx,
+ ret);
+ return ret;
+ }
+
+ ret = cca_ctrl_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d CCA CTRL init %d\n", mac_idx,
+ ret);
+ return ret;
+ }
+
+ ret = nav_ctrl_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d NAV CTRL init %d\n", mac_idx,
+ ret);
+ return ret;
+ }
+
+ ret = spatial_reuse_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d Spatial Reuse init %d\n",
+ mac_idx, ret);
+ return ret;
+ }
+
+ ret = tmac_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d TMAC init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = trxptcl_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d TRXPTCL init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = rmac_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d RMAC init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = resp_pktctl_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d resp pktctl init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = cmac_com_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d Com init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = ptcl_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d PTCL init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ ret = cmac_dma_init_be(rtwdev, mac_idx);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d DMA init %d\n", mac_idx, ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int tx_idle_poll_band_be(struct rtw89_dev *rtwdev, u8 mac_idx)
+{
+ u32 reg;
+ u8 val8;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PTCL_TX_CTN_SEL, mac_idx);
+
+ ret = read_poll_timeout_atomic(rtw89_read8, val8, !(val8 & B_BE_PTCL_BUSY),
+ 30, 66000, false, rtwdev, reg);
+
+ return ret;
+}
+
+static int dle_buf_req_be(struct rtw89_dev *rtwdev, u16 buf_len, bool wd, u16 *pkt_id)
+{
+ u32 val, reg;
+ int ret;
+
+ reg = wd ? R_BE_WD_BUF_REQ : R_BE_PL_BUF_REQ;
+ val = buf_len;
+ val |= B_BE_WD_BUF_REQ_EXEC;
+ rtw89_write32(rtwdev, reg, val);
+
+ reg = wd ? R_BE_WD_BUF_STATUS : R_BE_PL_BUF_STATUS;
+
+ ret = read_poll_timeout(rtw89_read32, val, val & B_BE_WD_BUF_STAT_DONE,
+ 1, 2000, false, rtwdev, reg);
+ if (ret)
+ return ret;
+
+ *pkt_id = u32_get_bits(val, B_BE_WD_BUF_STAT_PKTID_MASK);
+ if (*pkt_id == S_WD_BUF_STAT_PKTID_INVALID)
+ return -ENOENT;
+
+ return 0;
+}
+
+static int set_cpuio_be(struct rtw89_dev *rtwdev,
+ struct rtw89_cpuio_ctrl *ctrl_para, bool wd)
+{
+ u32 val_op0, val_op1, val_op2, val_op3;
+ u32 val, cmd_type, reg;
+ int ret;
+
+ cmd_type = ctrl_para->cmd_type;
+
+ reg = wd ? R_BE_WD_CPUQ_OP_3 : R_BE_PL_CPUQ_OP_3;
+ val_op3 = u32_replace_bits(0, ctrl_para->start_pktid,
+ B_BE_WD_CPUQ_OP_STRT_PKTID_MASK);
+ val_op3 = u32_replace_bits(val_op3, ctrl_para->end_pktid,
+ B_BE_WD_CPUQ_OP_END_PKTID_MASK);
+ rtw89_write32(rtwdev, reg, val_op3);
+
+ reg = wd ? R_BE_WD_CPUQ_OP_1 : R_BE_PL_CPUQ_OP_1;
+ val_op1 = u32_replace_bits(0, ctrl_para->src_pid,
+ B_BE_WD_CPUQ_OP_SRC_PID_MASK);
+ val_op1 = u32_replace_bits(val_op1, ctrl_para->src_qid,
+ B_BE_WD_CPUQ_OP_SRC_QID_MASK);
+ val_op1 = u32_replace_bits(val_op1, ctrl_para->macid,
+ B_BE_WD_CPUQ_OP_SRC_MACID_MASK);
+ rtw89_write32(rtwdev, reg, val_op1);
+
+ reg = wd ? R_BE_WD_CPUQ_OP_2 : R_BE_PL_CPUQ_OP_2;
+ val_op2 = u32_replace_bits(0, ctrl_para->dst_pid,
+ B_BE_WD_CPUQ_OP_DST_PID_MASK);
+ val_op2 = u32_replace_bits(val_op2, ctrl_para->dst_qid,
+ B_BE_WD_CPUQ_OP_DST_QID_MASK);
+ val_op2 = u32_replace_bits(val_op2, ctrl_para->macid,
+ B_BE_WD_CPUQ_OP_DST_MACID_MASK);
+ rtw89_write32(rtwdev, reg, val_op2);
+
+ reg = wd ? R_BE_WD_CPUQ_OP_0 : R_BE_PL_CPUQ_OP_0;
+ val_op0 = u32_replace_bits(0, cmd_type,
+ B_BE_WD_CPUQ_OP_CMD_TYPE_MASK);
+ val_op0 = u32_replace_bits(val_op0, ctrl_para->pkt_num,
+ B_BE_WD_CPUQ_OP_PKTNUM_MASK);
+ val_op0 |= B_BE_WD_CPUQ_OP_EXEC;
+ rtw89_write32(rtwdev, reg, val_op0);
+
+ reg = wd ? R_BE_WD_CPUQ_OP_STATUS : R_BE_PL_CPUQ_OP_STATUS;
+
+ ret = read_poll_timeout(rtw89_read32, val, val & B_BE_WD_CPUQ_OP_STAT_DONE,
+ 1, 2000, false, rtwdev, reg);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]set cpuio wd timeout\n");
+ rtw89_err(rtwdev, "[ERR]op_0=0x%X, op_1=0x%X, op_2=0x%X\n",
+ val_op0, val_op1, val_op2);
+ return ret;
+ }
+
+ if (cmd_type == CPUIO_OP_CMD_GET_NEXT_PID ||
+ cmd_type == CPUIO_OP_CMD_GET_1ST_PID)
+ ctrl_para->pktid = u32_get_bits(val, B_BE_WD_CPUQ_OP_PKTID_MASK);
+
+ return 0;
+}
+
+static int preload_init_be(struct rtw89_dev *rtwdev, u8 mac_idx,
+ enum rtw89_qta_mode mode)
+{
+ u32 max_preld_size, min_rsvd_size;
+ u32 val32;
+ u32 reg;
+
+ max_preld_size = mac_idx == RTW89_MAC_0 ?
+ PRELD_B0_ENT_NUM : PRELD_B1_ENT_NUM;
+ max_preld_size *= PRELD_AMSDU_SIZE;
+
+ reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG0 :
+ R_BE_TXPKTCTL_B1_PRELD_CFG0;
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, max_preld_size, B_BE_B0_PRELD_USEMAXSZ_MASK);
+ val32 |= B_BE_B0_PRELD_FEN;
+ rtw89_write32(rtwdev, reg, val32);
+
+ min_rsvd_size = PRELD_AMSDU_SIZE;
+ reg = mac_idx == RTW89_MAC_0 ? R_BE_TXPKTCTL_B0_PRELD_CFG1 :
+ R_BE_TXPKTCTL_B1_PRELD_CFG1;
+ val32 = rtw89_read32(rtwdev, reg);
+ val32 = u32_replace_bits(val32, PRELD_NEXT_WND, B_BE_B0_PRELD_NXT_TXENDWIN_MASK);
+ val32 = u32_replace_bits(val32, min_rsvd_size, B_BE_B0_PRELD_NXT_RSVMINSZ_MASK);
+ rtw89_write32(rtwdev, reg, val32);
+
+ return 0;
+}
+
+static int dbcc_bb_ctrl_be(struct rtw89_dev *rtwdev, bool bb1_en)
+{
+ return 0;
+}
+
+static int enable_imr_be(struct rtw89_dev *rtwdev, u8 mac_idx,
+ enum rtw89_mac_hwmod_sel sel)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ const struct rtw89_imr_table *table;
+ const struct rtw89_reg_imr *reg;
+ u32 addr;
+ u32 val;
+ int i;
+
+ if (sel == RTW89_DMAC_SEL)
+ table = chip->imr_dmac_table;
+ else if (sel == RTW89_CMAC_SEL)
+ table = chip->imr_cmac_table;
+ else
+ return -EINVAL;
+
+ for (i = 0; i < table->n_regs; i++) {
+ reg = &table->regs[i];
+ addr = rtw89_mac_reg_by_idx(rtwdev, reg->addr, mac_idx);
+
+ val = rtw89_read32(rtwdev, addr);
+ val &= ~reg->clr;
+ val |= reg->set;
+ rtw89_write32(rtwdev, addr, val);
+ }
+
+ return 0;
+}
+
+static void err_imr_ctrl_be(struct rtw89_dev *rtwdev, bool en)
+{
+ u32 v32_dmac = en ? DMAC_ERR_IMR_EN : DMAC_ERR_IMR_DIS;
+ u32 v32_cmac0 = en ? CMAC0_ERR_IMR_EN : CMAC0_ERR_IMR_DIS;
+ u32 v32_cmac1 = en ? CMAC1_ERR_IMR_EN : CMAC1_ERR_IMR_DIS;
+
+ v32_dmac &= ~B_BE_DMAC_NOTX_ERR_INT_EN;
+
+ rtw89_write32(rtwdev, R_BE_DMAC_ERR_IMR, v32_dmac);
+ rtw89_write32(rtwdev, R_BE_CMAC_ERR_IMR, v32_cmac0);
+
+ if (rtwdev->dbcc_en)
+ rtw89_write32(rtwdev, R_BE_CMAC_ERR_IMR_C1, v32_cmac1);
+}
+
+static int band1_enable_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ ret = tx_idle_poll_band_be(rtwdev, RTW89_MAC_0);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]tx idle poll %d\n", ret);
+ return ret;
+ }
+
+ ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret);
+ return ret;
+ }
+
+ ret = preload_init_be(rtwdev, RTW89_MAC_1, rtwdev->mac.qta_mode);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]preload init B1 %d\n", ret);
+ return ret;
+ }
+
+ ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, true);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d func en %d\n", RTW89_MAC_1, ret);
+ return ret;
+ }
+
+ ret = cmac_init_be(rtwdev, RTW89_MAC_1);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d init %d\n", RTW89_MAC_1, ret);
+ return ret;
+ }
+
+ ret = dbcc_bb_ctrl_be(rtwdev, true);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]enable bb 1 %d\n", ret);
+ return ret;
+ }
+
+ ret = enable_imr_be(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] enable CMAC1 IMR %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int band1_disable_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ ret = dbcc_bb_ctrl_be(rtwdev, false);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]disable bb 1 %d\n", ret);
+ return ret;
+ }
+
+ ret = cmac_func_en_be(rtwdev, RTW89_MAC_1, false);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d func dis %d\n", RTW89_MAC_1, ret);
+ return ret;
+ }
+
+ ret = rtw89_mac_dle_quota_change(rtwdev, rtwdev->mac.qta_mode);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]DLE quota change %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable)
+{
+ int ret;
+
+ if (enable) {
+ ret = band1_enable_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] band1_enable %d\n", ret);
+ return ret;
+ }
+
+ if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) {
+ ret = rtw89_fw_h2c_notify_dbcc(rtwdev, true);
+ if (ret) {
+ rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+ } else {
+ if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) {
+ ret = rtw89_fw_h2c_notify_dbcc(rtwdev, false);
+ if (ret) {
+ rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ ret = band1_disable_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] band1_disable %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int set_host_rpr_be(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+ u32 mode;
+ u32 fltr;
+ bool poh;
+
+ poh = is_qta_poh(rtwdev);
+
+ if (poh) {
+ mode = RTW89_RPR_MODE_POH;
+ fltr = S_BE_WDRLS_FLTR_TXOK | S_BE_WDRLS_FLTR_RTYLMT |
+ S_BE_WDRLS_FLTR_LIFTIM | S_BE_WDRLS_FLTR_MACID;
+ } else {
+ mode = RTW89_RPR_MODE_STF;
+ fltr = 0;
+ }
+
+ rtw89_write32_mask(rtwdev, R_BE_WDRLS_CFG, B_BE_WDRLS_MODE_MASK, mode);
+
+ val32 = rtw89_read32(rtwdev, R_BE_RLSRPT0_CFG1);
+ val32 = u32_replace_bits(val32, fltr, B_BE_RLSRPT0_FLTR_MAP_MASK);
+ val32 = u32_replace_bits(val32, 30, B_BE_RLSRPT0_AGGNUM_MASK);
+ val32 = u32_replace_bits(val32, 255, B_BE_RLSRPT0_TO_MASK);
+ rtw89_write32(rtwdev, R_BE_RLSRPT0_CFG1, val32);
+
+ return 0;
+}
+
+static int trx_init_be(struct rtw89_dev *rtwdev)
+{
+ enum rtw89_qta_mode qta_mode = rtwdev->mac.qta_mode;
+ int ret;
+
+ ret = dmac_init_be(rtwdev, 0);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]DMAC init %d\n", ret);
+ return ret;
+ }
+
+ ret = cmac_init_be(rtwdev, 0);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]CMAC%d init %d\n", 0, ret);
+ return ret;
+ }
+
+ if (rtw89_mac_is_qta_dbcc(rtwdev, qta_mode)) {
+ ret = dbcc_enable_be(rtwdev, true);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]dbcc_enable init %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = enable_imr_be(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] enable DMAC IMR %d\n", ret);
+ return ret;
+ }
+
+ ret = enable_imr_be(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] to enable CMAC0 IMR %d\n", ret);
+ return ret;
+ }
+
+ err_imr_ctrl_be(rtwdev, true);
+
+ ret = set_host_rpr_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] set host rpr %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static bool rtw89_mac_get_txpwr_cr_be(struct rtw89_dev *rtwdev,
enum rtw89_phy_idx phy_idx,
u32 reg_base, u32 *cr)
@@ -404,6 +1917,299 @@ static void rtw89_mac_bf_assoc_be(struct rtw89_dev *rtwdev,
}
}
+static void dump_err_status_dispatcher_be(struct rtw89_dev *rtwdev)
+{
+ rtw89_info(rtwdev, "R_BE_DISP_HOST_IMR=0x%08x ",
+ rtw89_read32(rtwdev, R_BE_DISP_HOST_IMR));
+ rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR1));
+ rtw89_info(rtwdev, "R_BE_DISP_CPU_IMR=0x%08x ",
+ rtw89_read32(rtwdev, R_BE_DISP_CPU_IMR));
+ rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR2=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR2));
+ rtw89_info(rtwdev, "R_BE_DISP_OTHER_IMR=0x%08x ",
+ rtw89_read32(rtwdev, R_BE_DISP_OTHER_IMR));
+ rtw89_info(rtwdev, "R_BE_DISP_ERROR_ISR0=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DISP_ERROR_ISR0));
+}
+
+static void rtw89_mac_dump_qta_lost_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mac_dle_dfi_qempty qempty;
+ struct rtw89_mac_dle_dfi_quota quota;
+ struct rtw89_mac_dle_dfi_ctrl ctrl;
+ u32 val, not_empty, i;
+ int ret;
+
+ qempty.dle_type = DLE_CTRL_TYPE_PLE;
+ qempty.grpsel = 0;
+ qempty.qempty = ~(u32)0;
+ ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty);
+ if (ret)
+ rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
+ else
+ rtw89_info(rtwdev, "DLE group0 empty: 0x%x\n", qempty.qempty);
+
+ for (not_empty = ~qempty.qempty, i = 0; not_empty != 0; not_empty >>= 1, i++) {
+ if (!(not_empty & BIT(0)))
+ continue;
+ ctrl.type = DLE_CTRL_TYPE_PLE;
+ ctrl.target = DLE_DFI_TYPE_QLNKTBL;
+ ctrl.addr = (QLNKTBL_ADDR_INFO_SEL_0 ? QLNKTBL_ADDR_INFO_SEL : 0) |
+ u32_encode_bits(i, QLNKTBL_ADDR_TBL_IDX_MASK);
+ ret = rtw89_mac_dle_dfi_cfg(rtwdev, &ctrl);
+ if (ret)
+ rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
+ else
+ rtw89_info(rtwdev, "qidx%d pktcnt = %d\n", i,
+ u32_get_bits(ctrl.out_data,
+ QLNKTBL_DATA_SEL1_PKT_CNT_MASK));
+ }
+
+ quota.dle_type = DLE_CTRL_TYPE_PLE;
+ quota.qtaid = 6;
+ ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, &quota);
+ if (ret)
+ rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
+ else
+ rtw89_info(rtwdev, "quota6 rsv/use: 0x%x/0x%x\n",
+ quota.rsv_pgnum, quota.use_pgnum);
+
+ val = rtw89_read32(rtwdev, R_BE_PLE_QTA6_CFG);
+ rtw89_info(rtwdev, "[PLE][CMAC0_RX]min_pgnum=0x%x\n",
+ u32_get_bits(val, B_BE_PLE_Q6_MIN_SIZE_MASK));
+ rtw89_info(rtwdev, "[PLE][CMAC0_RX]max_pgnum=0x%x\n",
+ u32_get_bits(val, B_BE_PLE_Q6_MAX_SIZE_MASK));
+ val = rtw89_read32(rtwdev, R_BE_RX_FLTR_OPT);
+ rtw89_info(rtwdev, "[PLE][CMAC0_RX]B_BE_RX_MPDU_MAX_LEN=0x%x\n",
+ u32_get_bits(val, B_BE_RX_MPDU_MAX_LEN_MASK));
+ rtw89_info(rtwdev, "R_BE_RSP_CHK_SIG=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_RSP_CHK_SIG));
+ rtw89_info(rtwdev, "R_BE_TRXPTCL_RESP_0=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_TRXPTCL_RESP_0));
+
+ if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) {
+ quota.dle_type = DLE_CTRL_TYPE_PLE;
+ quota.qtaid = 7;
+ ret = rtw89_mac_dle_dfi_quota_cfg(rtwdev, &quota);
+ if (ret)
+ rtw89_warn(rtwdev, "%s: query DLE fail\n", __func__);
+ else
+ rtw89_info(rtwdev, "quota7 rsv/use: 0x%x/0x%x\n",
+ quota.rsv_pgnum, quota.use_pgnum);
+
+ val = rtw89_read32(rtwdev, R_BE_PLE_QTA7_CFG);
+ rtw89_info(rtwdev, "[PLE][CMAC1_RX]min_pgnum=0x%x\n",
+ u32_get_bits(val, B_BE_PLE_Q7_MIN_SIZE_MASK));
+ rtw89_info(rtwdev, "[PLE][CMAC1_RX]max_pgnum=0x%x\n",
+ u32_get_bits(val, B_BE_PLE_Q7_MAX_SIZE_MASK));
+ val = rtw89_read32(rtwdev, R_BE_RX_FLTR_OPT_C1);
+ rtw89_info(rtwdev, "[PLE][CMAC1_RX]B_BE_RX_MPDU_MAX_LEN=0x%x\n",
+ u32_get_bits(val, B_BE_RX_MPDU_MAX_LEN_MASK));
+ rtw89_info(rtwdev, "R_BE_RSP_CHK_SIG_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_RSP_CHK_SIG_C1));
+ rtw89_info(rtwdev, "R_BE_TRXPTCL_RESP_0_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_TRXPTCL_RESP_0_C1));
+ }
+
+ rtw89_info(rtwdev, "R_BE_DLE_EMPTY0=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DLE_EMPTY0));
+ rtw89_info(rtwdev, "R_BE_DLE_EMPTY1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_DLE_EMPTY1));
+
+ dump_err_status_dispatcher_be(rtwdev);
+}
+
+static void rtw89_mac_dump_cmac_err_status_be(struct rtw89_dev *rtwdev,
+ u8 band)
+{
+ u32 offset = 0;
+ u32 cmac_err;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, band, RTW89_CMAC_SEL);
+ if (ret) {
+ rtw89_info(rtwdev, "[CMAC] : CMAC%d not enabled\n", band);
+ return;
+ }
+
+ if (band)
+ offset = RTW89_MAC_BE_BAND_REG_OFFSET;
+
+ cmac_err = rtw89_read32(rtwdev, R_BE_CMAC_ERR_ISR + offset);
+ rtw89_info(rtwdev, "R_BE_CMAC_ERR_ISR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_CMAC_ERR_ISR + offset));
+ rtw89_info(rtwdev, "R_BE_CMAC_FUNC_EN [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_CMAC_FUNC_EN + offset));
+ rtw89_info(rtwdev, "R_BE_CK_EN [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_CK_EN + offset));
+
+ if (cmac_err & B_BE_SCHEDULE_TOP_ERR_IND) {
+ rtw89_info(rtwdev, "R_BE_SCHEDULE_ERR_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_SCHEDULE_ERR_IMR + offset));
+ rtw89_info(rtwdev, "R_BE_SCHEDULE_ERR_ISR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_SCHEDULE_ERR_ISR + offset));
+ }
+
+ if (cmac_err & B_BE_PTCL_TOP_ERR_IND) {
+ rtw89_info(rtwdev, "R_BE_PTCL_IMR0 [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_PTCL_IMR0 + offset));
+ rtw89_info(rtwdev, "R_BE_PTCL_ISR0 [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_PTCL_ISR0 + offset));
+ rtw89_info(rtwdev, "R_BE_PTCL_IMR1 [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_PTCL_IMR1 + offset));
+ rtw89_info(rtwdev, "R_BE_PTCL_ISR1 [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_PTCL_ISR1 + offset));
+ }
+
+ if (cmac_err & B_BE_DMA_TOP_ERR_IND) {
+ rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_IMR + offset));
+ rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG + offset));
+ rtw89_info(rtwdev, "R_BE_TX_ERROR_FLAG_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_TX_ERROR_FLAG_IMR + offset));
+ rtw89_info(rtwdev, "R_BE_TX_ERROR_FLAG [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_TX_ERROR_FLAG + offset));
+ rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_IMR_1 [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_IMR_1 + offset));
+ rtw89_info(rtwdev, "R_BE_RX_ERROR_FLAG_1 [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_RX_ERROR_FLAG_1 + offset));
+ }
+
+ if (cmac_err & B_BE_PHYINTF_ERR_IND) {
+ rtw89_info(rtwdev, "R_BE_PHYINFO_ERR_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_PHYINFO_ERR_IMR_V1 + offset));
+ rtw89_info(rtwdev, "R_BE_PHYINFO_ERR_ISR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_PHYINFO_ERR_ISR + offset));
+ }
+
+ if (cmac_err & B_AX_TXPWR_CTRL_ERR_IND) {
+ rtw89_info(rtwdev, "R_BE_TXPWR_ERR_FLAG [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_TXPWR_ERR_FLAG + offset));
+ rtw89_info(rtwdev, "R_BE_TXPWR_ERR_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_TXPWR_ERR_IMR + offset));
+ }
+
+ if (cmac_err & (B_BE_WMAC_RX_ERR_IND | B_BE_WMAC_TX_ERR_IND |
+ B_BE_WMAC_RX_IDLETO_IDCT | B_BE_PTCL_TX_IDLETO_IDCT)) {
+ rtw89_info(rtwdev, "R_BE_DBGSEL_TRXPTCL [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_DBGSEL_TRXPTCL + offset));
+ rtw89_info(rtwdev, "R_BE_TRXPTCL_ERROR_INDICA_MASK [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_TRXPTCL_ERROR_INDICA_MASK + offset));
+ rtw89_info(rtwdev, "R_BE_TRXPTCL_ERROR_INDICA [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_TRXPTCL_ERROR_INDICA + offset));
+ rtw89_info(rtwdev, "R_BE_RX_ERR_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_RX_ERR_IMR + offset));
+ rtw89_info(rtwdev, "R_BE_RX_ERR_ISR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_RX_ERR_ISR + offset));
+ }
+
+ rtw89_info(rtwdev, "R_BE_CMAC_ERR_IMR [%d]=0x%08x\n", band,
+ rtw89_read32(rtwdev, R_BE_CMAC_ERR_IMR + offset));
+}
+
+static void rtw89_mac_dump_err_status_be(struct rtw89_dev *rtwdev,
+ enum mac_ax_err_info err)
+{
+ if (err != MAC_AX_ERR_L1_ERR_DMAC &&
+ err != MAC_AX_ERR_L0_PROMOTE_TO_L1 &&
+ err != MAC_AX_ERR_L0_ERR_CMAC0 &&
+ err != MAC_AX_ERR_L0_ERR_CMAC1 &&
+ err != MAC_AX_ERR_RXI300)
+ return;
+
+ rtw89_info(rtwdev, "--->\nerr=0x%x\n", err);
+ rtw89_info(rtwdev, "R_BE_SER_DBG_INFO=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_DBG_INFO));
+ rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT));
+ rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT1));
+ rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT2=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT2));
+ rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT3=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT3));
+ if (!rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL)) {
+ rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT_C1));
+ rtw89_info(rtwdev, "R_BE_SER_L0_DBG_CNT1_C1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L0_DBG_CNT1_C1));
+ }
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_0=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_0));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_1=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_1));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_2=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_2));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_3=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_3));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_4=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_4));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_5=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_5));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_6=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_6));
+ rtw89_info(rtwdev, "R_BE_SER_L1_DBG_CNT_7=0x%08x\n",
+ rtw89_read32(rtwdev, R_BE_SER_L1_DBG_CNT_7));
+
+ rtw89_mac_dump_dmac_err_status(rtwdev);
+ rtw89_mac_dump_cmac_err_status_be(rtwdev, RTW89_MAC_0);
+ rtw89_mac_dump_cmac_err_status_be(rtwdev, RTW89_MAC_1);
+
+ rtwdev->hci.ops->dump_err_status(rtwdev);
+
+ if (err == MAC_AX_ERR_L0_PROMOTE_TO_L1)
+ rtw89_mac_dump_l0_to_l1(rtwdev, err);
+
+ rtw89_info(rtwdev, "<---\n");
+}
+
+static bool mac_is_txq_empty_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_mac_dle_dfi_qempty qempty;
+ u32 val32, msk32;
+ u32 grpnum;
+ int ret;
+ int i;
+
+ grpnum = rtwdev->chip->wde_qempty_acq_grpnum;
+ qempty.dle_type = DLE_CTRL_TYPE_WDE;
+
+ for (i = 0; i < grpnum; i++) {
+ qempty.grpsel = i;
+ ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty);
+ if (ret) {
+ rtw89_warn(rtwdev,
+ "%s: failed to dle dfi acq empty: %d\n",
+ __func__, ret);
+ return false;
+ }
+
+ /* Each acq group contains 32 queues (8 macid * 4 acq),
+ * but here, we can simply check if all bits are set.
+ */
+ if (qempty.qempty != MASKDWORD)
+ return false;
+ }
+
+ qempty.grpsel = rtwdev->chip->wde_qempty_mgq_grpsel;
+ ret = rtw89_mac_dle_dfi_qempty_cfg(rtwdev, &qempty);
+ if (ret) {
+ rtw89_warn(rtwdev, "%s: failed to dle dfi mgq empty: %d\n",
+ __func__, ret);
+ return false;
+ }
+
+ msk32 = B_CMAC0_MGQ_NORMAL_BE | B_CMAC1_MGQ_NORMAL_BE;
+ if ((qempty.qempty & msk32) != msk32)
+ return false;
+
+ msk32 = B_BE_WDE_EMPTY_QUE_OTHERS;
+ val32 = rtw89_read32(rtwdev, R_BE_DLE_EMPTY0);
+ return (val32 & msk32) == msk32;
+}
+
const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
.band1_offset = RTW89_MAC_BE_BAND_REG_OFFSET,
.filter_model_addr = R_BE_FILTER_MODEL_ADDR,
@@ -423,13 +2229,44 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = {
B_BE_BFMEE_HE_NDPA_EN | B_BE_BFMEE_EHT_NDPA_EN,
},
+ .check_mac_en = rtw89_mac_check_mac_en_be,
+ .sys_init = sys_init_be,
+ .trx_init = trx_init_be,
+ .hci_func_en = rtw89_mac_hci_func_en_be,
+ .dmac_func_pre_en = rtw89_mac_dmac_func_pre_en_be,
+ .dle_func_en = dle_func_en_be,
+ .dle_clk_en = dle_clk_en_be,
.bf_assoc = rtw89_mac_bf_assoc_be,
+ .typ_fltr_opt = rtw89_mac_typ_fltr_opt_be,
+
+ .dle_mix_cfg = dle_mix_cfg_be,
+ .chk_dle_rdy = chk_dle_rdy_be,
+ .dle_buf_req = dle_buf_req_be,
+ .hfc_func_en = hfc_func_en_be,
+ .hfc_h2c_cfg = hfc_h2c_cfg_be,
+ .hfc_mix_cfg = hfc_mix_cfg_be,
+ .hfc_get_mix_info = hfc_get_mix_info_be,
+ .wde_quota_cfg = wde_quota_cfg_be,
+ .ple_quota_cfg = ple_quota_cfg_be,
+ .set_cpuio = set_cpuio_be,
+
.disable_cpu = rtw89_mac_disable_cpu_be,
.fwdl_enable_wcpu = rtw89_mac_fwdl_enable_wcpu_be,
.fwdl_get_status = fwdl_get_status_be,
.fwdl_check_path_ready = rtw89_fwdl_check_path_ready_be,
+ .parse_efuse_map = rtw89_parse_efuse_map_be,
+ .parse_phycap_map = rtw89_parse_phycap_map_be,
+ .cnv_efuse_state = rtw89_cnv_efuse_state_be,
.get_txpwr_cr = rtw89_mac_get_txpwr_cr_be,
+
+ .write_xtal_si = rtw89_mac_write_xtal_si_be,
+ .read_xtal_si = rtw89_mac_read_xtal_si_be,
+
+ .dump_qta_lost = rtw89_mac_dump_qta_lost_be,
+ .dump_err_status = rtw89_mac_dump_err_status_be,
+
+ .is_txq_empty = mac_is_txq_empty_be,
};
EXPORT_SYMBOL(rtw89_mac_gen_be);
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 14ddb0d39e63..769f1ce62ebc 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -19,28 +19,25 @@ MODULE_PARM_DESC(disable_clkreq, "Set Y to disable PCI clkreq support");
MODULE_PARM_DESC(disable_aspm_l1, "Set Y to disable PCI ASPM L1 support");
MODULE_PARM_DESC(disable_aspm_l1ss, "Set Y to disable PCI L1SS support");
-static int rtw89_pci_rst_bdram_pcie(struct rtw89_dev *rtwdev)
+static int rtw89_pci_rst_bdram_ax(struct rtw89_dev *rtwdev)
{
u32 val;
int ret;
- rtw89_write32(rtwdev, R_AX_PCIE_INIT_CFG1,
- rtw89_read32(rtwdev, R_AX_PCIE_INIT_CFG1) | B_AX_RST_BDRAM);
+ rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, B_AX_RST_BDRAM);
ret = read_poll_timeout_atomic(rtw89_read32, val, !(val & B_AX_RST_BDRAM),
1, RTW89_PCI_POLL_BDRAM_RST_CNT, false,
rtwdev, R_AX_PCIE_INIT_CFG1);
- if (ret)
- return -EBUSY;
-
- return 0;
+ return ret;
}
static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev,
struct rtw89_pci_dma_ring *bd_ring,
u32 cur_idx, bool tx)
{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
u32 cnt, cur_rp, wp, rp, len;
rp = bd_ring->rp;
@@ -48,10 +45,14 @@ static u32 rtw89_pci_dma_recalc(struct rtw89_dev *rtwdev,
len = bd_ring->len;
cur_rp = FIELD_GET(TXBD_HW_IDX_MASK, cur_idx);
- if (tx)
+ if (tx) {
cnt = cur_rp >= rp ? cur_rp - rp : len - (rp - cur_rp);
- else
+ } else {
+ if (info->rx_ring_eq_is_full)
+ wp += 1;
+
cnt = cur_rp >= wp ? cur_rp - wp : len - (wp - cur_rp);
+ }
bd_ring->rp = cur_rp;
@@ -226,6 +227,21 @@ rtw89_skb_put_rx_data(struct rtw89_dev *rtwdev, bool fs, bool ls,
return true;
}
+static u32 rtw89_pci_get_rx_skb_idx(struct rtw89_dev *rtwdev,
+ struct rtw89_pci_dma_ring *bd_ring)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ u32 wp = bd_ring->wp;
+
+ if (!info->rx_ring_eq_is_full)
+ return wp;
+
+ if (++wp >= bd_ring->len)
+ wp = 0;
+
+ return wp;
+}
+
static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev,
struct rtw89_pci_rx_ring *rx_ring)
{
@@ -235,12 +251,14 @@ static u32 rtw89_pci_rxbd_deliver_skbs(struct rtw89_dev *rtwdev,
struct sk_buff *new = rx_ring->diliver_skb;
struct sk_buff *skb;
u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
+ u32 skb_idx;
u32 offset;
u32 cnt = 1;
bool fs, ls;
int ret;
- skb = rx_ring->buf[bd_ring->wp];
+ skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
+ skb = rx_ring->buf[skb_idx];
rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
@@ -525,10 +543,12 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev,
u32 cnt = 0;
u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt);
u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info);
+ u32 skb_idx;
u32 offset;
int ret;
- skb = rx_ring->buf[bd_ring->wp];
+ skb_idx = rtw89_pci_get_rx_skb_idx(rtwdev, bd_ring);
+ skb = rx_ring->buf[skb_idx];
rtw89_pci_sync_skb_for_cpu(rtwdev, skb);
ret = rtw89_pci_rxbd_info_update(rtwdev, skb);
@@ -676,11 +696,26 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
}
EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v1);
-static void rtw89_pci_clear_isr0(struct rtw89_dev *rtwdev, u32 isr00)
+void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_pci *rtwpci,
+ struct rtw89_pci_isrs *isrs)
{
- /* write 1 clear */
- rtw89_write32(rtwdev, R_AX_PCIE_HISR00, isr00);
+ isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs;
+ isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ?
+ rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0;
+ isrs->isrs[0] = isrs->ind_isrs & B_BE_HCI_AXIDMA_INT ?
+ rtw89_read32(rtwdev, R_BE_HAXI_HISR00) & rtwpci->intrs[0] : 0;
+ isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR);
+
+ if (isrs->halt_c2h_isrs)
+ rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs);
+ if (isrs->isrs[0])
+ rtw89_write32(rtwdev, R_BE_HAXI_HISR00, isrs->isrs[0]);
+ if (isrs->isrs[1])
+ rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]);
+ rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs);
}
+EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2);
void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
{
@@ -713,6 +748,22 @@ void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpc
}
EXPORT_SYMBOL(rtw89_pci_disable_intr_v1);
+void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
+{
+ rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs);
+ rtw89_write32(rtwdev, R_BE_HAXI_HIMR00, rtwpci->intrs[0]);
+ rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]);
+ rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs);
+}
+EXPORT_SYMBOL(rtw89_pci_enable_intr_v2);
+
+void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci)
+{
+ rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0);
+ rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0);
+}
+EXPORT_SYMBOL(rtw89_pci_disable_intr_v2);
+
static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev)
{
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
@@ -753,6 +804,8 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
{
struct rtw89_dev *rtwdev = dev;
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
struct rtw89_pci_isrs isrs;
unsigned long flags;
@@ -760,13 +813,13 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev)
rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs);
spin_unlock_irqrestore(&rtwpci->irq_lock, flags);
- if (unlikely(isrs.isrs[0] & B_AX_RDU_INT))
+ if (unlikely(isrs.isrs[0] & gen_def->isr_rdu))
rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci);
- if (unlikely(isrs.halt_c2h_isrs & B_AX_HALT_C2H_INT_EN))
+ if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h))
rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev));
- if (unlikely(isrs.halt_c2h_isrs & B_AX_WDT_TIMEOUT_INT_EN))
+ if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout))
rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT);
if (unlikely(rtwpci->under_recovery))
@@ -817,6 +870,15 @@ exit:
return irqret;
}
+#define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \
+ [RTW89_TXCH_##ch_idx] = { \
+ .num = R_##gen##_##txch##_TXBD_NUM ##v, \
+ .idx = R_##gen##_##txch##_TXBD_IDX ##v, \
+ .bdram = 0, \
+ .desa_l = R_##gen##_##txch##_TXBD_DESA_L ##v, \
+ .desa_h = R_##gen##_##txch##_TXBD_DESA_H ##v, \
+ }
+
#define DEF_TXCHADDRS_TYPE1(info, txch, v...) \
[RTW89_TXCH_##txch] = { \
.num = R_AX_##txch##_TXBD_NUM ##v, \
@@ -835,12 +897,12 @@ exit:
.desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \
}
-#define DEF_RXCHADDRS(info, rxch, v...) \
- [RTW89_RXCH_##rxch] = { \
- .num = R_AX_##rxch##_RXBD_NUM ##v, \
- .idx = R_AX_##rxch##_RXBD_IDX ##v, \
- .desa_l = R_AX_##rxch##_RXBD_DESA_L ##v, \
- .desa_h = R_AX_##rxch##_RXBD_DESA_H ##v, \
+#define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \
+ [RTW89_RXCH_##ch_idx] = { \
+ .num = R_##gen##_##rxch##_RXBD_NUM ##v, \
+ .idx = R_##gen##_##rxch##_RXBD_IDX ##v, \
+ .desa_l = R_##gen##_##rxch##_RXBD_DESA_L ##v, \
+ .desa_h = R_##gen##_##rxch##_RXBD_DESA_H ##v, \
}
const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = {
@@ -860,8 +922,8 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set = {
DEF_TXCHADDRS(info, CH12),
},
.rx = {
- DEF_RXCHADDRS(info, RXQ),
- DEF_RXCHADDRS(info, RPQ),
+ DEF_RXCHADDRS(AX, RXQ, RXQ),
+ DEF_RXCHADDRS(AX, RPQ, RPQ),
},
};
EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set);
@@ -883,12 +945,35 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1 = {
DEF_TXCHADDRS(info, CH12, _V1),
},
.rx = {
- DEF_RXCHADDRS(info, RXQ, _V1),
- DEF_RXCHADDRS(info, RPQ, _V1),
+ DEF_RXCHADDRS(AX, RXQ, RXQ, _V1),
+ DEF_RXCHADDRS(AX, RPQ, RPQ, _V1),
},
};
EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_v1);
+const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = {
+ .tx = {
+ DEF_TXCHADDRS_TYPE2(BE, ACH0, CH0, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH1, CH1, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH2, CH2, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH3, CH3, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH4, CH4, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH5, CH5, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH6, CH6, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, ACH7, CH7, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, CH8, CH8, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, CH9, CH9, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, CH10, CH10, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, CH11, CH11, _V1),
+ DEF_TXCHADDRS_TYPE2(BE, CH12, CH12, _V1),
+ },
+ .rx = {
+ DEF_RXCHADDRS(BE, RXQ, RXQ0, _V1),
+ DEF_RXCHADDRS(BE, RPQ, RPQ0, _V1),
+ },
+};
+EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be);
+
#undef DEF_TXCHADDRS_TYPE1
#undef DEF_TXCHADDRS
#undef DEF_RXCHADDRS
@@ -1422,6 +1507,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
struct rtw89_pci_dma_ring *bd_ring;
const struct rtw89_pci_bd_ram *bd_ram;
u32 addr_num;
+ u32 addr_idx;
u32 addr_bdram;
u32 addr_desa_l;
u32 val32;
@@ -1433,19 +1519,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
tx_ring = &rtwpci->tx_rings[i];
bd_ring = &tx_ring->bd_ring;
- bd_ram = &bd_ram_table[i];
+ bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL;
addr_num = bd_ring->addr.num;
addr_bdram = bd_ring->addr.bdram;
addr_desa_l = bd_ring->addr.desa_l;
bd_ring->wp = 0;
bd_ring->rp = 0;
- val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) |
- FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) |
- FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num);
-
rtw89_write16(rtwdev, addr_num, bd_ring->len);
- rtw89_write32(rtwdev, addr_bdram, val32);
+ if (addr_bdram && bd_ram) {
+ val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) |
+ FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) |
+ FIELD_PREP(BDRAM_MIN_MASK, bd_ram->min_num);
+
+ rtw89_write32(rtwdev, addr_bdram, val32);
+ }
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
}
@@ -1453,14 +1541,21 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev)
rx_ring = &rtwpci->rx_rings[i];
bd_ring = &rx_ring->bd_ring;
addr_num = bd_ring->addr.num;
+ addr_idx = bd_ring->addr.idx;
addr_desa_l = bd_ring->addr.desa_l;
- bd_ring->wp = 0;
+ if (info->rx_ring_eq_is_full)
+ bd_ring->wp = bd_ring->len - 1;
+ else
+ bd_ring->wp = 0;
bd_ring->rp = 0;
rx_ring->diliver_skb = NULL;
rx_ring->diliver_desc.ready = false;
rtw89_write16(rtwdev, addr_num, bd_ring->len);
rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma);
+
+ if (info->rx_ring_eq_is_full)
+ rtw89_write16(rtwdev, addr_idx, bd_ring->wp);
}
}
@@ -1471,7 +1566,7 @@ static void rtw89_pci_release_tx_ring(struct rtw89_dev *rtwdev,
rtw89_pci_release_pending_txwd_skb(rtwdev, tx_ring);
}
-static void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev)
+void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev)
{
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
const struct rtw89_pci_info *info = rtwdev->pci_info;
@@ -1684,24 +1779,16 @@ static void rtw89_pci_ctrl_dma_trx(struct rtw89_dev *rtwdev, bool enable)
static void rtw89_pci_ctrl_dma_io(struct rtw89_dev *rtwdev, bool enable)
{
- enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
- u32 reg, mask;
-
- if (chip_id == RTL8852C) {
- reg = R_AX_HAXI_INIT_CFG1;
- mask = B_AX_STOP_AXI_MST;
- } else {
- reg = R_AX_PCIE_DMA_STOP1;
- mask = B_AX_STOP_PCIEIO;
- }
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_reg_def *reg = &info->dma_io_stop;
if (enable)
- rtw89_write32_clr(rtwdev, reg, mask);
+ rtw89_write32_clr(rtwdev, reg->addr, reg->mask);
else
- rtw89_write32_set(rtwdev, reg, mask);
+ rtw89_write32_set(rtwdev, reg->addr, reg->mask);
}
-static void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable)
+void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable)
{
rtw89_pci_ctrl_dma_io(rtwdev, enable);
rtw89_pci_ctrl_dma_trx(rtwdev, enable);
@@ -2303,7 +2390,7 @@ static void rtw89_pci_set_keep_reg(struct rtw89_dev *rtwdev)
B_AX_PCIE_TXRST_KEEP_REG | B_AX_PCIE_RXRST_KEEP_REG);
}
-static void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev)
+static void rtw89_pci_clr_idx_all_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_pci_info *info = rtwdev->pci_info;
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
@@ -2491,7 +2578,7 @@ static int rtw89_pci_ops_deinit(struct rtw89_dev *rtwdev)
return 0;
}
-static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev)
+static int rtw89_pci_ops_mac_pre_init_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_pci_info *info = rtwdev->pci_info;
int ret;
@@ -2550,7 +2637,7 @@ static int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev)
/* fill TRX BD indexes */
rtw89_pci_ops_reset(rtwdev);
- ret = rtw89_pci_rst_bdram_pcie(rtwdev);
+ ret = rtw89_pci_rst_bdram_ax(rtwdev);
if (ret) {
rtw89_warn(rtwdev, "reset bdram busy\n");
return ret;
@@ -2648,7 +2735,7 @@ int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en)
}
EXPORT_SYMBOL(rtw89_pci_ltr_set_v1);
-static int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev)
+static int rtw89_pci_ops_mac_post_init_ax(struct rtw89_dev *rtwdev)
{
const struct rtw89_pci_info *info = rtwdev->pci_info;
enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id;
@@ -3026,6 +3113,7 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
struct rtw89_pci_rx_ring *rx_ring,
u32 desc_size, u32 len, u32 rxch)
{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
const struct rtw89_pci_ch_dma_addr *rxch_addr;
struct sk_buff *skb;
u8 *head;
@@ -3052,7 +3140,10 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev,
rx_ring->bd_ring.len = len;
rx_ring->bd_ring.desc_size = desc_size;
rx_ring->bd_ring.addr = *rxch_addr;
- rx_ring->bd_ring.wp = 0;
+ if (info->rx_ring_eq_is_full)
+ rx_ring->bd_ring.wp = len - 1;
+ else
+ rx_ring->bd_ring.wp = 0;
rx_ring->bd_ring.rp = 0;
rx_ring->buf_sz = buf_sz;
rx_ring->diliver_skb = NULL;
@@ -3289,6 +3380,55 @@ void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev)
}
EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v1);
+static void rtw89_pci_recovery_intr_mask_v2(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+ rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0;
+ rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
+ rtwpci->intrs[0] = 0;
+ rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 |
+ B_BE_PCIE_RX_RPQ0_IMR0_V1;
+}
+
+static void rtw89_pci_default_intr_mask_v2(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+ rtwpci->ind_intrs = B_BE_HCI_AXIDMA_INT_EN0 |
+ B_BE_HS0_IND_INT_EN0;
+ rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
+ rtwpci->intrs[0] = B_BE_RDU_CH1_INT_IMR_V1 |
+ B_BE_RDU_CH0_INT_IMR_V1;
+ rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 |
+ B_BE_PCIE_RX_RPQ0_IMR0_V1;
+}
+
+static void rtw89_pci_low_power_intr_mask_v2(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+ rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0 |
+ B_BE_HS1_IND_INT_EN0;
+ rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN;
+ rtwpci->intrs[0] = 0;
+ rtwpci->intrs[1] = B_BE_PCIE_RX_RX0P2_IMR0_V1 |
+ B_BE_PCIE_RX_RPQ0_IMR0_V1;
+}
+
+void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+
+ if (rtwpci->under_recovery)
+ rtw89_pci_recovery_intr_mask_v2(rtwdev);
+ else if (rtwpci->low_power)
+ rtw89_pci_low_power_intr_mask_v2(rtwdev);
+ else
+ rtw89_pci_default_intr_mask_v2(rtwdev);
+}
+EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2);
+
static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev,
struct pci_dev *pdev)
{
@@ -3480,19 +3620,27 @@ static void rtw89_pci_aspm_set(struct rtw89_dev *rtwdev, bool enable)
static void rtw89_pci_recalc_int_mit(struct rtw89_dev *rtwdev)
{
+ enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen;
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
struct rtw89_traffic_stats *stats = &rtwdev->stats;
enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv;
enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv;
u32 val = 0;
- if (!rtwdev->scanning &&
- (tx_tfc_lv >= RTW89_TFC_HIGH || rx_tfc_lv >= RTW89_TFC_HIGH))
+ if (rtwdev->scanning ||
+ (tx_tfc_lv < RTW89_TFC_HIGH && rx_tfc_lv < RTW89_TFC_HIGH))
+ goto out;
+
+ if (chip_gen == RTW89_CHIP_BE)
+ val = B_BE_PCIE_MIT_RX0P2_EN | B_BE_PCIE_MIT_RX0P1_EN;
+ else
val = B_AX_RXMIT_RXP2_SEL | B_AX_RXMIT_RXP1_SEL |
FIELD_PREP(B_AX_RXCOUNTER_MATCH_MASK, RTW89_PCI_RXBD_NUM_MAX / 2) |
FIELD_PREP(B_AX_RXTIMER_UNIT_MASK, AX_RXTIMER_UNIT_64US) |
FIELD_PREP(B_AX_RXTIMER_MATCH_MASK, 2048 / 64);
- rtw89_write32(rtwdev, R_AX_INT_MIT_RX, val);
+out:
+ rtw89_write32(rtwdev, info->mit_addr, val);
}
static void rtw89_pci_link_cfg(struct rtw89_dev *rtwdev)
@@ -3582,7 +3730,7 @@ static void rtw89_pci_l1ss_cfg(struct rtw89_dev *rtwdev)
rtw89_pci_l1ss_set(rtwdev, true);
}
-static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev)
+static int rtw89_pci_poll_io_idle_ax(struct rtw89_dev *rtwdev)
{
int ret = 0;
u32 sts;
@@ -3599,7 +3747,7 @@ static int rtw89_pci_poll_io_idle(struct rtw89_dev *rtwdev)
return ret;
}
-static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev)
+static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev)
{
u32 val;
int ret;
@@ -3608,7 +3756,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev)
return 0;
rtw89_pci_ctrl_dma_all(rtwdev, false);
- ret = rtw89_pci_poll_io_idle(rtwdev);
+ ret = rtw89_pci_poll_io_idle_ax(rtwdev);
if (ret) {
val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG);
rtw89_debug(rtwdev, RTW89_DBG_HCI,
@@ -3619,7 +3767,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev)
if (val & B_AX_RX_STUCK)
rtw89_mac_ctrl_hci_dma_rx(rtwdev, false);
rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
- ret = rtw89_pci_poll_io_idle(rtwdev);
+ ret = rtw89_pci_poll_io_idle_ax(rtwdev);
val = rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG);
rtw89_debug(rtwdev, RTW89_DBG_HCI,
"[PCIe] poll_io_idle fail, after 0x%08x: 0x%08x\n",
@@ -3629,23 +3777,7 @@ static int rtw89_pci_lv1rst_stop_dma(struct rtw89_dev *rtwdev)
return ret;
}
-
-
-static int rtw89_pci_rst_bdram(struct rtw89_dev *rtwdev)
-{
- int ret = 0;
- u32 val32, sts;
-
- val32 = B_AX_RST_BDRAM;
- rtw89_write32_set(rtwdev, R_AX_PCIE_INIT_CFG1, val32);
-
- ret = read_poll_timeout_atomic(rtw89_read32, sts,
- (sts & B_AX_RST_BDRAM) == 0x0, 1, 100,
- true, rtwdev, R_AX_PCIE_INIT_CFG1);
- return ret;
-}
-
-static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev)
+static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev)
{
u32 ret;
@@ -3656,7 +3788,7 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev)
rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
rtw89_pci_clr_idx_all(rtwdev);
- ret = rtw89_pci_rst_bdram(rtwdev);
+ ret = rtw89_pci_rst_bdram_ax(rtwdev);
if (ret)
return ret;
@@ -3667,18 +3799,20 @@ static int rtw89_pci_lv1rst_start_dma(struct rtw89_dev *rtwdev)
static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev,
enum rtw89_lv1_rcvy_step step)
{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
int ret;
switch (step) {
case RTW89_LV1_RCVY_STEP_1:
- ret = rtw89_pci_lv1rst_stop_dma(rtwdev);
+ ret = gen_def->lv1rst_stop_dma(rtwdev);
if (ret)
rtw89_err(rtwdev, "lv1 rcvy pci stop dma fail\n");
break;
case RTW89_LV1_RCVY_STEP_2:
- ret = rtw89_pci_lv1rst_start_dma(rtwdev);
+ ret = gen_def->lv1rst_start_dma(rtwdev);
if (ret)
rtw89_err(rtwdev, "lv1 rcvy pci start dma fail\n");
break;
@@ -3692,29 +3826,41 @@ static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev,
static void rtw89_pci_ops_dump_err_status(struct rtw89_dev *rtwdev)
{
- rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n",
- rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX));
- rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG));
- rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n",
- rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG));
+ if (rtwdev->chip->chip_gen == RTW89_CHIP_BE)
+ return;
+
+ if (rtwdev->chip->chip_id == RTL8852C) {
+ rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG_V1));
+ rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG_V1));
+ } else {
+ rtw89_info(rtwdev, "R_AX_RPQ_RXBD_IDX =0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_RPQ_RXBD_IDX));
+ rtw89_info(rtwdev, "R_AX_DBG_ERR_FLAG=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_DBG_ERR_FLAG));
+ rtw89_info(rtwdev, "R_AX_LBC_WATCHDOG=0x%08x\n",
+ rtw89_read32(rtwdev, R_AX_LBC_WATCHDOG));
+ }
}
static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget)
{
struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi);
struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
unsigned long flags;
int work_done;
rtwdev->napi_budget_countdown = budget;
- rtw89_pci_clear_isr0(rtwdev, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT);
+ rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data);
work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
if (work_done == budget)
return budget;
- rtw89_pci_clear_isr0(rtwdev, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT);
+ rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data);
work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown);
if (work_done < budget && napi_complete_done(napi, work_done)) {
spin_lock_irqsave(&rtwpci->irq_lock, flags);
@@ -3791,6 +3937,26 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev)
SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume);
EXPORT_SYMBOL(rtw89_pm_ops);
+const struct rtw89_pci_gen_def rtw89_pci_gen_ax = {
+ .isr_rdu = B_AX_RDU_INT,
+ .isr_halt_c2h = B_AX_HALT_C2H_INT_EN,
+ .isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN,
+ .isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT},
+ .isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT |
+ B_AX_RDU_INT},
+
+ .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax,
+ .mac_pre_deinit = NULL,
+ .mac_post_init = rtw89_pci_ops_mac_post_init_ax,
+
+ .clr_idx_all = rtw89_pci_clr_idx_all_ax,
+ .rst_bdram = rtw89_pci_rst_bdram_ax,
+
+ .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_ax,
+ .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_ax,
+};
+EXPORT_SYMBOL(rtw89_pci_gen_ax);
+
static const struct rtw89_hci_ops rtw89_pci_ops = {
.tx_write = rtw89_pci_ops_tx_write,
.tx_kick_off = rtw89_pci_ops_tx_kick_off,
@@ -3810,6 +3976,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = {
.write32 = rtw89_pci_ops_write32,
.mac_pre_init = rtw89_pci_ops_mac_pre_init,
+ .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit,
.mac_post_init = rtw89_pci_ops_mac_post_init,
.deinit = rtw89_pci_ops_deinit,
@@ -3829,7 +3996,7 @@ static const struct rtw89_hci_ops rtw89_pci_ops = {
.clear = rtw89_pci_clear_resource,
.disable_intr = rtw89_pci_disable_intr_lock,
.enable_intr = rtw89_pci_enable_intr_lock,
- .rst_bdram = rtw89_pci_rst_bdram_pcie,
+ .rst_bdram = rtw89_pci_reset_bdram,
};
int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h
index 2f3d1ad3b0f7..ca5de77fee90 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.h
+++ b/drivers/net/wireless/realtek/rtw89/pci.h
@@ -245,6 +245,203 @@
#define B_AX_HS1ISR_IND_INT BIT(25)
#define B_AX_PCIE_DBG_STE_INT BIT(13)
+#define R_BE_PCIE_FRZ_CLK 0x3004
+#define B_BE_PCIE_FRZ_MAC_HW_RST BIT(31)
+#define B_BE_PCIE_FRZ_CFG_SPC_RST BIT(30)
+#define B_BE_PCIE_FRZ_ELBI_RST BIT(29)
+#define B_BE_PCIE_MAC_IS_ACTIVE BIT(28)
+#define B_BE_PCIE_FRZ_RTK_HW_RST BIT(27)
+#define B_BE_PCIE_FRZ_REG_RST BIT(26)
+#define B_BE_PCIE_FRZ_ANA_RST BIT(25)
+#define B_BE_PCIE_FRZ_WLAN_RST BIT(24)
+#define B_BE_PCIE_FRZ_FLR_RST BIT(23)
+#define B_BE_PCIE_FRZ_RET_NON_STKY_RST BIT(22)
+#define B_BE_PCIE_FRZ_RET_STKY_RST BIT(21)
+#define B_BE_PCIE_FRZ_NON_STKY_RST BIT(20)
+#define B_BE_PCIE_FRZ_STKY_RST BIT(19)
+#define B_BE_PCIE_FRZ_RET_CORE_RST BIT(18)
+#define B_BE_PCIE_FRZ_PWR_RST BIT(17)
+#define B_BE_PCIE_FRZ_PERST_RST BIT(16)
+#define B_BE_PCIE_FRZ_PHY_ALOAD BIT(15)
+#define B_BE_PCIE_FRZ_PHY_HW_RST BIT(14)
+#define B_BE_PCIE_DBG_CLK BIT(4)
+#define B_BE_PCIE_EN_CLK BIT(3)
+#define B_BE_PCIE_DBI_ACLK_ACT BIT(2)
+#define B_BE_PCIE_S1_ACLK_ACT BIT(1)
+#define B_BE_PCIE_EN_AUX_CLK BIT(0)
+
+#define R_BE_PCIE_PS_CTRL 0x3008
+#define B_BE_RSM_L0S_EN BIT(8)
+#define B_BE_CMAC_EXIT_L1_EN BIT(7)
+#define B_BE_DMAC0_EXIT_L1_EN BIT(6)
+#define B_BE_FORCE_L0 BIT(5)
+#define B_BE_DBI_RO_WR_DISABLE BIT(4)
+#define B_BE_SEL_XFER_PENDING BIT(3)
+#define B_BE_SEL_REQ_ENTR_L1 BIT(2)
+#define B_BE_PCIE_EN_SWENT_L23 BIT(1)
+#define B_BE_SEL_REQ_EXIT_L1 BIT(0)
+
+#define R_BE_PCIE_LAT_CTRL 0x3044
+#define B_BE_ELBI_PHY_REMAP_MASK GENMASK(29, 24)
+#define B_BE_SYS_SUS_L12_EN BIT(17)
+#define B_BE_MDIO_S_EN BIT(16)
+#define B_BE_SYM_AUX_CLK_SEL BIT(15)
+#define B_BE_RTK_LDO_POWER_LATENCY_MASK GENMASK(11, 10)
+#define B_BE_RTK_LDO_BIAS_LATENCY_MASK GENMASK(9, 8)
+#define B_BE_CLK_REQ_LAT_MASK GENMASK(7, 4)
+
+#define R_BE_PCIE_HIMR0 0x30B0
+#define B_BE_PCIE_HB1_IND_INTA_IMR BIT(31)
+#define B_BE_PCIE_HB0_IND_INTA_IMR BIT(30)
+#define B_BE_HCI_AXIDMA_INTA_IMR BIT(29)
+#define B_BE_HC0_IND_INTA_IMR BIT(28)
+#define B_BE_HD1_IND_INTA_IMR BIT(27)
+#define B_BE_HD0_IND_INTA_IMR BIT(26)
+#define B_BE_HS1_IND_INTA_IMR BIT(25)
+#define B_BE_HS0_IND_INTA_IMR BIT(24)
+#define B_BE_PCIE_HOTRST_INT_EN BIT(16)
+#define B_BE_PCIE_FLR_INT_EN BIT(15)
+#define B_BE_PCIE_PERST_INT_EN BIT(14)
+#define B_BE_PCIE_DBG_STE_INT_EN BIT(13)
+#define B_BE_HB1_IND_INT_EN0 BIT(9)
+#define B_BE_HB0_IND_INT_EN0 BIT(8)
+#define B_BE_HC1_IND_INT_EN0 BIT(7)
+#define B_BE_HCI_AXIDMA_INT_EN0 BIT(5)
+#define B_BE_HC0_IND_INT_EN0 BIT(4)
+#define B_BE_HD1_IND_INT_EN0 BIT(3)
+#define B_BE_HD0_IND_INT_EN0 BIT(2)
+#define B_BE_HS1_IND_INT_EN0 BIT(1)
+#define B_BE_HS0_IND_INT_EN0 BIT(0)
+
+#define R_BE_PCIE_HISR 0x30B4
+#define B_BE_PCIE_HOTRST_INT BIT(16)
+#define B_BE_PCIE_FLR_INT BIT(15)
+#define B_BE_PCIE_PERST_INT BIT(14)
+#define B_BE_PCIE_DBG_STE_INT BIT(13)
+#define B_BE_HB1IMR_IND BIT(9)
+#define B_BE_HB0IMR_IND BIT(8)
+#define B_BE_HC1ISR_IND_INT BIT(7)
+#define B_BE_HCI_AXIDMA_INT BIT(5)
+#define B_BE_HC0ISR_IND_INT BIT(4)
+#define B_BE_HD1ISR_IND_INT BIT(3)
+#define B_BE_HD0ISR_IND_INT BIT(2)
+#define B_BE_HS1ISR_IND_INT BIT(1)
+#define B_BE_HS0ISR_IND_INT BIT(0)
+
+#define R_BE_PCIE_DMA_IMR_0_V1 0x30B8
+#define B_BE_PCIE_RX_RX1P1_IMR0_V1 BIT(23)
+#define B_BE_PCIE_RX_RX0P1_IMR0_V1 BIT(22)
+#define B_BE_PCIE_RX_ROQ1_IMR0_V1 BIT(21)
+#define B_BE_PCIE_RX_RPQ1_IMR0_V1 BIT(20)
+#define B_BE_PCIE_RX_RX1P2_IMR0_V1 BIT(19)
+#define B_BE_PCIE_RX_ROQ0_IMR0_V1 BIT(18)
+#define B_BE_PCIE_RX_RPQ0_IMR0_V1 BIT(17)
+#define B_BE_PCIE_RX_RX0P2_IMR0_V1 BIT(16)
+#define B_BE_PCIE_TX_CH14_IMR0 BIT(14)
+#define B_BE_PCIE_TX_CH13_IMR0 BIT(13)
+#define B_BE_PCIE_TX_CH12_IMR0 BIT(12)
+#define B_BE_PCIE_TX_CH11_IMR0 BIT(11)
+#define B_BE_PCIE_TX_CH10_IMR0 BIT(10)
+#define B_BE_PCIE_TX_CH9_IMR0 BIT(9)
+#define B_BE_PCIE_TX_CH8_IMR0 BIT(8)
+#define B_BE_PCIE_TX_CH7_IMR0 BIT(7)
+#define B_BE_PCIE_TX_CH6_IMR0 BIT(6)
+#define B_BE_PCIE_TX_CH5_IMR0 BIT(5)
+#define B_BE_PCIE_TX_CH4_IMR0 BIT(4)
+#define B_BE_PCIE_TX_CH3_IMR0 BIT(3)
+#define B_BE_PCIE_TX_CH2_IMR0 BIT(2)
+#define B_BE_PCIE_TX_CH1_IMR0 BIT(1)
+#define B_BE_PCIE_TX_CH0_IMR0 BIT(0)
+
+#define R_BE_PCIE_DMA_ISR 0x30BC
+#define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23)
+#define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22)
+#define B_BE_PCIE_RX_ROQ1_ISR_V1 BIT(21)
+#define B_BE_PCIE_RX_RPQ1_ISR_V1 BIT(20)
+#define B_BE_PCIE_RX_RX1P2_ISR_V1 BIT(19)
+#define B_BE_PCIE_RX_ROQ0_ISR_V1 BIT(18)
+#define B_BE_PCIE_RX_RPQ0_ISR_V1 BIT(17)
+#define B_BE_PCIE_RX_RX0P2_ISR_V1 BIT(16)
+#define B_BE_PCIE_TX_CH14_ISR BIT(14)
+#define B_BE_PCIE_TX_CH13_ISR BIT(13)
+#define B_BE_PCIE_TX_CH12_ISR BIT(12)
+#define B_BE_PCIE_TX_CH11_ISR BIT(11)
+#define B_BE_PCIE_TX_CH10_ISR BIT(10)
+#define B_BE_PCIE_TX_CH9_ISR BIT(9)
+#define B_BE_PCIE_TX_CH8_ISR BIT(8)
+#define B_BE_PCIE_TX_CH7_ISR BIT(7)
+#define B_BE_PCIE_TX_CH6_ISR BIT(6)
+#define B_BE_PCIE_TX_CH5_ISR BIT(5)
+#define B_BE_PCIE_TX_CH4_ISR BIT(4)
+#define B_BE_PCIE_TX_CH3_ISR BIT(3)
+#define B_BE_PCIE_TX_CH2_ISR BIT(2)
+#define B_BE_PCIE_TX_CH1_ISR BIT(1)
+#define B_BE_PCIE_TX_CH0_ISR BIT(0)
+
+#define R_BE_HAXI_HIMR00 0xB0B0
+#define B_BE_RDU_CH5_INT_IMR_V1 BIT(30)
+#define B_BE_RDU_CH4_INT_IMR_V1 BIT(29)
+#define B_BE_RDU_CH3_INT_IMR_V1 BIT(28)
+#define B_BE_RDU_CH2_INT_IMR_V1 BIT(27)
+#define B_BE_RDU_CH1_INT_IMR_V1 BIT(26)
+#define B_BE_RDU_CH0_INT_IMR_V1 BIT(25)
+#define B_BE_RXDMA_STUCK_INT_EN_V1 BIT(24)
+#define B_BE_TXDMA_STUCK_INT_EN_V1 BIT(23)
+#define B_BE_TXDMA_CH14_INT_EN_V1 BIT(22)
+#define B_BE_TXDMA_CH13_INT_EN_V1 BIT(21)
+#define B_BE_TXDMA_CH12_INT_EN_V1 BIT(20)
+#define B_BE_TXDMA_CH11_INT_EN_V1 BIT(19)
+#define B_BE_TXDMA_CH10_INT_EN_V1 BIT(18)
+#define B_BE_TXDMA_CH9_INT_EN_V1 BIT(17)
+#define B_BE_TXDMA_CH8_INT_EN_V1 BIT(16)
+#define B_BE_TXDMA_CH7_INT_EN_V1 BIT(15)
+#define B_BE_TXDMA_CH6_INT_EN_V1 BIT(14)
+#define B_BE_TXDMA_CH5_INT_EN_V1 BIT(13)
+#define B_BE_TXDMA_CH4_INT_EN_V1 BIT(12)
+#define B_BE_TXDMA_CH3_INT_EN_V1 BIT(11)
+#define B_BE_TXDMA_CH2_INT_EN_V1 BIT(10)
+#define B_BE_TXDMA_CH1_INT_EN_V1 BIT(9)
+#define B_BE_TXDMA_CH0_INT_EN_V1 BIT(8)
+#define B_BE_RX1P1DMA_INT_EN_V1 BIT(7)
+#define B_BE_RX0P1DMA_INT_EN_V1 BIT(6)
+#define B_BE_RO1DMA_INT_EN BIT(5)
+#define B_BE_RP1DMA_INT_EN BIT(4)
+#define B_BE_RX1DMA_INT_EN BIT(3)
+#define B_BE_RO0DMA_INT_EN BIT(2)
+#define B_BE_RP0DMA_INT_EN BIT(1)
+#define B_BE_RX0DMA_INT_EN BIT(0)
+
+#define R_BE_HAXI_HISR00 0xB0B4
+#define B_BE_RDU_CH6_INT BIT(28)
+#define B_BE_RDU_CH5_INT BIT(27)
+#define B_BE_RDU_CH4_INT BIT(26)
+#define B_BE_RDU_CH2_INT BIT(25)
+#define B_BE_RDU_CH1_INT BIT(24)
+#define B_BE_RDU_CH0_INT BIT(23)
+#define B_BE_RXDMA_STUCK_INT BIT(22)
+#define B_BE_TXDMA_STUCK_INT BIT(21)
+#define B_BE_TXDMA_CH14_INT BIT(20)
+#define B_BE_TXDMA_CH13_INT BIT(19)
+#define B_BE_TXDMA_CH12_INT BIT(18)
+#define B_BE_TXDMA_CH11_INT BIT(17)
+#define B_BE_TXDMA_CH10_INT BIT(16)
+#define B_BE_TXDMA_CH9_INT BIT(15)
+#define B_BE_TXDMA_CH8_INT BIT(14)
+#define B_BE_TXDMA_CH7_INT BIT(13)
+#define B_BE_TXDMA_CH6_INT BIT(12)
+#define B_BE_TXDMA_CH5_INT BIT(11)
+#define B_BE_TXDMA_CH4_INT BIT(10)
+#define B_BE_TXDMA_CH3_INT BIT(9)
+#define B_BE_TXDMA_CH2_INT BIT(8)
+#define B_BE_TXDMA_CH1_INT BIT(7)
+#define B_BE_TXDMA_CH0_INT BIT(6)
+#define B_BE_RPQ1DMA_INT BIT(5)
+#define B_BE_RX1P1DMA_INT BIT(4)
+#define B_BE_RX1DMA_INT BIT(3)
+#define B_BE_RPQ0DMA_INT BIT(2)
+#define B_BE_RX0P1DMA_INT BIT(1)
+#define B_BE_RX0DMA_INT BIT(0)
+
/* TX/RX */
#define R_AX_DRV_FW_HSK_0 0x01B0
#define R_AX_DRV_FW_HSK_1 0x01B4
@@ -496,6 +693,105 @@
#define B_AX_CH11_BUSY BIT(1)
#define B_AX_CH10_BUSY BIT(0)
+#define R_BE_HAXI_DMA_STOP1 0xB010
+#define B_BE_STOP_WPDMA BIT(31)
+#define B_BE_STOP_CH14 BIT(14)
+#define B_BE_STOP_CH13 BIT(13)
+#define B_BE_STOP_CH12 BIT(12)
+#define B_BE_STOP_CH11 BIT(11)
+#define B_BE_STOP_CH10 BIT(10)
+#define B_BE_STOP_CH9 BIT(9)
+#define B_BE_STOP_CH8 BIT(8)
+#define B_BE_STOP_CH7 BIT(7)
+#define B_BE_STOP_CH6 BIT(6)
+#define B_BE_STOP_CH5 BIT(5)
+#define B_BE_STOP_CH4 BIT(4)
+#define B_BE_STOP_CH3 BIT(3)
+#define B_BE_STOP_CH2 BIT(2)
+#define B_BE_STOP_CH1 BIT(1)
+#define B_BE_STOP_CH0 BIT(0)
+#define B_BE_TX_STOP1_MASK (B_BE_STOP_CH0 | B_BE_STOP_CH1 | \
+ B_BE_STOP_CH2 | B_BE_STOP_CH3 | \
+ B_BE_STOP_CH4 | B_BE_STOP_CH5 | \
+ B_BE_STOP_CH6 | B_BE_STOP_CH7 | \
+ B_BE_STOP_CH8 | B_BE_STOP_CH9 | \
+ B_BE_STOP_CH10 | B_BE_STOP_CH11 | \
+ B_BE_STOP_CH12)
+
+#define R_BE_CH0_TXBD_NUM_V1 0xB030
+#define R_BE_CH1_TXBD_NUM_V1 0xB032
+#define R_BE_CH2_TXBD_NUM_V1 0xB034
+#define R_BE_CH3_TXBD_NUM_V1 0xB036
+#define R_BE_CH4_TXBD_NUM_V1 0xB038
+#define R_BE_CH5_TXBD_NUM_V1 0xB03A
+#define R_BE_CH6_TXBD_NUM_V1 0xB03C
+#define R_BE_CH7_TXBD_NUM_V1 0xB03E
+#define R_BE_CH8_TXBD_NUM_V1 0xB040
+#define R_BE_CH9_TXBD_NUM_V1 0xB042
+#define R_BE_CH10_TXBD_NUM_V1 0xB044
+#define R_BE_CH11_TXBD_NUM_V1 0xB046
+#define R_BE_CH12_TXBD_NUM_V1 0xB048
+#define R_BE_CH13_TXBD_NUM_V1 0xB04C
+#define R_BE_CH14_TXBD_NUM_V1 0xB04E
+
+#define R_BE_RXQ0_RXBD_NUM_V1 0xB050
+#define R_BE_RPQ0_RXBD_NUM_V1 0xB052
+
+#define R_BE_CH0_TXBD_IDX_V1 0xB100
+#define R_BE_CH1_TXBD_IDX_V1 0xB104
+#define R_BE_CH2_TXBD_IDX_V1 0xB108
+#define R_BE_CH3_TXBD_IDX_V1 0xB10C
+#define R_BE_CH4_TXBD_IDX_V1 0xB110
+#define R_BE_CH5_TXBD_IDX_V1 0xB114
+#define R_BE_CH6_TXBD_IDX_V1 0xB118
+#define R_BE_CH7_TXBD_IDX_V1 0xB11C
+#define R_BE_CH8_TXBD_IDX_V1 0xB120
+#define R_BE_CH9_TXBD_IDX_V1 0xB124
+#define R_BE_CH10_TXBD_IDX_V1 0xB128
+#define R_BE_CH11_TXBD_IDX_V1 0xB12C
+#define R_BE_CH12_TXBD_IDX_V1 0xB130
+#define R_BE_CH13_TXBD_IDX_V1 0xB134
+#define R_BE_CH14_TXBD_IDX_V1 0xB138
+
+#define R_BE_RXQ0_RXBD_IDX_V1 0xB160
+#define R_BE_RPQ0_RXBD_IDX_V1 0xB164
+
+#define R_BE_CH0_TXBD_DESA_L_V1 0xB200
+#define R_BE_CH0_TXBD_DESA_H_V1 0xB204
+#define R_BE_CH1_TXBD_DESA_L_V1 0xB208
+#define R_BE_CH1_TXBD_DESA_H_V1 0xB20C
+#define R_BE_CH2_TXBD_DESA_L_V1 0xB210
+#define R_BE_CH2_TXBD_DESA_H_V1 0xB214
+#define R_BE_CH3_TXBD_DESA_L_V1 0xB218
+#define R_BE_CH3_TXBD_DESA_H_V1 0xB21C
+#define R_BE_CH4_TXBD_DESA_L_V1 0xB220
+#define R_BE_CH4_TXBD_DESA_H_V1 0xB224
+#define R_BE_CH5_TXBD_DESA_L_V1 0xB228
+#define R_BE_CH5_TXBD_DESA_H_V1 0xB22C
+#define R_BE_CH6_TXBD_DESA_L_V1 0xB230
+#define R_BE_CH6_TXBD_DESA_H_V1 0xB234
+#define R_BE_CH7_TXBD_DESA_L_V1 0xB238
+#define R_BE_CH7_TXBD_DESA_H_V1 0xB23C
+#define R_BE_CH8_TXBD_DESA_L_V1 0xB240
+#define R_BE_CH8_TXBD_DESA_H_V1 0xB244
+#define R_BE_CH9_TXBD_DESA_L_V1 0xB248
+#define R_BE_CH9_TXBD_DESA_H_V1 0xB24C
+#define R_BE_CH10_TXBD_DESA_L_V1 0xB250
+#define R_BE_CH10_TXBD_DESA_H_V1 0xB254
+#define R_BE_CH11_TXBD_DESA_L_V1 0xB258
+#define R_BE_CH11_TXBD_DESA_H_V1 0xB25C
+#define R_BE_CH12_TXBD_DESA_L_V1 0xB260
+#define R_BE_CH12_TXBD_DESA_H_V1 0xB264
+#define R_BE_CH13_TXBD_DESA_L_V1 0xB268
+#define R_BE_CH13_TXBD_DESA_H_V1 0xB26C
+#define R_BE_CH14_TXBD_DESA_L_V1 0xB270
+#define R_BE_CH14_TXBD_DESA_H_V1 0xB274
+
+#define R_BE_RXQ0_RXBD_DESA_L_V1 0xB300
+#define R_BE_RXQ0_RXBD_DESA_H_V1 0xB304
+#define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308
+#define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C
+
/* Configure */
#define R_AX_PCIE_INIT_CFG2 0x1004
#define B_AX_WD_ITVL_IDLE GENMASK(27, 24)
@@ -516,6 +812,15 @@
#define B_AX_RXCOUNTER_MATCH_MASK GENMASK(15, 8)
#define B_AX_RXTIMER_MATCH_MASK GENMASK(7, 0)
+#define R_AX_DBG_ERR_FLAG_V1 0x1104
+
+#define R_AX_INT_MIT_RX_V1 0x1184
+#define B_AX_RXMIT_RXP2_SEL_V1 BIT(19)
+#define B_AX_RXMIT_RXP1_SEL_V1 BIT(18)
+#define B_AX_MIT_RXTIMER_UNIT_MASK GENMASK(17, 16)
+#define B_AX_MIT_RXCOUNTER_MATCH_MASK GENMASK(15, 8)
+#define B_AX_MIT_RXTIMER_MATCH_MASK GENMASK(7, 0)
+
#define R_AX_DBG_ERR_FLAG 0x11C4
#define B_AX_PCIE_RPQ_FULL BIT(29)
#define B_AX_PCIE_RXQ_FULL BIT(28)
@@ -554,6 +859,138 @@
#define R_AX_PCIE_HRPWM_V1 0x30C0
#define R_AX_PCIE_CRPWM 0x30C4
+#define R_AX_LBC_WATCHDOG_V1 0x30D8
+
+#define R_BE_PCIE_HRPWM 0x30C0
+#define R_BE_PCIE_CRPWM 0x30C4
+
+#define R_BE_L1_2_CTRL_HCILDO 0x3110
+#define B_BE_PCIE_DIS_L1_2_CTRL_HCILDO BIT(0)
+
+#define R_BE_PL1_DBG_INFO 0x3120
+#define B_BE_END_PL1_CNT_MASK GENMASK(23, 16)
+#define B_BE_START_PL1_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_PCIE_MIT0_TMR 0x3330
+#define B_BE_PCIE_MIT0_RX_TMR_MASK GENMASK(5, 4)
+#define BE_MIT0_TMR_UNIT_1MS 0
+#define BE_MIT0_TMR_UNIT_2MS 1
+#define BE_MIT0_TMR_UNIT_4MS 2
+#define BE_MIT0_TMR_UNIT_8MS 3
+#define B_BE_PCIE_MIT0_TX_TMR_MASK GENMASK(1, 0)
+
+#define R_BE_PCIE_MIT0_CNT 0x3334
+#define B_BE_PCIE_RX_MIT0_CNT_MASK GENMASK(31, 24)
+#define B_BE_PCIE_TX_MIT0_CNT_MASK GENMASK(23, 16)
+#define B_BE_PCIE_RX_MIT0_TMR_CNT_MASK GENMASK(15, 8)
+#define B_BE_PCIE_TX_MIT0_TMR_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_PCIE_MIT_CH_EN 0x3338
+#define B_BE_PCIE_MIT_RX1P1_EN BIT(23)
+#define B_BE_PCIE_MIT_RX0P1_EN BIT(22)
+#define B_BE_PCIE_MIT_ROQ1_EN BIT(21)
+#define B_BE_PCIE_MIT_RPQ1_EN BIT(20)
+#define B_BE_PCIE_MIT_RX1P2_EN BIT(19)
+#define B_BE_PCIE_MIT_ROQ0_EN BIT(18)
+#define B_BE_PCIE_MIT_RPQ0_EN BIT(17)
+#define B_BE_PCIE_MIT_RX0P2_EN BIT(16)
+#define B_BE_PCIE_MIT_TXCH14_EN BIT(14)
+#define B_BE_PCIE_MIT_TXCH13_EN BIT(13)
+#define B_BE_PCIE_MIT_TXCH12_EN BIT(12)
+#define B_BE_PCIE_MIT_TXCH11_EN BIT(11)
+#define B_BE_PCIE_MIT_TXCH10_EN BIT(10)
+#define B_BE_PCIE_MIT_TXCH9_EN BIT(9)
+#define B_BE_PCIE_MIT_TXCH8_EN BIT(8)
+#define B_BE_PCIE_MIT_TXCH7_EN BIT(7)
+#define B_BE_PCIE_MIT_TXCH6_EN BIT(6)
+#define B_BE_PCIE_MIT_TXCH5_EN BIT(5)
+#define B_BE_PCIE_MIT_TXCH4_EN BIT(4)
+#define B_BE_PCIE_MIT_TXCH3_EN BIT(3)
+#define B_BE_PCIE_MIT_TXCH2_EN BIT(2)
+#define B_BE_PCIE_MIT_TXCH1_EN BIT(1)
+#define B_BE_PCIE_MIT_TXCH0_EN BIT(0)
+
+#define R_BE_SER_PL1_CTRL 0x34A8
+#define B_BE_PL1_SER_PL1_EN BIT(31)
+#define B_BE_PL1_IGNORE_HOT_RST BIT(30)
+#define B_BE_PL1_TIMER_UNIT_MASK GENMASK(19, 17)
+#define B_BE_PL1_TIMER_CLEAR BIT(0)
+
+#define R_BE_REG_PL1_MASK 0x34B0
+#define B_BE_SER_PCLKREQ_ACK_MASK BIT(5)
+#define B_BE_SER_PM_CLK_MASK BIT(4)
+#define B_BE_SER_LTSSM_IMR BIT(3)
+#define B_BE_SER_PM_MASTER_IMR BIT(2)
+#define B_BE_SER_L1SUB_IMR BIT(1)
+#define B_BE_SER_PMU_IMR BIT(0)
+
+#define R_BE_RX_APPEND_MODE 0x8920
+#define B_BE_APPEND_OFFSET_MASK GENMASK(23, 16)
+#define B_BE_APPEND_LEN_MASK GENMASK(15, 0)
+
+#define R_BE_TXBD_RWPTR_CLR1 0xB014
+#define B_BE_CLR_CH14_IDX BIT(14)
+#define B_BE_CLR_CH13_IDX BIT(13)
+#define B_BE_CLR_CH12_IDX BIT(12)
+#define B_BE_CLR_CH11_IDX BIT(11)
+#define B_BE_CLR_CH10_IDX BIT(10)
+#define B_BE_CLR_CH9_IDX BIT(9)
+#define B_BE_CLR_CH8_IDX BIT(8)
+#define B_BE_CLR_CH7_IDX BIT(7)
+#define B_BE_CLR_CH6_IDX BIT(6)
+#define B_BE_CLR_CH5_IDX BIT(5)
+#define B_BE_CLR_CH4_IDX BIT(4)
+#define B_BE_CLR_CH3_IDX BIT(3)
+#define B_BE_CLR_CH2_IDX BIT(2)
+#define B_BE_CLR_CH1_IDX BIT(1)
+#define B_BE_CLR_CH0_IDX BIT(0)
+
+#define R_BE_RXBD_RWPTR_CLR1_V1 0xB018
+#define B_BE_CLR_ROQ1_IDX_V1 BIT(5)
+#define B_BE_CLR_RPQ1_IDX_V1 BIT(4)
+#define B_BE_CLR_RXQ1_IDX_V1 BIT(3)
+#define B_BE_CLR_ROQ0_IDX BIT(2)
+#define B_BE_CLR_RPQ0_IDX BIT(1)
+#define B_BE_CLR_RXQ0_IDX BIT(0)
+
+#define R_BE_HAXI_DMA_BUSY1 0xB01C
+#define B_BE_HAXI_MST_BUSY BIT(31)
+#define B_BE_HAXI_RX_IDLE BIT(25)
+#define B_BE_HAXI_TX_IDLE BIT(24)
+#define B_BE_ROQ1_BUSY_V1 BIT(21)
+#define B_BE_RPQ1_BUSY_V1 BIT(20)
+#define B_BE_RXQ1_BUSY_V1 BIT(19)
+#define B_BE_ROQ0_BUSY_V1 BIT(18)
+#define B_BE_RPQ0_BUSY_V1 BIT(17)
+#define B_BE_RXQ0_BUSY_V1 BIT(16)
+#define B_BE_WPDMA_BUSY BIT(15)
+#define B_BE_CH14_BUSY BIT(14)
+#define B_BE_CH13_BUSY BIT(13)
+#define B_BE_CH12_BUSY BIT(12)
+#define B_BE_CH11_BUSY BIT(11)
+#define B_BE_CH10_BUSY BIT(10)
+#define B_BE_CH9_BUSY BIT(9)
+#define B_BE_CH8_BUSY BIT(8)
+#define B_BE_CH7_BUSY BIT(7)
+#define B_BE_CH6_BUSY BIT(6)
+#define B_BE_CH5_BUSY BIT(5)
+#define B_BE_CH4_BUSY BIT(4)
+#define B_BE_CH3_BUSY BIT(3)
+#define B_BE_CH2_BUSY BIT(2)
+#define B_BE_CH1_BUSY BIT(1)
+#define B_BE_CH0_BUSY BIT(0)
+#define DMA_BUSY1_CHECK_BE (B_BE_CH0_BUSY | B_BE_CH1_BUSY | B_BE_CH2_BUSY | \
+ B_BE_CH3_BUSY | B_BE_CH4_BUSY | B_BE_CH5_BUSY | \
+ B_BE_CH6_BUSY | B_BE_CH7_BUSY | B_BE_CH8_BUSY | \
+ B_BE_CH9_BUSY | B_BE_CH10_BUSY | B_BE_CH11_BUSY | \
+ B_BE_CH12_BUSY | B_BE_CH13_BUSY | B_BE_CH14_BUSY)
+
+#define R_BE_HAXI_EXP_CTRL_V1 0xB020
+#define B_BE_R_NO_SEC_ACCESS BIT(31)
+#define B_BE_FORCE_EN_DMA_RX_GCLK BIT(5)
+#define B_BE_FORCE_EN_DMA_TX_GCLK BIT(4)
+#define B_BE_MAX_TAG_NUM_MASK GENMASK(3, 0)
+
#define RTW89_PCI_TXBD_NUM_MAX 256
#define RTW89_PCI_RXBD_NUM_MAX 256
#define RTW89_PCI_TXWD_NUM_MAX 512
@@ -565,12 +1002,15 @@
#define RTW89_PCI_MULTITAG 8
/* PCIE CFG register */
+#define RTW89_PCIE_CAPABILITY_SPEED 0x7C
+#define RTW89_PCIE_SUPPORT_GEN_MASK GENMASK(3, 0)
#define RTW89_PCIE_L1_STS_V1 0x80
#define RTW89_BCFG_LINK_SPEED_MASK GENMASK(19, 16)
#define RTW89_PCIE_GEN1_SPEED 0x01
#define RTW89_PCIE_GEN2_SPEED 0x02
#define RTW89_PCIE_PHY_RATE 0x82
#define RTW89_PCIE_PHY_RATE_MASK GENMASK(1, 0)
+#define RTW89_PCIE_LINK_CHANGE_SPEED 0xA0
#define RTW89_PCIE_L1SS_STS_V1 0x0168
#define RTW89_PCIE_BIT_ASPM_L11 BIT(3)
#define RTW89_PCIE_BIT_ASPM_L12 BIT(2)
@@ -585,6 +1025,8 @@
#define RTW89_PCIE_BIT_CLK BIT(4)
#define RTW89_PCIE_BIT_L1 BIT(3)
#define RTW89_PCIE_CLK_CTRL 0x0725
+#define RTW89_PCIE_FTS 0x080C
+#define RTW89_PCIE_POLLING_BIT BIT(17)
#define RTW89_PCIE_RST_MSTATE 0x0B48
#define RTW89_PCIE_BIT_CFG_RST_MSTATE BIT(0)
@@ -757,7 +1199,26 @@ struct rtw89_pci_bd_ram {
u8 min_num;
};
+struct rtw89_pci_gen_def {
+ u32 isr_rdu;
+ u32 isr_halt_c2h;
+ u32 isr_wdt_timeout;
+ struct rtw89_reg2_def isr_clear_rpq;
+ struct rtw89_reg2_def isr_clear_rxq;
+
+ int (*mac_pre_init)(struct rtw89_dev *rtwdev);
+ int (*mac_pre_deinit)(struct rtw89_dev *rtwdev);
+ int (*mac_post_init)(struct rtw89_dev *rtwdev);
+
+ void (*clr_idx_all)(struct rtw89_dev *rtwdev);
+ int (*rst_bdram)(struct rtw89_dev *rtwdev);
+
+ int (*lv1rst_stop_dma)(struct rtw89_dev *rtwdev);
+ int (*lv1rst_start_dma)(struct rtw89_dev *rtwdev);
+};
+
struct rtw89_pci_info {
+ const struct rtw89_pci_gen_def *gen_def;
enum mac_ax_bd_trunc_mode txbd_trunc_mode;
enum mac_ax_bd_trunc_mode rxbd_trunc_mode;
enum mac_ax_rxbd_mode rxbd_mode;
@@ -772,6 +1233,7 @@ struct rtw89_pci_info {
enum mac_ax_pcie_func_ctrl autok_en;
enum mac_ax_pcie_func_ctrl io_rcy_en;
enum mac_ax_io_rcy_tmr io_rcy_tmr;
+ bool rx_ring_eq_is_full;
u32 init_cfg_reg;
u32 txhci_en_bit;
@@ -781,6 +1243,7 @@ struct rtw89_pci_info {
u32 max_tag_num_mask;
u32 rxbd_rwptr_clr_reg;
u32 txbd_rwptr_clr2_reg;
+ struct rtw89_reg_def dma_io_stop;
struct rtw89_reg_def dma_stop1;
struct rtw89_reg_def dma_stop2;
struct rtw89_reg_def dma_busy1;
@@ -789,6 +1252,7 @@ struct rtw89_pci_info {
u32 rpwm_addr;
u32 cpwm_addr;
+ u32 mit_addr;
u32 tx_dma_ch_mask;
const struct rtw89_pci_bd_idx_addr *bd_idx_addr_low_power;
const struct rtw89_pci_ch_dma_addr_set *dma_addr_set;
@@ -1059,33 +1523,45 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val)
extern const struct dev_pm_ops rtw89_pm_ops;
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set;
extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1;
+extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be;
extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM];
extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM];
+extern const struct rtw89_pci_gen_def rtw89_pci_gen_ax;
+extern const struct rtw89_pci_gen_def rtw89_pci_gen_be;
struct pci_device_id;
int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
void rtw89_pci_remove(struct pci_dev *pdev);
+void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev);
int rtw89_pci_ltr_set(struct rtw89_dev *rtwdev, bool en);
int rtw89_pci_ltr_set_v1(struct rtw89_dev *rtwdev, bool en);
+int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en);
u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev,
void *txaddr_info_addr, u32 total_len,
dma_addr_t dma, u8 *add_info_nr);
u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev,
void *txaddr_info_addr, u32 total_len,
dma_addr_t dma, u8 *add_info_nr);
+void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable);
void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev);
void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev);
+void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev);
void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
+void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci);
void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev,
struct rtw89_pci *rtwpci,
struct rtw89_pci_isrs *isrs);
void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev,
struct rtw89_pci *rtwpci,
struct rtw89_pci_isrs *isrs);
+void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev,
+ struct rtw89_pci *rtwpci,
+ struct rtw89_pci_isrs *isrs);
static inline
u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev,
@@ -1157,4 +1633,47 @@ void rtw89_chip_recognize_intrs(struct rtw89_dev *rtwdev,
info->recognize_intrs(rtwdev, rtwpci, isrs);
}
+static inline int rtw89_pci_ops_mac_pre_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
+
+ return gen_def->mac_pre_init(rtwdev);
+}
+
+static inline int rtw89_pci_ops_mac_pre_deinit(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
+
+ if (!gen_def->mac_pre_deinit)
+ return 0;
+
+ return gen_def->mac_pre_deinit(rtwdev);
+}
+
+static inline int rtw89_pci_ops_mac_post_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
+
+ return gen_def->mac_post_init(rtwdev);
+}
+
+static inline void rtw89_pci_clr_idx_all(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
+
+ gen_def->clr_idx_all(rtwdev);
+}
+
+static inline int rtw89_pci_reset_bdram(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ const struct rtw89_pci_gen_def *gen_def = info->gen_def;
+
+ return gen_def->rst_bdram(rtwdev);
+}
+
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c
new file mode 100644
index 000000000000..629ffa4bee91
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/pci_be.c
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#include <linux/pci.h>
+
+#include "mac.h"
+#include "pci.h"
+#include "reg.h"
+
+enum pcie_rxbd_mode {
+ PCIE_RXBD_NORM = 0,
+ PCIE_RXBD_SEP,
+ PCIE_RXBD_EXT,
+};
+
+#define PL0_TMR_SCALE_ASIC 1
+#define PL0_TMR_ANA_172US 0x800
+#define PL0_TMR_MAC_1MS 0x27100
+#define PL0_TMR_AUX_1MS 0x1E848
+
+static void _patch_pcie_power_wake_be(struct rtw89_dev *rtwdev, bool power_up)
+{
+ if (power_up)
+ rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1);
+ else
+ rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, BIT_WAKE_CTRL_V1);
+}
+
+static void rtw89_pci_set_io_rcy_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ u32 scale = PL0_TMR_SCALE_ASIC;
+ u32 val32;
+
+ if (info->io_rcy_en == MAC_AX_PCIE_ENABLE) {
+ val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ?
+ PL0_TMR_ANA_172US : info->io_rcy_tmr;
+ val32 /= scale;
+
+ rtw89_write32(rtwdev, R_BE_AON_WDT_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_MDIO_WDT_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_LA_MODE_WDT_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_WDT_AR_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_WDT_AW_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_WDT_W_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_WDT_B_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_WDT_R_TMR, val32);
+
+ val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ?
+ PL0_TMR_MAC_1MS : info->io_rcy_tmr;
+ val32 /= scale;
+ rtw89_write32(rtwdev, R_BE_WLAN_WDT_TMR, val32);
+ rtw89_write32(rtwdev, R_BE_AXIDMA_WDT_TMR, val32);
+
+ val32 = info->io_rcy_tmr == MAC_AX_IO_RCY_ANA_TMR_DEF ?
+ PL0_TMR_AUX_1MS : info->io_rcy_tmr;
+ val32 /= scale;
+ rtw89_write32(rtwdev, R_BE_LOCAL_WDT_TMR, val32);
+ } else {
+ rtw89_write32_clr(rtwdev, R_BE_WLAN_WDT, B_BE_WLAN_WDT_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_AXIDMA_WDT, B_BE_AXIDMA_WDT_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_AON_WDT, B_BE_AON_WDT_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_LOCAL_WDT, B_BE_LOCAL_WDT_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_MDIO_WDT, B_BE_MDIO_WDT_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_LA_MODE_WDT, B_BE_LA_MODE_WDT_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_WDT_AR, B_BE_WDT_AR_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_WDT_AW, B_BE_WDT_AW_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_WDT_W, B_BE_WDT_W_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_WDT_B, B_BE_WDT_B_ENABLE);
+ rtw89_write32_clr(rtwdev, R_BE_WDT_R, B_BE_WDT_R_ENABLE);
+ }
+}
+
+static void rtw89_pci_ctrl_wpdma_pcie_be(struct rtw89_dev *rtwdev, bool en)
+{
+ if (en)
+ rtw89_write32_clr(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA);
+ else
+ rtw89_write32_set(rtwdev, R_BE_HAXI_DMA_STOP1, B_BE_STOP_WPDMA);
+}
+
+static void rtw89_pci_ctrl_trxdma_pcie_be(struct rtw89_dev *rtwdev,
+ enum mac_ax_pcie_func_ctrl tx_en,
+ enum mac_ax_pcie_func_ctrl rx_en,
+ enum mac_ax_pcie_func_ctrl io_en)
+{
+ u32 val;
+
+ val = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1);
+
+ if (tx_en == MAC_AX_PCIE_ENABLE)
+ val |= B_BE_TXDMA_EN;
+ else if (tx_en == MAC_AX_PCIE_DISABLE)
+ val &= ~B_BE_TXDMA_EN;
+
+ if (rx_en == MAC_AX_PCIE_ENABLE)
+ val |= B_BE_RXDMA_EN;
+ else if (rx_en == MAC_AX_PCIE_DISABLE)
+ val &= ~B_BE_RXDMA_EN;
+
+ if (io_en == MAC_AX_PCIE_ENABLE)
+ val &= ~B_BE_STOP_AXI_MST;
+ else if (io_en == MAC_AX_PCIE_DISABLE)
+ val |= B_BE_STOP_AXI_MST;
+
+ rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val);
+}
+
+static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv;
+ struct rtw89_pci_rx_ring *rx_ring;
+ u32 val;
+
+ val = B_BE_CLR_CH0_IDX | B_BE_CLR_CH1_IDX | B_BE_CLR_CH2_IDX |
+ B_BE_CLR_CH3_IDX | B_BE_CLR_CH4_IDX | B_BE_CLR_CH5_IDX |
+ B_BE_CLR_CH6_IDX | B_BE_CLR_CH7_IDX | B_BE_CLR_CH8_IDX |
+ B_BE_CLR_CH9_IDX | B_BE_CLR_CH10_IDX | B_BE_CLR_CH11_IDX |
+ B_BE_CLR_CH12_IDX | B_BE_CLR_CH13_IDX | B_BE_CLR_CH14_IDX;
+ rtw89_write32(rtwdev, R_BE_TXBD_RWPTR_CLR1, val);
+
+ rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1,
+ B_BE_CLR_RXQ0_IDX | B_BE_CLR_RPQ0_IDX);
+
+ rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ];
+ rtw89_write16(rtwdev, R_BE_RXQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1);
+
+ rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ];
+ rtw89_write16(rtwdev, R_BE_RPQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1);
+}
+
+static int rtw89_pci_poll_txdma_ch_idle_be(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ return read_poll_timeout(rtw89_read32, val, (val & DMA_BUSY1_CHECK_BE) == 0,
+ 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1);
+}
+
+static int rtw89_pci_poll_rxdma_ch_idle_be(struct rtw89_dev *rtwdev)
+{
+ u32 check;
+ u32 val;
+
+ check = B_BE_RXQ0_BUSY_V1 | B_BE_RPQ0_BUSY_V1;
+
+ return read_poll_timeout(rtw89_read32, val, (val & check) == 0,
+ 10, 1000, false, rtwdev, R_BE_HAXI_DMA_BUSY1);
+}
+
+static int rtw89_pci_poll_dma_all_idle_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ ret = rtw89_pci_poll_txdma_ch_idle_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "txdma ch busy\n");
+ return ret;
+ }
+
+ ret = rtw89_pci_poll_rxdma_ch_idle_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "rxdma ch busy\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rtw89_pci_mode_op_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ u32 val32_init1, val32_rxapp, val32_exp;
+
+ val32_init1 = rtw89_read32(rtwdev, R_BE_HAXI_INIT_CFG1);
+ val32_rxapp = rtw89_read32(rtwdev, R_BE_RX_APPEND_MODE);
+ val32_exp = rtw89_read32(rtwdev, R_BE_HAXI_EXP_CTRL_V1);
+
+ if (info->rxbd_mode == MAC_AX_RXBD_PKT) {
+ val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_NORM,
+ B_BE_RXQ_RXBD_MODE_MASK);
+ } else if (info->rxbd_mode == MAC_AX_RXBD_SEP) {
+ val32_init1 = u32_replace_bits(val32_init1, PCIE_RXBD_SEP,
+ B_BE_RXQ_RXBD_MODE_MASK);
+ val32_rxapp = u32_replace_bits(val32_rxapp, 0,
+ B_BE_APPEND_LEN_MASK);
+ }
+
+ val32_init1 = u32_replace_bits(val32_init1, info->tx_burst,
+ B_BE_MAX_TXDMA_MASK);
+ val32_init1 = u32_replace_bits(val32_init1, info->rx_burst,
+ B_BE_MAX_RXDMA_MASK);
+ val32_exp = u32_replace_bits(val32_exp, info->multi_tag_num,
+ B_BE_MAX_TAG_NUM_MASK);
+ val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_idle_intvl,
+ B_BE_CFG_WD_PERIOD_IDLE_MASK);
+ val32_init1 = u32_replace_bits(val32_init1, info->wd_dma_act_intvl,
+ B_BE_CFG_WD_PERIOD_ACTIVE_MASK);
+
+ rtw89_write32(rtwdev, R_BE_HAXI_INIT_CFG1, val32_init1);
+ rtw89_write32(rtwdev, R_BE_RX_APPEND_MODE, val32_rxapp);
+ rtw89_write32(rtwdev, R_BE_HAXI_EXP_CTRL_V1, val32_exp);
+}
+
+static int rtw89_pci_rst_bdram_be(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ rtw89_write32_set(rtwdev, R_BE_HAXI_INIT_CFG1, B_BE_SET_BDRAM_BOUND);
+
+ return read_poll_timeout(rtw89_read32, val, !(val & B_BE_SET_BDRAM_BOUND),
+ 50, 500000, false, rtwdev, R_BE_HAXI_INIT_CFG1);
+}
+
+static void rtw89_pci_debounce_be(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+
+ val32 = rtw89_read32(rtwdev, R_BE_SYS_PAGE_CLK_GATED);
+ val32 = u32_replace_bits(val32, 0, B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK);
+ val32 |= B_BE_SYM_PRST_DEBUNC_SEL;
+ rtw89_write32(rtwdev, R_BE_SYS_PAGE_CLK_GATED, val32);
+}
+
+static void rtw89_pci_ldo_low_pwr_be(struct rtw89_dev *rtwdev)
+{
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_PSUS_OFF_CAPC_EN);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PAGE_CLK_GATED,
+ B_BE_SOP_OFFPOOBS_PC | B_BE_CPHY_AUXCLK_OP |
+ B_BE_CPHY_POWER_READY_CHK);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN |
+ B_BE_PCIE_DIS_L2_RTK_PERST |
+ B_BE_PCIE_DIS_L2__CTRL_LDO_HCI);
+ rtw89_write32_clr(rtwdev, R_BE_L1_2_CTRL_HCILDO, B_BE_PCIE_DIS_L1_2_CTRL_HCILDO);
+}
+
+static void rtw89_pci_pcie_setting_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+ struct rtw89_hal *hal = &rtwdev->hal;
+
+ rtw89_write32_set(rtwdev, R_BE_PCIE_FRZ_CLK, B_BE_PCIE_EN_AUX_CLK);
+ rtw89_write32_clr(rtwdev, R_BE_PCIE_PS_CTRL, B_BE_CMAC_EXIT_L1_EN);
+
+ if (chip->chip_id == RTL8922A && hal->cv == CHIP_CAV)
+ return;
+
+ rtw89_write32_set(rtwdev, R_BE_EFUSE_CTRL_2_V1, B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL);
+ rtw89_write32_set(rtwdev, R_BE_PCIE_LAT_CTRL, B_BE_SYM_AUX_CLK_SEL);
+}
+
+static void rtw89_pci_ser_setting_be(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+
+ rtw89_write32(rtwdev, R_BE_PL1_DBG_INFO, 0x0);
+ rtw89_write32_set(rtwdev, R_BE_FWS1IMR, B_BE_PCIE_SER_TIMEOUT_INDIC_EN);
+ rtw89_write32_set(rtwdev, R_BE_SER_PL1_CTRL, B_BE_PL1_SER_PL1_EN);
+
+ val32 = rtw89_read32(rtwdev, R_BE_REG_PL1_MASK);
+ val32 |= B_BE_SER_PMU_IMR | B_BE_SER_L1SUB_IMR | B_BE_SER_PM_MASTER_IMR |
+ B_BE_SER_LTSSM_IMR | B_BE_SER_PM_CLK_MASK | B_BE_SER_PCLKREQ_ACK_MASK;
+ rtw89_write32(rtwdev, R_BE_REG_PL1_MASK, val32);
+}
+
+static void rtw89_pci_ctrl_txdma_ch_be(struct rtw89_dev *rtwdev, bool all_en,
+ bool h2c_en)
+{
+ u32 mask_all;
+ u32 val;
+
+ mask_all = B_BE_STOP_CH0 | B_BE_STOP_CH1 | B_BE_STOP_CH2 |
+ B_BE_STOP_CH3 | B_BE_STOP_CH4 | B_BE_STOP_CH5 |
+ B_BE_STOP_CH6 | B_BE_STOP_CH7 | B_BE_STOP_CH8 |
+ B_BE_STOP_CH9 | B_BE_STOP_CH10 | B_BE_STOP_CH11;
+
+ val = rtw89_read32(rtwdev, R_BE_HAXI_DMA_STOP1);
+ val |= B_BE_STOP_CH13 | B_BE_STOP_CH14;
+
+ if (all_en)
+ val &= ~mask_all;
+ else
+ val |= mask_all;
+
+ if (h2c_en)
+ val &= ~B_BE_STOP_CH12;
+ else
+ val |= B_BE_STOP_CH12;
+
+ rtw89_write32(rtwdev, R_BE_HAXI_DMA_STOP1, val);
+}
+
+static int rtw89_pci_ops_mac_pre_init_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ rtw89_pci_set_io_rcy_be(rtwdev);
+ _patch_pcie_power_wake_be(rtwdev, true);
+ rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, false);
+ rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE,
+ MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE);
+ rtw89_pci_clr_idx_all_be(rtwdev);
+
+ ret = rtw89_pci_poll_dma_all_idle_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR] poll pcie dma all idle\n");
+ return ret;
+ }
+
+ rtw89_pci_mode_op_be(rtwdev);
+ rtw89_pci_ops_reset(rtwdev);
+
+ ret = rtw89_pci_rst_bdram_be(rtwdev);
+ if (ret) {
+ rtw89_err(rtwdev, "[ERR]pcie rst bdram\n");
+ return ret;
+ }
+
+ rtw89_pci_debounce_be(rtwdev);
+ rtw89_pci_ldo_low_pwr_be(rtwdev);
+ rtw89_pci_pcie_setting_be(rtwdev);
+ rtw89_pci_ser_setting_be(rtwdev);
+
+ rtw89_pci_ctrl_txdma_ch_be(rtwdev, false, true);
+ rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_ENABLE,
+ MAC_AX_PCIE_ENABLE, MAC_AX_PCIE_ENABLE);
+
+ return 0;
+}
+
+static int rtw89_pci_ops_mac_pre_deinit_be(struct rtw89_dev *rtwdev)
+{
+ u32 val;
+
+ _patch_pcie_power_wake_be(rtwdev, false);
+
+ val = rtw89_read32_mask(rtwdev, R_BE_IC_PWR_STATE, B_BE_WLMAC_PWR_STE_MASK);
+ if (val == 0)
+ return 0;
+
+ rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_DISABLE,
+ MAC_AX_PCIE_DISABLE, MAC_AX_PCIE_DISABLE);
+ rtw89_pci_clr_idx_all_be(rtwdev);
+
+ return 0;
+}
+
+int rtw89_pci_ltr_set_v2(struct rtw89_dev *rtwdev, bool en)
+{
+ u32 ctrl0, cfg0, cfg1, dec_ctrl, idle_ltcy, act_ltcy, dis_ltcy;
+
+ ctrl0 = rtw89_read32(rtwdev, R_BE_LTR_CTRL_0);
+ if (rtw89_pci_ltr_is_err_reg_val(ctrl0))
+ return -EINVAL;
+ cfg0 = rtw89_read32(rtwdev, R_BE_LTR_CFG_0);
+ if (rtw89_pci_ltr_is_err_reg_val(cfg0))
+ return -EINVAL;
+ cfg1 = rtw89_read32(rtwdev, R_BE_LTR_CFG_1);
+ if (rtw89_pci_ltr_is_err_reg_val(cfg1))
+ return -EINVAL;
+ dec_ctrl = rtw89_read32(rtwdev, R_BE_LTR_DECISION_CTRL_V1);
+ if (rtw89_pci_ltr_is_err_reg_val(dec_ctrl))
+ return -EINVAL;
+ idle_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1);
+ if (rtw89_pci_ltr_is_err_reg_val(idle_ltcy))
+ return -EINVAL;
+ act_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1);
+ if (rtw89_pci_ltr_is_err_reg_val(act_ltcy))
+ return -EINVAL;
+ dis_ltcy = rtw89_read32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1);
+ if (rtw89_pci_ltr_is_err_reg_val(dis_ltcy))
+ return -EINVAL;
+
+ if (en) {
+ dec_ctrl |= B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1;
+ ctrl0 |= B_BE_LTR_HW_EN;
+ } else {
+ dec_ctrl &= ~(B_BE_ENABLE_LTR_CTL_DECISION | B_BE_LTR_HW_DEC_EN_V1 |
+ B_BE_LTR_EN_PORT_V1_MASK);
+ ctrl0 &= ~B_BE_LTR_HW_EN;
+ }
+
+ dec_ctrl = u32_replace_bits(dec_ctrl, PCI_LTR_SPC_500US,
+ B_BE_LTR_SPACE_IDX_MASK);
+ cfg0 = u32_replace_bits(cfg0, PCI_LTR_IDLE_TIMER_3_2MS,
+ B_BE_LTR_IDLE_TIMER_IDX_MASK);
+ cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK);
+ cfg1 = u32_replace_bits(cfg1, 0xC0, B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK);
+ cfg0 = u32_replace_bits(cfg0, 1, B_BE_LTR_IDX_ACTIVE_MASK);
+ cfg0 = u32_replace_bits(cfg0, 3, B_BE_LTR_IDX_IDLE_MASK);
+ dec_ctrl = u32_replace_bits(dec_ctrl, 0, B_BE_LTR_IDX_DISABLE_V1_MASK);
+
+ rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX3_V1, 0x90039003);
+ rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX1_V1, 0x880b880b);
+ rtw89_write32(rtwdev, R_BE_LTR_LATENCY_IDX0_V1, 0);
+ rtw89_write32(rtwdev, R_BE_LTR_DECISION_CTRL_V1, dec_ctrl);
+ rtw89_write32(rtwdev, R_BE_LTR_CFG_0, cfg0);
+ rtw89_write32(rtwdev, R_BE_LTR_CFG_1, cfg1);
+ rtw89_write32(rtwdev, R_BE_LTR_CTRL_0, ctrl0);
+
+ return 0;
+}
+EXPORT_SYMBOL(rtw89_pci_ltr_set_v2);
+
+static void rtw89_pci_configure_mit_be(struct rtw89_dev *rtwdev)
+{
+ u32 cnt;
+ u32 val;
+
+ rtw89_write32_mask(rtwdev, R_BE_PCIE_MIT0_TMR,
+ B_BE_PCIE_MIT0_RX_TMR_MASK, BE_MIT0_TMR_UNIT_1MS);
+
+ val = rtw89_read32(rtwdev, R_BE_PCIE_MIT0_CNT);
+ cnt = min_t(u32, U8_MAX, RTW89_PCI_RXBD_NUM_MAX / 2);
+ val = u32_replace_bits(val, cnt, B_BE_PCIE_RX_MIT0_CNT_MASK);
+ val = u32_replace_bits(val, 2, B_BE_PCIE_RX_MIT0_TMR_CNT_MASK);
+ rtw89_write32(rtwdev, R_BE_PCIE_MIT0_CNT, val);
+}
+
+static int rtw89_pci_ops_mac_post_init_be(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_pci_info *info = rtwdev->pci_info;
+ int ret;
+
+ ret = info->ltr_set(rtwdev, true);
+ if (ret) {
+ rtw89_err(rtwdev, "pci ltr set fail\n");
+ return ret;
+ }
+
+ rtw89_pci_ctrl_trxdma_pcie_be(rtwdev, MAC_AX_PCIE_IGNORE,
+ MAC_AX_PCIE_IGNORE, MAC_AX_PCIE_ENABLE);
+ rtw89_pci_ctrl_wpdma_pcie_be(rtwdev, true);
+ rtw89_pci_ctrl_txdma_ch_be(rtwdev, true, true);
+ rtw89_pci_configure_mit_be(rtwdev);
+
+ return 0;
+}
+
+static int rtw89_pci_poll_io_idle_be(struct rtw89_dev *rtwdev)
+{
+ u32 sts;
+ int ret;
+
+ ret = read_poll_timeout_atomic(rtw89_read32, sts,
+ !(sts & B_BE_HAXI_MST_BUSY),
+ 10, 1000, false, rtwdev,
+ R_BE_HAXI_DMA_BUSY1);
+ if (ret) {
+ rtw89_err(rtwdev, "pci dmach busy1 0x%X\n", sts);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rtw89_pci_lv1rst_stop_dma_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ rtw89_pci_ctrl_dma_all(rtwdev, false);
+ ret = rtw89_pci_poll_io_idle_be(rtwdev);
+ if (!ret)
+ return 0;
+
+ rtw89_debug(rtwdev, RTW89_DBG_HCI,
+ "[PCIe] poll_io_idle fail; reset hci dma trx\n");
+
+ rtw89_mac_ctrl_hci_dma_trx(rtwdev, false);
+ rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
+
+ return rtw89_pci_poll_io_idle_be(rtwdev);
+}
+
+static int rtw89_pci_lv1rst_start_dma_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ rtw89_mac_ctrl_hci_dma_trx(rtwdev, false);
+ rtw89_mac_ctrl_hci_dma_trx(rtwdev, true);
+ rtw89_pci_clr_idx_all(rtwdev);
+
+ ret = rtw89_pci_rst_bdram_be(rtwdev);
+ if (ret)
+ return ret;
+
+ rtw89_pci_ctrl_dma_all(rtwdev, true);
+ return 0;
+}
+
+const struct rtw89_pci_gen_def rtw89_pci_gen_be = {
+ .isr_rdu = B_BE_RDU_CH1_INT | B_BE_RDU_CH0_INT,
+ .isr_halt_c2h = B_BE_HALT_C2H_INT,
+ .isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT,
+ .isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1},
+ .isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1},
+
+ .mac_pre_init = rtw89_pci_ops_mac_pre_init_be,
+ .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be,
+ .mac_post_init = rtw89_pci_ops_mac_post_init_be,
+
+ .clr_idx_all = rtw89_pci_clr_idx_all_be,
+ .rst_bdram = rtw89_pci_rst_bdram_be,
+
+ .lv1rst_stop_dma = rtw89_pci_lv1rst_stop_dma_be,
+ .lv1rst_start_dma = rtw89_pci_lv1rst_start_dma_be,
+};
+EXPORT_SYMBOL(rtw89_pci_gen_be);
diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 17ccc9efed28..bafc7b1cc104 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -2445,6 +2445,298 @@ void (* const rtw89_phy_c2h_ra_handler[])(struct rtw89_dev *rtwdev,
[RTW89_PHY_C2H_FUNC_TXSTS] = NULL,
};
+static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_c2h_rfk_log_func func,
+ void *content, u16 len)
+{
+ struct rtw89_c2h_rf_txgapk_rpt_log *txgapk;
+ struct rtw89_c2h_rf_rxdck_rpt_log *rxdck;
+ struct rtw89_c2h_rf_dack_rpt_log *dack;
+ struct rtw89_c2h_rf_dpk_rpt_log *dpk;
+
+ switch (func) {
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK:
+ if (len != sizeof(*dpk))
+ goto out;
+
+ dpk = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "DPK ver:%d idx:%2ph band:%2ph bw:%2ph ch:%2ph path:%2ph\n",
+ dpk->ver, dpk->idx, dpk->band, dpk->bw, dpk->ch, dpk->path_ok);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "DPK txagc:%2ph ther:%2ph gs:%2ph dc_i:%4ph dc_q:%4ph\n",
+ dpk->txagc, dpk->ther, dpk->gs, dpk->dc_i, dpk->dc_q);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "DPK corr_v:%2ph corr_i:%2ph to:%2ph ov:%2ph\n",
+ dpk->corr_val, dpk->corr_idx, dpk->is_timeout, dpk->rxbb_ov);
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DACK:
+ if (len != sizeof(*dack))
+ goto out;
+
+ dack = content;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]ver=0x%x 0x%x\n",
+ dack->fwdack_ver, dack->fwdack_rpt_ver);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK ic = [0x%x, 0x%x]\n",
+ dack->cdack_d[0][0][0], dack->cdack_d[0][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 CDACK qc = [0x%x, 0x%x]\n",
+ dack->cdack_d[0][1][0], dack->cdack_d[0][1][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 CDACK ic = [0x%x, 0x%x]\n",
+ dack->cdack_d[1][0][0], dack->cdack_d[1][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 CDACK qc = [0x%x, 0x%x]\n",
+ dack->cdack_d[1][1][0], dack->cdack_d[1][1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK ic = [0x%x, 0x%x]\n",
+ dack->addck2_d[0][0][0], dack->addck2_d[0][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_DCK qc = [0x%x, 0x%x]\n",
+ dack->addck2_d[0][1][0], dack->addck2_d[0][1][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK ic = [0x%x, 0x%x]\n",
+ dack->addck2_d[1][0][0], dack->addck2_d[1][0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_DCK qc = [0x%x, 0x%x]\n",
+ dack->addck2_d[1][1][0], dack->addck2_d[1][1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 ADC_GAINK ic = 0x%x, qc = 0x%x\n",
+ dack->adgaink_d[0][0], dack->adgaink_d[0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 ADC_GAINK ic = 0x%x, qc = 0x%x\n",
+ dack->adgaink_d[1][0], dack->adgaink_d[1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 DAC_DCK ic = 0x%x, qc = 0x%x\n",
+ dack->dadck_d[0][0], dack->dadck_d[0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 DAC_DCK ic = 0x%x, qc = 0x%x\n",
+ dack->dadck_d[1][0], dack->dadck_d[1][1]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 biask iqc = 0x%x\n",
+ dack->biask_d[0][0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 biask iqc = 0x%x\n",
+ dack->biask_d[1][0]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK ic: %*ph\n",
+ (int)sizeof(dack->msbk_d[0][0]), dack->msbk_d[0][0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S0 MSBK qc: %*ph\n",
+ (int)sizeof(dack->msbk_d[0][1]), dack->msbk_d[0][1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK ic: %*ph\n",
+ (int)sizeof(dack->msbk_d[1][0]), dack->msbk_d[1][0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DACK]S1 MSBK qc: %*ph\n",
+ (int)sizeof(dack->msbk_d[1][1]), dack->msbk_d[1][1]);
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK:
+ if (len != sizeof(*rxdck))
+ goto out;
+
+ rxdck = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "RXDCK ver:%d band:%2ph bw:%2ph ch:%2ph to:%2ph\n",
+ rxdck->ver, rxdck->band, rxdck->bw, rxdck->ch,
+ rxdck->timeout);
+ return;
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK:
+ if (len != sizeof(*txgapk))
+ goto out;
+
+ txgapk = content;
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[TXGAPK]rpt r0x8010[0]=0x%x, r0x8010[1]=0x%x\n",
+ le32_to_cpu(txgapk->r0x8010[0]),
+ le32_to_cpu(txgapk->r0x8010[1]));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt chk_id = %d\n",
+ txgapk->chk_id);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt chk_cnt = %d\n",
+ le32_to_cpu(txgapk->chk_cnt));
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt ver = 0x%x\n",
+ txgapk->ver);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt rsv1 = %d\n",
+ txgapk->rsv1);
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[0] = %*ph\n",
+ (int)sizeof(txgapk->track_d[0]), txgapk->track_d[0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[0] = %*ph\n",
+ (int)sizeof(txgapk->power_d[0]), txgapk->power_d[0]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt track_d[1] = %*ph\n",
+ (int)sizeof(txgapk->track_d[1]), txgapk->track_d[1]);
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[1] = %*ph\n",
+ (int)sizeof(txgapk->power_d[1]), txgapk->power_d[1]);
+ return;
+ default:
+ break;
+ }
+
+out:
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "unexpected RFK func %d report log with length %d\n", func, len);
+}
+
+static bool rtw89_phy_c2h_rfk_run_log(struct rtw89_dev *rtwdev,
+ enum rtw89_phy_c2h_rfk_log_func func,
+ void *content, u16 len)
+{
+ struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info;
+ const struct rtw89_c2h_rf_run_log *log = content;
+ const struct rtw89_fw_element_hdr *elm;
+ u32 fmt_idx;
+ u16 offset;
+
+ if (sizeof(*log) != len)
+ return false;
+
+ if (!elm_info->rfk_log_fmt)
+ return false;
+
+ elm = elm_info->rfk_log_fmt->elm[func];
+ fmt_idx = le32_to_cpu(log->fmt_idx);
+ if (!elm || fmt_idx >= elm->u.rfk_log_fmt.nr)
+ return false;
+
+ offset = le16_to_cpu(elm->u.rfk_log_fmt.offset[fmt_idx]);
+ if (offset == 0)
+ return false;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, &elm->u.common.contents[offset],
+ le32_to_cpu(log->arg[0]), le32_to_cpu(log->arg[1]),
+ le32_to_cpu(log->arg[2]), le32_to_cpu(log->arg[3]));
+
+ return true;
+}
+
+static void rtw89_phy_c2h_rfk_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h,
+ u32 len, enum rtw89_phy_c2h_rfk_log_func func,
+ const char *rfk_name)
+{
+ struct rtw89_c2h_hdr *c2h_hdr = (struct rtw89_c2h_hdr *)c2h->data;
+ struct rtw89_c2h_rf_log_hdr *log_hdr;
+ void *log_ptr = c2h_hdr;
+ u16 content_len;
+ u16 chunk_len;
+ bool handled;
+
+ if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK))
+ return;
+
+ log_ptr += sizeof(*c2h_hdr);
+ len -= sizeof(*c2h_hdr);
+
+ while (len > sizeof(*log_hdr)) {
+ log_hdr = log_ptr;
+ content_len = le16_to_cpu(log_hdr->len);
+ chunk_len = content_len + sizeof(*log_hdr);
+
+ if (chunk_len > len)
+ break;
+
+ switch (log_hdr->type) {
+ case RTW89_RF_RUN_LOG:
+ handled = rtw89_phy_c2h_rfk_run_log(rtwdev, func,
+ log_hdr->content, content_len);
+ if (handled)
+ break;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK, "%s run: %*ph\n",
+ rfk_name, content_len, log_hdr->content);
+ break;
+ case RTW89_RF_RPT_LOG:
+ rtw89_phy_c2h_rfk_rpt_log(rtwdev, func,
+ log_hdr->content, content_len);
+ break;
+ default:
+ return;
+ }
+
+ log_ptr += chunk_len;
+ len -= chunk_len;
+ }
+}
+
+static void
+rtw89_phy_c2h_rfk_log_iqk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_IQK, "IQK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_dpk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_DPK, "DPK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_dack(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_DACK, "DACK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_rxdck(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK, "RX_DCK");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_tssi(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI, "TSSI");
+}
+
+static void
+rtw89_phy_c2h_rfk_log_txgapk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+ rtw89_phy_c2h_rfk_log(rtwdev, c2h, len,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK, "TXGAPK");
+}
+
+static
+void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev,
+ struct sk_buff *c2h, u32 len) = {
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_IQK] = rtw89_phy_c2h_rfk_log_iqk,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_DPK] = rtw89_phy_c2h_rfk_log_dpk,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_DACK] = rtw89_phy_c2h_rfk_log_dack,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK] = rtw89_phy_c2h_rfk_log_rxdck,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI] = rtw89_phy_c2h_rfk_log_tssi,
+ [RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk,
+};
+
+static void
+rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len)
+{
+}
+
+static
+void (* const rtw89_phy_c2h_rfk_report_handler[])(struct rtw89_dev *rtwdev,
+ struct sk_buff *c2h, u32 len) = {
+ [RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE] = rtw89_phy_c2h_rfk_report_state,
+};
+
+bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func)
+{
+ switch (class) {
+ case RTW89_PHY_C2H_RFK_LOG:
+ switch (func) {
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_IQK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DPK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_DACK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI:
+ case RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK:
+ return true;
+ default:
+ return false;
+ }
+ case RTW89_PHY_C2H_RFK_REPORT:
+ switch (func) {
+ case RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u32 len, u8 class, u8 func)
{
@@ -2456,6 +2748,14 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
if (func < RTW89_PHY_C2H_FUNC_RA_MAX)
handler = rtw89_phy_c2h_ra_handler[func];
break;
+ case RTW89_PHY_C2H_RFK_LOG:
+ if (func < ARRAY_SIZE(rtw89_phy_c2h_rfk_log_handler))
+ handler = rtw89_phy_c2h_rfk_log_handler[func];
+ break;
+ case RTW89_PHY_C2H_RFK_REPORT:
+ if (func < ARRAY_SIZE(rtw89_phy_c2h_rfk_report_handler))
+ handler = rtw89_phy_c2h_rfk_report_handler[func];
+ break;
case RTW89_PHY_C2H_CLASS_DM:
if (func == RTW89_PHY_C2H_DM_FUNC_LOWRT_RTY)
return;
@@ -4620,6 +4920,29 @@ static void rtw89_phy_env_monitor_init(struct rtw89_dev *rtwdev)
rtw89_phy_ifs_clm_setting_init(rtwdev);
}
+static void rtw89_phy_edcca_init(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak;
+
+ memset(edcca_bak, 0, sizeof(*edcca_bak));
+
+ if (rtwdev->chip->chip_id == RTL8922A && rtwdev->hal.cv == CHIP_CAV) {
+ rtw89_phy_set_phy_regs(rtwdev, R_TXGATING, B_TXGATING_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_VAL, 2);
+ rtw89_phy_set_phy_regs(rtwdev, R_CTLTOP, B_CTLTOP_ON, 1);
+ rtw89_phy_set_phy_regs(rtwdev, R_SPOOF_CG, B_SPOOF_CG_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_CG_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 0);
+ rtw89_phy_set_phy_regs(rtwdev, R_SEGSND, B_SEGSND_EN, 1);
+ rtw89_phy_set_phy_regs(rtwdev, R_DFS_FFT_CG, B_DFS_FFT_EN, 1);
+ }
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->tx_collision_t2r_st,
+ edcca_regs->tx_collision_t2r_st_mask, 0x29);
+}
+
void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
{
rtw89_phy_stat_init(rtwdev);
@@ -4630,6 +4953,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev)
rtw89_physts_parsing_init(rtwdev);
rtw89_phy_dig_init(rtwdev);
rtw89_phy_cfo_init(rtwdev);
+ rtw89_phy_edcca_init(rtwdev);
rtw89_phy_ul_tb_info_init(rtwdev);
rtw89_phy_antdiv_init(rtwdev);
rtw89_chip_rfe_gpio(rtwdev);
@@ -4892,23 +5216,188 @@ void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
}
EXPORT_SYMBOL(rtw89_decode_chan_idx);
-#define EDCCA_DEFAULT 249
void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan)
{
- u32 reg = rtwdev->chip->edcca_lvl_reg;
- struct rtw89_hal *hal = &rtwdev->hal;
- u32 val;
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak;
if (scan) {
- hal->edcca_bak = rtw89_phy_read32(rtwdev, reg);
- val = hal->edcca_bak;
- u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_A_MSK);
- u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_EDCCA_LVL_P_MSK);
- u32p_replace_bits(&val, EDCCA_DEFAULT, B_SEG0R_PPDU_LVL_MSK);
- rtw89_phy_write32(rtwdev, reg, val);
+ edcca_bak->a =
+ rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask);
+ edcca_bak->p =
+ rtw89_phy_read32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask);
+ edcca_bak->ppdu =
+ rtw89_phy_read32_mask(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask, EDCCA_MAX);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask, EDCCA_MAX);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask, EDCCA_MAX);
+ } else {
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask,
+ edcca_bak->a);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask,
+ edcca_bak->p);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask,
+ edcca_bak->ppdu);
+ }
+}
+
+static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80;
+ s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80;
+ u8 path, per20_bitmap;
+ u8 pwdb[8];
+ u32 tmp;
+
+ if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_EDCCA))
+ return;
+
+ if (rtwdev->chip->chip_id == RTL8922A)
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+ edcca_regs->rpt_sel_be_mask, 0);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+ edcca_regs->rpt_sel_mask, 0);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+ path = u32_get_bits(tmp, B_EDCCA_RPT_B_PATH_MASK);
+ flag_s80 = u32_get_bits(tmp, B_EDCCA_RPT_B_S80);
+ flag_s40 = u32_get_bits(tmp, B_EDCCA_RPT_B_S40);
+ flag_s20 = u32_get_bits(tmp, B_EDCCA_RPT_B_S20);
+ flag_p20 = u32_get_bits(tmp, B_EDCCA_RPT_B_P20);
+ flag_fb = u32_get_bits(tmp, B_EDCCA_RPT_B_FB);
+ pwdb_s20 = u32_get_bits(tmp, MASKBYTE1);
+ pwdb_p20 = u32_get_bits(tmp, MASKBYTE2);
+ pwdb_fb = u32_get_bits(tmp, MASKBYTE3);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+ edcca_regs->rpt_sel_mask, 4);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+ pwdb_s80 = u32_get_bits(tmp, MASKBYTE1);
+ pwdb_s40 = u32_get_bits(tmp, MASKBYTE2);
+
+ per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_regs->rpt_a,
+ MASKBYTE0);
+
+ if (rtwdev->chip->chip_id == RTL8922A) {
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+ edcca_regs->rpt_sel_be_mask, 4);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+ pwdb[0] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[1] = u32_get_bits(tmp, MASKBYTE2);
+ pwdb[2] = u32_get_bits(tmp, MASKBYTE1);
+ pwdb[3] = u32_get_bits(tmp, MASKBYTE0);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be,
+ edcca_regs->rpt_sel_be_mask, 5);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_b);
+ pwdb[4] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[5] = u32_get_bits(tmp, MASKBYTE2);
+ pwdb[6] = u32_get_bits(tmp, MASKBYTE1);
+ pwdb[7] = u32_get_bits(tmp, MASKBYTE0);
} else {
- rtw89_phy_write32(rtwdev, reg, hal->edcca_bak);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+ edcca_regs->rpt_sel_mask, 0);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+ pwdb[0] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[1] = u32_get_bits(tmp, MASKBYTE2);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+ edcca_regs->rpt_sel_mask, 1);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+ pwdb[2] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[3] = u32_get_bits(tmp, MASKBYTE2);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+ edcca_regs->rpt_sel_mask, 2);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+ pwdb[4] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[5] = u32_get_bits(tmp, MASKBYTE2);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel,
+ edcca_regs->rpt_sel_mask, 3);
+ tmp = rtw89_phy_read32(rtwdev, edcca_regs->rpt_a);
+ pwdb[6] = u32_get_bits(tmp, MASKBYTE3);
+ pwdb[7] = u32_get_bits(tmp, MASKBYTE2);
}
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: edcca_bitmap = %04x\n", per20_bitmap);
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: pwdb per20{0,1,2,3,4,5,6,7} = {%d,%d,%d,%d,%d,%d,%d,%d}(dBm)\n",
+ pwdb[0], pwdb[1], pwdb[2], pwdb[3], pwdb[4], pwdb[5],
+ pwdb[6], pwdb[7]);
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: path=%d, flag {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}\n",
+ path, flag_fb, flag_p20, flag_s20, flag_s40, flag_s80);
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: pwdb {FB,p20,s20,s40,s80} = {%d,%d,%d,%d,%d}(dBm)\n",
+ pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80);
+}
+
+static u8 rtw89_phy_edcca_get_thre_by_rssi(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_phy_ch_info *ch_info = &rtwdev->ch_info;
+ bool is_linked = rtwdev->total_sta_assoc > 0;
+ u8 rssi_min = ch_info->rssi_min >> 1;
+ u8 edcca_thre;
+
+ if (!is_linked) {
+ edcca_thre = EDCCA_MAX;
+ } else {
+ edcca_thre = rssi_min - RSSI_UNIT_CONVER + EDCCA_UNIT_CONVER -
+ EDCCA_TH_REF;
+ edcca_thre = max_t(u8, edcca_thre, EDCCA_TH_L2H_LB);
+ }
+
+ return edcca_thre;
+}
+
+void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_edcca_regs *edcca_regs = rtwdev->chip->edcca_regs;
+ struct rtw89_edcca_bak *edcca_bak = &rtwdev->hal.edcca_bak;
+ u8 th;
+
+ th = rtw89_phy_edcca_get_thre_by_rssi(rtwdev);
+ if (th == edcca_bak->th_old)
+ return;
+
+ edcca_bak->th_old = th;
+
+ rtw89_debug(rtwdev, RTW89_DBG_EDCCA,
+ "[EDCCA]: Normal Mode, EDCCA_th = %d\n", th);
+
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_mask, th);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->edcca_level,
+ edcca_regs->edcca_p_mask, th);
+ rtw89_phy_write32_mask(rtwdev, edcca_regs->ppdu_level,
+ edcca_regs->ppdu_mask, th);
+}
+
+void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+
+ if (hal->disabled_dm_bitmap & BIT(RTW89_DM_DYNAMIC_EDCCA))
+ return;
+
+ rtw89_phy_edcca_thre_calc(rtwdev);
+ rtw89_phy_edcca_log(rtwdev);
}
static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = {
diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h
index 5c85122e7bb5..3e379077c6ca 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.h
+++ b/drivers/net/wireless/realtek/rtw89/phy.h
@@ -122,6 +122,13 @@
#define PHYSTS_RSVD BIT(RTW89_RX_TYPE_RSVD)
#define PPDU_FILTER_BITMAP (PHYSTS_MGNT | PHYSTS_DATA)
+#define EDCCA_MAX 249
+#define EDCCA_TH_L2H_LB 66
+#define EDCCA_TH_REF 3
+#define EDCCA_HL_DIFF_NORMAL 8
+#define RSSI_UNIT_CONVER 110
+#define EDCCA_UNIT_CONVER 128
+
enum rtw89_phy_c2h_ra_func {
RTW89_PHY_C2H_FUNC_STS_RPT,
RTW89_PHY_C2H_FUNC_MU_GPTBL_RPT,
@@ -129,6 +136,21 @@ enum rtw89_phy_c2h_ra_func {
RTW89_PHY_C2H_FUNC_RA_MAX,
};
+enum rtw89_phy_c2h_rfk_log_func {
+ RTW89_PHY_C2H_RFK_LOG_FUNC_IQK = 0,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_DPK = 1,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_DACK = 2,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK = 3,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI = 4,
+ RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5,
+
+ RTW89_PHY_C2H_RFK_LOG_FUNC_NUM,
+};
+
+enum rtw89_phy_c2h_rfk_report_func {
+ RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE = 0,
+};
+
enum rtw89_phy_c2h_dm_func {
RTW89_PHY_C2H_DM_FUNC_FW_TEST,
RTW89_PHY_C2H_DM_FUNC_FW_TRIG_TX_RPT,
@@ -142,6 +164,8 @@ enum rtw89_phy_c2h_class {
RTW89_PHY_C2H_CLASS_RUA,
RTW89_PHY_C2H_CLASS_RA,
RTW89_PHY_C2H_CLASS_DM,
+ RTW89_PHY_C2H_RFK_LOG = 0x8,
+ RTW89_PHY_C2H_RFK_REPORT = 0x9,
RTW89_PHY_C2H_CLASS_BTC_MIN = 0x10,
RTW89_PHY_C2H_CLASS_BTC_MAX = 0x17,
RTW89_PHY_C2H_CLASS_MAX,
@@ -284,8 +308,6 @@ struct rtw89_txpwr_byrate_cfg {
u32 data;
};
-#define DELTA_SWINGIDX_SIZE 30
-
struct rtw89_txpwr_track_cfg {
const s8 (*delta_swingidx_6gb_n)[DELTA_SWINGIDX_SIZE];
const s8 (*delta_swingidx_6gb_p)[DELTA_SWINGIDX_SIZE];
@@ -478,6 +500,10 @@ struct rtw89_txpwr_limit_ru_be {
s8 ru106_26[RTW89_RU_SEC_NUM_BE];
};
+struct rtw89_phy_rfk_log_fmt {
+ const struct rtw89_fw_element_hdr *elm[RTW89_PHY_C2H_RFK_LOG_FUNC_NUM];
+};
+
struct rtw89_phy_gen_def {
u32 cr_base;
const struct rtw89_ccx_regs *ccx;
@@ -591,6 +617,22 @@ enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subb
return RTW89_GAIN_OFFSET_5G_MID;
case RTW89_CH_5G_BAND_4:
return RTW89_GAIN_OFFSET_5G_HIGH;
+ case RTW89_CH_6G_BAND_IDX0:
+ return RTW89_GAIN_OFFSET_6G_L0;
+ case RTW89_CH_6G_BAND_IDX1:
+ return RTW89_GAIN_OFFSET_6G_L1;
+ case RTW89_CH_6G_BAND_IDX2:
+ return RTW89_GAIN_OFFSET_6G_M0;
+ case RTW89_CH_6G_BAND_IDX3:
+ return RTW89_GAIN_OFFSET_6G_M1;
+ case RTW89_CH_6G_BAND_IDX4:
+ return RTW89_GAIN_OFFSET_6G_H0;
+ case RTW89_CH_6G_BAND_IDX5:
+ return RTW89_GAIN_OFFSET_6G_H1;
+ case RTW89_CH_6G_BAND_IDX6:
+ return RTW89_GAIN_OFFSET_6G_UH0;
+ case RTW89_CH_6G_BAND_IDX7:
+ return RTW89_GAIN_OFFSET_6G_UH1;
}
}
@@ -764,6 +806,7 @@ void rtw89_phy_ra_updata_sta(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta
void rtw89_phy_rate_pattern_vif(struct rtw89_dev *rtwdev,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask);
+bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func);
void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb,
u32 len, u8 class, u8 func);
void rtw89_phy_cfo_track(struct rtw89_dev *rtwdev);
@@ -791,5 +834,7 @@ u8 rtw89_encode_chan_idx(struct rtw89_dev *rtwdev, u8 central_ch, u8 band);
void rtw89_decode_chan_idx(struct rtw89_dev *rtwdev, u8 chan_idx,
u8 *ch, enum nl80211_band *band);
void rtw89_phy_config_edcca(struct rtw89_dev *rtwdev, bool scan);
+void rtw89_phy_edcca_track(struct rtw89_dev *rtwdev);
+void rtw89_phy_edcca_thre_calc(struct rtw89_dev *rtwdev);
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h
index aff0fba71cb0..54486e4550b6 100644
--- a/drivers/net/wireless/realtek/rtw89/ps.h
+++ b/drivers/net/wireless/realtek/rtw89/ps.h
@@ -33,6 +33,10 @@ static inline void rtw89_enter_ips_by_hwflags(struct rtw89_dev *rtwdev)
{
struct ieee80211_hw *hw = rtwdev->hw;
+ /* prevent entering IPS after ROC, but it is scanning */
+ if (rtwdev->scanning)
+ return;
+
if (hw->conf.flags & IEEE80211_CONF_IDLE)
rtw89_enter_ips(rtwdev);
}
diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index ccd5481e8a3d..8456e2b0c14f 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -116,6 +116,7 @@
#define B_AX_LTE_MUX_CTRL_PATH BIT(26)
#define R_AX_HCI_OPT_CTRL 0x0074
+#define BIT_WAKE_CTRL_V1 BIT(23)
#define BIT_WAKE_CTRL BIT(5)
#define R_AX_HCI_BG_CTRL 0x0078
@@ -1456,6 +1457,8 @@
#define B_AX_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16)
#define B_AX_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0)
#define R_AX_PLE_QTA7_CFG 0x905C
+#define B_AX_PLE_Q7_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_AX_PLE_Q7_MIN_SIZE_MASK GENMASK(11, 0)
#define R_AX_PLE_QTA8_CFG 0x9060
#define R_AX_PLE_QTA9_CFG 0x9064
#define R_AX_PLE_QTA10_CFG 0x9068
@@ -2375,6 +2378,14 @@
#define R_AX_TSFTR_HIGH_P4 0xC53C
#define B_AX_TSFTR_HIGH_MASK GENMASK(31, 0)
+#define R_AX_BCN_DROP_ALL0 0xC560
+#define R_AX_BCN_DROP_ALL0_C1 0xE560
+#define B_AX_BCN_DROP_ALL_P4 BIT(4)
+#define B_AX_BCN_DROP_ALL_P3 BIT(3)
+#define B_AX_BCN_DROP_ALL_P2 BIT(2)
+#define B_AX_BCN_DROP_ALL_P1 BIT(1)
+#define B_AX_BCN_DROP_ALL_P0 BIT(0)
+
#define R_AX_MBSSID_CTRL 0xC568
#define R_AX_MBSSID_CTRL_C1 0xE568
#define B_AX_P0MB_ALL_MASK GENMASK(23, 1)
@@ -2554,11 +2565,20 @@
#define R_AX_PTCL_DBG_INFO 0xC6F0
#define R_AX_PTCL_DBG_INFO_C1 0xE6F0
+#define B_AX_PTCL_DBG_INFO_MASK_BY_PORT(port) \
+({\
+ typeof(port) _port = (port); \
+ GENMASK((_port) * 2 + 1, (_port) * 2); \
+})
+
#define B_AX_PTCL_DBG_INFO_MASK GENMASK(31, 0)
#define R_AX_PTCL_DBG 0xC6F4
#define R_AX_PTCL_DBG_C1 0xE6F4
#define B_AX_PTCL_DBG_EN BIT(8)
#define B_AX_PTCL_DBG_SEL_MASK GENMASK(7, 0)
+#define AX_PTCL_DBG_BCNQ_NUM0 8
+#define AX_PTCL_DBG_BCNQ_NUM1 9
+
#define R_AX_DLE_CTRL 0xC800
#define R_AX_DLE_CTRL_C1 0xE800
@@ -3629,6 +3649,50 @@
#define B_AX_GNT_BT_TX_SW_VAL BIT(1)
#define B_AX_GNT_BT_TX_SW_CTRL BIT(0)
+#define R_BE_SYS_ISO_CTRL 0x0000
+#define B_BE_PWC_EV2EF_B BIT(15)
+#define B_BE_PWC_EV2EF_S BIT(14)
+#define B_BE_PA33V_EN BIT(13)
+#define B_BE_PA12V_EN BIT(12)
+#define B_BE_PAOOBS33V_EN BIT(11)
+#define B_BE_PAOOBS12V_EN BIT(10)
+#define B_BE_ISO_RFDIO BIT(9)
+#define B_BE_ISO_EB2CORE BIT(8)
+#define B_BE_ISO_DIOE BIT(7)
+#define B_BE_ISO_WLPON2PP BIT(6)
+#define B_BE_ISO_IP2MAC_WA02PP BIT(5)
+#define B_BE_ISO_PD2CORE BIT(4)
+#define B_BE_ISO_PA2PCIE BIT(3)
+#define B_BE_ISO_PAOOBS2PCIE BIT(1)
+#define B_BE_ISO_WD2PP BIT(0)
+
+#define R_BE_SYS_PW_CTRL 0x0004
+#define B_BE_SOP_ASWRM BIT(31)
+#define B_BE_SOP_EASWR BIT(30)
+#define B_BE_SOP_PWMM_DSWR BIT(29)
+#define B_BE_SOP_EDSWR BIT(28)
+#define B_BE_SOP_ACKF BIT(27)
+#define B_BE_SOP_ERCK BIT(26)
+#define B_BE_SOP_ANA_CLK_DIVISION_2 BIT(25)
+#define B_BE_SOP_EXTL BIT(24)
+#define B_BE_SOP_OFF_CAPC_EN BIT(23)
+#define B_BE_XTAL_OFF_A_DIE BIT(22)
+#define B_BE_ROP_SWPR BIT(21)
+#define B_BE_DIS_HW_LPLDM BIT(20)
+#define B_BE_DIS_HW_LPURLDO BIT(19)
+#define B_BE_DIS_WLBT_PDNSUSEN_SOPC BIT(18)
+#define B_BE_RDY_SYSPWR BIT(17)
+#define B_BE_EN_WLON BIT(16)
+#define B_BE_APDM_HPDN BIT(15)
+#define B_BE_PSUS_OFF_CAPC_EN BIT(14)
+#define B_BE_AFSM_PCIE_SUS_EN BIT(12)
+#define B_BE_AFSM_WLSUS_EN BIT(11)
+#define B_BE_APFM_SWLPS BIT(10)
+#define B_BE_APFM_OFFMAC BIT(9)
+#define B_BE_APFN_ONMAC BIT(8)
+#define B_BE_CHIP_PDN_EN BIT(7)
+#define B_BE_RDY_MACDIS BIT(6)
+
#define R_BE_SYS_CLK_CTRL 0x0008
#define B_BE_CPU_CLK_EN BIT(14)
#define B_BE_SYMR_BE_CLK_EN BIT(13)
@@ -3639,6 +3703,249 @@
#define B_BE_ANA_CLK_DIVISION_2 BIT(1)
#define B_BE_CNTD16V_EN BIT(0)
+#define R_BE_SYS_WL_EFUSE_CTRL 0x000A
+#define B_BE_OTP_B_PWC_RPT BIT(15)
+#define B_BE_OTP_S_PWC_RPT BIT(14)
+#define B_BE_OTP_ISO_RPT BIT(13)
+#define B_BE_OTP_BURST_RPT BIT(12)
+#define B_BE_OTP_AUTOLOAD_RPT BIT(11)
+#define B_BE_AUTOLOAD_DIS_A_DIE BIT(6)
+#define B_BE_AUTOLOAD_SUS BIT(5)
+#define B_BE_AUTOLOAD_DIS BIT(4)
+
+#define R_BE_SYS_PAGE_CLK_GATED 0x000C
+#define B_BE_USB_APHY_PC_DLP_OP BIT(27)
+#define B_BE_PCIE_APHY_PC_DLP_OP BIT(26)
+#define B_BE_UPHY_POWER_READY_CHK BIT(25)
+#define B_BE_CPHY_POWER_READY_CHK BIT(24)
+#define B_BE_PCIE_PRST_DEBUNC_PERIOD_MASK GENMASK(23, 22)
+#define B_BE_SYM_PRST_DEBUNC_SEL BIT(21)
+#define B_BE_CPHY_AUXCLK_OP BIT(20)
+#define B_BE_SOP_OFFUA_PC BIT(19)
+#define B_BE_SOP_OFFPOOBS_PC BIT(18)
+#define B_BE_PCIE_LAN1_MASK BIT(17)
+#define B_BE_PCIE_LAN0_MASK BIT(16)
+#define B_BE_DIS_CLK_REGF_GATE BIT(15)
+#define B_BE_DIS_CLK_REGE_GATE BIT(14)
+#define B_BE_DIS_CLK_REGD_GATE BIT(13)
+#define B_BE_DIS_CLK_REGC_GATE BIT(12)
+#define B_BE_DIS_CLK_REGB_GATE BIT(11)
+#define B_BE_DIS_CLK_REGA_GATE BIT(10)
+#define B_BE_DIS_CLK_REG9_GATE BIT(9)
+#define B_BE_DIS_CLK_REG8_GATE BIT(8)
+#define B_BE_DIS_CLK_REG7_GATE BIT(7)
+#define B_BE_DIS_CLK_REG6_GATE BIT(6)
+#define B_BE_DIS_CLK_REG5_GATE BIT(5)
+#define B_BE_DIS_CLK_REG4_GATE BIT(4)
+#define B_BE_DIS_CLK_REG3_GATE BIT(3)
+#define B_BE_DIS_CLK_REG2_GATE BIT(2)
+#define B_BE_DIS_CLK_REG1_GATE BIT(1)
+#define B_BE_DIS_CLK_REG0_GATE BIT(0)
+
+#define R_BE_ANAPAR_POW_MAC 0x0016
+#define B_BE_POW_PC_LDO_PORT1 BIT(3)
+#define B_BE_POW_PC_LDO_PORT0 BIT(2)
+#define B_BE_POW_PLL_V1 BIT(1)
+#define B_BE_POW_POWER_CUT_POW_LDO BIT(0)
+
+#define R_BE_SYS_ADIE_PAD_PWR_CTRL 0x0018
+#define B_BE_SYM_PADPDN_WL_RFC1_1P3 BIT(6)
+#define B_BE_SYM_PADPDN_WL_RFC0_1P3 BIT(5)
+
+#define R_BE_AFE_LDO_CTRL 0x0020
+#define B_BE_FORCE_MACBBBT_PWR_ON BIT(31)
+#define B_BE_R_SYM_WLPOFF_P4_PC_EN BIT(28)
+#define B_BE_R_SYM_WLPOFF_P3_PC_EN BIT(27)
+#define B_BE_R_SYM_WLPOFF_P2_PC_EN BIT(26)
+#define B_BE_R_SYM_WLPOFF_P1_PC_EN BIT(25)
+#define B_BE_R_SYM_WLPOFF_PC_EN BIT(24)
+#define B_BE_AON_OFF_PC_EN BIT(23)
+#define B_BE_R_SYM_WLPON_P3_PC_EN BIT(21)
+#define B_BE_R_SYM_WLPON_P2_PC_EN BIT(20)
+#define B_BE_R_SYM_WLPON_P1_PC_EN BIT(19)
+#define B_BE_R_SYM_WLPON_PC_EN BIT(18)
+#define B_BE_R_SYM_WLBBPON1_P1_PC_EN BIT(15)
+#define B_BE_R_SYM_WLBBPON1_PC_EN BIT(14)
+#define B_BE_R_SYM_WLBBPON_P1_PC_EN BIT(13)
+#define B_BE_R_SYM_WLBBPON_PC_EN BIT(12)
+#define B_BE_R_SYM_DIS_WPHYBBOFF_PC BIT(10)
+#define B_BE_R_SYM_WLBBOFF1_P4_PC_EN BIT(9)
+#define B_BE_R_SYM_WLBBOFF1_P3_PC_EN BIT(8)
+#define B_BE_R_SYM_WLBBOFF1_P2_PC_EN BIT(7)
+#define B_BE_R_SYM_WLBBOFF1_P1_PC_EN BIT(6)
+#define B_BE_R_SYM_WLBBOFF1_PC_EN BIT(5)
+#define B_BE_R_SYM_WLBBOFF_P4_PC_EN BIT(4)
+#define B_BE_R_SYM_WLBBOFF_P3_PC_EN BIT(3)
+#define B_BE_R_SYM_WLBBOFF_P2_PC_EN BIT(2)
+#define B_BE_R_SYM_WLBBOFF_P1_PC_EN BIT(1)
+#define B_BE_R_SYM_WLBBOFF_PC_EN BIT(0)
+
+#define R_BE_AFE_CTRL1 0x0024
+#define B_BE_R_SYM_WLCMAC0_P4_PC_EN BIT(28)
+#define B_BE_R_SYM_WLCMAC0_P3_PC_EN BIT(27)
+#define B_BE_R_SYM_WLCMAC0_P2_PC_EN BIT(26)
+#define B_BE_R_SYM_WLCMAC0_P1_PC_EN BIT(25)
+#define B_BE_R_SYM_WLCMAC0_PC_EN BIT(24)
+#define B_BE_DATAMEM_PC3_EN BIT(23)
+#define B_BE_DATAMEM_PC2_EN BIT(22)
+#define B_BE_DATAMEM_PC1_EN BIT(21)
+#define B_BE_DATAMEM_PC_EN BIT(20)
+#define B_BE_DMEM7_PC_EN BIT(19)
+#define B_BE_DMEM6_PC_EN BIT(18)
+#define B_BE_DMEM5_PC_EN BIT(17)
+#define B_BE_DMEM4_PC_EN BIT(16)
+#define B_BE_DMEM3_PC_EN BIT(15)
+#define B_BE_DMEM2_PC_EN BIT(14)
+#define B_BE_DMEM1_PC_EN BIT(13)
+#define B_BE_IMEM4_PC_EN BIT(12)
+#define B_BE_IMEM3_PC_EN BIT(11)
+#define B_BE_IMEM2_PC_EN BIT(10)
+#define B_BE_IMEM1_PC_EN BIT(9)
+#define B_BE_IMEM0_PC_EN BIT(8)
+#define B_BE_R_SYM_WLCMAC1_P4_PC_EN BIT(4)
+#define B_BE_R_SYM_WLCMAC1_P3_PC_EN BIT(3)
+#define B_BE_R_SYM_WLCMAC1_P2_PC_EN BIT(2)
+#define B_BE_R_SYM_WLCMAC1_P1_PC_EN BIT(1)
+#define B_BE_R_SYM_WLCMAC1_PC_EN BIT(0)
+#define B_BE_AFE_CTRL1_SET (B_BE_R_SYM_WLCMAC1_PC_EN | \
+ B_BE_R_SYM_WLCMAC1_P1_PC_EN | \
+ B_BE_R_SYM_WLCMAC1_P2_PC_EN | \
+ B_BE_R_SYM_WLCMAC1_P3_PC_EN | \
+ B_BE_R_SYM_WLCMAC1_P4_PC_EN)
+
+#define R_BE_EFUSE_CTRL 0x0030
+#define B_BE_EF_MODE_SEL_MASK GENMASK(31, 30)
+#define B_BE_EF_RDY BIT(29)
+#define B_BE_EF_COMP_RESULT BIT(28)
+#define B_BE_EF_ADDR_MASK GENMASK(15, 0)
+
+#define R_BE_EFUSE_CTRL_1_V1 0x0034
+#define B_BE_EF_DATA_MASK GENMASK(31, 0)
+
+#define R_BE_WL_BT_PWR_CTRL 0x0068
+#define B_BE_ISO_BD2PP BIT(31)
+#define B_BE_LDOV12B_EN BIT(30)
+#define B_BE_CKEN_BT BIT(29)
+#define B_BE_FEN_BT BIT(28)
+#define B_BE_BTCPU_BOOTSEL BIT(27)
+#define B_BE_SPI_SPEEDUP BIT(26)
+#define B_BE_BT_LDO_MODE BIT(25)
+#define B_BE_ISO_BTPON2PP BIT(22)
+#define B_BE_BT_FUNC_EN BIT(18)
+#define B_BE_BT_HWPDN_SL BIT(17)
+#define B_BE_BT_DISN_EN BIT(16)
+#define B_BE_SDM_SRC_SEL BIT(12)
+#define B_BE_ISO_BA2PP BIT(11)
+#define B_BE_BT_AFE_LDO_EN BIT(10)
+#define B_BE_BT_AFE_PLL_EN BIT(9)
+#define B_BE_WLAN_32K_SEL BIT(6)
+#define B_BE_WL_DRV_EXIST_IDX BIT(5)
+#define B_BE_DOP_EHPAD BIT(4)
+#define B_BE_WL_FUNC_EN BIT(2)
+#define B_BE_WL_HWPDN_SL BIT(1)
+#define B_BE_WL_HWPDN_EN BIT(0)
+
+#define R_BE_SYS_SDIO_CTRL 0x0070
+#define B_BE_MCM_FLASH_EN BIT(28)
+#define B_BE_PCIE_SEC_LOAD BIT(26)
+#define B_BE_PCIE_SER_RSTB BIT(25)
+#define B_BE_PCIE_SEC_LOAD_CLR BIT(24)
+#define B_BE_SDIO_CMD_SW_RST BIT(20)
+#define B_BE_SDIO_INT_POLARITY BIT(19)
+#define B_BE_SDIO_OFF_EN BIT(17)
+#define B_BE_SDIO_ON_EN BIT(16)
+#define B_BE_PCIE_DIS_L2__CTRL_LDO_HCI BIT(15)
+#define B_BE_PCIE_DIS_L2_RTK_PERST BIT(14)
+#define B_BE_PCIE_FORCE_PWR_NGAT BIT(13)
+#define B_BE_PCIE_FORCE_IBX_EN BIT(12)
+#define B_BE_PCIE_AUXCLK_GATE BIT(11)
+#define B_BE_PCIE_WAIT_TIMEOUT_EVENT BIT(10)
+#define B_BE_PCIE_WAIT_TIME BIT(9)
+#define B_BE_L1OFF_TO_L0_RESUME_EVT BIT(8)
+#define B_BE_USBA_FORCE_PWR_NGAT BIT(7)
+#define B_BE_USBD_FORCE_PWR_NGAT BIT(6)
+#define B_BE_BT_CTRL_USB_PWR BIT(5)
+#define B_BE_USB_D_STATE_HOLD BIT(4)
+#define B_BE_R_BE_FORCE_DP BIT(3)
+#define B_BE_R_BE_DP_MODE BIT(2)
+#define B_BE_RES_USB_MASS_STORAGE_DESC BIT(1)
+#define B_BE_USB_WAIT_TIME BIT(0)
+
+#define R_BE_HCI_OPT_CTRL 0x0074
+#define B_BE_HCI_WLAN_IO_ST BIT(31)
+#define B_BE_HCI_WLAN_IO_EN BIT(28)
+#define B_BE_HAXIDMA_IO_ST BIT(27)
+#define B_BE_HAXIDMA_BACKUP_RESTORE_ST BIT(26)
+#define B_BE_HAXIDMA_IO_EN BIT(24)
+#define B_BE_EN_PCIE_WAKE BIT(23)
+#define B_BE_SDIO_PAD_H3L1 BIT(22)
+#define B_BE_USBMAC_ANACLK_SW BIT(21)
+#define B_BE_PCIE_CPHY_CCK_XTAL_SEL BIT(20)
+#define B_BE_SDIO_DATA_PAD_SMT BIT(19)
+#define B_BE_SDIO_PAD_E5 BIT(18)
+#define B_BE_FORCE_PCIE_AUXCLK BIT(17)
+#define B_BE_HCI_LA_ADDR_MAP BIT(16)
+#define B_BE_HCI_LA_GLO_RST BIT(15)
+#define B_BE_USB3_SUS_DIS BIT(14)
+#define B_BE_NOPWR_CTRL_SEL BIT(13)
+#define B_BE_USB_HOST_PWR_OFF_EN BIT(12)
+#define B_BE_SYM_LPS_BLOCK_EN BIT(11)
+#define B_BE_USB_LPM_ACT_EN BIT(10)
+#define B_BE_USB_LPM_NY BIT(9)
+#define B_BE_USB2_SUS_DIS BIT(8)
+#define B_BE_SDIO_PAD_E_MASK GENMASK(7, 5)
+#define B_BE_USB_LPPLL_EN BIT(4)
+#define B_BE_USB1_1_USB2_0_DECISION BIT(3)
+#define B_BE_ROP_SW15 BIT(2)
+#define B_BE_PCI_CKRDY_OPT BIT(1)
+#define B_BE_PCI_VAUX_EN BIT(0)
+
+#define R_BE_SYS_ISO_CTRL_EXTEND 0x0080
+#define B_BE_R_SYM_ISO_DMEM62PP BIT(29)
+#define B_BE_R_SYM_ISO_DMEM52PP BIT(28)
+#define B_BE_R_SYM_ISO_DMEM42PP BIT(27)
+#define B_BE_R_SYM_ISO_DMEM32PP BIT(26)
+#define B_BE_R_SYM_ISO_DMEM22PP BIT(25)
+#define B_BE_R_SYM_ISO_DMEM12PP BIT(24)
+#define B_BE_R_SYM_ISO_IMEM42PP BIT(22)
+#define B_BE_R_SYM_ISO_IMEM32PP BIT(21)
+#define B_BE_R_SYM_ISO_IMEM22PP BIT(20)
+#define B_BE_R_SYM_ISO_IMEM12PP BIT(19)
+#define B_BE_R_SYM_ISO_IMEM02PP BIT(18)
+#define B_BE_R_SYM_ISO_AON_OFF2PP BIT(15)
+#define B_BE_R_SYM_PWC_HCILA BIT(13)
+#define B_BE_R_SYM_PWC_PD12V BIT(12)
+#define B_BE_R_SYM_PWC_UD12V BIT(11)
+#define B_BE_R_SYM_PWC_BTBRG BIT(10)
+#define B_BE_R_SYM_LDOBTSDIO_EN BIT(9)
+#define B_BE_R_SYM_LDOSPDIO_EN BIT(8)
+#define B_BE_R_SYM_ISO_HCILA BIT(4)
+#define B_BE_R_SYM_ISO_BTBRG2PP BIT(2)
+#define B_BE_R_SYM_ISO_BTSDIO2PP BIT(1)
+#define B_BE_R_SYM_ISO_SPDIO2PP BIT(0)
+
+#define R_BE_FEN_RST_ENABLE 0x0084
+#define B_BE_R_SYM_FEN_WLMACOFF BIT(31)
+#define B_BE_R_SYM_ISO_WA12PP BIT(28)
+#define B_BE_R_SYM_ISO_CMAC12PP BIT(25)
+#define B_BE_R_SYM_ISO_CMAC02PP BIT(24)
+#define B_BE_R_SYM_ISO_ADDA_P32PP BIT(23)
+#define B_BE_R_SYM_ISO_ADDA_P22PP BIT(22)
+#define B_BE_R_SYM_ISO_ADDA_P12PP BIT(21)
+#define B_BE_R_SYM_ISO_ADDA_P02PP BIT(20)
+#define B_BE_CMAC1_FEN BIT(17)
+#define B_BE_CMAC0_FEN BIT(16)
+#define B_BE_SYM_ISO_BBPON12PP BIT(13)
+#define B_BE_SYM_ISO_BB12PP BIT(12)
+#define B_BE_BOOT_RDY1 BIT(10)
+#define B_BE_FEN_BB1_IP_RSTN BIT(9)
+#define B_BE_FEN_BB1PLAT_RSTB BIT(8)
+#define B_BE_SYM_ISO_BBPON02PP BIT(5)
+#define B_BE_SYM_ISO_BB02PP BIT(4)
+#define B_BE_BOOT_RDY0 BIT(2)
+#define B_BE_FEN_BB_IP_RSTN BIT(1)
+#define B_BE_FEN_BBPLAT_RSTB BIT(0)
+
#define R_BE_PLATFORM_ENABLE 0x0088
#define B_BE_HOLD_AFTER_RESET BIT(11)
#define B_BE_SYM_WLPLT_MEM_MUX_EN BIT(10)
@@ -3652,6 +3959,92 @@
#define B_BE_WCPU_EN BIT(1)
#define B_BE_PLATFORM_EN BIT(0)
+#define R_BE_WLLPS_CTRL 0x0090
+#define B_BE_LPSOP_BBMEMDS BIT(30)
+#define B_BE_LPSOP_BBOFF BIT(29)
+#define B_BE_LPSOP_MACOFF BIT(28)
+#define B_BE_LPSOP_OFF_CAPC_EN BIT(27)
+#define B_BE_LPSOP_MEM_DS BIT(26)
+#define B_BE_LPSOP_XTALM_LPS BIT(23)
+#define B_BE_LPSOP_XTAL BIT(22)
+#define B_BE_LPSOP_ACLK_DIV_2 BIT(21)
+#define B_BE_LPSOP_ACLK_SEL BIT(20)
+#define B_BE_LPSOP_ASWRM BIT(17)
+#define B_BE_LPSOP_ASWR BIT(16)
+#define B_BE_LPSOP_DSWR_ADJ_MASK GENMASK(15, 12)
+#define B_BE_LPSOP_DSWRSD BIT(10)
+#define B_BE_LPSOP_DSWRM BIT(9)
+#define B_BE_LPSOP_DSWR BIT(8)
+#define B_BE_LPSOP_OLD_ADJ_MASK GENMASK(7, 4)
+#define B_BE_FORCE_LEAVE_LPS BIT(3)
+#define B_BE_LPSOP_OLDSD BIT(2)
+#define B_BE_DIS_WLBT_LPSEN_LOPC BIT(1)
+#define B_BE_WL_LPS_EN BIT(0)
+
+#define R_BE_WLRESUME_CTRL 0x0094
+#define B_BE_LPSROP_DMEM5_RSU_EN BIT(31)
+#define B_BE_LPSROP_DMEM4_RSU_EN BIT(30)
+#define B_BE_LPSROP_DMEM3_RSU_EN BIT(29)
+#define B_BE_LPSROP_DMEM2_RSU_EN BIT(28)
+#define B_BE_LPSROP_DMEM1_RSU_EN BIT(27)
+#define B_BE_LPSROP_DMEM0_RSU_EN BIT(26)
+#define B_BE_LPSROP_IMEM5_RSU_EN BIT(25)
+#define B_BE_LPSROP_IMEM4_RSU_EN BIT(24)
+#define B_BE_LPSROP_IMEM3_RSU_EN BIT(23)
+#define B_BE_LPSROP_IMEM2_RSU_EN BIT(22)
+#define B_BE_LPSROP_IMEM1_RSU_EN BIT(21)
+#define B_BE_LPSROP_IMEM0_RSU_EN BIT(20)
+#define B_BE_LPSROP_BB1_W_BB0 BIT(14)
+#define B_BE_LPSROP_CMAC1 BIT(13)
+#define B_BE_LPSROP_CMAC0 BIT(12)
+#define B_BE_LPSROP_XTALM BIT(11)
+#define B_BE_LPSROP_PLLM BIT(10)
+#define B_BE_LPSROP_HIOE BIT(9)
+#define B_BE_LPSROP_CPU BIT(8)
+#define B_BE_LPSROP_LOWPWRPLL BIT(7)
+#define B_BE_LPSROP_DSWRSD_SEL_MASK GENMASK(5, 4)
+
+#define R_BE_EFUSE_CTRL_2_V1 0x00A4
+#define B_BE_EF_ENT BIT(31)
+#define B_BE_EF_TCOLUMN_EN BIT(29)
+#define B_BE_BT_OTP_PWC_DIS BIT(28)
+#define B_BE_EF_RDT BIT(27)
+#define B_BE_R_SYM_AUTOLOAD_WITH_PMC_SEL BIT(24)
+#define B_BE_EF_PGTS_MASK GENMASK(23, 20)
+#define B_BE_EF_BURST BIT(19)
+#define B_BE_EF_TEST_SEL_MASK GENMASK(18, 16)
+#define B_BE_EF_TROW_EN BIT(15)
+#define B_BE_EF_ERR_FLAG BIT(14)
+#define B_BE_EF_FBURST_DIS BIT(13)
+#define B_BE_EF_HT_SEL BIT(12)
+#define B_BE_EF_DSB_EN BIT(11)
+#define B_BE_EF_DLY_SEL_MASK GENMASK(3, 0)
+
+#define R_BE_PMC_DBG_CTRL2 0x00CC
+#define B_BE_EFUSE_BURN_GNT_MASK GENMASK(31, 24)
+#define B_BE_DIS_IOWRAP_TIMEOUT BIT(16)
+#define B_BE_STOP_WL_PMC BIT(9)
+#define B_BE_STOP_SYM_PMC BIT(8)
+#define B_BE_SYM_REG_PCIE_WRMSK BIT(7)
+#define B_BE_BT_ACCESS_WL_PAGE0 BIT(6)
+#define B_BE_R_BE_RST_WLPMC BIT(5)
+#define B_BE_R_BE_RST_PD12N BIT(4)
+#define B_BE_SYSON_DIS_WLR_BE_WRMSK BIT(3)
+#define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2)
+#define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0)
+
+#define R_BE_PCIE_MIO_INTF 0x00E4
+#define B_BE_AON_MIO_EPHY_1K_SEL_MASK GENMASK(29, 24)
+#define B_BE_PCIE_MIO_ADDR_PAGE_V1_MASK GENMASK(20, 16)
+#define B_BE_PCIE_MIO_ASIF BIT(15)
+#define B_BE_PCIE_MIO_BYIOREG BIT(13)
+#define B_BE_PCIE_MIO_RE BIT(12)
+#define B_BE_PCIE_MIO_WE_MASK GENMASK(11, 8)
+#define B_BE_PCIE_MIO_ADDR_MASK GENMASK(7, 0)
+
+#define R_BE_PCIE_MIO_INTD 0x00E8
+#define B_BE_PCIE_MIO_DATA_MASK GENMASK(31, 0)
+
#define R_BE_HALT_H2C_CTRL 0x0160
#define B_BE_HALT_H2C_TRIGGER BIT(0)
@@ -3676,6 +4069,82 @@
#define R_BE_SECURE_BOOT_MALLOC_INFO 0x0184
+#define R_BE_FWS1IMR 0x0198
+#define B_BE_FS_RPWM_INT_EN_V1 BIT(24)
+#define B_BE_PCIE_HOTRST_EN BIT(22)
+#define B_BE_PCIE_SER_TIMEOUT_INDIC_EN BIT(21)
+#define B_BE_PCIE_RXI300_SLVTOUT_INDIC_EN BIT(20)
+#define B_BE_AON_PCIE_FLR_INT_EN BIT(19)
+#define B_BE_PCIE_ERR_INDIC_INT_EN BIT(18)
+#define B_BE_SDIO_ERR_INDIC_INT_EN BIT(17)
+#define B_BE_USB_ERR_INDIC_INT_EN BIT(16)
+#define B_BE_FS_GPIO27_INT_EN BIT(11)
+#define B_BE_FS_GPIO26_INT_EN BIT(10)
+#define B_BE_FS_GPIO25_INT_EN BIT(9)
+#define B_BE_FS_GPIO24_INT_EN BIT(8)
+#define B_BE_FS_GPIO23_INT_EN BIT(7)
+#define B_BE_FS_GPIO22_INT_EN BIT(6)
+#define B_BE_FS_GPIO21_INT_EN BIT(5)
+#define B_BE_FS_GPIO20_INT_EN BIT(4)
+#define B_BE_FS_GPIO19_INT_EN BIT(3)
+#define B_BE_FS_GPIO18_INT_EN BIT(2)
+#define B_BE_FS_GPIO17_INT_EN BIT(1)
+#define B_BE_FS_GPIO16_INT_EN BIT(0)
+
+#define R_BE_HIMR0 0x01A0
+#define B_BE_WDT_DATACPU_TIMEOUT_INT_EN BIT(25)
+#define B_BE_HALT_D2H_INT_EN BIT(24)
+#define B_BE_WDT_TIMEOUT_INT_EN BIT(22)
+#define B_BE_HALT_C2H_INT_EN BIT(21)
+#define B_BE_RON_INT_EN BIT(20)
+#define B_BE_PDNINT_EN BIT(19)
+#define B_BE_SPSANA_OCP_INT_EN BIT(18)
+#define B_BE_SPS_OCP_INT_EN BIT(17)
+#define B_BE_BTON_STS_UPDATE_INT_EN BIT(16)
+#define B_BE_GPIOF_INT_EN BIT(15)
+#define B_BE_GPIOE_INT_EN BIT(14)
+#define B_BE_GPIOD_INT_EN BIT(13)
+#define B_BE_GPIOC_INT_EN BIT(12)
+#define B_BE_GPIOB_INT_EN BIT(11)
+#define B_BE_GPIOA_INT_EN BIT(10)
+#define B_BE_GPIO9_INT_EN BIT(9)
+#define B_BE_GPIO8_INT_EN BIT(8)
+#define B_BE_GPIO7_INT_EN BIT(7)
+#define B_BE_GPIO6_INT_EN BIT(6)
+#define B_BE_GPIO5_INT_EN BIT(5)
+#define B_BE_GPIO4_INT_EN BIT(4)
+#define B_BE_GPIO3_INT_EN BIT(3)
+#define B_BE_GPIO2_INT_EN BIT(2)
+#define B_BE_GPIO1_INT_EN BIT(1)
+#define B_BE_GPIO0_INT_EN BIT(0)
+
+#define R_BE_HISR0 0x01A4
+#define B_BE_WDT_DATACPU_TIMEOUT_INT BIT(25)
+#define B_BE_HALT_D2H_INT BIT(24)
+#define B_BE_WDT_TIMEOUT_INT BIT(22)
+#define B_BE_HALT_C2H_INT BIT(21)
+#define B_BE_RON_INT BIT(20)
+#define B_BE_PDNINT BIT(19)
+#define B_BE_SPSANA_OCP_INT BIT(18)
+#define B_BE_SPS_OCP_INT BIT(17)
+#define B_BE_BTON_STS_UPDATE_INT BIT(16)
+#define B_BE_GPIOF_INT BIT(15)
+#define B_BE_GPIOE_INT BIT(14)
+#define B_BE_GPIOD_INT BIT(13)
+#define B_BE_GPIOC_INT BIT(12)
+#define B_BE_GPIOB_INT BIT(11)
+#define B_BE_GPIOA_INT BIT(10)
+#define B_BE_GPIO9_INT BIT(9)
+#define B_BE_GPIO8_INT BIT(8)
+#define B_BE_GPIO7_INT BIT(7)
+#define B_BE_GPIO6_INT BIT(6)
+#define B_BE_GPIO5_INT BIT(5)
+#define B_BE_GPIO4_INT BIT(4)
+#define B_BE_GPIO3_INT BIT(3)
+#define B_BE_GPIO2_INT BIT(2)
+#define B_BE_GPIO1_INT BIT(1)
+#define B_BE_GPIO0_INT BIT(0)
+
#define R_BE_WCPU_FW_CTRL 0x01E0
#define B_BE_RUN_ENV_MASK GENMASK(31, 30)
#define B_BE_WCPU_FWDL_STATUS_MASK GENMASK(29, 26)
@@ -3721,6 +4190,78 @@
#define R_BE_UDM2 0x01F8
#define B_BE_UDM2_EPC_RA_MASK GENMASK(31, 0)
+#define R_BE_AFE_ON_CTRL0 0x0240
+#define B_BE_REG_LPF_R3_3_0_MASK GENMASK(31, 29)
+#define B_BE_REG_LPF_R2_MASK GENMASK(28, 24)
+#define B_BE_REG_LPF_C3_MASK GENMASK(23, 21)
+#define B_BE_REG_LPF_C2_MASK GENMASK(20, 18)
+#define B_BE_REG_LPF_C1_MASK GENMASK(17, 15)
+#define B_BE_REG_CP_ICPX2 BIT(14)
+#define B_BE_REG_CP_ICP_SEL_FAST_MASK GENMASK(13, 10)
+#define B_BE_REG_CP_ICP_SEL_MASK GENMASK(9, 6)
+#define B_BE_REG_IB_PI_MASK GENMASK(5, 4)
+#define B_BE_REG_CK_DEBUG_BT BIT(3)
+#define B_BE_EN_PC_LDO BIT(2)
+#define B_BE_LDO_VSEL_MASK GENMASK(1, 0)
+
+#define R_BE_AFE_ON_CTRL1 0x0244
+#define B_BE_REG_CK_MON_SEL_MASK GENMASK(31, 29)
+#define B_BE_REG_CK_MON_CK960M_EN BIT(28)
+#define B_BE_REG_XTAL_FREQ_SEL BIT(27)
+#define B_BE_REG_XTAL_EDGE_SEL BIT(26)
+#define B_BE_REG_VCO_KVCO BIT(25)
+#define B_BE_REG_SDM_EDGE_SEL BIT(24)
+#define B_BE_REG_SDM_CK_SEL BIT(23)
+#define B_BE_REG_SDM_CK_GATED BIT(22)
+#define B_BE_REG_PFD_RESET_GATED BIT(21)
+#define B_BE_REG_LPF_R3_FAST_MASK GENMASK(20, 16)
+#define B_BE_REG_LPF_R2_FAST_MASK GENMASK(15, 11)
+#define B_BE_REG_LPF_C3_FAST_MASK GENMASK(10, 8)
+#define B_BE_REG_LPF_C2_FAST_MASK GENMASK(7, 5)
+#define B_BE_REG_LPF_C1_FAST_MASK GENMASK(4, 2)
+#define B_BE_REG_LPF_R3_4_MASK GENMASK(1, 0)
+
+#define R_BE_AFE_ON_CTRL3 0x024C
+#define B_BE_LDO_VSEL_DA_1_MASK GENMASK(31, 30)
+#define B_BE_LDO_VSEL_DA_0_MASK GENMASK(29, 28)
+#define B_BE_LDO_VSEL_D2S_1_MASK GENMASK(27, 26)
+#define B_BE_LDO_VSEL_D2S_0_MASK GENMASK(25, 24)
+#define B_BE_LDO_VSEL_BUF_MASK GENMASK(23, 22)
+#define B_BE_REG_R2_L_MASK GENMASK(21, 19)
+#define B_BE_REG_R1_L_MASK GENMASK(18, 16)
+#define B_BE_REG_CK_DEBUG_BT_MON BIT(15)
+#define B_BE_REG_BT_CLK_BUF_POWER BIT(14)
+#define B_BE_REG_BG_OUT_BTADC_V1 BIT(13)
+#define B_BE_REG_SEL_V18 BIT(11)
+#define B_BE_REG_FRAC_EN BIT(10)
+#define B_BE_REG_CK1920M_EN BIT(9)
+#define B_BE_REG_CK1280M_EN BIT(8)
+#define B_BE_REG_12LDO_SEL_MASK GENMASK(7, 6)
+#define B_BE_REG_09LDO_SEL_MASK GENMASK(5, 4)
+#define B_BE_REG_VC_TH BIT(3)
+#define B_BE_REG_VC_TL BIT(2)
+#define B_BE_REG_CK40M_EN BIT(1)
+#define B_BE_REG_CK640M_EN BIT(0)
+
+#define R_BE_WLAN_XTAL_SI_CTRL 0x0270
+#define B_BE_WL_XTAL_SI_CMD_POLL BIT(31)
+#define B_BE_WL_XTAL_SI_CHIPID_MASK GENMASK(30, 28)
+#define B_BE_WL_XTAL_SI_MODE_MASK GENMASK(25, 24)
+#define B_BE_WL_XTAL_SI_BITMASK_MASK GENMASK(23, 16)
+#define B_BE_WL_XTAL_SI_DATA_MASK GENMASK(15, 8)
+#define B_BE_WL_XTAL_SI_ADDR_MASK GENMASK(7, 0)
+
+#define R_BE_IC_PWR_STATE 0x03F0
+#define B_BE_WHOLE_SYS_PWR_STE_MASK GENMASK(25, 16)
+#define MAC_AX_SYS_ACT 0x220
+#define B_BE_WLMAC_PWR_STE_MASK GENMASK(9, 8)
+#define B_BE_UART_HCISYS_PWR_STE_MASK GENMASK(7, 6)
+#define B_BE_SDIO_HCISYS_PWR_STE_MASK GENMASK(5, 4)
+#define B_BE_USB_HCISYS_PWR_STE_MASK GENMASK(3, 2)
+#define B_BE_PCIE_HCISYS_PWR_STE_MASK GENMASK(1, 0)
+
+#define R_BE_WLCPU_PORT_PC 0x03FC
+
#define R_BE_DCPU_PLATFORM_ENABLE 0x0888
#define B_BE_DCPU_SYM_DPLT_MEM_MUX_EN BIT(10)
#define B_BE_DCPU_WARM_EN BIT(9)
@@ -3730,8 +4271,947 @@
#define B_BE_DCPU_EN BIT(1)
#define B_BE_DCPU_PLATFORM_EN BIT(0)
+#define R_BE_PL_AXIDMA_IDCT_MSK 0x0910
+#define B_BE_PL_AXIDMA_RRESP_ERR_MASK BIT(6)
+#define B_BE_PL_AXIDMA_BRESP_ERR_MASK BIT(5)
+#define B_BE_PL_AXIDMA_FC_ERR_MASK BIT(4)
+#define B_BE_PL_AXIDMA_TXBD_LEN0_MASK BIT(3)
+#define B_BE_PL_AXIDMA_TXBD_4KBOUD_LENERR_MASK BIT(2)
+#define B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK BIT(1)
+#define B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK BIT(0)
+#define B_BE_PL_AXIDMA_IDCT_MSK_CLR (B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK | \
+ B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK | \
+ B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \
+ B_BE_PL_AXIDMA_FC_ERR_MASK | \
+ B_BE_PL_AXIDMA_BRESP_ERR_MASK | \
+ B_BE_PL_AXIDMA_RRESP_ERR_MASK)
+#define B_BE_PL_AXIDMA_IDCT_MSK_SET (B_BE_PL_AXIDMA_TXBD_TX_STUCK_MASK | \
+ B_BE_PL_AXIDMA_TXBD_RX_STUCK_MASK | \
+ B_BE_PL_AXIDMA_TXBD_LEN0_MASK | \
+ B_BE_PL_AXIDMA_FC_ERR_MASK)
+
+#define R_BE_PL_AXIDMA_IDCT 0x0914
+#define B_BE_PL_AXIDMA_RRESP_ERR BIT(6)
+#define B_BE_PL_AXIDMA_BRESP_ERR BIT(5)
+#define B_BE_PL_AXIDMA_FC_ERR BIT(4)
+#define B_BE_PL_AXIDMA_TXBD_LEN0 BIT(3)
+#define B_BE_PL_AXIDMA_TXBD_4KBOUD_LENERR BIT(2)
+#define B_BE_PL_AXIDMA_TXBD_RX_STUCK BIT(1)
+#define B_BE_PL_AXIDMA_TXBD_TX_STUCK BIT(0)
+
#define R_BE_FILTER_MODEL_ADDR 0x0C04
+#define R_BE_WLAN_WDT 0x3050
+#define B_BE_WLAN_WDT_TIMEOUT BIT(31)
+#define B_BE_WLAN_WDT_TIMER_CLEAR BIT(4)
+#define B_BE_WLAN_WDT_BYPASS BIT(1)
+#define B_BE_WLAN_WDT_ENABLE BIT(0)
+
+#define R_BE_AXIDMA_WDT 0x305C
+#define B_BE_AXIDMA_WDT_TIMEOUT BIT(31)
+#define B_BE_AXIDMA_WDT_TIMER_CLEAR BIT(4)
+#define B_BE_AXIDMA_WDT_BYPASS BIT(1)
+#define B_BE_AXIDMA_WDT_ENABLE BIT(0)
+
+#define R_BE_AON_WDT 0x3068
+#define B_BE_AON_WDT_TIMEOUT BIT(31)
+#define B_BE_AON_WDT_TIMER_CLEAR BIT(4)
+#define B_BE_AON_WDT_BYPASS BIT(1)
+#define B_BE_AON_WDT_ENABLE BIT(0)
+
+#define R_BE_AON_WDT_TMR 0x306C
+#define R_BE_MDIO_WDT_TMR 0x3090
+#define R_BE_LA_MODE_WDT_TMR 0x309C
+#define R_BE_WDT_AR_TMR 0x3144
+#define R_BE_WDT_AW_TMR 0x3150
+#define R_BE_WLAN_WDT_TMR 0x3054
+#define R_BE_WDT_W_TMR 0x315C
+#define R_BE_AXIDMA_WDT_TMR 0x3060
+#define R_BE_WDT_B_TMR 0x3164
+#define R_BE_WDT_R_TMR 0x316C
+#define R_BE_LOCAL_WDT_TMR 0x3084
+
+#define R_BE_LOCAL_WDT 0x3080
+#define B_BE_LOCAL_WDT_TIMEOUT BIT(31)
+#define B_BE_LOCAL_WDT_TIMER_CLEAR BIT(4)
+#define B_BE_LOCAL_WDT_BYPASS BIT(1)
+#define B_BE_LOCAL_WDT_ENABLE BIT(0)
+
+#define R_BE_MDIO_WDT 0x308C
+#define B_BE_MDIO_WDT_TIMEOUT BIT(31)
+#define B_BE_MDIO_WDT_TIMER_CLEAR BIT(4)
+#define B_BE_MDIO_WDT_BYPASS BIT(1)
+#define B_BE_MDIO_WDT_ENABLE BIT(0)
+
+#define R_BE_LA_MODE_WDT 0x3098
+#define B_BE_LA_MODE_WDT_TIMEOUT BIT(31)
+#define B_BE_LA_MODE_WDT_TIMER_CLEAR BIT(4)
+#define B_BE_LA_MODE_WDT_BYPASS BIT(1)
+#define B_BE_LA_MODE_WDT_ENABLE BIT(0)
+
+#define R_BE_WDT_AR 0x3140
+#define B_BE_WDT_AR_TIMEOUT BIT(31)
+#define B_BE_WDT_AR_TIMER_CLEAR BIT(4)
+#define B_BE_WDT_AR_BYPASS BIT(1)
+#define B_BE_WDT_AR_ENABLE BIT(0)
+
+#define R_BE_WDT_AW 0x314C
+#define B_BE_WDT_AW_TIMEOUT BIT(31)
+#define B_BE_WDT_AW_TIMER_CLEAR BIT(4)
+#define B_BE_WDT_AW_BYPASS BIT(1)
+#define B_BE_WDT_AW_ENABLE BIT(0)
+
+#define R_BE_WDT_W 0x3158
+#define B_BE_WDT_W_TIMEOUT BIT(31)
+#define B_BE_WDT_W_TIMER_CLEAR BIT(4)
+#define B_BE_WDT_W_BYPASS BIT(1)
+#define B_BE_WDT_W_ENABLE BIT(0)
+
+#define R_BE_WDT_B 0x3160
+#define B_BE_WDT_B_TIMEOUT BIT(31)
+#define B_BE_WDT_B_TIMER_CLEAR BIT(4)
+#define B_BE_WDT_B_BYPASS BIT(1)
+#define B_BE_WDT_B_ENABLE BIT(0)
+
+#define R_BE_WDT_R 0x3168
+#define B_BE_WDT_R_TIMEOUT BIT(31)
+#define B_BE_WDT_R_TIMER_CLEAR BIT(4)
+#define B_BE_WDT_R_BYPASS BIT(1)
+#define B_BE_WDT_R_ENABLE BIT(0)
+
+#define R_BE_LTR_DECISION_CTRL_V1 0x3610
+#define B_BE_ENABLE_LTR_CTL_DECISION BIT(31)
+#define B_BE_LAT_LTR_IDX_DRV_VLD_V1 BIT(24)
+#define B_BE_LAT_LTR_IDX_DRV_V1_MASK GENMASK(23, 22)
+#define B_BE_LAT_LTR_IDX_FW_VLD_V1 BIT(21)
+#define B_BE_LAT_LTR_IDX_FW_V1_MASK GENMASK(20, 19)
+#define B_BE_LAT_LTR_IDX_HW_VLD_V1 BIT(18)
+#define B_BE_LAT_LTR_IDX_HW_V1_MASK GENMASK(17, 16)
+#define B_BE_LTR_IDX_DRV_V1_MASK GENMASK(15, 14)
+#define B_BE_LTR_REQ_DRV_V1 BIT(13)
+#define B_BE_LTR_IDX_DISABLE_V1_MASK GENMASK(9, 8)
+#define B_BE_LTR_EN_PORT_V1_MASK GENMASK(6, 4)
+#define B_BE_LTR_DRV_DEC_EN_V1 BIT(6)
+#define B_BE_LTR_FW_DEC_EN_V1 BIT(5)
+#define B_BE_LTR_HW_DEC_EN_V1 BIT(4)
+#define B_BE_LTR_SPACE_IDX_MASK GENMASK(1, 0)
+
+#define R_BE_LTR_LATENCY_IDX0_V1 0x3614
+#define R_BE_LTR_LATENCY_IDX1_V1 0x3618
+#define R_BE_LTR_LATENCY_IDX2_V1 0x361C
+#define R_BE_LTR_LATENCY_IDX3_V1 0x3620
+
+#define R_BE_HCI_FUNC_EN 0x7880
+#define B_BE_HCI_CR_PROTECT BIT(31)
+#define B_BE_HCI_TRXBUF_EN BIT(2)
+#define B_BE_HCI_RXDMA_EN BIT(1)
+#define B_BE_HCI_TXDMA_EN BIT(0)
+
+#define R_BE_DMAC_FUNC_EN 0x8400
+#define B_BE_DMAC_CRPRT BIT(31)
+#define B_BE_MAC_FUNC_EN BIT(30)
+#define B_BE_DMAC_FUNC_EN BIT(29)
+#define B_BE_MPDU_PROC_EN BIT(28)
+#define B_BE_WD_RLS_EN BIT(27)
+#define B_BE_DLE_WDE_EN BIT(26)
+#define B_BE_TXPKT_CTRL_EN BIT(25)
+#define B_BE_STA_SCH_EN BIT(24)
+#define B_BE_DLE_PLE_EN BIT(23)
+#define B_BE_PKT_BUF_EN BIT(22)
+#define B_BE_DMAC_TBL_EN BIT(21)
+#define B_BE_PKT_IN_EN BIT(20)
+#define B_BE_DLE_CPUIO_EN BIT(19)
+#define B_BE_DISPATCHER_EN BIT(18)
+#define B_BE_BBRPT_EN BIT(17)
+#define B_BE_MAC_SEC_EN BIT(16)
+#define B_BE_DMACREG_GCKEN BIT(15)
+#define B_BE_H_AXIDMA_EN BIT(14)
+#define B_BE_DMAC_MLO_EN BIT(11)
+#define B_BE_PLRLS_EN BIT(10)
+#define B_BE_P_AXIDMA_EN BIT(9)
+#define B_BE_DLE_DATACPUIO_EN BIT(8)
+#define B_BE_LTR_CTL_EN BIT(7)
+
+#define R_BE_DMAC_CLK_EN 0x8404
+#define B_BE_MAC_CKEN BIT(30)
+#define B_BE_DMAC_CKEN BIT(29)
+#define B_BE_MPDU_CKEN BIT(28)
+#define B_BE_WD_RLS_CLK_EN BIT(27)
+#define B_BE_DLE_WDE_CLK_EN BIT(26)
+#define B_BE_TXPKT_CTRL_CLK_EN BIT(25)
+#define B_BE_STA_SCH_CLK_EN BIT(24)
+#define B_BE_DLE_PLE_CLK_EN BIT(23)
+#define B_BE_PKTBUF_CKEN BIT(22)
+#define B_BE_DMAC_TABLE_CLK_EN BIT(21)
+#define B_BE_PKT_IN_CLK_EN BIT(20)
+#define B_BE_DLE_CPUIO_CLK_EN BIT(19)
+#define B_BE_DISPATCHER_CLK_EN BIT(18)
+#define B_BE_BBRPT_CLK_EN BIT(17)
+#define B_BE_MAC_SEC_CLK_EN BIT(16)
+#define B_BE_H_AXIDMA_CKEN BIT(14)
+#define B_BE_DMAC_MLO_CKEN BIT(11)
+#define B_BE_PLRLS_CKEN BIT(10)
+#define B_BE_P_AXIDMA_CKEN BIT(9)
+#define B_BE_DLE_DATACPUIO_CKEN BIT(8)
+
+#define R_BE_LTR_CTRL_0 0x8410
+#define B_BE_LTR_REQ_FW BIT(18)
+#define B_BE_LTR_IDX_FW_MASK GENMASK(17, 16)
+#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8)
+#define B_BE_LTR_WD_NOEMP_CHK BIT(1)
+#define B_BE_LTR_HW_EN BIT(0)
+
+#define R_BE_LTR_CFG_0 0x8414
+#define B_BE_LTR_IDX_DISABLE_MASK GENMASK(17, 16)
+#define B_BE_LTR_IDX_IDLE_MASK GENMASK(15, 14)
+#define B_BE_LTR_IDX_ACTIVE_MASK GENMASK(13, 12)
+#define B_BE_LTR_IDLE_TIMER_IDX_MASK GENMASK(10, 8)
+#define B_BE_EN_LTR_CMAC_RX_USE_PG_CHK BIT(3)
+#define B_BE_EN_LTR_WD_NON_EMPTY_CHK BIT(2)
+#define B_BE_EN_LTR_HAXIDMA_TX_IDLE_CHK BIT(1)
+#define B_BE_EN_LTR_HAXIDMA_RX_IDLE_CHK BIT(0)
+
+#define R_BE_LTR_CFG_1 0x8418
+#define B_BE_LTR_CMAC1_RX_USE_PG_TH_MASK GENMASK(27, 16)
+#define B_BE_LTR_CMAC0_RX_USE_PG_TH_MASK GENMASK(11, 0)
+
+#define R_BE_DMAC_TABLE_CTRL 0x8420
+#define B_BE_HWAMSDU_PADDING_MODE BIT(31)
+#define B_BE_MACID_MPDU_PROCESSOR_OFFSET_MASK GENMASK(26, 16)
+#define B_BE_DMAC_ADDR_MODE BIT(12)
+#define B_BE_DMAC_CTRL_INFO_SER_IO BIT(11)
+#define B_BE_DMAC_CTRL_INFO_OFFSET_MASK GENMASK(10, 0)
+
+#define R_BE_SER_DBG_INFO 0x8424
+#define B_BE_SER_L0_PROMOTE_L1_EVENT_MASK GENMASK(31, 28)
+#define B_BE_SER_L1_COUNTER_MASK GENMASK(27, 24)
+#define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16)
+#define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0)
+
+#define R_BE_DLE_EMPTY0 0x8430
+#define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27)
+#define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26)
+#define B_BE_PLE_EMPTY_QTA_DMAC_MPDU_TX BIT(25)
+#define B_BE_PLE_EMPTY_QTA_DMAC_WLAN_CPU BIT(24)
+#define B_BE_PLE_EMPTY_QTA_DMAC_H2C BIT(23)
+#define B_BE_PLE_EMPTY_QTA_DMAC_B1_TXPL BIT(22)
+#define B_BE_PLE_EMPTY_QTA_DMAC_B0_TXPL BIT(21)
+#define B_BE_WDE_EMPTY_QTA_DMAC_CPUIO BIT(20)
+#define B_BE_WDE_EMPTY_QTA_DMAC_PKTIN BIT(19)
+#define B_BE_WDE_EMPTY_QTA_DMAC_DATA_CPU BIT(18)
+#define B_BE_WDE_EMPTY_QTA_DMAC_WLAN_CPU BIT(17)
+#define B_BE_WDE_EMPTY_QTA_DMAC_HIF BIT(16)
+#define B_BE_WDE_EMPTY_QUE_CMAC_B1_HIQ BIT(15)
+#define B_BE_WDE_EMPTY_QUE_CMAC_B1_MBH BIT(14)
+#define B_BE_WDE_EMPTY_QUE_CMAC_B0_OTHERS BIT(13)
+#define B_BE_WDE_EMPTY_QUE_DMAC_MLO_ACQ BIT(12)
+#define B_BE_WDE_EMPTY_QUE_DMAC_MLO_MISC BIT(11)
+#define B_BE_WDE_EMPTY_QUE_DMAC_PKTIN BIT(10)
+#define B_BE_PLE_EMPTY_QUE_DMAC_SEC_TX BIT(9)
+#define B_BE_PLE_EMPTY_QUE_DMAC_MPDU_TX BIT(8)
+#define B_BE_WDE_EMPTY_QUE_OTHERS BIT(7)
+#define B_BE_WDE_EMPTY_QUE_CMAC_WMM3 BIT(6)
+#define B_BE_WDE_EMPTY_QUE_CMAC_WMM2 BIT(5)
+#define B_BE_WDE_EMPTY_QUE_CMAC0_WMM1 BIT(4)
+#define B_BE_WDE_EMPTY_QUE_CMAC0_WMM0 BIT(3)
+#define B_BE_WDE_EMPTY_QUE_CMAC1_MBH BIT(2)
+#define B_BE_WDE_EMPTY_QUE_CMAC0_MBH BIT(1)
+#define B_BE_WDE_EMPTY_QUE_CMAC0_ALL_AC BIT(0)
+
+#define R_BE_DLE_EMPTY1 0x8434
+#define B_BE_PLE_EMPTY_QTA_CMAC_DMA_TXRPT BIT(21)
+#define B_BE_PLE_EMPTY_QTA_DMAC_WDRLS BIT(20)
+#define B_BE_PLE_EMPTY_QTA_CMAC1_DMA_BBRPT BIT(19)
+#define B_BE_PLE_EMPTY_QTA_CMAC1_DMA_RX BIT(18)
+#define B_BE_PLE_EMPTY_QTA_CMAC0_DMA_RX BIT(17)
+#define B_BE_PLE_EMPTY_QTA_DMAC_C2H BIT(16)
+#define B_BE_PLE_EMPTY_QUE_DMAC_PLRLS BIT(5)
+#define B_BE_PLE_EMPTY_QUE_DMAC_CPUIO BIT(4)
+#define B_BE_PLE_EMPTY_QUE_DMAC_SEC_RX BIT(3)
+#define B_BE_PLE_EMPTY_QUE_DMAC_MPDU_RX BIT(2)
+#define B_BE_PLE_EMPTY_QUE_DMAC_HDP BIT(1)
+#define B_BE_WDE_EMPTY_QUE_DMAC_WDRLS BIT(0)
+
+#define R_BE_SER_L1_DBG_CNT_0 0x8440
+#define B_BE_SER_L1_WDRLS_CNT_MASK GENMASK(31, 24)
+#define B_BE_SER_L1_SEC_CNT_MASK GENMASK(23, 16)
+#define B_BE_SER_L1_MPDU_CNT_MASK GENMASK(15, 8)
+#define B_BE_SER_L1_STA_SCH_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_SER_L1_DBG_CNT_1 0x8444
+#define B_BE_SER_L1_WDE_CNT_MASK GENMASK(31, 24)
+#define B_BE_SER_L1_TXPKTCTRL_CNT_MASK GENMASK(23, 16)
+#define B_BE_SER_L1_PLE_CNT_MASK GENMASK(15, 8)
+#define B_BE_SER_L1_PKTIN_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_SER_L1_DBG_CNT_2 0x8448
+#define B_BE_SER_L1_DISP_CNT_MASK GENMASK(31, 24)
+#define B_BE_SER_L1_APB_BRIDGE_CNT_MASK GENMASK(23, 16)
+#define B_BE_SER_L1_DLE_W_CPUIO_CNT_MASK GENMASK(15, 8)
+#define B_BE_SER_L1_BBRPT_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_SER_L1_DBG_CNT_3 0x844C
+#define B_BE_SER_L1_HCI_BUF_CNT_MASK GENMASK(31, 24)
+#define B_BE_SER_L1_P_AXIDMA_CNT_MASK GENMASK(23, 16)
+#define B_BE_SER_L1_H_AXIDMA_CNT_MASK GENMASK(15, 8)
+#define B_BE_SER_L1_MLO_ERR_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_SER_L1_DBG_CNT_4 0x8450
+#define B_BE_SER_L1_PLDRLS_ERR_CNT_MASK GENMASK(31, 24)
+#define B_BE_SER_L1_DLE_D_CPUIO_CNT_MASK GENMASK(23, 16)
+
+#define R_BE_SER_L1_DBG_CNT_5 0x8454
+#define B_BE_SER_L1_DBG_0_MASK GENMASK(31, 0)
+
+#define R_BE_SER_L1_DBG_CNT_6 0x8458
+#define B_BE_SER_L1_DBG_1_MASK GENMASK(31, 0)
+
+#define R_BE_SER_L1_DBG_CNT_7 0x845C
+#define B_BE_SER_L1_DBG_2_MASK GENMASK(31, 0)
+
+#define R_BE_DMAC_ERR_IMR 0x8520
+#define B_BE_DMAC_NOTX_ERR_INT_EN BIT(21)
+#define B_BE_DMAC_NORX_ERR_INT_EN BIT(20)
+#define B_BE_DLE_DATACPUIO_ERR_INT_EN BIT(19)
+#define B_BE_PLRSL_ERR_INT_EN BIT(18)
+#define B_BE_MLO_ERR_INT_EN BIT(17)
+#define B_BE_DMAC_FW_ERR_INT_EN BIT(16)
+#define B_BE_H_AXIDMA_ERR_INT_EN BIT(14)
+#define B_BE_P_AXIDMA_ERR_INT_EN BIT(13)
+#define B_BE_HCI_BUF_ERR_INT_EN BIT(12)
+#define B_BE_BBRPT_ERR_INT_EN BIT(11)
+#define B_BE_DLE_CPUIO_ERR_INT_EN BIT(10)
+#define B_BE_APB_BRIDGE_ERR_INT_EN BIT(9)
+#define B_BE_DISPATCH_ERR_INT_EN BIT(8)
+#define B_BE_PKTIN_ERR_INT_EN BIT(7)
+#define B_BE_PLE_DLE_ERR_INT_EN BIT(6)
+#define B_BE_TXPKTCTRL_ERR_INT_EN BIT(5)
+#define B_BE_WDE_DLE_ERR_INT_EN BIT(4)
+#define B_BE_STA_SCHEDULER_ERR_INT_EN BIT(3)
+#define B_BE_MPDU_ERR_INT_EN BIT(2)
+#define B_BE_WSEC_ERR_INT_EN BIT(1)
+#define B_BE_WDRLS_ERR_INT_EN BIT(0)
+
+#define R_BE_DMAC_ERR_ISR 0x8524
+#define B_BE_DLE_DATACPUIO_ERR_INT BIT(19)
+#define B_BE_PLRLS_ERR_INT BIT(18)
+#define B_BE_MLO_ERR_INT BIT(17)
+#define B_BE_DMAC_FW_ERR_IDCT BIT(16)
+#define B_BE_H_AXIDMA_ERR_INT BIT(14)
+#define B_BE_P_AXIDMA_ERR_INT BIT(13)
+#define B_BE_HCI_BUF_ERR_FLAG BIT(12)
+#define B_BE_BBRPT_ERR_FLAG BIT(11)
+#define B_BE_DLE_CPUIO_ERR_FLAG BIT(10)
+#define B_BE_APB_BRIDGE_ERR_FLAG BIT(9)
+#define B_BE_DISPATCH_ERR_FLAG BIT(8)
+#define B_BE_PKTIN_ERR_FLAG BIT(7)
+#define B_BE_PLE_DLE_ERR_FLAG BIT(6)
+#define B_BE_TXPKTCTRL_ERR_FLAG BIT(5)
+#define B_BE_WDE_DLE_ERR_FLAG BIT(4)
+#define B_BE_STA_SCHEDULER_ERR_FLAG BIT(3)
+#define B_BE_MPDU_ERR_FLAG BIT(2)
+#define B_BE_WSEC_ERR_FLAG BIT(1)
+#define B_BE_WDRLS_ERR_FLAG BIT(0)
+
+#define R_BE_DISP_ERROR_ISR0 0x8804
+#define B_BE_REUSE_SIZE_ERR BIT(31)
+#define B_BE_REUSE_EN_ERR BIT(30)
+#define B_BE_STF_OQT_UNDERFLOW_ERR BIT(29)
+#define B_BE_STF_OQT_OVERFLOW_ERR BIT(28)
+#define B_BE_STF_WRFF_UNDERFLOW_ERR BIT(27)
+#define B_BE_STF_WRFF_OVERFLOW_ERR BIT(26)
+#define B_BE_STF_CMD_UNDERFLOW_ERR BIT(25)
+#define B_BE_STF_CMD_OVERFLOW_ERR BIT(24)
+#define B_BE_REUSE_SIZE_ZERO_ERR BIT(23)
+#define B_BE_REUSE_PKT_CNT_ERR BIT(22)
+#define B_BE_CDT_PTR_TIMEOUT_ERR BIT(21)
+#define B_BE_CDT_HCI_TIMEOUT_ERR BIT(20)
+#define B_BE_HDT_PTR_TIMEOUT_ERR BIT(19)
+#define B_BE_HDT_HCI_TIMEOUT_ERR BIT(18)
+#define B_BE_CDT_ADDR_INFO_LEN_ERR BIT(17)
+#define B_BE_HDT_ADDR_INFO_LEN_ERR BIT(16)
+#define B_BE_CDR_DMA_TIMEOUT_ERR BIT(15)
+#define B_BE_CDR_RX_TIMEOUT_ERR BIT(14)
+#define B_BE_PLE_OUTPUT_ERR BIT(12)
+#define B_BE_PLE_RESPOSE_ERR BIT(11)
+#define B_BE_PLE_BURST_NUM_ERR BIT(10)
+#define B_BE_PLE_NULL_PKT_ERR BIT(9)
+#define B_BE_PLE_FLOW_CTRL_ERR BIT(8)
+#define B_BE_HDR_DMA_TIMEOUT_ERR BIT(7)
+#define B_BE_HDR_RX_TIMEOUT_ERR BIT(6)
+#define B_BE_WDE_OUTPUT_ERR BIT(4)
+#define B_BE_WDE_RESPONSE_ERR BIT(3)
+#define B_BE_WDE_BURST_NUM_ERR BIT(2)
+#define B_BE_WDE_NULL_PKT_ERR BIT(1)
+#define B_BE_WDE_FLOW_CTRL_ERR BIT(0)
+
+#define R_BE_DISP_ERROR_ISR1 0x8808
+#define B_BE_HR_WRFF_UNDERFLOW_ERR BIT(31)
+#define B_BE_HR_WRFF_OVERFLOW_ERR BIT(30)
+#define B_BE_HR_CHKSUM_FSM_ERR BIT(29)
+#define B_BE_HR_SHIFT_DMA_CFG_ERR BIT(28)
+#define B_BE_HR_DMA_PROCESS_ERR BIT(27)
+#define B_BE_HR_TOTAL_LEN_UNDER_ERR BIT(26)
+#define B_BE_HR_SHIFT_EN_ERR BIT(25)
+#define B_BE_HR_AGG_CFG_ERR BIT(24)
+#define B_BE_HR_PLD_LEN_ZERO_ERR BIT(22)
+#define B_BE_HT_ILL_CH_ERR BIT(20)
+#define B_BE_HT_ADDR_INFO_LEN_ERR BIT(18)
+#define B_BE_HT_WD_LEN_OVER_ERR BIT(17)
+#define B_BE_HT_PLD_CMD_UNDERFLOW_ERR BIT(16)
+#define B_BE_HT_PLD_CMD_OVERFLOW_ERR BIT(15)
+#define B_BE_HT_WRFF_UNDERFLOW_ERR BIT(14)
+#define B_BE_HT_WRFF_OVERFLOW_ERR BIT(13)
+#define B_BE_HT_CHKSUM_FSM_ERR BIT(12)
+#define B_BE_HT_NON_IDLE_PKT_STR_ERR BIT(11)
+#define B_BE_HT_PRE_SUB_BE_ERR BIT(10)
+#define B_BE_HT_WD_CHKSUM_ERR BIT(9)
+#define B_BE_HT_CHANNEL_DMA_ERR BIT(8)
+#define B_BE_HT_OFFSET_UNMATCH_ERR BIT(7)
+#define B_BE_HT_PAYLOAD_UNDER_ERR BIT(6)
+#define B_BE_HT_PAYLOAD_OVER_ERR BIT(5)
+#define B_BE_HT_PERMU_FF_UNDERFLOW_ERR BIT(4)
+#define B_BE_HT_PERMU_FF_OVERFLOW_ERR BIT(3)
+#define B_BE_HT_PKT_FAIL_ERR BIT(2)
+#define B_BE_HT_CH_ID_ERR BIT(1)
+#define B_BE_HT_EP_CH_DIFF_ERR BIT(0)
+
+#define R_BE_DISP_ERROR_ISR2 0x880C
+#define B_BE_CR_PLD_LEN_ERR BIT(30)
+#define B_BE_CR_WRFF_UNDERFLOW_ERR BIT(29)
+#define B_BE_CR_WRFF_OVERFLOW_ERR BIT(28)
+#define B_BE_CR_SHIFT_DMA_CFG_ERR BIT(27)
+#define B_BE_CR_DMA_PROCESS_ERR BIT(26)
+#define B_BE_CR_SHIFT_EN_ERR BIT(24)
+#define B_BE_REUSE_FIFO_B_UNDER_ERR BIT(22)
+#define B_BE_REUSE_FIFO_B_OVER_ERR BIT(21)
+#define B_BE_REUSE_FIFO_A_UNDER_ERR BIT(20)
+#define B_BE_REUSE_FIFO_A_OVER_ERR BIT(19)
+#define B_BE_CT_ADDR_INFO_LEN_MISS_ERR BIT(17)
+#define B_BE_CT_WD_LEN_OVER_ERR BIT(16)
+#define B_BE_CT_F2P_SEQ_ERR BIT(15)
+#define B_BE_CT_F2P_QSEL_ERR BIT(14)
+#define B_BE_CT_PLD_CMD_UNDERFLOW_ERR BIT(13)
+#define B_BE_CT_PLD_CMD_OVERFLOW_ERR BIT(12)
+#define B_BE_CT_PRE_SUB_ERR BIT(11)
+#define B_BE_CT_WD_CHKSUM_ERR BIT(10)
+#define B_BE_CT_CHANNEL_DMA_ERR BIT(9)
+#define B_BE_CT_OFFSET_UNMATCH_ERR BIT(8)
+#define B_BE_F2P_TOTAL_NUM_ERR BIT(7)
+#define B_BE_CT_PAYLOAD_UNDER_ERR BIT(6)
+#define B_BE_CT_PAYLOAD_OVER_ERR BIT(5)
+#define B_BE_CT_PERMU_FF_UNDERFLOW_ERR BIT(4)
+#define B_BE_CT_PERMU_FF_OVERFLOW_ERR BIT(3)
+#define B_BE_CT_CH_ID_ERR BIT(2)
+#define B_BE_CT_EP_CH_DIFF_ERR BIT(0)
+
+#define R_BE_DISP_OTHER_IMR 0x8870
+#define B_BE_REUSE_SIZE_ERR_INT_EN BIT(31)
+#define B_BE_REUSE_EN_ERR_INT_EN BIT(30)
+#define B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN BIT(29)
+#define B_BE_STF_OQT_OVERFLOW_ERR_INT_EN BIT(28)
+#define B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN BIT(27)
+#define B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN BIT(26)
+#define B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN BIT(25)
+#define B_BE_STF_CMD_OVERFLOW_ERR_INT_EN BIT(24)
+#define B_BE_REUSE_SIZE_ZERO_ERR_INT_EN BIT(23)
+#define B_BE_REUSE_PKT_CNT_ERR_INT_EN BIT(22)
+#define B_BE_CDT_PTR_TIMEOUT_ERR_INT_EN BIT(21)
+#define B_BE_CDT_HCI_TIMEOUT_ERR_INT_EN BIT(20)
+#define B_BE_HDT_PTR_TIMEOUT_ERR_INT_EN BIT(19)
+#define B_BE_HDT_HCI_TIMEOUT_ERR_INT_EN BIT(18)
+#define B_BE_CDT_ADDR_INFO_LEN_ERR_INT_EN BIT(17)
+#define B_BE_HDT_ADDR_INFO_LEN_ERR_INT_EN BIT(16)
+#define B_BE_CDR_DMA_TIMEOUT_ERR_INT_EN BIT(15)
+#define B_BE_CDR_RX_TIMEOUT_ERR_INT_EN BIT(14)
+#define B_BE_PLE_OUTPUT_ERR_INT_EN BIT(12)
+#define B_BE_PLE_RESPOSE_ERR_INT_EN BIT(11)
+#define B_BE_PLE_BURST_NUM_ERR_INT_EN BIT(10)
+#define B_BE_PLE_NULL_PKT_ERR_INT_EN BIT(9)
+#define B_BE_PLE_FLOW_CTRL_ERR_INT_EN BIT(8)
+#define B_BE_HDR_DMA_TIMEOUT_ERR_INT_EN BIT(7)
+#define B_BE_HDR_RX_TIMEOUT_ERR_INT_EN BIT(6)
+#define B_BE_WDE_OUTPUT_ERR_INT_EN BIT(4)
+#define B_BE_WDE_RESPONSE_ERR_INT_EN BIT(3)
+#define B_BE_WDE_BURST_NUM_ERR_INT_EN BIT(2)
+#define B_BE_WDE_NULL_PKT_ERR_INT_EN BIT(1)
+#define B_BE_WDE_FLOW_CTRL_ERR_INT_EN BIT(0)
+#define B_BE_DISP_OTHER_IMR_CLR (B_BE_WDE_FLOW_CTRL_ERR_INT_EN | \
+ B_BE_WDE_NULL_PKT_ERR_INT_EN | \
+ B_BE_WDE_BURST_NUM_ERR_INT_EN | \
+ B_BE_WDE_RESPONSE_ERR_INT_EN | \
+ B_BE_WDE_OUTPUT_ERR_INT_EN | \
+ B_BE_HDR_RX_TIMEOUT_ERR_INT_EN | \
+ B_BE_HDR_DMA_TIMEOUT_ERR_INT_EN | \
+ B_BE_PLE_FLOW_CTRL_ERR_INT_EN | \
+ B_BE_PLE_NULL_PKT_ERR_INT_EN | \
+ B_BE_PLE_BURST_NUM_ERR_INT_EN | \
+ B_BE_PLE_RESPOSE_ERR_INT_EN | \
+ B_BE_PLE_OUTPUT_ERR_INT_EN | \
+ B_BE_CDR_RX_TIMEOUT_ERR_INT_EN | \
+ B_BE_CDR_DMA_TIMEOUT_ERR_INT_EN | \
+ B_BE_HDT_ADDR_INFO_LEN_ERR_INT_EN | \
+ B_BE_CDT_ADDR_INFO_LEN_ERR_INT_EN | \
+ B_BE_HDT_HCI_TIMEOUT_ERR_INT_EN | \
+ B_BE_HDT_PTR_TIMEOUT_ERR_INT_EN | \
+ B_BE_CDT_HCI_TIMEOUT_ERR_INT_EN | \
+ B_BE_CDT_PTR_TIMEOUT_ERR_INT_EN | \
+ B_BE_REUSE_PKT_CNT_ERR_INT_EN | \
+ B_BE_REUSE_SIZE_ZERO_ERR_INT_EN | \
+ B_BE_STF_CMD_OVERFLOW_ERR_INT_EN | \
+ B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN | \
+ B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \
+ B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN | \
+ B_BE_REUSE_EN_ERR_INT_EN | \
+ B_BE_REUSE_SIZE_ERR_INT_EN)
+#define B_BE_DISP_OTHER_IMR_SET (B_BE_STF_CMD_OVERFLOW_ERR_INT_EN | \
+ B_BE_STF_CMD_UNDERFLOW_ERR_INT_EN | \
+ B_BE_STF_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_STF_WRFF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_STF_OQT_OVERFLOW_ERR_INT_EN | \
+ B_BE_STF_OQT_UNDERFLOW_ERR_INT_EN)
+
+#define R_BE_DISP_HOST_IMR 0x8874
+#define B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN BIT(31)
+#define B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN BIT(30)
+#define B_BE_HR_CHKSUM_FSM_ERR_INT_EN BIT(29)
+#define B_BE_HR_SHIFT_DMA_CFG_ERR_INT_EN BIT(28)
+#define B_BE_HR_DMA_PROCESS_ERR_INT_EN BIT(27)
+#define B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN BIT(26)
+#define B_BE_HR_SHIFT_EN_ERR_INT_EN BIT(25)
+#define B_BE_HR_AGG_CFG_ERR_INT_EN BIT(24)
+#define B_BE_HR_PLD_LEN_ZERO_ERR_INT_EN BIT(22)
+#define B_BE_HT_ILL_CH_ERR_INT_EN BIT(20)
+#define B_BE_HT_ADDR_INFO_LEN_ERR_INT_EN BIT(18)
+#define B_BE_HT_WD_LEN_OVER_ERR_INT_EN BIT(17)
+#define B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN BIT(16)
+#define B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN BIT(15)
+#define B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN BIT(14)
+#define B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN BIT(13)
+#define B_BE_HT_CHKSUM_FSM_ERR_INT_EN BIT(12)
+#define B_BE_HT_NON_IDLE_PKT_STR_ERR_EN BIT(11)
+#define B_BE_HT_PRE_SUB_ERR_INT_EN BIT(10)
+#define B_BE_HT_WD_CHKSUM_ERR_INT_EN BIT(9)
+#define B_BE_HT_CHANNEL_DMA_ERR_INT_EN BIT(8)
+#define B_BE_HT_OFFSET_UNMATCH_ERR_INT_EN BIT(7)
+#define B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN BIT(6)
+#define B_BE_HT_PAYLOAD_OVER_ERR_INT_EN BIT(5)
+#define B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN BIT(4)
+#define B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN BIT(3)
+#define B_BE_HT_PKT_FAIL_ERR_INT_EN BIT(2)
+#define B_BE_HT_CH_ID_ERR_INT_EN BIT(1)
+#define B_BE_HT_EP_CH_DIFF_ERR_INT_EN BIT(0)
+#define B_BE_DISP_HOST_IMR_CLR (B_BE_HT_EP_CH_DIFF_ERR_INT_EN | \
+ B_BE_HT_CH_ID_ERR_INT_EN | \
+ B_BE_HT_PKT_FAIL_ERR_INT_EN | \
+ B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN | \
+ B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_HT_PAYLOAD_OVER_ERR_INT_EN | \
+ B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN | \
+ B_BE_HT_OFFSET_UNMATCH_ERR_INT_EN | \
+ B_BE_HT_CHANNEL_DMA_ERR_INT_EN | \
+ B_BE_HT_WD_CHKSUM_ERR_INT_EN | \
+ B_BE_HT_PRE_SUB_ERR_INT_EN | \
+ B_BE_HT_NON_IDLE_PKT_STR_ERR_EN | \
+ B_BE_HT_CHKSUM_FSM_ERR_INT_EN | \
+ B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN | \
+ B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \
+ B_BE_HT_WD_LEN_OVER_ERR_INT_EN | \
+ B_BE_HT_ADDR_INFO_LEN_ERR_INT_EN | \
+ B_BE_HT_ILL_CH_ERR_INT_EN | \
+ B_BE_HR_PLD_LEN_ZERO_ERR_INT_EN | \
+ B_BE_HR_AGG_CFG_ERR_INT_EN | \
+ B_BE_HR_SHIFT_EN_ERR_INT_EN | \
+ B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN | \
+ B_BE_HR_DMA_PROCESS_ERR_INT_EN | \
+ B_BE_HR_SHIFT_DMA_CFG_ERR_INT_EN | \
+ B_BE_HR_CHKSUM_FSM_ERR_INT_EN | \
+ B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN)
+#define B_BE_DISP_HOST_IMR_SET (B_BE_HT_EP_CH_DIFF_ERR_INT_EN | \
+ B_BE_HT_PERMU_FF_OVERFLOW_ERR_INT_EN | \
+ B_BE_HT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_HT_PAYLOAD_OVER_ERR_INT_EN | \
+ B_BE_HT_PAYLOAD_UNDER_ERR_INT_EN | \
+ B_BE_HT_CHANNEL_DMA_ERR_INT_EN | \
+ B_BE_HT_PRE_SUB_ERR_INT_EN | \
+ B_BE_HT_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_HT_WRFF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_HT_PLD_CMD_OVERFLOW_ERR_INT_EN | \
+ B_BE_HT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \
+ B_BE_HT_WD_LEN_OVER_ERR_INT_EN | \
+ B_BE_HT_ILL_CH_ERR_INT_EN | \
+ B_BE_HR_TOTAL_LEN_UNDER_ERR_INT_EN | \
+ B_BE_HR_DMA_PROCESS_ERR_INT_EN | \
+ B_BE_HR_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_HR_WRFF_UNDERFLOW_ERR_INT_EN)
+
+#define R_BE_DISP_CPU_IMR 0x8878
+#define B_BE_CR_PLD_LEN_ERR_INT_EN BIT(30)
+#define B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN BIT(29)
+#define B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN BIT(28)
+#define B_BE_CR_SHIFT_DMA_CFG_ERR_INT_EN BIT(27)
+#define B_BE_CR_DMA_PROCESS_ERR_INT_EN BIT(26)
+#define B_BE_CR_TOTAL_LEN_UNDER_ERR_INT_EN BIT(25)
+#define B_BE_CR_SHIFT_EN_ERR_INT_EN BIT(24)
+#define B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN BIT(22)
+#define B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN BIT(21)
+#define B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN BIT(20)
+#define B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN BIT(19)
+#define B_BE_CT_ADDR_INFO_LEN_MISS_ERR_INT_EN BIT(17)
+#define B_BE_CT_WD_LEN_OVER_ERR_INT_EN BIT(16)
+#define B_BE_CT_F2P_SEQ_ERR_INT_EN BIT(15)
+#define B_BE_CT_F2P_QSEL_ERR_INT_EN BIT(14)
+#define B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN BIT(13)
+#define B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN BIT(12)
+#define B_BE_CT_PRE_SUB_ERR_INT_EN BIT(11)
+#define B_BE_CT_WD_CHKSUM_ERR_INT_EN BIT(10)
+#define B_BE_CT_CHANNEL_DMA_ERR_INT_EN BIT(9)
+#define B_BE_CT_OFFSET_UNMATCH_ERR_INT_EN BIT(8)
+#define B_BE_CT_PAYLOAD_CHKSUM_ERR_INT_EN BIT(7)
+#define B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN BIT(6)
+#define B_BE_CT_PAYLOAD_OVER_ERR_INT_EN BIT(5)
+#define B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN BIT(4)
+#define B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN BIT(3)
+#define B_BE_CT_CH_ID_ERR_INT_EN BIT(2)
+#define B_BE_CT_PKT_FAIL_ERR_INT_EN BIT(1)
+#define B_BE_CT_EP_CH_DIFF_ERR_INT_EN BIT(0)
+#define B_BE_DISP_CPU_IMR_CLR (B_BE_CT_EP_CH_DIFF_ERR_INT_EN | \
+ B_BE_CT_CH_ID_ERR_INT_EN | \
+ B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN | \
+ B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_CT_PAYLOAD_OVER_ERR_INT_EN | \
+ B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN | \
+ B_BE_CT_OFFSET_UNMATCH_ERR_INT_EN | \
+ B_BE_CT_CHANNEL_DMA_ERR_INT_EN | \
+ B_BE_CT_WD_CHKSUM_ERR_INT_EN | \
+ B_BE_CT_PRE_SUB_ERR_INT_EN | \
+ B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN | \
+ B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \
+ B_BE_CT_F2P_QSEL_ERR_INT_EN | \
+ B_BE_CT_F2P_SEQ_ERR_INT_EN | \
+ B_BE_CT_WD_LEN_OVER_ERR_INT_EN | \
+ B_BE_CT_ADDR_INFO_LEN_MISS_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN | \
+ B_BE_CR_SHIFT_EN_ERR_INT_EN | \
+ B_BE_CR_DMA_PROCESS_ERR_INT_EN | \
+ B_BE_CR_SHIFT_DMA_CFG_ERR_INT_EN | \
+ B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_CR_PLD_LEN_ERR_INT_EN)
+#define B_BE_DISP_CPU_IMR_SET (B_BE_CT_EP_CH_DIFF_ERR_INT_EN | \
+ B_BE_CT_CH_ID_ERR_INT_EN | \
+ B_BE_CT_PERMU_FF_OVERFLOW_ERR_INT_EN | \
+ B_BE_CT_PERMU_FF_UNDERFLOW_ERR_INT_EN | \
+ B_BE_CT_PAYLOAD_OVER_ERR_INT_EN | \
+ B_BE_CT_PAYLOAD_UNDER_ERR_INT_EN | \
+ B_BE_CT_PRE_SUB_ERR_INT_EN | \
+ B_BE_CT_PLD_CMD_OVERFLOW_ERR_INT_EN | \
+ B_BE_CT_PLD_CMD_UNDERFLOW_ERR_INT_EN | \
+ B_BE_CT_WD_LEN_OVER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_A_OVER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_A_UNDER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_B_OVER_ERR_INT_EN | \
+ B_BE_REUSE_FIFO_B_UNDER_ERR_INT_EN | \
+ B_BE_CR_DMA_PROCESS_ERR_INT_EN | \
+ B_BE_CR_WRFF_OVERFLOW_ERR_INT_EN | \
+ B_BE_CR_WRFF_UNDERFLOW_ERR_INT_EN)
+
+#define R_BE_DISP_FWD_WLAN_0 0x8938
+#define B_BE_FWD_WLAN_CPU_TYPE_13_MASK GENMASK(31, 30)
+#define B_BE_FWD_WLAN_CPU_TYPE_12_MASK GENMASK(29, 28)
+#define B_BE_FWD_WLAN_CPU_TYPE_11_MASK GENMASK(27, 26)
+#define B_BE_FWD_WLAN_CPU_TYPE_10_MASK GENMASK(25, 24)
+#define B_BE_FWD_WLAN_CPU_TYPE_9_MASK GENMASK(23, 22)
+#define B_BE_FWD_WLAN_CPU_TYPE_8_MASK GENMASK(21, 20)
+#define B_BE_FWD_WLAN_CPU_TYPE_7_MASK GENMASK(19, 18)
+#define B_BE_FWD_WLAN_CPU_TYPE_6_MASK GENMASK(17, 16)
+#define B_BE_FWD_WLAN_CPU_TYPE_5_MASK GENMASK(15, 14)
+#define B_BE_FWD_WLAN_CPU_TYPE_4_MASK GENMASK(13, 12)
+#define B_BE_FWD_WLAN_CPU_TYPE_3_MASK GENMASK(11, 10)
+#define B_BE_FWD_WLAN_CPU_TYPE_2_MASK GENMASK(9, 8)
+#define B_BE_FWD_WLAN_CPU_TYPE_1_MASK GENMASK(7, 6)
+#define B_BE_FWD_WLAN_CPU_TYPE_0_CTL_MASK GENMASK(5, 4)
+#define B_BE_FWD_WLAN_CPU_TYPE_0_MNG_MASK GENMASK(3, 2)
+#define B_BE_FWD_WLAN_CPU_TYPE_0_DATA_MASK GENMASK(1, 0)
+
+#define R_BE_WDE_PKTBUF_CFG 0x8C08
+#define B_BE_WDE_FREE_PAGE_NUM_MASK GENMASK(28, 16)
+#define B_BE_WDE_START_BOUND_MASK GENMASK(14, 8)
+#define B_BE_WDE_PAGE_SEL_MASK GENMASK(1, 0)
+
+#define R_BE_WDE_ERR_IMR 0x8C38
+#define B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN BIT(29)
+#define B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN BIT(28)
+#define B_BE_WDE_DATCHN_RRDY_ERR_INT_EN BIT(27)
+#define B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN BIT(26)
+#define B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN BIT(25)
+#define B_BE_WDE_DATCHN_ARBT_ERR_INT_EN BIT(24)
+#define B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN BIT(23)
+#define B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN BIT(22)
+#define B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN BIT(21)
+#define B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN BIT(20)
+#define B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN BIT(19)
+#define B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN BIT(18)
+#define B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN BIT(17)
+#define B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN BIT(16)
+#define B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN BIT(13)
+#define B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN BIT(12)
+#define B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN BIT(11)
+#define B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN BIT(10)
+#define B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN BIT(9)
+#define B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN BIT(8)
+#define B_BE_WDE_GETNPG_STRPG_ERR_INT_EN BIT(7)
+#define B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN BIT(6)
+#define B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN BIT(5)
+#define B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN BIT(4)
+#define B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN BIT(3)
+#define B_BE_WDE_BUFREQ_SIZELMT_INT_EN BIT(2)
+#define B_BE_WDE_BUFREQ_SIZE0_INT_EN BIT(1)
+#define B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN BIT(0)
+#define B_BE_WDE_ERR_IMR_CLR (B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN | \
+ B_BE_WDE_BUFREQ_SIZE0_INT_EN | \
+ B_BE_WDE_BUFREQ_SIZELMT_INT_EN | \
+ B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN | \
+ B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \
+ B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN | \
+ B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \
+ B_BE_WDE_GETNPG_STRPG_ERR_INT_EN | \
+ B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN | \
+ B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \
+ B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN | \
+ B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN | \
+ B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN | \
+ B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \
+ B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \
+ B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN | \
+ B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN | \
+ B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_ARBT_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_RRDY_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN)
+#define B_BE_WDE_ERR_IMR_SET (B_BE_WDE_BUFREQ_QTAID_ERR_INT_EN | \
+ B_BE_WDE_BUFREQ_SIZE0_INT_EN | \
+ B_BE_WDE_BUFREQ_SIZELMT_INT_EN | \
+ B_BE_WDE_BUFREQ_UNAVAL_ERR_INT_EN | \
+ B_BE_WDE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \
+ B_BE_WDE_BUFRTN_SIZE_ERR_INT_EN | \
+ B_BE_WDE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \
+ B_BE_WDE_GETNPG_STRPG_ERR_INT_EN | \
+ B_BE_WDE_GETNPG_PGOFST_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_FRZTO_ERR_INT_EN | \
+ B_BE_WDE_ERR_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_MRG_QTAID_ERR_INT_EN | \
+ B_BE_WDE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \
+ B_BE_WDE_QUE_CMDTYPE_ERR_INT_EN | \
+ B_BE_WDE_QUE_DSTQUEID_ERR_INT_EN | \
+ B_BE_WDE_QUE_SRCQUEID_ERR_INT_EN | \
+ B_BE_WDE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \
+ B_BE_WDE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \
+ B_BE_WDE_PREPKTLLT_AD_ERR_INT_EN | \
+ B_BE_WDE_NXTPKTLL_AD_ERR_INT_EN | \
+ B_BE_WDE_QUEMGN_FRZTO_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_ARBT_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_NULLPG_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_FRZTO_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_RRDY_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_ADRERR_ERR_INT_EN | \
+ B_BE_WDE_DATCHN_CAMREQ_ERR_INT_EN)
+
+#define R_BE_WDE_QTA0_CFG 0x8C40
+#define B_BE_WDE_Q0_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_WDE_Q0_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_WDE_QTA1_CFG 0x8C44
+#define B_BE_WDE_Q1_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_WDE_Q1_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_WDE_QTA2_CFG 0x8C48
+#define B_BE_WDE_Q2_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_WDE_Q2_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_WDE_QTA3_CFG 0x8C4C
+#define B_BE_WDE_Q3_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_WDE_Q3_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_WDE_QTA4_CFG 0x8C50
+#define B_BE_WDE_Q4_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_WDE_Q4_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_WDE_ERR1_IMR 0x8CC0
+#define B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN BIT(8)
+#define B_BE_WDE_ERR1_IMR_CLR B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN
+#define B_BE_WDE_ERR1_IMR_SET B_BE_WDE_QUEMGN_CMACACQ_DEQNTFY_INT_EN
+
+#define R_BE_PLE_PKTBUF_CFG 0x9008
+#define B_BE_PLE_FREE_PAGE_NUM_MASK GENMASK(28, 16)
+#define B_BE_PLE_START_BOUND_MASK GENMASK(14, 8)
+#define B_BE_PLE_PAGE_SEL_MASK GENMASK(1, 0)
+
+#define R_BE_PLE_ERR_IMR 0x9038
+#define B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN BIT(29)
+#define B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN BIT(28)
+#define B_BE_PLE_DATCHN_RRDY_ERR_INT_EN BIT(27)
+#define B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN BIT(26)
+#define B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN BIT(25)
+#define B_BE_PLE_DATCHN_ARBT_ERR_INT_EN BIT(24)
+#define B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN BIT(23)
+#define B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN BIT(22)
+#define B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN BIT(21)
+#define B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN BIT(20)
+#define B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN BIT(19)
+#define B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN BIT(18)
+#define B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN BIT(17)
+#define B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN BIT(16)
+#define B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN BIT(13)
+#define B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN BIT(12)
+#define B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN BIT(11)
+#define B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN BIT(10)
+#define B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN BIT(9)
+#define B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN BIT(8)
+#define B_BE_PLE_GETNPG_STRPG_ERR_INT_EN BIT(7)
+#define B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN BIT(6)
+#define B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN BIT(5)
+#define B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN BIT(4)
+#define B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN BIT(3)
+#define B_BE_PLE_BUFREQ_SIZELMT_INT_EN BIT(2)
+#define B_BE_PLE_BUFREQ_SIZE0_INT_EN BIT(1)
+#define B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN BIT(0)
+#define B_BE_PLE_ERR_IMR_CLR (B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN | \
+ B_BE_PLE_BUFREQ_SIZE0_INT_EN | \
+ B_BE_PLE_BUFREQ_SIZELMT_INT_EN | \
+ B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN | \
+ B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \
+ B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN | \
+ B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \
+ B_BE_PLE_GETNPG_STRPG_ERR_INT_EN | \
+ B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \
+ B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN | \
+ B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN | \
+ B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN | \
+ B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \
+ B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \
+ B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN | \
+ B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN | \
+ B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_ARBT_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_RRDY_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN)
+#define B_BE_PLE_ERR_IMR_SET (B_BE_PLE_BUFREQ_QTAID_ERR_INT_EN | \
+ B_BE_PLE_BUFREQ_SIZE0_INT_EN | \
+ B_BE_PLE_BUFREQ_SIZELMT_INT_EN | \
+ B_BE_PLE_BUFREQ_UNAVAL_ERR_INT_EN | \
+ B_BE_PLE_BUFRTN_INVLD_PKTID_ERR_INT_EN | \
+ B_BE_PLE_BUFRTN_SIZE_ERR_INT_EN | \
+ B_BE_PLE_BUFREQ_SRCHTAILPG_ERR_INT_EN | \
+ B_BE_PLE_GETNPG_STRPG_ERR_INT_EN | \
+ B_BE_PLE_GETNPG_PGOFST_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_FRZTO_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_STRPKTID_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_ENDPKTID_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_QTAID_ERR_INT_EN | \
+ B_BE_PLE_BUFMGN_MRG_SZLMT_ERR_INT_EN | \
+ B_BE_PLE_QUE_CMDTYPE_ERR_INT_EN | \
+ B_BE_PLE_QUE_DSTQUEID_ERR_INT_EN | \
+ B_BE_PLE_QUE_SRCQUEID_ERR_INT_EN | \
+ B_BE_PLE_ENQ_PKTCNT_OVRF_ERR_INT_EN | \
+ B_BE_PLE_ENQ_PKTCNT_NVAL_ERR_INT_EN | \
+ B_BE_PLE_PREPKTLLT_AD_ERR_INT_EN | \
+ B_BE_PLE_NXTPKTLL_AD_ERR_INT_EN | \
+ B_BE_PLE_QUEMGN_FRZTO_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_ARBT_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_NULLPG_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_FRZTO_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_RRDY_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_ADRERR_ERR_INT_EN | \
+ B_BE_PLE_DATCHN_CAMREQ_ERR_INT_EN)
+
+#define R_BE_PLE_QTA0_CFG 0x9040
+#define B_BE_PLE_Q0_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q0_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA1_CFG 0x9044
+#define B_BE_PLE_Q1_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q1_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA2_CFG 0x9048
+#define B_BE_PLE_Q2_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q2_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA3_CFG 0x904C
+#define B_BE_PLE_Q3_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q3_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA4_CFG 0x9050
+#define B_BE_PLE_Q4_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q4_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA5_CFG 0x9054
+#define B_BE_PLE_Q5_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q5_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA6_CFG 0x9058
+#define B_BE_PLE_Q6_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q6_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA7_CFG 0x905C
+#define B_BE_PLE_Q7_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q7_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA8_CFG 0x9060
+#define B_BE_PLE_Q8_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q8_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA9_CFG 0x9064
+#define B_BE_PLE_Q9_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q9_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA10_CFG 0x9068
+#define B_BE_PLE_Q10_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q10_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA11_CFG 0x906C
+#define B_BE_PLE_Q11_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q11_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_QTA12_CFG 0x9070
+#define B_BE_PLE_Q12_MAX_SIZE_MASK GENMASK(27, 16)
+#define B_BE_PLE_Q12_MIN_SIZE_MASK GENMASK(11, 0)
+
+#define R_BE_PLE_ERRFLAG1_IMR 0x90C0
+#define B_BE_PLE_SRCHPG_PGOFST_IMR BIT(26)
+#define B_BE_PLE_SRCHPG_STRPG_IMR BIT(25)
+#define B_BE_PLE_SRCHPG_FRZTO_IMR BIT(24)
+#define B_BE_PLE_ERRFLAG1_IMR_CLR (B_BE_PLE_SRCHPG_FRZTO_IMR | \
+ B_BE_PLE_SRCHPG_STRPG_IMR | \
+ B_BE_PLE_SRCHPG_PGOFST_IMR)
+#define B_BE_PLE_ERRFLAG1_IMR_SET (B_BE_PLE_SRCHPG_FRZTO_IMR | \
+ B_BE_PLE_SRCHPG_STRPG_IMR | \
+ B_BE_PLE_SRCHPG_PGOFST_IMR)
+
#define R_BE_PLE_DBG_FUN_INTF_CTL 0x9110
#define B_BE_PLE_DFI_ACTIVE BIT(31)
#define B_BE_PLE_DFI_TRGSEL_MASK GENMASK(19, 16)
@@ -3740,6 +5220,608 @@
#define R_BE_PLE_DBG_FUN_INTF_DATA 0x9114
#define B_BE_PLE_DFI_DATA_MASK GENMASK(31, 0)
+#define R_BE_WDRLS_CFG 0x9408
+#define B_BE_WDRLS_DIS_AGAC BIT(31)
+#define B_BE_RLSRPT_BUFREQ_TO_MASK GENMASK(15, 8)
+#define B_BE_RLSRPT_BUFREQ_TO_SEL_MASK GENMASK(7, 6)
+#define B_BE_WDRLS_MODE_MASK GENMASK(1, 0)
+
+#define R_BE_WDRLS_ERR_IMR 0x9430
+#define B_BE_WDRLS_RPT3_FRZTO_ERR_INT_EN BIT(21)
+#define B_BE_WDRLS_RPT3_AGGNUM0_ERR_INT_EN BIT(20)
+#define B_BE_WDRLS_RPT2_FRZTO_ERR_INT_EN BIT(17)
+#define B_BE_WDRLS_RPT2_AGGNUM0_ERR_INT_EN BIT(16)
+#define B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN BIT(13)
+#define B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN BIT(12)
+#define B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN BIT(9)
+#define B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN BIT(8)
+#define B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN BIT(5)
+#define B_BE_WDRLS_PLEBREQ_TO_ERR_INT_EN BIT(4)
+#define B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN BIT(2)
+#define B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN BIT(1)
+#define B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN BIT(0)
+#define B_BE_WDRLS_ERR_IMR_CLR (B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN | \
+ B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN | \
+ B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN | \
+ B_BE_WDRLS_PLEBREQ_TO_ERR_INT_EN | \
+ B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN | \
+ B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN | \
+ B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN | \
+ B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \
+ B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN)
+#define B_BE_WDRLS_ERR_IMR_SET (B_BE_WDRLS_CTL_WDPKTID_ISNULL_ERR_INT_EN | \
+ B_BE_WDRLS_CTL_PLPKTID_ISNULL_ERR_INT_EN | \
+ B_BE_WDRLS_CTL_FRZTO_ERR_INT_EN | \
+ B_BE_WDRLS_PLEBREQ_PKTID_ISNULL_ERR_INT_EN | \
+ B_BE_WDRLS_RPT0_AGGNUM0_ERR_INT_EN | \
+ B_BE_WDRLS_RPT0_FRZTO_ERR_INT_EN | \
+ B_BE_WDRLS_RPT1_AGGNUM0_ERR_INT_EN | \
+ B_BE_WDRLS_RPT1_FRZTO_ERR_INT_EN)
+
+#define R_BE_RLSRPT0_CFG1 0x9444
+#define B_BE_RLSRPT0_FLTR_MAP_MASK GENMASK(27, 24)
+#define S_BE_WDRLS_FLTR_TXOK 1
+#define S_BE_WDRLS_FLTR_RTYLMT 2
+#define S_BE_WDRLS_FLTR_LIFTIM 4
+#define S_BE_WDRLS_FLTR_MACID 8
+#define B_BE_RLSRPT0_TO_MASK GENMASK(23, 16)
+#define B_BE_RLSRPT0_AGGNUM_MASK GENMASK(7, 0)
+
+#define R_BE_BBRPT_COM_ERR_IMR 0x9608
+#define B_BE_BBRPT_COM_EVT01_ISR_EN BIT(1)
+#define B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN BIT(0)
+#define B_BE_BBRPT_COM_ERR_IMR_CLR (B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN | \
+ B_BE_BBRPT_COM_EVT01_ISR_EN)
+#define B_BE_BBRPT_COM_ERR_IMR_SET B_BE_BBRPT_COM_NULL_PLPKTID_ISR_EN
+
+#define R_BE_BBRPT_CHINFO_ERR_IMR 0x9628
+#define B_BE_ERR_BB_ONETEN_INT_EN BIT(1)
+#define B_BE_ERR_GEN_FRZTO_INT_EN BIT(0)
+#define B_BE_BBRPT_CHINFO_ERR_IMR_CLR (B_BE_ERR_GEN_FRZTO_INT_EN | \
+ B_BE_ERR_BB_ONETEN_INT_EN)
+#define B_BE_BBRPT_CHINFO_ERR_IMR_SET (B_BE_ERR_GEN_FRZTO_INT_EN | \
+ B_BE_ERR_BB_ONETEN_INT_EN)
+
+#define R_BE_BBRPT_DFS_ERR_IMR 0x9638
+#define B_BE_BBRPT_DFS_TO_ERR_INT_EN BIT(0)
+#define B_BE_BBRPT_DFS_ERR_IMR_CLR B_BE_BBRPT_DFS_TO_ERR_INT_EN
+#define B_BE_BBRPT_DFS_ERR_IMR_SET B_BE_BBRPT_DFS_TO_ERR_INT_EN
+
+#define R_BE_LA_ERRFLAG_IMR 0x9668
+#define B_BE_LA_IMR_DATA_LOSS BIT(0)
+#define B_BE_LA_ERRFLAG_IMR_CLR B_BE_LA_IMR_DATA_LOSS
+#define B_BE_LA_ERRFLAG_IMR_SET B_BE_LA_IMR_DATA_LOSS
+
+#define R_BE_LA_ERRFLAG_ISR 0x966C
+#define B_BE_LA_ISR_DATA_LOSS BIT(0)
+
+#define R_BE_CH_INFO_DBGFLAG_IMR 0x9688
+#define B_BE_BCHN_EVT01_ISR_EN BIT(29)
+#define B_BE_BCHN_REQTO_ISR_EN BIT(28)
+#define B_BE_CHIF_RXDATA_AFACT_ISR_EN BIT(11)
+#define B_BE_CHIF_RXDATA_BFACT_ISR_EN BIT(10)
+#define B_BE_CHIF_HDR_SEGLEN_ISR_EN BIT(9)
+#define B_BE_CHIF_HDR_INVLD_ISR_EN BIT(8)
+#define B_BE_CHIF_BBONL_BFACT_ISR_EN BIT(4)
+#define B_BE_CHIF_RPT_OVF_ISR_EN BIT(3)
+#define B_BE_DBG_CHIF_DATA_LOSS_ISR_EN BIT(2)
+#define B_BE_CHIF_DATA_WTOUT_ISR_EN BIT(1)
+#define B_BE_CHIF_RPT_WTOUT_ISR_EN BIT(0)
+#define B_BE_CH_INFO_DBGFLAG_IMR_CLR (B_BE_CHIF_RPT_WTOUT_ISR_EN | \
+ B_BE_CHIF_DATA_WTOUT_ISR_EN | \
+ B_BE_DBG_CHIF_DATA_LOSS_ISR_EN | \
+ B_BE_CHIF_RPT_OVF_ISR_EN | \
+ B_BE_CHIF_HDR_INVLD_ISR_EN | \
+ B_BE_CHIF_HDR_SEGLEN_ISR_EN | \
+ B_BE_CHIF_RXDATA_BFACT_ISR_EN | \
+ B_BE_CHIF_RXDATA_AFACT_ISR_EN)
+#define B_BE_CH_INFO_DBGFLAG_IMR_SET 0
+
+#define R_BE_WD_BUF_REQ 0x9800
+#define B_BE_WD_BUF_REQ_EXEC BIT(31)
+#define B_BE_WD_BUF_REQ_QUOTA_ID_MASK GENMASK(23, 16)
+#define B_BE_WD_BUF_REQ_LEN_MASK GENMASK(15, 0)
+
+#define R_BE_WD_BUF_STATUS 0x9804
+#define B_BE_WD_BUF_STAT_DONE BIT(31)
+#define B_BE_WD_BUF_STAT_PKTID_MASK GENMASK(11, 0)
+
+#define R_BE_WD_CPUQ_OP_0 0x9810
+#define B_BE_WD_CPUQ_OP_EXEC BIT(31)
+#define B_BE_WD_CPUQ_OP_CMD_TYPE_MASK GENMASK(27, 24)
+#define B_BE_WD_CPUQ_OP_PKTNUM_MASK GENMASK(7, 0)
+
+#define R_BE_WD_CPUQ_OP_1 0x9814
+#define B_BE_WD_CPUQ_OP_SRC_MACID_MASK GENMASK(19, 12)
+#define B_BE_WD_CPUQ_OP_SRC_QID_MASK GENMASK(9, 4)
+#define B_BE_WD_CPUQ_OP_SRC_PID_MASK GENMASK(2, 0)
+
+#define R_BE_WD_CPUQ_OP_2 0x9818
+#define B_BE_WD_CPUQ_OP_DST_MACID_MASK GENMASK(19, 12)
+#define B_BE_WD_CPUQ_OP_DST_QID_MASK GENMASK(9, 4)
+#define B_BE_WD_CPUQ_OP_DST_PID_MASK GENMASK(2, 0)
+
+#define R_BE_WD_CPUQ_OP_3 0x981C
+#define B_BE_WD_CPUQ_OP_STRT_PKTID_MASK GENMASK(27, 16)
+#define B_BE_WD_CPUQ_OP_END_PKTID_MASK GENMASK(11, 0)
+
+#define R_BE_WD_CPUQ_OP_STATUS 0x9820
+#define B_BE_WD_CPUQ_OP_STAT_DONE BIT(31)
+#define B_BE_WD_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16)
+#define B_BE_WD_CPUQ_OP_PKTID_MASK GENMASK(11, 0)
+
+#define R_BE_PL_BUF_REQ 0x9840
+#define B_BE_PL_BUF_REQ_EXEC BIT(31)
+#define B_BE_PL_BUF_REQ_QUOTA_ID_MASK GENMASK(19, 16)
+#define B_BE_PL_BUF_REQ_LEN_MASK GENMASK(15, 0)
+
+#define R_BE_PL_BUF_STATUS 0x9844
+#define B_BE_PL_BUF_STAT_DONE BIT(31)
+#define B_BE_PL_BUF_STAT_PKTID_MASK GENMASK(11, 0)
+
+#define R_BE_PL_CPUQ_OP_0 0x9850
+#define B_BE_PL_CPUQ_OP_EXEC BIT(31)
+#define B_BE_PL_CPUQ_OP_CMD_TYPE_MASK GENMASK(27, 24)
+#define B_BE_PL_CPUQ_OP_PKTNUM_MASK GENMASK(7, 0)
+
+#define R_BE_PL_CPUQ_OP_1 0x9854
+#define B_BE_PL_CPUQ_OP_SRC_MACID_MASK GENMASK(19, 12)
+#define B_BE_PL_CPUQ_OP_SRC_QID_MASK GENMASK(9, 4)
+#define B_BE_PL_CPUQ_OP_SRC_PID_MASK GENMASK(2, 0)
+
+#define R_BE_PL_CPUQ_OP_2 0x9858
+#define B_BE_PL_CPUQ_OP_DST_MACID_MASK GENMASK(19, 12)
+#define B_BE_PL_CPUQ_OP_DST_QID_MASK GENMASK(9, 4)
+#define B_BE_PL_CPUQ_OP_DST_PID_MASK GENMASK(2, 0)
+
+#define R_BE_PL_CPUQ_OP_3 0x985C
+#define B_BE_PL_CPUQ_OP_STRT_PKTID_MASK GENMASK(27, 16)
+#define B_BE_PL_CPUQ_OP_END_PKTID_MASK GENMASK(11, 0)
+
+#define R_BE_PL_CPUQ_OP_STATUS 0x9860
+#define B_BE_PL_CPUQ_OP_STAT_DONE BIT(31)
+#define B_BE_PL_CPUQ_OP_PKTCNT_MASK GENMASK(27, 16)
+#define B_BE_PL_CPUQ_OP_PKTID_MASK GENMASK(11, 0)
+
+#define R_BE_CPUIO_ERR_IMR 0x9888
+#define B_BE_PLEQUE_OP_ERR_INT_EN BIT(12)
+#define B_BE_PLEBUF_OP_ERR_INT_EN BIT(8)
+#define B_BE_WDEQUE_OP_ERR_INT_EN BIT(4)
+#define B_BE_WDEBUF_OP_ERR_INT_EN BIT(0)
+#define B_BE_CPUIO_ERR_IMR_CLR (B_BE_WDEBUF_OP_ERR_INT_EN | \
+ B_BE_WDEQUE_OP_ERR_INT_EN | \
+ B_BE_PLEBUF_OP_ERR_INT_EN | \
+ B_BE_PLEQUE_OP_ERR_INT_EN)
+#define B_BE_CPUIO_ERR_IMR_SET (B_BE_WDEBUF_OP_ERR_INT_EN | \
+ B_BE_WDEQUE_OP_ERR_INT_EN | \
+ B_BE_PLEBUF_OP_ERR_INT_EN | \
+ B_BE_PLEQUE_OP_ERR_INT_EN)
+
+#define R_BE_PKTIN_ERR_IMR 0x9A20
+#define B_BE_SW_MERGE_ERR_INT_EN BIT(1)
+#define B_BE_GET_NULL_PKTID_ERR_INT_EN BIT(0)
+#define B_BE_PKTIN_ERR_IMR_CLR (B_BE_SW_MERGE_ERR_INT_EN | \
+ B_BE_GET_NULL_PKTID_ERR_INT_EN)
+#define B_BE_PKTIN_ERR_IMR_SET (B_BE_SW_MERGE_ERR_INT_EN | \
+ B_BE_GET_NULL_PKTID_ERR_INT_EN)
+
+#define R_BE_HDR_SHCUT_SETTING 0x9B00
+#define B_BE_TX_ADDR_MLD_TO_LIK BIT(4)
+#define B_BE_TX_HW_SEC_HDR_EN BIT(3)
+#define B_BE_TX_MAC_MPDU_PROC_EN BIT(2)
+#define B_BE_TX_HW_ACK_POLICY_EN BIT(1)
+#define B_BE_TX_HW_SEQ_EN BIT(0)
+
+#define R_BE_MPDU_TX_ERR_IMR 0x9BF4
+#define B_BE_TX_TIMEOUT_ERR_EN BIT(0)
+#define B_BE_MPDU_TX_ERR_IMR_CLR B_BE_TX_TIMEOUT_ERR_EN
+#define B_BE_MPDU_TX_ERR_IMR_SET 0
+
+#define R_BE_MPDU_PROC 0x9C00
+#define B_BE_PORT_SEL BIT(29)
+#define B_BE_WPKT_WLANCPU_QSEL_MASK GENMASK(28, 27)
+#define B_BE_WPKT_DATACPU_QSEL_MASK GENMASK(26, 25)
+#define B_BE_WPKT_FW_RLS BIT(24)
+#define B_BE_FWD_RPKT_MASK GENMASK(23, 16)
+#define B_BE_FWD_WPKT_MASK GENMASK(15, 8)
+#define B_BE_RXFWD_PRIO_MASK GENMASK(5, 4)
+#define B_BE_RXFWD_EN BIT(3)
+#define B_BE_DROP_NONDMA_PPDU BIT(2)
+#define B_BE_APPEND_FCS BIT(0)
+
+#define R_BE_CUT_AMSDU_CTRL 0x9C94
+#define B_BE_EN_CUT_AMSDU BIT(31)
+#define B_BE_CUT_AMSDU_CHKLEN_EN BIT(30)
+#define B_BE_CA_CHK_ADDRCAM_EN BIT(29)
+#define B_BE_MPDU_CUT_CTRL_EN BIT(24)
+#define B_BE_CUT_AMSDU_CHKLEN_L_TH_MASK GENMASK(23, 16)
+#define B_BE_CUT_AMSDU_CHKLEN_H_TH_MASK GENMASK(15, 0)
+
+#define R_BE_RX_HDRTRNS 0x9CC0
+#define B_BE_RX_MGN_MLD_ADDR_EN BIT(6)
+#define B_BE_HDR_INFO_MASK GENMASK(5, 4)
+#define B_BE_HC_ADDR_HIT_EN BIT(3)
+#define B_BE_RX_ADDR_LINK_TO_MLO BIT(2)
+#define B_BE_HDR_CNV BIT(1)
+#define B_BE_RX_HDR_CNV_EN BIT(0)
+#define TRXCFG_MPDU_PROC_RX_HDR_CONV 0x00000000
+
+#define R_BE_MPDU_RX_ERR_IMR 0x9CF4
+#define B_BE_LEN_ERR_IMR BIT(3)
+#define B_BE_TIMEOUT_ERR_IMR BIT(1)
+#define B_BE_MPDU_RX_ERR_IMR_CLR B_BE_TIMEOUT_ERR_IMR
+#define B_BE_MPDU_RX_ERR_IMR_SET 0
+
+#define R_BE_SEC_ENG_CTRL 0x9D00
+#define B_BE_SEC_ENG_EN BIT(31)
+#define B_BE_CCMP_SPP_MIC BIT(30)
+#define B_BE_CCMP_SPP_CTR BIT(29)
+#define B_BE_SEC_CAM_ACC BIT(28)
+#define B_BE_WMAC_SEC_PN_SEL_MASK GENMASK(27, 26)
+#define B_BE_WMAC_SEC_MASKIV BIT(25)
+#define B_BE_WAPI_SPEC BIT(24)
+#define B_BE_REVERT_TA_RA_MLD_EN BIT(23)
+#define B_BE_SEC_DBG_SEL_MASK GENMASK(19, 16)
+#define B_BE_CAM_FORCE_CLK BIT(15)
+#define B_BE_SEC_FORCE_CLK BIT(14)
+#define B_BE_SEC_RX_SHORT_ADD_ICVERR BIT(13)
+#define B_BE_SRAM_IO_PROT BIT(12)
+#define B_BE_SEC_PRE_ENQUE_TX BIT(11)
+#define B_BE_CLK_EN_CGCMP BIT(10)
+#define B_BE_CLK_EN_WAPI BIT(9)
+#define B_BE_CLK_EN_WEP_TKIP BIT(8)
+#define B_BE_BMC_MGNT_DEC BIT(5)
+#define B_BE_UC_MGNT_DEC BIT(4)
+#define B_BE_MC_DEC BIT(3)
+#define B_BE_BC_DEC BIT(2)
+#define B_BE_SEC_RX_DEC BIT(1)
+#define B_BE_SEC_TX_ENC BIT(0)
+
+#define R_BE_SEC_MPDU_PROC 0x9D04
+#define B_BE_DBG_ENGINE_SEL BIT(8)
+#define B_BE_STOP_RX_PKT_HANDLE BIT(7)
+#define B_BE_STOP_TX_PKT_HANDLE BIT(6)
+#define B_BE_QUEUE_FOWARD_SEL BIT(5)
+#define B_BE_RESP1_PROTECT BIT(4)
+#define B_BE_RESP0_PROTECT BIT(3)
+#define B_BE_TX_ACTIVE_PROTECT BIT(2)
+#define B_BE_APPEND_ICV BIT(1)
+#define B_BE_APPEND_MIC BIT(0)
+
+#define R_BE_SEC_CAM_ACCESS 0x9D10
+#define B_BE_SEC_TIME_OUT_MASK GENMASK(31, 16)
+#define B_BE_SEC_CAM_POLL BIT(15)
+#define B_BE_SEC_CAM_RW BIT(14)
+#define B_BE_SEC_CAM_ACC_FAIL BIT(13)
+#define B_BE_SEC_CAM_OFFSET_MASK GENMASK(10, 0)
+
+#define R_BE_SEC_CAM_RDATA 0x9D14
+#define B_BE_SEC_CAM_RDATA_MASK GENMASK(31, 0)
+
+#define R_BE_SEC_DEBUG2 0x9D28
+#define B_BE_DBG_READ_MASK GENMASK(31, 0)
+
+#define R_BE_SEC_ERROR_IMR 0x9D2C
+#define B_BE_QUEUE_OPERATION_HANG_IMR BIT(4)
+#define B_BE_SEC1_RX_HANG_IMR BIT(3)
+#define B_BE_SEC1_TX_HANG_IMR BIT(2)
+#define B_BE_RX_HANG_IMR BIT(1)
+#define B_BE_TX_HANG_IMR BIT(0)
+#define B_BE_SEC_ERROR_IMR_CLR (B_BE_TX_HANG_IMR | \
+ B_BE_RX_HANG_IMR | \
+ B_BE_SEC1_TX_HANG_IMR | \
+ B_BE_SEC1_RX_HANG_IMR | \
+ B_BE_QUEUE_OPERATION_HANG_IMR)
+#define B_BE_SEC_ERROR_IMR_SET (B_BE_TX_HANG_IMR | \
+ B_BE_RX_HANG_IMR | \
+ B_BE_SEC1_TX_HANG_IMR | \
+ B_BE_SEC1_RX_HANG_IMR | \
+ B_BE_QUEUE_OPERATION_HANG_IMR)
+
+#define R_BE_SEC_ERROR_FLAG 0x9D30
+#define B_BE_TXD_DIFF_KEYCAM_TYPE_ERROR BIT(5)
+#define B_BE_QUEUE_OPERATION_HANG_ERROR BIT(4)
+#define B_BE_SEC1_RX_HANG_ERROR BIT(3)
+#define B_BE_SEC1_TX_HANG_ERROR BIT(2)
+#define B_BE_RX_HANG_ERROR BIT(1)
+#define B_BE_TX_HANG_ERROR BIT(0)
+
+#define R_BE_TXPKTCTL_MPDUINFO_CFG 0x9F10
+#define B_BE_MPDUINFO_FEN BIT(31)
+#define B_BE_MPDUINFO_PKTID_MASK GENMASK(27, 16)
+#define B_BE_MPDUINFO_B1_BADDR_MASK GENMASK(5, 0)
+#define MPDU_INFO_B1_OFST 18
+
+#define R_BE_TXPKTCTL_B0_PRELD_CFG0 0x9F48
+#define B_BE_B0_PRELD_FEN BIT(31)
+#define B_BE_B0_PRELD_USEMAXSZ_MASK GENMASK(25, 16)
+#define B_BE_B0_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8)
+#define B_BE_B0_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0)
+
+#define R_BE_TXPKTCTL_B0_PRELD_CFG1 0x9F4C
+#define B_BE_B0_PRELD_NXT_TXENDWIN_MASK GENMASK(11, 8)
+#define B_BE_B0_PRELD_NXT_RSVMINSZ_MASK GENMASK(7, 0)
+
+#define R_BE_TXPKTCTL_B0_ERRFLAG_IMR 0x9F78
+#define B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN BIT(25)
+#define B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD BIT(24)
+#define B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG BIT(17)
+#define B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR BIT(16)
+#define B_BE_B0_IMR_ERR_CMDPSR_TBLSZ BIT(11)
+#define B_BE_B0_IMR_ERR_CMDPSR_FRZTO BIT(10)
+#define B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE BIT(9)
+#define B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR BIT(8)
+#define B_BE_B0_IMR_ERR_USRCTL_NOINIT BIT(1)
+#define B_BE_B0_IMR_ERR_USRCTL_REINIT BIT(0)
+#define B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR (B_BE_B0_IMR_ERR_USRCTL_REINIT | \
+ B_BE_B0_IMR_ERR_USRCTL_NOINIT | \
+ B_BE_B0_IMR_DBG_USRCTL_RDNRLSCMD | \
+ B_BE_B0_IMR_DBG_USRCTL_RLSBMPLEN | \
+ B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR | \
+ B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE | \
+ B_BE_B0_IMR_ERR_CMDPSR_FRZTO | \
+ B_BE_B0_IMR_ERR_CMDPSR_TBLSZ | \
+ B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR | \
+ B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG)
+#define B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET (B_BE_B0_IMR_ERR_USRCTL_REINIT | \
+ B_BE_B0_IMR_ERR_USRCTL_NOINIT | \
+ B_BE_B0_IMR_ERR_CMDPSR_1STCMDERR | \
+ B_BE_B0_IMR_ERR_CMDPSR_CMDTYPE | \
+ B_BE_B0_IMR_ERR_CMDPSR_FRZTO | \
+ B_BE_B0_IMR_ERR_CMDPSR_TBLSZ | \
+ B_BE_B0_IMR_ERR_PRELD_RLSPKTSZERR | \
+ B_BE_B0_IMR_ERR_PRELD_ENTNUMCFG)
+
+#define R_BE_TXPKTCTL_B1_PRELD_CFG0 0x9F88
+#define B_BE_B1_PRELD_FEN BIT(31)
+#define B_BE_B1_PRELD_USEMAXSZ_MASK GENMASK(25, 16)
+#define B_BE_B1_PRELD_CAM_G1ENTNUM_MASK GENMASK(12, 8)
+#define B_BE_B1_PRELD_CAM_G0ENTNUM_MASK GENMASK(4, 0)
+
+#define R_BE_TXPKTCTL_B1_PRELD_CFG1 0x9F8C
+#define B_BE_B1_PRELD_NXT_TXENDWIN_MASK GENMASK(11, 8)
+#define B_BE_B1_PRELD_NXT_RSVMINSZ_MASK GENMASK(7, 0)
+
+#define R_BE_TXPKTCTL_B1_ERRFLAG_IMR 0x9FB8
+#define B_BE_B1_IMR_DBG_USRCTL_RLSBMPLEN BIT(25)
+#define B_BE_B1_IMR_DBG_USRCTL_RDNRLSCMD BIT(24)
+#define B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG BIT(17)
+#define B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR BIT(16)
+#define B_BE_B1_IMR_ERR_CMDPSR_TBLSZ BIT(11)
+#define B_BE_B1_IMR_ERR_CMDPSR_FRZTO BIT(10)
+#define B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE BIT(9)
+#define B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR BIT(8)
+#define B_BE_B1_IMR_ERR_USRCTL_NOINIT BIT(1)
+#define B_BE_B1_IMR_ERR_USRCTL_REINIT BIT(0)
+#define B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR (B_BE_B1_IMR_ERR_USRCTL_REINIT | \
+ B_BE_B1_IMR_ERR_USRCTL_NOINIT | \
+ B_BE_B1_IMR_DBG_USRCTL_RDNRLSCMD | \
+ B_BE_B1_IMR_DBG_USRCTL_RLSBMPLEN | \
+ B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR | \
+ B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE | \
+ B_BE_B1_IMR_ERR_CMDPSR_FRZTO | \
+ B_BE_B1_IMR_ERR_CMDPSR_TBLSZ | \
+ B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR | \
+ B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG)
+#define B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET (B_BE_B1_IMR_ERR_USRCTL_REINIT | \
+ B_BE_B1_IMR_ERR_USRCTL_NOINIT | \
+ B_BE_B1_IMR_ERR_CMDPSR_1STCMDERR | \
+ B_BE_B1_IMR_ERR_CMDPSR_CMDTYPE | \
+ B_BE_B1_IMR_ERR_CMDPSR_FRZTO | \
+ B_BE_B1_IMR_ERR_CMDPSR_TBLSZ | \
+ B_BE_B1_IMR_ERR_PRELD_RLSPKTSZERR | \
+ B_BE_B1_IMR_ERR_PRELD_ENTNUMCFG)
+
+#define R_BE_MLO_INIT_CTL 0xA114
+#define B_BE_MLO_TABLE_INIT_DONE BIT(31)
+#define B_BE_MLO_TABLE_CLR_DONE BIT(30)
+#define B_BE_MLO_TABLE_REINIT BIT(23)
+#define B_BE_MLO_TABLE_HW_FLAG_CLR BIT(22)
+
+#define R_BE_MLO_ERR_IDCT_IMR 0xA128
+#define B_BE_MLO_ERR_IDCT_IMR_0 BIT(31)
+#define B_BE_MLO_ERR_IDCT_IMR_1 BIT(30)
+#define B_BE_MLO_ERR_IDCT_IMR_2 BIT(29)
+#define B_BE_MLO_ERR_IDCT_IMR_3 BIT(28)
+#define B_BE_MLO_ERR_IDCT_IMR_CLR (B_BE_MLO_ERR_IDCT_IMR_2 | \
+ B_BE_MLO_ERR_IDCT_IMR_1 | \
+ B_BE_MLO_ERR_IDCT_IMR_0)
+#define B_BE_MLO_ERR_IDCT_IMR_SET (B_BE_MLO_ERR_IDCT_IMR_2 | \
+ B_BE_MLO_ERR_IDCT_IMR_1 | \
+ B_BE_MLO_ERR_IDCT_IMR_0)
+
+#define R_BE_MLO_ERR_IDCT_ISR 0xA12C
+#define B_BE_MLO_ISR_IDCT_0 BIT(31)
+#define B_BE_MLO_ISR_IDCT_1 BIT(30)
+#define B_BE_MLO_ISR_IDCT_2 BIT(29)
+#define B_BE_MLO_ISR_IDCT_3 BIT(28)
+
+#define R_BE_PLRLS_ERR_IMR 0xA218
+#define B_BE_PLRLS_CTL_FRZTO_IMR BIT(0)
+#define B_BE_PLRLS_ERR_IMR_CLR B_BE_PLRLS_CTL_FRZTO_IMR
+#define B_BE_PLRLS_ERR_IMR_SET B_BE_PLRLS_CTL_FRZTO_IMR
+
+#define R_BE_PLRLS_ERR_ISR 0xA21C
+#define B_BE_PLRLS_CTL_EVT03_ISR BIT(3)
+#define B_BE_PLRLS_CTL_EVT02_ISR BIT(2)
+#define B_BE_PLRLS_CTL_EVT01_ISR BIT(1)
+#define B_BE_PLRLS_CTL_FRZTO_ISR BIT(0)
+
+#define R_BE_SS_CTRL 0xA310
+#define B_BE_SS_INIT_DONE BIT(31)
+#define B_BE_WDE_STA_DIS BIT(30)
+#define B_BE_WARM_INIT BIT(29)
+#define B_BE_BAND_TRIG_EN BIT(28)
+#define B_BE_RMAC_REQ_DIS BIT(27)
+#define B_BE_DLYTX_SEL_MASK GENMASK(25, 24)
+#define B_BE_WMM3_SWITCH_MASK GENMASK(23, 22)
+#define B_BE_WMM2_SWITCH_MASK GENMASK(21, 20)
+#define B_BE_WMM1_SWITCH_MASK GENMASK(19, 18)
+#define B_BE_WMM0_SWITCH_MASK GENMASK(17, 16)
+#define B_BE_STA_OPTION_CR BIT(15)
+#define B_BE_EMLSR_STA_EMPTY_EN BIT(11)
+#define B_BE_MLO_HW_CHGLINK_EN BIT(10)
+#define B_BE_BAND1_TRIG_EN BIT(9)
+#define B_BE_RMAC1_REQ_DIS BIT(8)
+#define B_BE_MRT_SRAM_EN BIT(7)
+#define B_BE_MRT_INIT_EN BIT(6)
+#define B_BE_AVG_LENG_EN BIT(5)
+#define B_BE_AVG_INIT_EN BIT(4)
+#define B_BE_LENG_INIT_EN BIT(2)
+#define B_BE_PMPA_INIT_EN BIT(1)
+#define B_BE_SS_EN BIT(0)
+
+#define R_BE_INTERRUPT_MASK_REG 0xA3F0
+#define B_BE_PLE_B_PKTID_ERR_IMR BIT(2)
+#define B_BE_RPT_TIMEOUT_IMR BIT(1)
+#define B_BE_SEARCH_TIMEOUT_IMR BIT(0)
+#define B_BE_INTERRUPT_MASK_REG_CLR (B_BE_SEARCH_TIMEOUT_IMR | \
+ B_BE_RPT_TIMEOUT_IMR | \
+ B_BE_PLE_B_PKTID_ERR_IMR)
+#define B_BE_INTERRUPT_MASK_REG_SET (B_BE_SEARCH_TIMEOUT_IMR | \
+ B_BE_RPT_TIMEOUT_IMR | \
+ B_BE_PLE_B_PKTID_ERR_IMR)
+
+#define R_BE_INTERRUPT_STS_REG 0xA3F4
+#define B_BE_PLE_B_PKTID_ERR_ISR BIT(2)
+#define B_BE_RPT_TIMEOUT_ISR BIT(1)
+#define B_BE_SEARCH_TIMEOUT_ISR BIT(0)
+
+#define R_BE_HAXI_INIT_CFG1 0xB000
+#define B_BE_CFG_WD_PERIOD_IDLE_MASK GENMASK(31, 28)
+#define B_BE_CFG_WD_PERIOD_ACTIVE_MASK GENMASK(27, 24)
+#define B_BE_EN_RO_IDX_UPD_BY_IO BIT(19)
+#define B_BE_RST_KEEP_REG BIT(18)
+#define B_BE_FLUSH_HAXI_MST BIT(17)
+#define B_BE_SET_BDRAM_BOUND BIT(16)
+#define B_BE_ADDRINFO_ALIGN4B_EN BIT(15)
+#define B_BE_RXBD_DONE_MODE_MASK GENMASK(14, 13)
+#define B_BE_RXQ_RXBD_MODE_MASK GENMASK(12, 11)
+#define B_BE_DMA_MODE_MASK GENMASK(10, 8)
+#define S_BE_DMA_MOD_PCIE_NO_DATA_CPU 0x0
+#define S_BE_DMA_MOD_PCIE_DATA_CPU 0x1
+#define S_BE_DMA_MOD_USB 0x4
+#define S_BE_DMA_MOD_SDIO 0x6
+#define B_BE_STOP_AXI_MST BIT(7)
+#define B_BE_RXDMA_ALIGN64B_EN BIT(6)
+#define B_BE_RXDMA_EN BIT(5)
+#define B_BE_TXDMA_EN BIT(4)
+#define B_BE_MAX_RXDMA_MASK GENMASK(3, 2)
+#define B_BE_MAX_TXDMA_MASK GENMASK(1, 0)
+
+#define R_BE_HAXI_DMA_STOP1 0xB010
+#define B_BE_STOP_WPDMA BIT(31)
+#define B_BE_STOP_CH14 BIT(14)
+#define B_BE_STOP_CH13 BIT(13)
+#define B_BE_STOP_CH12 BIT(12)
+#define B_BE_STOP_CH11 BIT(11)
+#define B_BE_STOP_CH10 BIT(10)
+#define B_BE_STOP_CH9 BIT(9)
+#define B_BE_STOP_CH8 BIT(8)
+#define B_BE_STOP_CH7 BIT(7)
+#define B_BE_STOP_CH6 BIT(6)
+#define B_BE_STOP_CH5 BIT(5)
+#define B_BE_STOP_CH4 BIT(4)
+#define B_BE_STOP_CH3 BIT(3)
+#define B_BE_STOP_CH2 BIT(2)
+#define B_BE_STOP_CH1 BIT(1)
+#define B_BE_STOP_CH0 BIT(0)
+
+#define R_BE_HAXI_IDCT_MSK 0xB0B8
+#define B_BE_HAXI_RRESP_ERR_IDCT_MSK BIT(7)
+#define B_BE_HAXI_BRESP_ERR_IDCT_MSK BIT(6)
+#define B_BE_RXDMA_ERR_FLAG_IDCT_MSK BIT(5)
+#define B_BE_SET_FC_ERROR_FLAG_IDCT_MSK BIT(4)
+#define B_BE_TXBD_LEN0_ERR_IDCT_MSK BIT(3)
+#define B_BE_TXBD_4KBOUND_ERR_IDCT_MSK BIT(2)
+#define B_BE_RXMDA_STUCK_IDCT_MSK BIT(1)
+#define B_BE_TXMDA_STUCK_IDCT_MSK BIT(0)
+#define B_BE_HAXI_IDCT_MSK_CLR (B_BE_TXMDA_STUCK_IDCT_MSK | \
+ B_BE_RXMDA_STUCK_IDCT_MSK | \
+ B_BE_TXBD_LEN0_ERR_IDCT_MSK | \
+ B_BE_SET_FC_ERROR_FLAG_IDCT_MSK | \
+ B_BE_RXDMA_ERR_FLAG_IDCT_MSK | \
+ B_BE_HAXI_BRESP_ERR_IDCT_MSK | \
+ B_BE_HAXI_RRESP_ERR_IDCT_MSK)
+#define B_BE_HAXI_IDCT_MSK_SET (B_BE_TXMDA_STUCK_IDCT_MSK | \
+ B_BE_RXMDA_STUCK_IDCT_MSK | \
+ B_BE_TXBD_LEN0_ERR_IDCT_MSK | \
+ B_BE_SET_FC_ERROR_FLAG_IDCT_MSK | \
+ B_BE_RXDMA_ERR_FLAG_IDCT_MSK | \
+ B_BE_HAXI_BRESP_ERR_IDCT_MSK | \
+ B_BE_HAXI_RRESP_ERR_IDCT_MSK)
+
+#define R_BE_HAXI_IDCT 0xB0BC
+#define B_BE_HAXI_RRESP_ERR_IDCT BIT(7)
+#define B_BE_HAXI_BRESP_ERR_IDCT BIT(6)
+#define B_BE_RXDMA_ERR_FLAG_IDCT BIT(5)
+#define B_BE_SET_FC_ERROR_FLAG_IDCT BIT(4)
+#define B_BE__TXBD_LEN0_ERR_IDCT BIT(3)
+#define B_BE__TXBD_4KBOUND_ERR_IDCT BIT(2)
+#define B_BE_RXMDA_STUCK_IDCT BIT(1)
+#define B_BE_TXMDA_STUCK_IDCT BIT(0)
+
+#define R_BE_HCI_FC_CTRL 0xB700
+#define B_BE_WD_PAGE_MODE_MASK GENMASK(17, 16)
+#define B_BE_HCI_FC_CH14_FULL_COND_MASK GENMASK(15, 14)
+#define B_BE_HCI_FC_TWD_FULL_COND_MASK GENMASK(13, 12)
+#define B_BE_HCI_FC_CH12_FULL_COND_MASK GENMASK(11, 10)
+#define B_BE_HCI_FC_WP_CH811_FULL_COND_MASK GENMASK(9, 8)
+#define B_BE_HCI_FC_WP_CH07_FULL_COND_MASK GENMASK(7, 6)
+#define B_BE_HCI_FC_WD_FULL_COND_MASK GENMASK(5, 4)
+#define B_BE_HCI_FC_CH12_EN BIT(3)
+#define B_BE_HCI_FC_MODE_MASK GENMASK(2, 1)
+#define B_BE_HCI_FC_EN BIT(0)
+
+#define R_BE_CH_PAGE_CTRL 0xB704
+#define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16)
+#define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0)
+
+#define R_BE_PUB_PAGE_INFO3 0xB78C
+#define B_BE_G1_AVAL_PG_MASK GENMASK(28, 16)
+#define B_BE_G0_AVAL_PG_MASK GENMASK(12, 0)
+
+#define R_BE_PUB_PAGE_CTRL1 0xB790
+#define B_BE_PUBPG_G1_MASK GENMASK(28, 16)
+#define B_BE_PUBPG_G0_MASK GENMASK(12, 0)
+
+#define R_BE_PUB_PAGE_CTRL2 0xB794
+#define B_BE_PUBPG_ALL_MASK GENMASK(12, 0)
+
+#define R_BE_PUB_PAGE_INFO1 0xB79C
+#define B_BE_G1_USE_PG_MASK GENMASK(28, 16)
+#define B_BE_G0_USE_PG_MASK GENMASK(12, 0)
+
+#define R_BE_PUB_PAGE_INFO2 0xB7A0
+#define B_BE_PUB_AVAL_PG_MASK GENMASK(12, 0)
+
+#define R_BE_WP_PAGE_CTRL1 0xB7A4
+#define B_BE_PREC_PAGE_WP_CH811_MASK GENMASK(24, 16)
+#define B_BE_PREC_PAGE_WP_CH07_MASK GENMASK(8, 0)
+
+#define R_BE_WP_PAGE_CTRL2 0xB7A8
+#define B_BE_WP_THRD_MASK GENMASK(12, 0)
+
+#define R_BE_WP_PAGE_INFO1 0xB7AC
+#define B_BE_WP_AVAL_PG_MASK GENMASK(28, 16)
+
+#define R_BE_CMAC_SHARE_FUNC_EN 0x0E000
+#define B_BE_CMAC_SHARE_CRPRT BIT(31)
+#define B_BE_CMAC_SHARE_EN BIT(30)
+#define B_BE_FORCE_BTCOEX_REG_GCKEN BIT(24)
+#define B_BE_FORCE_CMAC_SHARE_COMMON_REG_GCKEN BIT(16)
+#define B_BE_FORCE_CMAC_SHARE_REG_GCKEN BIT(15)
+#define B_BE_RESPBA_EN BIT(2)
+#define B_BE_ADDRSRCH_EN BIT(1)
+#define B_BE_BTCOEX_EN BIT(0)
+
+#define R_BE_CMAC_SHARE_ACQCHK_CFG_0 0x0E010
+#define B_BE_ACQCHK_ERR_FLAG_MASK GENMASK(31, 24)
+#define B_BE_R_ACQCHK_ENTRY_IDX_SEL_MASK GENMASK(7, 4)
+#define B_BE_MACID_ACQ_GRP1_CLR_P BIT(3)
+#define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2)
+#define B_BE_R_MACID_ACQ_CHK_EN BIT(0)
+
#define R_BE_CMAC_FUNC_EN 0x10000
#define R_BE_CMAC_FUNC_EN_C1 0x14000
#define B_BE_CMAC_CRPRT BIT(31)
@@ -3772,6 +5854,138 @@
B_BE_CMAC_CRPRT | B_BE_TXTIME_EN | B_BE_RESP_PKTCTL_EN | \
B_BE_SIGB_EN)
+#define R_BE_CK_EN 0x10004
+#define R_BE_CK_EN_C1 0x14004
+#define B_BE_CMAC_CKEN BIT(30)
+#define B_BE_BCN_P1_P4_CKEN BIT(15)
+#define B_BE_BCN_P0MB1_15_CKEN BIT(14)
+#define B_BE_TXTIME_CKEN BIT(8)
+#define B_BE_RESP_PKTCTL_CKEN BIT(7)
+#define B_BE_SIGB_CKEN BIT(6)
+#define B_BE_PHYINTF_CKEN BIT(5)
+#define B_BE_CMAC_DMA_CKEN BIT(4)
+#define B_BE_PTCLTOP_CKEN BIT(3)
+#define B_BE_SCHEDULER_CKEN BIT(2)
+#define B_BE_TMAC_CKEN BIT(1)
+#define B_BE_RMAC_CKEN BIT(0)
+#define B_BE_CK_EN_SET (B_BE_CMAC_CKEN | B_BE_PHYINTF_CKEN | B_BE_CMAC_DMA_CKEN | \
+ B_BE_PTCLTOP_CKEN | B_BE_SCHEDULER_CKEN | B_BE_TMAC_CKEN | \
+ B_BE_RMAC_CKEN | B_BE_TXTIME_CKEN | B_BE_RESP_PKTCTL_CKEN | \
+ B_BE_SIGB_CKEN)
+
+#define R_BE_TX_SUB_BAND_VALUE 0x10088
+#define R_BE_TX_SUB_BAND_VALUE_C1 0x14088
+#define B_BE_PRI20_BITMAP_MASK GENMASK(31, 16)
+#define BE_PRI20_BITMAP_MAX 15
+#define B_BE_TXSB_160M_MASK GENMASK(15, 12)
+#define S_BE_TXSB_160M_0 0
+#define S_BE_TXSB_160M_1 1
+#define B_BE_TXSB_80M_MASK GENMASK(11, 8)
+#define S_BE_TXSB_80M_0 0
+#define S_BE_TXSB_80M_2 2
+#define S_BE_TXSB_80M_4 4
+#define B_BE_TXSB_40M_MASK GENMASK(7, 4)
+#define S_BE_TXSB_40M_0 0
+#define S_BE_TXSB_40M_1 1
+#define S_BE_TXSB_40M_4 4
+#define B_BE_TXSB_20M_MASK GENMASK(3, 0)
+#define S_BE_TXSB_20M_8 8
+#define S_BE_TXSB_20M_4 4
+#define S_BE_TXSB_20M_2 2
+
+#define R_BE_PTCL_RRSR0 0x1008C
+#define R_BE_PTCL_RRSR0_C1 0x1408C
+#define B_BE_RRSR_HE_MASK GENMASK(31, 24)
+#define B_BE_RRSR_VHT_MASK GENMASK(23, 16)
+#define B_BE_RRSR_HT_MASK GENMASK(15, 8)
+#define B_BE_RRSR_OFDM_MASK GENMASK(7, 0)
+
+#define R_BE_PTCL_RRSR1 0x10090
+#define R_BE_PTCL_RRSR1_C1 0x14090
+#define B_BE_RRSR_EHT_MASK GENMASK(23, 16)
+#define B_BE_RRSR_RATE_EN_MASK GENMASK(12, 8)
+#define B_BE_RSC_MASK GENMASK(7, 6)
+#define B_BE_RRSR_CCK_MASK GENMASK(3, 0)
+
+#define R_BE_CMAC_ERR_IMR 0x10160
+#define R_BE_CMAC_ERR_IMR_C1 0x14160
+#define B_BE_CMAC_FW_ERR_IDCT_EN BIT(16)
+#define B_BE_PTCL_TX_IDLETO_IDCT_EN BIT(9)
+#define B_BE_WMAC_RX_IDLETO_IDCT_EN BIT(8)
+#define B_BE_WMAC_TX_ERR_IND_EN BIT(7)
+#define B_BE_WMAC_RX_ERR_IND_EN BIT(6)
+#define B_BE_TXPWR_CTRL_ERR_IND_EN BIT(5)
+#define B_BE_PHYINTF_ERR_IND_EN BIT(4)
+#define B_BE_DMA_TOP_ERR_IND_EN BIT(3)
+#define B_BE_RESP_PKTCTL_ERR_IND_EN BIT(2)
+#define B_BE_PTCL_TOP_ERR_IND_EN BIT(1)
+#define B_BE_SCHEDULE_TOP_ERR_IND_EN BIT(0)
+
+#define R_BE_CMAC_ERR_ISR 0x10164
+#define R_BE_CMAC_ERR_ISR_C1 0x14164
+#define B_BE_CMAC_FW_ERR_IDCT BIT(16)
+#define B_BE_PTCL_TX_IDLETO_IDCT BIT(9)
+#define B_BE_WMAC_RX_IDLETO_IDCT BIT(8)
+#define B_BE_WMAC_TX_ERR_IND BIT(7)
+#define B_BE_WMAC_RX_ERR_IND BIT(6)
+#define B_BE_TXPWR_CTRL_ERR_IND BIT(5)
+#define B_BE_PHYINTF_ERR_IND BIT(4)
+#define B_BE_DMA_TOP_ERR_IND BIT(3)
+#define B_BE_RESP_PKTCTL_ERR_IDCT BIT(2)
+#define B_BE_PTCL_TOP_ERR_IND BIT(1)
+#define B_BE_SCHEDULE_TOP_ERR_IND BIT(0)
+
+#define R_BE_SER_L0_DBG_CNT 0x10170
+#define R_BE_SER_L0_DBG_CNT_C1 0x14170
+#define B_BE_SER_L0_PHYINTF_CNT_MASK GENMASK(31, 24)
+#define B_BE_SER_L0_DMA_CNT_MASK GENMASK(23, 16)
+#define B_BE_SER_L0_PTCL_CNT_MASK GENMASK(15, 8)
+#define B_BE_SER_L0_SCH_CNT_MASK GENMASK(7, 0)
+
+#define R_BE_SER_L0_DBG_CNT1 0x10174
+#define R_BE_SER_L0_DBG_CNT1_C1 0x14174
+#define B_BE_SER_L0_TMAC_COUNTER_MASK GENMASK(23, 16)
+#define B_BE_SER_L0_RMAC_COUNTER_MASK GENMASK(15, 8)
+#define B_BE_SER_L0_TXPWR_COUNTER_MASK GENMASK(7, 0)
+
+#define R_BE_SER_L0_DBG_CNT2 0x10178
+#define R_BE_SER_L0_DBG_CNT2_C1 0x14178
+
+#define R_BE_SER_L0_DBG_CNT3 0x1017C
+#define R_BE_SER_L0_DBG_CNT3_C1 0x1417C
+#define B_BE_SER_L0_SUBMODULE_BIT31_CNT BIT(31)
+#define B_BE_SER_L0_SUBMODULE_BIT30_CNT BIT(30)
+#define B_BE_SER_L0_SUBMODULE_BIT29_CNT BIT(29)
+#define B_BE_SER_L0_SUBMODULE_BIT28_CNT BIT(28)
+#define B_BE_SER_L0_SUBMODULE_BIT27_CNT BIT(27)
+#define B_BE_SER_L0_SUBMODULE_BIT26_CNT BIT(26)
+#define B_BE_SER_L0_SUBMODULE_BIT25_CNT BIT(25)
+#define B_BE_SER_L0_SUBMODULE_BIT24_CNT BIT(24)
+#define B_BE_SER_L0_SUBMODULE_BIT23_CNT BIT(23)
+#define B_BE_SER_L0_SUBMODULE_BIT22_CNT BIT(22)
+#define B_BE_SER_L0_SUBMODULE_BIT21_CNT BIT(21)
+#define B_BE_SER_L0_SUBMODULE_BIT20_CNT BIT(20)
+#define B_BE_SER_L0_SUBMODULE_BIT19_CNT BIT(19)
+#define B_BE_SER_L0_SUBMODULE_BIT18_CNT BIT(18)
+#define B_BE_SER_L0_SUBMODULE_BIT17_CNT BIT(17)
+#define B_BE_SER_L0_SUBMODULE_BIT16_CNT BIT(16)
+#define B_BE_SER_L0_SUBMODULE_BIT15_CNT BIT(15)
+#define B_BE_SER_L0_SUBMODULE_BIT14_CNT BIT(14)
+#define B_BE_SER_L0_SUBMODULE_BIT13_CNT BIT(13)
+#define B_BE_SER_L0_SUBMODULE_BIT12_CNT BIT(12)
+#define B_BE_SER_L0_SUBMODULE_BIT11_CNT BIT(11)
+#define B_BE_SER_L0_SUBMODULE_BIT10_CNT BIT(10)
+#define B_BE_SER_L0_SUBMODULE_BIT9_CNT BIT(9)
+#define B_BE_SER_L0_SUBMODULE_BIT8_CNT BIT(8)
+#define B_BE_SER_L0_SUBMODULE_BIT7_CNT BIT(7)
+#define B_BE_SER_L0_SUBMODULE_BIT6_CNT BIT(6)
+#define B_BE_SER_L0_SUBMODULE_BIT5_CNT BIT(5)
+#define B_BE_SER_L0_SUBMODULE_BIT4_CNT BIT(4)
+#define B_BE_SER_L0_SUBMODULE_BIT3_CNT BIT(3)
+#define B_BE_SER_L0_SUBMODULE_BIT2_CNT BIT(2)
+#define B_BE_SER_L0_SUBMODULE_BIT1_CNT BIT(1)
+#define B_BE_SER_L0_SUBMODULE_BIT0_CNT BIT(0)
+
#define R_BE_PORT_0_TSF_SYNC 0x102A0
#define R_BE_PORT_0_TSF_SYNC_C1 0x142A0
#define B_BE_P0_SYNC_NOW_P BIT(30)
@@ -3780,6 +5994,55 @@
#define B_BE_P0_SYNC_PORT_SRC_SEL_MASK GENMASK(26, 24)
#define B_BE_P0_TSFTR_SYNC_OFFSET_MASK GENMASK(18, 0)
+#define R_BE_EDCA_BCNQ_PARAM 0x10324
+#define R_BE_EDCA_BCNQ_PARAM_C1 0x14324
+#define B_BE_BCNQ_CW_MASK GENMASK(31, 24)
+#define B_BE_BCNQ_AIFS_MASK GENMASK(23, 16)
+#define BCN_IFS_25US 0x19
+#define B_BE_PIFS_MASK GENMASK(15, 8)
+#define B_BE_FORCE_BCN_IFS_MASK GENMASK(7, 0)
+
+#define R_BE_PREBKF_CFG_0 0x10338
+#define R_BE_PREBKF_CFG_0_C1 0x14338
+#define B_BE_100NS_TIME_MASK GENMASK(28, 24)
+#define B_BE_RX_AIR_END_TIME_MASK GENMASK(22, 16)
+#define B_BE_MACTX_LATENCY_MASK GENMASK(10, 8)
+#define B_BE_PREBKF_TIME_MASK GENMASK(4, 0)
+
+#define R_BE_CCA_CFG_0 0x10340
+#define R_BE_CCA_CFG_0_C1 0x14340
+#define B_BE_R_SIFS_AGGR_TIME_V1_MASK GENMASK(31, 24)
+#define B_BE_EDCCA_SEC160_EN BIT(23)
+#define B_BE_EDCCA_SEC80_EN BIT(22)
+#define B_BE_EDCCA_SEC40_EN BIT(21)
+#define B_BE_EDCCA_SEC20_EN BIT(20)
+#define B_BE_SEC160_EN BIT(19)
+#define B_BE_CCA_BITMAP_EN BIT(18)
+#define B_BE_TXPKTCTL_RST_EDCA_EN BIT(17)
+#define B_BE_WMAC_RST_EDCA_EN BIT(16)
+#define B_BE_TXFAIL_BRK_TXOP_EN BIT(11)
+#define B_BE_EDCCA_PER20_BITMAP_SIFS_EN BIT(10)
+#define B_BE_NO_GNT_WL_BRK_TXOP_EN BIT(9)
+#define B_BE_NAV_BRK_TXOP_EN BIT(8)
+#define B_BE_TX_NAV_EN BIT(7)
+#define B_BE_BCN_IGNORE_EDCCA BIT(6)
+#define B_BE_NO_GNT_WL_EN BIT(5)
+#define B_BE_EDCCA_EN BIT(4)
+#define B_BE_SEC80_EN BIT(3)
+#define B_BE_SEC40_EN BIT(2)
+#define B_BE_SEC20_EN BIT(1)
+#define B_BE_CCA_EN BIT(0)
+
+#define R_BE_CTN_CFG_0 0x1034C
+#define R_BE_CTN_CFG_0_C1 0x1434C
+#define B_BE_OTHER_LINK_BKF_BLK_TX_THD_MASK GENMASK(30, 24)
+#define B_BE_CCK_SIFS_COMP_MASK GENMASK(22, 16)
+#define B_BE_PIFS_TIMEUNIT_MASK GENMASK(15, 14)
+#define B_BE_PREBKF_TIME_NONAC_MASK GENMASK(12, 8)
+#define B_BE_SR_TX_EN BIT(2)
+#define B_BE_NAV_BLK_MGQ BIT(1)
+#define B_BE_NAV_BLK_HGQ BIT(0)
+
#define R_BE_MUEDCA_BE_PARAM_0 0x10350
#define R_BE_MUEDCA_BK_PARAM_0 0x10354
#define R_BE_MUEDCA_VI_PARAM_0 0x10358
@@ -3792,6 +6055,74 @@
#define B_BE_SET_MUEDCATIMER_TF_0 BIT(4)
#define B_BE_MUEDCA_EN_0 BIT(0)
+#define R_BE_TB_CHK_CCA_NAV 0x103AC
+#define R_BE_TB_CHK_CCA_NAV_C1 0x143AC
+#define B_BE_TB_CHK_TX_NAV BIT(15)
+#define B_BE_TB_CHK_INTRA_NAV BIT(14)
+#define B_BE_TB_CHK_BASIC_NAV BIT(13)
+#define B_BE_TB_CHK_NO_GNT_WL BIT(12)
+#define B_BE_TB_CHK_EDCCA_S160 BIT(11)
+#define B_BE_TB_CHK_EDCCA_S80 BIT(10)
+#define B_BE_TB_CHK_EDCCA_S40 BIT(9)
+#define B_BE_TB_CHK_EDCCA_S20 BIT(8)
+#define B_BE_TB_CHK_CCA_S160 BIT(7)
+#define B_BE_TB_CHK_CCA_S80 BIT(6)
+#define B_BE_TB_CHK_CCA_S40 BIT(5)
+#define B_BE_TB_CHK_CCA_S20 BIT(4)
+#define B_BE_TB_CHK_EDCCA_BITMAP BIT(3)
+#define B_BE_TB_CHK_CCA_BITMAP BIT(2)
+#define B_BE_TB_CHK_EDCCA_P20 BIT(1)
+#define B_BE_TB_CHK_CCA_P20 BIT(0)
+
+#define R_BE_HE_SIFS_CHK_CCA_NAV 0x103B4
+#define R_BE_HE_SIFS_CHK_CCA_NAV_C1 0x143B4
+#define B_BE_HE_SIFS_CHK_TX_NAV BIT(15)
+#define B_BE_HE_SIFS_CHK_INTRA_NAV BIT(14)
+#define B_BE_HE_SIFS_CHK_BASIC_NAV BIT(13)
+#define B_BE_HE_SIFS_CHK_NO_GNT_WL BIT(12)
+#define B_BE_HE_SIFS_CHK_EDCCA_S160 BIT(11)
+#define B_BE_HE_SIFS_CHK_EDCCA_S80 BIT(10)
+#define B_BE_HE_SIFS_CHK_EDCCA_S40 BIT(9)
+#define B_BE_HE_SIFS_CHK_EDCCA_S20 BIT(8)
+#define B_BE_HE_SIFS_CHK_CCA_S160 BIT(7)
+#define B_BE_HE_SIFS_CHK_CCA_S80 BIT(6)
+#define B_BE_HE_SIFS_CHK_CCA_S40 BIT(5)
+#define B_BE_HE_SIFS_CHK_CCA_S20 BIT(4)
+#define B_BE_HE_SIFS_CHK_EDCCA_BITMAP BIT(3)
+#define B_BE_HE_SIFS_CHK_CCA_BITMAP BIT(2)
+#define B_BE_HE_SIFS_CHK_EDCCA_P20 BIT(1)
+#define B_BE_HE_SIFS_CHK_CCA_P20 BIT(0)
+
+#define R_BE_HE_CTN_CHK_CCA_NAV 0x103C4
+#define R_BE_HE_CTN_CHK_CCA_NAV_C1 0x143C4
+#define B_BE_HE_CTN_CHK_TX_NAV BIT(15)
+#define B_BE_HE_CTN_CHK_INTRA_NAV BIT(14)
+#define B_BE_HE_CTN_CHK_BASIC_NAV BIT(13)
+#define B_BE_HE_CTN_CHK_NO_GNT_WL BIT(12)
+#define B_BE_HE_CTN_CHK_EDCCA_S160 BIT(11)
+#define B_BE_HE_CTN_CHK_EDCCA_S80 BIT(10)
+#define B_BE_HE_CTN_CHK_EDCCA_S40 BIT(9)
+#define B_BE_HE_CTN_CHK_EDCCA_S20 BIT(8)
+#define B_BE_HE_CTN_CHK_CCA_S160 BIT(7)
+#define B_BE_HE_CTN_CHK_CCA_S80 BIT(6)
+#define B_BE_HE_CTN_CHK_CCA_S40 BIT(5)
+#define B_BE_HE_CTN_CHK_CCA_S20 BIT(4)
+#define B_BE_HE_CTN_CHK_EDCCA_BITMAP BIT(3)
+#define B_BE_HE_CTN_CHK_CCA_BITMAP BIT(2)
+#define B_BE_HE_CTN_CHK_EDCCA_P20 BIT(1)
+#define B_BE_HE_CTN_CHK_CCA_P20 BIT(0)
+
+#define R_BE_SCHEDULE_ERR_IMR 0x103E8
+#define R_BE_SCHEDULE_ERR_IMR_C1 0x143E8
+#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0)
+#define B_BE_SCHEDULE_ERR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN
+#define B_BE_SCHEDULE_ERR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN
+
+#define R_BE_SCHEDULE_ERR_ISR 0x103EC
+#define R_BE_SCHEDULE_ERR_ISR_C1 0x143EC
+#define B_BE_SORT_NON_IDLE_ERR_INT BIT(1)
+#define B_BE_FSM_TIMEOUT_ERR_INT BIT(0)
+
#define R_BE_PORT_CFG_P0 0x10400
#define R_BE_PORT_CFG_P0_C1 0x14400
#define B_BE_BCN_ERLY_SORT_EN_P0 BIT(18)
@@ -3906,12 +6237,51 @@
#define R_BE_PORT_HGQ_WINDOW_CFG 0x105A0
#define R_BE_PORT_HGQ_WINDOW_CFG_C1 0x145A0
+#define R_BE_PTCL_COMMON_SETTING_0 0x10800
+#define R_BE_PTCL_COMMON_SETTING_0_C1 0x14800
+#define B_BE_PCIE_MODE_MASK GENMASK(15, 14)
+#define B_BE_CPUMGQ_LIFETIME_EN BIT(8)
+#define B_BE_MGQ_LIFETIME_EN BIT(7)
+#define B_BE_LIFETIME_EN BIT(6)
+#define B_BE_DIS_PTCL_CLK_GATING BIT(5)
+#define B_BE_PTCL_TRIGGER_SS_EN_UL BIT(4)
+#define B_BE_PTCL_TRIGGER_SS_EN_1 BIT(3)
+#define B_BE_PTCL_TRIGGER_SS_EN_0 BIT(2)
+#define B_BE_CMAC_TX_MODE_1 BIT(1)
+#define B_BE_CMAC_TX_MODE_0 BIT(0)
+
+#define R_BE_TB_PPDU_CTRL 0x1080C
+#define R_BE_TB_PPDU_CTRL_C1 0x1480C
+#define B_BE_TB_PPDU_BK_DIS BIT(15)
+#define B_BE_TB_PPDU_BE_DIS BIT(14)
+#define B_BE_TB_PPDU_VI_DIS BIT(13)
+#define B_BE_TB_PPDU_VO_DIS BIT(12)
+#define B_BE_QOSNULL_UPD_MUEDCA_EN BIT(3)
+#define B_BE_TB_BYPASS_TXPWR BIT(2)
+#define B_BE_SW_PREFER_AC_MASK GENMASK(1, 0)
+
+#define R_BE_AMPDU_AGG_LIMIT 0x10810
+#define R_BE_AMPDU_AGG_LIMIT_C1 0x14810
+#define B_BE_AMPDU_MAX_TIME_MASK GENMASK(31, 24)
+#define AMPDU_MAX_TIME 0x9E
+#define B_BE_RA_TRY_RATE_AGG_LMT_MASK GENMASK(23, 16)
+#define B_BE_RTS_MAX_AGG_NUM_MASK GENMASK(15, 8)
+#define B_BE_MAX_AGG_NUM_MASK GENMASK(7, 0)
+
#define R_BE_AGG_LEN_HT_0 0x10814
#define R_BE_AGG_LEN_HT_0_C1 0x14814
#define B_BE_AMPDU_MAX_LEN_HT_MASK GENMASK(31, 16)
#define B_BE_RTS_TXTIME_TH_MASK GENMASK(15, 8)
#define B_BE_RTS_LEN_TH_MASK GENMASK(7, 0)
+#define R_BE_SIFS_SETTING 0x10824
+#define R_BE_SIFS_SETTING_C1 0x14824
+#define B_BE_HW_CTS2SELF_PKT_LEN_TH_MASK GENMASK(31, 24)
+#define B_BE_HW_CTS2SELF_PKT_LEN_TH_TWW_MASK GENMASK(23, 18)
+#define B_BE_HW_CTS2SELF_EN BIT(16)
+#define B_BE_SPEC_SIFS_OFDM_PTCL_MASK GENMASK(15, 8)
+#define B_BE_SPEC_SIFS_CCK_PTCL_MASK GENMASK(7, 0)
+
#define R_BE_MBSSID_DROP_0 0x1083C
#define R_BE_MBSSID_DROP_0_C1 0x1483C
#define B_BE_GI_LTF_FB_SEL BIT(30)
@@ -3930,6 +6300,375 @@
#define R_BE_PTCL_BSS_COLOR_1_C1 0x148A4
#define B_BE_BSS_COLOB_BE_PORT_4_MASK GENMASK(5, 0)
+#define R_BE_PTCL_IMR_2 0x108B8
+#define R_BE_PTCL_IMR_2_C1 0x148B8
+#define B_BE_NO_TRX_TIMEOUT_IMR BIT(1)
+#define B_BE_TX_IDLE_TIMEOUT_IMR BIT(0)
+#define B_BE_PTCL_IMR_2_CLR B_BE_TX_IDLE_TIMEOUT_IMR
+#define B_BE_PTCL_IMR_2_SET 0
+
+#define R_BE_PTCL_IMR0 0x108C0
+#define R_BE_PTCL_IMR0_C1 0x148C0
+#define B_BE_PTCL_ERROR_FLAG_IMR BIT(31)
+#define B_BE_FSM1_TIMEOUT_ERR_INT_EN BIT(1)
+#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0)
+#define B_BE_PTCL_IMR0_CLR (B_BE_FSM_TIMEOUT_ERR_INT_EN | \
+ B_BE_FSM1_TIMEOUT_ERR_INT_EN | \
+ B_BE_PTCL_ERROR_FLAG_IMR)
+#define B_BE_PTCL_IMR0_SET (B_BE_FSM_TIMEOUT_ERR_INT_EN | \
+ B_BE_FSM1_TIMEOUT_ERR_INT_EN | \
+ B_BE_PTCL_ERROR_FLAG_IMR)
+
+#define R_BE_PTCL_ISR0 0x108C4
+#define R_BE_PTCL_ISR0_C1 0x148C4
+#define B_BE_PTCL_ERROR_FLAG_ISR BIT(31)
+#define B_BE_FSM1_TIMEOUT_ERR BIT(1)
+#define B_BE_FSM_TIMEOUT_ERR BIT(0)
+
+#define R_BE_PTCL_IMR1 0x108C8
+#define R_BE_PTCL_IMR1_C1 0x148C8
+#define B_BE_F2PCMD_PKTID_IMR BIT(30)
+#define B_BE_F2PCMD_RD_PKTID_IMR BIT(29)
+#define B_BE_F2PCMD_ASSIGN_PKTID_IMR BIT(28)
+#define B_BE_F2PCMD_USER_ALLC_IMR BIT(27)
+#define B_BE_RX_SPF_U0_PKTID_IMR BIT(26)
+#define B_BE_TX_SPF_U1_PKTID_IMR BIT(25)
+#define B_BE_TX_SPF_U2_PKTID_IMR BIT(24)
+#define B_BE_TX_SPF_U3_PKTID_IMR BIT(23)
+#define B_BE_TX_RECORD_PKTID_IMR BIT(22)
+#define B_BE_TWTSP_QSEL_IMR BIT(14)
+#define B_BE_F2P_RLS_CTN_SEL_IMR BIT(13)
+#define B_BE_BCNQ_ORDER_IMR BIT(12)
+#define B_BE_Q_PKTID_IMR BIT(11)
+#define B_BE_D_PKTID_IMR BIT(10)
+#define B_BE_TXPRT_FULL_DROP_IMR BIT(9)
+#define B_BE_F2PCMDRPT_FULL_DROP_IMR BIT(8)
+#define B_BE_PTCL_IMR1_CLR (B_BE_F2PCMDRPT_FULL_DROP_IMR | \
+ B_BE_TXPRT_FULL_DROP_IMR | \
+ B_BE_D_PKTID_IMR | \
+ B_BE_Q_PKTID_IMR | \
+ B_BE_BCNQ_ORDER_IMR | \
+ B_BE_F2P_RLS_CTN_SEL_IMR | \
+ B_BE_TWTSP_QSEL_IMR | \
+ B_BE_TX_RECORD_PKTID_IMR | \
+ B_BE_TX_SPF_U3_PKTID_IMR | \
+ B_BE_TX_SPF_U2_PKTID_IMR | \
+ B_BE_TX_SPF_U1_PKTID_IMR | \
+ B_BE_RX_SPF_U0_PKTID_IMR | \
+ B_BE_F2PCMD_USER_ALLC_IMR | \
+ B_BE_F2PCMD_ASSIGN_PKTID_IMR | \
+ B_BE_F2PCMD_RD_PKTID_IMR | \
+ B_BE_F2PCMD_PKTID_IMR)
+#define B_BE_PTCL_IMR1_SET B_BE_F2PCMD_USER_ALLC_IMR
+
+#define R_BE_PTCL_ISR1 0x108CC
+#define R_BE_PTCL_ISR1_C1 0x148CC
+#define B_BE_F2PCMD_PKTID_ERR BIT(30)
+#define B_BE_F2PCMD_RD_PKTID_ERR BIT(29)
+#define B_BE_F2PCMD_ASSIGN_PKTID_ERR BIT(28)
+#define B_BE_F2PCMD_USER_ALLC_ERR BIT(27)
+#define B_BE_RX_SPF_U0_PKTID_ERR BIT(26)
+#define B_BE_TX_SPF_U1_PKTID_ERR BIT(25)
+#define B_BE_TX_SPF_U2_PKTID_ERR BIT(24)
+#define B_BE_TX_SPF_U3_PKTID_ERR BIT(23)
+#define B_BE_TX_RECORD_PKTID_ERR BIT(22)
+#define B_BE_TWTSP_QSEL_ERR BIT(14)
+#define B_BE_F2P_RLS_CTN_SEL_ERR BIT(13)
+#define B_BE_BCNQ_ORDER_ERR BIT(12)
+#define B_BE_Q_PKTID_ERR BIT(11)
+#define B_BE_D_PKTID_ERR BIT(10)
+#define B_BE_TXPRT_FULL_DROP_ERR BIT(9)
+#define B_BE_F2PCMDRPT_FULL_DROP_ERR BIT(8)
+
+#define R_BE_PTCL_FSM_MON 0x108E8
+#define R_BE_PTCL_FSM_MON_C1 0x148E8
+#define B_BE_PTCL_FSM2_TO_MODE BIT(30)
+#define B_BE_PTCL_FSM2_TO_THR_MASK GENMASK(29, 24)
+#define B_BE_PTCL_FSM1_TO_MODE BIT(22)
+#define B_BE_PTCL_FSM1_TO_THR_MASK GENMASK(21, 16)
+#define B_BE_PTCL_FSM0_TO_MODE BIT(14)
+#define B_BE_PTCL_FSM0_TO_THR_MASK GENMASK(13, 8)
+#define B_BE_PTCL_TX_ARB_TO_MODE BIT(6)
+#define B_BE_PTCL_TX_ARB_TO_THR_MASK GENMASK(5, 0)
+
+#define R_BE_PTCL_TX_CTN_SEL 0x108EC
+#define R_BE_PTCL_TX_CTN_SEL_C1 0x148EC
+#define B_BE_PTCL_TXOP_STAT BIT(8)
+#define B_BE_PTCL_BUSY BIT(7)
+#define B_BE_PTCL_DROP BIT(5)
+#define B_BE_PTCL_TX_QUEUE_IDX_MASK GENMASK(4, 0)
+
+#define R_BE_RX_ERROR_FLAG 0x10C00
+#define R_BE_RX_ERROR_FLAG_C1 0x14C00
+#define B_BE_RX_CSI_NOT_RELEASE_ERROR BIT(31)
+#define B_BE_RX_GET_NULL_PKT_ERROR BIT(30)
+#define B_BE_RX_RU0_FSM_HANG_ERROR BIT(29)
+#define B_BE_RX_RU1_FSM_HANG_ERROR BIT(28)
+#define B_BE_RX_RU2_FSM_HANG_ERROR BIT(27)
+#define B_BE_RX_RU3_FSM_HANG_ERROR BIT(26)
+#define B_BE_RX_RU4_FSM_HANG_ERROR BIT(25)
+#define B_BE_RX_RU5_FSM_HANG_ERROR BIT(24)
+#define B_BE_RX_RU6_FSM_HANG_ERROR BIT(23)
+#define B_BE_RX_RU7_FSM_HANG_ERROR BIT(22)
+#define B_BE_RX_RXSTS_FSM_HANG_ERROR BIT(21)
+#define B_BE_RX_CSI_FSM_HANG_ERROR BIT(20)
+#define B_BE_RX_TXRPT_FSM_HANG_ERROR BIT(19)
+#define B_BE_RX_F2PCMD_FSM_HANG_ERROR BIT(18)
+#define B_BE_RX_RU0_ZERO_LENGTH_ERROR BIT(17)
+#define B_BE_RX_RU1_ZERO_LENGTH_ERROR BIT(16)
+#define B_BE_RX_RU2_ZERO_LENGTH_ERROR BIT(15)
+#define B_BE_RX_RU3_ZERO_LENGTH_ERROR BIT(14)
+#define B_BE_RX_RU4_ZERO_LENGTH_ERROR BIT(13)
+#define B_BE_RX_RU5_ZERO_LENGTH_ERROR BIT(12)
+#define B_BE_RX_RU6_ZERO_LENGTH_ERROR BIT(11)
+#define B_BE_RX_RU7_ZERO_LENGTH_ERROR BIT(10)
+#define B_BE_RX_RXSTS_ZERO_LENGTH_ERROR BIT(9)
+#define B_BE_RX_CSI_ZERO_LENGTH_ERROR BIT(8)
+#define B_BE_PLE_DATA_OPT_FSM_HANG BIT(7)
+#define B_BE_PLE_RXDATA_REQUEST_BUFFER_FSM_HANG BIT(6)
+#define B_BE_PLE_TXRPT_REQUEST_BUFFER_FSM_HANG BIT(5)
+#define B_BE_PLE_WD_OPT_FSM_HANG BIT(4)
+#define B_BE_PLE_ENQ_FSM_HANG BIT(3)
+#define B_BE_RXDATA_ENQUE_ORDER_ERROR BIT(2)
+#define B_BE_RXSTS_ENQUE_ORDER_ERROR BIT(1)
+#define B_BE_RX_CSI_PKT_NUM_ERROR BIT(0)
+
+#define R_BE_RX_ERROR_FLAG_IMR 0x10C04
+#define R_BE_RX_ERROR_FLAG_IMR_C1 0x14C04
+#define B_BE_RX_CSI_NOT_RELEASE_ERROR_IMR BIT(31)
+#define B_BE_RX_GET_NULL_PKT_ERROR_IMR BIT(30)
+#define B_BE_RX_RU0_FSM_HANG_ERROR_IMR BIT(29)
+#define B_BE_RX_RU1_FSM_HANG_ERROR_IMR BIT(28)
+#define B_BE_RX_RU2_FSM_HANG_ERROR_IMR BIT(27)
+#define B_BE_RX_RU3_FSM_HANG_ERROR_IMR BIT(26)
+#define B_BE_RX_RU4_FSM_HANG_ERROR_IMR BIT(25)
+#define B_BE_RX_RU5_FSM_HANG_ERROR_IMR BIT(24)
+#define B_BE_RX_RU6_FSM_HANG_ERROR_IMR BIT(23)
+#define B_BE_RX_RU7_FSM_HANG_ERROR_IMR BIT(22)
+#define B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR BIT(21)
+#define B_BE_RX_CSI_FSM_HANG_ERROR_IMR BIT(20)
+#define B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR BIT(19)
+#define B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR BIT(18)
+#define B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR BIT(17)
+#define B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR BIT(16)
+#define B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR BIT(15)
+#define B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR BIT(14)
+#define B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR BIT(13)
+#define B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR BIT(12)
+#define B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR BIT(11)
+#define B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR BIT(10)
+#define B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR BIT(9)
+#define B_BE_RX_CSI_ZERO_LENGTH_ERROR_IMR BIT(8)
+#define B_BE_PLE_DATA_OPT_FSM_HANG_IMR BIT(7)
+#define B_BE_PLE_RXDATA_REQUEST_BUFFER_FSM_HANG_IMR BIT(6)
+#define B_BE_PLE_TXRPT_REQUEST_BUFFER_FSM_HANG_IMR BIT(5)
+#define B_BE_PLE_WD_OPT_FSM_HANG_IMR BIT(4)
+#define B_BE_PLE_ENQ_FSM_HANG_IMR BIT(3)
+#define B_BE_RXDATA_ENQUE_ORDER_ERROR_IMR BIT(2)
+#define B_BE_RXSTS_ENQUE_ORDER_ERROR_IMR BIT(1)
+#define B_BE_RX_CSI_PKT_NUM_ERROR_IMR BIT(0)
+#define B_BE_RX_ERROR_FLAG_IMR_CLR (B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_CSI_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU7_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU6_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU5_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU4_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU3_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU2_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_GET_NULL_PKT_ERROR_IMR)
+#define B_BE_RX_ERROR_FLAG_IMR_SET (B_BE_RX_RXSTS_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU7_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU6_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU5_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU4_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU3_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU2_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU1_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU0_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_F2PCMD_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_TXRPT_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_CSI_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RXSTS_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU7_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU6_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU5_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU4_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU3_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU2_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU1_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU0_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_GET_NULL_PKT_ERROR_IMR)
+
+#define R_BE_RX_CTRL_1 0x10C0C
+#define R_BE_RX_CTRL_1_C1 0x14C0C
+#define B_BE_RXDMA_TXRPT_QUEUE_ID_SW_MASK GENMASK(30, 25)
+#define B_BE_RXDMA_F2PCMDRPT_QUEUE_ID_SW_MASK GENMASK(23, 18)
+#define B_BE_RXDMA_TXRPT_PORT_ID_SW_MASK GENMASK(17, 14)
+#define B_BE_RXDMA_F2PCMDRPT_PORT_ID_SW_MASK GENMASK(13, 10)
+#define B_BE_DBG_SEL_MASK GENMASK(1, 0)
+#define WLCPU_RXCH2_QID 0xA
+
+#define R_BE_TX_ERROR_FLAG 0x10C6C
+#define R_BE_TX_ERROR_FLAG_C1 0x14C6C
+#define B_BE_TX_RU0_FSM_HANG_ERROR BIT(31)
+#define B_BE_TX_RU1_FSM_HANG_ERROR BIT(30)
+#define B_BE_TX_RU2_FSM_HANG_ERROR BIT(29)
+#define B_BE_TX_RU3_FSM_HANG_ERROR BIT(28)
+#define B_BE_TX_RU4_FSM_HANG_ERROR BIT(27)
+#define B_BE_TX_RU5_FSM_HANG_ERROR BIT(26)
+#define B_BE_TX_RU6_FSM_HANG_ERROR BIT(25)
+#define B_BE_TX_RU7_FSM_HANG_ERROR BIT(24)
+#define B_BE_TX_RU8_FSM_HANG_ERROR BIT(23)
+#define B_BE_TX_RU9_FSM_HANG_ERROR BIT(22)
+#define B_BE_TX_RU10_FSM_HANG_ERROR BIT(21)
+#define B_BE_TX_RU11_FSM_HANG_ERROR BIT(20)
+#define B_BE_TX_RU12_FSM_HANG_ERROR BIT(19)
+#define B_BE_TX_RU13_FSM_HANG_ERROR BIT(18)
+#define B_BE_TX_RU14_FSM_HANG_ERROR BIT(17)
+#define B_BE_TX_RU15_FSM_HANG_ERROR BIT(16)
+#define B_BE_TX_CSI_FSM_HANG_ERROR BIT(15)
+#define B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR BIT(14)
+
+#define R_BE_TX_ERROR_FLAG_IMR 0x10C70
+#define R_BE_TX_ERROR_FLAG_IMR_C1 0x14C70
+#define B_BE_TX_RU0_FSM_HANG_ERROR_IMR BIT(31)
+#define B_BE_TX_RU1_FSM_HANG_ERROR_IMR BIT(30)
+#define B_BE_TX_RU2_FSM_HANG_ERROR_IMR BIT(29)
+#define B_BE_TX_RU3_FSM_HANG_ERROR_IMR BIT(28)
+#define B_BE_TX_RU4_FSM_HANG_ERROR_IMR BIT(27)
+#define B_BE_TX_RU5_FSM_HANG_ERROR_IMR BIT(26)
+#define B_BE_TX_RU6_FSM_HANG_ERROR_IMR BIT(25)
+#define B_BE_TX_RU7_FSM_HANG_ERROR_IMR BIT(24)
+#define B_BE_TX_RU8_FSM_HANG_ERROR_IMR BIT(23)
+#define B_BE_TX_RU9_FSM_HANG_ERROR_IMR BIT(22)
+#define B_BE_TX_RU10_FSM_HANG_ERROR_IMR BIT(21)
+#define B_BE_TX_RU11_FSM_HANG_ERROR_IMR BIT(20)
+#define B_BE_TX_RU12_FSM_HANG_ERROR_IMR BIT(19)
+#define B_BE_TX_RU13_FSM_HANG_ERROR_IMR BIT(18)
+#define B_BE_TX_RU14_FSM_HANG_ERROR_IMR BIT(17)
+#define B_BE_TX_RU15_FSM_HANG_ERROR_IMR BIT(16)
+#define B_BE_TX_CSI_FSM_HANG_ERROR_IMR BIT(15)
+#define B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR BIT(14)
+#define B_BE_TX_ERROR_FLAG_IMR_CLR (B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_CSI_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU15_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU14_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU13_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU12_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU11_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU10_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU9_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU8_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU7_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU6_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU5_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU4_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU3_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU2_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU0_FSM_HANG_ERROR_IMR)
+#define B_BE_TX_ERROR_FLAG_IMR_SET (B_BE_TX_WD_PLD_ID_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_CSI_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU15_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU14_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU13_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU12_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU11_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU10_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU9_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU8_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU7_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU6_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU5_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU4_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU3_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU2_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU1_FSM_HANG_ERROR_IMR | \
+ B_BE_TX_RU0_FSM_HANG_ERROR_IMR)
+
+#define R_BE_RX_ERROR_FLAG_1 0x10C84
+#define R_BE_RX_ERROR_FLAG_1_C1 0x14C84
+#define B_BE_RX_RU8_FSM_HANG_ERROR BIT(29)
+#define B_BE_RX_RU9_FSM_HANG_ERROR BIT(28)
+#define B_BE_RX_RU10_FSM_HANG_ERROR BIT(27)
+#define B_BE_RX_RU11_FSM_HANG_ERROR BIT(26)
+#define B_BE_RX_RU12_FSM_HANG_ERROR BIT(25)
+#define B_BE_RX_RU13_FSM_HANG_ERROR BIT(24)
+#define B_BE_RX_RU14_FSM_HANG_ERROR BIT(23)
+#define B_BE_RX_RU15_FSM_HANG_ERROR BIT(22)
+#define B_BE_RX_RU8_ZERO_LENGTH_ERROR BIT(17)
+#define B_BE_RX_RU9_ZERO_LENGTH_ERROR BIT(16)
+#define B_BE_RX_RU10_ZERO_LENGTH_ERROR BIT(15)
+#define B_BE_RX_RU11_ZERO_LENGTH_ERROR BIT(14)
+#define B_BE_RX_RU12_ZERO_LENGTH_ERROR BIT(13)
+#define B_BE_RX_RU13_ZERO_LENGTH_ERROR BIT(12)
+#define B_BE_RX_RU14_ZERO_LENGTH_ERROR BIT(11)
+#define B_BE_RX_RU15_ZERO_LENGTH_ERROR BIT(10)
+
+#define R_BE_RX_ERROR_FLAG_IMR_1 0x10C88
+#define R_BE_RX_ERROR_FLAG_IMR_1_C1 0x14C88
+#define B_BE_RX_RU8_FSM_HANG_ERROR_IMR BIT(29)
+#define B_BE_RX_RU9_FSM_HANG_ERROR_IMR BIT(28)
+#define B_BE_RX_RU10_FSM_HANG_ERROR_IMR BIT(27)
+#define B_BE_RX_RU11_FSM_HANG_ERROR_IMR BIT(26)
+#define B_BE_RX_RU12_FSM_HANG_ERROR_IMR BIT(25)
+#define B_BE_RX_RU13_FSM_HANG_ERROR_IMR BIT(24)
+#define B_BE_RX_RU14_FSM_HANG_ERROR_IMR BIT(23)
+#define B_BE_RX_RU15_FSM_HANG_ERROR_IMR BIT(22)
+#define B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR BIT(17)
+#define B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR BIT(16)
+#define B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR BIT(15)
+#define B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR BIT(14)
+#define B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR BIT(13)
+#define B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR BIT(12)
+#define B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR BIT(11)
+#define B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR BIT(10)
+#define B_BE_TX_ERROR_FLAG_IMR_1_CLR (B_BE_RX_RU8_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU9_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU10_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU11_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU12_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU13_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU14_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU15_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR)
+#define B_BE_TX_ERROR_FLAG_IMR_1_SET (B_BE_RX_RU8_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU9_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU10_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU11_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU12_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU13_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU14_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU15_FSM_HANG_ERROR_IMR | \
+ B_BE_RX_RU8_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU9_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU10_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU11_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU12_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU13_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU14_ZERO_LENGTH_ERROR_IMR | \
+ B_BE_RX_RU15_ZERO_LENGTH_ERROR_IMR)
+
#define R_BE_WMTX_MOREDATA_TSFT_STMP_CTL 0x10E08
#define R_BE_WMTX_MOREDATA_TSFT_STMP_CTL_C1 0x14E08
#define B_BE_TSFT_OFS_MASK GENMASK(31, 16)
@@ -3937,6 +6676,173 @@
#define B_BE_UPD_HGQMD BIT(1)
#define B_BE_UPD_TIMIE BIT(0)
+#define R_BE_WMTX_TCR_BE_4 0x10E2C
+#define R_BE_WMTX_TCR_BE_4_C1 0x14E2C
+#define B_BE_UL_EHT_MUMIMO_LTF_MODE BIT(30)
+#define B_BE_UL_HE_MUMIMO_LTF_MODE BIT(29)
+#define B_BE_EHT_HE_PPDU_4XLTF_ZLD_USTIMER_MASK GENMASK(28, 24)
+#define B_BE_EHT_HE_PPDU_2XLTF_ZLD_USTIMER_MASK GENMASK(20, 16)
+#define B_BE_NON_LEGACY_PPDU_ZLD_USTIMER_MASK GENMASK(12, 8)
+#define B_BE_LEGACY_PPDU_ZLD_USTIMER_MASK GENMASK(4, 0)
+
+#define R_BE_RSP_CHK_SIG 0x11000
+#define R_BE_RSP_CHK_SIG_C1 0x15000
+#define B_BE_RSP_STATIC_RTS_CHK_SERV_BW_EN BIT(30)
+#define B_BE_RSP_TBPPDU_CHK_PWR BIT(29)
+#define B_BE_RESP_PAIR_MACID_LEN_EN BIT(25)
+#define B_BE_RESP_TX_ABORT_TEST_EN BIT(24)
+#define B_BE_RESP_ER_SU_RU106_EN BIT(23)
+#define B_BE_RESP_ER_SU_EN BIT(22)
+#define B_BE_TXDATA_END_PS_OPT BIT(18)
+#define B_BE_CHECK_SOUNDING_SEQ BIT(17)
+#define B_BE_RXBA_IGNOREA2 BIT(16)
+#define B_BE_ACKTO_CCK_MASK GENMASK(15, 8)
+#define B_BE_ACKTO_MASK GENMASK(8, 0)
+
+#define R_BE_TRXPTCL_RESP_0 0x11004
+#define R_BE_TRXPTCL_RESP_0_C1 0x15004
+#define B_BE_WMAC_RESP_STBC_EN BIT(31)
+#define B_BE_WMAC_RXFTM_TXACK_SB BIT(30)
+#define B_BE_WMAC_RXFTM_TXACKBWEQ BIT(29)
+#define B_BE_RESP_TB_CHK_TXTIME BIT(24)
+#define B_BE_RSP_CHK_CCA BIT(23)
+#define B_BE_WMAC_LDPC_EN BIT(22)
+#define B_BE_WMAC_SGIEN BIT(21)
+#define B_BE_WMAC_SPLCPEN BIT(20)
+#define B_BE_RESP_EHT_MCS15_REF BIT(19)
+#define B_BE_RESP_EHT_MCS14_REF BIT(18)
+#define B_BE_WMAC_BESP_EARLY_TXBA BIT(17)
+#define B_BE_WMAC_MBA_DUR_FORCE BIT(16)
+#define B_BE_WMAC_SPEC_SIFS_OFDM_MASK GENMASK(15, 8)
+#define WMAC_SPEC_SIFS_OFDM_1115E 0x11
+#define B_BE_WMAC_SPEC_SIFS_CCK_MASK GENMASK(7, 0)
+
+#define R_BE_TRXPTCL_RESP_1 0x11008
+#define R_BE_TRXPTCL_RESP_1_C1 0x15008
+#define B_BE_WMAC_RESP_SR_MODE_EN BIT(31)
+#define B_BE_FTM_RRSR_RATE_EN_MASK GENMASK(28, 24)
+#define B_BE_NESS_MASK GENMASK(23, 22)
+#define B_BE_WMAC_RESP_DOPPLEB_BE_EN BIT(21)
+#define B_BE_WMAC_RESP_DCM_EN BIT(20)
+#define B_BE_WMAC_CLR_ABORT_RESP_TX_CNT BIT(15)
+#define B_BE_WMAC_RESP_REF_RATE_SEL BIT(12)
+#define B_BE_WMAC_RESP_REF_RATE_MASK GENMASK(11, 0)
+
+#define R_BE_MAC_LOOPBACK 0x11020
+#define R_BE_MAC_LOOPBACK_C1 0x15020
+#define B_BE_MACLBK_DIS_GCLK BIT(30)
+#define B_BE_MACLBK_STS_EN BIT(29)
+#define B_BE_MACLBK_RDY_PERIOD_MASK GENMASK(28, 17)
+#define B_BE_MACLBK_PLCP_DLY_MASK GENMASK(16, 8)
+#define S_BE_MACLBK_PLCP_DLY_DEF 0x28
+#define B_BE_MACLBK_RDY_NUM_MASK GENMASK(7, 3)
+#define B_BE_MACLBK_EN BIT(0)
+
+#define R_BE_WMAC_NAV_CTL 0x11080
+#define R_BE_WMAC_NAV_CTL_C1 0x15080
+#define B_BE_WMAC_NAV_UPPER_EN BIT(26)
+#define B_BE_WMAC_0P125US_TIMER_MASK GENMASK(25, 18)
+#define B_BE_WMAC_PLCP_UP_NAV_EN BIT(17)
+#define B_BE_WMAC_TF_UP_NAV_EN BIT(16)
+#define B_BE_WMAC_NAV_UPPER_MASK GENMASK(15, 8)
+#define NAV_25MS 0xC4
+#define B_BE_WMAC_RTS_RST_DUR_MASK GENMASK(7, 0)
+
+#define R_BE_RXTRIG_TEST_USER_2 0x110B0
+#define R_BE_RXTRIG_TEST_USER_2_C1 0x150B0
+#define B_BE_RXTRIG_MACID_MASK GENMASK(31, 24)
+#define B_BE_RXTRIG_RU26_DIS BIT(21)
+#define B_BE_RXTRIG_FCSCHK_EN BIT(20)
+#define B_BE_RXTRIG_PORT_SEL_MASK GENMASK(19, 17)
+#define B_BE_RXTRIG_EN BIT(16)
+#define B_BE_RXTRIG_USERINFO_2_MASK GENMASK(15, 0)
+
+#define R_BE_TRXPTCL_ERROR_INDICA_MASK 0x110BC
+#define R_BE_TRXPTCL_ERROR_INDICA_MASK_C1 0x150BC
+#define B_BE_WMAC_FTM_TIMEOUT_MODE BIT(30)
+#define B_BE_WMAC_FTM_TIMEOUT_THR_MASK GENMASK(29, 24)
+#define B_BE_WMAC_MODE BIT(22)
+#define B_BE_WMAC_TIMETOUT_THR_MASK GENMASK(21, 16)
+#define B_BE_RMAC_BFMER BIT(9)
+#define B_BE_RMAC_FTM BIT(8)
+#define B_BE_RMAC_CSI BIT(7)
+#define B_BE_TMAC_MIMO_CTRL BIT(6)
+#define B_BE_TMAC_RXTB BIT(5)
+#define B_BE_TMAC_HWSIGB_GEN BIT(4)
+#define B_BE_TMAC_TXPLCP BIT(3)
+#define B_BE_TMAC_RESP BIT(2)
+#define B_BE_TMAC_TXCTL BIT(1)
+#define B_BE_TMAC_MACTX BIT(0)
+#define B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR (B_BE_TMAC_MACTX | \
+ B_BE_TMAC_TXCTL | \
+ B_BE_TMAC_RESP | \
+ B_BE_TMAC_TXPLCP | \
+ B_BE_TMAC_HWSIGB_GEN | \
+ B_BE_TMAC_RXTB | \
+ B_BE_TMAC_MIMO_CTRL | \
+ B_BE_RMAC_CSI | \
+ B_BE_RMAC_FTM | \
+ B_BE_RMAC_BFMER)
+#define B_BE_TRXPTCL_ERROR_INDICA_MASK_SET (B_BE_TMAC_MACTX | \
+ B_BE_TMAC_TXCTL | \
+ B_BE_TMAC_RESP | \
+ B_BE_TMAC_TXPLCP | \
+ B_BE_TMAC_HWSIGB_GEN | \
+ B_BE_TMAC_RXTB | \
+ B_BE_TMAC_MIMO_CTRL | \
+ B_BE_RMAC_CSI | \
+ B_BE_RMAC_FTM | \
+ B_BE_RMAC_BFMER)
+
+#define R_BE_TRXPTCL_ERROR_INDICA 0x110C0
+#define R_BE_TRXPTCL_ERROR_INDICA_C1 0x150C0
+#define B_BE_BFMER_ERR_FLAG BIT(9)
+#define B_BE_FTM_ERROR_FLAG_CLR BIT(8)
+#define B_BE_CSI_ERROR_FLAG_CLR BIT(7)
+#define B_BE_MIMOCTRL_ERROR_FLAG_CLR BIT(6)
+#define B_BE_RXTB_ERROR_FLAG_CLR BIT(5)
+#define B_BE_HWSIGB_GEN_ERROR_FLAG_CLR BIT(4)
+#define B_BE_TXPLCP_ERROR_FLAG_CLR BIT(3)
+#define B_BE_RESP_ERROR_FLAG_CLR BIT(2)
+#define B_BE_TXCTL_ERROR_FLAG_CLR BIT(1)
+#define B_BE_MACTX_ERROR_FLAG_CLR BIT(0)
+
+#define R_BE_DBGSEL_TRXPTCL 0x110F4
+#define R_BE_DBGSEL_TRXPTCL_C1 0x150F4
+#define B_BE_WMAC_CHNSTS_STATE_MASK GENMASK(19, 16)
+#define B_BE_DBGSEL_TRIGCMD_SEL_MASK GENMASK(11, 8)
+#define B_BE_DBGSEL_TRXPTCL_MASK GENMASK(7, 0)
+
+#define R_BE_PHYINFO_ERR_IMR_V1 0x110F8
+#define R_BE_PHYINFO_ERR_IMR_V1_C1 0x150F8
+#define B_BE_PHYINTF_RXTB_WIDTH_MASK GENMASK(31, 30)
+#define B_BE_PHYINTF_RXTB_EN_PHASE_MASK GENMASK(29, 28)
+#define B_BE_PHYINTF_MIMO_WIDTH_MASK GENMASK(27, 26)
+#define B_BE_PHYINTF_MIMO_EN_PHASE_MASK GENMASK(25, 24)
+#define B_BE_PHYINTF_TIMEOUT_THR_V1_MASK GENMASK(21, 16)
+#define B_BE_CSI_ON_TIMEOUT_EN BIT(5)
+#define B_BE_STS_ON_TIMEOUT_EN BIT(4)
+#define B_BE_DATA_ON_TIMEOUT_EN BIT(3)
+#define B_BE_OFDM_CCA_TIMEOUT_EN BIT(2)
+#define B_BE_CCK_CCA_TIMEOUT_EN BIT(1)
+#define B_BE_PHY_TXON_TIMEOUT_EN BIT(0)
+#define B_BE_PHYINFO_ERR_IMR_V1_CLR (B_BE_PHY_TXON_TIMEOUT_EN | \
+ B_BE_CCK_CCA_TIMEOUT_EN | \
+ B_BE_OFDM_CCA_TIMEOUT_EN | \
+ B_BE_DATA_ON_TIMEOUT_EN | \
+ B_BE_STS_ON_TIMEOUT_EN | \
+ B_BE_CSI_ON_TIMEOUT_EN)
+#define B_BE_PHYINFO_ERR_IMR_V1_SET 0
+
+#define R_BE_PHYINFO_ERR_ISR 0x110FC
+#define R_BE_PHYINFO_ERR_ISR_C1 0x150FC
+#define B_BE_CSI_ON_TIMEOUT_ERR BIT(5)
+#define B_BE_STS_ON_TIMEOUT_ERR BIT(4)
+#define B_BE_DATA_ON_TIMEOUT_ERR BIT(3)
+#define B_BE_OFDM_CCA_TIMEOUT_ERR BIT(2)
+#define B_BE_CCK_CCA_TIMEOUT_ERR BIT(1)
+#define B_BE_PHY_TXON_TIMEOUT_ERR BIT(0)
+
#define R_BE_BFMEE_RESP_OPTION 0x11180
#define R_BE_BFMEE_RESP_OPTION_C1 0x15180
#define B_BE_BFMEE_CSI_SEC_TYPE_SH 20
@@ -3992,6 +6898,103 @@
#define B_BE_BFMEE_HT_CSI_RATE_MASK GENMASK(7, 0)
#define CSI_INIT_RATE_EHT 0x3
+#define R_BE_WMAC_ACK_BA_RESP_LEGACY 0x11200
+#define R_BE_WMAC_ACK_BA_RESP_LEGACY_C1 0x15200
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_NSTR BIT(16)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_TX_NAV BIT(15)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_INTRA_NAV BIT(14)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_BASIC_NAV BIT(13)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_BTCCA BIT(12)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA160 BIT(11)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA80 BIT(10)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA40 BIT(9)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_EDCCA20 BIT(8)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA_PER20_BMP BIT(7)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_CCA_PER20_BMP BIT(6)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA160 BIT(5)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA80 BIT(4)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA40 BIT(3)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_SEC_CCA20 BIT(2)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_EDCCA BIT(1)
+#define B_BE_ACK_BA_RESP_LEGACY_CHK_CCA BIT(0)
+
+#define R_BE_WMAC_ACK_BA_RESP_HE 0x11204
+#define R_BE_WMAC_ACK_BA_RESP_HE_C1 0x15204
+#define B_BE_ACK_BA_RESP_HE_CHK_NSTR BIT(16)
+#define B_BE_ACK_BA_RESP_HE_CHK_TX_NAV BIT(15)
+#define B_BE_ACK_BA_RESP_HE_CHK_INTRA_NAV BIT(14)
+#define B_BE_ACK_BA_RESP_HE_CHK_BASIC_NAV BIT(13)
+#define B_BE_ACK_BA_RESP_HE_CHK_BTCCA BIT(12)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA160 BIT(11)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA80 BIT(10)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA40 BIT(9)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_EDCCA20 BIT(8)
+#define B_BE_ACK_BA_RESP_HE_CHK_EDCCA_PER20_BMP BIT(7)
+#define B_BE_ACK_BA_RESP_HE_CHK_CCA_PER20_BMP BIT(6)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA160 BIT(5)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA80 BIT(4)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA40 BIT(3)
+#define B_BE_ACK_BA_RESP_HE_CHK_SEC_CCA20 BIT(2)
+#define B_BE_ACK_BA_RESP_HE_CHK_EDCCA BIT(1)
+#define B_BE_ACK_BA_RESP_HE_CHK_CCA BIT(0)
+
+#define R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC 0x11208
+#define R_BE_WMAC_ACK_BA_RESP_EHT_LEG_PUNC_C1 0x15208
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_NSTR BIT(16)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_TX_NAV BIT(15)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_INTRA_NAV BIT(14)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_BASIC_NAV BIT(13)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_BTCCA BIT(12)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA160 BIT(11)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA80 BIT(10)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA40 BIT(9)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_EDCCA20 BIT(8)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA_PER20_BMP BIT(7)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_CCA_PER20_BMP BIT(6)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA160 BIT(5)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA80 BIT(4)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA40 BIT(3)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_SEC_CCA20 BIT(2)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_EDCCA BIT(1)
+#define B_BE_ACK_BA_EHT_LEG_PUNC_CHK_CCA BIT(0)
+
+#define R_BE_RCR 0x11400
+#define R_BE_RCR_C1 0x15400
+#define B_BE_BUSY_CHKSN BIT(15)
+#define B_BE_DYN_CHEN BIT(14)
+#define B_BE_AUTO_RST BIT(13)
+#define B_BE_TIMER_SEL BIT(12)
+#define B_BE_STOP_RX_IN BIT(11)
+#define B_BE_PSR_RDY_CHKDIS BIT(10)
+#define B_BE_DRV_INFO_SZ_MASK GENMASK(9, 8)
+#define B_BE_HDR_CNV_SZ_MASK GENMASK(7, 6)
+#define B_BE_PHY_RPT_SZ_MASK GENMASK(5, 4)
+#define B_BE_CH_EN BIT(0)
+
+#define R_BE_DLK_PROTECT_CTL 0x11402
+#define R_BE_DLK_PROTECT_CTL_C1 0x15402
+#define B_BE_RX_DLK_CCA_TIME_MASK GENMASK(15, 8)
+#define TRXCFG_RMAC_CCA_TO 32
+#define B_BE_RX_DLK_DATA_TIME_MASK GENMASK(7, 4)
+#define TRXCFG_RMAC_DATA_TO 15
+#define B_BE_RX_DLK_RST_FSM BIT(3)
+#define B_BE_RX_DLK_RST_SKIPDMA BIT(2)
+#define B_BE_RX_DLK_RST_EN BIT(1)
+#define B_BE_RX_DLK_INT_EN BIT(0)
+
+#define R_BE_PLCP_HDR_FLTR 0x11404
+#define R_BE_PLCP_HDR_FLTR_C1 0x15404
+#define B_BE_PLCP_RXFA_RESET_TYPE_MASK GENMASK(15, 12)
+#define B_BE_PLCP_RXFA_RESET_EN BIT(11)
+#define B_BE_DIS_CHK_MIN_LEN BIT(8)
+#define B_BE_HE_SIGB_CRC_CHK BIT(6)
+#define B_BE_VHT_MU_SIGB_CRC_CHK BIT(5)
+#define B_BE_VHT_SU_SIGB_CRC_CHK BIT(4)
+#define B_BE_SIGA_CRC_CHK BIT(3)
+#define B_BE_LSIG_PARITY_CHK_EN BIT(2)
+#define B_BE_CCK_SIG_CHK BIT(1)
+#define B_BE_CCK_CRC_CHK BIT(0)
+
#define R_BE_RX_FLTR_OPT 0x11420
#define R_BE_RX_FLTR_OPT_C1 0x15420
#define B_BE_UID_FILTER_MASK GENMASK(31, 24)
@@ -4011,12 +7014,168 @@
#define B_BE_A_A1_MATCH BIT(1)
#define B_BE_SNIFFER_MODE BIT(0)
+#define R_BE_CTRL_FLTR 0x11424
+#define R_BE_CTRL_FLTR_C1 0x15424
+#define B_BE_CTRL_STYPE_MASK GENMASK(15, 0)
+#define RX_FLTR_FRAME_DROP_BE 0x0000
+#define RX_FLTR_FRAME_ACCEPT_BE 0xFFFF
+
+#define R_BE_MGNT_FLTR 0x11428
+#define R_BE_MGNT_FLTR_C1 0x15428
+#define B_BE_MGNT_STYPE_MASK GENMASK(15, 0)
+
+#define R_BE_DATA_FLTR 0x1142C
+#define R_BE_DATA_FLTR_C1 0x1542C
+#define B_BE_DATA_STYPE_MASK GENMASK(15, 0)
+
+#define R_BE_ADDR_CAM_CTRL 0x11434
+#define R_BE_ADDR_CAM_CTRL_C1 0x15434
+#define B_BE_ADDR_CAM_RANGE_MASK GENMASK(23, 16)
+#define ADDR_CAM_SERCH_RANGE 0x7f
+#define B_BE_ADDR_CAM_CMPLIMT_MASK GENMASK(15, 12)
+#define B_BE_ADDR_CAM_IORST BIT(10)
+#define B_BE_DIS_ADDR_CLK_GATED BIT(9)
+#define B_BE_ADDR_CAM_CLR BIT(8)
+#define B_BE_ADDR_CAM_A2_B0_CHK BIT(2)
+#define B_BE_ADDR_CAM_SRCH_PERPKT BIT(1)
+#define B_BE_ADDR_CAM_EN BIT(0)
+
+#define R_BE_RESPBA_CAM_CTRL 0x1143C
+#define R_BE_RESPBA_CAM_CTRL_C1 0x1543C
+#define B_BE_BACAM_SKIP_ALL_QOSNULL BIT(24)
+#define B_BE_BACAM_STD_SSN_SEL BIT(20)
+#define B_BE_BACAM_TEMP_SZ_MASK GENMASK(17, 16)
+#define B_BE_BACAM_RST_IDX_MASK GENMASK(15, 8)
+#define B_BE_BACAM_SHIFT_POLL BIT(7)
+#define B_BE_BACAM_IORST BIT(6)
+#define B_BE_BACAM_GCK_DIS BIT(5)
+#define B_BE_COMPL_VAL BIT(3)
+#define B_BE_SSN_SEL BIT(2)
+#define B_BE_BACAM_RST_MASK GENMASK(1, 0)
+#define S_BE_BACAM_RST_DONE 0
+#define S_BE_BACAM_RST_ENT 1
+#define S_BE_BACAM_RST_ALL 2
+
+#define R_BE_RX_SR_CTRL 0x1144A
+#define R_BE_RX_SR_CTRL_C1 0x1544A
+#define B_BE_SR_OP_MODE_MASK GENMASK(5, 4)
+#define B_BE_SRG_CHK_EN BIT(2)
+#define B_BE_SR_CTRL_PLCP_EN BIT(1)
+#define B_BE_SR_EN BIT(0)
+
#define R_BE_CSIRPT_OPTION 0x11464
#define R_BE_CSIRPT_OPTION_C1 0x15464
#define B_BE_CSIPRT_EHTSU_AID_EN BIT(26)
#define B_BE_CSIPRT_HESU_AID_EN BIT(25)
#define B_BE_CSIPRT_VHTSU_AID_EN BIT(24)
+#define R_BE_RX_ERR_ISR 0x114F4
+#define R_BE_RX_ERR_ISR_C1 0x154F4
+#define B_BE_RX_ERR_TRIG_ACT_TO BIT(9)
+#define B_BE_RX_ERR_STS_ACT_TO BIT(8)
+#define B_BE_RX_ERR_CSI_ACT_TO BIT(7)
+#define B_BE_RX_ERR_ACT_TO BIT(6)
+#define B_BE_CSI_DATAON_ASSERT_TO BIT(5)
+#define B_BE_DATAON_ASSERT_TO BIT(4)
+#define B_BE_CCA_ASSERT_TO BIT(3)
+#define B_BE_RX_ERR_DMA_TO BIT(2)
+#define B_BE_RX_ERR_DATA_TO BIT(1)
+#define B_BE_RX_ERR_CCA_TO BIT(0)
+
+#define R_BE_RX_ERR_IMR 0x114F8
+#define R_BE_RX_ERR_IMR_C1 0x154F8
+#define B_BE_RX_ERR_TRIG_ACT_TO_MSK BIT(9)
+#define B_BE_RX_ERR_STS_ACT_TO_MSK BIT(8)
+#define B_BE_RX_ERR_CSI_ACT_TO_MSK BIT(7)
+#define B_BE_RX_ERR_ACT_TO_MSK BIT(6)
+#define B_BE_CSI_DATAON_ASSERT_TO_MSK BIT(5)
+#define B_BE_DATAON_ASSERT_TO_MSK BIT(4)
+#define B_BE_CCA_ASSERT_TO_MSK BIT(3)
+#define B_BE_RX_ERR_DMA_TO_MSK BIT(2)
+#define B_BE_RX_ERR_DATA_TO_MSK BIT(1)
+#define B_BE_RX_ERR_CCA_TO_MSK BIT(0)
+#define B_BE_RX_ERR_IMR_CLR (B_BE_RX_ERR_CCA_TO_MSK | \
+ B_BE_RX_ERR_DATA_TO_MSK | \
+ B_BE_RX_ERR_DMA_TO_MSK | \
+ B_BE_CCA_ASSERT_TO_MSK | \
+ B_BE_DATAON_ASSERT_TO_MSK | \
+ B_BE_CSI_DATAON_ASSERT_TO_MSK | \
+ B_BE_RX_ERR_ACT_TO_MSK | \
+ B_BE_RX_ERR_CSI_ACT_TO_MSK | \
+ B_BE_RX_ERR_STS_ACT_TO_MSK | \
+ B_BE_RX_ERR_TRIG_ACT_TO_MSK)
+#define B_BE_RX_ERR_IMR_SET (B_BE_RX_ERR_ACT_TO_MSK | \
+ B_BE_RX_ERR_STS_ACT_TO_MSK | \
+ B_BE_RX_ERR_TRIG_ACT_TO_MSK)
+
+#define R_BE_RX_PLCP_EXT_OPTION_1 0x11514
+#define R_BE_RX_PLCP_EXT_OPTION_1_C1 0x15514
+#define B_BE_PLCP_CLOSE_RX_UNSPUUORT BIT(19)
+#define B_BE_PLCP_CLOSE_RX_BB_BRK BIT(18)
+#define B_BE_PLCP_CLOSE_RX_PSDU_PRES BIT(17)
+#define B_BE_PLCP_CLOSE_RX_NDP BIT(16)
+#define B_BE_PLCP_NSS_SRC BIT(11)
+#define B_BE_PLCP_DOPPLEB_BE_SRC BIT(10)
+#define B_BE_PLCP_STBC_SRC BIT(9)
+#define B_BE_PLCP_SU_PSDU_LEN_SRC BIT(8)
+#define B_BE_PLCP_RXSB_SRC BIT(7)
+#define B_BE_PLCP_BW_SRC_MASK GENMASK(6, 5)
+#define B_BE_PLCP_GILTF_SRC BIT(4)
+#define B_BE_PLCP_NSTS_SRC BIT(3)
+#define B_BE_PLCP_MCS_SRC BIT(2)
+#define B_BE_PLCP_CH20_WIDATA_SRC BIT(1)
+#define B_BE_PLCP_PPDU_TYPE_SRC BIT(0)
+
+#define R_BE_RESP_CSI_RESERVED_PAGE 0x11810
+#define R_BE_RESP_CSI_RESERVED_PAGE_C1 0x15810
+#define B_BE_CSI_RESERVED_PAGE_NUM_MASK GENMASK(27, 16)
+#define B_BE_CSI_RESERVED_START_PAGE_MASK GENMASK(11, 0)
+
+#define R_BE_RESP_IMR 0x11884
+#define R_BE_RESP_IMR_C1 0x15884
+#define B_BE_RESP_TBL_FLAG_ERR_ISR_EN BIT(17)
+#define B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN BIT(16)
+#define B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN BIT(15)
+#define B_BE_RESP_TOO_MANY_PLD_ERR_ISR_EN BIT(14)
+#define B_BE_RESP_TXDMA_READ_DATA_ERR_ISR_EN BIT(13)
+#define B_BE_RESP_PLDID_RDY_ERR_ISR_EN BIT(12)
+#define B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN BIT(11)
+#define B_BE_RESP_RXDMA_WRPTR_INVLD_ERR_ISR_EN BIT(10)
+#define B_BE_RESP_RXDMA_REQ_INVLD_ERR_ISR_EN BIT(9)
+#define B_BE_RESP_RXDMA_REQ_MACID_ERR_ISR_EN BIT(8)
+#define B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN BIT(6)
+#define B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN BIT(5)
+#define B_BE_RESP_TXCMD_TBL_ERR_ISR_EN BIT(4)
+#define B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN BIT(3)
+#define B_BE_RESP_INITCMD_RESERVD_PAGE_ABORT_ERR_ISR_EN BIT(2)
+#define B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN BIT(1)
+#define B_BE_RESP_DMAC_PROC_ERR_ISR_EN BIT(0)
+#define B_BE_RESP_IMR_CLR (B_BE_RESP_DMAC_PROC_ERR_ISR_EN | \
+ B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN | \
+ B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN | \
+ B_BE_RESP_TXCMD_TBL_ERR_ISR_EN | \
+ B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN | \
+ B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN | \
+ B_BE_RESP_RXDMA_REQ_MACID_ERR_ISR_EN | \
+ B_BE_RESP_RXDMA_REQ_INVLD_ERR_ISR_EN | \
+ B_BE_RESP_RXDMA_WRPTR_INVLD_ERR_ISR_EN | \
+ B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN | \
+ B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \
+ B_BE_RESP_TXDMA_READ_DATA_ERR_ISR_EN | \
+ B_BE_RESP_TOO_MANY_PLD_ERR_ISR_EN | \
+ B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \
+ B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN)
+#define B_BE_RESP_IMR_SET (B_BE_RESP_DMAC_PROC_ERR_ISR_EN | \
+ B_BE_RESP_INITCMD_TX_ST_ABORT_ERR_ISR_EN | \
+ B_BE_RESP_INITCMD_RX_ST_ABORT_ERR_ISR_EN | \
+ B_BE_RESP_TXCMD_TBL_ERR_ISR_EN | \
+ B_BE_RESP_TXCMD_DMAC_PROC_ERR_ISR_EN | \
+ B_BE_RESP_TXCMD_TX_ST_ABORT_ERR_ISR_EN | \
+ B_BE_RESP_RX_OVERWRITE_ERR_ISR_EN | \
+ B_BE_RESP_PLDID_RDY_ERR_ISR_EN | \
+ B_BE_RESP_WRPTR_CROSS_ERR_ISR_EN | \
+ B_BE_RESP_SEC_DOUBLE_HIT_ERR_ISR_EN)
+
#define R_BE_PWR_MODULE 0x11900
#define R_BE_PWR_MODULE_C1 0x15900
@@ -4028,6 +7187,17 @@
#define R_BE_PWR_RU_LMT 0x12048
#define R_BE_PWR_RU_LMT_MAX 0x120E4
+#define R_BE_C0_TXPWR_IMR 0x128E0
+#define R_BE_C0_TXPWR_IMR_C1 0x168E0
+#define B_BE_FSM_TIMEOUT_ERR_INT_EN BIT(0)
+#define B_BE_C0_TXPWR_IMR_CLR B_BE_FSM_TIMEOUT_ERR_INT_EN
+#define B_BE_C0_TXPWR_IMR_SET B_BE_FSM_TIMEOUT_ERR_INT_EN
+
+#define R_BE_TXPWR_ERR_FLAG 0x128E4
+#define R_BE_TXPWR_ERR_IMR 0x128E0
+#define R_BE_TXPWR_ERR_FLAG_C1 0x158E4
+#define R_BE_TXPWR_ERR_IMR_C1 0x158E0
+
#define CMAC1_START_ADDR_BE 0x14000
#define CMAC1_END_ADDR_BE 0x17FFF
@@ -4293,6 +7463,11 @@
#define B_P0_RSTB_WATCH_DOG BIT(0)
#define B_P1_RSTB_WATCH_DOG BIT(1)
#define B_UPD_P0_EN BIT(31)
+#define R_SPOOF_CG 0x00B4
+#define B_SPOOF_CG_EN BIT(17)
+#define R_DFS_FFT_CG 0x00B8
+#define B_DFS_CG_EN BIT(1)
+#define B_DFS_FFT_EN BIT(0)
#define R_ANAPAR_PW15 0x030C
#define B_ANAPAR_PW15 GENMASK(31, 24)
#define B_ANAPAR_PW15_H GENMASK(27, 24)
@@ -4355,6 +7530,8 @@
#define R_PHY_STS_BITMAP_HT 0x076C
#define R_PHY_STS_BITMAP_VHT 0x0770
#define R_PHY_STS_BITMAP_HE 0x0774
+#define R_EDCCA_RPTREG_SEL_BE 0x078C
+#define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20)
#define R_PMAC_GNT 0x0980
#define B_PMAC_GNT_TXEN BIT(0)
#define B_PMAC_GNT_RXEN BIT(16)
@@ -4414,12 +7591,18 @@
#define B_IOQ_IQK_DPK_EN BIT(1)
#define R_GNT_BT_WGT_EN 0x0C6C
#define B_GNT_BT_WGT_EN BIT(21)
+#define R_TX_COLLISION_T2R_ST 0x0C70
+#define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20)
+#define R_TXGATING 0x0C74
+#define B_TXGATING_EN BIT(4)
#define R_PD_ARBITER_OFF 0x0C80
#define B_PD_ARBITER_OFF BIT(31)
#define R_SNDCCA_A1 0x0C9C
#define B_SNDCCA_A1_EN GENMASK(19, 12)
#define R_SNDCCA_A2 0x0CA0
#define B_SNDCCA_A2_VAL GENMASK(19, 12)
+#define R_TX_COLLISION_T2R_ST_BE 0x0CC8
+#define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8)
#define R_RXHT_MCS_LIMIT 0x0D18
#define B_RXHT_MCS_LIMIT GENMASK(9, 8)
#define R_RXVHT_MCS_LIMIT 0x0D18
@@ -4438,6 +7621,10 @@
#define R_BRK_ASYNC_RST_EN_1 0x0DC0
#define R_BRK_ASYNC_RST_EN_2 0x0DC4
#define R_BRK_ASYNC_RST_EN_3 0x0DC8
+#define R_CTLTOP 0x1008
+#define B_CTLTOP_ON BIT(23)
+#define B_CTLTOP_VAL GENMASK(15, 12)
+#define R_EDCCA_RPT_SEL_BE 0x10CC
#define R_S0_HW_SI_DIS 0x1200
#define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28)
#define R_P0_RXCK 0x12A0
@@ -4469,6 +7656,14 @@
#define R_CFO_COMP_SEG0_H 0x1388
#define R_CFO_COMP_SEG0_CTRL 0x138C
#define R_DBG32_D 0x1730
+#define R_EDCCA_RPT_A 0x1738
+#define R_EDCCA_RPT_B 0x173c
+#define B_EDCCA_RPT_B_FB BIT(7)
+#define B_EDCCA_RPT_B_P20 BIT(6)
+#define B_EDCCA_RPT_B_S20 BIT(5)
+#define B_EDCCA_RPT_B_S40 BIT(4)
+#define B_EDCCA_RPT_B_S80 BIT(3)
+#define B_EDCCA_RPT_B_PATH_MASK GENMASK(2, 1)
#define R_SWSI_V1 0x174C
#define B_SWSI_W_BUSY_V1 BIT(24)
#define B_SWSI_R_BUSY_V1 BIT(25)
@@ -4530,6 +7725,8 @@
#define R_S0_ADDCK 0x1E00
#define B_S0_ADDCK_I GENMASK(9, 0)
#define B_S0_ADDCK_Q GENMASK(19, 10)
+#define R_EDCCA_RPT_SEL 0x20CC
+#define B_EDCCA_RPT_SEL_MSK GENMASK(2, 0)
#define R_ADC_FIFO 0x20fc
#define B_ADC_FIFO_RST GENMASK(31, 24)
#define B_ADC_FIFO_RXK GENMASK(31, 16)
@@ -4576,6 +7773,8 @@
#define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0)
#define R_P1_EN_SOUND_WO_NDP 0x2D7C
#define B_P1_EN_SOUND_WO_NDP BIT(1)
+#define R_EDCCA_RPT_A_BE 0x2E38
+#define R_EDCCA_RPT_B_BE 0x2E3C
#define R_S1_HW_SI_DIS 0x3200
#define B_S1_HW_SI_DIS_W_R_TRIG GENMASK(30, 28)
#define R_P1_RXCK 0x32A0
@@ -4619,6 +7818,7 @@
#define B_SEG0CSI_EN BIT(23)
#define R_BSS_CLR_MAP 0x43ac
#define R_BSS_CLR_MAP_V1 0x43B0
+#define R_BSS_CLR_MAP_V2 0x4EB0
#define B_BSS_CLR_MAP_VLD0 BIT(28)
#define B_BSS_CLR_MAP_TGT GENMASK(27, 22)
#define B_BSS_CLR_MAP_STAID GENMASK(21, 11)
@@ -4783,9 +7983,9 @@
#define R_SEG0R_PD_V2 0x6A74
#define R_SEG0R_EDCCA_LVL 0x4840
#define R_SEG0R_EDCCA_LVL_V1 0x4884
-#define B_SEG0R_PPDU_LVL_MSK GENMASK(31, 24)
-#define B_SEG0R_EDCCA_LVL_P_MSK GENMASK(15, 8)
-#define B_SEG0R_EDCCA_LVL_A_MSK GENMASK(7, 0)
+#define B_EDCCA_LVL_MSK3 GENMASK(31, 24)
+#define B_EDCCA_LVL_MSK1 GENMASK(15, 8)
+#define B_EDCCA_LVL_MSK0 GENMASK(7, 0)
#define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1 BIT(30)
#define B_SEG0R_PD_SPATIAL_REUSE_EN_MSK BIT(29)
#define B_SEG0R_PD_LOWER_BOUND_MSK GENMASK(10, 6)
@@ -4912,6 +8112,8 @@
#define R_BMODE_PDTH_EN_V1 0x4B74
#define R_BMODE_PDTH_EN_V2 0x6718
#define B_BMODE_PDTH_LIMIT_EN_MSK_V1 BIT(30)
+#define R_BSS_CLR_VLD_V2 0x4EBC
+#define B_BSS_CLR_VLD0_V2 BIT(2)
#define R_CFO_COMP_SEG1_L 0x5384
#define R_CFO_COMP_SEG1_H 0x5388
#define R_CFO_COMP_SEG1_CTRL 0x538C
@@ -5039,6 +8241,10 @@
#define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28)
#define R_DCFO_OPT_V1 0x6260
#define B_DCFO_OPT_EN_V1 BIT(17)
+#define R_SEG0R_EDCCA_LVL_BE 0x69EC
+#define R_SEG0R_PPDU_LVL_BE 0x69F0
+#define R_SEGSND 0x6A14
+#define B_SEGSND_EN BIT(31)
#define R_RPL_BIAS_COMP1 0x6DF0
#define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0)
#define R_P1_TSSI_ALIM1 0x7630
diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c
index ca99422e600f..d0857ef60ea6 100644
--- a/drivers/net/wireless/realtek/rtw89/regd.c
+++ b/drivers/net/wireless/realtek/rtw89/regd.c
@@ -112,9 +112,9 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("MY", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("PK", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("PH", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
+ COUNTRY_REGD("SG", RTW89_ETSI, RTW89_ETSI, RTW89_ETSI),
COUNTRY_REGD("LK", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_NA),
+ COUNTRY_REGD("TW", RTW89_FCC, RTW89_FCC, RTW89_ETSI),
COUNTRY_REGD("TH", RTW89_ETSI, RTW89_ETSI, RTW89_THAILAND),
COUNTRY_REGD("VN", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("AU", RTW89_ACMA, RTW89_ACMA, RTW89_ACMA),
@@ -179,7 +179,7 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("GE", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GI", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GL", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
- COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_NA),
+ COUNTRY_REGD("GD", RTW89_FCC, RTW89_FCC, RTW89_FCC),
COUNTRY_REGD("GP", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
COUNTRY_REGD("GU", RTW89_FCC, RTW89_FCC, RTW89_NA),
COUNTRY_REGD("GG", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
@@ -257,7 +257,42 @@ static const struct rtw89_regd rtw89_regd_map[] = {
COUNTRY_REGD("PS", RTW89_ETSI, RTW89_ETSI, RTW89_NA),
};
-static const struct rtw89_regd *rtw89_regd_find_reg_by_name(char *alpha2)
+static const char rtw89_alpha2_list_eu[][3] = {
+ "AT",
+ "BE",
+ "CY",
+ "CZ",
+ "DK",
+ "EE",
+ "FI",
+ "FR",
+ "DE",
+ "GR",
+ "HU",
+ "IS",
+ "IE",
+ "IT",
+ "LV",
+ "LI",
+ "LT",
+ "LU",
+ "MT",
+ "MC",
+ "NL",
+ "NO",
+ "PL",
+ "PT",
+ "SK",
+ "SI",
+ "ES",
+ "SE",
+ "CH",
+ "BG",
+ "HR",
+ "RO",
+};
+
+static const struct rtw89_regd *rtw89_regd_find_reg_by_name(const char *alpha2)
{
u32 i;
@@ -274,6 +309,24 @@ static bool rtw89_regd_is_ww(const struct rtw89_regd *regd)
return regd == &rtw89_ww_regd;
}
+static u8 rtw89_regd_get_index(const struct rtw89_regd *regd)
+{
+ BUILD_BUG_ON(ARRAY_SIZE(rtw89_regd_map) > RTW89_REGD_MAX_COUNTRY_NUM);
+
+ if (rtw89_regd_is_ww(regd))
+ return RTW89_REGD_MAX_COUNTRY_NUM;
+
+ return regd - rtw89_regd_map;
+}
+
+static u8 rtw89_regd_get_index_by_name(const char *alpha2)
+{
+ const struct rtw89_regd *regd;
+
+ regd = rtw89_regd_find_reg_by_name(alpha2);
+ return rtw89_regd_get_index(regd);
+}
+
#define rtw89_debug_regd(_dev, _regd, _desc, _argv...) \
do { \
typeof(_regd) __r = _regd; \
@@ -291,19 +344,22 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev,
const struct rtw89_chip_info *chip = rtwdev->chip;
bool regd_allow_unii_4 = chip->support_unii4;
struct ieee80211_supported_band *sband;
+ struct rtw89_acpi_dsm_result res = {};
int ret;
u8 val;
if (!chip->support_unii4)
goto bottom;
- ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &val);
+ ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_59G_EN, &res);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_REGD,
"acpi: cannot eval unii 4: %d\n", ret);
goto bottom;
}
+ val = res.u.value;
+
rtw89_debug(rtwdev, RTW89_DBG_REGD,
"acpi: eval if allow unii 4: %d\n", val);
@@ -332,25 +388,99 @@ bottom:
sband->n_channels -= 3;
}
+static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block,
+ const char *alpha2)
+{
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ u8 index;
+
+ index = rtw89_regd_get_index_by_name(alpha2);
+ if (index == RTW89_REGD_MAX_COUNTRY_NUM) {
+ rtw89_debug(rtwdev, RTW89_DBG_REGD, "%s: unknown alpha2 %c%c\n",
+ __func__, alpha2[0], alpha2[1]);
+ return;
+ }
+
+ if (block)
+ set_bit(index, regulatory->block_6ghz);
+ else
+ clear_bit(index, regulatory->block_6ghz);
+}
+
+static void rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ const struct rtw89_acpi_country_code *country;
+ const struct rtw89_acpi_policy_6ghz *ptr;
+ struct rtw89_acpi_dsm_result res = {};
+ bool to_block;
+ int i, j;
+ int ret;
+
+ ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_BP, &res);
+ if (ret) {
+ rtw89_debug(rtwdev, RTW89_DBG_REGD,
+ "acpi: cannot eval policy 6ghz: %d\n", ret);
+ return;
+ }
+
+ ptr = res.u.policy_6ghz;
+
+ switch (ptr->policy_mode) {
+ case RTW89_ACPI_POLICY_BLOCK:
+ to_block = true;
+ break;
+ case RTW89_ACPI_POLICY_ALLOW:
+ to_block = false;
+ /* only below list is allowed; block all first */
+ bitmap_fill(regulatory->block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM);
+ break;
+ default:
+ rtw89_debug(rtwdev, RTW89_DBG_REGD,
+ "%s: unknown policy mode: %d\n", __func__,
+ ptr->policy_mode);
+ goto out;
+ }
+
+ for (i = 0; i < ptr->country_count; i++) {
+ country = &ptr->country_list[i];
+ if (memcmp("EU", country->alpha2, 2) != 0) {
+ __rtw89_regd_setup_policy_6ghz(rtwdev, to_block,
+ country->alpha2);
+ continue;
+ }
+
+ for (j = 0; j < ARRAY_SIZE(rtw89_alpha2_list_eu); j++)
+ __rtw89_regd_setup_policy_6ghz(rtwdev, to_block,
+ rtw89_alpha2_list_eu[j]);
+ }
+
+out:
+ kfree(ptr);
+}
+
static void rtw89_regd_setup_6ghz(struct rtw89_dev *rtwdev, struct wiphy *wiphy)
{
const struct rtw89_chip_info *chip = rtwdev->chip;
bool chip_support_6ghz = chip->support_bands & BIT(NL80211_BAND_6GHZ);
bool regd_allow_6ghz = chip_support_6ghz;
struct ieee80211_supported_band *sband;
+ struct rtw89_acpi_dsm_result res = {};
int ret;
u8 val;
if (!chip_support_6ghz)
goto bottom;
- ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &val);
+ ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6G_DIS, &res);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_REGD,
"acpi: cannot eval 6ghz: %d\n", ret);
goto bottom;
}
+ val = res.u.value;
+
rtw89_debug(rtwdev, RTW89_DBG_REGD,
"acpi: eval if disallow 6ghz: %d\n", val);
@@ -369,8 +499,10 @@ bottom:
rtw89_debug(rtwdev, RTW89_DBG_REGD, "regd: allow 6ghz: %d\n",
regd_allow_6ghz);
- if (regd_allow_6ghz)
+ if (regd_allow_6ghz) {
+ rtw89_regd_setup_policy_6ghz(rtwdev);
return;
+ }
sband = wiphy->bands[NL80211_BAND_6GHZ];
if (!sband)
@@ -430,6 +562,33 @@ int rtw89_regd_init(struct rtw89_dev *rtwdev,
return 0;
}
+static void rtw89_regd_apply_policy_6ghz(struct rtw89_dev *rtwdev,
+ struct wiphy *wiphy)
+{
+ struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory;
+ const struct rtw89_regd *regd = regulatory->regd;
+ struct ieee80211_supported_band *sband;
+ u8 index;
+ int i;
+
+ index = rtw89_regd_get_index(regd);
+ if (index == RTW89_REGD_MAX_COUNTRY_NUM)
+ return;
+
+ if (!test_bit(index, regulatory->block_6ghz))
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_REGD, "%c%c 6 GHz is blocked by policy\n",
+ regd->alpha2[0], regd->alpha2[1]);
+
+ sband = wiphy->bands[NL80211_BAND_6GHZ];
+ if (!sband)
+ return;
+
+ for (i = 0; i < sband->n_channels; i++)
+ sband->channels[i].flags |= IEEE80211_CHAN_DISABLED;
+}
+
static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev,
struct wiphy *wiphy,
struct regulatory_request *request)
@@ -444,6 +603,8 @@ static void rtw89_regd_notifier_apply(struct rtw89_dev *rtwdev,
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
else
wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
+
+ rtw89_regd_apply_policy_6ghz(rtwdev, wiphy);
}
void rtw89_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request)
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
index 50522ff85003..5c167a9278ce 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c
@@ -205,6 +205,20 @@ static const struct rtw89_dig_regs rtw8851b_dig_regs = {
B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK},
};
+static const struct rtw89_edcca_regs rtw8851b_edcca_regs = {
+ .edcca_level = R_SEG0R_EDCCA_LVL_V1,
+ .edcca_mask = B_EDCCA_LVL_MSK0,
+ .edcca_p_mask = B_EDCCA_LVL_MSK1,
+ .ppdu_level = R_SEG0R_EDCCA_LVL_V1,
+ .ppdu_mask = B_EDCCA_LVL_MSK3,
+ .rpt_a = R_EDCCA_RPT_A,
+ .rpt_b = R_EDCCA_RPT_B,
+ .rpt_sel = R_EDCCA_RPT_SEL,
+ .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK,
+ .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST,
+ .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
+};
+
static const struct rtw89_btc_rf_trx_para rtw89_btc_8851b_rf_ul[] = {
{255, 0, 0, 7}, /* 0 -> original */
{255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */
@@ -500,7 +514,8 @@ static void rtw8851b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
gain->offset_valid = valid;
}
-static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map)
+static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block)
{
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw8851b_efuse *map;
@@ -2359,8 +2374,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.rsvd_ple_ofst = 0x2f800,
.hfc_param_ini = rtw8851b_hfc_param_ini_pcie,
.dle_mem = rtw8851b_dle_mem_pcie,
- .wde_qempty_acq_num = 4,
- .wde_qempty_mgq_sel = 4,
+ .wde_qempty_acq_grpnum = 4,
+ .wde_qempty_mgq_grpsel = 4,
.rf_base_addr = {0xe000},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
@@ -2393,12 +2408,14 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.bacam_num = 2,
.bacam_dynamic_num = 4,
.bacam_ver = RTW89_BACAM_V0,
+ .ppdu_max_usr = 4,
.sec_ctrl_efuse_size = 4,
.physical_efuse_size = 1216,
.logical_efuse_size = 2048,
.limit_efuse_size = 1280,
.dav_phy_efuse_size = 0,
.dav_log_efuse_size = 0,
+ .efuse_blocks = NULL,
.phycap_addr = 0x580,
.phycap_size = 128,
.para_ver = 0,
@@ -2437,13 +2454,15 @@ const struct rtw89_chip_info rtw8851b_chip_info = {
.dcfo_comp = &rtw8851b_dcfo_comp,
.dcfo_comp_sft = 12,
.imr_info = &rtw8851b_imr_info,
+ .imr_dmac_table = NULL,
+ .imr_cmac_table = NULL,
.rrsr_cfgs = &rtw8851b_rrsr_cfgs,
.bss_clr_vld = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0},
.bss_clr_map_reg = R_BSS_CLR_MAP_V1,
.dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) |
BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
- .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1,
+ .edcca_regs = &rtw8851b_edcca_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8851b,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
index 0f7711c50bd1..ade69bd30fc8 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c
@@ -10,6 +10,7 @@
#include "rtw8851b.h"
static const struct rtw89_pci_info rtw8851b_pci_info = {
+ .gen_def = &rtw89_pci_gen_ax,
.txbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_mode = MAC_AX_RXBD_PKT,
@@ -33,6 +34,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = {
.max_tag_num_mask = B_AX_MAX_TAG_NUM,
.rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR,
.txbd_rwptr_clr2_reg = 0,
+ .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO},
.dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1},
.dma_stop2 = {0},
.dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1},
@@ -41,6 +43,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = {
.rpwm_addr = R_AX_PCIE_HRPWM,
.cpwm_addr = R_AX_CPWM,
+ .mit_addr = R_AX_INT_MIT_RX,
.tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) |
BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) |
BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
index 0c36e6180e25..0c76c52ce22c 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c
@@ -498,6 +498,20 @@ static const struct rtw89_dig_regs rtw8852a_dig_regs = {
B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK},
};
+static const struct rtw89_edcca_regs rtw8852a_edcca_regs = {
+ .edcca_level = R_SEG0R_EDCCA_LVL,
+ .edcca_mask = B_EDCCA_LVL_MSK0,
+ .edcca_p_mask = B_EDCCA_LVL_MSK1,
+ .ppdu_level = R_SEG0R_EDCCA_LVL,
+ .ppdu_mask = B_EDCCA_LVL_MSK3,
+ .rpt_a = R_EDCCA_RPT_A,
+ .rpt_b = R_EDCCA_RPT_B,
+ .rpt_sel = R_EDCCA_RPT_SEL,
+ .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK,
+ .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST,
+ .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
+};
+
static void rtw8852ae_efuse_parsing(struct rtw89_efuse *efuse,
struct rtw8852a_efuse *map)
{
@@ -537,7 +551,8 @@ static void rtw8852a_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
}
}
-static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map)
+static int rtw8852a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block)
{
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw8852a_efuse *map;
@@ -2094,8 +2109,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.rsvd_ple_ofst = 0x6f800,
.hfc_param_ini = rtw8852a_hfc_param_ini_pcie,
.dle_mem = rtw8852a_dle_mem_pcie,
- .wde_qempty_acq_num = 16,
- .wde_qempty_mgq_sel = 16,
+ .wde_qempty_acq_grpnum = 16,
+ .wde_qempty_mgq_grpsel = 16,
.rf_base_addr = {0xc000, 0xd000},
.pwr_on_seq = pwr_on_seq_8852a,
.pwr_off_seq = pwr_off_seq_8852a,
@@ -2129,12 +2144,14 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.bacam_num = 2,
.bacam_dynamic_num = 4,
.bacam_ver = RTW89_BACAM_V0,
+ .ppdu_max_usr = 4,
.sec_ctrl_efuse_size = 4,
.physical_efuse_size = 1216,
.logical_efuse_size = 1536,
.limit_efuse_size = 1152,
.dav_phy_efuse_size = 0,
.dav_log_efuse_size = 0,
+ .efuse_blocks = NULL,
.phycap_addr = 0x580,
.phycap_size = 128,
.para_ver = 0x0,
@@ -2174,11 +2191,13 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.dcfo_comp = &rtw8852a_dcfo_comp,
.dcfo_comp_sft = 10,
.imr_info = &rtw8852a_imr_info,
+ .imr_dmac_table = NULL,
+ .imr_cmac_table = NULL,
.rrsr_cfgs = &rtw8852a_rrsr_cfgs,
.bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0},
.bss_clr_map_reg = R_BSS_CLR_MAP,
.dma_ch_mask = 0,
- .edcca_lvl_reg = R_SEG0R_EDCCA_LVL,
+ .edcca_regs = &rtw8852a_edcca_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852a,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
index d835a44a1d0d..f1e890bde049 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c
@@ -10,6 +10,7 @@
#include "rtw8852a.h"
static const struct rtw89_pci_info rtw8852a_pci_info = {
+ .gen_def = &rtw89_pci_gen_ax,
.txbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_mode = MAC_AX_RXBD_PKT,
@@ -24,6 +25,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
.autok_en = MAC_AX_PCIE_DISABLE,
.io_rcy_en = MAC_AX_PCIE_DISABLE,
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
+ .rx_ring_eq_is_full = false,
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
.txhci_en_bit = B_AX_TXHCI_EN,
@@ -33,6 +35,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
.max_tag_num_mask = B_AX_MAX_TAG_NUM,
.rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR,
.txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2,
+ .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO},
.dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK},
.dma_stop2 = {R_AX_PCIE_DMA_STOP2, B_AX_TX_STOP2_ALL},
.dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK},
@@ -41,6 +44,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = {
.rpwm_addr = R_AX_PCIE_HRPWM,
.cpwm_addr = R_AX_CPWM,
+ .mit_addr = R_AX_INT_MIT_RX,
.tx_dma_ch_mask = 0,
.bd_idx_addr_low_power = NULL,
.dma_addr_set = &rtw89_pci_ch_dma_addr_set,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
index 9d4e6f08218d..de887a35f3fb 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c
@@ -330,6 +330,20 @@ static const struct rtw89_dig_regs rtw8852b_dig_regs = {
B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK},
};
+static const struct rtw89_edcca_regs rtw8852b_edcca_regs = {
+ .edcca_level = R_SEG0R_EDCCA_LVL_V1,
+ .edcca_mask = B_EDCCA_LVL_MSK0,
+ .edcca_p_mask = B_EDCCA_LVL_MSK1,
+ .ppdu_level = R_SEG0R_EDCCA_LVL_V1,
+ .ppdu_mask = B_EDCCA_LVL_MSK3,
+ .rpt_a = R_EDCCA_RPT_A,
+ .rpt_b = R_EDCCA_RPT_B,
+ .rpt_sel = R_EDCCA_RPT_SEL,
+ .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK,
+ .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST,
+ .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
+};
+
static const struct rtw89_btc_rf_trx_para rtw89_btc_8852b_rf_ul[] = {
{255, 0, 0, 7}, /* 0 -> original */
{255, 2, 0, 7}, /* 1 -> for BT-connected ACI issue && BTG co-rx */
@@ -638,7 +652,8 @@ static void rtw8852b_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
gain->offset_valid = valid;
}
-static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map)
+static int rtw8852b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block)
{
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw8852b_efuse *map;
@@ -2528,8 +2543,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.rsvd_ple_ofst = 0x2f800,
.hfc_param_ini = rtw8852b_hfc_param_ini_pcie,
.dle_mem = rtw8852b_dle_mem_pcie,
- .wde_qempty_acq_num = 4,
- .wde_qempty_mgq_sel = 4,
+ .wde_qempty_acq_grpnum = 4,
+ .wde_qempty_mgq_grpsel = 4,
.rf_base_addr = {0xe000, 0xf000},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
@@ -2563,12 +2578,14 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.bacam_num = 2,
.bacam_dynamic_num = 4,
.bacam_ver = RTW89_BACAM_V0,
+ .ppdu_max_usr = 4,
.sec_ctrl_efuse_size = 4,
.physical_efuse_size = 1216,
.logical_efuse_size = 2048,
.limit_efuse_size = 1280,
.dav_phy_efuse_size = 96,
.dav_log_efuse_size = 16,
+ .efuse_blocks = NULL,
.phycap_addr = 0x580,
.phycap_size = 128,
.para_ver = 0,
@@ -2608,13 +2625,15 @@ const struct rtw89_chip_info rtw8852b_chip_info = {
.dcfo_comp = &rtw8852b_dcfo_comp,
.dcfo_comp_sft = 10,
.imr_info = &rtw8852b_imr_info,
+ .imr_dmac_table = NULL,
+ .imr_cmac_table = NULL,
.rrsr_cfgs = &rtw8852b_rrsr_cfgs,
.bss_clr_vld = {R_BSS_CLR_MAP_V1, B_BSS_CLR_MAP_VLD0},
.bss_clr_map_reg = R_BSS_CLR_MAP_V1,
.dma_ch_mask = BIT(RTW89_DMA_ACH4) | BIT(RTW89_DMA_ACH5) |
BIT(RTW89_DMA_ACH6) | BIT(RTW89_DMA_ACH7) |
BIT(RTW89_DMA_B1MG) | BIT(RTW89_DMA_B1HI),
- .edcca_lvl_reg = R_SEG0R_EDCCA_LVL_V1,
+ .edcca_regs = &rtw8852b_edcca_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852b,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
index ecf39d2d9f81..920b20bbcfb7 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c
@@ -10,6 +10,7 @@
#include "rtw8852b.h"
static const struct rtw89_pci_info rtw8852b_pci_info = {
+ .gen_def = &rtw89_pci_gen_ax,
.txbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_mode = MAC_AX_RXBD_PKT,
@@ -24,6 +25,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
.autok_en = MAC_AX_PCIE_DISABLE,
.io_rcy_en = MAC_AX_PCIE_DISABLE,
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
+ .rx_ring_eq_is_full = false,
.init_cfg_reg = R_AX_PCIE_INIT_CFG1,
.txhci_en_bit = B_AX_TXHCI_EN,
@@ -33,6 +35,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
.max_tag_num_mask = B_AX_MAX_TAG_NUM,
.rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR,
.txbd_rwptr_clr2_reg = 0,
+ .dma_io_stop = {R_AX_PCIE_DMA_STOP1, B_AX_STOP_PCIEIO},
.dma_stop1 = {R_AX_PCIE_DMA_STOP1, B_AX_TX_STOP1_MASK_V1},
.dma_stop2 = {0},
.dma_busy1 = {R_AX_PCIE_DMA_BUSY1, DMA_BUSY1_CHECK_V1},
@@ -41,6 +44,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = {
.rpwm_addr = R_AX_PCIE_HRPWM,
.cpwm_addr = R_AX_CPWM,
+ .mit_addr = R_AX_INT_MIT_RX,
.tx_dma_ch_mask = BIT(RTW89_TXCH_ACH4) | BIT(RTW89_TXCH_ACH5) |
BIT(RTW89_TXCH_ACH6) | BIT(RTW89_TXCH_ACH7) |
BIT(RTW89_TXCH_CH10) | BIT(RTW89_TXCH_CH11),
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
index 3b7d8ab39bab..8618d0204f66 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c
@@ -167,6 +167,20 @@ static const struct rtw89_dig_regs rtw8852c_dig_regs = {
B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK},
};
+static const struct rtw89_edcca_regs rtw8852c_edcca_regs = {
+ .edcca_level = R_SEG0R_EDCCA_LVL,
+ .edcca_mask = B_EDCCA_LVL_MSK0,
+ .edcca_p_mask = B_EDCCA_LVL_MSK1,
+ .ppdu_level = R_SEG0R_EDCCA_LVL,
+ .ppdu_mask = B_EDCCA_LVL_MSK3,
+ .rpt_a = R_EDCCA_RPT_A,
+ .rpt_b = R_EDCCA_RPT_B,
+ .rpt_sel = R_EDCCA_RPT_SEL,
+ .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK,
+ .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST,
+ .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_M,
+};
+
static void rtw8852c_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en,
enum rtw89_phy_idx phy_idx);
@@ -426,11 +440,36 @@ static void rtw8852c_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
valid |= _decode_efuse_gain(map->rx_gain_5g_high,
&gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH],
&gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_l0,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_l1,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_m0,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_m1,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_h0,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_h1,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_uh0,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0]);
+ valid |= _decode_efuse_gain(map->rx_gain_6g_uh1,
+ &gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1],
+ &gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1]);
gain->offset_valid = valid;
}
-static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map)
+static int rtw8852c_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block)
{
struct rtw89_efuse *efuse = &rtwdev->efuse;
struct rtw8852c_efuse *map;
@@ -2840,8 +2879,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.rsvd_ple_ofst = 0x6f800,
.hfc_param_ini = rtw8852c_hfc_param_ini_pcie,
.dle_mem = rtw8852c_dle_mem_pcie,
- .wde_qempty_acq_num = 16,
- .wde_qempty_mgq_sel = 16,
+ .wde_qempty_acq_grpnum = 16,
+ .wde_qempty_mgq_grpsel = 16,
.rf_base_addr = {0xe000, 0xf000},
.pwr_on_seq = NULL,
.pwr_off_seq = NULL,
@@ -2877,12 +2916,14 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.bacam_num = 8,
.bacam_dynamic_num = 8,
.bacam_ver = RTW89_BACAM_V0_EXT,
+ .ppdu_max_usr = 8,
.sec_ctrl_efuse_size = 4,
.physical_efuse_size = 1216,
.logical_efuse_size = 2048,
.limit_efuse_size = 1280,
.dav_phy_efuse_size = 96,
.dav_log_efuse_size = 16,
+ .efuse_blocks = NULL,
.phycap_addr = 0x590,
.phycap_size = 0x60,
.para_ver = 0x1,
@@ -2923,11 +2964,13 @@ const struct rtw89_chip_info rtw8852c_chip_info = {
.dcfo_comp = &rtw8852c_dcfo_comp,
.dcfo_comp_sft = 12,
.imr_info = &rtw8852c_imr_info,
+ .imr_dmac_table = NULL,
+ .imr_cmac_table = NULL,
.rrsr_cfgs = &rtw8852c_rrsr_cfgs,
.bss_clr_vld = {R_BSS_CLR_MAP, B_BSS_CLR_MAP_VLD0},
.bss_clr_map_reg = R_BSS_CLR_MAP,
.dma_ch_mask = 0,
- .edcca_lvl_reg = R_SEG0R_EDCCA_LVL,
+ .edcca_regs = &rtw8852c_edcca_regs,
#ifdef CONFIG_PM
.wowlan_stub = &rtw_wowlan_stub_8852c,
#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.h b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
index ac642808a81f..77b05daedd10 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852c.h
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.h
@@ -73,9 +73,25 @@ struct rtw8852c_efuse {
u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM];
u8 rsvd14[10];
u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM];
- u8 rsvd15[110];
+ u8 rsvd15[94];
+ u8 rx_gain_6g_l0;
+ u8 rsvd16;
+ u8 rx_gain_6g_l1;
+ u8 rsvd17;
+ u8 rx_gain_6g_m0;
+ u8 rsvd18;
+ u8 rx_gain_6g_m1;
+ u8 rsvd19;
+ u8 rx_gain_6g_h0;
+ u8 rsvd20;
+ u8 rx_gain_6g_h1;
+ u8 rsvd21;
+ u8 rx_gain_6g_uh0;
+ u8 rsvd22;
+ u8 rx_gain_6g_uh1;
+ u8 rsvd23;
u8 channel_plan_6g;
- u8 rsvd16[71];
+ u8 rsvd24[71];
union {
struct rtw8852c_u_efuse u;
struct rtw8852c_e_efuse e;
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
index 80490a5437df..4592de3dbd94 100644
--- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
+++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c
@@ -19,6 +19,7 @@ static const struct rtw89_pci_bd_idx_addr rtw8852c_bd_idx_addr_low_power = {
};
static const struct rtw89_pci_info rtw8852c_pci_info = {
+ .gen_def = &rtw89_pci_gen_ax,
.txbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_trunc_mode = MAC_AX_BD_TRUNC,
.rxbd_mode = MAC_AX_RXBD_PKT,
@@ -33,6 +34,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
.autok_en = MAC_AX_PCIE_DISABLE,
.io_rcy_en = MAC_AX_PCIE_ENABLE,
.io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_6MS,
+ .rx_ring_eq_is_full = false,
.init_cfg_reg = R_AX_HAXI_INIT_CFG1,
.txhci_en_bit = B_AX_TXHCI_EN_V1,
@@ -42,6 +44,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
.max_tag_num_mask = B_AX_MAX_TAG_NUM_V1_MASK,
.rxbd_rwptr_clr_reg = R_AX_RXBD_RWPTR_CLR_V1,
.txbd_rwptr_clr2_reg = R_AX_TXBD_RWPTR_CLR2_V1,
+ .dma_io_stop = {R_AX_HAXI_INIT_CFG1, B_AX_STOP_AXI_MST},
.dma_stop1 = {R_AX_HAXI_DMA_STOP1, B_AX_TX_STOP1_MASK},
.dma_stop2 = {R_AX_HAXI_DMA_STOP2, B_AX_TX_STOP2_ALL},
.dma_busy1 = {R_AX_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK},
@@ -50,6 +53,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = {
.rpwm_addr = R_AX_PCIE_HRPWM_V1,
.cpwm_addr = R_AX_PCIE_CRPWM,
+ .mit_addr = R_AX_INT_MIT_RX_V1,
.tx_dma_ch_mask = 0,
.bd_idx_addr_low_power = &rtw8852c_bd_idx_addr_low_power,
.dma_addr_set = &rtw89_pci_ch_dma_addr_set_v1,
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
new file mode 100644
index 000000000000..0e7300cc6d9e
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c
@@ -0,0 +1,710 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#include "debug.h"
+#include "efuse.h"
+#include "fw.h"
+#include "mac.h"
+#include "phy.h"
+#include "reg.h"
+#include "rtw8922a.h"
+
+#define RTW8922A_FW_FORMAT_MAX 0
+#define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw"
+#define RTW8922A_MODULE_FIRMWARE \
+ RTW8922A_FW_BASENAME ".bin"
+
+static const struct rtw89_hfc_ch_cfg rtw8922a_hfc_chcfg_pcie[] = {
+ {2, 1641, grp_0}, /* ACH 0 */
+ {2, 1641, grp_0}, /* ACH 1 */
+ {2, 1641, grp_0}, /* ACH 2 */
+ {2, 1641, grp_0}, /* ACH 3 */
+ {2, 1641, grp_1}, /* ACH 4 */
+ {2, 1641, grp_1}, /* ACH 5 */
+ {2, 1641, grp_1}, /* ACH 6 */
+ {2, 1641, grp_1}, /* ACH 7 */
+ {2, 1641, grp_0}, /* B0MGQ */
+ {2, 1641, grp_0}, /* B0HIQ */
+ {2, 1641, grp_1}, /* B1MGQ */
+ {2, 1641, grp_1}, /* B1HIQ */
+ {0, 0, 0}, /* FWCMDQ */
+ {0, 0, 0}, /* BMC */
+ {0, 0, 0}, /* H2D */
+};
+
+static const struct rtw89_hfc_pub_cfg rtw8922a_hfc_pubcfg_pcie = {
+ 1651, /* Group 0 */
+ 1651, /* Group 1 */
+ 3302, /* Public Max */
+ 0, /* WP threshold */
+};
+
+static const struct rtw89_hfc_param_ini rtw8922a_hfc_param_ini_pcie[] = {
+ [RTW89_QTA_SCC] = {rtw8922a_hfc_chcfg_pcie, &rtw8922a_hfc_pubcfg_pcie,
+ &rtw89_mac_size.hfc_prec_cfg_c0, RTW89_HCIFC_POH},
+ [RTW89_QTA_DLFW] = {NULL, NULL, &rtw89_mac_size.hfc_prec_cfg_c2,
+ RTW89_HCIFC_POH},
+ [RTW89_QTA_INVALID] = {NULL},
+};
+
+static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = {
+ [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size0_v1,
+ &rtw89_mac_size.ple_size0_v1, &rtw89_mac_size.wde_qt0_v1,
+ &rtw89_mac_size.wde_qt0_v1, &rtw89_mac_size.ple_qt0,
+ &rtw89_mac_size.ple_qt1, &rtw89_mac_size.ple_rsvd_qt0,
+ &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0},
+ [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size4_v1,
+ &rtw89_mac_size.ple_size3_v1, &rtw89_mac_size.wde_qt4,
+ &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt9,
+ &rtw89_mac_size.ple_qt9, &rtw89_mac_size.ple_rsvd_qt1,
+ &rtw89_mac_size.rsvd0_size0, &rtw89_mac_size.rsvd1_size0},
+ [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL,
+ NULL},
+};
+
+static const struct rtw89_reg_imr rtw8922a_imr_dmac_regs[] = {
+ {R_BE_DISP_HOST_IMR, B_BE_DISP_HOST_IMR_CLR, B_BE_DISP_HOST_IMR_SET},
+ {R_BE_DISP_CPU_IMR, B_BE_DISP_CPU_IMR_CLR, B_BE_DISP_CPU_IMR_SET},
+ {R_BE_DISP_OTHER_IMR, B_BE_DISP_OTHER_IMR_CLR, B_BE_DISP_OTHER_IMR_SET},
+ {R_BE_PKTIN_ERR_IMR, B_BE_PKTIN_ERR_IMR_CLR, B_BE_PKTIN_ERR_IMR_SET},
+ {R_BE_INTERRUPT_MASK_REG, B_BE_INTERRUPT_MASK_REG_CLR, B_BE_INTERRUPT_MASK_REG_SET},
+ {R_BE_MLO_ERR_IDCT_IMR, B_BE_MLO_ERR_IDCT_IMR_CLR, B_BE_MLO_ERR_IDCT_IMR_SET},
+ {R_BE_MPDU_TX_ERR_IMR, B_BE_MPDU_TX_ERR_IMR_CLR, B_BE_MPDU_TX_ERR_IMR_SET},
+ {R_BE_MPDU_RX_ERR_IMR, B_BE_MPDU_RX_ERR_IMR_CLR, B_BE_MPDU_RX_ERR_IMR_SET},
+ {R_BE_SEC_ERROR_IMR, B_BE_SEC_ERROR_IMR_CLR, B_BE_SEC_ERROR_IMR_SET},
+ {R_BE_CPUIO_ERR_IMR, B_BE_CPUIO_ERR_IMR_CLR, B_BE_CPUIO_ERR_IMR_SET},
+ {R_BE_WDE_ERR_IMR, B_BE_WDE_ERR_IMR_CLR, B_BE_WDE_ERR_IMR_SET},
+ {R_BE_WDE_ERR1_IMR, B_BE_WDE_ERR1_IMR_CLR, B_BE_WDE_ERR1_IMR_SET},
+ {R_BE_PLE_ERR_IMR, B_BE_PLE_ERR_IMR_CLR, B_BE_PLE_ERR_IMR_SET},
+ {R_BE_PLE_ERRFLAG1_IMR, B_BE_PLE_ERRFLAG1_IMR_CLR, B_BE_PLE_ERRFLAG1_IMR_SET},
+ {R_BE_WDRLS_ERR_IMR, B_BE_WDRLS_ERR_IMR_CLR, B_BE_WDRLS_ERR_IMR_SET},
+ {R_BE_TXPKTCTL_B0_ERRFLAG_IMR, B_BE_TXPKTCTL_B0_ERRFLAG_IMR_CLR,
+ B_BE_TXPKTCTL_B0_ERRFLAG_IMR_SET},
+ {R_BE_TXPKTCTL_B1_ERRFLAG_IMR, B_BE_TXPKTCTL_B1_ERRFLAG_IMR_CLR,
+ B_BE_TXPKTCTL_B1_ERRFLAG_IMR_SET},
+ {R_BE_BBRPT_COM_ERR_IMR, B_BE_BBRPT_COM_ERR_IMR_CLR, B_BE_BBRPT_COM_ERR_IMR_SET},
+ {R_BE_BBRPT_CHINFO_ERR_IMR, B_BE_BBRPT_CHINFO_ERR_IMR_CLR,
+ B_BE_BBRPT_CHINFO_ERR_IMR_SET},
+ {R_BE_BBRPT_DFS_ERR_IMR, B_BE_BBRPT_DFS_ERR_IMR_CLR, B_BE_BBRPT_DFS_ERR_IMR_SET},
+ {R_BE_LA_ERRFLAG_IMR, B_BE_LA_ERRFLAG_IMR_CLR, B_BE_LA_ERRFLAG_IMR_SET},
+ {R_BE_CH_INFO_DBGFLAG_IMR, B_BE_CH_INFO_DBGFLAG_IMR_CLR, B_BE_CH_INFO_DBGFLAG_IMR_SET},
+ {R_BE_PLRLS_ERR_IMR, B_BE_PLRLS_ERR_IMR_CLR, B_BE_PLRLS_ERR_IMR_SET},
+ {R_BE_HAXI_IDCT_MSK, B_BE_HAXI_IDCT_MSK_CLR, B_BE_HAXI_IDCT_MSK_SET},
+};
+
+static const struct rtw89_imr_table rtw8922a_imr_dmac_table = {
+ .regs = rtw8922a_imr_dmac_regs,
+ .n_regs = ARRAY_SIZE(rtw8922a_imr_dmac_regs),
+};
+
+static const struct rtw89_reg_imr rtw8922a_imr_cmac_regs[] = {
+ {R_BE_RESP_IMR, B_BE_RESP_IMR_CLR, B_BE_RESP_IMR_SET},
+ {R_BE_RX_ERROR_FLAG_IMR, B_BE_RX_ERROR_FLAG_IMR_CLR, B_BE_RX_ERROR_FLAG_IMR_SET},
+ {R_BE_TX_ERROR_FLAG_IMR, B_BE_TX_ERROR_FLAG_IMR_CLR, B_BE_TX_ERROR_FLAG_IMR_SET},
+ {R_BE_RX_ERROR_FLAG_IMR_1, B_BE_TX_ERROR_FLAG_IMR_1_CLR, B_BE_TX_ERROR_FLAG_IMR_1_SET},
+ {R_BE_PTCL_IMR1, B_BE_PTCL_IMR1_CLR, B_BE_PTCL_IMR1_SET},
+ {R_BE_PTCL_IMR0, B_BE_PTCL_IMR0_CLR, B_BE_PTCL_IMR0_SET},
+ {R_BE_PTCL_IMR_2, B_BE_PTCL_IMR_2_CLR, B_BE_PTCL_IMR_2_SET},
+ {R_BE_SCHEDULE_ERR_IMR, B_BE_SCHEDULE_ERR_IMR_CLR, B_BE_SCHEDULE_ERR_IMR_SET},
+ {R_BE_C0_TXPWR_IMR, B_BE_C0_TXPWR_IMR_CLR, B_BE_C0_TXPWR_IMR_SET},
+ {R_BE_TRXPTCL_ERROR_INDICA_MASK, B_BE_TRXPTCL_ERROR_INDICA_MASK_CLR,
+ B_BE_TRXPTCL_ERROR_INDICA_MASK_SET},
+ {R_BE_RX_ERR_IMR, B_BE_RX_ERR_IMR_CLR, B_BE_RX_ERR_IMR_SET},
+ {R_BE_PHYINFO_ERR_IMR_V1, B_BE_PHYINFO_ERR_IMR_V1_CLR, B_BE_PHYINFO_ERR_IMR_V1_SET},
+};
+
+static const struct rtw89_imr_table rtw8922a_imr_cmac_table = {
+ .regs = rtw8922a_imr_cmac_regs,
+ .n_regs = ARRAY_SIZE(rtw8922a_imr_cmac_regs),
+};
+
+static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = {
+ [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310},
+ [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240},
+ [RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO] = {.offset = 0x20000, .size = 0x4800},
+ [RTW89_EFUSE_BLOCK_HCI_DIG_USB] = {.offset = 0x30000, .size = 0x890},
+ [RTW89_EFUSE_BLOCK_HCI_PHY_PCIE] = {.offset = 0x40000, .size = 0x200},
+ [RTW89_EFUSE_BLOCK_HCI_PHY_USB3] = {.offset = 0x50000, .size = 0x80},
+ [RTW89_EFUSE_BLOCK_HCI_PHY_USB2] = {.offset = 0x60000, .size = 0x0},
+ [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10},
+};
+
+static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev)
+{
+ struct rtw89_hal *hal = &rtwdev->hal;
+ u32 val32;
+ int ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_AFSM_WLSUS_EN |
+ B_BE_AFSM_PCIE_SUS_EN);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_DIS_WLBT_PDNSUSEN_SOPC);
+ rtw89_write32_set(rtwdev, R_BE_WLLPS_CTRL, B_BE_DIS_WLBT_LPSEN_LOPC);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APDM_HPDN);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
+
+ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_RDY_SYSPWR,
+ 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
+ rtw89_write32_set(rtwdev, R_BE_WLRESUME_CTRL, B_BE_LPSROP_CMAC0 |
+ B_BE_LPSROP_CMAC1);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFN_ONMAC);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_APFN_ONMAC),
+ 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_AFE_ON_CTRL1, B_BE_REG_CK_MON_CK960M_EN);
+ rtw89_write8_set(rtwdev, R_BE_ANAPAR_POW_MAC, B_BE_POW_PC_LDO_PORT0 |
+ B_BE_POW_PC_LDO_PORT1);
+ rtw89_write32_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_R_SYM_ISO_ADDA_P02PP |
+ B_BE_R_SYM_ISO_ADDA_P12PP);
+ rtw89_write8_set(rtwdev, R_BE_PLATFORM_ENABLE, B_BE_PLATFORM_EN);
+ rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_HAXIDMA_IO_ST,
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_BACKUP_RESTORE_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, val32 & B_BE_HCI_WLAN_IO_ST,
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_SDIO_CTRL, B_BE_PCIE_FORCE_IBX_EN);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x02, 0x02);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x01, 0x01);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC1_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x40, 0x40);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC0_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x20, 0x20);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x04, 0x04);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x08, 0x08);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x10);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xEB, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xEB, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x01, 0x01);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x02, 0x02);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x80);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XREF_RF1, 0, 0x40);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_XREF_RF2, 0, 0x40);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL_1, 0x40, 0x60);
+ if (ret)
+ return ret;
+
+ if (hal->cv != CHIP_CAV) {
+ rtw89_write32_set(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+ rtw89_write32_set(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_ISO_EB2CORE);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_B);
+
+ mdelay(1);
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ISO_CTRL, B_BE_PWC_EV2EF_S);
+ rtw89_write32_clr(rtwdev, R_BE_PMC_DBG_CTRL2, B_BE_SYSON_DIS_PMCR_BE_WRMSK);
+ }
+
+ rtw89_write32_set(rtwdev, R_BE_DMAC_FUNC_EN,
+ B_BE_MAC_FUNC_EN | B_BE_DMAC_FUNC_EN | B_BE_MPDU_PROC_EN |
+ B_BE_WD_RLS_EN | B_BE_DLE_WDE_EN | B_BE_TXPKT_CTRL_EN |
+ B_BE_STA_SCH_EN | B_BE_DLE_PLE_EN | B_BE_PKT_BUF_EN |
+ B_BE_DMAC_TBL_EN | B_BE_PKT_IN_EN | B_BE_DLE_CPUIO_EN |
+ B_BE_DISPATCHER_EN | B_BE_BBRPT_EN | B_BE_MAC_SEC_EN |
+ B_BE_H_AXIDMA_EN | B_BE_DMAC_MLO_EN | B_BE_PLRLS_EN |
+ B_BE_P_AXIDMA_EN | B_BE_DLE_DATACPUIO_EN | B_BE_LTR_CTL_EN);
+
+ set_bit(RTW89_FLAG_DMAC_FUNC, rtwdev->flags);
+
+ rtw89_write32_set(rtwdev, R_BE_CMAC_SHARE_FUNC_EN,
+ B_BE_CMAC_SHARE_EN | B_BE_RESPBA_EN | B_BE_ADDRSRCH_EN |
+ B_BE_BTCOEX_EN);
+ rtw89_write32_set(rtwdev, R_BE_CMAC_FUNC_EN,
+ B_BE_CMAC_EN | B_BE_CMAC_TXEN | B_BE_CMAC_RXEN |
+ B_BE_SIGB_EN | B_BE_PHYINTF_EN | B_BE_CMAC_DMA_EN |
+ B_BE_PTCLTOP_EN | B_BE_SCHEDULER_EN | B_BE_TMAC_EN |
+ B_BE_RMAC_EN | B_BE_TXTIME_EN | B_BE_RESP_PKTCTL_EN);
+
+ set_bit(RTW89_FLAG_CMAC0_FUNC, rtwdev->flags);
+
+ rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN |
+ B_BE_FEN_BBPLAT_RSTB);
+
+ return 0;
+}
+
+static int rtw8922a_pwr_off_func(struct rtw89_dev *rtwdev)
+{
+ u32 val32;
+ int ret;
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x10, 0x10);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x08);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x04);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S0, 0xC6, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_WL_RFC_S1, 0xC6, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0x80, 0x80);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x02);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x01);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x02, 0xFF);
+ if (ret)
+ return ret;
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_PLL, 0x00, 0xFF);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_R_SYM_ISO_ADDA_P02PP |
+ B_BE_R_SYM_ISO_ADDA_P12PP);
+ rtw89_write8_clr(rtwdev, R_BE_ANAPAR_POW_MAC, B_BE_POW_PC_LDO_PORT0 |
+ B_BE_POW_PC_LDO_PORT1);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_EN_WLON);
+ rtw89_write8_clr(rtwdev, R_BE_FEN_RST_ENABLE, B_BE_FEN_BB_IP_RSTN |
+ B_BE_FEN_BBPLAT_RSTB);
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC0_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x20);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_SYS_ADIE_PAD_PWR_CTRL, B_BE_SYM_PADPDN_WL_RFC1_1P3);
+
+ ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, 0, 0x40);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HAXIDMA_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_IO_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HAXIDMA_BACKUP_RESTORE_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_clr(rtwdev, R_BE_HCI_OPT_CTRL, B_BE_HCI_WLAN_IO_EN);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_HCI_WLAN_IO_ST),
+ 1000, 3000000, false, rtwdev, R_BE_HCI_OPT_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_OFFMAC);
+
+ ret = read_poll_timeout(rtw89_read32, val32, !(val32 & B_BE_APFM_OFFMAC),
+ 1000, 3000000, false, rtwdev, R_BE_SYS_PW_CTRL);
+ if (ret)
+ return ret;
+
+ rtw89_write32(rtwdev, R_BE_WLLPS_CTRL, 0x0000A1B2);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_XTAL_OFF_A_DIE);
+ rtw89_write32_set(rtwdev, R_BE_SYS_PW_CTRL, B_BE_APFM_SWLPS);
+ rtw89_write32(rtwdev, R_BE_UDM1, 0);
+
+ return 0;
+}
+
+static void rtw8922a_efuse_parsing_tssi(struct rtw89_dev *rtwdev,
+ struct rtw8922a_efuse *map)
+{
+ struct rtw8922a_tssi_offset *ofst[] = {&map->path_a_tssi, &map->path_b_tssi};
+ u8 *bw40_1s_tssi_6g_ofst[] = {map->bw40_1s_tssi_6g_a, map->bw40_1s_tssi_6g_b};
+ struct rtw89_tssi_info *tssi = &rtwdev->tssi;
+ u8 i, j;
+
+ tssi->thermal[RF_PATH_A] = map->path_a_therm;
+ tssi->thermal[RF_PATH_B] = map->path_b_therm;
+
+ for (i = 0; i < RF_PATH_NUM_8922A; i++) {
+ memcpy(tssi->tssi_cck[i], ofst[i]->cck_tssi,
+ sizeof(ofst[i]->cck_tssi));
+
+ for (j = 0; j < TSSI_CCK_CH_GROUP_NUM; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][EFUSE] path=%d cck[%d]=0x%x\n",
+ i, j, tssi->tssi_cck[i][j]);
+
+ memcpy(tssi->tssi_mcs[i], ofst[i]->bw40_tssi,
+ sizeof(ofst[i]->bw40_tssi));
+ memcpy(tssi->tssi_mcs[i] + TSSI_MCS_2G_CH_GROUP_NUM,
+ ofst[i]->bw40_1s_tssi_5g, sizeof(ofst[i]->bw40_1s_tssi_5g));
+ memcpy(tssi->tssi_6g_mcs[i], bw40_1s_tssi_6g_ofst[i],
+ sizeof(tssi->tssi_6g_mcs[i]));
+
+ for (j = 0; j < TSSI_MCS_CH_GROUP_NUM; j++)
+ rtw89_debug(rtwdev, RTW89_DBG_TSSI,
+ "[TSSI][EFUSE] path=%d mcs[%d]=0x%x\n",
+ i, j, tssi->tssi_mcs[i][j]);
+ }
+}
+
+static void rtw8922a_efuse_parsing_gain_offset(struct rtw89_dev *rtwdev,
+ struct rtw8922a_efuse *map)
+{
+ struct rtw89_phy_efuse_gain *gain = &rtwdev->efuse_gain;
+ bool all_0xff = true, all_0x00 = true;
+ int i, j;
+ u8 t;
+
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_a._2g_cck;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_CCK] = map->rx_gain_b._2g_cck;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_a._2g_ofdm;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_2G_OFDM] = map->rx_gain_b._2g_ofdm;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_a._5g_low;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_LOW] = map->rx_gain_b._5g_low;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_a._5g_mid;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_MID] = map->rx_gain_b._5g_mid;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_a._5g_high;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_5G_HIGH] = map->rx_gain_b._5g_high;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_a._6g_l0;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L0] = map->rx_gain_6g_b._6g_l0;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_a._6g_l1;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_L1] = map->rx_gain_6g_b._6g_l1;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_a._6g_m0;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M0] = map->rx_gain_6g_b._6g_m0;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_a._6g_m1;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_M1] = map->rx_gain_6g_b._6g_m1;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_a._6g_h0;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H0] = map->rx_gain_6g_b._6g_h0;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_a._6g_h1;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_H1] = map->rx_gain_6g_b._6g_h1;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_a._6g_uh0;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH0] = map->rx_gain_6g_b._6g_uh0;
+ gain->offset[RF_PATH_A][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_a._6g_uh1;
+ gain->offset[RF_PATH_B][RTW89_GAIN_OFFSET_6G_UH1] = map->rx_gain_6g_b._6g_uh1;
+
+ for (i = RF_PATH_A; i <= RF_PATH_B; i++)
+ for (j = 0; j < RTW89_GAIN_OFFSET_NR; j++) {
+ t = gain->offset[i][j];
+ if (t != 0xff)
+ all_0xff = false;
+ if (t != 0x0)
+ all_0x00 = false;
+
+ /* transform: sign-bit + U(7,2) to S(8,2) */
+ if (t & 0x80)
+ gain->offset[i][j] = (t ^ 0x7f) + 1;
+ }
+
+ gain->offset_valid = !all_0xff && !all_0x00;
+}
+
+static void rtw8922a_read_efuse_mac_addr(struct rtw89_dev *rtwdev, u32 addr)
+{
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+ u16 val;
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i += 2, addr += 2) {
+ val = rtw89_read16(rtwdev, addr);
+ efuse->addr[i] = val & 0xff;
+ efuse->addr[i + 1] = val >> 8;
+ }
+}
+
+static int rtw8922a_read_efuse_pci_sdio(struct rtw89_dev *rtwdev, u8 *log_map)
+{
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+ if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE)
+ rtw8922a_read_efuse_mac_addr(rtwdev, 0x3104);
+ else
+ ether_addr_copy(efuse->addr, log_map + 0x001A);
+
+ return 0;
+}
+
+static int rtw8922a_read_efuse_usb(struct rtw89_dev *rtwdev, u8 *log_map)
+{
+ rtw8922a_read_efuse_mac_addr(rtwdev, 0x4078);
+
+ return 0;
+}
+
+static int rtw8922a_read_efuse_rf(struct rtw89_dev *rtwdev, u8 *log_map)
+{
+ struct rtw8922a_efuse *map = (struct rtw8922a_efuse *)log_map;
+ struct rtw89_efuse *efuse = &rtwdev->efuse;
+
+ efuse->rfe_type = map->rfe_type;
+ efuse->xtal_cap = map->xtal_k;
+ efuse->country_code[0] = map->country_code[0];
+ efuse->country_code[1] = map->country_code[1];
+ rtw8922a_efuse_parsing_tssi(rtwdev, map);
+ rtw8922a_efuse_parsing_gain_offset(rtwdev, map);
+
+ rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type);
+
+ return 0;
+}
+
+static int rtw8922a_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map,
+ enum rtw89_efuse_block block)
+{
+ switch (block) {
+ case RTW89_EFUSE_BLOCK_HCI_DIG_PCIE_SDIO:
+ return rtw8922a_read_efuse_pci_sdio(rtwdev, log_map);
+ case RTW89_EFUSE_BLOCK_HCI_DIG_USB:
+ return rtw8922a_read_efuse_usb(rtwdev, log_map);
+ case RTW89_EFUSE_BLOCK_RF:
+ return rtw8922a_read_efuse_rf(rtwdev, log_map);
+ default:
+ return 0;
+ }
+}
+
+#define THM_TRIM_POSITIVE_MASK BIT(6)
+#define THM_TRIM_MAGNITUDE_MASK GENMASK(5, 0)
+
+static void rtw8922a_phycap_parsing_thermal_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 thm_trim_addr[RF_PATH_NUM_8922A] = {0x1706, 0x1733};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ bool pg = true;
+ u8 pg_th;
+ s8 val;
+ u8 i;
+
+ for (i = 0; i < RF_PATH_NUM_8922A; i++) {
+ pg_th = phycap_map[thm_trim_addr[i] - addr];
+ if (pg_th == 0xff) {
+ info->thermal_trim[i] = 0;
+ pg = false;
+ break;
+ }
+
+ val = u8_get_bits(pg_th, THM_TRIM_MAGNITUDE_MASK);
+
+ if (!(pg_th & THM_TRIM_POSITIVE_MASK))
+ val *= -1;
+
+ info->thermal_trim[i] = val;
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[THERMAL][TRIM] path=%d thermal_trim=0x%x (%d)\n",
+ i, pg_th, val);
+ }
+
+ info->pg_thermal_trim = pg;
+}
+
+static void rtw8922a_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 pabias_trim_addr[RF_PATH_NUM_8922A] = {0x1707, 0x1734};
+ static const u32 check_pa_pad_trim_addr = 0x1700;
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ u8 val;
+ u8 i;
+
+ val = phycap_map[check_pa_pad_trim_addr - addr];
+ if (val != 0xff)
+ info->pg_pa_bias_trim = true;
+
+ for (i = 0; i < RF_PATH_NUM_8922A; i++) {
+ info->pa_bias_trim[i] = phycap_map[pabias_trim_addr[i] - addr];
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PA_BIAS][TRIM] path=%d pa_bias_trim=0x%x\n",
+ i, info->pa_bias_trim[i]);
+ }
+}
+
+static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev,
+ u8 *phycap_map)
+{
+ static const u32 pad_bias_trim_addr[RF_PATH_NUM_8922A] = {0x1708, 0x1735};
+ struct rtw89_power_trim_info *info = &rtwdev->pwr_trim;
+ u32 addr = rtwdev->chip->phycap_addr;
+ u8 i;
+
+ for (i = 0; i < RF_PATH_NUM_8922A; i++) {
+ info->pad_bias_trim[i] = phycap_map[pad_bias_trim_addr[i] - addr];
+
+ rtw89_debug(rtwdev, RTW89_DBG_RFK,
+ "[PAD_BIAS][TRIM] path=%d pad_bias_trim=0x%x\n",
+ i, info->pad_bias_trim[i]);
+ }
+}
+
+static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map)
+{
+ rtw8922a_phycap_parsing_thermal_trim(rtwdev, phycap_map);
+ rtw8922a_phycap_parsing_pa_bias_trim(rtwdev, phycap_map);
+ rtw8922a_phycap_parsing_pad_bias_trim(rtwdev, phycap_map);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+ .n_patterns = RTW89_MAX_PATTERN_NUM,
+ .pattern_max_len = RTW89_MAX_PATTERN_SIZE,
+ .pattern_min_len = 1,
+};
+#endif
+
+static const struct rtw89_chip_ops rtw8922a_chip_ops = {
+ .read_efuse = rtw8922a_read_efuse,
+ .read_phycap = rtw8922a_read_phycap,
+ .pwr_on_func = rtw8922a_pwr_on_func,
+ .pwr_off_func = rtw8922a_pwr_off_func,
+};
+
+const struct rtw89_chip_info rtw8922a_chip_info = {
+ .chip_id = RTL8922A,
+ .chip_gen = RTW89_CHIP_BE,
+ .ops = &rtw8922a_chip_ops,
+ .mac_def = &rtw89_mac_gen_be,
+ .phy_def = &rtw89_phy_gen_be,
+ .fw_basename = RTW8922A_FW_BASENAME,
+ .fw_format_max = RTW8922A_FW_FORMAT_MAX,
+ .try_ce_fw = false,
+ .bbmcu_nr = 1,
+ .needed_fw_elms = RTW89_BE_GEN_DEF_NEEDED_FW_ELEMENTS,
+ .fifo_size = 589824,
+ .small_fifo_size = false,
+ .dle_scc_rsvd_size = 0,
+ .max_amsdu_limit = 8000,
+ .dis_2g_40m_ul_ofdma = false,
+ .rsvd_ple_ofst = 0x8f800,
+ .hfc_param_ini = rtw8922a_hfc_param_ini_pcie,
+ .dle_mem = rtw8922a_dle_mem_pcie,
+ .wde_qempty_acq_grpnum = 4,
+ .wde_qempty_mgq_grpsel = 4,
+ .rf_base_addr = {0xe000, 0xf000},
+ .pwr_on_seq = NULL,
+ .pwr_off_seq = NULL,
+ .bb_table = NULL,
+ .bb_gain_table = NULL,
+ .rf_table = {},
+ .nctl_table = NULL,
+ .nctl_post_table = NULL,
+ .dflt_parms = NULL, /* load parm from fw */
+ .rfe_parms_conf = NULL, /* load parm from fw */
+ .txpwr_factor_rf = 2,
+ .txpwr_factor_mac = 1,
+ .dig_table = NULL,
+ .tssi_dbw_table = NULL,
+ .support_chanctx_num = 1,
+ .support_bands = BIT(NL80211_BAND_2GHZ) |
+ BIT(NL80211_BAND_5GHZ) |
+ BIT(NL80211_BAND_6GHZ),
+ .support_unii4 = true,
+ .ul_tb_waveform_ctrl = false,
+ .ul_tb_pwr_diff = false,
+ .hw_sec_hdr = true,
+ .rf_path_num = 2,
+ .tx_nss = 2,
+ .rx_nss = 2,
+ .acam_num = 128,
+ .bcam_num = 20,
+ .scam_num = 32,
+ .bacam_num = 8,
+ .bacam_dynamic_num = 8,
+ .bacam_ver = RTW89_BACAM_V1,
+ .ppdu_max_usr = 16,
+ .sec_ctrl_efuse_size = 4,
+ .physical_efuse_size = 0x1300,
+ .logical_efuse_size = 0x70000,
+ .limit_efuse_size = 0x40000,
+ .dav_phy_efuse_size = 0,
+ .dav_log_efuse_size = 0,
+ .efuse_blocks = rtw8922a_efuse_blocks,
+ .phycap_addr = 0x1700,
+ .phycap_size = 0x38,
+
+ .ps_mode_supported = BIT(RTW89_PS_MODE_RFOFF) |
+ BIT(RTW89_PS_MODE_CLK_GATED) |
+ BIT(RTW89_PS_MODE_PWR_GATED),
+ .low_power_hci_modes = 0,
+ .hci_func_en_addr = R_BE_HCI_FUNC_EN,
+ .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2),
+ .txwd_body_size = sizeof(struct rtw89_txwd_body_v2),
+ .txwd_info_size = sizeof(struct rtw89_txwd_info_v2),
+ .cfo_src_fd = true,
+ .cfo_hw_comp = true,
+ .dcfo_comp = NULL,
+ .dcfo_comp_sft = 0,
+ .imr_info = NULL,
+ .imr_dmac_table = &rtw8922a_imr_dmac_table,
+ .imr_cmac_table = &rtw8922a_imr_cmac_table,
+ .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2},
+ .bss_clr_map_reg = R_BSS_CLR_MAP_V2,
+ .dma_ch_mask = 0,
+#ifdef CONFIG_PM
+ .wowlan_stub = &rtw_wowlan_stub_8922a,
+#endif
+ .xtal_info = NULL,
+};
+EXPORT_SYMBOL(rtw8922a_chip_info);
+
+MODULE_FIRMWARE(RTW8922A_MODULE_FIRMWARE);
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11be wireless 8922A driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.h b/drivers/net/wireless/realtek/rtw89/rtw8922a.h
new file mode 100644
index 000000000000..597317ab6af7
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#ifndef __RTW89_8922A_H__
+#define __RTW89_8922A_H__
+
+#include "core.h"
+
+#define RF_PATH_NUM_8922A 2
+#define BB_PATH_NUM_8922A 2
+
+struct rtw8922a_tssi_offset {
+ u8 cck_tssi[TSSI_CCK_CH_GROUP_NUM];
+ u8 bw40_tssi[TSSI_MCS_2G_CH_GROUP_NUM];
+ u8 rsvd[7];
+ u8 bw40_1s_tssi_5g[TSSI_MCS_5G_CH_GROUP_NUM];
+ u8 bw_diff_5g[10];
+} __packed;
+
+struct rtw8922a_rx_gain {
+ u8 _2g_ofdm;
+ u8 _2g_cck;
+ u8 _5g_low;
+ u8 _5g_mid;
+ u8 _5g_high;
+} __packed;
+
+struct rtw8922a_rx_gain_6g {
+ u8 _6g_l0;
+ u8 _6g_l1;
+ u8 _6g_m0;
+ u8 _6g_m1;
+ u8 _6g_h0;
+ u8 _6g_h1;
+ u8 _6g_uh0;
+ u8 _6g_uh1;
+} __packed;
+
+struct rtw8922a_efuse {
+ u8 country_code[2];
+ u8 rsvd[0xe];
+ struct rtw8922a_tssi_offset path_a_tssi;
+ struct rtw8922a_tssi_offset path_b_tssi;
+ u8 rsvd1[0x54];
+ u8 channel_plan;
+ u8 xtal_k;
+ u8 rsvd2[0x7];
+ u8 board_info;
+ u8 rsvd3[0x8];
+ u8 rfe_type;
+ u8 rsvd4[0x5];
+ u8 path_a_therm;
+ u8 path_b_therm;
+ u8 rsvd5[0x2];
+ struct rtw8922a_rx_gain rx_gain_a;
+ struct rtw8922a_rx_gain rx_gain_b;
+ u8 rsvd6[0x22];
+ u8 bw40_1s_tssi_6g_a[TSSI_MCS_6G_CH_GROUP_NUM];
+ u8 rsvd7[0xa];
+ u8 bw40_1s_tssi_6g_b[TSSI_MCS_6G_CH_GROUP_NUM];
+ u8 rsvd8[0xa];
+ u8 bw40_1s_tssi_6g_c[TSSI_MCS_6G_CH_GROUP_NUM];
+ u8 rsvd9[0xa];
+ u8 bw40_1s_tssi_6g_d[TSSI_MCS_6G_CH_GROUP_NUM];
+ u8 rsvd10[0xa];
+ struct rtw8922a_rx_gain_6g rx_gain_6g_a;
+ struct rtw8922a_rx_gain_6g rx_gain_6g_b;
+} __packed;
+
+extern const struct rtw89_chip_info rtw8922a_chip_info;
+
+#endif
diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
new file mode 100644
index 000000000000..7b3d98d2c402
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright(c) 2023 Realtek Corporation
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "pci.h"
+#include "reg.h"
+#include "rtw8922a.h"
+
+static const struct rtw89_pci_info rtw8922a_pci_info = {
+ .gen_def = &rtw89_pci_gen_be,
+ .txbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_trunc_mode = MAC_AX_BD_TRUNC,
+ .rxbd_mode = MAC_AX_RXBD_PKT,
+ .tag_mode = MAC_AX_TAG_MULTI,
+ .tx_burst = MAC_AX_TX_BURST_V1_256B,
+ .rx_burst = MAC_AX_RX_BURST_V1_128B,
+ .wd_dma_idle_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .wd_dma_act_intvl = MAC_AX_WD_DMA_INTVL_256NS,
+ .multi_tag_num = MAC_AX_TAG_NUM_8,
+ .lbc_en = MAC_AX_PCIE_ENABLE,
+ .lbc_tmr = MAC_AX_LBC_TMR_2MS,
+ .autok_en = MAC_AX_PCIE_DISABLE,
+ .io_rcy_en = MAC_AX_PCIE_ENABLE,
+ .io_rcy_tmr = MAC_AX_IO_RCY_ANA_TMR_DEF,
+ .rx_ring_eq_is_full = true,
+
+ .init_cfg_reg = R_BE_HAXI_INIT_CFG1,
+ .txhci_en_bit = B_BE_TXDMA_EN,
+ .rxhci_en_bit = B_BE_RXDMA_EN,
+ .rxbd_mode_bit = B_BE_RXQ_RXBD_MODE_MASK,
+ .exp_ctrl_reg = R_BE_HAXI_EXP_CTRL_V1,
+ .max_tag_num_mask = B_BE_MAX_TAG_NUM_MASK,
+ .rxbd_rwptr_clr_reg = R_BE_RXBD_RWPTR_CLR1_V1,
+ .txbd_rwptr_clr2_reg = R_BE_TXBD_RWPTR_CLR1,
+ .dma_io_stop = {R_BE_HAXI_INIT_CFG1, B_BE_STOP_AXI_MST},
+ .dma_stop1 = {R_BE_HAXI_DMA_STOP1, B_BE_TX_STOP1_MASK},
+ .dma_stop2 = {0},
+ .dma_busy1 = {R_BE_HAXI_DMA_BUSY1, DMA_BUSY1_CHECK_BE},
+ .dma_busy2_reg = 0,
+ .dma_busy3_reg = R_BE_HAXI_DMA_BUSY1,
+
+ .rpwm_addr = R_BE_PCIE_HRPWM,
+ .cpwm_addr = R_BE_PCIE_CRPWM,
+ .mit_addr = R_BE_PCIE_MIT_CH_EN,
+ .tx_dma_ch_mask = 0,
+ .bd_idx_addr_low_power = NULL,
+ .dma_addr_set = &rtw89_pci_ch_dma_addr_set_be,
+ .bd_ram_table = NULL,
+
+ .ltr_set = rtw89_pci_ltr_set_v2,
+ .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1,
+ .config_intr_mask = rtw89_pci_config_intr_mask_v2,
+ .enable_intr = rtw89_pci_enable_intr_v2,
+ .disable_intr = rtw89_pci_disable_intr_v2,
+ .recognize_intrs = rtw89_pci_recognize_intrs_v2,
+};
+
+static const struct rtw89_driver_info rtw89_8922ae_info = {
+ .chip = &rtw8922a_chip_info,
+ .bus = {
+ .pci = &rtw8922a_pci_info,
+ },
+};
+
+static const struct pci_device_id rtw89_8922ae_id_table[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8922),
+ .driver_data = (kernel_ulong_t)&rtw89_8922ae_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, rtw89_8922ae_id_table);
+
+static struct pci_driver rtw89_8922ae_driver = {
+ .name = "rtw89_8922ae",
+ .id_table = rtw89_8922ae_id_table,
+ .probe = rtw89_pci_probe,
+ .remove = rtw89_pci_remove,
+ .driver.pm = &rtw89_pm_ops,
+};
+module_pci_driver(rtw89_8922ae_driver);
+
+MODULE_AUTHOR("Realtek Corporation");
+MODULE_DESCRIPTION("Realtek 802.11be wireless 8922AE driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c
index aed05b026c6c..1b2a400406ae 100644
--- a/drivers/net/wireless/realtek/rtw89/sar.c
+++ b/drivers/net/wireless/realtek/rtw89/sar.c
@@ -404,16 +404,18 @@ out:
void rtw89_tas_init(struct rtw89_dev *rtwdev)
{
struct rtw89_tas_info *tas = &rtwdev->tas;
+ struct rtw89_acpi_dsm_result res = {};
int ret;
u8 val;
- ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &val);
+ ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_TAS_EN, &res);
if (ret) {
rtw89_debug(rtwdev, RTW89_DBG_SAR,
"acpi: cannot get TAS: %d\n", ret);
return;
}
+ val = res.u.value;
switch (val) {
case 0:
tas->enable = false;
diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c
index c1644353053f..99896d85d2f8 100644
--- a/drivers/net/wireless/realtek/rtw89/ser.c
+++ b/drivers/net/wireless/realtek/rtw89/ser.c
@@ -361,6 +361,9 @@ static int hal_enable_dma(struct rtw89_ser *ser)
ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_2);
if (!ret)
clear_bit(RTW89_SER_HAL_STOP_DMA, ser->flags);
+ else
+ rtw89_debug(rtwdev, RTW89_DBG_SER,
+ "lv1 rcvy fail to start dma: %d\n", ret);
return ret;
}
@@ -376,6 +379,9 @@ static int hal_stop_dma(struct rtw89_ser *ser)
ret = rtwdev->hci.ops->mac_lv1_rcvy(rtwdev, RTW89_LV1_RCVY_STEP_1);
if (!ret)
set_bit(RTW89_SER_HAL_STOP_DMA, ser->flags);
+ else
+ rtw89_debug(rtwdev, RTW89_DBG_SER,
+ "lv1 rcvy fail to stop dma: %d\n", ret);
return ret;
}
@@ -584,6 +590,14 @@ struct __fw_backtrace_info {
static_assert(RTW89_FW_BACKTRACE_INFO_SIZE ==
sizeof(struct __fw_backtrace_info));
+static u32 convert_addr_from_wcpu(u32 wcpu_addr)
+{
+ if (wcpu_addr < 0x30000000)
+ return wcpu_addr;
+
+ return wcpu_addr & GENMASK(28, 0);
+}
+
static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf,
const struct __fw_backtrace_entry *ent)
{
@@ -591,7 +605,7 @@ static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf,
const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
u32 filter_model_addr = mac->filter_model_addr;
u32 indir_access_addr = mac->indir_access_addr;
- u32 fwbt_addr = ent->wcpu_addr & RTW89_WCPU_BASE_MASK;
+ u32 fwbt_addr = convert_addr_from_wcpu(ent->wcpu_addr);
u32 fwbt_size = ent->size;
u32 fwbt_key = ent->key;
u32 i;
diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h
index 7142cce167de..c467a80ffa88 100644
--- a/drivers/net/wireless/realtek/rtw89/txrx.h
+++ b/drivers/net/wireless/realtek/rtw89/txrx.h
@@ -416,8 +416,11 @@ struct rtw89_rxinfo {
} __packed;
#define RTW89_RXINFO_W0_USR_NUM GENMASK(3, 0)
+#define RTW89_RXINFO_W0_USR_NUM_V1 GENMASK(4, 0)
#define RTW89_RXINFO_W0_FW_DEFINE GENMASK(15, 8)
+#define RTW89_RXINFO_W0_PLCP_LEN_V1 GENMASK(23, 16)
#define RTW89_RXINFO_W0_LSIG_LEN GENMASK(27, 16)
+#define RTW89_RXINFO_W0_INVALID_V1 BIT(27)
#define RTW89_RXINFO_W0_IS_TO_SELF BIT(28)
#define RTW89_RXINFO_W0_RX_CNT_VLD BIT(29)
#define RTW89_RXINFO_W0_LONG_RXD GENMASK(31, 30)
@@ -430,6 +433,7 @@ struct rtw89_phy_sts_hdr {
} __packed;
#define RTW89_PHY_STS_HDR_W0_IE_MAP GENMASK(4, 0)
+#define RTW89_PHY_STS_HDR_W0_VALID BIT(7)
#define RTW89_PHY_STS_HDR_W0_LEN GENMASK(15, 8)
#define RTW89_PHY_STS_HDR_W0_RSSI_AVG GENMASK(31, 24)
#define RTW89_PHY_STS_HDR_W1_RSSI_A GENMASK(7, 0)
diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c
index 660bf2ece927..5c7ca36c09b6 100644
--- a/drivers/net/wireless/realtek/rtw89/wow.c
+++ b/drivers/net/wireless/realtek/rtw89/wow.c
@@ -73,13 +73,14 @@ static int rtw89_wow_config_mac(struct rtw89_dev *rtwdev, bool enable_wow)
static void rtw89_wow_set_rx_filter(struct rtw89_dev *rtwdev, bool enable)
{
+ const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def;
enum rtw89_mac_fwd_target fwd_target = enable ?
RTW89_FWD_DONT_CARE :
RTW89_FWD_TO_HOST;
- rtw89_mac_typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0);
- rtw89_mac_typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0);
- rtw89_mac_typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0);
+ mac->typ_fltr_opt(rtwdev, RTW89_MGNT, fwd_target, RTW89_MAC_0);
+ mac->typ_fltr_opt(rtwdev, RTW89_CTRL, fwd_target, RTW89_MAC_0);
+ mac->typ_fltr_opt(rtwdev, RTW89_DATA, fwd_target, RTW89_MAC_0);
}
static void rtw89_wow_show_wakeup_reason(struct rtw89_dev *rtwdev)
diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c
index 1b6c158457b4..537caf9d914a 100644
--- a/drivers/net/wireless/silabs/wfx/sta.c
+++ b/drivers/net/wireless/silabs/wfx/sta.c
@@ -336,29 +336,38 @@ static int wfx_upload_ap_templates(struct wfx_vif *wvif)
return 0;
}
-static void wfx_set_mfp_ap(struct wfx_vif *wvif)
+static int wfx_set_mfp_ap(struct wfx_vif *wvif)
{
struct ieee80211_vif *vif = wvif_to_vif(wvif);
struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0);
const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
- const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,
- skb->len - ieoffset);
const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16);
const int pairwise_cipher_suite_size = 4 / sizeof(u16);
const int akm_suite_size = 4 / sizeof(u16);
+ const u16 *ptr;
- if (ptr) {
- ptr += pairwise_cipher_suite_count_offset;
- if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
- return;
- ptr += 1 + pairwise_cipher_suite_size * *ptr;
- if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
- return;
- ptr += 1 + akm_suite_size * *ptr;
- if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
- return;
- wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6));
- }
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,
+ skb->len - ieoffset);
+ if (unlikely(!ptr))
+ return -EINVAL;
+
+ ptr += pairwise_cipher_suite_count_offset;
+ if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
+ return -EINVAL;
+
+ ptr += 1 + pairwise_cipher_suite_size * *ptr;
+ if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
+ return -EINVAL;
+
+ ptr += 1 + akm_suite_size * *ptr;
+ if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
+ return -EINVAL;
+
+ wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6));
+ return 0;
}
int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -376,8 +385,7 @@ int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
ret = wfx_hif_start(wvif, &vif->bss_conf, wvif->channel);
if (ret > 0)
return -EIO;
- wfx_set_mfp_ap(wvif);
- return ret;
+ return wfx_set_mfp_ap(wvif);
}
void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index 301bd0043a43..4e5b351f80f0 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -343,5 +343,6 @@ static void __exit wl1251_sdio_exit(void)
module_init(wl1251_sdio_init);
module_exit(wl1251_sdio_exit);
+MODULE_DESCRIPTION("TI WL1251 SDIO helpers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c
index 29292f06bd3d..1936bb3af54a 100644
--- a/drivers/net/wireless/ti/wl1251/spi.c
+++ b/drivers/net/wireless/ti/wl1251/spi.c
@@ -342,6 +342,7 @@ static struct spi_driver wl1251_spi_driver = {
module_spi_driver(wl1251_spi_driver);
+MODULE_DESCRIPTION("TI WL1251 SPI helpers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
MODULE_ALIAS("spi:wl1251");
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index de045fe4ca1e..b26d42b4e3cc 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -1955,6 +1955,7 @@ module_param_named(tcxo, tcxo_param, charp, 0);
MODULE_PARM_DESC(tcxo,
"TCXO clock: 19.2, 26, 38.4, 52, 16.368, 32.736, 16.8, 33.6");
+MODULE_DESCRIPTION("TI WL12xx wireless driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE);
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 20d9181b3410..2ccac1cdec01 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -2086,6 +2086,7 @@ module_param_named(num_rx_desc, num_rx_desc_param, int, 0400);
MODULE_PARM_DESC(num_rx_desc_param,
"Number of Rx descriptors: u8 (default is 32)");
+MODULE_DESCRIPTION("TI WiLink 8 wireless driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_FIRMWARE(WL18XX_FW_NAME);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index fb9ed97774c7..5736acb4d206 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -6793,6 +6793,7 @@ MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
module_param(no_recovery, int, 0600);
MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck.");
+MODULE_DESCRIPTION("TI WLAN core driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c
index f0686635db46..eb5482ed76ae 100644
--- a/drivers/net/wireless/ti/wlcore/sdio.c
+++ b/drivers/net/wireless/ti/wlcore/sdio.c
@@ -447,6 +447,7 @@ module_sdio_driver(wl1271_sdio_driver);
module_param(dump, bool, 0600);
MODULE_PARM_DESC(dump, "Enable sdio read/write dumps.");
+MODULE_DESCRIPTION("TI WLAN SDIO helpers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c
index 7d9a139db59e..0aa2b2f3c5c9 100644
--- a/drivers/net/wireless/ti/wlcore/spi.c
+++ b/drivers/net/wireless/ti/wlcore/spi.c
@@ -562,6 +562,7 @@ static struct spi_driver wl1271_spi_driver = {
};
module_spi_driver(wl1271_spi_driver);
+MODULE_DESCRIPTION("TI WLAN SPI helpers");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index c7b4414cc6c3..a84340c2075f 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -190,10 +190,25 @@ static const struct ieee80211_regdomain hwsim_world_regdom_custom_03 = {
}
};
+static const struct ieee80211_regdomain hwsim_world_regdom_custom_04 = {
+ .n_reg_rules = 6,
+ .alpha2 = "99",
+ .reg_rules = {
+ REG_RULE(2412 - 10, 2462 + 10, 40, 0, 20, 0),
+ REG_RULE(2484 - 10, 2484 + 10, 40, 0, 20, 0),
+ REG_RULE(5150 - 10, 5240 + 10, 80, 0, 30, 0),
+ REG_RULE(5260 - 10, 5320 + 10, 80, 0, 30,
+ NL80211_RRF_DFS_CONCURRENT | NL80211_RRF_DFS),
+ REG_RULE(5745 - 10, 5825 + 10, 80, 0, 30, 0),
+ REG_RULE(5855 - 10, 5925 + 10, 80, 0, 33, 0),
+ }
+};
+
static const struct ieee80211_regdomain *hwsim_world_regdom_custom[] = {
&hwsim_world_regdom_custom_01,
&hwsim_world_regdom_custom_02,
&hwsim_world_regdom_custom_03,
+ &hwsim_world_regdom_custom_04,
};
struct hwsim_vif_priv {
@@ -4029,6 +4044,8 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = {
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3,
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
+ .phy_cap_info[0] =
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
@@ -4134,6 +4151,8 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = {
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3,
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
+ .phy_cap_info[0] =
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
@@ -4237,6 +4256,8 @@ static const struct ieee80211_sband_iftype_data sband_capa_2ghz[] = {
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3,
.mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU,
+ .phy_cap_info[0] =
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G,
.phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK |
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
@@ -5288,6 +5309,10 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
schedule_timeout_interruptible(1);
}
+ /* TODO: Add param */
+ wiphy_ext_feature_set(hw->wiphy,
+ NL80211_EXT_FEATURE_DFS_CONCURRENT);
+
if (param->no_vif)
ieee80211_hw_set(hw, NO_AUTO_VIF);
diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig
index 08574433df66..839e1217e855 100644
--- a/drivers/net/wireless/zydas/Kconfig
+++ b/drivers/net/wireless/zydas/Kconfig
@@ -12,25 +12,6 @@ config WLAN_VENDOR_ZYDAS
if WLAN_VENDOR_ZYDAS
-config USB_ZD1201
- tristate "USB ZD1201 based Wireless device support"
- depends on CFG80211 && USB
- select WIRELESS_EXT
- select WEXT_PRIV
- select FW_LOADER
- help
- Say Y if you want to use wireless LAN adapters based on the ZyDAS
- ZD1201 chip.
-
- This driver makes the adapter appear as a normal Ethernet interface,
- typically on wlan0.
-
- The zd1201 device requires external firmware to be loaded.
- This can be found at http://linux-lc100020.sourceforge.net/
-
- To compile this driver as a module, choose M here: the
- module will be called zd1201.
-
source "drivers/net/wireless/zydas/zd1211rw/Kconfig"
endif # WLAN_VENDOR_ZYDAS
diff --git a/drivers/net/wireless/zydas/Makefile b/drivers/net/wireless/zydas/Makefile
index c70003d30a8f..3e0a51db9874 100644
--- a/drivers/net/wireless/zydas/Makefile
+++ b/drivers/net/wireless/zydas/Makefile
@@ -1,4 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ZD1211RW) += zd1211rw/
-
-obj-$(CONFIG_USB_ZD1201) += zd1201.o
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
deleted file mode 100644
index 2814df1ecc78..000000000000
--- a/drivers/net/wireless/zydas/zd1201.c
+++ /dev/null
@@ -1,1909 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for ZyDAS zd1201 based USB wireless devices.
- *
- * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
- *
- * Parts of this driver have been derived from a wlan-ng version
- * modified by ZyDAS. They also made documentation available, thanks!
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- */
-
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-#include <net/iw_handler.h>
-#include <linux/string.h>
-#include <linux/if_arp.h>
-#include <linux/firmware.h>
-#include "zd1201.h"
-
-static const struct usb_device_id zd1201_table[] = {
- {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */
- {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */
- {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */
- {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */
- {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */
- {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */
- {}
-};
-
-static int ap; /* Are we an AP or a normal station? */
-
-#define ZD1201_VERSION "0.15"
-
-MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
-MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters");
-MODULE_VERSION(ZD1201_VERSION);
-MODULE_LICENSE("GPL");
-module_param(ap, int, 0);
-MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded");
-MODULE_DEVICE_TABLE(usb, zd1201_table);
-
-
-static int zd1201_fw_upload(struct usb_device *dev, int apfw)
-{
- const struct firmware *fw_entry;
- const char *data;
- unsigned long len;
- int err;
- unsigned char ret;
- char *buf;
- char *fwfile;
-
- if (apfw)
- fwfile = "zd1201-ap.fw";
- else
- fwfile = "zd1201.fw";
-
- err = request_firmware(&fw_entry, fwfile, &dev->dev);
- if (err) {
- dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile);
- dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n");
- dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n");
- return err;
- }
-
- data = fw_entry->data;
- len = fw_entry->size;
-
- buf = kmalloc(1024, GFP_ATOMIC);
- if (!buf) {
- err = -ENOMEM;
- goto exit;
- }
-
- while (len > 0) {
- int translen = (len > 1024) ? 1024 : len;
- memcpy(buf, data, translen);
-
- err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0,
- USB_DIR_OUT | 0x40, 0, 0, buf, translen,
- ZD1201_FW_TIMEOUT);
- if (err < 0)
- goto exit;
-
- len -= translen;
- data += translen;
- }
-
- err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2,
- USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT);
- if (err < 0)
- goto exit;
-
- err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
- USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT);
- if (err < 0)
- goto exit;
-
- memcpy(&ret, buf, sizeof(ret));
-
- if (ret & 0x80) {
- err = -EIO;
- goto exit;
- }
-
- err = 0;
-exit:
- kfree(buf);
- release_firmware(fw_entry);
- return err;
-}
-
-MODULE_FIRMWARE("zd1201-ap.fw");
-MODULE_FIRMWARE("zd1201.fw");
-
-static void zd1201_usbfree(struct urb *urb)
-{
- struct zd1201 *zd = urb->context;
-
- switch(urb->status) {
- case -EILSEQ:
- case -ENODEV:
- case -ETIME:
- case -ENOENT:
- case -EPIPE:
- case -EOVERFLOW:
- case -ESHUTDOWN:
- dev_warn(&zd->usb->dev, "%s: urb failed: %d\n",
- zd->dev->name, urb->status);
- }
-
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
-}
-
-/* cmdreq message:
- u32 type
- u16 cmd
- u16 parm0
- u16 parm1
- u16 parm2
- u8 pad[4]
-
- total: 4 + 2 + 2 + 2 + 2 + 4 = 16
-*/
-static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0,
- int parm1, int parm2)
-{
- unsigned char *command;
- int ret;
- struct urb *urb;
-
- command = kmalloc(16, GFP_ATOMIC);
- if (!command)
- return -ENOMEM;
-
- *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ);
- *((__le16*)&command[4]) = cpu_to_le16(cmd);
- *((__le16*)&command[6]) = cpu_to_le16(parm0);
- *((__le16*)&command[8]) = cpu_to_le16(parm1);
- *((__le16*)&command[10])= cpu_to_le16(parm2);
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb) {
- kfree(command);
- return -ENOMEM;
- }
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
- command, 16, zd1201_usbfree, zd);
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret) {
- kfree(command);
- usb_free_urb(urb);
- }
-
- return ret;
-}
-
-/* Callback after sending out a packet */
-static void zd1201_usbtx(struct urb *urb)
-{
- struct zd1201 *zd = urb->context;
- netif_wake_queue(zd->dev);
-}
-
-/* Incoming data */
-static void zd1201_usbrx(struct urb *urb)
-{
- struct zd1201 *zd = urb->context;
- int free = 0;
- unsigned char *data = urb->transfer_buffer;
- struct sk_buff *skb;
- unsigned char type;
-
- if (!zd)
- return;
-
- switch(urb->status) {
- case -EILSEQ:
- case -ENODEV:
- case -ETIME:
- case -ENOENT:
- case -EPIPE:
- case -EOVERFLOW:
- case -ESHUTDOWN:
- dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n",
- zd->dev->name, urb->status);
- free = 1;
- goto exit;
- }
-
- if (urb->status != 0 || urb->actual_length == 0)
- goto resubmit;
-
- type = data[0];
- if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) {
- memcpy(zd->rxdata, data, urb->actual_length);
- zd->rxlen = urb->actual_length;
- zd->rxdatas = 1;
- wake_up(&zd->rxdataq);
- }
- /* Info frame */
- if (type == ZD1201_PACKET_INQUIRE) {
- int i = 0;
- unsigned short infotype, copylen;
- infotype = le16_to_cpu(*(__le16*)&data[6]);
-
- if (infotype == ZD1201_INF_LINKSTATUS) {
- short linkstatus;
-
- linkstatus = le16_to_cpu(*(__le16*)&data[8]);
- switch(linkstatus) {
- case 1:
- netif_carrier_on(zd->dev);
- break;
- case 2:
- netif_carrier_off(zd->dev);
- break;
- case 3:
- netif_carrier_off(zd->dev);
- break;
- case 4:
- netif_carrier_on(zd->dev);
- break;
- default:
- netif_carrier_off(zd->dev);
- }
- goto resubmit;
- }
- if (infotype == ZD1201_INF_ASSOCSTATUS) {
- short status = le16_to_cpu(*(__le16*)(data+8));
- int event;
- union iwreq_data wrqu;
-
- switch (status) {
- case ZD1201_ASSOCSTATUS_STAASSOC:
- case ZD1201_ASSOCSTATUS_REASSOC:
- event = IWEVREGISTERED;
- break;
- case ZD1201_ASSOCSTATUS_DISASSOC:
- case ZD1201_ASSOCSTATUS_ASSOCFAIL:
- case ZD1201_ASSOCSTATUS_AUTHFAIL:
- default:
- event = IWEVEXPIRED;
- }
- memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(zd->dev, event, &wrqu, NULL);
-
- goto resubmit;
- }
- if (infotype == ZD1201_INF_AUTHREQ) {
- union iwreq_data wrqu;
-
- memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- /* There isn't a event that trully fits this request.
- We assume that userspace will be smart enough to
- see a new station being expired and sends back a
- authstation ioctl to authorize it. */
- wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL);
- goto resubmit;
- }
- /* Other infotypes are handled outside this handler */
- zd->rxlen = 0;
- while (i < urb->actual_length) {
- copylen = le16_to_cpu(*(__le16*)&data[i+2]);
- /* Sanity check, sometimes we get junk */
- if (copylen+zd->rxlen > sizeof(zd->rxdata))
- break;
- memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen);
- zd->rxlen += copylen;
- i += 64;
- }
- if (i >= urb->actual_length) {
- zd->rxdatas = 1;
- wake_up(&zd->rxdataq);
- }
- goto resubmit;
- }
- /* Actual data */
- if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) {
- int datalen = urb->actual_length-1;
- unsigned short len, fc, seq;
-
- len = ntohs(*(__be16 *)&data[datalen-2]);
- if (len>datalen)
- len=datalen;
- fc = le16_to_cpu(*(__le16 *)&data[datalen-16]);
- seq = le16_to_cpu(*(__le16 *)&data[datalen-24]);
-
- if (zd->monitor) {
- if (datalen < 24)
- goto resubmit;
- if (!(skb = dev_alloc_skb(datalen+24)))
- goto resubmit;
-
- skb_put_data(skb, &data[datalen - 16], 2);
- skb_put_data(skb, &data[datalen - 2], 2);
- skb_put_data(skb, &data[datalen - 14], 6);
- skb_put_data(skb, &data[datalen - 22], 6);
- skb_put_data(skb, &data[datalen - 8], 6);
- skb_put_data(skb, &data[datalen - 24], 2);
- skb_put_data(skb, data, len);
- skb->protocol = eth_type_trans(skb, zd->dev);
- zd->dev->stats.rx_packets++;
- zd->dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- goto resubmit;
- }
-
- if ((seq & IEEE80211_SCTL_FRAG) ||
- (fc & IEEE80211_FCTL_MOREFRAGS)) {
- struct zd1201_frag *frag = NULL;
- char *ptr;
-
- if (datalen<14)
- goto resubmit;
- if ((seq & IEEE80211_SCTL_FRAG) == 0) {
- frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
- if (!frag)
- goto resubmit;
- skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
- if (!skb) {
- kfree(frag);
- goto resubmit;
- }
- frag->skb = skb;
- frag->seq = seq & IEEE80211_SCTL_SEQ;
- skb_reserve(skb, 2);
- skb_put_data(skb, &data[datalen - 14], 12);
- skb_put_data(skb, &data[6], 2);
- skb_put_data(skb, data + 8, len);
- hlist_add_head(&frag->fnode, &zd->fraglist);
- goto resubmit;
- }
- hlist_for_each_entry(frag, &zd->fraglist, fnode)
- if (frag->seq == (seq&IEEE80211_SCTL_SEQ))
- break;
- if (!frag)
- goto resubmit;
- skb = frag->skb;
- ptr = skb_put(skb, len);
- if (ptr)
- memcpy(ptr, data+8, len);
- if (fc & IEEE80211_FCTL_MOREFRAGS)
- goto resubmit;
- hlist_del_init(&frag->fnode);
- kfree(frag);
- } else {
- if (datalen<14)
- goto resubmit;
- skb = dev_alloc_skb(len + 14 + 2);
- if (!skb)
- goto resubmit;
- skb_reserve(skb, 2);
- skb_put_data(skb, &data[datalen - 14], 12);
- skb_put_data(skb, &data[6], 2);
- skb_put_data(skb, data + 8, len);
- }
- skb->protocol = eth_type_trans(skb, zd->dev);
- zd->dev->stats.rx_packets++;
- zd->dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- }
-resubmit:
- memset(data, 0, ZD1201_RXSIZE);
-
- urb->status = 0;
- urb->dev = zd->usb;
- if(usb_submit_urb(urb, GFP_ATOMIC))
- free = 1;
-
-exit:
- if (free) {
- zd->rxlen = 0;
- zd->rxdatas = 1;
- wake_up(&zd->rxdataq);
- kfree(urb->transfer_buffer);
- }
-}
-
-static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
- unsigned int riddatalen)
-{
- int err;
- int i = 0;
- int code;
- int rid_fid;
- int length;
- unsigned char *pdata;
-
- zd->rxdatas = 0;
- err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0);
- if (err)
- return err;
-
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen)
- return -EIO;
-
- code = le16_to_cpu(*(__le16*)(&zd->rxdata[4]));
- rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6]));
- length = le16_to_cpu(*(__le16*)(&zd->rxdata[8]));
- if (length > zd->rxlen)
- length = zd->rxlen-6;
-
- /* If access bit is not on, then error */
- if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid )
- return -EINVAL;
-
- /* Not enough buffer for allocating data */
- if (riddatalen != (length - 4)) {
- dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n",
- riddatalen, zd->rxlen, length, rid, rid_fid);
- return -ENODATA;
- }
-
- zd->rxdatas = 0;
- /* Issue SetRxRid commnd */
- err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length);
- if (err)
- return err;
-
- /* Receive RID record from resource packets */
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen)
- return -EIO;
-
- if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) {
- dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n",
- zd->rxdata[zd->rxlen-1]);
- return -EINVAL;
- }
-
- /* Set the data pointer and received data length */
- pdata = zd->rxdata;
- length = zd->rxlen;
-
- do {
- int actual_length;
-
- actual_length = (length > 64) ? 64 : length;
-
- if (pdata[0] != 0x3) {
- dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n",
- pdata[0]);
- return -EINVAL;
- }
-
- if (actual_length != 64) {
- /* Trim the last packet type byte */
- actual_length--;
- }
-
- /* Skip the 4 bytes header (RID length and RID) */
- if (i == 0) {
- pdata += 8;
- actual_length -= 8;
- } else {
- pdata += 4;
- actual_length -= 4;
- }
-
- memcpy(riddata, pdata, actual_length);
- riddata += actual_length;
- pdata += actual_length;
- length -= 64;
- i++;
- } while (length > 0);
-
- return 0;
-}
-
-/*
- * resreq:
- * byte type
- * byte sequence
- * u16 reserved
- * byte data[12]
- * total: 16
- */
-static int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait)
-{
- int err;
- unsigned char *request;
- int reqlen;
- char seq=0;
- struct urb *urb;
- gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC;
-
- len += 4; /* first 4 are for header */
-
- zd->rxdatas = 0;
- zd->rxlen = 0;
- for (seq=0; len > 0; seq++) {
- request = kzalloc(16, gfp_mask);
- if (!request)
- return -ENOMEM;
- urb = usb_alloc_urb(0, gfp_mask);
- if (!urb) {
- kfree(request);
- return -ENOMEM;
- }
- reqlen = len>12 ? 12 : len;
- request[0] = ZD1201_USB_RESREQ;
- request[1] = seq;
- request[2] = 0;
- request[3] = 0;
- if (request[1] == 0) {
- /* add header */
- *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2);
- *(__le16*)&request[6] = cpu_to_le16(rid);
- memcpy(request+8, buf, reqlen-4);
- buf += reqlen-4;
- } else {
- memcpy(request+4, buf, reqlen);
- buf += reqlen;
- }
-
- len -= reqlen;
-
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb,
- zd->endp_out2), request, 16, zd1201_usbfree, zd);
- err = usb_submit_urb(urb, gfp_mask);
- if (err)
- goto err;
- }
-
- request = kmalloc(16, gfp_mask);
- if (!request)
- return -ENOMEM;
- urb = usb_alloc_urb(0, gfp_mask);
- if (!urb) {
- kfree(request);
- return -ENOMEM;
- }
- *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ);
- *((__le16*)&request[4]) =
- cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT);
- *((__le16*)&request[6]) = cpu_to_le16(rid);
- *((__le16*)&request[8]) = cpu_to_le16(0);
- *((__le16*)&request[10]) = cpu_to_le16(0);
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
- request, 16, zd1201_usbfree, zd);
- err = usb_submit_urb(urb, gfp_mask);
- if (err)
- goto err;
-
- if (wait) {
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) {
- dev_dbg(&zd->usb->dev, "wrong or no RID received\n");
- }
- }
-
- return 0;
-err:
- kfree(request);
- usb_free_urb(urb);
- return err;
-}
-
-static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val)
-{
- int err;
- __le16 zdval;
-
- err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16));
- if (err)
- return err;
- *val = le16_to_cpu(zdval);
- return 0;
-}
-
-static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val)
-{
- __le16 zdval = cpu_to_le16(val);
- return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1));
-}
-
-static int zd1201_drvr_start(struct zd1201 *zd)
-{
- int err, i;
- short max;
- __le16 zdmax;
- unsigned char *buffer;
-
- buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- usb_fill_bulk_urb(zd->rx_urb, zd->usb,
- usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,
- zd1201_usbrx, zd);
-
- err = usb_submit_urb(zd->rx_urb, GFP_KERNEL);
- if (err)
- goto err_buffer;
-
- err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
- if (err)
- goto err_urb;
-
- err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax,
- sizeof(__le16));
- if (err)
- goto err_urb;
-
- max = le16_to_cpu(zdmax);
- for (i=0; i<max; i++) {
- err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0);
- if (err)
- goto err_urb;
- }
-
- return 0;
-
-err_urb:
- usb_kill_urb(zd->rx_urb);
- return err;
-err_buffer:
- kfree(buffer);
- return err;
-}
-
-/* Magic alert: The firmware doesn't seem to like the MAC state being
- * toggled in promisc (aka monitor) mode.
- * (It works a number of times, but will halt eventually)
- * So we turn it of before disabling and on after enabling if needed.
- */
-static int zd1201_enable(struct zd1201 *zd)
-{
- int err;
-
- if (zd->mac_enabled)
- return 0;
-
- err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0);
- if (!err)
- zd->mac_enabled = 1;
-
- if (zd->monitor)
- err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1);
-
- return err;
-}
-
-static int zd1201_disable(struct zd1201 *zd)
-{
- int err;
-
- if (!zd->mac_enabled)
- return 0;
- if (zd->monitor) {
- err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
- if (err)
- return err;
- }
-
- err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0);
- if (!err)
- zd->mac_enabled = 0;
- return err;
-}
-
-static int zd1201_mac_reset(struct zd1201 *zd)
-{
- if (!zd->mac_enabled)
- return 0;
- zd1201_disable(zd);
- return zd1201_enable(zd);
-}
-
-static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen)
-{
- int err, val;
- char buf[IW_ESSID_MAX_SIZE+2];
-
- err = zd1201_disable(zd);
- if (err)
- return err;
-
- val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
- val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val);
- if (err)
- return err;
-
- *(__le16 *)buf = cpu_to_le16(essidlen);
- memcpy(buf+2, essid, essidlen);
- if (!zd->ap) { /* Normal station */
- err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
- IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- return err;
- } else { /* AP */
- err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf,
- IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- return err;
- }
-
- err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR,
- zd->dev->dev_addr, zd->dev->addr_len, 1);
- if (err)
- return err;
-
- err = zd1201_enable(zd);
- if (err)
- return err;
-
- msleep(100);
- return 0;
-}
-
-static int zd1201_net_open(struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- /* Start MAC with wildcard if no essid set */
- if (!zd->mac_enabled)
- zd1201_join(zd, zd->essid, zd->essidlen);
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int zd1201_net_stop(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-/*
- RFC 1042 encapsulates Ethernet frames in 802.11 frames
- by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0
- (0x00, 0x00, 0x00). Zd requires an additional padding, copy
- of ethernet addresses, length of the standard RFC 1042 packet
- and a command byte (which is nul for tx).
-
- tx frame (from Wlan NG):
- RFC 1042:
- llc 0xAA 0xAA 0x03 (802.2 LLC)
- snap 0x00 0x00 0x00 (Ethernet encapsulated)
- type 2 bytes, Ethernet type field
- payload (minus eth header)
- Zydas specific:
- padding 1B if (skb->len+8+1)%64==0
- Eth MAC addr 12 bytes, Ethernet MAC addresses
- length 2 bytes, RFC 1042 packet length
- (llc+snap+type+payload)
- zd 1 null byte, zd1201 packet type
- */
-static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
- unsigned char *txbuf = zd->txdata;
- int txbuflen, pad = 0, err;
- struct urb *urb = zd->tx_urb;
-
- if (!zd->mac_enabled || zd->monitor) {
- dev->stats.tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- netif_stop_queue(dev);
-
- txbuflen = skb->len + 8 + 1;
- if (txbuflen%64 == 0) {
- pad = 1;
- txbuflen++;
- }
- txbuf[0] = 0xAA;
- txbuf[1] = 0xAA;
- txbuf[2] = 0x03;
- txbuf[3] = 0x00; /* rfc1042 */
- txbuf[4] = 0x00;
- txbuf[5] = 0x00;
-
- skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12);
- if (pad)
- txbuf[skb->len-12+6]=0;
- skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12);
- *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);
- txbuf[txbuflen-1] = 0;
-
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out),
- txbuf, txbuflen, zd1201_usbtx, zd);
-
- err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);
- if (err) {
- dev->stats.tx_errors++;
- netif_start_queue(dev);
- } else {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
- }
- kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-static void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- if (!zd)
- return;
- dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
- dev->name);
- usb_unlink_urb(zd->tx_urb);
- dev->stats.tx_errors++;
- /* Restart the timeout to quiet the watchdog: */
- netif_trans_update(dev); /* prevent tx timeout */
-}
-
-static int zd1201_set_mac_address(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = p;
- struct zd1201 *zd = netdev_priv(dev);
- int err;
-
- if (!zd)
- return -ENODEV;
-
- err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR,
- addr->sa_data, dev->addr_len, 1);
- if (err)
- return err;
- eth_hw_addr_set(dev, addr->sa_data);
-
- return zd1201_mac_reset(zd);
-}
-
-static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- return &zd->iwstats;
-}
-
-static void zd1201_set_multicast(struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
- int i;
-
- if (netdev_mc_count(dev) > ZD1201_MAXMULTI)
- return;
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
- zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
- netdev_mc_count(dev) * ETH_ALEN, 0);
-}
-
-static int zd1201_config_commit(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_name(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- strcpy(wrqu->name, "IEEE 802.11b");
- return 0;
-}
-
-static int zd1201_set_freq(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct zd1201 *zd = netdev_priv(dev);
- short channel = 0;
- int err;
-
- if (freq->e == 0)
- channel = freq->m;
- else
- channel = ieee80211_frequency_to_channel(freq->m);
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
- if (err)
- return err;
-
- zd1201_mac_reset(zd);
-
- return 0;
-}
-
-static int zd1201_get_freq(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct zd1201 *zd = netdev_priv(dev);
- short channel;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel);
- if (err)
- return err;
- freq->e = 0;
- freq->m = channel;
-
- return 0;
-}
-
-static int zd1201_set_mode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct zd1201 *zd = netdev_priv(dev);
- short porttype, monitor = 0;
- unsigned char buffer[IW_ESSID_MAX_SIZE+2];
- int err;
-
- if (zd->ap) {
- if (*mode != IW_MODE_MASTER)
- return -EINVAL;
- return 0;
- }
-
- err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
- if (err)
- return err;
- zd->dev->type = ARPHRD_ETHER;
- switch(*mode) {
- case IW_MODE_MONITOR:
- monitor = 1;
- zd->dev->type = ARPHRD_IEEE80211;
- /* Make sure we are no longer associated with by
- setting an 'impossible' essid.
- (otherwise we mess up firmware)
- */
- zd1201_join(zd, "\0-*#\0", 5);
- /* Put port in pIBSS */
- fallthrough;
- case 8: /* No pseudo-IBSS in wireless extensions (yet) */
- porttype = ZD1201_PORTTYPE_PSEUDOIBSS;
- break;
- case IW_MODE_ADHOC:
- porttype = ZD1201_PORTTYPE_IBSS;
- break;
- case IW_MODE_INFRA:
- porttype = ZD1201_PORTTYPE_BSS;
- break;
- default:
- return -EINVAL;
- }
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
- if (err)
- return err;
- if (zd->monitor && !monitor) {
- zd1201_disable(zd);
- *(__le16 *)buffer = cpu_to_le16(zd->essidlen);
- memcpy(buffer+2, zd->essid, zd->essidlen);
- err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID,
- buffer, IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- return err;
- }
- zd->monitor = monitor;
- /* If monitor mode is set we don't actually turn it on here since it
- * is done during mac reset anyway (see zd1201_mac_enable).
- */
- zd1201_mac_reset(zd);
-
- return 0;
-}
-
-static int zd1201_get_mode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct zd1201 *zd = netdev_priv(dev);
- short porttype;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype);
- if (err)
- return err;
- switch(porttype) {
- case ZD1201_PORTTYPE_IBSS:
- *mode = IW_MODE_ADHOC;
- break;
- case ZD1201_PORTTYPE_BSS:
- *mode = IW_MODE_INFRA;
- break;
- case ZD1201_PORTTYPE_WDS:
- *mode = IW_MODE_REPEAT;
- break;
- case ZD1201_PORTTYPE_PSEUDOIBSS:
- *mode = 8;/* No Pseudo-IBSS... */
- break;
- case ZD1201_PORTTYPE_AP:
- *mode = IW_MODE_MASTER;
- break;
- default:
- dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n",
- porttype);
- *mode = IW_MODE_AUTO;
- }
- if (zd->monitor)
- *mode = IW_MODE_MONITOR;
-
- return 0;
-}
-
-static int zd1201_get_range(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *wrq = &wrqu->data;
- struct iw_range *range = (struct iw_range *)extra;
-
- wrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = WIRELESS_EXT;
-
- range->max_qual.qual = 128;
- range->max_qual.level = 128;
- range->max_qual.noise = 128;
- range->max_qual.updated = 7;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = ZD1201_NUMKEYS;
-
- range->num_bitrates = 4;
- range->bitrate[0] = 1000000;
- range->bitrate[1] = 2000000;
- range->bitrate[2] = 5500000;
- range->bitrate[3] = 11000000;
-
- range->min_rts = 0;
- range->min_frag = ZD1201_FRAGMIN;
- range->max_rts = ZD1201_RTSMAX;
- range->min_frag = ZD1201_FRAGMAX;
-
- return 0;
-}
-
-/* Little bit of magic here: we only get the quality if we poll
- * for it, and we never get an actual request to trigger such
- * a poll. Therefore we 'assume' that the user will soon ask for
- * the stats after asking the bssid.
- */
-static int zd1201_get_wap(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct zd1201 *zd = netdev_priv(dev);
- unsigned char buffer[6];
-
- if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
- /* Unfortunately the quality and noise reported is useless.
- they seem to be accumulators that increase until you
- read them, unless we poll on a fixed interval we can't
- use them
- */
- /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/
- zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]);
- /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/
- zd->iwstats.qual.updated = 2;
- }
-
- return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6);
-}
-
-static int zd1201_set_scan(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- /* We do everything in get_scan */
- return 0;
-}
-
-static int zd1201_get_scan(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *srq = &wrqu->data;
- struct zd1201 *zd = netdev_priv(dev);
- int err, i, j, enabled_save;
- struct iw_event iwe;
- char *cev = extra;
- char *end_buf = extra + IW_SCAN_MAX_DATA;
-
- /* No scanning in AP mode */
- if (zd->ap)
- return -EOPNOTSUPP;
-
- /* Scan doesn't seem to work if disabled */
- enabled_save = zd->mac_enabled;
- zd1201_enable(zd);
-
- zd->rxdatas = 0;
- err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE,
- ZD1201_INQ_SCANRESULTS, 0, 0);
- if (err)
- return err;
-
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen)
- return -EIO;
-
- if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS)
- return -EIO;
-
- for(i=8; i<zd->rxlen; i+=62) {
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = zd->rxdata[i+16];
- iwe.u.data.flags = 1;
- cev = iwe_stream_add_point(info, cev, end_buf,
- &iwe, zd->rxdata+i+18);
-
- iwe.cmd = SIOCGIWMODE;
- if (zd->rxdata[i+14]&0x01)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_UINT_LEN);
-
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = zd->rxdata[i+0];
- iwe.u.freq.e = 0;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.cmd = SIOCGIWRATE;
- iwe.u.bitrate.fixed = 0;
- iwe.u.bitrate.disabled = 0;
- for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
- iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
-
- iwe.cmd = SIOCGIWENCODE;
- iwe.u.data.length = 0;
- if (zd->rxdata[i+14]&0x10)
- iwe.u.data.flags = IW_ENCODE_ENABLED;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
-
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = zd->rxdata[i+4];
- iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
- iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
- iwe.u.qual.updated = 7;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
- }
-
- if (!enabled_save)
- zd1201_disable(zd);
-
- srq->length = cev - extra;
- srq->flags = 0;
-
- return 0;
-}
-
-static int zd1201_set_essid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct iw_point *data = &wrqu->data;
- struct zd1201 *zd = netdev_priv(dev);
-
- if (data->length > IW_ESSID_MAX_SIZE)
- return -EINVAL;
- if (data->length < 1)
- data->length = 1;
- zd->essidlen = data->length;
- memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
- memcpy(zd->essid, essid, data->length);
- return zd1201_join(zd, zd->essid, zd->essidlen);
-}
-
-static int zd1201_get_essid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct iw_point *data = &wrqu->data;
- struct zd1201 *zd = netdev_priv(dev);
-
- memcpy(essid, zd->essid, zd->essidlen);
- data->flags = 1;
- data->length = zd->essidlen;
-
- return 0;
-}
-
-static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *nick)
-{
- struct iw_point *data = &wrqu->data;
- strcpy(nick, "zd1201");
- data->flags = 1;
- data->length = strlen(nick);
- return 0;
-}
-
-static int zd1201_set_rate(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct zd1201 *zd = netdev_priv(dev);
- short rate;
- int err;
-
- switch (rrq->value) {
- case 1000000:
- rate = ZD1201_RATEB1;
- break;
- case 2000000:
- rate = ZD1201_RATEB2;
- break;
- case 5500000:
- rate = ZD1201_RATEB5;
- break;
- case 11000000:
- default:
- rate = ZD1201_RATEB11;
- break;
- }
- if (!rrq->fixed) { /* Also enable all lower bitrates */
- rate |= rate-1;
- }
-
- err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate);
- if (err)
- return err;
-
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_rate(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct zd1201 *zd = netdev_priv(dev);
- short rate;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate);
- if (err)
- return err;
-
- switch(rate) {
- case 1:
- rrq->value = 1000000;
- break;
- case 2:
- rrq->value = 2000000;
- break;
- case 5:
- rrq->value = 5500000;
- break;
- case 11:
- rrq->value = 11000000;
- break;
- default:
- rrq->value = 0;
- }
- rrq->fixed = 0;
- rrq->disabled = 0;
-
- return 0;
-}
-
-static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct zd1201 *zd = netdev_priv(dev);
- int err;
- short val = rts->value;
-
- if (rts->disabled || !rts->fixed)
- val = ZD1201_RTSMAX;
- if (val > ZD1201_RTSMAX)
- return -EINVAL;
- if (val < 0)
- return -EINVAL;
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val);
- if (err)
- return err;
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct zd1201 *zd = netdev_priv(dev);
- short rtst;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst);
- if (err)
- return err;
- rts->value = rtst;
- rts->disabled = (rts->value == ZD1201_RTSMAX);
- rts->fixed = 1;
-
- return 0;
-}
-
-static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *frag = &wrqu->frag;
- struct zd1201 *zd = netdev_priv(dev);
- int err;
- short val = frag->value;
-
- if (frag->disabled || !frag->fixed)
- val = ZD1201_FRAGMAX;
- if (val > ZD1201_FRAGMAX)
- return -EINVAL;
- if (val < ZD1201_FRAGMIN)
- return -EINVAL;
- if (val & 1)
- return -EINVAL;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val);
- if (err)
- return err;
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *frag = &wrqu->frag;
- struct zd1201 *zd = netdev_priv(dev);
- short fragt;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt);
- if (err)
- return err;
- frag->value = fragt;
- frag->disabled = (frag->value == ZD1201_FRAGMAX);
- frag->fixed = 1;
-
- return 0;
-}
-
-static int zd1201_set_retry(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- return 0;
-}
-
-static int zd1201_get_retry(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- return 0;
-}
-
-static int zd1201_set_encode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *key)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct zd1201 *zd = netdev_priv(dev);
- short i;
- int err, rid;
-
- if (erq->length > ZD1201_MAXKEYLEN)
- return -EINVAL;
-
- i = (erq->flags & IW_ENCODE_INDEX)-1;
- if (i == -1) {
- err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i);
- if (err)
- return err;
- } else {
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i);
- if (err)
- return err;
- }
-
- if (i < 0 || i >= ZD1201_NUMKEYS)
- return -EINVAL;
-
- rid = ZD1201_RID_CNFDEFAULTKEY0 + i;
- err = zd1201_setconfig(zd, rid, key, erq->length, 1);
- if (err)
- return err;
- zd->encode_keylen[i] = erq->length;
- memcpy(zd->encode_keys[i], key, erq->length);
-
- i=0;
- if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) {
- i |= 0x01;
- zd->encode_enabled = 1;
- } else
- zd->encode_enabled = 0;
- if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) {
- i |= 0x02;
- zd->encode_restricted = 1;
- } else
- zd->encode_restricted = 0;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i);
- if (err)
- return err;
-
- if (zd->encode_enabled)
- i = ZD1201_CNFAUTHENTICATION_SHAREDKEY;
- else
- i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i);
- if (err)
- return err;
-
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_encode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *key)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct zd1201 *zd = netdev_priv(dev);
- short i;
- int err;
-
- if (zd->encode_enabled)
- erq->flags = IW_ENCODE_ENABLED;
- else
- erq->flags = IW_ENCODE_DISABLED;
- if (zd->encode_restricted)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- i = (erq->flags & IW_ENCODE_INDEX) -1;
- if (i == -1) {
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i);
- if (err)
- return err;
- }
- if (i<0 || i>= ZD1201_NUMKEYS)
- return -EINVAL;
-
- erq->flags |= i+1;
-
- erq->length = zd->encode_keylen[i];
- memcpy(key, zd->encode_keys[i], erq->length);
-
- return 0;
-}
-
-static int zd1201_set_power(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct zd1201 *zd = netdev_priv(dev);
- short enabled, duration, level;
- int err;
-
- enabled = vwrq->disabled ? 0 : 1;
- if (enabled) {
- if (vwrq->flags & IW_POWER_PERIOD) {
- duration = vwrq->value;
- err = zd1201_setconfig16(zd,
- ZD1201_RID_CNFMAXSLEEPDURATION, duration);
- if (err)
- return err;
- goto out;
- }
- if (vwrq->flags & IW_POWER_TIMEOUT) {
- err = zd1201_getconfig16(zd,
- ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
- if (err)
- return err;
- level = vwrq->value * 4 / duration;
- if (level > 4)
- level = 4;
- if (level < 0)
- level = 0;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS,
- level);
- if (err)
- return err;
- goto out;
- }
- return -EINVAL;
- }
-out:
- return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled);
-}
-
-static int zd1201_get_power(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct zd1201 *zd = netdev_priv(dev);
- short enabled, level, duration;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled);
- if (err)
- return err;
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level);
- if (err)
- return err;
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
- if (err)
- return err;
- vwrq->disabled = enabled ? 0 : 1;
- if (vwrq->flags & IW_POWER_TYPE) {
- if (vwrq->flags & IW_POWER_PERIOD) {
- vwrq->value = duration;
- vwrq->flags = IW_POWER_PERIOD;
- } else {
- vwrq->value = duration * level / 4;
- vwrq->flags = IW_POWER_TIMEOUT;
- }
- }
- if (vwrq->flags & IW_POWER_MODE) {
- if (enabled && level)
- vwrq->flags = IW_POWER_UNICAST_R;
- else
- vwrq->flags = IW_POWER_ALL_R;
- }
-
- return 0;
-}
-
-
-static const iw_handler zd1201_iw_handler[] =
-{
- IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit),
- IW_HANDLER(SIOCGIWNAME, zd1201_get_name),
- IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq),
- IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq),
- IW_HANDLER(SIOCSIWMODE, zd1201_set_mode),
- IW_HANDLER(SIOCGIWMODE, zd1201_get_mode),
- IW_HANDLER(SIOCGIWRANGE, zd1201_get_range),
- IW_HANDLER(SIOCGIWAP, zd1201_get_wap),
- IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan),
- IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan),
- IW_HANDLER(SIOCSIWESSID, zd1201_set_essid),
- IW_HANDLER(SIOCGIWESSID, zd1201_get_essid),
- IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick),
- IW_HANDLER(SIOCSIWRATE, zd1201_set_rate),
- IW_HANDLER(SIOCGIWRATE, zd1201_get_rate),
- IW_HANDLER(SIOCSIWRTS, zd1201_set_rts),
- IW_HANDLER(SIOCGIWRTS, zd1201_get_rts),
- IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag),
- IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag),
- IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry),
- IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry),
- IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode),
- IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode),
- IW_HANDLER(SIOCSIWPOWER, zd1201_set_power),
- IW_HANDLER(SIOCGIWPOWER, zd1201_get_power),
-};
-
-static int zd1201_set_hostauth(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value);
-}
-
-static int zd1201_get_hostauth(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
- short hostauth;
- int err;
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth);
- if (err)
- return err;
- rrq->value = hostauth;
- rrq->fixed = 1;
-
- return 0;
-}
-
-static int zd1201_auth_sta(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *sta = &wrqu->ap_addr;
- struct zd1201 *zd = netdev_priv(dev);
- unsigned char buffer[10];
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- memcpy(buffer, sta->sa_data, ETH_ALEN);
- *(short*)(buffer+6) = 0; /* 0==success, 1==failure */
- *(short*)(buffer+8) = 0;
-
- return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1);
-}
-
-static int zd1201_set_maxassoc(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value);
-}
-
-static int zd1201_get_maxassoc(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
- short maxassoc;
- int err;
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc);
- if (err)
- return err;
- rrq->value = maxassoc;
- rrq->fixed = 1;
-
- return 0;
-}
-
-static const iw_handler zd1201_private_handler[] = {
- zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */
- zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */
- zd1201_auth_sta, /* ZD1201SIWAUTHSTA */
- NULL, /* nothing to get */
- zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */
- zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */
-};
-
-static const struct iw_priv_args zd1201_private_args[] = {
- { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_NONE, "sethostauth" },
- { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" },
- { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_NONE, "authstation" },
- { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_NONE, "setmaxassoc" },
- { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" },
-};
-
-static const struct iw_handler_def zd1201_iw_handlers = {
- .num_standard = ARRAY_SIZE(zd1201_iw_handler),
- .num_private = ARRAY_SIZE(zd1201_private_handler),
- .num_private_args = ARRAY_SIZE(zd1201_private_args),
- .standard = zd1201_iw_handler,
- .private = zd1201_private_handler,
- .private_args = (struct iw_priv_args *) zd1201_private_args,
- .get_wireless_stats = zd1201_get_wireless_stats,
-};
-
-static const struct net_device_ops zd1201_netdev_ops = {
- .ndo_open = zd1201_net_open,
- .ndo_stop = zd1201_net_stop,
- .ndo_start_xmit = zd1201_hard_start_xmit,
- .ndo_tx_timeout = zd1201_tx_timeout,
- .ndo_set_rx_mode = zd1201_set_multicast,
- .ndo_set_mac_address = zd1201_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int zd1201_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct zd1201 *zd;
- struct net_device *dev;
- struct usb_device *usb;
- int err;
- short porttype;
- char buf[IW_ESSID_MAX_SIZE+2];
- u8 addr[ETH_ALEN];
-
- usb = interface_to_usbdev(interface);
-
- dev = alloc_etherdev(sizeof(*zd));
- if (!dev)
- return -ENOMEM;
- zd = netdev_priv(dev);
- zd->dev = dev;
-
- zd->ap = ap;
- zd->usb = usb;
- zd->removed = 0;
- init_waitqueue_head(&zd->rxdataq);
- INIT_HLIST_HEAD(&zd->fraglist);
-
- err = zd1201_fw_upload(usb, zd->ap);
- if (err) {
- dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err);
- goto err_zd;
- }
-
- zd->endp_in = 1;
- zd->endp_out = 1;
- zd->endp_out2 = 2;
- zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!zd->rx_urb || !zd->tx_urb) {
- err = -ENOMEM;
- goto err_zd;
- }
-
- mdelay(100);
- err = zd1201_drvr_start(zd);
- if (err)
- goto err_zd;
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312);
- if (err)
- goto err_start;
-
- err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL,
- ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11);
- if (err)
- goto err_start;
-
- dev->netdev_ops = &zd1201_netdev_ops;
- dev->wireless_handlers = &zd1201_iw_handlers;
- dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
- strcpy(dev->name, "wlan%d");
-
- err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN);
- if (err)
- goto err_start;
- eth_hw_addr_set(dev, addr);
-
- /* Set wildcard essid to match zd->essid */
- *(__le16 *)buf = cpu_to_le16(0);
- err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
- IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- goto err_start;
-
- if (zd->ap)
- porttype = ZD1201_PORTTYPE_AP;
- else
- porttype = ZD1201_PORTTYPE_BSS;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
- if (err)
- goto err_start;
-
- SET_NETDEV_DEV(dev, &usb->dev);
-
- err = register_netdev(dev);
- if (err)
- goto err_start;
- dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
- dev->name);
-
- usb_set_intfdata(interface, zd);
- zd1201_enable(zd); /* zd1201 likes to startup enabled, */
- zd1201_disable(zd); /* interfering with all the wifis in range */
- return 0;
-
-err_start:
- /* Leave the device in reset state */
- zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
-err_zd:
- usb_free_urb(zd->tx_urb);
- usb_free_urb(zd->rx_urb);
- free_netdev(dev);
- return err;
-}
-
-static void zd1201_disconnect(struct usb_interface *interface)
-{
- struct zd1201 *zd = usb_get_intfdata(interface);
- struct hlist_node *node2;
- struct zd1201_frag *frag;
-
- if (!zd)
- return;
- usb_set_intfdata(interface, NULL);
-
- hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) {
- hlist_del_init(&frag->fnode);
- kfree_skb(frag->skb);
- kfree(frag);
- }
-
- if (zd->tx_urb) {
- usb_kill_urb(zd->tx_urb);
- usb_free_urb(zd->tx_urb);
- }
- if (zd->rx_urb) {
- usb_kill_urb(zd->rx_urb);
- usb_free_urb(zd->rx_urb);
- }
-
- if (zd->dev) {
- unregister_netdev(zd->dev);
- free_netdev(zd->dev);
- }
-}
-
-#ifdef CONFIG_PM
-
-static int zd1201_suspend(struct usb_interface *interface,
- pm_message_t message)
-{
- struct zd1201 *zd = usb_get_intfdata(interface);
-
- netif_device_detach(zd->dev);
-
- zd->was_enabled = zd->mac_enabled;
-
- if (zd->was_enabled)
- return zd1201_disable(zd);
- else
- return 0;
-}
-
-static int zd1201_resume(struct usb_interface *interface)
-{
- struct zd1201 *zd = usb_get_intfdata(interface);
-
- if (!zd || !zd->dev)
- return -ENODEV;
-
- netif_device_attach(zd->dev);
-
- if (zd->was_enabled)
- return zd1201_enable(zd);
- else
- return 0;
-}
-
-#else
-
-#define zd1201_suspend NULL
-#define zd1201_resume NULL
-
-#endif
-
-static struct usb_driver zd1201_usb = {
- .name = "zd1201",
- .probe = zd1201_probe,
- .disconnect = zd1201_disconnect,
- .id_table = zd1201_table,
- .suspend = zd1201_suspend,
- .resume = zd1201_resume,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(zd1201_usb);
diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h
deleted file mode 100644
index c46ac87550d1..000000000000
--- a/drivers/net/wireless/zydas/zd1201.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq@amsat.org)
- *
- * Parts of this driver have been derived from a wlan-ng version
- * modified by ZyDAS.
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- */
-
-#ifndef _INCLUDE_ZD1201_H_
-#define _INCLUDE_ZD1201_H_
-
-#define ZD1201_NUMKEYS 4
-#define ZD1201_MAXKEYLEN 13
-#define ZD1201_MAXMULTI 16
-#define ZD1201_FRAGMAX 2500
-#define ZD1201_FRAGMIN 256
-#define ZD1201_RTSMAX 2500
-
-#define ZD1201_RXSIZE 3000
-
-struct zd1201 {
- struct usb_device *usb;
- int removed;
- struct net_device *dev;
- struct iw_statistics iwstats;
-
- int endp_in;
- int endp_out;
- int endp_out2;
- struct urb *rx_urb;
- struct urb *tx_urb;
-
- unsigned char rxdata[ZD1201_RXSIZE];
- int rxlen;
- wait_queue_head_t rxdataq;
- int rxdatas;
- struct hlist_head fraglist;
- unsigned char txdata[ZD1201_RXSIZE];
-
- int ap;
- char essid[IW_ESSID_MAX_SIZE+1];
- int essidlen;
- int mac_enabled;
- int was_enabled;
- int monitor;
- int encode_enabled;
- int encode_restricted;
- unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN];
- int encode_keylen[ZD1201_NUMKEYS];
-};
-
-struct zd1201_frag {
- struct hlist_node fnode;
- int seq;
- struct sk_buff *skb;
-};
-
-#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV
-#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1
-#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2
-#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4
-#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1
-
-#define ZD1201_FW_TIMEOUT (1000)
-
-#define ZD1201_TX_TIMEOUT (2000)
-
-#define ZD1201_USB_CMDREQ 0
-#define ZD1201_USB_RESREQ 1
-
-#define ZD1201_CMDCODE_INIT 0x00
-#define ZD1201_CMDCODE_ENABLE 0x01
-#define ZD1201_CMDCODE_DISABLE 0x02
-#define ZD1201_CMDCODE_ALLOC 0x0a
-#define ZD1201_CMDCODE_INQUIRE 0x11
-#define ZD1201_CMDCODE_SETRXRID 0x17
-#define ZD1201_CMDCODE_ACCESS 0x21
-
-#define ZD1201_PACKET_EVENTSTAT 0x0
-#define ZD1201_PACKET_RXDATA 0x1
-#define ZD1201_PACKET_INQUIRE 0x2
-#define ZD1201_PACKET_RESOURCE 0x3
-
-#define ZD1201_ACCESSBIT 0x0100
-
-#define ZD1201_RID_CNFPORTTYPE 0xfc00
-#define ZD1201_RID_CNFOWNMACADDR 0xfc01
-#define ZD1201_RID_CNFDESIREDSSID 0xfc02
-#define ZD1201_RID_CNFOWNCHANNEL 0xfc03
-#define ZD1201_RID_CNFOWNSSID 0xfc04
-#define ZD1201_RID_CNFMAXDATALEN 0xfc07
-#define ZD1201_RID_CNFPMENABLED 0xfc09
-#define ZD1201_RID_CNFPMEPS 0xfc0a
-#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c
-#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23
-#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24
-#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25
-#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26
-#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27
-#define ZD1201_RID_CNFWEBFLAGS 0xfc28
-#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a
-#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b
-#define ZD1201_RID_CNFHOSTAUTH 0xfc2e
-#define ZD1201_RID_CNFGROUPADDRESS 0xfc80
-#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82
-#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83
-#define ZD1201_RID_TXRATECNTL 0xfc84
-#define ZD1201_RID_PROMISCUOUSMODE 0xfc85
-#define ZD1201_RID_CNFBASICRATES 0xfcb3
-#define ZD1201_RID_AUTHENTICATESTA 0xfce3
-#define ZD1201_RID_CURRENTBSSID 0xfd42
-#define ZD1201_RID_COMMSQUALITY 0xfd43
-#define ZD1201_RID_CURRENTTXRATE 0xfd44
-#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0
-#define ZD1201_RID_CURRENTCHANNEL 0xfdc1
-
-#define ZD1201_INQ_SCANRESULTS 0xf101
-
-#define ZD1201_INF_LINKSTATUS 0xf200
-#define ZD1201_INF_ASSOCSTATUS 0xf201
-#define ZD1201_INF_AUTHREQ 0xf202
-
-#define ZD1201_ASSOCSTATUS_STAASSOC 0x1
-#define ZD1201_ASSOCSTATUS_REASSOC 0x2
-#define ZD1201_ASSOCSTATUS_DISASSOC 0x3
-#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4
-#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5
-
-#define ZD1201_PORTTYPE_IBSS 0
-#define ZD1201_PORTTYPE_BSS 1
-#define ZD1201_PORTTYPE_WDS 2
-#define ZD1201_PORTTYPE_PSEUDOIBSS 3
-#define ZD1201_PORTTYPE_AP 6
-
-#define ZD1201_RATEB1 1
-#define ZD1201_RATEB2 2
-#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */
-#define ZD1201_RATEB11 8
-
-#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0x0001
-#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 0x0002
-
-#endif /* _INCLUDE_ZD1201_H_ */
diff --git a/drivers/net/wwan/qcom_bam_dmux.c b/drivers/net/wwan/qcom_bam_dmux.c
index 17d46f4d2913..26ca719fa0de 100644
--- a/drivers/net/wwan/qcom_bam_dmux.c
+++ b/drivers/net/wwan/qcom_bam_dmux.c
@@ -846,7 +846,7 @@ static int bam_dmux_probe(struct platform_device *pdev)
return 0;
}
-static int bam_dmux_remove(struct platform_device *pdev)
+static void bam_dmux_remove(struct platform_device *pdev)
{
struct bam_dmux *dmux = platform_get_drvdata(pdev);
struct device *dev = dmux->dev;
@@ -877,8 +877,6 @@ static int bam_dmux_remove(struct platform_device *pdev)
disable_irq(dmux->pc_irq);
bam_dmux_power_off(dmux);
bam_dmux_free_skbs(dmux->tx_skbs, DMA_TO_DEVICE);
-
- return 0;
}
static const struct dev_pm_ops bam_dmux_pm_ops = {
@@ -893,7 +891,7 @@ MODULE_DEVICE_TABLE(of, bam_dmux_of_match);
static struct platform_driver bam_dmux_driver = {
.probe = bam_dmux_probe,
- .remove = bam_dmux_remove,
+ .remove_new = bam_dmux_remove,
.driver = {
.name = "bam-dmux",
.pm = &bam_dmux_pm_ops,
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 88f760a7cbc3..ef76850d9bcd 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -104,13 +104,12 @@ bool provides_xdp_headroom = true;
module_param(provides_xdp_headroom, bool, 0644);
static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
- u8 status);
+ s8 status);
static void make_tx_response(struct xenvif_queue *queue,
- struct xen_netif_tx_request *txp,
+ const struct xen_netif_tx_request *txp,
unsigned int extra_count,
- s8 st);
-static void push_tx_responses(struct xenvif_queue *queue);
+ s8 status);
static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx);
@@ -208,13 +207,9 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
unsigned int extra_count, RING_IDX end)
{
RING_IDX cons = queue->tx.req_cons;
- unsigned long flags;
do {
- spin_lock_irqsave(&queue->response_lock, flags);
make_tx_response(queue, txp, extra_count, XEN_NETIF_RSP_ERROR);
- push_tx_responses(queue);
- spin_unlock_irqrestore(&queue->response_lock, flags);
if (cons == end)
break;
RING_COPY_REQUEST(&queue->tx, cons++, txp);
@@ -463,12 +458,20 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
}
for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS;
- shinfo->nr_frags++, gop++, nr_slots--) {
+ nr_slots--) {
+ if (unlikely(!txp->size)) {
+ make_tx_response(queue, txp, 0, XEN_NETIF_RSP_OKAY);
+ ++txp;
+ continue;
+ }
+
index = pending_index(queue->pending_cons++);
pending_idx = queue->pending_ring[index];
xenvif_tx_create_map_op(queue, pending_idx, txp,
txp == first ? extra_count : 0, gop);
frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
+ ++shinfo->nr_frags;
+ ++gop;
if (txp == first)
txp = txfrags;
@@ -481,20 +484,33 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
shinfo = skb_shinfo(nskb);
frags = shinfo->frags;
- for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots;
- shinfo->nr_frags++, txp++, gop++) {
+ for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots; ++txp) {
+ if (unlikely(!txp->size)) {
+ make_tx_response(queue, txp, 0,
+ XEN_NETIF_RSP_OKAY);
+ continue;
+ }
+
index = pending_index(queue->pending_cons++);
pending_idx = queue->pending_ring[index];
xenvif_tx_create_map_op(queue, pending_idx, txp, 0,
gop);
frag_set_pending_idx(&frags[shinfo->nr_frags],
pending_idx);
+ ++shinfo->nr_frags;
+ ++gop;
+ }
+
+ if (shinfo->nr_frags) {
+ skb_shinfo(skb)->frag_list = nskb;
+ nskb = NULL;
}
+ }
- skb_shinfo(skb)->frag_list = nskb;
- } else if (nskb) {
+ if (nskb) {
/* A frag_list skb was allocated but it is no longer needed
- * because enough slots were converted to copy ops above.
+ * because enough slots were converted to copy ops above or some
+ * were empty.
*/
kfree_skb(nskb);
}
@@ -963,7 +979,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
(ret == 0) ?
XEN_NETIF_RSP_OKAY :
XEN_NETIF_RSP_ERROR);
- push_tx_responses(queue);
continue;
}
@@ -975,7 +990,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
make_tx_response(queue, &txreq, extra_count,
XEN_NETIF_RSP_OKAY);
- push_tx_responses(queue);
continue;
}
@@ -1401,8 +1415,35 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget)
return work_done;
}
+static void _make_tx_response(struct xenvif_queue *queue,
+ const struct xen_netif_tx_request *txp,
+ unsigned int extra_count,
+ s8 status)
+{
+ RING_IDX i = queue->tx.rsp_prod_pvt;
+ struct xen_netif_tx_response *resp;
+
+ resp = RING_GET_RESPONSE(&queue->tx, i);
+ resp->id = txp->id;
+ resp->status = status;
+
+ while (extra_count-- != 0)
+ RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+
+ queue->tx.rsp_prod_pvt = ++i;
+}
+
+static void push_tx_responses(struct xenvif_queue *queue)
+{
+ int notify;
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
+ if (notify)
+ notify_remote_via_irq(queue->tx_irq);
+}
+
static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
- u8 status)
+ s8 status)
{
struct pending_tx_info *pending_tx_info;
pending_ring_idx_t index;
@@ -1412,8 +1453,8 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
spin_lock_irqsave(&queue->response_lock, flags);
- make_tx_response(queue, &pending_tx_info->req,
- pending_tx_info->extra_count, status);
+ _make_tx_response(queue, &pending_tx_info->req,
+ pending_tx_info->extra_count, status);
/* Release the pending index before pusing the Tx response so
* its available before a new Tx request is pushed by the
@@ -1427,32 +1468,19 @@ static void xenvif_idx_release(struct xenvif_queue *queue, u16 pending_idx,
spin_unlock_irqrestore(&queue->response_lock, flags);
}
-
static void make_tx_response(struct xenvif_queue *queue,
- struct xen_netif_tx_request *txp,
+ const struct xen_netif_tx_request *txp,
unsigned int extra_count,
- s8 st)
+ s8 status)
{
- RING_IDX i = queue->tx.rsp_prod_pvt;
- struct xen_netif_tx_response *resp;
-
- resp = RING_GET_RESPONSE(&queue->tx, i);
- resp->id = txp->id;
- resp->status = st;
-
- while (extra_count-- != 0)
- RING_GET_RESPONSE(&queue->tx, ++i)->status = XEN_NETIF_RSP_NULL;
+ unsigned long flags;
- queue->tx.rsp_prod_pvt = ++i;
-}
+ spin_lock_irqsave(&queue->response_lock, flags);
-static void push_tx_responses(struct xenvif_queue *queue)
-{
- int notify;
+ _make_tx_response(queue, txp, extra_count, status);
+ push_tx_responses(queue);
- RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&queue->tx, notify);
- if (notify)
- notify_remote_via_irq(queue->tx_irq);
+ spin_unlock_irqrestore(&queue->response_lock, flags);
}
static void xenvif_idx_unmap(struct xenvif_queue *queue, u16 pending_idx)
@@ -1750,5 +1778,6 @@ static void __exit netback_fini(void)
}
module_exit(netback_fini);
+MODULE_DESCRIPTION("Xen backend network device module");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("xen-backend:vif");